Import of the watch repository from Pebble

This commit is contained in:
Matthieu Jeanson 2024-12-12 16:43:03 -08:00 committed by Katharine Berry
commit 3b92768480
10334 changed files with 2564465 additions and 0 deletions

View file

@ -0,0 +1,132 @@
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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.
*/
#include "ecma-alloc.h"
#include "ecma-globals.h"
#include "ecma-gc.h"
#include "ecma-lcache.h"
#include "jrt.h"
#include "jmem-poolman.h"
JERRY_STATIC_ASSERT (sizeof (ecma_property_value_t) == sizeof (ecma_value_t),
size_of_ecma_property_value_t_must_be_equal_to_size_of_ecma_value_t);
JERRY_STATIC_ASSERT (((sizeof (ecma_property_value_t) - 1) & sizeof (ecma_property_value_t)) == 0,
size_of_ecma_property_value_t_must_be_power_of_2);
JERRY_STATIC_ASSERT (sizeof (ecma_string_t) == sizeof (uint64_t),
size_of_ecma_string_t_must_be_less_than_or_equal_to_8_bytes);
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmaalloc Routines for allocation/freeing memory for ECMA data types
* @{
*/
/**
* Implementation of routines for allocation/freeing memory for ECMA data types.
*
* All allocation routines from this module have the same structure:
* 1. Try to allocate memory.
* 2. If allocation was successful, return pointer to the allocated block.
* 3. Run garbage collection.
* 4. Try to allocate memory.
* 5. If allocation was successful, return pointer to the allocated block;
* else - shutdown engine.
*/
/**
* Template of an allocation routine.
*/
#define ALLOC(ecma_type) ecma_ ## ecma_type ## _t * \
ecma_alloc_ ## ecma_type (void) \
{ \
ecma_ ## ecma_type ## _t *ecma_type ## _p; \
ecma_type ## _p = (ecma_ ## ecma_type ## _t *) jmem_pools_alloc (sizeof (ecma_ ## ecma_type ## _t)); \
\
JERRY_ASSERT (ecma_type ## _p != NULL); \
\
return ecma_type ## _p; \
}
/**
* Deallocation routine template
*/
#define DEALLOC(ecma_type) void \
ecma_dealloc_ ## ecma_type (ecma_ ## ecma_type ## _t *ecma_type ## _p) \
{ \
jmem_pools_free ((uint8_t *) ecma_type ## _p, sizeof (ecma_ ## ecma_type ## _t)); \
}
/**
* Declaration of alloc/free routine for specified ecma-type.
*/
#define DECLARE_ROUTINES_FOR(ecma_type) \
ALLOC (ecma_type) \
DEALLOC (ecma_type)
DECLARE_ROUTINES_FOR (object)
DECLARE_ROUTINES_FOR (number)
DECLARE_ROUTINES_FOR (collection_header)
DECLARE_ROUTINES_FOR (collection_chunk)
DECLARE_ROUTINES_FOR (string)
DECLARE_ROUTINES_FOR (getter_setter_pointers)
DECLARE_ROUTINES_FOR (external_pointer)
/**
* Allocate memory for extended object
*
* @return pointer to allocated memory
*/
inline ecma_extended_object_t * __attr_always_inline___
ecma_alloc_extended_object (void)
{
return jmem_heap_alloc_block (sizeof (ecma_extended_object_t));
} /* ecma_alloc_extended_object */
/**
* Dealloc memory of an extended object
*/
inline void __attr_always_inline___
ecma_dealloc_extended_object (ecma_extended_object_t *ext_object_p) /**< property pair to be freed */
{
jmem_heap_free_block (ext_object_p, sizeof (ecma_extended_object_t));
} /* ecma_dealloc_extended_object */
/**
* Allocate memory for ecma-property pair
*
* @return pointer to allocated memory
*/
inline ecma_property_pair_t * __attr_always_inline___
ecma_alloc_property_pair (void)
{
return jmem_heap_alloc_block (sizeof (ecma_property_pair_t));
} /* ecma_alloc_property_pair */
/**
* Dealloc memory of an ecma-property
*/
inline void __attr_always_inline___
ecma_dealloc_property_pair (ecma_property_pair_t *property_pair_p) /**< property pair to be freed */
{
jmem_heap_free_block (property_pair_p, sizeof (ecma_property_pair_t));
} /* ecma_dealloc_property_pair */
/**
* @}
* @}
*/

View file

@ -0,0 +1,141 @@
/* Copyright 2014-2016 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.
*/
#ifndef ECMA_ALLOC_H
#define ECMA_ALLOC_H
#include "ecma-globals.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmaalloc Routines for allocation/freeing memory for ECMA data types
* @{
*/
/**
* Allocate memory for ecma-object
*
* @return pointer to allocated memory
*/
extern ecma_object_t *ecma_alloc_object (void);
/**
* Dealloc memory from an ecma-object
*/
extern void ecma_dealloc_object (ecma_object_t *);
/**
* Allocate memory for ecma-number
*
* @return pointer to allocated memory
*/
extern ecma_number_t *ecma_alloc_number (void);
/**
* Dealloc memory from an ecma-number
*/
extern void ecma_dealloc_number (ecma_number_t *);
/**
* Allocate memory for header of a collection
*
* @return pointer to allocated memory
*/
extern ecma_collection_header_t *ecma_alloc_collection_header (void);
/**
* Dealloc memory from the collection's header
*/
extern void ecma_dealloc_collection_header (ecma_collection_header_t *);
/**
* Allocate memory for non-first chunk of a collection
*
* @return pointer to allocated memory
*/
extern ecma_collection_chunk_t *ecma_alloc_collection_chunk (void);
/**
* Dealloc memory from non-first chunk of a collection
*/
extern void ecma_dealloc_collection_chunk (ecma_collection_chunk_t *);
/**
* Allocate memory for ecma-string descriptor
*
* @return pointer to allocated memory
*/
extern ecma_string_t *ecma_alloc_string (void);
/**
* Dealloc memory from ecma-string descriptor
*/
extern void ecma_dealloc_string (ecma_string_t *);
/**
* Allocate memory for getter-setter pointer pair
*
* @return pointer to allocated memory
*/
extern ecma_getter_setter_pointers_t *ecma_alloc_getter_setter_pointers (void);
/**
* Dealloc memory from getter-setter pointer pair
*/
extern void ecma_dealloc_getter_setter_pointers (ecma_getter_setter_pointers_t *);
/**
* Allocate memory for external pointer
*
* @return pointer to allocated memory
*/
extern ecma_external_pointer_t *ecma_alloc_external_pointer (void);
/**
* Dealloc memory from external pointer
*/
extern void ecma_dealloc_external_pointer (ecma_external_pointer_t *);
/*
* Allocate memory for extended object
*
* @return pointer to allocated memory
*/
extern ecma_extended_object_t *ecma_alloc_extended_object (void);
/**
* Dealloc memory of an extended object
*/
extern void ecma_dealloc_extended_object (ecma_extended_object_t *);
/**
* Allocate memory for ecma-property pair
*
* @return pointer to allocated memory
*/
extern ecma_property_pair_t *ecma_alloc_property_pair (void);
/**
* Dealloc memory from an ecma-property pair
*/
extern void ecma_dealloc_property_pair (ecma_property_pair_t *);
/**
* @}
* @}
*/
#endif /* !ECMA_ALLOC_H */

View file

@ -0,0 +1,615 @@
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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.
*/
/**
* Garbage collector implementation
*/
#include "ecma-alloc.h"
#include "ecma-globals.h"
#include "ecma-gc.h"
#include "ecma-helpers.h"
#include "ecma-lcache.h"
#include "ecma-property-hashmap.h"
#include "jcontext.h"
#include "jrt.h"
#include "jrt-libc-includes.h"
#include "jrt-bit-fields.h"
#include "re-compiler.h"
#include "vm-defines.h"
#include "vm-stack.h"
#define JERRY_INTERNAL
#include "jerry-internal.h"
/* TODO: Extract GC to a separate component */
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmagc Garbage collector
* @{
*/
/**
* Current state of an object's visited flag that
* indicates whether the object is in visited state:
*
* visited_field | visited_flip_flag | real_value
* false | false | false
* false | true | true
* true | false | true
* true | true | false
*/
static void ecma_gc_mark (ecma_object_t *object_p);
static void ecma_gc_sweep (ecma_object_t *object_p);
/**
* 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 */
/**
* Set next object in list of objects with same generation.
*/
static inline void
ecma_gc_set_object_next (ecma_object_t *object_p, /**< object */
ecma_object_t *next_object_p) /**< next object */
{
JERRY_ASSERT (object_p != NULL);
ECMA_SET_POINTER (object_p->gc_next_cp, next_object_p);
} /* ecma_gc_set_object_next */
/**
* Get visited flag of the object.
*/
static inline bool
ecma_gc_is_object_visited (ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (object_p != NULL);
bool flag_value = (object_p->type_flags_refs & ECMA_OBJECT_FLAG_GC_VISITED) != 0;
return flag_value != JERRY_CONTEXT (ecma_gc_visited_flip_flag);
} /* ecma_gc_is_object_visited */
/**
* Set visited flag of the object.
*/
static inline void
ecma_gc_set_object_visited (ecma_object_t *object_p, /**< object */
bool is_visited) /**< flag value */
{
JERRY_ASSERT (object_p != NULL);
if (is_visited != JERRY_CONTEXT (ecma_gc_visited_flip_flag))
{
object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_FLAG_GC_VISITED);
}
else
{
object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & ~ECMA_OBJECT_FLAG_GC_VISITED);
}
} /* ecma_gc_set_object_visited */
/**
* Initialize GC information for the object
*/
inline void
ecma_init_gc_info (ecma_object_t *object_p) /**< object */
{
JERRY_CONTEXT (ecma_gc_objects_number)++;
JERRY_CONTEXT (ecma_gc_new_objects)++;
JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_new_objects) <= JERRY_CONTEXT (ecma_gc_objects_number));
JERRY_ASSERT (object_p->type_flags_refs < ECMA_OBJECT_REF_ONE);
object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_REF_ONE);
ecma_gc_set_object_next (object_p, JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY]);
JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY] = object_p;
/* Should be set to false at the beginning of garbage collection */
ecma_gc_set_object_visited (object_p, false);
} /* ecma_init_gc_info */
/**
* Increase reference counter of an object
*/
void
ecma_ref_object (ecma_object_t *object_p) /**< object */
{
if (likely (object_p->type_flags_refs < ECMA_OBJECT_MAX_REF))
{
object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs + ECMA_OBJECT_REF_ONE);
}
else
{
jerry_fatal (ERR_REF_COUNT_LIMIT);
}
} /* ecma_ref_object */
/**
* Decrease reference counter of an object
*/
void
ecma_deref_object (ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE);
object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs - ECMA_OBJECT_REF_ONE);
} /* ecma_deref_object */
/**
* Mark referenced object from property
*/
static void
ecma_gc_mark_property (ecma_property_t *property_p) /**< property */
{
switch (ECMA_PROPERTY_GET_TYPE (*property_p))
{
case ECMA_PROPERTY_TYPE_NAMEDDATA:
{
ecma_value_t value = ECMA_PROPERTY_VALUE_PTR (property_p)->value;
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_TYPE_NAMEDACCESSOR:
{
ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
ecma_object_t *getter_obj_p = ecma_get_named_accessor_property_getter (prop_value_p);
ecma_object_t *setter_obj_p = ecma_get_named_accessor_property_setter (prop_value_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_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_ECMA_VALUE: /* an ecma_value_t except object */
case ECMA_INTERNAL_PROPERTY_DATE_FLOAT: /* pointer to a ecma_number_t */
case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */
case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE: /* pointer to a regexp bytecode array */
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_INSTANTIATED_MASK_32_63: /* an integer (bit-mask) */
{
break;
}
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: /* an ecma value */
{
if (ecma_is_value_object (property_value))
{
ecma_object_t *obj_p = ecma_get_object_from_value (property_value);
ecma_gc_set_object_visited (obj_p, true);
}
break;
}
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS: /* a collection of ecma values */
{
ecma_collection_header_t *bound_arg_list_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_header_t,
property_value);
ecma_collection_iterator_t bound_args_iterator;
ecma_collection_iterator_init (&bound_args_iterator, bound_arg_list_p);
for (ecma_length_t i = 0; i < bound_arg_list_p->unit_number; i++)
{
bool is_moved = ecma_collection_iterator_next (&bound_args_iterator);
JERRY_ASSERT (is_moved);
if (ecma_is_value_object (*bound_args_iterator.current_value_p))
{
ecma_object_t *obj_p = ecma_get_object_from_value (*bound_args_iterator.current_value_p);
ecma_gc_set_object_visited (obj_p, true);
}
}
break;
}
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION: /* an object */
case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */
case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */
{
ecma_object_t *obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, property_value);
ecma_gc_set_object_visited (obj_p, true);
break;
}
case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type,
* but number of the real internal property types */
{
JERRY_UNREACHABLE ();
break;
}
}
break;
}
default:
{
JERRY_UNREACHABLE ();
break;
}
}
} /* ecma_gc_mark_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 */
/**
* 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 */
/**
* Run garbage collection
*/
void
ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */
{
JERRY_CONTEXT (ecma_gc_new_objects) = 0;
JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK] == NULL);
/* if some object is referenced from stack or globals (i.e. it is root), mark it */
for (ecma_object_t *obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY];
obj_iter_p != NULL;
obj_iter_p = ecma_gc_get_object_next (obj_iter_p))
{
JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p));
if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE)
{
ecma_gc_set_object_visited (obj_iter_p, true);
}
}
bool marked_anything_during_current_iteration = false;
do
{
marked_anything_during_current_iteration = false;
ecma_object_t *obj_prev_p = NULL;
ecma_object_t *obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY];
while (obj_iter_p != NULL)
{
ecma_object_t *obj_next_p = ecma_gc_get_object_next (obj_iter_p);
if (ecma_gc_is_object_visited (obj_iter_p))
{
/* Moving the object to list of marked objects */
ecma_gc_set_object_next (obj_iter_p, JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK]);
JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK] = obj_iter_p;
if (likely (obj_prev_p != NULL))
{
JERRY_ASSERT (ecma_gc_get_object_next (obj_prev_p) == obj_iter_p);
ecma_gc_set_object_next (obj_prev_p, obj_next_p);
}
else
{
JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY] = obj_next_p;
}
ecma_gc_mark (obj_iter_p);
marked_anything_during_current_iteration = true;
}
else
{
obj_prev_p = obj_iter_p;
}
obj_iter_p = obj_next_p;
}
}
while (marked_anything_during_current_iteration);
/* Sweeping objects that are currently unmarked */
ecma_object_t *obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY];
while (obj_iter_p != NULL)
{
ecma_object_t *obj_next_p = ecma_gc_get_object_next (obj_iter_p);
JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p));
ecma_gc_sweep (obj_iter_p);
obj_iter_p = obj_next_p;
}
if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH)
{
/* Remove the property hashmap of BLACK objects */
obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK];
while (obj_iter_p != NULL)
{
JERRY_ASSERT (ecma_gc_is_object_visited (obj_iter_p));
if (!ecma_is_lexical_environment (obj_iter_p)
|| ecma_get_lex_env_type (obj_iter_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_iter_p);
if (prop_iter_p != NULL
&& ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP)
{
ecma_property_hashmap_free (obj_iter_p);
}
}
obj_iter_p = ecma_gc_get_object_next (obj_iter_p);
}
}
/* Unmarking all objects */
ecma_object_t *black_objects = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK];
JERRY_CONTEXT (ecma_gc_objects_lists)[ECMA_GC_COLOR_WHITE_GRAY] = black_objects;
JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK] = NULL;
JERRY_CONTEXT (ecma_gc_visited_flip_flag) = !JERRY_CONTEXT (ecma_gc_visited_flip_flag);
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
/* Free RegExp bytecodes stored in cache */
re_cache_gc_run ();
#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
} /* ecma_gc_run */
/**
* Try to free some memory (depending on severity).
*/
void
ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity, /**< severity of the request */
size_t requested_size_bytes, /**< number of bytes to be allocated */
bool fatal_if_not_freed) /**< run-time will terminate if not enough memory is freed */
{
if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW)
{
/*
* If there is enough newly allocated objects since last GC, probably it is worthwhile to start GC now.
* Otherwise, probability to free sufficient space is considered to be low.
*/
size_t new_objects_share = CONFIG_ECMA_GC_NEW_OBJECTS_SHARE_TO_START_GC;
if (JERRY_CONTEXT (ecma_gc_new_objects) * new_objects_share > JERRY_CONTEXT (ecma_gc_objects_number))
{
ecma_gc_run (severity);
}
}
else
{
JERRY_ASSERT (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH);
/* Freeing as much memory as we currently can */
ecma_gc_run (severity);
}
} /* ecma_free_unused_memory */
/**
* @}
* @}
*/

View file

@ -0,0 +1,40 @@
/* Copyright 2014-2016 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.
*/
#ifndef ECMA_GC_H
#define ECMA_GC_H
#include "ecma-globals.h"
#include "jmem-allocator.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmagc Garbage collector
* @{
*/
extern void ecma_init_gc_info (ecma_object_t *);
extern void ecma_ref_object (ecma_object_t *);
extern void ecma_deref_object (ecma_object_t *);
extern void ecma_gc_run (jmem_free_unused_memory_severity_t);
extern void ecma_free_unused_memory (jmem_free_unused_memory_severity_t, size_t, bool);
/**
* @}
* @}
*/
#endif /* !ECMA_GC_H */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,237 @@
/* Copyright 2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged
*
* 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.
*
* This file is based on work under the following copyright and permission
* notice:
*
* Copyright (c) 2016 Marc Andrysco
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <math.h>
#include "config.h"
#include "ecma-helpers.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmahelpers Helpers for operations with ECMA data types
* @{
*/
/**
* Printing Floating-Point Numbers
*
* available at http://cseweb.ucsd.edu/~mandrysc/pub/dtoa.pdf
*/
/**
* Floating point format definitions
*/
#define ECMA_NEXT_FLOAT(value) (nextafter ((value), INFINITY))
#define ECMA_PREV_FLOAT(value) (nextafter ((value), -INFINITY))
#define ERROL0_EPSILON 0.0000001
/**
* High-precision data structure.
*/
typedef struct
{
double value; /**< value */
double offset; /**< offset */
} ecma_high_prec_t;
/**
* Normalize the number by factoring in the error.
*/
static inline void __attr_always_inline___
ecma_normalize_high_prec_data (ecma_high_prec_t *hp_data_p) /**< [in, out] float pair */
{
double val = hp_data_p->value;
hp_data_p->value += hp_data_p->offset;
hp_data_p->offset += val - hp_data_p->value;
} /* ecma_normalize_high_prec_data */
/**
* Multiply the high-precision number by ten.
*/
static inline void __attr_always_inline___
ecma_multiply_high_prec_by_10 (ecma_high_prec_t *hp_data_p) /**< [in, out] high-precision number */
{
double value = hp_data_p->value;
hp_data_p->value *= 10.0;
hp_data_p->offset *= 10.0;
double offset = hp_data_p->value;
offset -= value * 8.0;
offset -= value * 2.0;
hp_data_p->offset -= offset;
ecma_normalize_high_prec_data (hp_data_p);
} /* ecma_multiply_high_prec_by_10 */
/**
* Divide the high-precision number by ten.
*/
static void
ecma_divide_high_prec_by_10 (ecma_high_prec_t *hp_data_p) /**< [in, out] high-precision number */
{
double value = hp_data_p->value;
hp_data_p->value /= 10.0;
hp_data_p->offset /= 10.0;
value -= hp_data_p->value * 8.0;
value -= hp_data_p->value * 2.0;
hp_data_p->offset += value / 10.0;
ecma_normalize_high_prec_data (hp_data_p);
} /* ecma_divide_high_prec_by_10 */
/**
* Errol0 double to ASCII conversion, guaranteed correct but possibly not optimal.
*
* @return number of generated digits
*/
inline lit_utf8_size_t __attr_always_inline___
ecma_errol0_dtoa (double val, /**< ecma number */
lit_utf8_byte_t *buffer_p, /**< buffer to generate digits into */
int32_t *exp_p) /**< [out] exponent */
{
double power_of_10 = 1.0;
int32_t exp = 1;
/* normalize the midpoint */
ecma_high_prec_t mid;
mid.value = val;
mid.offset = 0.0;
while (((mid.value > 10.0) || ((mid.value == 10.0) && (mid.offset >= 0.0))) && (exp < 308))
{
exp++;
ecma_divide_high_prec_by_10 (&mid);
power_of_10 /= 10.0;
}
while (((mid.value < 1.0) || ((mid.value == 1.0) && (mid.offset < 0.0))) && (exp > -307))
{
exp--;
ecma_multiply_high_prec_by_10 (&mid);
power_of_10 *= 10.0;
}
ecma_high_prec_t high_bound, low_bound;
high_bound.value = mid.value;
high_bound.offset = mid.offset;
if (ECMA_NEXT_FLOAT (val) != INFINITY)
{
high_bound.offset += (ECMA_NEXT_FLOAT (val) - val) * power_of_10 / (2.0 + ERROL0_EPSILON);
}
low_bound.value = mid.value;
low_bound.offset = mid.offset + (ECMA_PREV_FLOAT (val) - val) * power_of_10 / (2.0 + ERROL0_EPSILON);
ecma_normalize_high_prec_data (&high_bound);
ecma_normalize_high_prec_data (&low_bound);
/* normalized boundaries */
while (high_bound.value > 10.0 || (high_bound.value == 10.0 && (high_bound.offset >= 0.0)))
{
exp++;
ecma_divide_high_prec_by_10 (&high_bound);
ecma_divide_high_prec_by_10 (&low_bound);
}
while (high_bound.value < 1.0 || (high_bound.value == 1.0 && (high_bound.offset < 0.0)))
{
exp--;
ecma_multiply_high_prec_by_10 (&high_bound);
ecma_multiply_high_prec_by_10 (&low_bound);
}
/* digit generation */
lit_utf8_byte_t *dst_p = buffer_p;
while (high_bound.value != 0.0 || high_bound.offset != 0.0)
{
uint8_t high_digit = (uint8_t) high_bound.value;
if ((high_bound.value == high_digit) && (high_bound.offset < 0))
{
high_digit = (uint8_t) (high_digit - 1u);
}
uint8_t low_digit = (uint8_t) low_bound.value;
if ((low_bound.value == low_digit) && (low_bound.offset < 0))
{
low_digit = (uint8_t) (low_digit - 1u);
}
if (low_digit != high_digit)
{
break;
}
*dst_p++ = (lit_utf8_byte_t) ('0' + high_digit);
high_bound.value -= high_digit;
ecma_multiply_high_prec_by_10 (&high_bound);
low_bound.value -= low_digit;
ecma_multiply_high_prec_by_10 (&low_bound);
}
double mdig = (high_bound.value + low_bound.value) / 2.0 + 0.5;
*dst_p++ = (lit_utf8_byte_t) ('0' + (uint8_t) mdig);
*exp_p = exp;
return (lit_utf8_size_t) (dst_p - buffer_p);
} /* ecma_errol0_dtoa */
/**
* @}
* @}
*/

View file

@ -0,0 +1,159 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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.
*/
#include "ecma-alloc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmahelpers Helpers for operations with ECMA data types
* @{
*/
/**
* Create internal property with specified identifier and store external pointer in the property.
*
* Note:
* property identifier should be one of the following:
* - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE;
* - ECMA_INTERNAL_PROPERTY_FREE_CALLBACK.
*
* @return true - if property was just created with specified value,
* false - otherwise, if property existed before the call, it's value was updated.
*/
bool
ecma_create_external_pointer_property (ecma_object_t *obj_p, /**< object to create property in */
ecma_internal_property_id_t id, /**< identifier of internal
* property to create */
ecma_external_pointer_t ptr_value) /**< value to store in the property */
{
JERRY_ASSERT (id == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE
|| id == ECMA_INTERNAL_PROPERTY_FREE_CALLBACK);
ecma_value_t *prop_p = ecma_find_internal_property (obj_p, id);
bool is_new = (prop_p == NULL);
if (is_new)
{
prop_p = ecma_create_internal_property (obj_p, id);
}
JERRY_STATIC_ASSERT (sizeof (uint32_t) <= sizeof (ECMA_PROPERTY_VALUE_PTR (prop_p)->value),
size_of_internal_property_value_must_be_greater_than_or_equal_to_4_bytes);
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
*prop_p = (ecma_value_t) ptr_value;
#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
ecma_external_pointer_t *handler_p;
if (is_new)
{
handler_p = ecma_alloc_external_pointer ();
ECMA_SET_NON_NULL_POINTER (*prop_p, handler_p);
}
else
{
handler_p = ECMA_GET_NON_NULL_POINTER (ecma_external_pointer_t, *prop_p);
}
*handler_p = ptr_value;
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
return is_new;
} /* ecma_create_external_pointer_property */
/**
* Get value of external pointer stored in the object's property with specified identifier
*
* Note:
* property identifier should be one of the following:
* - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE;
* - ECMA_INTERNAL_PROPERTY_FREE_CALLBACK.
*
* @return true - if property exists and it's value is returned through out_pointer_p,
* false - otherwise (value returned through out_pointer_p is NULL).
*/
bool
ecma_get_external_pointer_value (ecma_object_t *obj_p, /**< object to get property value from */
ecma_internal_property_id_t id, /**< identifier of internal property
* to get value from */
ecma_external_pointer_t *out_pointer_p) /**< [out] value of the external pointer */
{
JERRY_ASSERT (id == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE
|| id == ECMA_INTERNAL_PROPERTY_FREE_CALLBACK);
ecma_value_t *prop_p = ecma_find_internal_property (obj_p, id);
if (prop_p == NULL)
{
*out_pointer_p = (ecma_external_pointer_t) NULL;
return false;
}
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
*out_pointer_p = *prop_p;
#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
*out_pointer_p = *ECMA_GET_NON_NULL_POINTER (ecma_external_pointer_t, *prop_p);
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
return true;
} /* ecma_get_external_pointer_value */
/**
* Free memory associated with external pointer stored in the property
*
* Note:
* property identifier should be one of the following:
* - ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE;
* - ECMA_INTERNAL_PROPERTY_FREE_CALLBACK.
*/
void
ecma_free_external_pointer_in_property (ecma_property_t *prop_p) /**< internal property */
{
JERRY_ASSERT (ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (prop_p) == ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE
|| ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (prop_p) == ECMA_INTERNAL_PROPERTY_FREE_CALLBACK);
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
/* no additional memory was allocated for the pointer storage */
#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
ecma_external_pointer_t *handler_p = ECMA_GET_NON_NULL_POINTER (ecma_external_pointer_t,
ECMA_PROPERTY_VALUE_PTR (prop_p)->value);
ecma_dealloc_external_pointer (handler_p);
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
} /* ecma_free_external_pointer_in_property */
/**
* @}
* @}
*/

View file

@ -0,0 +1,737 @@
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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.
*/
#include "ecma-globals.h"
#include "ecma-helpers.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmahelpers Helpers for operations with ECMA data types
* @{
*/
JERRY_STATIC_ASSERT (sizeof (ecma_value_t) == sizeof (ecma_integer_value_t),
size_of_ecma_value_t_must_be_equal_to_the_size_of_ecma_integer_value_t);
JERRY_STATIC_ASSERT (ECMA_DIRECT_SHIFT == ECMA_VALUE_SHIFT + 1,
currently_directly_encoded_values_has_one_extra_flag);
JERRY_STATIC_ASSERT (((1 << (ECMA_DIRECT_SHIFT - 1)) | ECMA_TYPE_DIRECT) == ECMA_DIRECT_TYPE_SIMPLE_VALUE,
currently_directly_encoded_values_start_after_direct_type_simple_value);
#define ECMA_NUMBER_SIGN_POS (ECMA_NUMBER_FRACTION_WIDTH + \
ECMA_NUMBER_BIASED_EXP_WIDTH)
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint32_t),
size_of_ecma_number_t_must_be_equal_to_4_bytes);
/**
* Packing sign, fraction and biased exponent to ecma-number
*
* @return ecma-number with specified sign, biased_exponent and fraction
*/
static ecma_number_t
ecma_number_pack (bool sign, /**< sign */
uint32_t biased_exp, /**< biased exponent */
uint64_t fraction) /**< fraction */
{
JERRY_ASSERT ((biased_exp & ~((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) == 0);
JERRY_ASSERT ((fraction & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0);
uint32_t packed_value = (((sign ? 1u : 0u) << ECMA_NUMBER_SIGN_POS) |
(biased_exp << ECMA_NUMBER_FRACTION_WIDTH) |
((uint32_t) fraction));
union
{
uint32_t u32_value;
ecma_number_t float_value;
} u;
u.u32_value = packed_value;
return u.float_value;
} /* ecma_number_pack */
/**
* Unpacking sign, fraction and biased exponent from ecma-number
*/
static void
ecma_number_unpack (ecma_number_t num, /**< ecma-number */
bool *sign_p, /**< [out] sign (optional) */
uint32_t *biased_exp_p, /**< [out] biased exponent (optional) */
uint64_t *fraction_p) /**< [out] fraction (optional) */
{
union
{
uint32_t u32_value;
ecma_number_t float_value;
} u;
u.float_value = num;
uint32_t packed_value = u.u32_value;
if (sign_p != NULL)
{
*sign_p = ((packed_value >> ECMA_NUMBER_SIGN_POS) != 0);
}
if (biased_exp_p != NULL)
{
*biased_exp_p = (((packed_value) & ~(1u << ECMA_NUMBER_SIGN_POS)) >> ECMA_NUMBER_FRACTION_WIDTH);
}
if (fraction_p != NULL)
{
*fraction_p = (packed_value & ((1u << ECMA_NUMBER_FRACTION_WIDTH) - 1));
}
} /* ecma_number_unpack */
/**
* Value used to calculate exponent from biased exponent
*
* See also:
* IEEE-754 2008, 3.6, Table 3.5
*/
const int32_t ecma_number_exponent_bias = 127;
#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint64_t),
size_of_ecma_number_t_must_be_equal_to_8_bytes);
/**
* Packing sign, fraction and biased exponent to ecma-number
*
* @return ecma-number with specified sign, biased_exponent and fraction
*/
static ecma_number_t
ecma_number_pack (bool sign, /**< sign */
uint32_t biased_exp, /**< biased exponent */
uint64_t fraction) /**< fraction */
{
uint64_t packed_value = (((sign ? 1ull : 0ull) << ECMA_NUMBER_SIGN_POS) |
(((uint64_t) biased_exp) << ECMA_NUMBER_FRACTION_WIDTH) |
fraction);
JERRY_ASSERT ((biased_exp & ~((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) == 0);
JERRY_ASSERT ((fraction & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0);
union
{
uint64_t u64_value;
ecma_number_t float_value;
} u;
u.u64_value = packed_value;
return u.float_value;
} /* ecma_number_pack */
/**
* Unpacking sign, fraction and biased exponent from ecma-number
*/
static void
ecma_number_unpack (ecma_number_t num, /**< ecma-number */
bool *sign_p, /**< [out] sign (optional) */
uint32_t *biased_exp_p, /**< [out] biased exponent (optional) */
uint64_t *fraction_p) /**< [out] fraction (optional) */
{
union
{
uint64_t u64_value;
ecma_number_t float_value;
} u;
u.float_value = num;
uint64_t packed_value = u.u64_value;
if (sign_p != NULL)
{
*sign_p = ((packed_value >> ECMA_NUMBER_SIGN_POS) != 0);
}
if (biased_exp_p != NULL)
{
*biased_exp_p = (uint32_t) (((packed_value) & ~(1ull << ECMA_NUMBER_SIGN_POS)) >> ECMA_NUMBER_FRACTION_WIDTH);
}
if (fraction_p != NULL)
{
*fraction_p = (packed_value & ((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1));
}
} /* ecma_number_unpack */
/**
* Value used to calculate exponent from biased exponent
*
* See also:
* IEEE-754 2008, 3.6, Table 3.5
*/
const int32_t ecma_number_exponent_bias = 1023;
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */
/**
* Get fraction of number
*
* @return normalized fraction field of number
*/
static uint64_t
ecma_number_get_fraction_field (ecma_number_t num) /**< ecma-number */
{
uint64_t fraction;
ecma_number_unpack (num, NULL, NULL, &fraction);
return fraction;
} /* ecma_number_get_fraction_field */
/**
* Get exponent of number
*
* @return exponent corresponding to normalized fraction of number
*/
static uint32_t
ecma_number_get_biased_exponent_field (ecma_number_t num) /**< ecma-number */
{
uint32_t biased_exp;
ecma_number_unpack (num, NULL, &biased_exp, NULL);
return biased_exp;
} /* ecma_number_get_biased_exponent_field */
/**
* Get sign bit of number
*
* @return 0 or 1 - value of sign bit
*/
static uint32_t
ecma_number_get_sign_field (ecma_number_t num) /**< ecma-number */
{
bool sign;
ecma_number_unpack (num, &sign, NULL, NULL);
return sign;
} /* ecma_number_get_sign_field */
/**
* Check if ecma-number is NaN
*
* @return true - if biased exponent is filled with 1 bits and
fraction is filled with anything but not all zero bits,
* false - otherwise
*/
bool __attr_always_inline___
ecma_number_is_nan (ecma_number_t num) /**< ecma-number */
{
bool is_nan = (num != num);
#ifndef JERRY_NDEBUG
uint32_t biased_exp = ecma_number_get_biased_exponent_field (num);
uint64_t fraction = ecma_number_get_fraction_field (num);
/* IEEE-754 2008, 3.4, a */
bool is_nan_ieee754 = ((biased_exp == (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)
&& (fraction != 0));
JERRY_ASSERT (is_nan == is_nan_ieee754);
#endif /* !JERRY_NDEBUG */
return is_nan;
} /* ecma_number_is_nan */
/**
* Make a NaN.
*
* @return NaN value
*/
ecma_number_t
ecma_number_make_nan (void)
{
return ecma_number_pack (false,
(1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1u,
1u);
} /* ecma_number_make_nan */
/**
* Make an Infinity.
*
* @return if !sign - +Infinity value,
* else - -Infinity value.
*/
ecma_number_t
ecma_number_make_infinity (bool sign) /**< true - for negative Infinity,
false - for positive Infinity */
{
return ecma_number_pack (sign,
(1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1u,
0u);
} /* ecma_number_make_infinity */
/**
* Check if ecma-number is negative
*
* @return true - if sign bit of ecma-number is set
* false - otherwise
*/
bool __attr_always_inline___
ecma_number_is_negative (ecma_number_t num) /**< ecma-number */
{
JERRY_ASSERT (!ecma_number_is_nan (num));
/* IEEE-754 2008, 3.4 */
return (ecma_number_get_sign_field (num) != 0);
} /* ecma_number_is_negative */
/**
* Check if ecma-number is zero
*
* @return true - if fraction is zero and biased exponent is zero,
* false - otherwise
*/
bool
ecma_number_is_zero (ecma_number_t num) /**< ecma-number */
{
JERRY_ASSERT (!ecma_number_is_nan (num));
bool is_zero = (num == ECMA_NUMBER_ZERO);
#ifndef JERRY_NDEBUG
/* IEEE-754 2008, 3.4, e */
bool is_zero_ieee754 = (ecma_number_get_fraction_field (num) == 0
&& ecma_number_get_biased_exponent_field (num) == 0);
JERRY_ASSERT (is_zero == is_zero_ieee754);
#endif /* !JERRY_NDEBUG */
return is_zero;
} /* ecma_number_is_zero */
/**
* Check if number is infinity
*
* @return true - if biased exponent is filled with 1 bits and
* fraction is filled with zero bits,
* false - otherwise.
*/
bool
ecma_number_is_infinity (ecma_number_t num) /**< ecma-number */
{
JERRY_ASSERT (!ecma_number_is_nan (num));
uint32_t biased_exp = ecma_number_get_biased_exponent_field (num);
uint64_t fraction = ecma_number_get_fraction_field (num);
/* IEEE-754 2008, 3.4, b */
return ((biased_exp == (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)
&& (fraction == 0));
} /* ecma_number_is_infinity */
/**
* Get fraction and exponent of the number
*
* @return shift of dot in the fraction
*/
int32_t
ecma_number_get_fraction_and_exponent (ecma_number_t num, /**< ecma-number */
uint64_t *out_fraction_p, /**< [out] fraction of the number */
int32_t *out_exponent_p) /**< [out] exponent of the number */
{
JERRY_ASSERT (!ecma_number_is_nan (num));
uint32_t biased_exp = ecma_number_get_biased_exponent_field (num);
uint64_t fraction = ecma_number_get_fraction_field (num);
int32_t exponent;
if (unlikely (biased_exp == 0))
{
/* IEEE-754 2008, 3.4, d */
if (ecma_number_is_zero (num))
{
exponent = -ecma_number_exponent_bias;
}
else
{
exponent = 1 - ecma_number_exponent_bias;
while (!(fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)))
{
JERRY_ASSERT (fraction != 0);
fraction <<= 1;
exponent--;
}
}
}
else if (ecma_number_is_infinity (num))
{
/* The fraction and exponent should round to infinity */
exponent = (int32_t) biased_exp - ecma_number_exponent_bias;
JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0);
fraction |= 1ull << ECMA_NUMBER_FRACTION_WIDTH;
}
else
{
/* IEEE-754 2008, 3.4, c */
exponent = (int32_t) biased_exp - ecma_number_exponent_bias;
JERRY_ASSERT (biased_exp > 0 && biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1);
JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0);
fraction |= 1ull << ECMA_NUMBER_FRACTION_WIDTH;
}
*out_fraction_p = fraction;
*out_exponent_p = exponent;
return ECMA_NUMBER_FRACTION_WIDTH;
} /* ecma_number_get_fraction_and_exponent */
/**
* Make normalised positive Number from given fraction and exponent
*
* @return ecma-number
*/
ecma_number_t
ecma_number_make_normal_positive_from_fraction_and_exponent (uint64_t fraction, /**< fraction */
int32_t exponent) /**< exponent */
{
uint32_t biased_exp = (uint32_t) (exponent + ecma_number_exponent_bias);
JERRY_ASSERT (biased_exp > 0 && biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1);
JERRY_ASSERT ((fraction & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0);
JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) != 0);
return ecma_number_pack (false,
biased_exp,
fraction & ~(1ull << ECMA_NUMBER_FRACTION_WIDTH));
} /* ecma_number_make_normal_positive_from_fraction_and_exponent */
/**
* Make Number of given sign from given mantissa value and binary exponent
*
* @return ecma-number (possibly Infinity of specified sign)
*/
ecma_number_t
ecma_number_make_from_sign_mantissa_and_exponent (bool sign, /**< true - for negative sign,
false - for positive sign */
uint64_t mantissa, /**< mantissa */
int32_t exponent) /**< binary exponent */
{
/* Rounding mantissa to fit into fraction field width */
if (mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1))
{
/* Rounded mantissa looks like the following: |00...0|1|fraction_width mantissa bits| */
while ((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) != 0)
{
uint64_t rightmost_bit = (mantissa & 1);
exponent++;
mantissa >>= 1;
if ((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0)
{
/* Rounding to nearest value */
mantissa += rightmost_bit;
/* In the first case loop is finished,
and in the second - just one shift follows and then loop finishes */
JERRY_ASSERT (((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0)
|| (mantissa == (1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1))));
}
}
}
/* Normalizing mantissa */
while (mantissa != 0
&& ((mantissa & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0))
{
exponent--;
mantissa <<= 1;
}
/* Moving floating point */
exponent += ECMA_NUMBER_FRACTION_WIDTH - 1;
int32_t biased_exp_signed = exponent + ecma_number_exponent_bias;
if (biased_exp_signed < 1)
{
/* Denormalizing mantissa if biased_exponent is less than zero */
while (biased_exp_signed < 0)
{
biased_exp_signed++;
mantissa >>= 1;
}
/* Rounding to nearest value */
mantissa += 1;
mantissa >>= 1;
/* Encoding denormalized exponent */
biased_exp_signed = 0;
}
else
{
/* Clearing highest mantissa bit that should have been non-zero if mantissa is non-zero */
mantissa &= ~(1ull << ECMA_NUMBER_FRACTION_WIDTH);
}
uint32_t biased_exp = (uint32_t) biased_exp_signed;
if (biased_exp >= ((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1))
{
return ecma_number_make_infinity (sign);
}
JERRY_ASSERT (biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1);
JERRY_ASSERT ((mantissa & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0);
return ecma_number_pack (sign,
biased_exp,
mantissa);
} /* ecma_number_make_from_sign_mantissa_and_exponent */
/**
* Get previous representable ecma-number
*
* @return maximum ecma-number that is less compared to passed argument
*/
ecma_number_t
ecma_number_get_prev (ecma_number_t num) /**< ecma-number */
{
JERRY_ASSERT (!ecma_number_is_nan (num));
JERRY_ASSERT (!ecma_number_is_zero (num));
if (ecma_number_is_negative (num))
{
return ecma_number_negate (ecma_number_get_next (num));
}
uint32_t biased_exp = ecma_number_get_biased_exponent_field (num);
uint64_t fraction = ecma_number_get_fraction_field (num);
if (fraction == 0 && biased_exp != 0)
{
fraction = (1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1;
biased_exp--;
}
else
{
fraction--;
}
return ecma_number_pack (false,
biased_exp,
fraction);
} /* ecma_number_get_prev */
/**
* Get next representable ecma-number
*
* @return minimum ecma-number that is greater compared to passed argument
*/
ecma_number_t
ecma_number_get_next (ecma_number_t num) /**< ecma-number */
{
JERRY_ASSERT (!ecma_number_is_nan (num));
JERRY_ASSERT (!ecma_number_is_infinity (num));
if (ecma_number_is_negative (num))
{
return ecma_number_negate (ecma_number_get_prev (num));
}
uint32_t biased_exp = ecma_number_get_biased_exponent_field (num);
uint64_t fraction = ecma_number_get_fraction_field (num);
fraction |= (1ull << ECMA_NUMBER_FRACTION_WIDTH);
fraction++;
if ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0)
{
fraction >>= 1;
biased_exp++;
}
JERRY_ASSERT (fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH));
fraction &= ~(1ull << ECMA_NUMBER_FRACTION_WIDTH);
return ecma_number_pack (false,
biased_exp,
fraction);
} /* ecma_number_get_next */
/**
* Negate ecma-number
*
* @return negated number
*/
ecma_number_t
ecma_number_negate (ecma_number_t num) /**< ecma-number */
{
ecma_number_t negated = -num;
#ifndef JERRY_NDEBUG
bool sign;
uint32_t biased_exp;
uint64_t fraction;
ecma_number_unpack (num, &sign, &biased_exp, &fraction);
sign = !sign;
ecma_number_t negated_ieee754 = ecma_number_pack (sign, biased_exp, fraction);
JERRY_ASSERT (negated == negated_ieee754
|| (ecma_number_is_nan (negated)
&& ecma_number_is_nan (negated_ieee754)));
#endif /* !JERRY_NDEBUG */
return negated;
} /* ecma_number_negate */
/**
* Truncate fractional part of the number
*
* @return integer part of the number
*/
ecma_number_t
ecma_number_trunc (ecma_number_t num) /**< ecma-number */
{
JERRY_ASSERT (!ecma_number_is_nan (num));
uint64_t fraction;
int32_t exponent;
const int32_t dot_shift = ecma_number_get_fraction_and_exponent (num, &fraction, &exponent);
const bool sign = ecma_number_is_negative (num);
if (exponent < 0)
{
return ECMA_NUMBER_ZERO;
}
else if (exponent < dot_shift)
{
fraction &= ~((1ull << (dot_shift - exponent)) - 1);
ecma_number_t tmp = ecma_number_make_normal_positive_from_fraction_and_exponent (fraction,
exponent);
if (sign)
{
return ecma_number_negate (tmp);
}
else
{
return tmp;
}
}
else
{
return num;
}
} /* ecma_number_trunc */
/**
* Calculate remainder of division of two numbers,
* as specified in ECMA-262 v5, 11.5.3, item 6.
*
* Note:
* operands shouldn't contain NaN, Infinity, or zero.
*
* @return number - calculated remainder.
*/
ecma_number_t
ecma_number_calc_remainder (ecma_number_t left_num, /**< left operand */
ecma_number_t right_num) /**< right operand */
{
JERRY_ASSERT (!ecma_number_is_nan (left_num)
&& !ecma_number_is_zero (left_num)
&& !ecma_number_is_infinity (left_num));
JERRY_ASSERT (!ecma_number_is_nan (right_num)
&& !ecma_number_is_zero (right_num)
&& !ecma_number_is_infinity (right_num));
const ecma_number_t q = ecma_number_trunc (ecma_number_divide (left_num, right_num));
ecma_number_t r = ecma_number_substract (left_num, ecma_number_multiply (right_num, q));
if (ecma_number_is_zero (r)
&& ecma_number_is_negative (left_num))
{
r = ecma_number_negate (r);
}
return r;
} /* ecma_number_calc_remainder */
/**
* ECMA-number addition.
*
* @return number - result of addition.
*/
ecma_number_t
ecma_number_add (ecma_number_t left_num, /**< left operand */
ecma_number_t right_num) /**< right operand */
{
return left_num + right_num;
} /* ecma_number_add */
/**
* ECMA-number substraction.
*
* @return number - result of substraction.
*/
ecma_number_t
ecma_number_substract (ecma_number_t left_num, /**< left operand */
ecma_number_t right_num) /**< right operand */
{
return ecma_number_add (left_num, ecma_number_negate (right_num));
} /* ecma_number_substract */
/**
* ECMA-number multiplication.
*
* @return number - result of multiplication.
*/
ecma_number_t
ecma_number_multiply (ecma_number_t left_num, /**< left operand */
ecma_number_t right_num) /**< right operand */
{
return left_num * right_num;
} /* ecma_number_multiply */
/**
* ECMA-number division.
*
* @return number - result of division.
*/
ecma_number_t
ecma_number_divide (ecma_number_t left_num, /**< left operand */
ecma_number_t right_num) /**< right operand */
{
return left_num / right_num;
} /* ecma_number_divide */
/**
* @}
* @}
*/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,924 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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.
*/
#include "ecma-alloc.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "jrt.h"
#include "jrt-bit-fields.h"
#include "vm-defines.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmahelpers Helpers for operations with ECMA data types
* @{
*/
/**
* Masking the type and flags
*/
#define ECMA_VALUE_FULL_MASK (ECMA_VALUE_TYPE_MASK | ECMA_VALUE_ERROR_FLAG)
JERRY_STATIC_ASSERT (ECMA_TYPE___MAX <= ECMA_VALUE_TYPE_MASK,
ecma_types_must_be_less_than_mask);
JERRY_STATIC_ASSERT ((ECMA_VALUE_FULL_MASK + 1) == (1 << ECMA_VALUE_SHIFT),
ecma_value_part_must_start_after_flags);
JERRY_STATIC_ASSERT (ECMA_VALUE_SHIFT <= JMEM_ALIGNMENT_LOG,
ecma_value_shift_must_be_less_than_or_equal_than_mem_alignment_log);
JERRY_STATIC_ASSERT (sizeof (jmem_cpointer_t) <= sizeof (ecma_value_t),
size_of_jmem_cpointer_t_must_be_less_or_equal_to_the_size_of_ecma_value_t);
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
JERRY_STATIC_ASSERT (sizeof (uintptr_t) <= sizeof (ecma_value_t),
uintptr_t_must_fit_in_ecma_value_t);
#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
JERRY_STATIC_ASSERT (sizeof (uintptr_t) > sizeof (ecma_value_t),
uintptr_t_must_not_fit_in_ecma_value_t);
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
JERRY_STATIC_ASSERT ((ECMA_SIMPLE_VALUE_FALSE | 0x1) == ECMA_SIMPLE_VALUE_TRUE
&& ECMA_SIMPLE_VALUE_FALSE != ECMA_SIMPLE_VALUE_TRUE,
only_the_lowest_bit_must_be_different_for_simple_value_true_and_false);
/**
* Get type field of ecma value
*
* @return type field
*/
static inline ecma_type_t __attr_pure___ __attr_always_inline___
ecma_get_value_type_field (ecma_value_t value) /**< ecma value */
{
return value & ECMA_VALUE_TYPE_MASK;
} /* ecma_get_value_type_field */
/**
* Convert a pointer into an ecma value.
*
* @return ecma value
*/
static inline ecma_value_t __attr_pure___ __attr_always_inline___
ecma_pointer_to_ecma_value (const void *ptr) /**< pointer */
{
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
uintptr_t uint_ptr = (uintptr_t) ptr;
JERRY_ASSERT ((uint_ptr & ECMA_VALUE_FULL_MASK) == 0);
return (ecma_value_t) uint_ptr;
#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
jmem_cpointer_t ptr_cp;
ECMA_SET_NON_NULL_POINTER (ptr_cp, ptr);
return ((ecma_value_t) ptr_cp) << ECMA_VALUE_SHIFT;
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
} /* ecma_pointer_to_ecma_value */
/**
* Get a pointer from an ecma value
*
* @return pointer
*/
static inline void * __attr_pure___ __attr_always_inline___
ecma_get_pointer_from_ecma_value (ecma_value_t value) /**< value */
{
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
return (void *) (uintptr_t) ((value) & ~ECMA_VALUE_FULL_MASK);
#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
return ECMA_GET_NON_NULL_POINTER (ecma_number_t,
value >> ECMA_VALUE_SHIFT);
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
} /* ecma_get_pointer_from_ecma_value */
/**
* Check if the value is direct ecma-value.
*
* @return true - if the value is a direct value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_direct (ecma_value_t value) /**< ecma value */
{
return (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT);
} /* ecma_is_value_direct */
/**
* Check if the value is simple ecma-value.
*
* @return true - if the value is a simple value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_simple (ecma_value_t value) /**< ecma value */
{
return (value & ECMA_DIRECT_TYPE_MASK) == ECMA_DIRECT_TYPE_SIMPLE_VALUE;
} /* ecma_is_value_simple */
/**
* Check whether the value is a given simple value.
*
* @return true - if the value is equal to the given simple value,
* false - otherwise.
*/
static inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_equal_to_simple_value (ecma_value_t value, /**< ecma value */
ecma_simple_value_t simple_value) /**< simple value */
{
return (value | ECMA_VALUE_ERROR_FLAG) == (ecma_make_simple_value (simple_value) | ECMA_VALUE_ERROR_FLAG);
} /* ecma_is_value_equal_to_simple_value */
/**
* Check if the value is empty.
*
* @return true - if the value contains implementation-defined empty simple value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_empty (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_SIMPLE_VALUE_EMPTY);
} /* ecma_is_value_empty */
/**
* Check if the value is undefined.
*
* @return true - if the value contains ecma-undefined simple value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_undefined (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_SIMPLE_VALUE_UNDEFINED);
} /* ecma_is_value_undefined */
/**
* Check if the value is null.
*
* @return true - if the value contains ecma-null simple value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_null (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_SIMPLE_VALUE_NULL);
} /* ecma_is_value_null */
/**
* Check if the value is boolean.
*
* @return true - if the value contains ecma-true or ecma-false simple values,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_boolean (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_true (value | (1 << ECMA_DIRECT_SHIFT));
} /* ecma_is_value_boolean */
/**
* Check if the value is true.
*
* @return true - if the value contains ecma-true simple value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_true (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_SIMPLE_VALUE_TRUE);
} /* ecma_is_value_true */
/**
* Check if the value is false.
*
* @return true - if the value contains ecma-false simple value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_false (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_SIMPLE_VALUE_FALSE);
} /* ecma_is_value_false */
/**
* Check if the value is not found.
*
* @return true - if the value contains ecma-not-found simple value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_found (ecma_value_t value) /**< ecma value */
{
return value != ecma_make_simple_value (ECMA_SIMPLE_VALUE_NOT_FOUND);
} /* ecma_is_value_found */
/**
* Check if the value is array hole.
*
* @return true - if the value contains ecma-array-hole simple value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_array_hole (ecma_value_t value) /**< ecma value */
{
return ecma_is_value_equal_to_simple_value (value, ECMA_SIMPLE_VALUE_ARRAY_HOLE);
} /* ecma_is_value_array_hole */
/**
* Check if the value is integer ecma-number.
*
* @return true - if the value contains an integer ecma-number value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_integer_number (ecma_value_t value) /**< ecma value */
{
return (value & ECMA_DIRECT_TYPE_MASK) == ECMA_DIRECT_TYPE_INTEGER_VALUE;
} /* ecma_is_value_integer_number */
/**
* Check if both values are integer ecma-numbers.
*
* @return true - if both values contain integer ecma-number values,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_are_values_integer_numbers (ecma_value_t first_value, /**< first ecma value */
ecma_value_t second_value) /**< second ecma value */
{
JERRY_STATIC_ASSERT (ECMA_DIRECT_TYPE_INTEGER_VALUE == 0,
ecma_direct_type_integer_value_must_be_zero);
return ((first_value | second_value) & ECMA_DIRECT_TYPE_MASK) == ECMA_DIRECT_TYPE_INTEGER_VALUE;
} /* ecma_are_values_integer_numbers */
/**
* Check if the value is floating-point ecma-number.
*
* @return true - if the value contains a floating-point ecma-number value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_float_number (ecma_value_t value) /**< ecma value */
{
return (ecma_get_value_type_field (value) == ECMA_TYPE_FLOAT);
} /* ecma_is_value_float_number */
/**
* Check if the value is ecma-number.
*
* @return true - if the value contains ecma-number value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_number (ecma_value_t value) /**< ecma value */
{
return (ecma_is_value_integer_number (value)
|| ecma_is_value_float_number (value));
} /* ecma_is_value_number */
/**
* Check if the value is ecma-string.
*
* @return true - if the value contains ecma-string value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_string (ecma_value_t value) /**< ecma value */
{
return (ecma_get_value_type_field (value) == ECMA_TYPE_STRING);
} /* ecma_is_value_string */
/**
* Check if the value is object.
*
* @return true - if the value contains object value,
* false - otherwise.
*/
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_object (ecma_value_t value) /**< ecma value */
{
return (ecma_get_value_type_field (value) == ECMA_TYPE_OBJECT);
} /* ecma_is_value_object */
/**
* Debug assertion that specified value's type is one of ECMA-defined
* script-visible types, i.e.: undefined, null, boolean, number, string, object.
*/
void
ecma_check_value_type_is_spec_defined (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_is_value_undefined (value)
|| ecma_is_value_null (value)
|| ecma_is_value_boolean (value)
|| ecma_is_value_number (value)
|| ecma_is_value_string (value)
|| ecma_is_value_object (value));
} /* ecma_check_value_type_is_spec_defined */
/**
* Simple value constructor
*/
inline ecma_value_t __attr_const___ __attr_always_inline___
ecma_make_simple_value (const ecma_simple_value_t simple_value) /**< simple value */
{
return (((ecma_value_t) (simple_value)) << ECMA_DIRECT_SHIFT) | ECMA_DIRECT_TYPE_SIMPLE_VALUE;
} /* ecma_make_simple_value */
/**
* Creates an ecma value from the given raw boolean.
*
* @return boolean ecma_value
*/
inline ecma_value_t __attr_const___ __attr_always_inline___
ecma_make_boolean_value (bool boolean_value) /**< raw bool value from which the ecma value will be created */
{
return ecma_make_simple_value (boolean_value ? ECMA_SIMPLE_VALUE_TRUE
: ECMA_SIMPLE_VALUE_FALSE);
} /* ecma_make_boolean_value */
/**
* Encode an integer number into an ecma-value without allocating memory
*
* Note:
* The value must fit into the range of allowed ecma integer values
*
* @return ecma-value
*/
inline ecma_value_t __attr_const___ __attr_always_inline___
ecma_make_integer_value (ecma_integer_value_t integer_value) /**< integer number to be encoded */
{
JERRY_ASSERT (ECMA_IS_INTEGER_NUMBER (integer_value));
return ((ecma_value_t) (integer_value << ECMA_DIRECT_SHIFT)) | ECMA_DIRECT_TYPE_INTEGER_VALUE;
} /* ecma_make_integer_value */
/**
* Allocate and initialize a new float number without checks.
*
* @return ecma-value
*/
static ecma_value_t __attr_const___
ecma_create_float_number (ecma_number_t ecma_number) /**< value of the float number */
{
ecma_number_t *ecma_num_p = ecma_alloc_number ();
*ecma_num_p = ecma_number;
return ecma_pointer_to_ecma_value (ecma_num_p) | ECMA_TYPE_FLOAT;
} /* ecma_create_float_number */
/**
* Create a new NaN value.
*
* @return ecma-value
*/
inline ecma_value_t __attr_always_inline___
ecma_make_nan_value (void)
{
return ecma_create_float_number (ecma_number_make_nan ());
} /* ecma_make_nan_value */
/**
* Checks whether the passed number is +0.0
*
* @return true, if it is +0.0, false otherwise
*/
static inline bool __attr_const___ __attr_always_inline___
ecma_is_number_equal_to_positive_zero (ecma_number_t ecma_number) /**< number */
{
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
union
{
uint32_t u32_value;
ecma_number_t float_value;
} u;
u.float_value = ecma_number;
return u.u32_value == 0;
#else /* CONFIG_ECMA_NUMBER_TYPE != CONFIG_ECMA_NUMBER_FLOAT32 */
union
{
uint64_t u64_value;
ecma_number_t float_value;
} u;
u.float_value = ecma_number;
return u.u64_value == 0;
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */
} /* ecma_is_number_equal_to_positive_zero */
/**
* Encode a number into an ecma-value
*
* @return ecma-value
*/
ecma_value_t
ecma_make_number_value (ecma_number_t ecma_number) /**< number to be encoded */
{
ecma_integer_value_t integer_value = (ecma_integer_value_t) ecma_number;
if ((ecma_number_t) integer_value == ecma_number
&& ((integer_value == 0) ? ecma_is_number_equal_to_positive_zero (ecma_number)
: ECMA_IS_INTEGER_NUMBER (integer_value)))
{
return ecma_make_integer_value (integer_value);
}
return ecma_create_float_number (ecma_number);
} /* ecma_make_number_value */
/**
* Encode an int32 number into an ecma-value
*
* @return ecma-value
*/
ecma_value_t
ecma_make_int32_value (int32_t int32_number) /**< int32 number to be encoded */
{
if (ECMA_IS_INTEGER_NUMBER (int32_number))
{
return ecma_make_integer_value ((ecma_integer_value_t) int32_number);
}
return ecma_create_float_number ((ecma_number_t) int32_number);
} /* ecma_make_int32_value */
/**
* Encode an unsigned int32 number into an ecma-value
*
* @return ecma-value
*/
ecma_value_t
ecma_make_uint32_value (uint32_t uint32_number) /**< uint32 number to be encoded */
{
if (uint32_number <= ECMA_INTEGER_NUMBER_MAX)
{
return ecma_make_integer_value ((ecma_integer_value_t) uint32_number);
}
return ecma_create_float_number ((ecma_number_t) uint32_number);
} /* ecma_make_uint32_value */
/**
* String value constructor
*/
ecma_value_t __attr_const___
ecma_make_string_value (const ecma_string_t *ecma_string_p) /**< string to reference in value */
{
JERRY_ASSERT (ecma_string_p != NULL);
return ecma_pointer_to_ecma_value (ecma_string_p) | ECMA_TYPE_STRING;
} /* ecma_make_string_value */
/**
* Object value constructor
*/
ecma_value_t __attr_const___
ecma_make_object_value (const ecma_object_t *object_p) /**< object to reference in value */
{
JERRY_ASSERT (object_p != NULL);
return ecma_pointer_to_ecma_value (object_p) | ECMA_TYPE_OBJECT;
} /* ecma_make_object_value */
/**
* Error value constructor
*/
ecma_value_t __attr_const___
ecma_make_error_value (ecma_value_t value) /**< original ecma value */
{
/* Error values cannot be converted. */
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (value));
return value | ECMA_VALUE_ERROR_FLAG;
} /* ecma_make_error_value */
/**
* Error value constructor
*/
ecma_value_t __attr_const___
ecma_make_error_obj_value (const ecma_object_t *object_p) /**< object to reference in value */
{
return ecma_make_error_value (ecma_make_object_value (object_p));
} /* ecma_make_error_obj_value */
/**
* Get integer value from an integer ecma value
*
* @return floating point value
*/
inline ecma_integer_value_t __attr_pure___ __attr_always_inline___
ecma_get_integer_from_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_is_value_integer_number (value));
return ((ecma_integer_value_t) value) >> ECMA_DIRECT_SHIFT;
} /* ecma_get_integer_from_value */
inline ecma_number_t __attr_pure___ __attr_always_inline___
ecma_get_float_from_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_FLOAT);
return *(ecma_number_t *) ecma_get_pointer_from_ecma_value (value);
} /* ecma_get_float_from_value */
/**
* Get floating point value from an ecma value
*
* @return floating point value
*/
ecma_number_t __attr_pure___
ecma_get_number_from_value (ecma_value_t value) /**< ecma value */
{
if (ecma_is_value_integer_number (value))
{
return (ecma_number_t) ecma_get_integer_from_value (value);
}
return ecma_get_float_from_value (value);
} /* ecma_get_number_from_value */
/**
* Get uint32 value from an ecma value
*
* @return floating point value
*/
uint32_t __attr_pure___
ecma_get_uint32_from_value (ecma_value_t value) /**< ecma value */
{
if (ecma_is_value_integer_number (value))
{
/* Works with negative numbers as well. */
return (uint32_t) (((ecma_integer_value_t) value) >> ECMA_DIRECT_SHIFT);
}
JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_FLOAT);
return ecma_number_to_uint32 (*(ecma_number_t *) ecma_get_pointer_from_ecma_value (value));
} /* ecma_get_uint32_from_value */
/**
* Get pointer to ecma-string from ecma value
*
* @return the pointer
*/
inline ecma_string_t *__attr_pure___ __attr_always_inline___
ecma_get_string_from_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_STRING);
return (ecma_string_t *) ecma_get_pointer_from_ecma_value (value);
} /* ecma_get_string_from_value */
/**
* Get pointer to ecma-object from ecma value
*
* @return the pointer
*/
inline ecma_object_t *__attr_pure___ __attr_always_inline___
ecma_get_object_from_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_OBJECT);
return (ecma_object_t *) ecma_get_pointer_from_ecma_value (value);
} /* ecma_get_object_from_value */
/**
* Invert a boolean value
*
* @return ecma value
*/
inline ecma_value_t __attr_pure___ __attr_always_inline___
ecma_invert_boolean_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_is_value_boolean (value));
return (value ^ (1 << ECMA_DIRECT_SHIFT));
} /* ecma_invert_boolean_value */
/**
* Get the value from an error ecma value
*
* @return ecma value
*/
ecma_value_t __attr_pure___
ecma_get_value_from_error_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ECMA_IS_VALUE_ERROR (value));
value = (ecma_value_t) (value & ~ECMA_VALUE_ERROR_FLAG);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (value));
return value;
} /* ecma_get_value_from_error_value */
/**
* Copy ecma value.
*
* @return copy of the given value
*/
ecma_value_t
ecma_copy_value (ecma_value_t value) /**< value description */
{
switch (ecma_get_value_type_field (value))
{
case ECMA_TYPE_DIRECT:
{
return value;
}
case ECMA_TYPE_FLOAT:
{
ecma_number_t *num_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (value);
return ecma_create_float_number (*num_p);
}
case ECMA_TYPE_STRING:
{
ecma_ref_ecma_string (ecma_get_string_from_value (value));
return value;
}
case ECMA_TYPE_OBJECT:
{
ecma_ref_object (ecma_get_object_from_value (value));
return value;
}
}
JERRY_UNREACHABLE ();
} /* ecma_copy_value */
/**
* Copy ecma value.
*
* Note:
* this function is similar to ecma_copy_value, but it is
* faster for direct values since no function call is performed.
* It also increases the binary size so it is recommended for
* critical code paths only.
*
* @return copy of the given value
*/
inline ecma_value_t __attr_always_inline___
ecma_fast_copy_value (ecma_value_t value) /**< value description */
{
return (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT) ? value : ecma_copy_value (value);
} /* ecma_fast_copy_value */
/**
* Copy the ecma value if not an object
*
* @return copy of the given value
*/
ecma_value_t
ecma_copy_value_if_not_object (ecma_value_t value) /**< value description */
{
if (ecma_get_value_type_field (value) != ECMA_TYPE_OBJECT)
{
return ecma_copy_value (value);
}
return value;
} /* ecma_copy_value_if_not_object */
/**
* Assign a new value to an ecma-value
*
* Note:
* value previously stored in the property is freed
*/
void
ecma_value_assign_value (ecma_value_t *value_p, /**< [in, out] ecma value */
ecma_value_t ecma_value) /**< value to assign */
{
JERRY_STATIC_ASSERT (ECMA_TYPE_DIRECT == 0,
ecma_type_direct_must_be_zero_for_the_next_check);
if (*value_p == ecma_value)
{
return;
}
if (ecma_get_value_type_field (ecma_value || *value_p) == ECMA_TYPE_DIRECT)
{
*value_p = ecma_value;
}
else if (ecma_is_value_float_number (ecma_value)
&& ecma_is_value_float_number (*value_p))
{
const ecma_number_t *num_src_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (ecma_value);
ecma_number_t *num_dst_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (*value_p);
*num_dst_p = *num_src_p;
}
else
{
ecma_free_value_if_not_object (*value_p);
*value_p = ecma_copy_value_if_not_object (ecma_value);
}
} /* ecma_value_assign_value */
/**
* Update the value of a float number to a new value
*
* Note:
* The original value is destroyed.
*
* @return updated ecma value
*/
ecma_value_t
ecma_update_float_number (ecma_value_t float_value, /**< original float value */
ecma_number_t new_number) /**< updated number value */
{
JERRY_ASSERT (ecma_is_value_float_number (float_value));
ecma_integer_value_t integer_number = (ecma_integer_value_t) new_number;
ecma_number_t *number_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (float_value);
if ((ecma_number_t) integer_number == new_number
&& ((integer_number == 0) ? ecma_is_number_equal_to_positive_zero (new_number)
: ECMA_IS_INTEGER_NUMBER (integer_number)))
{
ecma_dealloc_number (number_p);
return ecma_make_integer_value (integer_number);
}
*number_p = new_number;
return float_value;
} /* ecma_update_float_number */
/**
* Assign a float number to an ecma-value
*
* Note:
* value previously stored in the property is freed
*/
static void
ecma_value_assign_float_number (ecma_value_t *value_p, /**< [in, out] ecma value */
ecma_number_t ecma_number) /**< number to assign */
{
if (ecma_is_value_float_number (*value_p))
{
ecma_number_t *num_dst_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (*value_p);
*num_dst_p = ecma_number;
return;
}
if (ecma_get_value_type_field (*value_p) != ECMA_TYPE_DIRECT
&& ecma_get_value_type_field (*value_p) != ECMA_TYPE_OBJECT)
{
ecma_free_value (*value_p);
}
*value_p = ecma_create_float_number (ecma_number);
} /* ecma_value_assign_float_number */
/**
* Assign a number to an ecma-value
*
* Note:
* value previously stored in the property is freed
*/
void
ecma_value_assign_number (ecma_value_t *value_p, /**< [in, out] ecma value */
ecma_number_t ecma_number) /**< number to assign */
{
ecma_integer_value_t integer_value = (ecma_integer_value_t) ecma_number;
if ((ecma_number_t) integer_value == ecma_number
&& ((integer_value == 0) ? ecma_is_number_equal_to_positive_zero (ecma_number)
: ECMA_IS_INTEGER_NUMBER (integer_value)))
{
if (ecma_get_value_type_field (*value_p) != ECMA_TYPE_DIRECT
&& ecma_get_value_type_field (*value_p) != ECMA_TYPE_OBJECT)
{
ecma_free_value (*value_p);
}
*value_p = ecma_make_integer_value (integer_value);
return;
}
ecma_value_assign_float_number (value_p, ecma_number);
} /* ecma_value_assign_number */
/**
* Assign an uint32 value to an ecma-value
*
* Note:
* value previously stored in the property is freed
*/
void
ecma_value_assign_uint32 (ecma_value_t *value_p, /**< [in, out] ecma value */
uint32_t uint32_number) /**< number to assign */
{
if (uint32_number <= ECMA_INTEGER_NUMBER_MAX)
{
if (ecma_get_value_type_field (*value_p) != ECMA_TYPE_DIRECT
&& ecma_get_value_type_field (*value_p) != ECMA_TYPE_OBJECT)
{
ecma_free_value (*value_p);
}
*value_p = ecma_make_integer_value ((ecma_integer_value_t) uint32_number);
return;
}
ecma_value_assign_float_number (value_p, (ecma_number_t) uint32_number);
} /* ecma_value_assign_uint32 */
/**
* Free the ecma value
*/
void
ecma_free_value (ecma_value_t value) /**< value description */
{
switch (ecma_get_value_type_field (value))
{
case ECMA_TYPE_DIRECT:
{
/* no memory is allocated */
break;
}
case ECMA_TYPE_FLOAT:
{
ecma_number_t *number_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (value);
ecma_dealloc_number (number_p);
break;
}
case ECMA_TYPE_STRING:
{
ecma_string_t *string_p = ecma_get_string_from_value (value);
ecma_deref_ecma_string (string_p);
break;
}
case ECMA_TYPE_OBJECT:
{
ecma_deref_object (ecma_get_object_from_value (value));
break;
}
}
} /* ecma_free_value */
/**
* Free the ecma value
*
* Note:
* this function is similar to ecma_free_value, but it is
* faster for direct values since no function call is performed.
* It also increases the binary size so it is recommended for
* critical code paths only.
*/
inline void __attr_always_inline___
ecma_fast_free_value (ecma_value_t value) /**< value description */
{
if (ecma_get_value_type_field (value) != ECMA_TYPE_DIRECT)
{
ecma_free_value (value);
}
} /* ecma_fast_free_value */
/**
* Free the ecma value if not an object
*/
void
ecma_free_value_if_not_object (ecma_value_t value) /**< value description */
{
if (ecma_get_value_type_field (value) != ECMA_TYPE_OBJECT)
{
ecma_free_value (value);
}
} /* ecma_free_value_if_not_object */
/**
* @}
* @}
*/

View file

@ -0,0 +1,374 @@
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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.
*/
#include "ecma-alloc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "jrt.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmahelpers Helpers for operations with ECMA data types
* @{
*/
/**
* Allocate a collection of ecma values.
*
* @return pointer to the collection's header
*/
ecma_collection_header_t *
ecma_new_values_collection (const ecma_value_t values_buffer[], /**< ecma values */
ecma_length_t values_number, /**< number of ecma values */
bool do_ref_if_object) /**< if the value is object value,
increase reference counter of the object */
{
JERRY_ASSERT (values_buffer != NULL || values_number == 0);
const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t);
ecma_collection_header_t *header_p = ecma_alloc_collection_header ();
header_p->unit_number = values_number;
jmem_cpointer_t *next_chunk_cp_p = &header_p->first_chunk_cp;
ecma_collection_chunk_t *last_chunk_p = NULL;
ecma_value_t *cur_value_buf_iter_p = NULL;
ecma_value_t *cur_value_buf_end_p = NULL;
for (ecma_length_t value_index = 0;
value_index < values_number;
value_index++)
{
if (cur_value_buf_iter_p == cur_value_buf_end_p)
{
ecma_collection_chunk_t *chunk_p = ecma_alloc_collection_chunk ();
ECMA_SET_POINTER (*next_chunk_cp_p, chunk_p);
next_chunk_cp_p = &chunk_p->next_chunk_cp;
cur_value_buf_iter_p = (ecma_value_t *) chunk_p->data;
cur_value_buf_end_p = cur_value_buf_iter_p + values_in_chunk;
last_chunk_p = chunk_p;
}
JERRY_ASSERT (cur_value_buf_iter_p + 1 <= cur_value_buf_end_p);
if (do_ref_if_object)
{
*cur_value_buf_iter_p++ = ecma_copy_value (values_buffer[value_index]);
}
else
{
*cur_value_buf_iter_p++ = ecma_copy_value_if_not_object (values_buffer[value_index]);
}
}
*next_chunk_cp_p = ECMA_NULL_POINTER;
ECMA_SET_POINTER (header_p->last_chunk_cp, last_chunk_p);
return header_p;
} /* ecma_new_values_collection */
/**
* 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 */
/**
* 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 = JERRY_SIZE_OF_STRUCT_MEMBER (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));
if (do_ref_if_object)
{
values_p[pos_of_new_value_in_chunk] = ecma_copy_value (v);
}
else
{
values_p[pos_of_new_value_in_chunk] = ecma_copy_value_if_not_object (v);
}
} /* ecma_append_to_values_collection */
/**
* Remove last element of the collection
*
* Warning:
* the function invalidates all iterators that are configured to access the passed collection
*/
void
ecma_remove_last_value_from_values_collection (ecma_collection_header_t *header_p) /**< collection's header */
{
JERRY_ASSERT (header_p != NULL && header_p->unit_number > 0);
const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t);
size_t values_number = header_p->unit_number;
size_t pos_of_value_to_remove_in_chunk = (values_number - 1u) % values_in_chunk;
ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
header_p->last_chunk_cp);
ecma_value_t *values_p = (ecma_value_t *) last_chunk_p->data;
JERRY_ASSERT ((uint8_t *) (values_p + pos_of_value_to_remove_in_chunk + 1) <= (uint8_t *) (last_chunk_p + 1));
ecma_value_t value_to_remove = values_p[pos_of_value_to_remove_in_chunk];
ecma_free_value (value_to_remove);
header_p->unit_number--;
if (pos_of_value_to_remove_in_chunk == 0)
{
ecma_collection_chunk_t *chunk_to_remove_p = last_chunk_p;
/* free last chunk */
if (header_p->first_chunk_cp == header_p->last_chunk_cp)
{
header_p->first_chunk_cp = ECMA_NULL_POINTER;
header_p->last_chunk_cp = ECMA_NULL_POINTER;
}
else
{
ecma_collection_chunk_t *chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
header_p->first_chunk_cp);
while (chunk_iter_p->next_chunk_cp != header_p->last_chunk_cp)
{
chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
chunk_iter_p->next_chunk_cp);
}
ecma_collection_chunk_t *new_last_chunk_p = chunk_iter_p;
JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
new_last_chunk_p->next_chunk_cp) == chunk_to_remove_p);
ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, new_last_chunk_p);
new_last_chunk_p->next_chunk_cp = ECMA_NULL_POINTER;
}
ecma_dealloc_collection_chunk (chunk_to_remove_p);
}
} /* ecma_remove_last_value_from_values_collection */
/**
* Allocate a collection of ecma-strings.
*
* @return pointer to the collection's header
*/
ecma_collection_header_t *
ecma_new_strings_collection (ecma_string_t *string_ptrs_buffer[], /**< pointers to ecma-strings */
ecma_length_t strings_number) /**< number of ecma-strings */
{
JERRY_ASSERT (string_ptrs_buffer != NULL || strings_number == 0);
ecma_collection_header_t *new_collection_p;
new_collection_p = ecma_new_values_collection (NULL, 0, false);
for (ecma_length_t string_index = 0;
string_index < strings_number;
string_index++)
{
ecma_append_to_values_collection (new_collection_p,
ecma_make_string_value (string_ptrs_buffer[string_index]),
false);
}
return new_collection_p;
} /* ecma_new_strings_collection */
/**
* Initialize new collection iterator for the collection
*/
void
ecma_collection_iterator_init (ecma_collection_iterator_t *iterator_p, /**< context of iterator */
ecma_collection_header_t *collection_p) /**< header of collection */
{
iterator_p->header_p = collection_p;
iterator_p->next_chunk_cp = (collection_p != NULL ? collection_p->first_chunk_cp : JMEM_CP_NULL);
iterator_p->current_index = 0;
iterator_p->current_value_p = NULL;
iterator_p->current_chunk_end_p = NULL;
} /* ecma_collection_iterator_init */
/**
* 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 */
/**
* @}
* @}
*/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,340 @@
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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.
*/
#ifndef ECMA_HELPERS_H
#define ECMA_HELPERS_H
#include "ecma-globals.h"
#include "jmem-allocator.h"
#include "lit-strings.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmahelpers Helpers for operations with ECMA data types
* @{
*/
/**
* Get value of pointer from specified non-null compressed pointer.
*/
#define ECMA_GET_NON_NULL_POINTER(type, field) JMEM_CP_GET_NON_NULL_POINTER (type, field)
/**
* Get value of pointer from specified compressed pointer.
*/
#define ECMA_GET_POINTER(type, field) JMEM_CP_GET_POINTER (type, field)
/**
* Set value of non-null compressed pointer so that it will correspond
* to specified non_compressed_pointer.
*/
#define ECMA_SET_NON_NULL_POINTER(field, non_compressed_pointer) JMEM_CP_SET_NON_NULL_POINTER (field, \
non_compressed_pointer)
/**
* Set value of compressed pointer so that it will correspond
* to specified non_compressed_pointer.
*/
#define ECMA_SET_POINTER(field, non_compressed_pointer) JMEM_CP_SET_POINTER (field, non_compressed_pointer)
/**
* Convert ecma-string's contents to a cesu-8 string and put it into a buffer.
*/
#define ECMA_STRING_TO_UTF8_STRING(ecma_str_ptr, /**< ecma string pointer */ \
utf8_ptr, /**< [out] output buffer pointer */ \
utf8_str_size) /**< [out] output buffer size */ \
lit_utf8_size_t utf8_str_size; \
bool utf8_ptr ## must_be_freed; \
const lit_utf8_byte_t *utf8_ptr = ecma_string_raw_chars (ecma_str_ptr, &utf8_str_size, &utf8_ptr ## must_be_freed); \
utf8_ptr ## must_be_freed = false; /* it was used as 'is_ascii' in 'ecma_string_raw_chars', so we must reset it */ \
\
if (utf8_ptr == NULL) \
{ \
utf8_ptr = (const lit_utf8_byte_t *) jmem_heap_alloc_block (utf8_str_size); \
ecma_string_to_utf8_bytes (ecma_str_ptr, (lit_utf8_byte_t *) utf8_ptr, utf8_str_size); \
utf8_ptr ## must_be_freed = true; \
}
#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY
/**
* Set an internal property value of pointer
*/
#define ECMA_SET_INTERNAL_VALUE_POINTER(field, pointer) \
(field) = ((ecma_value_t) pointer)
/**
* Get an internal property value of pointer
*/
#define ECMA_GET_INTERNAL_VALUE_POINTER(type, field) \
((type *) field)
#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
/**
* Set an internal property value of non-null pointer so that it will correspond
* to specified non_compressed_pointer.
*/
#define ECMA_SET_INTERNAL_VALUE_POINTER(field, non_compressed_pointer) \
ECMA_SET_NON_NULL_POINTER (field, non_compressed_pointer)
/**
* Get an internal property value of pointer from specified compressed pointer.
*/
#define ECMA_GET_INTERNAL_VALUE_POINTER(type, field) \
ECMA_GET_POINTER (type, field)
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
/**
* Free the cesu-8 string buffer allocated by 'ECMA_STRING_TO_UTF8_STRING'
*/
#define ECMA_FINALIZE_UTF8_STRING(utf8_ptr, /**< pointer to character buffer */ \
utf8_str_size) /**< buffer size */ \
if (utf8_ptr ## must_be_freed) \
{ \
JERRY_ASSERT (utf8_ptr != NULL); \
jmem_heap_free_block ((void *) utf8_ptr, utf8_str_size); \
}
/* ecma-helpers-value.c */
extern bool ecma_is_value_direct (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_simple (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_empty (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_undefined (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_null (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_boolean (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_true (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_false (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_found (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_array_hole (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_integer_number (ecma_value_t) __attr_pure___;
extern bool ecma_are_values_integer_numbers (ecma_value_t, ecma_value_t) __attr_pure___;
extern bool ecma_is_value_float_number (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_number (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_string (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_object (ecma_value_t) __attr_pure___;
extern void ecma_check_value_type_is_spec_defined (ecma_value_t);
extern ecma_value_t ecma_make_simple_value (const ecma_simple_value_t value) __attr_const___;
extern ecma_value_t ecma_make_boolean_value (bool) __attr_const___;
extern ecma_value_t ecma_make_integer_value (ecma_integer_value_t) __attr_const___;
extern ecma_value_t ecma_make_nan_value (void);
extern ecma_value_t ecma_make_number_value (ecma_number_t);
extern ecma_value_t ecma_make_int32_value (int32_t);
extern ecma_value_t ecma_make_uint32_value (uint32_t);
extern ecma_value_t ecma_make_string_value (const ecma_string_t *);
extern ecma_value_t ecma_make_object_value (const ecma_object_t *);
extern ecma_value_t ecma_make_error_value (ecma_value_t);
extern ecma_value_t ecma_make_error_obj_value (const ecma_object_t *);
extern ecma_integer_value_t ecma_get_integer_from_value (ecma_value_t) __attr_pure___;
extern ecma_number_t ecma_get_float_from_value (ecma_value_t) __attr_pure___;
extern ecma_number_t ecma_get_number_from_value (ecma_value_t) __attr_pure___;
extern uint32_t ecma_get_uint32_from_value (ecma_value_t) __attr_pure___;
extern ecma_string_t *ecma_get_string_from_value (ecma_value_t) __attr_pure___;
extern ecma_object_t *ecma_get_object_from_value (ecma_value_t) __attr_pure___;
extern ecma_value_t ecma_get_value_from_error_value (ecma_value_t) __attr_pure___;
extern ecma_value_t ecma_invert_boolean_value (ecma_value_t) __attr_pure___;
extern ecma_value_t ecma_copy_value (ecma_value_t);
extern ecma_value_t ecma_fast_copy_value (ecma_value_t);
extern ecma_value_t ecma_copy_value_if_not_object (ecma_value_t);
extern ecma_value_t ecma_update_float_number (ecma_value_t, ecma_number_t);
extern void ecma_value_assign_value (ecma_value_t *, ecma_value_t);
extern void ecma_value_assign_number (ecma_value_t *, ecma_number_t);
extern void ecma_value_assign_uint32 (ecma_value_t *, uint32_t);
extern void ecma_free_value (ecma_value_t);
extern void ecma_fast_free_value (ecma_value_t);
extern void ecma_free_value_if_not_object (ecma_value_t);
/* ecma-helpers-string.c */
extern ecma_string_t *ecma_new_ecma_string_from_utf8 (const lit_utf8_byte_t *, lit_utf8_size_t);
extern ecma_string_t *ecma_new_ecma_string_from_utf8_to_cesu8 (const lit_utf8_byte_t *, lit_utf8_size_t);
extern ecma_string_t *ecma_new_ecma_string_from_code_unit (ecma_char_t);
extern ecma_string_t *ecma_new_ecma_string_from_uint32 (uint32_t);
extern ecma_string_t *ecma_new_ecma_string_from_number (ecma_number_t);
extern ecma_string_t *ecma_new_ecma_string_from_magic_string_id (lit_magic_string_id_t);
extern ecma_string_t *ecma_new_ecma_string_from_magic_string_ex_id (lit_magic_string_ex_id_t);
extern ecma_string_t *ecma_new_ecma_length_string ();
extern ecma_string_t *ecma_concat_ecma_strings (ecma_string_t *, ecma_string_t *);
extern void ecma_ref_ecma_string (ecma_string_t *);
extern void ecma_deref_ecma_string (ecma_string_t *);
extern ecma_number_t ecma_string_to_number (const ecma_string_t *);
extern bool ecma_string_get_array_index (const ecma_string_t *, uint32_t *);
extern lit_utf8_size_t __attr_return_value_should_be_checked___
ecma_string_copy_to_utf8_buffer (const ecma_string_t *, lit_utf8_byte_t *, lit_utf8_size_t);
extern lit_utf8_size_t __attr_return_value_should_be_checked___
ecma_string_copy_and_convert_to_utf8_buffer (const ecma_string_t *, lit_utf8_byte_t *, lit_utf8_size_t);
extern void ecma_string_to_utf8_bytes (const ecma_string_t *, lit_utf8_byte_t *, lit_utf8_size_t);
extern const lit_utf8_byte_t *ecma_string_raw_chars (const ecma_string_t *, lit_utf8_size_t *, bool *);
extern void ecma_init_ecma_string_from_uint32 (ecma_string_t *, uint32_t);
extern void ecma_init_ecma_length_string (ecma_string_t *);
extern bool ecma_string_is_empty (const ecma_string_t *);
extern bool ecma_string_is_length (const ecma_string_t *);
extern bool ecma_compare_ecma_strings_equal_hashes (const ecma_string_t *, const ecma_string_t *);
extern bool ecma_compare_ecma_strings (const ecma_string_t *, const ecma_string_t *);
extern bool ecma_compare_ecma_strings_relational (const ecma_string_t *, const ecma_string_t *);
extern ecma_length_t ecma_string_get_length (const ecma_string_t *);
extern lit_utf8_size_t ecma_string_get_size (const ecma_string_t *);
extern lit_utf8_size_t ecma_string_get_utf8_size (const ecma_string_t *);
extern ecma_char_t ecma_string_get_char_at_pos (const ecma_string_t *, ecma_length_t);
extern ecma_string_t *ecma_get_magic_string (lit_magic_string_id_t);
extern ecma_string_t *ecma_get_magic_string_ex (lit_magic_string_ex_id_t);
extern bool ecma_is_string_magic (const ecma_string_t *, lit_magic_string_id_t *);
extern lit_string_hash_t ecma_string_hash (const ecma_string_t *);
extern ecma_string_t *ecma_string_substr (const ecma_string_t *, ecma_length_t, ecma_length_t);
extern ecma_string_t *ecma_string_trim (const ecma_string_t *);
/* ecma-helpers-number.c */
extern ecma_number_t ecma_number_make_nan (void);
extern ecma_number_t ecma_number_make_infinity (bool);
extern bool ecma_number_is_nan (ecma_number_t);
extern bool ecma_number_is_negative (ecma_number_t);
extern bool ecma_number_is_zero (ecma_number_t);
extern bool ecma_number_is_infinity (ecma_number_t);
extern int32_t
ecma_number_get_fraction_and_exponent (ecma_number_t, uint64_t *, int32_t *);
extern ecma_number_t
ecma_number_make_normal_positive_from_fraction_and_exponent (uint64_t, int32_t);
extern ecma_number_t
ecma_number_make_from_sign_mantissa_and_exponent (bool, uint64_t, int32_t);
extern ecma_number_t ecma_number_get_prev (ecma_number_t);
extern ecma_number_t ecma_number_get_next (ecma_number_t);
extern ecma_number_t ecma_number_negate (ecma_number_t);
extern ecma_number_t ecma_number_trunc (ecma_number_t);
extern ecma_number_t ecma_number_calc_remainder (ecma_number_t, ecma_number_t);
extern ecma_number_t ecma_number_add (ecma_number_t, ecma_number_t);
extern ecma_number_t ecma_number_substract (ecma_number_t, ecma_number_t);
extern ecma_number_t ecma_number_multiply (ecma_number_t, ecma_number_t);
extern ecma_number_t ecma_number_divide (ecma_number_t, ecma_number_t);
extern lit_utf8_size_t ecma_number_to_decimal (ecma_number_t, lit_utf8_byte_t *, int32_t *);
/* ecma-helpers-values-collection.c */
extern ecma_collection_header_t *ecma_new_values_collection (const ecma_value_t[], ecma_length_t, bool);
extern void ecma_free_values_collection (ecma_collection_header_t *, bool);
extern void ecma_append_to_values_collection (ecma_collection_header_t *, ecma_value_t, bool);
extern void ecma_remove_last_value_from_values_collection (ecma_collection_header_t *);
extern ecma_collection_header_t *ecma_new_strings_collection (ecma_string_t *[], ecma_length_t);
/**
* Context of ecma values' collection iterator
*/
typedef struct
{
ecma_collection_header_t *header_p; /**< collection header */
jmem_cpointer_t next_chunk_cp; /**< compressed pointer to next chunk */
ecma_length_t current_index; /**< index of current element */
const ecma_value_t *current_value_p; /**< pointer to current element */
const ecma_value_t *current_chunk_beg_p; /**< pointer to beginning of current chunk's data */
const ecma_value_t *current_chunk_end_p; /**< pointer to place right after the end of current chunk's data */
} ecma_collection_iterator_t;
extern void
ecma_collection_iterator_init (ecma_collection_iterator_t *, ecma_collection_header_t *);
extern bool
ecma_collection_iterator_next (ecma_collection_iterator_t *);
/* ecma-helpers.c */
extern ecma_object_t *ecma_create_object (ecma_object_t *, bool, bool, ecma_object_type_t);
extern ecma_object_t *ecma_create_decl_lex_env (ecma_object_t *);
extern ecma_object_t *ecma_create_object_lex_env (ecma_object_t *, ecma_object_t *, bool);
extern bool ecma_is_lexical_environment (const ecma_object_t *) __attr_pure___;
extern bool ecma_get_object_extensible (const ecma_object_t *) __attr_pure___;
extern void ecma_set_object_extensible (ecma_object_t *, bool);
extern ecma_object_type_t ecma_get_object_type (const ecma_object_t *) __attr_pure___;
extern void ecma_set_object_type (ecma_object_t *, ecma_object_type_t);
extern ecma_object_t *ecma_get_object_prototype (const ecma_object_t *) __attr_pure___;
extern bool ecma_get_object_is_builtin (const ecma_object_t *) __attr_pure___;
extern void ecma_set_object_is_builtin (ecma_object_t *);
extern ecma_lexical_environment_type_t ecma_get_lex_env_type (const ecma_object_t *) __attr_pure___;
extern ecma_object_t *ecma_get_lex_env_outer_reference (const ecma_object_t *) __attr_pure___;
extern ecma_property_header_t *ecma_get_property_list (const ecma_object_t *) __attr_pure___;
extern ecma_object_t *ecma_get_lex_env_binding_object (const ecma_object_t *) __attr_pure___;
extern bool ecma_get_lex_env_provide_this (const ecma_object_t *) __attr_pure___;
extern ecma_value_t *ecma_create_internal_property (ecma_object_t *, ecma_internal_property_id_t);
extern ecma_value_t *ecma_find_internal_property (ecma_object_t *, ecma_internal_property_id_t);
extern ecma_value_t *ecma_get_internal_property (ecma_object_t *, ecma_internal_property_id_t);
extern ecma_property_value_t *
ecma_create_named_data_property (ecma_object_t *, ecma_string_t *, uint8_t, ecma_property_t **);
extern ecma_property_value_t *
ecma_create_named_accessor_property (ecma_object_t *, ecma_string_t *, ecma_object_t *, ecma_object_t *, uint8_t);
extern ecma_property_t *
ecma_find_named_property (ecma_object_t *, ecma_string_t *);
extern ecma_property_value_t *
ecma_get_named_data_property (ecma_object_t *, ecma_string_t *);
extern void ecma_free_property (ecma_object_t *, ecma_string_t *, ecma_property_t *);
extern void ecma_delete_property (ecma_object_t *, ecma_property_value_t *);
extern void ecma_named_data_property_assign_value (ecma_object_t *, ecma_property_value_t *, ecma_value_t);
extern ecma_object_t *ecma_get_named_accessor_property_getter (const ecma_property_value_t *);
extern ecma_object_t *ecma_get_named_accessor_property_setter (const ecma_property_value_t *);
extern void ecma_set_named_accessor_property_getter (ecma_object_t *, ecma_property_value_t *, ecma_object_t *);
extern void ecma_set_named_accessor_property_setter (ecma_object_t *, ecma_property_value_t *, ecma_object_t *);
extern bool ecma_is_property_writable (ecma_property_t);
extern void ecma_set_property_writable_attr (ecma_property_t *, bool);
extern bool ecma_is_property_enumerable (ecma_property_t);
extern void ecma_set_property_enumerable_attr (ecma_property_t *, bool);
extern bool ecma_is_property_configurable (ecma_property_t);
extern void ecma_set_property_configurable_attr (ecma_property_t *, bool);
extern bool ecma_is_property_lcached (ecma_property_t *);
extern void ecma_set_property_lcached (ecma_property_t *, bool);
extern ecma_property_descriptor_t ecma_make_empty_property_descriptor (void);
extern void ecma_free_property_descriptor (ecma_property_descriptor_t *);
extern ecma_property_t *ecma_get_next_property_pair (ecma_property_pair_t *);
extern void ecma_bytecode_ref (ecma_compiled_code_t *);
extern void ecma_bytecode_deref (ecma_compiled_code_t *);
/* ecma-helpers-external-pointers.c */
extern bool
ecma_create_external_pointer_property (ecma_object_t *, ecma_internal_property_id_t, ecma_external_pointer_t);
extern bool
ecma_get_external_pointer_value (ecma_object_t *, ecma_internal_property_id_t, ecma_external_pointer_t *);
extern void
ecma_free_external_pointer_in_property (ecma_property_t *);
/* ecma-helpers-conversion.c */
extern ecma_number_t ecma_utf8_string_to_number (const lit_utf8_byte_t *, lit_utf8_size_t);
extern lit_utf8_size_t ecma_uint32_to_utf8_string (uint32_t, lit_utf8_byte_t *, lit_utf8_size_t);
extern uint32_t ecma_number_to_uint32 (ecma_number_t);
extern int32_t ecma_number_to_int32 (ecma_number_t);
extern lit_utf8_size_t ecma_number_to_utf8_string (ecma_number_t, lit_utf8_byte_t *, lit_utf8_size_t);
/* ecma-helpers-errol.c */
extern lit_utf8_size_t ecma_errol0_dtoa (double, lit_utf8_byte_t *, int32_t *);
/**
* @}
* @}
*/
#endif /* !ECMA_HELPERS_H */

View file

@ -0,0 +1,61 @@
/* Copyright 2014-2016 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.
*/
#include "ecma-builtins.h"
#include "ecma-gc.h"
#include "ecma-helpers.h"
#include "ecma-init-finalize.h"
#include "ecma-lcache.h"
#include "ecma-lex-env.h"
#include "ecma-literal-storage.h"
#include "jmem-allocator.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmainitfinalize Initialization and finalization of ECMA components
* @{
*/
/**
* Initialize ECMA components
*/
void
ecma_init (void)
{
ecma_lcache_init ();
ecma_init_global_lex_env ();
jmem_register_free_unused_memory_callback (ecma_free_unused_memory);
} /* ecma_init */
/**
* Finalize ECMA components
*/
void
ecma_finalize (void)
{
jmem_unregister_free_unused_memory_callback (ecma_free_unused_memory);
ecma_finalize_global_lex_env ();
ecma_finalize_builtins ();
ecma_gc_run (JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW);
ecma_finalize_lit_storage ();
} /* ecma_finalize */
/**
* @}
* @}
*/

View file

@ -0,0 +1,34 @@
/* Copyright 2014-2016 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.
*/
#ifndef ECMA_INIT_FINALIZE_H
#define ECMA_INIT_FINALIZE_H
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmainitfinalize Initialization and finalization of ECMA components
* @{
*/
extern void ecma_init (void);
extern void ecma_finalize (void);
/**
* @}
* @}
*/
#endif /* !ECMA_INIT_FINALIZE_H */

View file

@ -0,0 +1,229 @@
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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.
*/
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-lcache.h"
#include "jcontext.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmalcache Property lookup cache
* @{
*/
#ifndef CONFIG_ECMA_LCACHE_DISABLE
/**
* Mask for hash bits
*/
#define ECMA_LCACHE_HASH_MASK (ECMA_LCACHE_HASH_ROWS_COUNT - 1)
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
/**
* Initialize LCache
*/
void
ecma_lcache_init (void)
{
#ifndef CONFIG_ECMA_LCACHE_DISABLE
memset (JERRY_HASH_TABLE_CONTEXT (table), 0, sizeof (jerry_hash_table_t));
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
} /* ecma_lcache_init */
#ifndef CONFIG_ECMA_LCACHE_DISABLE
/**
* Invalidate specified LCache entry
*/
static inline void __attr_always_inline___
ecma_lcache_invalidate_entry (ecma_lcache_hash_entry_t *entry_p) /**< entry to invalidate */
{
JERRY_ASSERT (entry_p != NULL);
JERRY_ASSERT (entry_p->object_cp != ECMA_NULL_POINTER);
JERRY_ASSERT (entry_p->prop_name_cp != ECMA_NULL_POINTER);
JERRY_ASSERT (entry_p->prop_p != NULL);
entry_p->object_cp = ECMA_NULL_POINTER;
ecma_set_property_lcached (entry_p->prop_p, false);
} /* ecma_lcache_invalidate_entry */
/**
* Compute the row index of object / property name pair
*
* @return row index
*/
static inline size_t __attr_always_inline___
ecma_lcache_row_index (jmem_cpointer_t object_cp, /**< compressed pointer to object */
const ecma_string_t *prop_name_p) /**< proeprty name */
{
/* Randomize the hash of the property name with the object pointer using a xor operation,
* so properties of different objects with the same name can be cached effectively. */
return (size_t) ((ecma_string_hash (prop_name_p) ^ object_cp) & ECMA_LCACHE_HASH_MASK);
} /* ecma_lcache_row_index */
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
/**
* Insert an entry into LCache
*/
void
ecma_lcache_insert (ecma_object_t *object_p, /**< object */
ecma_string_t *prop_name_p, /**< property name */
ecma_property_t *prop_p) /**< property */
{
JERRY_ASSERT (object_p != NULL);
JERRY_ASSERT (prop_name_p != NULL);
JERRY_ASSERT (prop_p != NULL && !ecma_is_property_lcached (prop_p));
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
|| ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
#ifndef CONFIG_ECMA_LCACHE_DISABLE
jmem_cpointer_t object_cp;
ECMA_SET_NON_NULL_POINTER (object_cp, object_p);
size_t row_index = ecma_lcache_row_index (object_cp, prop_name_p);
ecma_lcache_hash_entry_t *entries_p = JERRY_HASH_TABLE_CONTEXT (table)[row_index];
int32_t entry_index;
for (entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++)
{
if (entries_p[entry_index].object_cp == ECMA_NULL_POINTER)
{
break;
}
}
if (entry_index == ECMA_LCACHE_HASH_ROW_LENGTH)
{
/* Invalidate the last entry. */
ecma_lcache_invalidate_entry (entries_p + ECMA_LCACHE_HASH_ROW_LENGTH - 1);
/* Shift other entries towards the end. */
for (uint32_t i = ECMA_LCACHE_HASH_ROW_LENGTH - 1; i > 0; i--)
{
entries_p[i] = entries_p[i - 1];
}
entry_index = 0;
}
ecma_lcache_hash_entry_t *entry_p = entries_p + entry_index;
ECMA_SET_NON_NULL_POINTER (entry_p->object_cp, object_p);
ECMA_SET_NON_NULL_POINTER (entry_p->prop_name_cp, prop_name_p);
entry_p->prop_p = prop_p;
ecma_set_property_lcached (entry_p->prop_p, true);
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
} /* ecma_lcache_insert */
/**
* Lookup property in the LCache
*
* @return a pointer to an ecma_property_t if the lookup is successful
* NULL otherwise
*/
inline ecma_property_t * __attr_always_inline___
ecma_lcache_lookup (ecma_object_t *object_p, /**< object */
const ecma_string_t *prop_name_p) /**< property's name */
{
JERRY_ASSERT (object_p != NULL);
JERRY_ASSERT (prop_name_p != NULL);
#ifndef CONFIG_ECMA_LCACHE_DISABLE
jmem_cpointer_t object_cp;
ECMA_SET_NON_NULL_POINTER (object_cp, object_p);
size_t row_index = ecma_lcache_row_index (object_cp, prop_name_p);
ecma_lcache_hash_entry_t *entry_p = JERRY_HASH_TABLE_CONTEXT (table) [row_index];
ecma_lcache_hash_entry_t *entry_end_p = entry_p + ECMA_LCACHE_HASH_ROW_LENGTH;
ecma_string_container_t prop_container = ECMA_STRING_GET_CONTAINER (prop_name_p);
while (entry_p < entry_end_p)
{
if (entry_p->object_cp == object_cp)
{
ecma_string_t *entry_prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
entry_p->prop_name_cp);
JERRY_ASSERT ((prop_name_p->hash & ECMA_LCACHE_HASH_MASK) == (entry_prop_name_p->hash & ECMA_LCACHE_HASH_MASK));
if (prop_name_p == entry_prop_name_p
|| (prop_container > ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING
&& prop_container == ECMA_STRING_GET_CONTAINER (entry_prop_name_p)
&& prop_name_p->u.common_field == entry_prop_name_p->u.common_field))
{
ecma_property_t *prop_p = entry_p->prop_p;
JERRY_ASSERT (prop_p != NULL && ecma_is_property_lcached (prop_p));
return prop_p;
}
else
{
/* They can be equal, but generic string comparison is too costly. */
}
}
entry_p++;
}
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
return NULL;
} /* ecma_lcache_lookup */
/**
* Invalidate LCache entries associated with given object and property name / property
*/
void
ecma_lcache_invalidate (ecma_object_t *object_p, /**< object */
ecma_string_t *prop_name_p, /**< property's name */
ecma_property_t *prop_p) /**< property */
{
JERRY_ASSERT (object_p != NULL);
JERRY_ASSERT (prop_name_p != NULL);
JERRY_ASSERT (prop_p != NULL && ecma_is_property_lcached (prop_p));
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
|| ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
#ifndef CONFIG_ECMA_LCACHE_DISABLE
jmem_cpointer_t object_cp;
ECMA_SET_NON_NULL_POINTER (object_cp, object_p);
size_t row_index = ecma_lcache_row_index (object_cp, prop_name_p);
ecma_lcache_hash_entry_t *entry_p = JERRY_HASH_TABLE_CONTEXT (table) [row_index];
for (uint32_t entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++)
{
if (entry_p->object_cp != ECMA_NULL_POINTER && entry_p->prop_p == prop_p)
{
JERRY_ASSERT (entry_p->object_cp == object_cp);
ecma_lcache_invalidate_entry (entry_p);
return;
}
entry_p++;
}
/* The property must be present. */
JERRY_UNREACHABLE ();
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
} /* ecma_lcache_invalidate */
/**
* @}
* @}
*/

View file

@ -0,0 +1,36 @@
/* Copyright 2014-2016 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.
*/
#ifndef ECMA_LCACHE_H
#define ECMA_LCACHE_H
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmalcache Property lookup cache
* @{
*/
extern void ecma_lcache_init (void);
extern void ecma_lcache_insert (ecma_object_t *, ecma_string_t *, ecma_property_t *);
extern ecma_property_t *ecma_lcache_lookup (ecma_object_t *, const ecma_string_t *);
extern void ecma_lcache_invalidate (ecma_object_t *, ecma_string_t *, ecma_property_t *);
/**
* @}
* @}
*/
#endif /* !ECMA_LCACHE_H */

View file

@ -0,0 +1,514 @@
/* Copyright 2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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.
*/
#include "ecma-literal-storage.h"
#include "ecma-helpers.h"
#include "jcontext.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmalitstorage Literal storage
* @{
*/
/**
* Free string list
*/
static void
ecma_free_string_list (ecma_lit_storage_item_t *string_list_p) /**< string list */
{
while (string_list_p != NULL)
{
for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
if (string_list_p->values[i] != JMEM_CP_NULL)
{
ecma_string_t *string_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t,
string_list_p->values[i]);
JERRY_ASSERT (ECMA_STRING_IS_REF_EQUALS_TO_ONE (string_p));
ecma_deref_ecma_string (string_p);
}
}
ecma_lit_storage_item_t *prev_item = string_list_p;
string_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, string_list_p->next_cp);
jmem_pools_free (prev_item, sizeof (ecma_lit_storage_item_t));
}
} /* ecma_free_string_list */
/**
* Finalize literal storage
*/
void
ecma_finalize_lit_storage (void)
{
ecma_free_string_list (JERRY_CONTEXT (string_list_first_p));
ecma_free_string_list (JERRY_CONTEXT (number_list_first_p));
} /* ecma_finalize_lit_storage */
/**
* Find or create a literal string.
*
* @return ecma_string_t compressed pointer
*/
jmem_cpointer_t
ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string to be searched */
lit_utf8_size_t size) /**< size of the string */
{
ecma_string_t *string_p = ecma_new_ecma_string_from_utf8 (chars_p, size);
ecma_lit_storage_item_t *string_list_p = JERRY_CONTEXT (string_list_first_p);
jmem_cpointer_t *empty_cpointer_p = NULL;
while (string_list_p != NULL)
{
for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
if (string_list_p->values[i] == JMEM_CP_NULL)
{
if (empty_cpointer_p == NULL)
{
empty_cpointer_p = string_list_p->values + i;
}
}
else
{
ecma_string_t *value_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t,
string_list_p->values[i]);
if (ecma_compare_ecma_strings (string_p, value_p))
{
/* Return with string if found in the list. */
ecma_deref_ecma_string (string_p);
return string_list_p->values[i];
}
}
}
string_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, string_list_p->next_cp);
}
jmem_cpointer_t result;
JMEM_CP_SET_NON_NULL_POINTER (result, string_p);
if (empty_cpointer_p != NULL)
{
*empty_cpointer_p = result;
return result;
}
ecma_lit_storage_item_t *new_item_p;
new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (sizeof (ecma_lit_storage_item_t));
new_item_p->values[0] = result;
for (int i = 1; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
new_item_p->values[i] = JMEM_CP_NULL;
}
JMEM_CP_SET_POINTER (new_item_p->next_cp, JERRY_CONTEXT (string_list_first_p));
JERRY_CONTEXT (string_list_first_p) = new_item_p;
return result;
} /* ecma_find_or_create_literal_string */
/**
* Find or create a literal number.
*
* @return ecma_string_t compressed pointer
*/
jmem_cpointer_t
ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be searched */
{
ecma_value_t num = ecma_make_number_value (number_arg);
ecma_lit_storage_item_t *number_list_p = JERRY_CONTEXT (number_list_first_p);
jmem_cpointer_t *empty_cpointer_p = NULL;
while (number_list_p != NULL)
{
for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
if (number_list_p->values[i] == JMEM_CP_NULL)
{
if (empty_cpointer_p == NULL)
{
empty_cpointer_p = number_list_p->values + i;
}
}
else
{
ecma_string_t *value_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t,
number_list_p->values[i]);
JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (value_p) == ECMA_STRING_LITERAL_NUMBER);
if (ecma_is_value_integer_number (num))
{
if (value_p->u.lit_number == num)
{
return number_list_p->values[i];
}
}
else
{
if (ecma_is_value_float_number (value_p->u.lit_number)
&& ecma_get_float_from_value (value_p->u.lit_number) == ecma_get_float_from_value (num))
{
ecma_free_value (num);
return number_list_p->values[i];
}
}
}
}
number_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, number_list_p->next_cp);
}
ecma_string_t *string_p = (ecma_string_t *) jmem_pools_alloc (sizeof (ecma_string_t));
string_p->refs_and_container = ECMA_STRING_REF_ONE | ECMA_STRING_LITERAL_NUMBER;
string_p->u.lit_number = num;
jmem_cpointer_t result;
JMEM_CP_SET_NON_NULL_POINTER (result, string_p);
if (empty_cpointer_p != NULL)
{
*empty_cpointer_p = result;
return result;
}
ecma_lit_storage_item_t *new_item_p;
new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (sizeof (ecma_lit_storage_item_t));
new_item_p->values[0] = result;
for (int i = 1; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
new_item_p->values[i] = JMEM_CP_NULL;
}
JMEM_CP_SET_POINTER (new_item_p->next_cp, JERRY_CONTEXT (number_list_first_p));
JERRY_CONTEXT (number_list_first_p) = new_item_p;
return result;
} /* ecma_find_or_create_literal_number */
/**
* Log2 of snapshot literal alignment.
*/
#define JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG 2
/**
* Snapshot literal alignment.
*/
#define JERRY_SNAPSHOT_LITERAL_ALIGNMENT (1u << JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG)
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
/**
* Save literals to specified snapshot buffer.
*
* @return true, if save was performed successfully (i.e. buffer size is sufficient),
* false - otherwise.
*/
bool
ecma_save_literals_for_snapshot (uint8_t *buffer_p, /**< [out] output snapshot buffer */
size_t buffer_size, /**< size of the buffer */
size_t *in_out_buffer_offset_p, /**< [in,out] write position in the buffer */
lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< [out] map from literal identifiers
* to the literal offsets
* in snapshot */
uint32_t *out_map_len_p, /**< [out] number of literals */
uint32_t *out_lit_table_size_p) /**< [out] number of bytes, saved to snapshot buffer */
{
/* Count literals and literal space. */
uint32_t string_count = 0;
uint32_t number_count = 0;
uint32_t lit_table_size = 2 * sizeof (uint32_t);
ecma_lit_storage_item_t *string_list_p = JERRY_CONTEXT (string_list_first_p);
while (string_list_p != NULL)
{
for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
if (string_list_p->values[i] != JMEM_CP_NULL)
{
ecma_string_t *string_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t,
string_list_p->values[i]);
lit_table_size += (uint32_t) JERRY_ALIGNUP (sizeof (uint16_t) + ecma_string_get_size (string_p),
JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
string_count++;
}
}
string_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, string_list_p->next_cp);
}
ecma_lit_storage_item_t *number_list_p = JERRY_CONTEXT (number_list_first_p);
while (number_list_p != NULL)
{
for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
if (number_list_p->values[i] != JMEM_CP_NULL)
{
lit_table_size += (uint32_t) sizeof (ecma_number_t);
number_count++;
}
}
number_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, number_list_p->next_cp);
}
/* Check whether enough space is available. */
if (*in_out_buffer_offset_p + lit_table_size > buffer_size)
{
return false;
}
/* Check whether the maximum literal table size is reached. */
if ((lit_table_size >> JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG) > UINT16_MAX)
{
return false;
}
uint32_t total_count = string_count + number_count;
lit_mem_to_snapshot_id_map_entry_t *map_p;
map_p = jmem_heap_alloc_block (total_count * sizeof (lit_mem_to_snapshot_id_map_entry_t));
/* Set return values (no error is possible from here). */
buffer_p += *in_out_buffer_offset_p;
*in_out_buffer_offset_p += lit_table_size;
*out_map_p = map_p;
*out_map_len_p = total_count;
*out_lit_table_size_p = lit_table_size;
/* Write data into the buffer. */
/* The zero value is reserved for NULL (no literal)
* constant so the first literal must have offset one. */
uint32_t literal_offset = JERRY_SNAPSHOT_LITERAL_ALIGNMENT;
((uint32_t *) buffer_p)[0] = string_count;
((uint32_t *) buffer_p)[1] = number_count;
buffer_p += 2 * sizeof (uint32_t);
string_list_p = JERRY_CONTEXT (string_list_first_p);
while (string_list_p != NULL)
{
for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
if (string_list_p->values[i] != JMEM_CP_NULL)
{
map_p->literal_id = string_list_p->values[i];
map_p->literal_offset = (jmem_cpointer_t) (literal_offset >> JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG);
map_p++;
ecma_string_t *string_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t,
string_list_p->values[i]);
ecma_length_t length = ecma_string_get_size (string_p);
*((uint16_t *) buffer_p) = (uint16_t) length;
ecma_string_to_utf8_bytes (string_p, buffer_p + sizeof (uint16_t), length);
length = JERRY_ALIGNUP (sizeof (uint16_t) + length,
JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
buffer_p += length;
literal_offset += length;
}
}
string_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, string_list_p->next_cp);
}
number_list_p = JERRY_CONTEXT (number_list_first_p);
while (number_list_p != NULL)
{
for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
if (number_list_p->values[i] != JMEM_CP_NULL)
{
map_p->literal_id = number_list_p->values[i];
map_p->literal_offset = (jmem_cpointer_t) (literal_offset >> JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG);
map_p++;
ecma_string_t *value_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t,
number_list_p->values[i]);
JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (value_p) == ECMA_STRING_LITERAL_NUMBER);
ecma_number_t num = ecma_get_number_from_value (value_p->u.lit_number);
memcpy (buffer_p, &num, sizeof (ecma_number_t));
ecma_length_t length = JERRY_ALIGNUP (sizeof (ecma_number_t),
JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
buffer_p += length;
literal_offset += length;
}
}
number_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, number_list_p->next_cp);
}
return true;
} /* ecma_save_literals_for_snapshot */
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
/**
* Helper function for ecma_load_literals_from_snapshot.
*
* Note: always inline because it is used only once.
*
* @return true, if load was performed successfully
* false - otherwise (i.e. buffer length is incorrect).
*/
static inline bool __attr_always_inline___
ecma_load_literals_from_buffer (const uint8_t *buffer_p, /**< buffer with literal table in snapshot */
uint32_t lit_table_size, /**< size of literal table in snapshot */
lit_mem_to_snapshot_id_map_entry_t *map_p, /**< literal map */
uint32_t string_count, /**< number of strings */
uint32_t number_count) /**< number of numbers */
{
/* The zero value is reserved for NULL (no literal)
* constant so the first literal must have offset one. */
uint32_t literal_offset = JERRY_SNAPSHOT_LITERAL_ALIGNMENT;
/* Load strings first. */
while (string_count > 0)
{
if (lit_table_size < literal_offset + sizeof (uint32_t))
{
/* Buffer is not sufficent. */
return false;
}
lit_utf8_size_t length = *((uint16_t *) buffer_p);
lit_utf8_size_t aligned_length = JERRY_ALIGNUP (sizeof (uint16_t) + length,
JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
if (lit_table_size < literal_offset + aligned_length)
{
/* Buffer is not sufficent. */
return false;
}
map_p->literal_id = ecma_find_or_create_literal_string (buffer_p + sizeof (uint16_t), length);
map_p->literal_offset = (jmem_cpointer_t) (literal_offset >> JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG);
map_p++;
buffer_p += aligned_length;
literal_offset += aligned_length;
string_count--;
}
/* Load numbers. */
while (number_count > 0)
{
if (lit_table_size < literal_offset + sizeof (ecma_number_t))
{
/* Buffer is not sufficent. */
return false;
}
ecma_number_t num;
memcpy (&num, buffer_p, sizeof (ecma_number_t));
map_p->literal_id = ecma_find_or_create_literal_number (num);
map_p->literal_offset = (jmem_cpointer_t) (literal_offset >> JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG);
map_p++;
ecma_length_t length = JERRY_ALIGNUP (sizeof (ecma_number_t),
JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
buffer_p += length;
literal_offset += length;
number_count--;
}
return (lit_table_size == (literal_offset + 2 * sizeof (uint32_t) - JERRY_SNAPSHOT_LITERAL_ALIGNMENT));
} /* ecma_load_literals_from_buffer */
/**
* Load literals from snapshot.
*
* @return true, if load was performed successfully (i.e. literals saved in the snapshot are consistent),
* false - otherwise (i.e. snapshot is incorrect).
*/
bool
ecma_load_literals_from_snapshot (const uint8_t *buffer_p, /**< buffer with literal table in snapshot */
uint32_t lit_table_size, /**< size of literal table in snapshot */
lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< [out] map from literal offsets
* in snapshot to identifiers
* of loaded literals in literal
* storage */
uint32_t *out_map_len_p) /**< [out] literals number */
{
*out_map_p = NULL;
if (lit_table_size < 2 * sizeof (uint32_t))
{
/* Buffer is not sufficent. */
return false;
}
uint32_t string_count = ((uint32_t *) buffer_p)[0];
uint32_t number_count = ((uint32_t *) buffer_p)[1];
buffer_p += 2 * sizeof (uint32_t);
uint32_t total_count = string_count + number_count;
lit_mem_to_snapshot_id_map_entry_t *map_p;
*out_map_len_p = total_count;
if (total_count == 0)
{
return true;
}
map_p = jmem_heap_alloc_block (total_count * sizeof (lit_mem_to_snapshot_id_map_entry_t));
*out_map_p = map_p;
if (ecma_load_literals_from_buffer (buffer_p, lit_table_size, map_p, string_count, number_count))
{
return true;
}
jmem_heap_free_block (map_p, total_count * sizeof (lit_mem_to_snapshot_id_map_entry_t));
*out_map_p = NULL;
return false;
} /* ecma_load_literals_from_snapshot */
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
/**
* @}
* @}
*/

View file

@ -0,0 +1,62 @@
/* Copyright 2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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.
*/
#ifndef ECMA_LIT_STORAGE_H
#define ECMA_LIT_STORAGE_H
#include "ecma-globals.h"
#include "jmem-allocator.h"
#include "lit-globals.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmalitstorage Literal storage
* @{
*/
/**
* Snapshot literal - offset map
*/
typedef struct
{
jmem_cpointer_t literal_id; /**< literal id */
jmem_cpointer_t literal_offset; /**< literal offset */
} lit_mem_to_snapshot_id_map_entry_t;
extern void ecma_finalize_lit_storage (void);
extern jmem_cpointer_t ecma_find_or_create_literal_string (const lit_utf8_byte_t *, lit_utf8_size_t);
extern jmem_cpointer_t ecma_find_or_create_literal_number (ecma_number_t);
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
extern bool
ecma_save_literals_for_snapshot (uint8_t *, size_t, size_t *,
lit_mem_to_snapshot_id_map_entry_t **, uint32_t *, uint32_t *);
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
extern bool
ecma_load_literals_from_snapshot (const uint8_t *, uint32_t,
lit_mem_to_snapshot_id_map_entry_t **, uint32_t *);
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
/**
* @}
* @}
*/
#endif /* !ECMA_LIT_STORAGE_H */

View file

@ -0,0 +1,519 @@
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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.
*/
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-property-hashmap.h"
#include "jrt-libc-includes.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmapropertyhashmap Property hashmap
* @{
*/
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
/**
* Compute the total size of the property hashmap.
*/
#define ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE(max_property_count) \
(sizeof (ecma_property_hashmap_t) + (max_property_count * sizeof (jmem_cpointer_t)) + (max_property_count >> 3))
/**
* Number of items in the stepping table.
*/
#define ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS 8
/**
* Stepping values for searching items in the hashmap.
*/
static const uint8_t ecma_property_hashmap_steps[ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS] JERRY_CONST_DATA =
{
3, 5, 7, 11, 13, 17, 19, 23
};
/**
* Get the value of a bit in a bitmap.
*/
#define ECMA_PROPERTY_HASHMAP_GET_BIT(byte_p, index) \
((byte_p)[(index) >> 3] & (1 << ((index) & 0x7)))
/**
* Clear the value of a bit in a bitmap.
*/
#define ECMA_PROPERTY_HASHMAP_CLEAR_BIT(byte_p, index) \
((byte_p)[(index) >> 3] = (uint8_t) ((byte_p)[(index) >> 3] & ~(1 << ((index) & 0x7))))
/**
* Set the value of a bit in a bitmap.
*/
#define ECMA_PROPERTY_HASHMAP_SET_BIT(byte_p, index) \
((byte_p)[(index) >> 3] = (uint8_t) ((byte_p)[(index) >> 3] | (1 << ((index) & 0x7))))
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
/**
* Create a new property hashmap for the object.
* The object must not have a property hashmap.
*/
void
ecma_property_hashmap_create (ecma_object_t *object_p) /**< object */
{
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
JERRY_ASSERT (ecma_get_property_list (object_p) != NULL);
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (ecma_get_property_list (object_p)));
uint32_t named_property_count = 0;
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));
for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
{
ecma_property_types_t type = ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[i]);
if (type == ECMA_PROPERTY_TYPE_NAMEDDATA || type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
{
named_property_count++;
}
}
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
/* The max_property_count must be power of 2. */
uint32_t max_property_count = ECMA_PROPERTY_HASMAP_MINIMUM_SIZE;
/* At least 1/3 items must be NULL. */
while (max_property_count < (named_property_count + (named_property_count >> 1)))
{
max_property_count <<= 1;
}
size_t total_size = ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE (max_property_count);
ecma_property_hashmap_t *hashmap_p = (ecma_property_hashmap_t *) jmem_heap_alloc_block_null_on_error (total_size);
if (hashmap_p == NULL)
{
return;
}
memset (hashmap_p, 0, total_size);
hashmap_p->header.types[0] = ECMA_PROPERTY_TYPE_HASHMAP;
hashmap_p->header.next_property_cp = object_p->property_list_or_bound_object_cp;
hashmap_p->max_property_count = max_property_count;
hashmap_p->null_count = max_property_count - named_property_count;
jmem_cpointer_t *pair_list_p = (jmem_cpointer_t *) (hashmap_p + 1);
uint8_t *bits_p = (uint8_t *) (pair_list_p + max_property_count);
uint32_t mask = max_property_count - 1;
uint8_t shift_counter = 0;
if (max_property_count <= LIT_STRING_HASH_LIMIT)
{
hashmap_p->header.types[1] = 0;
}
else
{
while (max_property_count > LIT_STRING_HASH_LIMIT)
{
shift_counter++;
max_property_count >>= 1;
}
}
hashmap_p->header.types[1] = shift_counter;
prop_iter_p = ecma_get_property_list (object_p);
ECMA_SET_POINTER (object_p->property_list_or_bound_object_cp, hashmap_p);
while (prop_iter_p != NULL)
{
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
{
ecma_property_types_t type = ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[i]);
if (!(type == ECMA_PROPERTY_TYPE_NAMEDDATA || type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR))
{
continue;
}
ecma_property_pair_t *property_pair_p = (ecma_property_pair_t *) prop_iter_p;
ecma_string_t *name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_pair_p->names_cp[i]);
uint32_t entry_index = name_p->hash;
uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
if (mask < LIT_STRING_HASH_LIMIT)
{
entry_index &= mask;
}
else
{
entry_index <<= shift_counter;
JERRY_ASSERT (entry_index <= mask);
}
#ifndef JERRY_NDEBUG
/* Because max_property_count (power of 2) and step (a prime
* number) are relative primes, all entries of the hasmap are
* visited exactly once before the start entry index is reached
* again. Furthermore because at least one NULL is present in
* the hashmap, the while loop must be terminated before the
* the starting index is reached again. */
uint32_t start_entry_index = entry_index;
#endif /* !JERRY_NDEBUG */
while (pair_list_p[entry_index] != ECMA_NULL_POINTER)
{
entry_index = (entry_index + step) & mask;
#ifndef JERRY_NDEBUG
JERRY_ASSERT (entry_index != start_entry_index);
#endif /* !JERRY_NDEBUG */
}
ECMA_SET_POINTER (pair_list_p[entry_index], property_pair_p);
if (i != 0)
{
ECMA_PROPERTY_HASHMAP_SET_BIT (bits_p, entry_index);
}
}
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
#else /* CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
JERRY_UNUSED (object_p);
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
} /* ecma_property_hashmap_create */
/**
* Free the hashmap of the object.
* The object must have a property hashmap.
*/
void
ecma_property_hashmap_free (ecma_object_t *object_p) /**< object */
{
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
/* Property hash must be exists and must be the first property. */
ecma_property_header_t *property_p = ecma_get_property_list (object_p);
JERRY_ASSERT (property_p != NULL
&& ECMA_PROPERTY_GET_TYPE (property_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP);
ecma_property_hashmap_t *hashmap_p = (ecma_property_hashmap_t *) property_p;
object_p->property_list_or_bound_object_cp = property_p->next_property_cp;
jmem_heap_free_block (hashmap_p,
ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE (hashmap_p->max_property_count));
#else /* CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
JERRY_UNUSED (object_p);
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
} /* ecma_property_hashmap_free */
/**
* Insert named property into the hashmap.
*/
void
ecma_property_hashmap_insert (ecma_object_t *object_p, /**< object */
ecma_string_t *name_p, /**< name of the property */
ecma_property_pair_t *property_pair_p, /**< property pair */
int property_index) /**< property index in the pair (0 or 1) */
{
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
ecma_property_hashmap_t *hashmap_p = ECMA_GET_NON_NULL_POINTER (ecma_property_hashmap_t,
object_p->property_list_or_bound_object_cp);
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (hashmap_p->header.types[0]) == ECMA_PROPERTY_TYPE_HASHMAP);
/* The NULLs are reduced below 1/8 of the hashmap. */
if (hashmap_p->null_count < (hashmap_p->max_property_count >> 3))
{
ecma_property_hashmap_free (object_p);
ecma_property_hashmap_create (object_p);
return;
}
JERRY_ASSERT (property_index < ECMA_PROPERTY_PAIR_ITEM_COUNT);
uint32_t entry_index = name_p->hash;
uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
uint32_t mask = hashmap_p->max_property_count - 1;
if (mask < LIT_STRING_HASH_LIMIT)
{
entry_index &= mask;
}
else
{
entry_index <<= hashmap_p->header.types[1];
}
#ifndef JERRY_NDEBUG
/* See the comment for this variable in ecma_property_hashmap_create. */
uint32_t start_entry_index = entry_index;
#endif /* !JERRY_NDEBUG */
jmem_cpointer_t *pair_list_p = (jmem_cpointer_t *) (hashmap_p + 1);
while (pair_list_p[entry_index] != ECMA_NULL_POINTER)
{
entry_index = (entry_index + step) & mask;
#ifndef JERRY_NDEBUG
JERRY_ASSERT (entry_index != start_entry_index);
#endif /* !JERRY_NDEBUG */
}
ECMA_SET_POINTER (pair_list_p[entry_index], property_pair_p);
uint8_t *bits_p = (uint8_t *) (pair_list_p + hashmap_p->max_property_count);
bits_p += (entry_index >> 3);
mask = (uint32_t) (1 << (entry_index & 0x7));
if (!(*bits_p & mask))
{
/* Deleted entries also has ECMA_NULL_POINTER
* value, but they are not NULL values. */
hashmap_p->null_count--;
JERRY_ASSERT (hashmap_p->null_count > 0);
}
if (property_index == 0)
{
*bits_p = (uint8_t) ((*bits_p) & ~mask);
}
else
{
*bits_p = (uint8_t) ((*bits_p) | mask);
}
#else /* CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
JERRY_UNUSED (object_p);
JERRY_UNUSED (name_p);
JERRY_UNUSED (property_pair_p);
JERRY_UNUSED (property_index);
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
} /* ecma_property_hashmap_insert */
/**
* Delete named property from the hashmap.
*/
void
ecma_property_hashmap_delete (ecma_object_t *object_p, /**< object */
ecma_string_t *name_p, /**< name of the property */
ecma_property_t *property_p) /**< property */
{
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
ecma_property_hashmap_t *hashmap_p = ECMA_GET_NON_NULL_POINTER (ecma_property_hashmap_t,
object_p->property_list_or_bound_object_cp);
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (hashmap_p->header.types[0]) == ECMA_PROPERTY_TYPE_HASHMAP);
uint32_t entry_index = name_p->hash;
uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
uint32_t mask = hashmap_p->max_property_count - 1;
jmem_cpointer_t *pair_list_p = (jmem_cpointer_t *) (hashmap_p + 1);
uint8_t *bits_p = (uint8_t *) (pair_list_p + hashmap_p->max_property_count);
if (mask < LIT_STRING_HASH_LIMIT)
{
entry_index &= mask;
}
else
{
entry_index <<= hashmap_p->header.types[1];
JERRY_ASSERT (entry_index <= mask);
}
#ifndef JERRY_NDEBUG
/* See the comment for this variable in ecma_property_hashmap_create. */
uint32_t start_entry_index = entry_index;
#endif /* !JERRY_NDEBUG */
while (true)
{
if (pair_list_p[entry_index] != ECMA_NULL_POINTER)
{
size_t offset = 0;
if (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
{
offset = 1;
}
ecma_property_pair_t *property_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_property_pair_t,
pair_list_p[entry_index]);
if ((property_pair_p->header.types + offset) == property_p)
{
JERRY_ASSERT (ecma_compare_ecma_strings (ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_pair_p->names_cp[offset]),
name_p));
pair_list_p[entry_index] = ECMA_NULL_POINTER;
ECMA_PROPERTY_HASHMAP_SET_BIT (bits_p, entry_index);
return;
}
}
else
{
/* Must be a deleted entry. */
JERRY_ASSERT (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index));
}
entry_index = (entry_index + step) & mask;
#ifndef JERRY_NDEBUG
JERRY_ASSERT (entry_index != start_entry_index);
#endif /* !JERRY_NDEBUG */
}
#else /* CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
JERRY_UNUSED (object_p);
JERRY_UNUSED (name_p);
JERRY_UNUSED (property_p);
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
} /* ecma_property_hashmap_delete */
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
/**
* Find a named property.
*
* @return pointer to the property if found or NULL otherwise
*/
ecma_property_t *
ecma_property_hashmap_find (ecma_property_hashmap_t *hashmap_p, /**< hashmap */
ecma_string_t *name_p, /**< property name */
ecma_string_t **property_real_name_p) /**< [out] property real name */
{
#ifndef JERRY_NDEBUG
/* A sanity check in debug mode: a named property must be present
* in both the property hashmap and in the property chain, or missing
* from both data collection. The following code checks the property
* chain, and sets the property_found variable. */
bool property_found = false;
ecma_property_header_t *prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
hashmap_p->header.next_property_cp);
while (prop_iter_p != NULL && !property_found)
{
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->names_cp[i] != ECMA_NULL_POINTER)
{
ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
prop_pair_p->names_cp[i]);
if (ecma_compare_ecma_strings (name_p, property_name_p))
{
property_found = true;
break;
}
}
}
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
#endif /* !JERRY_NDEBUG */
uint32_t entry_index = name_p->hash;
uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
uint32_t mask = hashmap_p->max_property_count - 1;
jmem_cpointer_t *pair_list_p = (jmem_cpointer_t *) (hashmap_p + 1);
uint8_t *bits_p = (uint8_t *) (pair_list_p + hashmap_p->max_property_count);
if (mask < LIT_STRING_HASH_LIMIT)
{
entry_index &= mask;
}
else
{
entry_index <<= hashmap_p->header.types[1];
JERRY_ASSERT (entry_index <= mask);
}
#ifndef JERRY_NDEBUG
/* See the comment for this variable in ecma_property_hashmap_create. */
uint32_t start_entry_index = entry_index;
#endif /* !JERRY_NDEBUG */
while (true)
{
if (pair_list_p[entry_index] != ECMA_NULL_POINTER)
{
size_t offset = 0;
if (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
{
offset = 1;
}
ecma_property_pair_t *property_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_property_pair_t,
pair_list_p[entry_index]);
ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_pair_p->names_cp[offset]);
if (ecma_compare_ecma_strings (name_p, property_name_p))
{
#ifndef JERRY_NDEBUG
JERRY_ASSERT (property_found);
#endif /* !JERRY_NDEBUG */
*property_real_name_p = property_name_p;
return property_pair_p->header.types + offset;
}
}
else
{
if (!ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
{
#ifndef JERRY_NDEBUG
JERRY_ASSERT (!property_found);
#endif /* !JERRY_NDEBUG */
return NULL;
}
/* Otherwise it is a deleted entry. */
}
entry_index = (entry_index + step) & mask;
#ifndef JERRY_NDEBUG
JERRY_ASSERT (entry_index != start_entry_index);
#endif /* !JERRY_NDEBUG */
}
} /* ecma_property_hashmap_find */
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
/**
* @}
* @}
*/

View file

@ -0,0 +1,70 @@
/* Copyright 2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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.
*/
#ifndef ECMA_PROPERTY_HASHMAP_H
#define ECMA_PROPERTY_HASHMAP_H
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmapropertyhashmap Property hashmap
* @{
*/
/**
* Recommended minimum number of items in a property cache.
*/
#define ECMA_PROPERTY_HASMAP_MINIMUM_SIZE 32
/**
* Property hash.
*/
typedef struct
{
ecma_property_header_t header; /**< header of the property */
uint32_t max_property_count; /**< maximum property count (power of 2) */
uint32_t null_count; /**< number of NULLs in the map */
/*
* The hash is followed by max_property_count ecma_cpointer_t
* compressed pointers and (max_property_count + 7) / 8 bytes
* which stores a flag for each compressed pointer.
*
* If the compressed pointer is equal to ECMA_NULL_POINTER
* - flag is cleared if the entry is NULL
* - flag is set if the entry is deleted
*
* If the compressed pointer is not equal to ECMA_NULL_POINTER
* - flag is cleared if the first entry of a property pair is referenced
* - flag is set if the second entry of a property pair is referenced
*/
} ecma_property_hashmap_t;
extern void ecma_property_hashmap_create (ecma_object_t *);
extern void ecma_property_hashmap_free (ecma_object_t *);
extern void ecma_property_hashmap_insert (ecma_object_t *, ecma_string_t *, ecma_property_pair_t *, int);
extern void ecma_property_hashmap_delete (ecma_object_t *, ecma_string_t *, ecma_property_t *);
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
extern ecma_property_t *ecma_property_hashmap_find (ecma_property_hashmap_t *, ecma_string_t *, ecma_string_t **);
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
/**
* @}
* @}
*/
#endif /* !ECMA_PROPERTY_HASHMAP_H */