Introduce integer ecma-value representation to reduce the double allocations.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2016-05-17 00:11:05 -07:00
parent 7cf8b79429
commit 00f759e275
32 changed files with 759 additions and 588 deletions
+55 -6
View File
@@ -55,8 +55,8 @@
*/
typedef enum
{
ECMA_TYPE_SIMPLE, /**< simple value */
ECMA_TYPE_NUMBER, /**< 64-bit integer */
ECMA_TYPE_DIRECT, /**< directly encoded value, a 28 bit signed integer or a simple value */
ECMA_TYPE_FLOAT, /**< pointer to a 64 or 32 bit floating point number */
ECMA_TYPE_STRING, /**< pointer to description of a string */
ECMA_TYPE_OBJECT, /**< pointer to description of an object */
ECMA_TYPE___MAX = ECMA_TYPE_OBJECT /** highest value for ecma types */
@@ -68,10 +68,10 @@ typedef enum
typedef enum
{
/**
* Empty value is implementation defined value, used for:
* - representing empty value in completion values (see also: ECMA-262 v5, 8.9 Completion specification type);
* - values of uninitialized immutable bindings;
* - values of empty register variables.
* Empty value is implementation defined value, used for representing:
* - empty (uninitialized) values
* - immutable binding values
* - special register or stack values for vm
*/
ECMA_SIMPLE_VALUE_EMPTY,
ECMA_SIMPLE_VALUE_UNDEFINED, /**< undefined value */
@@ -90,6 +90,11 @@ typedef enum
*/
typedef uint32_t ecma_value_t;
/**
* Type for directly encoded integer numbers in JerryScript.
*/
typedef int32_t ecma_integer_value_t;
#if UINTPTR_MAX <= UINT32_MAX
/**
@@ -114,6 +119,50 @@ typedef uint32_t ecma_value_t;
*/
#define ECMA_VALUE_SHIFT 3
/**
* Mask for directly encoded values
*/
#define ECMA_DIRECT_TYPE_MASK ((1u << ECMA_VALUE_SHIFT) | ECMA_VALUE_TYPE_MASK)
/**
* Ecma integer value type
*/
#define ECMA_DIRECT_TYPE_INTEGER_VALUE ((0u << ECMA_VALUE_SHIFT) | ECMA_TYPE_DIRECT)
/**
* Ecma simple value type
*/
#define ECMA_DIRECT_TYPE_SIMPLE_VALUE ((1u << ECMA_VALUE_SHIFT) | ECMA_TYPE_DIRECT)
/**
* Shift for directly encoded values in ecma_value_t
*/
#define ECMA_DIRECT_SHIFT 4
/**
* Maximum integer number for an ecma value
*/
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
#define ECMA_INTEGER_NUMBER_MAX 0x7fffff
#else /* CONFIG_ECMA_NUMBER_TYPE != CONFIG_ECMA_NUMBER_FLOAT32 */
#define ECMA_INTEGER_NUMBER_MAX 0x7ffffff
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */
/**
* Minimum integer number for an ecma value
*/
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
#define ECMA_INTEGER_NUMBER_MIN -0x7fffff
#else /* CONFIG_ECMA_NUMBER_TYPE != CONFIG_ECMA_NUMBER_FLOAT32 */
#define ECMA_INTEGER_NUMBER_MIN -0x8000000
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */
/**
* Checks whether the integer number is in the integer number range.
*/
#define ECMA_IS_INTEGER_NUMBER(num) \
(ECMA_INTEGER_NUMBER_MIN <= (num) && (num) <= ECMA_INTEGER_NUMBER_MAX)
/**
* Internal properties' identifiers.
*/
@@ -24,6 +24,15 @@
* @{
*/
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)
+297 -25
View File
@@ -206,6 +206,30 @@ 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 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.
*
@@ -215,7 +239,8 @@ ecma_is_value_array_hole (ecma_value_t value) /**< ecma value */
inline bool __attr_pure___ __attr_always_inline___
ecma_is_value_number (ecma_value_t value) /**< ecma value */
{
return (ecma_get_value_type_field (value) == ECMA_TYPE_NUMBER);
return (ecma_is_value_integer_number (value)
|| ecma_is_value_float_number (value));
} /* ecma_is_value_number */
/**
@@ -275,20 +300,134 @@ ecma_check_value_type_is_spec_defined (ecma_value_t value) /**< ecma value */
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_VALUE_SHIFT) | ECMA_TYPE_SIMPLE;
return (((ecma_value_t) (simple_value)) << ECMA_DIRECT_SHIFT) | ECMA_DIRECT_TYPE_SIMPLE_VALUE;
} /* ecma_make_simple_value */
/**
* Number value constructor
* 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
*/
ecma_value_t __attr_const___
ecma_make_number_value (const ecma_number_t *ecma_num_p) /**< number to reference in 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_num_p != NULL);
JERRY_ASSERT (ECMA_IS_INTEGER_NUMBER (integer_value));
return ecma_pointer_to_ecma_value (ecma_num_p) | ECMA_TYPE_NUMBER;
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
*/
@@ -333,24 +472,48 @@ ecma_make_error_obj_value (const ecma_object_t *object_p) /**< object to referen
} /* ecma_make_error_obj_value */
/**
* Get pointer to ecma-number from ecma value
* Get floating point value from an ecma value
*
* @return the pointer
* @return floating point value
*/
ecma_number_t *__attr_pure___
ecma_number_t __attr_pure___
ecma_get_number_from_value (ecma_value_t value) /**< ecma value */
{
JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_NUMBER);
if (ecma_is_value_integer_number (value))
{
return (ecma_number_t) (((ecma_integer_value_t) value) >> ECMA_DIRECT_SHIFT);
}
return (ecma_number_t *) ecma_get_pointer_from_ecma_value (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_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
*/
ecma_string_t *__attr_pure___
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);
@@ -363,7 +526,7 @@ ecma_get_string_from_value (ecma_value_t value) /**< ecma value */
*
* @return the pointer
*/
ecma_object_t *__attr_pure___
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);
@@ -398,18 +561,15 @@ ecma_copy_value (ecma_value_t value) /**< value description */
{
switch (ecma_get_value_type_field (value))
{
case ECMA_TYPE_SIMPLE:
case ECMA_TYPE_DIRECT:
{
return value;
}
case ECMA_TYPE_NUMBER:
case ECMA_TYPE_FLOAT:
{
ecma_number_t *num_p = ecma_get_number_from_value (value);
ecma_number_t *num_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (value);
ecma_number_t *number_copy_p = ecma_alloc_number ();
*number_copy_p = *num_p;
return ecma_make_number_value (number_copy_p);
return ecma_create_float_number (*num_p);
}
case ECMA_TYPE_STRING:
{
@@ -441,6 +601,118 @@ ecma_copy_value_if_not_object (ecma_value_t value) /**< value description */
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 (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 */
/**
* 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
*/
@@ -449,15 +721,15 @@ ecma_free_value (ecma_value_t value) /**< value description */
{
switch (ecma_get_value_type_field (value))
{
case ECMA_TYPE_SIMPLE:
case ECMA_TYPE_DIRECT:
{
/* doesn't hold additional memory */
/* no memory is allocated */
break;
}
case ECMA_TYPE_NUMBER:
case ECMA_TYPE_FLOAT:
{
ecma_number_t *number_p = ecma_get_number_from_value (value);
ecma_number_t *number_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (value);
ecma_dealloc_number (number_p);
break;
}
+2 -14
View File
@@ -1110,21 +1110,9 @@ ecma_named_data_property_assign_value (ecma_object_t *obj_p, /**< object */
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
ecma_assert_object_contains_the_property (obj_p, prop_p);
if (ecma_is_value_number (value)
&& ecma_is_value_number (ecma_get_named_data_property_value (prop_p)))
{
const ecma_number_t *num_src_p = ecma_get_number_from_value (value);
ecma_number_t *num_dst_p = ecma_get_number_from_value (ecma_get_named_data_property_value (prop_p));
ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p);
*num_dst_p = *num_src_p;
}
else
{
ecma_value_t v = ecma_get_named_data_property_value (prop_p);
ecma_free_value_if_not_object (v);
ecma_set_named_data_property_value (prop_p, ecma_copy_value_if_not_object (value));
}
ecma_value_assign_value (&prop_value_p->value, value);
} /* ecma_named_data_property_assign_value */
/**
+12 -2
View File
@@ -122,6 +122,8 @@ extern bool ecma_is_value_true (ecma_value_t);
extern bool ecma_is_value_false (ecma_value_t);
extern bool ecma_is_value_array_hole (ecma_value_t);
extern bool ecma_is_value_integer_number (ecma_value_t);
extern bool ecma_is_value_float_number (ecma_value_t);
extern bool ecma_is_value_number (ecma_value_t);
extern bool ecma_is_value_string (ecma_value_t);
extern bool ecma_is_value_object (ecma_value_t);
@@ -130,17 +132,25 @@ extern bool ecma_is_value_error (ecma_value_t);
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);
extern ecma_value_t ecma_make_number_value (const ecma_number_t *);
extern ecma_value_t ecma_make_integer_value (ecma_integer_value_t);
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_number_t *ecma_get_number_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_copy_value (ecma_value_t);
extern ecma_value_t ecma_copy_value_if_not_object (ecma_value_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_free_value_if_not_object (ecma_value_t);