Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
328 changes: 328 additions & 0 deletions jerry-core/ecma/builtin-objects/ecma-builtin-bigint.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* limitations under the License.
*/

#include "ecma-big-uint.h"
#include "ecma-bigint.h"
#include "ecma-builtins.h"
#include "ecma-exceptions.h"
Expand All @@ -22,6 +23,21 @@
#define ECMA_BUILTINS_INTERNAL
#include "ecma-builtins-internal.h"

/**
* This object has a custom dispatch function.
*/
#define BUILTIN_CUSTOM_DISPATCH

/**
* List of built-in routine identifiers.
*/
enum
{
ECMA_BUILTIN_BIGINT_START = 0, /**< Special value, should be ignored */
ECMA_BUILTIN_BIGINT_AS_INT_N, /**< The 'asIntN' routine of the BigInt object */
ECMA_BUILTIN_BIGINT_AS_U_INT_N, /**< The 'asUintN' routine of the BigInt object */
};

#define BUILTIN_INC_HEADER_NAME "ecma-builtin-bigint.inc.h"
#define BUILTIN_UNDERSCORED_ID bigint
#include "ecma-builtin-internal-routines-template.inc.h"
Expand All @@ -36,6 +52,286 @@
* @{
*/

/**
* The BigInt object's 'asIntN' and 'asUintN' routines
*
* See also:
* ECMA-262 v15, 21.2.2
*
* @return ecma value
* Truncated BigInt value for the given number of LSBs
* as an integer or unsigned integer.
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_bigint_object_as_int_n (ecma_value_t bits, /**< number of bits */
ecma_value_t bigint, /**< bigint number */
bool is_signed) /**< The operation is signed */
{
ecma_number_t input_bits;
ecma_value_t bit_value = ecma_op_to_index (bits, &input_bits);

if (ECMA_IS_VALUE_ERROR (bit_value))
{
return bit_value;
}

ecma_value_t bigint_value = ecma_bigint_to_bigint (bigint, false);

if (ECMA_IS_VALUE_ERROR (bigint_value))
{
return bigint_value;
}

if (input_bits == 0 || bigint_value == ECMA_BIGINT_ZERO)
{
ecma_free_value (bigint_value);
return ECMA_BIGINT_ZERO;
}

ecma_extended_primitive_t *input_bigint_p = ecma_get_extended_primitive_from_value (bigint_value);
uint32_t bigint_size = ECMA_BIGINT_GET_SIZE (input_bigint_p);

if (input_bits >= UINT32_MAX)
{
return bigint_value;
}

uint8_t input_bigint_sign = input_bigint_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
const uint32_t size_of_divisor_in_bits = sizeof (uint32_t) * JERRY_BITSINBYTE;
uint32_t whole_part = (uint32_t) input_bits / size_of_divisor_in_bits;
uint32_t remainder = (uint32_t) input_bits % size_of_divisor_in_bits;
uint32_t input_bit_length =
(whole_part == 0 || remainder == 0) ? (uint32_t) input_bits : (whole_part + 1) * size_of_divisor_in_bits;

uint32_t input_byte_size = (uint32_t) input_bits / JERRY_BITSINBYTE;

if ((uint32_t) input_bits % JERRY_BITSINBYTE != 0)
{
input_byte_size += 1;
}

const uint32_t input_bits_in_byte = (uint32_t) input_bit_length / JERRY_BITSINBYTE;
uint32_t min_size = (input_bits_in_byte < bigint_size) ? input_bits_in_byte : bigint_size;

if (input_bigint_sign && (input_byte_size > bigint_size))
{
min_size = (input_bits_in_byte > bigint_size) ? input_bits_in_byte : bigint_size;
}

if (min_size < sizeof (uint32_t))
{
min_size = sizeof (uint32_t);
}

ecma_extended_primitive_t *result_p = ecma_bigint_create ((uint32_t) min_size);

if (JERRY_UNLIKELY (result_p == NULL))
{
ecma_deref_bigint (input_bigint_p);
return ECMA_VALUE_ERROR;
}

ecma_bigint_digit_t *last_digit_p = ECMA_BIGINT_GET_DIGITS (input_bigint_p, bigint_size);

/* Calculate the leading zeros of the input_bigint */

ecma_bigint_digit_t zeros = ecma_big_uint_count_leading_zero (last_digit_p[-1]);
uint32_t bits_of_bigint = (uint32_t) (bigint_size * JERRY_BITSINBYTE) - zeros;
uint32_t exact_size =
(input_bigint_sign || ((bits_of_bigint > (size_of_divisor_in_bits - 1)) && (input_byte_size < bigint_size)))
? (uint32_t) input_byte_size
: bigint_size;

if (input_bigint_sign)
{
bits_of_bigint += 1;
}

if (bits_of_bigint > (input_bits - 1) || input_bigint_sign)
{
ecma_bigint_digit_t *digits_p = ECMA_BIGINT_GET_DIGITS (input_bigint_p, 0);
ecma_bigint_digit_t *digits_end_p = ECMA_BIGINT_GET_DIGITS (input_bigint_p, exact_size);
ecma_bigint_digit_t *result_number_p = ECMA_BIGINT_GET_DIGITS (result_p, 0);
int32_t first_cell = 0;
uint32_t surplus_bits =
(whole_part > 0) ? (uint32_t) (whole_part * size_of_divisor_in_bits) : (uint32_t) size_of_divisor_in_bits;
uint32_t mask_bit = (whole_part == 0) ? (uint32_t) input_bits : (uint32_t) input_bits - surplus_bits;

if (mask_bit == 0)
{
mask_bit = size_of_divisor_in_bits - 1;
}

uint32_t check_sign_mask = (uint32_t) 1 << (mask_bit - 1);
uint32_t mask = ((uint32_t) 1 << mask_bit) - 1;
uint32_t last_cell = (exact_size >= sizeof (uint32_t)) ? (uint32_t) (min_size / sizeof (uint32_t)) - 1 : 0;
bool is_positive = false;
bool is_representation_positive = false;

if (is_signed)
{
if (input_bigint_sign && ((~digits_p[last_cell] + 1) & check_sign_mask) == 0)
{
is_positive = true;
}

if ((digits_p[last_cell] & check_sign_mask) == 0)
{
is_representation_positive = true;
}
}

do
{
*result_number_p++ =
(is_representation_positive || (!is_signed && !input_bigint_sign)) ? *digits_p++ : ~(*digits_p++);
first_cell--;
} while (digits_p < digits_end_p);

int16_t equal_bits = 0;

if (remainder != 0)
{
equal_bits = -1;
}

int32_t last_cell_negative = (last_cell != 0) ? ((int32_t) last_cell * (-1)) : -1;
bool is_zero_values = false;

if (!is_signed)
{
if (input_bigint_sign)
{
is_zero_values = true;
}
}
else
{
if (((digits_p[-1] & check_sign_mask) > 0) || (result_number_p[-1] & check_sign_mask) > 0)
{
is_zero_values = true;
}
}

if (is_zero_values)
{
result_number_p[first_cell] += 1;

if (result_number_p[first_cell] == 0)
{
do
{
result_number_p[++first_cell] += 1;
} while (first_cell != equal_bits);

first_cell = last_cell_negative;
}
}

result_number_p[-1] &= mask;
uint32_t surplus = (uint32_t) (min_size - exact_size) / sizeof (ecma_char_t);
uint32_t new_size = result_p->u.bigint_sign_and_size;

if ((min_size - exact_size) % (sizeof (ecma_char_t)) > 0 && surplus == 0)
{
surplus += (uint32_t) sizeof (ecma_char_t);
}
else
{
surplus = (uint32_t) (surplus * sizeof (ecma_char_t));
}

if (min_size / JERRY_BITSINBYTE < 1)
{
surplus = 0;
}

if (is_signed)
{
if (result_p->u.bigint_sign_and_size > exact_size && min_size > sizeof (uint32_t)
&& result_number_p[last_cell_negative] < 1)
{
new_size -= surplus;
}

new_size += 1;

if (is_positive || ((digits_p[-1] & check_sign_mask) == 0 && !input_bigint_sign))
{
new_size -= 1;
}
}

while (first_cell != 0 && result_number_p[first_cell] == 0)
{
first_cell++;
}

if (first_cell == 0)
{
ecma_deref_bigint (result_p);
ecma_deref_bigint (input_bigint_p);

return ECMA_BIGINT_ZERO;
}

last_cell_negative = first_cell + (int32_t) last_cell;
int16_t zero_section_cnt = 0;

while (last_cell_negative > first_cell)
{
if (result_number_p[last_cell_negative] == 0)
{
zero_section_cnt++;
}

last_cell_negative--;
}

uint32_t size_limit = sizeof (uint32_t);

if (zero_section_cnt >= 1)
{
size_limit = new_size - (uint32_t) zero_section_cnt * size_limit;
new_size = (size_limit < sizeof (uint32_t)) ? (uint32_t) (JERRY_BITSINBYTE - size_limit) : size_limit;
}

if (new_size < result_p->u.bigint_sign_and_size)
{
result_p->refs_and_type = ECMA_EXTENDED_PRIMITIVE_REF_ONE | ECMA_TYPE_BIGINT;
uint32_t new_size_remainder = new_size % sizeof (uint32_t);
ecma_extended_primitive_t *new_result_p = ecma_bigint_create (new_size - new_size_remainder);

new_result_p->u.bigint_sign_and_size += new_size_remainder;
memcpy (new_result_p + 1, result_p + 1, new_size - new_size_remainder);

ecma_deref_bigint (result_p);
ecma_deref_bigint (input_bigint_p);

return ecma_make_extended_primitive_value (new_result_p, ECMA_TYPE_BIGINT);
}

result_p->u.bigint_sign_and_size = new_size;
result_p->refs_and_type = ECMA_EXTENDED_PRIMITIVE_REF_ONE | ECMA_TYPE_BIGINT;

ecma_deref_bigint (input_bigint_p);
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
}

memcpy (result_p + 1, input_bigint_p + 1, exact_size);
result_p->refs_and_type = ECMA_EXTENDED_PRIMITIVE_REF_ONE | ECMA_TYPE_BIGINT;

if (input_bigint_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
{
ecma_deref_bigint (input_bigint_p);
return ecma_bigint_negate (result_p);
}

ecma_deref_bigint (input_bigint_p);
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
} /* ecma_builtin_bigint_object_as_int_n */

/**
* Handle calling [[Call]] of built-in BigInt object
*
Expand Down Expand Up @@ -71,6 +367,38 @@ ecma_builtin_bigint_dispatch_construct (const ecma_value_t *arguments_list_p, /*
return ecma_raise_type_error (ECMA_ERR_BIGINT_FUNCTION_NOT_CONSTRUCTOR);
} /* ecma_builtin_bigint_dispatch_construct */

/**
* Dispatcher of the built-in's routines
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
ecma_value_t
ecma_builtin_bigint_dispatch_routine (uint8_t builtin_routine_id, /**< built-in wide routine identifier */
ecma_value_t this_arg, /**< 'this' argument value */
const ecma_value_t arguments_list_p[], /**< list of arguments
* passed to routine */
uint32_t arguments_number) /**< length of arguments' list */
{
JERRY_UNUSED_2 (this_arg, arguments_number);

switch (builtin_routine_id)
{
case ECMA_BUILTIN_BIGINT_AS_INT_N:
{
return ecma_builtin_bigint_object_as_int_n (arguments_list_p[0], arguments_list_p[1], true);
}
case ECMA_BUILTIN_BIGINT_AS_U_INT_N:
{
return ecma_builtin_bigint_object_as_int_n (arguments_list_p[0], arguments_list_p[1], false);
}
default:
{
JERRY_UNREACHABLE ();
}
}
} /* ecma_builtin_bigint_dispatch_routine */

/**
* @}
* @}
Expand Down
5 changes: 5 additions & 0 deletions jerry-core/ecma/builtin-objects/ecma-builtin-bigint.inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ STRING_VALUE (LIT_MAGIC_STRING_NAME, LIT_MAGIC_STRING_BIGINT_UL, ECMA_PROPERTY_F
/* ECMA-262 v11, 20.2.2.3 */
OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, ECMA_BUILTIN_ID_BIGINT_PROTOTYPE, ECMA_PROPERTY_FIXED)

/* Routine properties:
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */

ROUTINE (LIT_MAGIC_STRING_AS_INT_N, ECMA_BUILTIN_BIGINT_AS_INT_N, 2, 2)
ROUTINE (LIT_MAGIC_STRING_AS_U_INT_N, ECMA_BUILTIN_BIGINT_AS_U_INT_N, 2, 2)
#endif /* JERRY_BUILTIN_BIGINT */

#include "ecma-builtin-helpers-macro-undefs.inc.h"
6 changes: 6 additions & 0 deletions jerry-core/lit/lit-magic-strings.inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SCRIPT_UL, "Script")
#endif /* JERRY_PARSER */
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_STRING_UL, "String")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL_UL, "Symbol")
#if JERRY_BUILTIN_BIGINT
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_AS_INT_N, "asIntN")
#endif /* JERRY_BUILTIN_BIGINT */
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASSIGN, "assign")
#if JERRY_BUILTIN_BIGINT
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BIGINT, "bigint")
Expand Down Expand Up @@ -411,6 +414,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKREF_UL, "WeakRef")
#if JERRY_BUILTIN_CONTAINER
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKSET_UL, "WeakSet")
#endif /* JERRY_BUILTIN_CONTAINER */
#if JERRY_BUILTIN_BIGINT
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_AS_U_INT_N, "asUintN")
#endif /* JERRY_BUILTIN_BIGINT */
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BOOLEAN, "boolean")
#if JERRY_BUILTIN_ANNEXB && JERRY_BUILTIN_REGEXP
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMPILE, "compile")
Expand Down
2 changes: 2 additions & 0 deletions jerry-core/lit/lit-magic-strings.ini
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ LIT_MAGIC_STRING_THROW = "throw"
LIT_MAGIC_STRING_TRUNC = "trunc"
LIT_MAGIC_STRING_VALUE = "value"
LIT_MAGIC_STRING_SOURCE_NAME_EVAL = "<eval>"
LIT_MAGIC_STRING_AS_INT_N = "asIntN"
LIT_MAGIC_STRING_AS_U_INT_N = "asUintN"
LIT_MAGIC_STRING_BIGINT_UL = "BigInt"
LIT_MAGIC_STRING_ERRORS_UL = "errors"
LIT_MAGIC_STRING_HAS_OWN_UL = "hasOwn"
Expand Down
Loading
Loading