/* Copyright 2014 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** \addtogroup ecma ---TODO--- * @{ * * \addtogroup ecmahelpers Helpers for operations with ECMA data types * @{ */ #include "ecma-alloc.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" #include "jerry-libc.h" /** * Compress pointer. */ uintptr_t ecma_compress_pointer(void *pointer) /**< pointer to compress */ { if ( pointer == NULL ) { return ECMA_NULL_POINTER; } uintptr_t int_ptr = (uintptr_t) pointer; JERRY_ASSERT(int_ptr % MEM_ALIGNMENT == 0); int_ptr -= mem_get_base_pointer(); int_ptr >>= MEM_ALIGNMENT_LOG; JERRY_ASSERT((int_ptr & ~((1u << ECMA_POINTER_FIELD_WIDTH) - 1)) == 0); return int_ptr; } /* ecma_compress_pointer */ /** * Decompress pointer. */ void* ecma_decompress_pointer(uintptr_t compressed_pointer) /**< pointer to decompress */ { if ( compressed_pointer == ECMA_NULL_POINTER ) { return NULL; } uintptr_t int_ptr = compressed_pointer; int_ptr <<= MEM_ALIGNMENT_LOG; int_ptr += mem_get_base_pointer(); return (void*) int_ptr; } /* ecma_decompress_pointer */ /** * Create an object with specified prototype object * (or NULL prototype if there is not prototype for the object) * and value of 'Extensible' attribute. * * Reference counter's value will be set to one. * * @return pointer to the object's descriptor */ ecma_object_t* ecma_create_object( ecma_object_t *prototype_object_p, /**< pointer to prototybe of the object (or NULL) */ bool is_extensible, /**< value of extensible attribute */ ecma_object_type_t type) /**< object type */ { ecma_object_t *object_p = ecma_alloc_object(); object_p->properties_p = ECMA_NULL_POINTER; object_p->is_lexical_environment = false; object_p->GCInfo.is_object_valid = true; /* The global object is always referenced * (at least with the ctx_GlobalObject variable) */ object_p->GCInfo.u.refs = 1; object_p->u.object.extensible = is_extensible; ecma_set_pointer( object_p->u.object.prototype_object_p, prototype_object_p); object_p->u.object.type = type; return object_p; } /* ecma_create_object */ /** * Create a declarative lexical environment with specified outer lexical environment * (or NULL if the environment is not nested). * * See also: ECMA-262 v5, 10.2.1.1 * * Reference counter's value will be set to one. * * @return pointer to the descriptor of lexical environment */ ecma_object_t* ecma_create_decl_lex_env(ecma_object_t *outer_lexical_environment_p) /**< outer lexical environment */ { ecma_object_t *new_lexical_environment_p = ecma_alloc_object(); new_lexical_environment_p->is_lexical_environment = true; new_lexical_environment_p->u.lexical_environment.type = ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE; new_lexical_environment_p->properties_p = ECMA_NULL_POINTER; new_lexical_environment_p->GCInfo.is_object_valid = true; new_lexical_environment_p->GCInfo.u.refs = 1; if ( outer_lexical_environment_p != NULL ) { ecma_ref_object( outer_lexical_environment_p); } ecma_set_pointer( new_lexical_environment_p->u.lexical_environment.outer_reference_p, outer_lexical_environment_p); return new_lexical_environment_p; } /* ecma_create_decl_lex_env */ /** * Create a declarative lexical environment with specified outer lexical environment * (or NULL if the environment is not nested). * * See also: ECMA-262 v5, 10.2.1.2 * * Reference counter's value will be set to one. * * @return pointer to the descriptor of lexical environment */ ecma_object_t* ecma_create_object_lex_env(ecma_object_t *outer_lexical_environment_p, /**< outer lexical environment */ ecma_object_t *binding_obj_p, /**< binding object */ bool provide_this) /**< provideThis flag */ { JERRY_ASSERT( binding_obj_p != NULL ); ecma_object_t *new_lexical_environment_p = ecma_alloc_object(); new_lexical_environment_p->is_lexical_environment = true; new_lexical_environment_p->u.lexical_environment.type = ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND; new_lexical_environment_p->properties_p = ECMA_NULL_POINTER; new_lexical_environment_p->GCInfo.is_object_valid = true; new_lexical_environment_p->GCInfo.u.refs = 1; if ( outer_lexical_environment_p != NULL ) { ecma_ref_object( outer_lexical_environment_p); } ecma_set_pointer( new_lexical_environment_p->u.lexical_environment.outer_reference_p, outer_lexical_environment_p); ecma_property_t *provide_this_prop_p = ecma_create_internal_property( new_lexical_environment_p, ECMA_INTERNAL_PROPERTY_PROVIDE_THIS); provide_this_prop_p->u.internal_property.value = provide_this; ecma_property_t *binding_object_prop_p = ecma_create_internal_property( new_lexical_environment_p, ECMA_INTERNAL_PROPERTY_BINDING_OBJECT); ecma_ref_object( binding_obj_p); ecma_set_pointer( binding_object_prop_p->u.internal_property.value, binding_obj_p); return new_lexical_environment_p; } /* ecma_create_object_lex_env */ /** * Create internal property in an object and link it into * the object's properties' linked-list (at start of the list). * * @return pointer to newly created property */ ecma_property_t* ecma_create_internal_property(ecma_object_t *object_p, /**< the object */ ecma_internal_property_id_t property_id) /**< internal property identifier */ { ecma_property_t *new_property_p = ecma_alloc_property(); new_property_p->type = ECMA_PROPERTY_INTERNAL; ecma_set_pointer( new_property_p->next_property_p, ecma_get_pointer( object_p->properties_p)); ecma_set_pointer( object_p->properties_p, new_property_p); new_property_p->u.internal_property.internal_property_type = property_id; new_property_p->u.internal_property.value = ECMA_NULL_POINTER; return new_property_p; } /* ecma_create_internal_property */ /** * 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 ); for ( ecma_property_t *property_p = ecma_get_pointer( object_p->properties_p); property_p != NULL; property_p = ecma_get_pointer( property_p->next_property_p) ) { if ( property_p->type == ECMA_PROPERTY_INTERNAL ) { if ( property_p->u.internal_property.internal_property_type == property_id ) { return property_p; } } } return NULL; } /* ecma_find_internal_property */ /** * Get an internal property. * * Warning: * the property must exist * * @return pointer to the property */ ecma_property_t* ecma_get_internal_property(ecma_object_t *object_p, /**< object descriptor */ ecma_internal_property_id_t property_id) /**< internal property identifier */ { ecma_property_t *property_p = ecma_find_internal_property( object_p, property_id); JERRY_ASSERT( property_p != NULL ); return property_p; } /* ecma_get_internal_property */ /** * Create named data property with given name, attributes and undefined value * in the specified object. * * @return pointer to newly created property */ ecma_property_t* ecma_create_named_data_property(ecma_object_t *obj_p, /**< object */ const ecma_char_t *name_p, /**< property name */ ecma_property_writable_value_t writable, /**< 'writable' attribute */ ecma_property_enumerable_value_t enumerable, /**< 'enumerable' attribute */ ecma_property_configurable_value_t configurable) /**< 'configurable' attribute */ { JERRY_ASSERT( obj_p != NULL && name_p != NULL ); ecma_property_t *prop = ecma_alloc_property(); prop->type = ECMA_PROPERTY_NAMEDDATA; ecma_set_pointer( prop->u.named_data_property.name_p, ecma_new_ecma_string( name_p)); prop->u.named_data_property.writable = writable; prop->u.named_data_property.enumerable = enumerable; prop->u.named_data_property.configurable = configurable; prop->u.named_data_property.value = ecma_make_simple_value( ECMA_SIMPLE_VALUE_UNDEFINED); ecma_set_pointer( prop->next_property_p, ecma_get_pointer( obj_p->properties_p)); ecma_set_pointer( obj_p->properties_p, prop); return prop; } /* ecma_create_named_data_property */ /** * Create named accessor property with given name, attributes, getter and setter. * * @return pointer to newly created property */ ecma_property_t* ecma_create_named_accessor_property(ecma_object_t *obj_p, /**< object */ const ecma_char_t *name_p, /**< property name */ ecma_object_t *get_p, /**< getter */ ecma_object_t *set_p, /**< setter */ ecma_property_enumerable_value_t enumerable, /**< 'enumerable' attribute */ ecma_property_configurable_value_t configurable) /**< 'configurable' attribute */ { JERRY_ASSERT( obj_p != NULL && name_p != NULL ); ecma_property_t *prop_p = ecma_alloc_property(); prop_p->type = ECMA_PROPERTY_NAMEDACCESSOR; ecma_set_pointer( prop_p->u.named_accessor_property.name_p, ecma_new_ecma_string( name_p)); ecma_set_pointer( prop_p->u.named_accessor_property.get_p, get_p); ecma_set_pointer( prop_p->u.named_accessor_property.set_p, set_p); prop_p->u.named_accessor_property.enumerable = enumerable; prop_p->u.named_accessor_property.configurable = configurable; ecma_set_pointer( prop_p->next_property_p, ecma_get_pointer( obj_p->properties_p)); ecma_set_pointer( obj_p->properties_p, prop_p); return prop_p; } /* ecma_create_named_accessor_property */ /** * 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 */ const ecma_char_t *name_p) /**< property's name */ { JERRY_ASSERT( obj_p != NULL ); JERRY_ASSERT( name_p != NULL ); for ( ecma_property_t *property_p = ecma_get_pointer( obj_p->properties_p); property_p != NULL; property_p = ecma_get_pointer( property_p->next_property_p) ) { ecma_array_first_chunk_t *property_name_p; if ( property_p->type == ECMA_PROPERTY_NAMEDDATA ) { property_name_p = ecma_get_pointer( property_p->u.named_data_property.name_p); } else if ( property_p->type == ECMA_PROPERTY_NAMEDACCESSOR ) { property_name_p = ecma_get_pointer( property_p->u.named_accessor_property.name_p); } else { continue; } JERRY_ASSERT( property_name_p != NULL ); if ( ecma_compare_zt_string_to_ecma_string( name_p, property_name_p) ) { return property_p; } } return NULL; } /* ecma_find_named_property */ /** * Get named data property or named access property in specified object. * * Warning: * the property must exist * * @return pointer to the property, if it is found, * NULL - otherwise. */ ecma_property_t* ecma_get_named_property(ecma_object_t *obj_p, /**< object to find property in */ const ecma_char_t *name_p) /**< property's name */ { JERRY_ASSERT( obj_p != NULL ); JERRY_ASSERT( name_p != NULL ); ecma_property_t *property_p = ecma_find_named_property( obj_p, name_p); JERRY_ASSERT( property_p != NULL ); return property_p; } /* ecma_get_named_property */ /** * Get named data property in specified object. * * Warning: * the property must exist and be named data property * * @return pointer to the property, if it is found, * NULL - otherwise. */ ecma_property_t* ecma_get_named_data_property(ecma_object_t *obj_p, /**< object to find property in */ const ecma_char_t *name_p) /**< property's name */ { JERRY_ASSERT( obj_p != NULL ); JERRY_ASSERT( name_p != NULL ); ecma_property_t *property_p = ecma_find_named_property( obj_p, name_p); JERRY_ASSERT( property_p != NULL && property_p->type == ECMA_PROPERTY_NAMEDDATA ); return property_p; } /* ecma_get_named_data_property */ /** * Free the named data property and values it references. */ void ecma_free_named_data_property( ecma_property_t *property_p) /**< the property */ { JERRY_ASSERT( property_p->type == ECMA_PROPERTY_NAMEDDATA ); ecma_free_array( ecma_get_pointer( property_p->u.named_data_property.name_p)); ecma_free_value( property_p->u.named_data_property.value); ecma_dealloc_property( property_p); } /* ecma_free_named_data_property */ /** * Free the named accessor property and values it references. */ void ecma_free_named_accessor_property( ecma_property_t *property_p) /**< the property */ { JERRY_ASSERT( property_p->type == ECMA_PROPERTY_NAMEDACCESSOR ); ecma_free_array( ecma_get_pointer( property_p->u.named_accessor_property.name_p)); ecma_object_t *get_p = ecma_get_pointer(property_p->u.named_accessor_property.get_p); ecma_object_t *set_p = ecma_get_pointer(property_p->u.named_accessor_property.set_p); if ( get_p != NULL ) { ecma_deref_object( get_p); } if ( set_p != NULL ) { ecma_deref_object( set_p); } ecma_dealloc_property( property_p); } /* ecma_free_named_accessor_property */ /** * Free the internal property and values it references. */ void ecma_free_internal_property( ecma_property_t *property_p) /**< the property */ { JERRY_ASSERT( property_p->type == ECMA_PROPERTY_INTERNAL ); ecma_internal_property_id_t property_id = property_p->u.internal_property.internal_property_type; uint32_t property_value = property_p->u.internal_property.value; switch ( property_id ) { case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* an array */ case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* an array */ case ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS: /* an array */ { ecma_free_array( ecma_get_pointer( property_value)); break; } case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ case ECMA_INTERNAL_PROPERTY_BINDING_OBJECT: /* an object */ { ecma_deref_object( ecma_get_pointer( property_value)); break; } 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_PROVIDE_THIS: /* a boolean */ case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */ case ECMA_INTERNAL_PROPERTY_CODE: /* an integer */ { break; } } ecma_dealloc_property( property_p); } /* ecma_free_internal_property */ /** * Free the property and values it references. */ void ecma_free_property(ecma_property_t *prop_p) /**< property */ { switch ( (ecma_property_type_t) prop_p->type ) { case ECMA_PROPERTY_NAMEDDATA: { ecma_free_named_data_property( prop_p); break; } case ECMA_PROPERTY_NAMEDACCESSOR: { ecma_free_named_accessor_property( prop_p); break; } case ECMA_PROPERTY_INTERNAL: { ecma_free_internal_property( prop_p); break; } } } /* ecma_free_property */ /** * Delete the object's property. * * Warning: specified property must be owned by specified object. */ void ecma_delete_property(ecma_object_t *obj_p, /**< object */ ecma_property_t *prop_p) /**< property */ { for ( ecma_property_t *cur_prop_p = ecma_get_pointer( obj_p->properties_p), *prev_prop_p = NULL, *next_prop_p; cur_prop_p != NULL; prev_prop_p = cur_prop_p, cur_prop_p = next_prop_p ) { next_prop_p = ecma_get_pointer( cur_prop_p->next_property_p); if ( cur_prop_p == prop_p ) { ecma_free_property( prop_p); if ( prev_prop_p == NULL ) { ecma_set_pointer( obj_p->properties_p, next_prop_p); } else { ecma_set_pointer( prev_prop_p->next_property_p, next_prop_p); } return; } } JERRY_UNREACHABLE(); } /* ecma_delete_property */ /** * Allocate new ecma-string and fill it with characters from specified buffer * * @return Pointer to first chunk of an array, containing allocated string */ ecma_array_first_chunk_t* ecma_new_ecma_string(const ecma_char_t *string_p) /**< zero-terminated string of ecma-characters */ { ecma_length_t length = 0; /* * TODO: Do not precalculate length. */ if ( string_p != NULL ) { const ecma_char_t *iter_p = string_p; while ( *iter_p++ ) { length++; } } ecma_array_first_chunk_t *string_first_chunk_p = ecma_alloc_array_first_chunk(); string_first_chunk_p->header.unit_number = length; uint8_t *copy_pointer = (uint8_t*) string_p; size_t chars_left = length; size_t chars_to_copy = JERRY_MIN( length, sizeof (string_first_chunk_p->data) / sizeof (ecma_char_t)); __memcpy(string_first_chunk_p->data, copy_pointer, chars_to_copy * sizeof (ecma_char_t)); chars_left -= chars_to_copy; copy_pointer += chars_to_copy * sizeof (ecma_char_t); ecma_array_non_first_chunk_t *string_non_first_chunk_p; JERRY_STATIC_ASSERT( ECMA_POINTER_FIELD_WIDTH <= sizeof(uint16_t) * JERRY_BITSINBYTE ); uint16_t *next_chunk_compressed_pointer_p = &string_first_chunk_p->header.next_chunk_p; while ( chars_left > 0 ) { string_non_first_chunk_p = ecma_alloc_array_non_first_chunk(); size_t chars_to_copy = JERRY_MIN( chars_left, sizeof (string_non_first_chunk_p->data) / sizeof (ecma_char_t)); __memcpy(string_non_first_chunk_p->data, copy_pointer, chars_to_copy * sizeof (ecma_char_t)); chars_left -= chars_to_copy; copy_pointer += chars_to_copy * sizeof (ecma_char_t); ecma_set_pointer( *next_chunk_compressed_pointer_p, string_non_first_chunk_p); next_chunk_compressed_pointer_p = &string_non_first_chunk_p->next_chunk_p; } *next_chunk_compressed_pointer_p = ECMA_NULL_POINTER; return string_first_chunk_p; } /* ecma_new_ecma_string */ /** * Copy ecma-string's contents to a buffer. * * Buffer will contain length of string, in characters, followed by string's characters. * * @return number of bytes, actually copied to the buffer, if string's content was copied successfully; * negative number, which is calculated as negation of buffer size, that is required * to hold the string's content (in case size of buffer is insuficcient). */ ssize_t ecma_copy_ecma_string_chars_to_buffer(ecma_array_first_chunk_t *first_chunk_p, /**< first chunk of ecma-string */ uint8_t *buffer_p, /**< destination buffer */ size_t buffer_size) /**< size of buffer */ { ecma_length_t string_length = first_chunk_p->header.unit_number; size_t required_buffer_size = sizeof (ecma_length_t) + sizeof (ecma_char_t) * string_length; if ( required_buffer_size < buffer_size ) { return -(ssize_t) required_buffer_size; } *(ecma_length_t*) buffer_p = string_length; size_t chars_left = string_length; uint8_t *dest_pointer = buffer_p + sizeof (ecma_length_t); size_t copy_chunk_chars = JERRY_MIN(sizeof (first_chunk_p->data) / sizeof (ecma_char_t), chars_left); __memcpy( dest_pointer, first_chunk_p->data, copy_chunk_chars * sizeof (ecma_char_t)); dest_pointer += copy_chunk_chars * sizeof (ecma_char_t); chars_left -= copy_chunk_chars; ecma_array_non_first_chunk_t *non_first_chunk_p = ecma_get_pointer( first_chunk_p->header.next_chunk_p); while ( chars_left > 0 ) { JERRY_ASSERT( chars_left < string_length ); copy_chunk_chars = JERRY_MIN(sizeof (non_first_chunk_p->data) / sizeof (ecma_char_t), chars_left); __memcpy( dest_pointer, non_first_chunk_p->data, copy_chunk_chars * sizeof (ecma_char_t)); dest_pointer += copy_chunk_chars * sizeof (ecma_char_t); chars_left -= copy_chunk_chars; non_first_chunk_p = ecma_get_pointer( non_first_chunk_p->next_chunk_p); } return (ssize_t) required_buffer_size; } /* ecma_copy_ecma_string_chars_to_buffer */ /** * Duplicate an ecma-string. * * @return pointer to new ecma-string's first chunk */ ecma_array_first_chunk_t* ecma_duplicate_ecma_string( ecma_array_first_chunk_t *first_chunk_p) /**< first chunk of string to duplicate */ { JERRY_ASSERT( first_chunk_p != NULL ); ecma_array_first_chunk_t *first_chunk_copy_p = ecma_alloc_array_first_chunk(); __memcpy( first_chunk_copy_p, first_chunk_p, sizeof (ecma_array_first_chunk_t)); ecma_array_non_first_chunk_t *non_first_chunk_p, *non_first_chunk_copy_p; non_first_chunk_p = ecma_get_pointer( first_chunk_p->header.next_chunk_p); uint16_t *next_pointer_p = &first_chunk_copy_p->header.next_chunk_p; while ( non_first_chunk_p != NULL ) { non_first_chunk_copy_p = ecma_alloc_array_non_first_chunk(); ecma_set_pointer( *next_pointer_p, non_first_chunk_copy_p); next_pointer_p = &non_first_chunk_copy_p->next_chunk_p; __memcpy( non_first_chunk_copy_p, non_first_chunk_p, sizeof (ecma_array_non_first_chunk_t)); non_first_chunk_p = ecma_get_pointer( non_first_chunk_p->next_chunk_p); } *next_pointer_p = ECMA_NULL_POINTER; return first_chunk_copy_p; } /* ecma_duplicate_ecma_string */ /** * Compare zero-terminated string to ecma-string * * @return true - if strings are equal; * false - otherwise. */ bool ecma_compare_ecma_string_to_ecma_string(const ecma_array_first_chunk_t *string1_p, /* ecma-string */ const ecma_array_first_chunk_t *string2_p) /* ecma-string */ { JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( string1_p, string2_p); } /* ecma_compare_ecma_string_to_ecma_string */ /** * Compare zero-terminated string to ecma-string * * @return true - if strings are equal; * false - otherwise. */ bool ecma_compare_zt_string_to_ecma_string(const ecma_char_t *string_p, /**< zero-terminated string */ const ecma_array_first_chunk_t *ecma_string_p) /* ecma-string */ { JERRY_ASSERT( string_p != NULL ); JERRY_ASSERT( ecma_string_p != NULL ); const ecma_char_t *str_iter_p = string_p; ecma_length_t ecma_str_len = ecma_string_p->header.unit_number; const ecma_char_t *current_chunk_chars_cur = (const ecma_char_t*) ecma_string_p->data, *current_chunk_chars_end = (const ecma_char_t*) (ecma_string_p->data + sizeof(ecma_string_p->data)); JERRY_STATIC_ASSERT( ECMA_POINTER_FIELD_WIDTH <= sizeof(uint16_t) * JERRY_BITSINBYTE ); const uint16_t *next_chunk_compressed_pointer_p = &ecma_string_p->header.next_chunk_p; for ( ecma_length_t str_index = 0; str_index < ecma_str_len; str_index++, str_iter_p++, current_chunk_chars_cur++ ) { JERRY_ASSERT( current_chunk_chars_cur <= current_chunk_chars_end ); if ( current_chunk_chars_cur == current_chunk_chars_end ) { /* switching to next chunk */ ecma_array_non_first_chunk_t *next_chunk_p = ecma_get_pointer( *next_chunk_compressed_pointer_p); JERRY_ASSERT( next_chunk_p != NULL ); current_chunk_chars_cur = (const ecma_char_t*) ecma_string_p->data; current_chunk_chars_end = (const ecma_char_t*) (next_chunk_p->data + sizeof(next_chunk_p->data)); next_chunk_compressed_pointer_p = &next_chunk_p->next_chunk_p; } if ( *str_iter_p != *current_chunk_chars_cur ) { /* * Either *str_iter_p is 0 (zero-terminated string is shorter), * or the character is just different. * * In both cases strings are not equal. */ return false; } } /* * Now, we have reached end of ecma-string. * * If we have also reached end of zero-terminated string, than strings are equal. * Otherwise zero-terminated string is longer. */ return ( *str_iter_p == 0 ); } /* ecma_compare_zt_string_to_ecma_string */ /** * Free all chunks of an array */ void ecma_free_array( ecma_array_first_chunk_t *first_chunk_p) /**< first chunk of the array */ { JERRY_ASSERT( first_chunk_p != NULL ); ecma_array_non_first_chunk_t *non_first_chunk_p = ecma_get_pointer( first_chunk_p->header.next_chunk_p); ecma_dealloc_array_first_chunk( first_chunk_p); while ( non_first_chunk_p != NULL ) { ecma_array_non_first_chunk_t *next_chunk_p = ecma_get_pointer( non_first_chunk_p->next_chunk_p); ecma_dealloc_array_non_first_chunk( non_first_chunk_p); non_first_chunk_p = next_chunk_p; } } /* ecma_free_array */ /** * Construct empty property descriptor. * * @return property descriptor with all *_defined properties set to false, * and rest properties set to default values (ECMA-262 v5, Table 7). */ ecma_property_descriptor_t ecma_make_empty_property_descriptor( void) { ecma_property_descriptor_t prop_desc = (ecma_property_descriptor_t) { .is_value_defined = false, .value = ecma_make_simple_value( ECMA_SIMPLE_VALUE_UNDEFINED), .is_writable_defined = false, .writable = ECMA_PROPERTY_NOT_WRITABLE, .is_enumerable_defined = false, .enumerable = ECMA_PROPERTY_NOT_ENUMERABLE, .is_configurable_defined = false, .configurable = ECMA_PROPERTY_NOT_CONFIGURABLE, .is_get_defined = false, .get_p = NULL, .is_set_defined = false, .set_p = NULL }; return prop_desc; } /* ecma_make_empty_property_descriptor */ /** * @} * @} */