/** * Delete the object's property. * * Warning: specified property must be owned by specified object. */ void ecma_delete_property (ecma_object_t *object_p, /**< object */ ecma_property_t *prop_p) /**< property */ { ecma_property_header_t *cur_prop_p = ecma_get_property_list (object_p); ecma_property_header_t *prev_prop_p = NULL; while (true) { JERRY_ASSERT (cur_prop_p != NULL); JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (cur_prop_p)); ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) cur_prop_p; for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { if ((cur_prop_p->types + i) == prop_p) { ecma_string_t *name_p = ECMA_GET_POINTER (ecma_string_t, prop_pair_p->names_cp[i]); ecma_free_property (object_p, name_p, cur_prop_p->types + i); prop_pair_p->names_cp[i] = ECMA_NULL_POINTER; if (name_p != NULL) { ecma_deref_ecma_string (name_p); } JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2); if (cur_prop_p->types[1 - i].type_and_flags != ECMA_PROPERTY_TYPE_DELETED) { /* The other property is still valid. */ return; } JERRY_ASSERT (cur_prop_p->types[i].type_and_flags == ECMA_PROPERTY_TYPE_DELETED); if (prev_prop_p == NULL) { object_p->property_list_or_bound_object_cp = cur_prop_p->next_property_cp; } else { prev_prop_p->next_property_cp = cur_prop_p->next_property_cp; } ecma_dealloc_property_pair ((ecma_property_pair_t *) cur_prop_p); return; } } prev_prop_p = cur_prop_p; cur_prop_p = ECMA_GET_POINTER (ecma_property_header_t, cur_prop_p->next_property_cp); } } /* ecma_delete_property */
/** * Get setter of named accessor property * * @return pointer to object - setter of the property */ ecma_object_t * ecma_get_named_accessor_property_setter (const ecma_property_value_t *prop_value_p) /**< property value reference */ { #ifdef JERRY_CPOINTER_32_BIT ecma_getter_setter_pointers_t *getter_setter_pair_p; getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t, prop_value_p->getter_setter_pair_cp); return ECMA_GET_POINTER (ecma_object_t, getter_setter_pair_p->setter_p); #else /* !JERRY_CPOINTER_32_BIT */ return ECMA_GET_POINTER (ecma_object_t, prop_value_p->getter_setter_pair.setter_p); #endif /* JERRY_CPOINTER_32_BIT */ } /* ecma_get_named_accessor_property_setter */
/** * Find internal property in the object's property set. * * @return pointer to the property, if it is found, * NULL - otherwise. */ ecma_property_t * ecma_find_internal_property (ecma_object_t *object_p, /**< object descriptor */ ecma_internal_property_id_t property_id) /**< internal property identifier */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (property_id != ECMA_INTERNAL_PROPERTY_PROTOTYPE && property_id != ECMA_INTERNAL_PROPERTY_EXTENSIBLE); ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); if (ECMA_PROPERTY_GET_TYPE (&prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_INTERNAL && ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (prop_iter_p->types + 0) == property_id) { return prop_iter_p->types + 0; } if (ECMA_PROPERTY_GET_TYPE (&prop_iter_p->types[1]) == ECMA_PROPERTY_TYPE_INTERNAL && ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (prop_iter_p->types + 1) == property_id) { return prop_iter_p->types + 1; } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } return NULL; } /* ecma_find_internal_property */
/** * Get next object in list of objects with same generation. */ static inline ecma_object_t * ecma_gc_get_object_next (ecma_object_t *object_p) /**< object */ { JERRY_ASSERT (object_p != NULL); return ECMA_GET_POINTER (ecma_object_t, object_p->gc_next_cp); } /* ecma_gc_get_object_next */
/** * Get setter of named accessor property * * @return pointer to object - setter of the property */ ecma_object_t * ecma_get_named_accessor_property_setter (const ecma_property_t *prop_p) /**< named accessor property */ { JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); return ECMA_GET_POINTER (ecma_object_t, ECMA_PROPERTY_VALUE_PTR (prop_p)->getter_setter_pair.setter_p); } /* ecma_get_named_accessor_property_setter */
/** * Check that */ static void ecma_assert_object_contains_the_property (const ecma_object_t *object_p, /**< ecma-object */ const ecma_property_t *prop_p) /**< ecma-property */ { #ifndef JERRY_NDEBUG ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { if ((prop_pair_p->header.types + i) == prop_p) { return; } } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } JERRY_UNREACHABLE (); #else /* JERRY_NDEBUG */ (void) object_p; (void) prop_p; #endif /* JERRY_NDEBUG */ } /* ecma_assert_object_contains_the_property */
/** * Free the collection of ecma values. */ void ecma_free_values_collection (ecma_collection_header_t *header_p, /**< collection's header */ bool do_deref_if_object) /**< if the value is object value, decrement reference counter of the object */ { JERRY_ASSERT (header_p != NULL); const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); ecma_collection_chunk_t *chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, header_p->first_chunk_cp); ecma_length_t value_index = 0; while (chunk_p != NULL) { JERRY_ASSERT (value_index < header_p->unit_number); ecma_value_t *cur_value_buf_iter_p = (ecma_value_t *) chunk_p->data; ecma_value_t *cur_value_buf_end_p = cur_value_buf_iter_p + values_in_chunk; while (cur_value_buf_iter_p != cur_value_buf_end_p && value_index < header_p->unit_number) { JERRY_ASSERT (cur_value_buf_iter_p < cur_value_buf_end_p); if (do_deref_if_object) { ecma_free_value (*cur_value_buf_iter_p); } else { ecma_free_value_if_not_object (*cur_value_buf_iter_p); } cur_value_buf_iter_p++; value_index++; } ecma_collection_chunk_t *next_chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, chunk_p->next_chunk_cp); ecma_dealloc_collection_chunk (chunk_p); chunk_p = next_chunk_p; } ecma_dealloc_collection_header (header_p); } /* ecma_free_values_collection */
/** * Find named data property or named access property in specified object. * * @return pointer to the property, if it is found, * NULL - otherwise. */ ecma_property_t * ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in */ ecma_string_t *name_p) /**< property's name */ { JERRY_ASSERT (obj_p != NULL); JERRY_ASSERT (name_p != NULL); ecma_property_t *property_p; if (ecma_lcache_lookup (obj_p, name_p, &property_p)) { return property_p; } property_p = NULL; ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_p); while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2); if (prop_pair_p->names_cp[0] != ECMA_NULL_POINTER) { ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_pair_p->names_cp[0]); if (ecma_compare_ecma_strings (name_p, property_name_p)) { property_p = prop_iter_p->types + 0; break; } } if (prop_pair_p->names_cp[1] != ECMA_NULL_POINTER) { ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_pair_p->names_cp[1]); if (ecma_compare_ecma_strings (name_p, property_name_p)) { property_p = prop_iter_p->types + 1; break; } } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } ecma_lcache_insert (obj_p, name_p, property_p); return property_p; } /* ecma_find_named_property */
/** * Get outer reference of lexical environment. */ inline ecma_object_t *__attr_pure___ ecma_get_lex_env_outer_reference (const ecma_object_t *object_p) /**< lexical environment */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (object_p)); return ECMA_GET_POINTER (ecma_object_t, object_p->prototype_or_outer_reference_cp); } /* ecma_get_lex_env_outer_reference */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p); if (lex_env_p != NULL) { ecma_gc_set_object_visited (lex_env_p, true); } if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p, true); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } } if (traverse_properties) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); if (prop_iter_p->types[0].type_and_flags != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 0); } if (prop_iter_p->types[1].type_and_flags != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 1); } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } } } /* ecma_gc_mark */
/** * Get object's/lexical environment's property list. * * See also: * ecma_op_object_get_property_names */ inline ecma_property_header_t *__attr_pure___ ecma_get_property_list (const ecma_object_t *object_p) /**< object or lexical environment */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (!ecma_is_lexical_environment (object_p) || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); return ECMA_GET_POINTER (ecma_property_header_t, object_p->property_list_or_bound_object_cp); } /* ecma_get_property_list */
/** * Check whether the object contains a property */ static void ecma_assert_object_contains_the_property (const ecma_object_t *object_p, /**< ecma-object */ const ecma_property_value_t *prop_value_p, /**< property value */ ecma_property_types_t type) /**< expected property type */ { #ifndef JERRY_NDEBUG ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); JERRY_ASSERT (prop_iter_p != NULL); if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) { prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { if ((prop_pair_p->values + i) == prop_value_p) { JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_pair_p->header.types[i]) == type); return; } } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } JERRY_UNREACHABLE (); #else /* JERRY_NDEBUG */ JERRY_UNUSED (object_p); JERRY_UNUSED (prop_value_p); JERRY_UNUSED (type); #endif /* !JERRY_NDEBUG */ } /* ecma_assert_object_contains_the_property */
/** * Free property values and change their type to deleted. */ void ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to */ jmem_cpointer_t name_cp, /**< name of the property or ECMA_NULL_POINTER */ ecma_property_t *property_p) /**< property */ { JERRY_ASSERT (object_p != NULL && property_p != NULL); switch (ECMA_PROPERTY_GET_TYPE (*property_p)) { case ECMA_PROPERTY_TYPE_NAMEDDATA: { if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_STRING_CONTAINER_MAGIC_STRING) { if (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE || name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER) { ecma_free_native_pointer (property_p); break; } } ecma_free_value_if_not_object (ECMA_PROPERTY_VALUE_PTR (property_p)->value); break; } case ECMA_PROPERTY_TYPE_NAMEDACCESSOR: { #ifdef JERRY_CPOINTER_32_BIT ecma_getter_setter_pointers_t *getter_setter_pair_p; getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t, ECMA_PROPERTY_VALUE_PTR (property_p)->getter_setter_pair_cp); jmem_pools_free (getter_setter_pair_p, sizeof (ecma_getter_setter_pointers_t)); #endif /* JERRY_CPOINTER_32_BIT */ break; } default: { JERRY_UNREACHABLE (); return; } } if (ecma_is_property_lcached (property_p)) { ecma_lcache_invalidate (object_p, name_cp, property_p); } if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_PROPERTY_NAME_TYPE_STRING) { ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp); ecma_deref_ecma_string (prop_name_p); } *property_p = ECMA_PROPERTY_TYPE_DELETED; } /* ecma_free_property */
/** * Move collection iterator to next element if there is any. * * @return true - if iterator moved, * false - otherwise (current element is last element in the collection) */ bool ecma_collection_iterator_next (ecma_collection_iterator_t *iterator_p) /**< context of iterator */ { if (iterator_p->header_p == NULL || unlikely (iterator_p->header_p->unit_number == 0)) { return false; } const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); if (iterator_p->current_value_p == NULL) { JERRY_ASSERT (iterator_p->current_index == 0); ecma_collection_chunk_t *first_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, iterator_p->header_p->first_chunk_cp); iterator_p->next_chunk_cp = first_chunk_p->next_chunk_cp; iterator_p->current_value_p = (ecma_value_t *) &first_chunk_p->data; iterator_p->current_chunk_end_p = (iterator_p->current_value_p + values_in_chunk); } else { if (iterator_p->current_index + 1 == iterator_p->header_p->unit_number) { return false; } JERRY_ASSERT (iterator_p->current_index + 1 < iterator_p->header_p->unit_number); iterator_p->current_index++; iterator_p->current_value_p++; } if (iterator_p->current_value_p == iterator_p->current_chunk_end_p) { ecma_collection_chunk_t *next_chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, iterator_p->next_chunk_cp); JERRY_ASSERT (next_chunk_p != NULL); iterator_p->next_chunk_cp = next_chunk_p->next_chunk_cp; iterator_p->current_value_p = (ecma_value_t *) &next_chunk_p->data; iterator_p->current_chunk_end_p = iterator_p->current_value_p + values_in_chunk; } else { JERRY_ASSERT (iterator_p->current_value_p < iterator_p->current_chunk_end_p); } return true; } /* ecma_collection_iterator_next */
/** * Get next object in list of objects with same generation. */ static ecma_object_t* ecma_gc_get_object_next (ecma_object_t *object_p) /**< object */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (sizeof (uintptr_t) * JERRY_BITSINBYTE >= ECMA_OBJECT_GC_NEXT_CP_WIDTH); uintptr_t next_cp = (uintptr_t) jrt_extract_bit_field (object_p->container, ECMA_OBJECT_GC_NEXT_CP_POS, ECMA_OBJECT_GC_NEXT_CP_WIDTH); return ECMA_GET_POINTER (ecma_object_t, next_cp); } /* ecma_gc_get_object_next */
/** * Helper function to merge argument lists * * See also: * ECMA-262 v5, 15.3.4.5.1 step 4 * ECMA-262 v5, 15.3.4.5.2 step 4 * * Used by: * - [[Call]] implementation for Function objects. * - [[Construct]] implementation for Function objects. * * @return ecma_value_t* - pointer to the merged argument list. */ static ecma_value_t* ecma_function_bind_merge_arg_lists (ecma_object_t *func_obj_p, /**< Function object */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len, /**< length of arguments list */ ecma_length_t *total_args_count) /**< length of the merged argument list */ { ecma_value_t *arg_list_p; ecma_length_t bound_args_count = 0; ecma_property_t *bound_args_prop_p; bound_args_prop_p = ecma_find_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS); if (bound_args_prop_p != NULL) { ecma_collection_header_t *bound_arg_list_p = ECMA_GET_POINTER (ecma_collection_header_t, bound_args_prop_p->u.internal_property.value); ecma_collection_iterator_t bound_args_iterator; ecma_collection_iterator_init (&bound_args_iterator, bound_arg_list_p); bound_args_count = bound_arg_list_p->unit_number; *total_args_count = bound_args_count + arguments_list_len; const size_t arg_list_size = (size_t) *total_args_count * sizeof (ecma_value_t); arg_list_p = static_cast <ecma_value_t *> (mem_heap_alloc_block (arg_list_size, MEM_HEAP_ALLOC_SHORT_TERM)); for (ecma_length_t i = 0; i < bound_args_count; i++) { bool is_moved = ecma_collection_iterator_next (&bound_args_iterator); JERRY_ASSERT (is_moved); arg_list_p[i] = *bound_args_iterator.current_value_p; } } else { *total_args_count = arguments_list_len; const size_t arg_list_size = (size_t) *total_args_count * sizeof (ecma_value_t); arg_list_p = static_cast <ecma_value_t *> (mem_heap_alloc_block (arg_list_size, MEM_HEAP_ALLOC_SHORT_TERM)); } for (ecma_length_t i = 0; i < arguments_list_len; i++) { arg_list_p[i + bound_args_count] = arguments_list_p[i]; } return arg_list_p; } /* ecma_function_bind_merge_arg_lists */
/** * Set setter of named accessor property */ void ecma_set_named_accessor_property_setter (ecma_object_t *object_p, /**< the property's container */ ecma_property_value_t *prop_value_p, /**< property value reference */ ecma_object_t *setter_p) /**< setter object */ { ecma_assert_object_contains_the_property (object_p, prop_value_p, ECMA_PROPERTY_TYPE_NAMEDACCESSOR); #ifdef JERRY_CPOINTER_32_BIT ecma_getter_setter_pointers_t *getter_setter_pair_p; getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t, prop_value_p->getter_setter_pair_cp); ECMA_SET_POINTER (getter_setter_pair_p->setter_p, setter_p); #else /* !JERRY_CPOINTER_32_BIT */ ECMA_SET_POINTER (prop_value_p->getter_setter_pair.setter_p, setter_p); #endif /* JERRY_CPOINTER_32_BIT */ } /* ecma_set_named_accessor_property_setter */
/** * Free specified object */ void ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ { JERRY_ASSERT (object_p != NULL && !ecma_gc_is_object_visited (object_p) && ecma_gc_get_object_refs (object_p) == 0); if (!ecma_is_lexical_environment (object_p)) { /* if the object provides free callback, invoke it with handle stored in the object */ ecma_external_pointer_t freecb_p; ecma_external_pointer_t native_p; bool is_retrieved = ecma_get_external_pointer_value (object_p, ECMA_INTERNAL_PROPERTY_FREE_CALLBACK, &freecb_p); if (is_retrieved) { is_retrieved = ecma_get_external_pointer_value (object_p, ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE, &native_p); JERRY_ASSERT (is_retrieved); jerry_dispatch_object_free_callback (freecb_p, native_p); } } if (!ecma_is_lexical_environment (object_p) || ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND) { for (ecma_property_t *property = ecma_get_property_list (object_p), *next_property_p; property != NULL; property = next_property_p) { next_property_p = ECMA_GET_POINTER (ecma_property_t, property->next_property_p); ecma_free_property (object_p, property); } } JERRY_ASSERT (ecma_gc_objects_number > 0); ecma_gc_objects_number--; ecma_dealloc_object (object_p); } /* ecma_gc_sweep */
/** * Lookup property in the LCache * * @return true - if (object, property name) pair is registered in LCache, * false - probably, not registered. */ bool __attr_always_inline___ ecma_lcache_lookup (ecma_object_t *object_p, /**< object */ const ecma_string_t *prop_name_p, /**< property's name */ ecma_property_t **prop_p_p) /**< [out] if return value is true, * then here will be pointer to property, * if the object contains property with specified name, * or, otherwise - NULL; * if return value is false, * then the output parameter is not set */ { #ifndef CONFIG_ECMA_LCACHE_DISABLE lit_string_hash_t hash_key = ecma_string_hash (prop_name_p); unsigned int object_cp; ECMA_SET_NON_NULL_POINTER (object_cp, object_p); for (uint32_t i = 0; i < ECMA_LCACHE_HASH_ROW_LENGTH; i++) { if (ecma_lcache_hash_table[hash_key][i].object_cp == object_cp) { ecma_string_t *entry_prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, ecma_lcache_hash_table[hash_key][i].prop_name_cp); if (ecma_compare_ecma_strings_equal_hashes (prop_name_p, entry_prop_name_p)) { ecma_property_t *prop_p = ECMA_GET_POINTER (ecma_property_t, ecma_lcache_hash_table[hash_key][i].prop_cp); JERRY_ASSERT (prop_p == NULL || ecma_is_property_lcached (prop_p)); *prop_p_p = prop_p; return true; } else { /* may be equal but it is long to compare it here */ } } } #else /* CONFIG_ECMA_LCACHE_DISABLE */ (void) object_p; (void) prop_name_p; (void) prop_p_p; #endif /* CONFIG_ECMA_LCACHE_DISABLE */ return false; } /* ecma_lcache_lookup */
/** * Free the internal property and values it references. */ static void ecma_free_internal_property (ecma_property_t *property_p) /**< the property */ { JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_GET_TYPE (property_p) == ECMA_PROPERTY_TYPE_INTERNAL); uint32_t property_value = ECMA_PROPERTY_VALUE_PTR (property_p)->value; switch (ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (property_p)) { case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* a collection */ case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* a collection */ { ecma_free_values_collection (ECMA_GET_NON_NULL_POINTER (ecma_collection_header_t, property_value), true); break; } case ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE: /* compressed pointer to a ecma_string_t */ { ecma_string_t *str_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_value); ecma_deref_ecma_string (str_p); break; } case ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE: /* pointer to a ecma_number_t */ { ecma_number_t *num_p = ECMA_GET_NON_NULL_POINTER (ecma_number_t, property_value); ecma_dealloc_number (num_p); break; } case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_FREE_CALLBACK: /* an external pointer */ { ecma_free_external_pointer_in_property (property_p); break; } case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */ case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */ case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_object_t */ case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_object_t */ case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_DESC: /* an integer */ case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION: { break; } case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: { ecma_free_value_if_not_object (property_value); break; } case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS: { if (property_value != ECMA_NULL_POINTER) { ecma_free_values_collection (ECMA_GET_NON_NULL_POINTER (ecma_collection_header_t, property_value), false); } break; } case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type, * but number of the real internal property types */ { JERRY_UNREACHABLE (); break; } case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */ { ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, property_value)); break; } case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE: /* compressed pointer to a regexp bytecode array */ { ecma_compiled_code_t *bytecode_p = ECMA_GET_POINTER (ecma_compiled_code_t, property_value); if (bytecode_p != NULL) { ecma_bytecode_deref (bytecode_p); } break; } } } /* ecma_free_internal_property */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p); if (lex_env_p != NULL) { ecma_gc_set_object_visited (lex_env_p, true); } if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND) { ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p, true); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } } if (traverse_properties) { for (ecma_property_t *property_p = ecma_get_property_list (object_p), *next_property_p; property_p != NULL; property_p = next_property_p) { next_property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p); switch ((ecma_property_type_t) property_p->type) { case ECMA_PROPERTY_NAMEDDATA: { ecma_value_t value = ecma_get_named_data_property_value (property_p); if (ecma_is_value_object (value)) { ecma_object_t *value_obj_p = ecma_get_object_from_value (value); ecma_gc_set_object_visited (value_obj_p, true); } break; } case ECMA_PROPERTY_NAMEDACCESSOR: { ecma_object_t *getter_obj_p = ecma_get_named_accessor_property_getter (property_p); ecma_object_t *setter_obj_p = ecma_get_named_accessor_property_setter (property_p); if (getter_obj_p != NULL) { ecma_gc_set_object_visited (getter_obj_p, true); } if (setter_obj_p != NULL) { ecma_gc_set_object_visited (setter_obj_p, true); } break; } case ECMA_PROPERTY_INTERNAL: { ecma_internal_property_id_t property_id = (ecma_internal_property_id_t) property_p->u.internal_property.type; uint32_t property_value = property_p->u.internal_property.value; switch (property_id) { case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* a collection of ecma-values */ case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* a collection of ecma-values */ { JERRY_UNIMPLEMENTED ("Indexed array storage is not implemented yet."); } case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_object_t (see above in the routine) */ case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_object_t (see above in the routine) */ case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type, * but number of the real internal property types */ { JERRY_UNREACHABLE (); } case ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS: /* a collection of strings */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE: /* compressed pointer to a ecma_string_t */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE: /* compressed pointer to a ecma_number_t */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */ case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */ case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */ case ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET: /* an integer */ case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_FREE_CALLBACK: /* an object's native free callback */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_DESC: /* an integer */ case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS: { break; } case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */ { ecma_object_t *obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, property_value); ecma_gc_set_object_visited (obj_p, true); break; } } break; } } } } } /* ecma_gc_mark */
/** * Append new value to ecma-values collection */ void ecma_append_to_values_collection (ecma_collection_header_t *header_p, /**< collection's header */ ecma_value_t v, /**< ecma-value to append */ bool do_ref_if_object) /**< if the value is object value, increase reference counter of the object */ { const size_t values_in_chunk = sizeof (ecma_collection_chunk_t::data) / sizeof (ecma_value_t); size_t values_number = header_p->unit_number; size_t pos_of_new_value_in_chunk = values_number % values_in_chunk; values_number++; if ((ecma_length_t) values_number == values_number) { header_p->unit_number = (ecma_length_t) values_number; } else { jerry_fatal (ERR_OUT_OF_MEMORY); } ecma_collection_chunk_t *chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, header_p->last_chunk_cp); if (pos_of_new_value_in_chunk == 0) { /* all chunks are currently filled with values */ chunk_p = ecma_alloc_collection_chunk (); chunk_p->next_chunk_cp = ECMA_NULL_POINTER; if (header_p->last_chunk_cp == ECMA_NULL_POINTER) { JERRY_ASSERT (header_p->first_chunk_cp == ECMA_NULL_POINTER); ECMA_SET_NON_NULL_POINTER (header_p->first_chunk_cp, chunk_p); } else { ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, header_p->last_chunk_cp); JERRY_ASSERT (last_chunk_p->next_chunk_cp == ECMA_NULL_POINTER); ECMA_SET_NON_NULL_POINTER (last_chunk_p->next_chunk_cp, chunk_p); } ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, chunk_p); } else { /* last chunk can be appended with the new value */ JERRY_ASSERT (chunk_p != NULL); } ecma_value_t *values_p = (ecma_value_t *) chunk_p->data; JERRY_ASSERT ((uint8_t *) (values_p + pos_of_new_value_in_chunk + 1) <= (uint8_t *) (chunk_p + 1)); values_p[pos_of_new_value_in_chunk] = ecma_copy_value (v, do_ref_if_object); } /* ecma_append_to_values_collection */
/** * The Object.keys and Object.getOwnPropertyName routine's common part. * * See also: * ECMA-262 v5, 15.2.3.4 steps 2-5 * ECMA-262 v5, 15.2.3.14 steps 3-6 * * @return completion value - Array of property names. * Returned value must be freed with ecma_free_completion_value. */ ecma_completion_value_t ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /** < object */ bool only_enumerable_properties) /** < list enumerable properties? */ { JERRY_ASSERT (obj_p != NULL); ecma_completion_value_t new_array = ecma_op_create_array_object (NULL, 0, false); JERRY_ASSERT (ecma_is_completion_value_normal (new_array)); ecma_object_t *new_array_p = ecma_get_object_from_completion_value (new_array); uint32_t index = 0; for (ecma_property_t *property_p = ecma_get_property_list (obj_p); property_p != NULL; property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) { ecma_string_t *property_name_p; if (property_p->type == ECMA_PROPERTY_NAMEDDATA) { property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_p->u.named_data_property.name_p); } else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR) { property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_p->u.named_accessor_property.name_p); } else { continue; } if (only_enumerable_properties && !ecma_is_property_enumerable (property_p)) { continue; } JERRY_ASSERT (property_name_p != NULL); ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_property_descriptor_t item_prop_desc = ecma_make_empty_property_descriptor (); { item_prop_desc.is_value_defined = true; item_prop_desc.value = ecma_make_string_value (property_name_p); item_prop_desc.is_writable_defined = true; item_prop_desc.is_writable = true; item_prop_desc.is_enumerable_defined = true; item_prop_desc.is_enumerable = true; item_prop_desc.is_configurable_defined = true; item_prop_desc.is_configurable = true; } ecma_completion_value_t completion = ecma_op_object_define_own_property (new_array_p, index_string_p, &item_prop_desc, false); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion)); ecma_free_completion_value (completion); ecma_deref_ecma_string (index_string_p); index++; } return new_array; } /* ecma_builtin_helper_object_get_properties */
/** * Free specified object */ void ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ { JERRY_ASSERT (object_p != NULL && !ecma_gc_is_object_visited (object_p) && object_p->type_flags_refs < ECMA_OBJECT_REF_ONE); if (!ecma_is_lexical_environment (object_p)) { /* if the object provides free callback, invoke it with handle stored in the object */ ecma_external_pointer_t freecb_p; ecma_external_pointer_t native_p; bool is_retrieved = ecma_get_external_pointer_value (object_p, ECMA_INTERNAL_PROPERTY_FREE_CALLBACK, &freecb_p); if (is_retrieved && ((jerry_object_free_callback_t) freecb_p) != NULL) { is_retrieved = ecma_get_external_pointer_value (object_p, ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE, &native_p); JERRY_ASSERT (is_retrieved); jerry_dispatch_object_free_callback (freecb_p, native_p); } } if (!ecma_is_lexical_environment (object_p) || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); if (prop_iter_p != NULL && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP) { ecma_property_hashmap_free (object_p); prop_iter_p = ecma_get_property_list (object_p); } while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); /* Both cannot be deleted. */ JERRY_ASSERT (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED || prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED); ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED) { ecma_string_t *name_p = ECMA_GET_POINTER (ecma_string_t, prop_pair_p->names_cp[i]); ecma_free_property (object_p, name_p, prop_iter_p->types + i); if (name_p != NULL) { ecma_deref_ecma_string (name_p); } } } /* Both must be deleted. */ JERRY_ASSERT (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_DELETED && prop_iter_p->types[1] == ECMA_PROPERTY_TYPE_DELETED); prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); ecma_dealloc_property_pair (prop_pair_p); } } JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_number) > 0); JERRY_CONTEXT (ecma_gc_objects_number)--; if (!ecma_is_lexical_environment (object_p)) { if (ecma_get_object_is_builtin (object_p) || ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) { ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p); return; } if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) { /* Function with byte-code (not a built-in function). */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ext_func_p->u.function.bytecode_cp)); ecma_dealloc_extended_object (ext_func_p); return; } } ecma_dealloc_object (object_p); } /* ecma_gc_sweep */
/** * Find named data property or named access property in specified object. * * @return pointer to the property, if it is found, * NULL - otherwise. */ ecma_property_t * ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in */ ecma_string_t *name_p) /**< property's name */ { JERRY_ASSERT (obj_p != NULL); JERRY_ASSERT (name_p != NULL); ecma_property_t *property_p = ecma_lcache_lookup (obj_p, name_p); if (property_p != NULL) { return property_p; } ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_p); #ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE if (prop_iter_p != NULL && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP) { ecma_string_t *property_real_name_p; property_p = ecma_property_hashmap_find ((ecma_property_hashmap_t *) prop_iter_p, name_p, &property_real_name_p); if (property_p != NULL && !ecma_is_property_lcached (property_p)) { ecma_lcache_insert (obj_p, property_real_name_p, property_p); } return property_p; } #endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */ property_p = NULL; ecma_string_t *property_name_p = NULL; uint32_t steps = 0; while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2); if (prop_pair_p->names_cp[0] != ECMA_NULL_POINTER) { property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_pair_p->names_cp[0]); if (ecma_compare_ecma_strings (name_p, property_name_p)) { property_p = prop_iter_p->types + 0; break; } } if (prop_pair_p->names_cp[1] != ECMA_NULL_POINTER) { property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_pair_p->names_cp[1]); if (ecma_compare_ecma_strings (name_p, property_name_p)) { property_p = prop_iter_p->types + 1; break; } } steps++; prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } if (steps > (ECMA_PROPERTY_HASMAP_MINIMUM_SIZE / 4)) { ecma_property_hashmap_create (obj_p); } if (property_p != NULL && !ecma_is_property_lcached (property_p)) { ecma_lcache_insert (obj_p, property_name_p, property_p); } return property_p; } /* ecma_find_named_property */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p); if (lex_env_p != NULL) { ecma_gc_set_object_visited (lex_env_p, true); } if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p, true); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } if (!ecma_get_object_is_builtin (object_p) && ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_func_p->u.function.scope_cp); ecma_gc_set_object_visited (scope_p, true); } } if (traverse_properties) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); if (prop_iter_p != NULL && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP) { prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); if (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 0); } if (prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 1); } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } } } /* ecma_gc_mark */
/** * Enumerate properties and construct collection with their * names for further iteration in for-in opcode handler. * * See also: * ECMA-262 v5, 12.6.4 * * @return header of constructed strings collection (should be freed with ecma_free_values_collection), * or NULL - if there are no properties to enumerate in for-in. */ static ecma_collection_header_t * vm_helper_for_in_enumerate_properties_names (ecma_object_t *obj_p) /**< starting object - result of ToObject * conversion (ECMA-262 v5, 12.6.4, step 4) */ { const size_t bitmap_row_size = sizeof (uint32_t) * JERRY_BITSINBYTE; uint32_t names_hashes_bitmap[(1u << LIT_STRING_HASH_BITS) / bitmap_row_size]; memset (names_hashes_bitmap, 0, sizeof (names_hashes_bitmap)); ecma_length_t all_properties_count = 0; /* First pass: counting properties */ for (ecma_object_t *prototype_chain_iter_p = obj_p; prototype_chain_iter_p != NULL; prototype_chain_iter_p = ecma_get_object_prototype (prototype_chain_iter_p)) { for (ecma_property_t *prop_iter_p = ecma_get_property_list (prototype_chain_iter_p); prop_iter_p != NULL; prop_iter_p = ECMA_GET_POINTER (ecma_property_t, prop_iter_p->next_property_p)) { if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA || prop_iter_p->type == ECMA_PROPERTY_NAMEDACCESSOR) { all_properties_count++; } else { JERRY_ASSERT (prop_iter_p->type == ECMA_PROPERTY_INTERNAL); } } } if (all_properties_count == 0) { return NULL; } ecma_collection_header_t *ret_p = NULL; /* Second pass: collecting properties names */ MEM_DEFINE_LOCAL_ARRAY (names_p, all_properties_count, ecma_string_t*); ecma_length_t enumerated_properties_count = 0; ecma_length_t non_enumerated_properties_count = 0; for (ecma_object_t *prototype_chain_iter_p = obj_p; prototype_chain_iter_p != NULL; prototype_chain_iter_p = ecma_get_object_prototype (prototype_chain_iter_p)) { for (ecma_property_t *prop_iter_p = ecma_get_property_list (prototype_chain_iter_p); prop_iter_p != NULL; prop_iter_p = ECMA_GET_POINTER (ecma_property_t, prop_iter_p->next_property_p)) { if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA || prop_iter_p->type == ECMA_PROPERTY_NAMEDACCESSOR) { bool is_enumerated; ecma_string_t *prop_name_p; if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA) { prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_iter_p->u.named_data_property.name_p); } else { prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_iter_p->u.named_accessor_property.name_p); } lit_string_hash_t hash = prop_name_p->hash; uint32_t bitmap_row = hash / bitmap_row_size; uint32_t bitmap_column = hash % bitmap_row_size; if (ecma_is_property_enumerable (prop_iter_p)) { if ((names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) == 0) { /* no name with the hash occured during the iteration session */ is_enumerated = true; } else { /* name with same hash already occured */ bool is_equal_found = false; for (uint32_t index = 0; !is_equal_found && index < enumerated_properties_count; index++) { if (ecma_compare_ecma_strings (prop_name_p, names_p[index])) { is_equal_found = true; } } for (uint32_t index = 0; !is_equal_found && index < non_enumerated_properties_count; index++) { if (ecma_compare_ecma_strings (prop_name_p, names_p[all_properties_count - index - 1])) { is_equal_found = true; } } is_enumerated = !is_equal_found; } } else { is_enumerated = false; } names_hashes_bitmap[bitmap_row] |= (1u << bitmap_column); if (is_enumerated) { names_p[enumerated_properties_count++] = prop_name_p; } else { names_p[all_properties_count - non_enumerated_properties_count++ - 1] = prop_name_p; } JERRY_ASSERT (enumerated_properties_count + non_enumerated_properties_count <= all_properties_count); } else { JERRY_ASSERT (prop_iter_p->type == ECMA_PROPERTY_INTERNAL); } } } if (enumerated_properties_count != 0) { ret_p = ecma_new_strings_collection (names_p, enumerated_properties_count); } MEM_FINALIZE_LOCAL_ARRAY (names_p); return ret_p; } /* vm_helper_for_in_enumerate_properties_names */
/** * RegExp helper function to start the recursive matching algorithm * and create the result Array object * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ ecma_value_t input_string, /**< input string */ bool ignore_global) /**< ignore global flag */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); JERRY_ASSERT (ecma_is_value_object (regexp_value)); JERRY_ASSERT (ecma_is_value_string (input_string)); ecma_object_t *regexp_object_p = ecma_get_object_from_value (regexp_value); JERRY_ASSERT (ecma_object_get_class_name (regexp_object_p) == LIT_MAGIC_STRING_REGEXP_UL); ecma_property_t *bytecode_prop_p = ecma_get_internal_property (regexp_object_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); re_bytecode_t *bc_p = ECMA_GET_POINTER (re_bytecode_t, bytecode_prop_p->u.internal_property.value); ecma_string_t *input_string_p = ecma_get_string_from_value (input_string); lit_utf8_size_t input_string_size = ecma_string_get_size (input_string_p); MEM_DEFINE_LOCAL_ARRAY (input_utf8_buffer_p, input_string_size, lit_utf8_byte_t); ecma_string_to_utf8_string (input_string_p, input_utf8_buffer_p, (ssize_t) input_string_size); lit_utf8_iterator_t iterator = lit_utf8_iterator_create (input_utf8_buffer_p, input_string_size); re_matcher_ctx_t re_ctx; re_ctx.input_start_p = iterator.buf_p; re_ctx.input_end_p = iterator.buf_p + iterator.buf_size; /* 1. Read bytecode header and init regexp matcher context. */ re_ctx.flags = (uint8_t) re_get_value (&bc_p); if (ignore_global) { re_ctx.flags &= (uint8_t) ~RE_FLAG_GLOBAL; } JERRY_DDLOG ("Exec with flags [global: %d, ignoreCase: %d, multiline: %d]\n", re_ctx.flags & RE_FLAG_GLOBAL, re_ctx.flags & RE_FLAG_IGNORE_CASE, re_ctx.flags & RE_FLAG_MULTILINE); re_ctx.num_of_captures = re_get_value (&bc_p); JERRY_ASSERT (re_ctx.num_of_captures % 2 == 0); re_ctx.num_of_non_captures = re_get_value (&bc_p); /* We create an invalid iterator, that will be used to identify unused result values. */ lit_utf8_iterator_t unused_iter = lit_utf8_iterator_create (NULL, 0); unused_iter.buf_p = (lit_utf8_byte_t *) 1; MEM_DEFINE_LOCAL_ARRAY (saved_p, re_ctx.num_of_captures + re_ctx.num_of_non_captures, lit_utf8_iterator_t); for (uint32_t i = 0; i < re_ctx.num_of_captures + re_ctx.num_of_non_captures; i++) { saved_p[i] = unused_iter; } re_ctx.saved_p = saved_p; uint32_t num_of_iter_length = (re_ctx.num_of_captures / 2) + (re_ctx.num_of_non_captures - 1); MEM_DEFINE_LOCAL_ARRAY (num_of_iter_p, num_of_iter_length, uint32_t); for (uint32_t i = 0; i < num_of_iter_length; i++) { num_of_iter_p[i] = 0u; } bool is_match = false; re_ctx.num_of_iterations_p = num_of_iter_p; int32_t index = 0; ecma_length_t input_str_len = lit_utf8_string_length (iterator.buf_p, iterator.buf_size); if (iterator.buf_p && (re_ctx.flags & RE_FLAG_GLOBAL)) { ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_property_t *lastindex_prop_p = ecma_op_object_get_property (regexp_object_p, magic_str_p); ECMA_OP_TO_NUMBER_TRY_CATCH (lastindex_num, lastindex_prop_p->u.named_data_property.value, ret_value) index = ecma_number_to_int32 (lastindex_num); JERRY_ASSERT (iterator.buf_pos.offset == 0 && !iterator.buf_pos.is_non_bmp_middle); if (!lit_utf8_iterator_is_eos (&iterator) && index <= (int32_t) input_str_len && index > 0) { lit_utf8_iterator_advance (&iterator, (ecma_length_t) index); } ECMA_OP_TO_NUMBER_FINALIZE (lastindex_num); ecma_deref_ecma_string (magic_str_p); } /* 2. Try to match */ lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); while (ecma_is_completion_value_empty (ret_value)) { if (index < 0 || index > (int32_t) input_str_len) { if (re_ctx.flags & RE_FLAG_GLOBAL) { ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_number_t *lastindex_num_p = ecma_alloc_number (); *lastindex_num_p = ECMA_NUMBER_ZERO; ecma_op_object_put (regexp_object_p, magic_str_p, ecma_make_number_value (lastindex_num_p), true); ecma_dealloc_number (lastindex_num_p); ecma_deref_ecma_string (magic_str_p); } is_match = false; break; } else { ECMA_TRY_CATCH (match_value, re_match_regexp (&re_ctx, bc_p, iterator, &sub_iter), ret_value); if (ecma_is_value_true (match_value)) { is_match = true; break; } if (!lit_utf8_iterator_is_eos (&iterator)) { lit_utf8_iterator_advance (&iterator, 1); } index++; ECMA_FINALIZE (match_value); } } if (iterator.buf_p && (re_ctx.flags & RE_FLAG_GLOBAL)) { ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_number_t *lastindex_num_p = ecma_alloc_number (); *lastindex_num_p = sub_iter.buf_pos.offset; ecma_op_object_put (regexp_object_p, magic_str_p, ecma_make_number_value (lastindex_num_p), true); ecma_dealloc_number (lastindex_num_p); ecma_deref_ecma_string (magic_str_p); } /* 3. Fill the result array or return with 'undefiend' */ if (ecma_is_completion_value_empty (ret_value)) { if (is_match) { ecma_completion_value_t result_array = ecma_op_create_array_object (0, 0, false); ecma_object_t *result_array_obj_p = ecma_get_object_from_completion_value (result_array); ecma_string_t *input_str_p = ecma_new_ecma_string_from_utf8 (iterator.buf_p, iterator.buf_size); re_set_result_array_properties (result_array_obj_p, input_str_p, re_ctx.num_of_captures / 2, index); ecma_deref_ecma_string (input_str_p); for (uint32_t i = 0; i < re_ctx.num_of_captures; i += 2) { ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (i / 2); /* Note: 'iter_p->buf_p == NULL' means the input is empty string */ if ((re_ctx.saved_p[i].buf_p != unused_iter.buf_p && re_ctx.saved_p[i + 1].buf_p != unused_iter.buf_p) && re_ctx.saved_p[i + 1].buf_pos.offset >= re_ctx.saved_p[i].buf_pos.offset) { ecma_length_t capture_str_len; capture_str_len = (ecma_length_t) re_ctx.saved_p[i + 1].buf_pos.offset - re_ctx.saved_p[i].buf_pos.offset; ecma_string_t *capture_str_p; if (capture_str_len > 0) { const lit_utf8_byte_t *utf8_str_p = re_ctx.saved_p[i].buf_p + re_ctx.saved_p[i].buf_pos.offset; capture_str_p = ecma_new_ecma_string_from_utf8 (utf8_str_p, capture_str_len); } else { capture_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); } ecma_op_object_put (result_array_obj_p, index_str_p, ecma_make_string_value (capture_str_p), true); ecma_deref_ecma_string (capture_str_p); } else { ecma_op_object_put (result_array_obj_p, index_str_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), true); } ecma_deref_ecma_string (index_str_p); } ret_value = result_array; } else { ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL)); } } MEM_FINALIZE_LOCAL_ARRAY (num_of_iter_p); MEM_FINALIZE_LOCAL_ARRAY (saved_p); MEM_FINALIZE_LOCAL_ARRAY (input_utf8_buffer_p); return ret_value; } /* ecma_regexp_exec_helper */
/** * The RegExp.prototype object's 'compile' routine * * See also: * ECMA-262 v5, B.2.5.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument */ ecma_value_t pattern_arg, /**< pattern or RegExp object */ ecma_value_t flags_arg) /**< flags */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg); if (ecma_object_get_class_name (this_obj_p) != LIT_MAGIC_STRING_REGEXP_UL) { /* Compile can only be called on RegExp objects. */ ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_string_t *pattern_string_p = NULL; uint16_t flags = 0; if (ecma_is_value_object (pattern_arg) && ecma_object_get_class_name (ecma_get_object_from_value (pattern_arg)) == LIT_MAGIC_STRING_REGEXP_UL) { if (!ecma_is_value_undefined (flags_arg)) { ret_value = ecma_raise_type_error ("Invalid argument of RegExp compile."); } else { /* Compile from existing RegExp pbject. */ ecma_object_t *target_p = ecma_get_object_from_value (pattern_arg); /* Get source. */ ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE); ecma_property_t *prop_p = ecma_get_named_data_property (target_p, magic_string_p); pattern_string_p = ecma_get_string_from_value (ecma_get_named_data_property_value (prop_p)); ecma_deref_ecma_string (magic_string_p); /* Get flags. */ magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL); prop_p = ecma_get_named_data_property (target_p, magic_string_p); if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p))) { flags |= RE_FLAG_GLOBAL; } ecma_deref_ecma_string (magic_string_p); magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL); prop_p = ecma_get_named_data_property (target_p, magic_string_p); if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p))) { flags |= RE_FLAG_IGNORE_CASE; } ecma_deref_ecma_string (magic_string_p); magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE); prop_p = ecma_get_named_data_property (target_p, magic_string_p); if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p))) { flags |= RE_FLAG_MULTILINE; } ecma_deref_ecma_string (magic_string_p); /* Get bytecode property. */ ecma_property_t *bc_prop_p = ecma_get_internal_property (this_obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); /* FIXME: "We currently have to re-compile the bytecode, because * we can't copy it without knowing its length." */ re_compiled_code_t *new_bc_p = NULL; ecma_completion_value_t bc_comp = re_compile_bytecode (&new_bc_p, pattern_string_p, flags); /* Should always succeed, since we're compiling from a source that has been compiled previously. */ JERRY_ASSERT (ecma_is_completion_value_empty (bc_comp)); re_compiled_code_t *old_bc_p = ECMA_GET_POINTER (re_compiled_code_t, bc_prop_p->u.internal_property.value); if (old_bc_p != NULL) { /* Free the old bytecode */ ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p); } ECMA_SET_POINTER (bc_prop_p->u.internal_property.value, new_bc_p); re_initialize_props (this_obj_p, pattern_string_p, flags); ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); } } else { /* Get source string. */ if (!ecma_is_value_undefined (pattern_arg)) { ECMA_TRY_CATCH (regexp_str_value, ecma_op_to_string (pattern_arg), ret_value); if (ecma_string_get_length (ecma_get_string_from_value (regexp_str_value)) == 0) { pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP); } else { pattern_string_p = ecma_copy_or_ref_ecma_string (ecma_get_string_from_value (regexp_str_value)); } ECMA_FINALIZE (regexp_str_value); } else { pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP); } /* Parse flags. */ if (ecma_is_completion_value_empty (ret_value) && !ecma_is_value_undefined (flags_arg)) { ECMA_TRY_CATCH (flags_str_value, ecma_op_to_string (flags_arg), ret_value); ECMA_TRY_CATCH (flags_dummy, re_parse_regexp_flags (ecma_get_string_from_value (flags_str_value), &flags), ret_value); ECMA_FINALIZE (flags_dummy); ECMA_FINALIZE (flags_str_value); } if (ecma_is_completion_value_empty (ret_value)) { ecma_property_t *bc_prop_p = ecma_get_internal_property (this_obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); /* Try to compile bytecode from new source. */ re_compiled_code_t *new_bc_p = NULL; ECMA_TRY_CATCH (bc_dummy, re_compile_bytecode (&new_bc_p, pattern_string_p, flags), ret_value); re_compiled_code_t *old_bc_p = ECMA_GET_POINTER (re_compiled_code_t, bc_prop_p->u.internal_property.value); if (old_bc_p != NULL) { /* Free the old bytecode */ ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p); } ECMA_SET_POINTER (bc_prop_p->u.internal_property.value, new_bc_p); re_initialize_props (this_obj_p, pattern_string_p, flags); ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); ECMA_FINALIZE (bc_dummy); } if (pattern_string_p != NULL) { ecma_deref_ecma_string (pattern_string_p); } } } return ret_value; } /* ecma_builtin_regexp_prototype_compile */
/** * Setup variables for arguments listed in formal parameter list, * and, if necessary, Arguments object with 'arguments' binding. * * See also: * Declaration binding instantiation (ECMA-262 v5, 10.5), block 4 and 7 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ static ecma_completion_value_t ecma_function_call_setup_args_variables (ecma_object_t *func_obj_p, /**< Function object */ ecma_object_t *env_p, /**< lexical environment */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len, /**< length of argument list */ bool is_strict, /**< flag indicating strict mode */ bool do_instantiate_arguments_object) /**< flag indicating whether * Arguments object should be * instantiated */ { ecma_property_t *formal_parameters_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS); ecma_collection_header_t *formal_parameters_p; formal_parameters_p = ECMA_GET_POINTER (ecma_collection_header_t, formal_parameters_prop_p->u.internal_property.value); if (formal_parameters_p != NULL) { ecma_length_t formal_parameters_count = formal_parameters_p->unit_number; ecma_collection_iterator_t formal_params_iterator; ecma_collection_iterator_init (&formal_params_iterator, formal_parameters_p); /* * Formal parameter list is stored in reversed order * * Although, specification defines ascending order of formal parameters list enumeration, * implementation enumerates the parameters in descending order. * * In the case, redundant SetMutableBinding invocation could be avoided. */ for (ssize_t n = (ssize_t) formal_parameters_count - 1; n >= 0; n--) { ecma_value_t v; if (n >= (ssize_t) arguments_list_len) { v = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else { v = arguments_list_p[n]; } bool is_moved = ecma_collection_iterator_next (&formal_params_iterator); JERRY_ASSERT (is_moved); ecma_value_t formal_parameter_name_value = *formal_params_iterator.current_value_p; ecma_string_t *formal_parameter_name_string_p = ecma_get_string_from_value (formal_parameter_name_value); bool arg_already_declared = ecma_op_has_binding (env_p, formal_parameter_name_string_p); if (!arg_already_declared) { ecma_completion_value_t completion = ecma_op_create_mutable_binding (env_p, formal_parameter_name_string_p, false); if (ecma_is_completion_value_throw (completion)) { return completion; } JERRY_ASSERT (ecma_is_completion_value_empty (completion)); completion = ecma_op_set_mutable_binding (env_p, formal_parameter_name_string_p, v, is_strict); if (ecma_is_completion_value_throw (completion)) { return completion; } JERRY_ASSERT (ecma_is_completion_value_empty (completion)); } } } if (do_instantiate_arguments_object) { /* * According to ECMA-262 v5, 10.5, the Arguments object should be instantiated * after instantiating declared functions, and only if there is no binding named 'arguments' * by that time. * * However, we can setup Arguments object and 'arguments' binding here, because: * - instantiation of Arguments object itself doesn't have any side effects; * - if 'arguments' is name of a declared function in current scope, * value of the binding would be overwritten, execution would proceed in correct state. * - declaration of function, named 'arguments', is considered to be unrecommended (and so, rare) case, * so instantiation of Arguments object here, in general, is supposed to not affect resource consumption * significantly. */ ecma_string_t *arguments_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); bool binding_already_declared = ecma_op_has_binding (env_p, arguments_string_p); if (!binding_already_declared) { ecma_object_t *args_obj_p = ecma_op_create_arguments_object (func_obj_p, env_p, formal_parameters_p, arguments_list_p, arguments_list_len, is_strict); if (is_strict) { ecma_op_create_immutable_binding (env_p, arguments_string_p); ecma_op_initialize_immutable_binding (env_p, arguments_string_p, ecma_make_object_value (args_obj_p)); } else { ecma_completion_value_t completion = ecma_op_create_mutable_binding (env_p, arguments_string_p, false); JERRY_ASSERT (ecma_is_completion_value_empty (completion)); completion = ecma_op_set_mutable_binding (env_p, arguments_string_p, ecma_make_object_value (args_obj_p), false); JERRY_ASSERT (ecma_is_completion_value_empty (completion)); } ecma_deref_object (args_obj_p); } ecma_deref_ecma_string (arguments_string_p); } return ecma_make_empty_completion_value (); } /* ecma_function_call_setup_args_variables */