Skip to content

Commit addf8f2

Browse files
committed
Implement BigInt asIntN and asUintN methods
The following methods were implemented: - BigInt.asIntN - BigInt.asUintN Custom dispatcher also added to builtin_bigint. The implementation is based on PR #4736, only applied the requested changes. Co-authored-by: Daniel Batiz [email protected] JerryScript-DCO-1.0-Signed-off-by: Gergo Csizi [email protected]
1 parent d2e0d71 commit addf8f2

File tree

8 files changed

+560
-26
lines changed

8 files changed

+560
-26
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-bigint.c

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* limitations under the License.
1414
*/
1515

16+
#include "ecma-big-uint.h"
1617
#include "ecma-bigint.h"
1718
#include "ecma-builtins.h"
1819
#include "ecma-exceptions.h"
@@ -22,6 +23,21 @@
2223
#define ECMA_BUILTINS_INTERNAL
2324
#include "ecma-builtins-internal.h"
2425

26+
/**
27+
* This object has a custom dispatch function.
28+
*/
29+
#define BUILTIN_CUSTOM_DISPATCH
30+
31+
/**
32+
* List of built-in routine identifiers.
33+
*/
34+
enum
35+
{
36+
ECMA_BUILTIN_BIGINT_START = 0, /**< Special value, should be ignored */
37+
ECMA_BUILTIN_BIGINT_AS_INT_N, /**< The 'asIntN' routine of the BigInt object */
38+
ECMA_BUILTIN_BIGINT_AS_U_INT_N, /**< The 'asUintN' routine of the BigInt object */
39+
};
40+
2541
#define BUILTIN_INC_HEADER_NAME "ecma-builtin-bigint.inc.h"
2642
#define BUILTIN_UNDERSCORED_ID bigint
2743
#include "ecma-builtin-internal-routines-template.inc.h"
@@ -36,6 +52,289 @@
3652
* @{
3753
*/
3854

55+
/**
56+
* The BigInt object's 'asIntN' and 'asUintN' routines
57+
*
58+
* See also:
59+
* ECMA-262 v5, 11.0
60+
*
61+
* @return ecma value
62+
* Returned value must be freed with ecma_free_value.
63+
*/
64+
static ecma_value_t
65+
ecma_builtin_bigint_object_as_int_n (ecma_value_t bits, /**< number of bits */
66+
ecma_value_t bigint, /**< bigint number */
67+
bool is_signed) /**< The operation is signed */
68+
{
69+
ecma_number_t input_bits;
70+
ecma_value_t bit_value = ecma_op_to_index (bits, &input_bits);
71+
72+
if (ECMA_IS_VALUE_ERROR (bit_value))
73+
{
74+
return bit_value;
75+
}
76+
77+
ecma_value_t bigint_value = ecma_bigint_to_bigint (bigint, false);
78+
79+
if (ECMA_IS_VALUE_ERROR (bigint_value))
80+
{
81+
return bigint_value;
82+
}
83+
84+
if (input_bits == 0 || bigint_value == ECMA_BIGINT_ZERO)
85+
{
86+
ecma_free_value (bigint_value);
87+
return ECMA_BIGINT_ZERO;
88+
}
89+
90+
ecma_extended_primitive_t *input_bigint_p = ecma_get_extended_primitive_from_value (bigint_value);
91+
uint32_t bigint_size = ECMA_BIGINT_GET_SIZE (input_bigint_p);
92+
93+
if (input_bits >= UINT32_MAX)
94+
{
95+
return bigint_value;
96+
}
97+
98+
uint8_t input_bigint_sign = input_bigint_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
99+
const uint32_t size_of_divisor_in_bits = sizeof (uint32_t) * JERRY_BITSINBYTE;
100+
uint32_t whole_part = (uint32_t) input_bits / size_of_divisor_in_bits;
101+
uint32_t remainder = (uint32_t) input_bits % size_of_divisor_in_bits;
102+
uint32_t input_bit_length =
103+
(whole_part == 0 || remainder == 0) ? (uint32_t) input_bits : (whole_part + 1) * size_of_divisor_in_bits;
104+
105+
uint32_t input_byte_size = (uint32_t) input_bits / JERRY_BITSINBYTE;
106+
107+
if ((uint32_t) input_bits % JERRY_BITSINBYTE != 0)
108+
{
109+
input_byte_size += 1;
110+
}
111+
112+
const uint32_t input_bits_in_byte = (uint32_t) input_bit_length / JERRY_BITSINBYTE;
113+
uint32_t min_size = (input_bits_in_byte < bigint_size) ? input_bits_in_byte : bigint_size;
114+
115+
if (input_bigint_sign && (input_byte_size > bigint_size))
116+
{
117+
min_size = (input_bits_in_byte > bigint_size) ? input_bits_in_byte : bigint_size;
118+
}
119+
120+
if (min_size < sizeof (uint32_t))
121+
{
122+
min_size = sizeof (uint32_t);
123+
}
124+
125+
ecma_extended_primitive_t *result_p = ecma_bigint_create ((uint32_t) min_size);
126+
127+
if (JERRY_UNLIKELY (result_p == NULL))
128+
{
129+
ecma_deref_bigint (input_bigint_p);
130+
return ECMA_VALUE_ERROR;
131+
}
132+
133+
ecma_bigint_digit_t *last_digit_p = ECMA_BIGINT_GET_DIGITS (input_bigint_p, bigint_size);
134+
135+
/* Calculate the leading zeros of the input_bigint */
136+
137+
ecma_bigint_digit_t zeros = ecma_big_uint_count_leading_zero (last_digit_p[-1]);
138+
uint32_t bits_of_bigint = (uint32_t) (bigint_size * JERRY_BITSINBYTE) - zeros;
139+
uint32_t exact_size =
140+
(input_bigint_sign || ((bits_of_bigint > (size_of_divisor_in_bits - 1)) && (input_byte_size < bigint_size)))
141+
? (uint32_t) input_byte_size
142+
: bigint_size;
143+
144+
if (input_bigint_sign)
145+
{
146+
bits_of_bigint += 1;
147+
}
148+
149+
if (bits_of_bigint > (input_bits - 1) || input_bigint_sign)
150+
{
151+
ecma_bigint_digit_t *digits_p = ECMA_BIGINT_GET_DIGITS (input_bigint_p, 0);
152+
ecma_bigint_digit_t *digits_end_p = ECMA_BIGINT_GET_DIGITS (input_bigint_p, exact_size);
153+
ecma_bigint_digit_t *result_number_p = ECMA_BIGINT_GET_DIGITS (result_p, 0);
154+
int32_t first_cell = 0;
155+
uint32_t surplus_bits =
156+
(whole_part > 0) ? (uint32_t) (whole_part * size_of_divisor_in_bits) : (uint32_t) size_of_divisor_in_bits;
157+
uint32_t mask_bit = (whole_part == 0) ? (uint32_t) input_bits : (uint32_t) input_bits - surplus_bits;
158+
159+
if (mask_bit == 0)
160+
{
161+
mask_bit = size_of_divisor_in_bits - 1;
162+
}
163+
164+
uint32_t check_sign_mask = (uint32_t) 1 << (mask_bit - 1);
165+
uint32_t mask = ((uint32_t) 1 << mask_bit) - 1;
166+
uint32_t last_cell = (exact_size >= sizeof (uint32_t)) ? (uint32_t) (min_size / sizeof (uint32_t)) - 1 : 0;
167+
bool is_positive = false;
168+
bool is_representation_positive = false;
169+
170+
if (is_signed)
171+
{
172+
if (input_bigint_sign && ((~digits_p[last_cell] + 1) & check_sign_mask) == 0)
173+
{
174+
is_positive = true;
175+
}
176+
177+
if ((digits_p[last_cell] & check_sign_mask) == 0)
178+
{
179+
is_representation_positive = true;
180+
}
181+
}
182+
183+
do
184+
{
185+
*result_number_p++ =
186+
(is_representation_positive || (!is_signed && !input_bigint_sign)) ? *digits_p++ : ~(*digits_p++);
187+
first_cell--;
188+
} while (digits_p < digits_end_p);
189+
190+
int16_t equal_bits = 0;
191+
192+
if (remainder != 0)
193+
{
194+
equal_bits = -1;
195+
}
196+
197+
int32_t last_cell_negative = (last_cell != 0) ? ((int32_t) last_cell * (-1)) : -1;
198+
bool is_zero_values = false;
199+
200+
if (!is_signed)
201+
{
202+
if (input_bigint_sign)
203+
{
204+
is_zero_values = true;
205+
}
206+
}
207+
else
208+
{
209+
if (((digits_p[-1] & check_sign_mask) > 0) || (result_number_p[-1] & check_sign_mask) > 0)
210+
{
211+
is_zero_values = true;
212+
}
213+
}
214+
215+
if (is_zero_values)
216+
{
217+
result_number_p[first_cell] += 1;
218+
219+
if (result_number_p[first_cell] == 0)
220+
{
221+
do
222+
{
223+
result_number_p[++first_cell] += 1;
224+
} while (first_cell != equal_bits);
225+
226+
first_cell = last_cell_negative;
227+
}
228+
}
229+
230+
result_number_p[-1] &= mask;
231+
uint32_t surplus = (uint32_t) (min_size - exact_size) / sizeof (ecma_char_t);
232+
uint32_t new_size = result_p->u.bigint_sign_and_size;
233+
234+
if ((min_size - exact_size) % (sizeof (ecma_char_t)) > 0 && surplus == 0)
235+
{
236+
surplus += (uint32_t) sizeof (ecma_char_t);
237+
}
238+
else
239+
{
240+
surplus = (uint32_t) (surplus * sizeof (ecma_char_t));
241+
}
242+
243+
if (min_size / JERRY_BITSINBYTE < 1)
244+
{
245+
surplus = 0;
246+
}
247+
248+
if (is_signed)
249+
{
250+
if (result_p->u.bigint_sign_and_size > exact_size && min_size > sizeof (uint32_t)
251+
&& result_number_p[last_cell_negative] < 1)
252+
{
253+
new_size -= surplus;
254+
}
255+
256+
new_size += 1;
257+
258+
if (is_positive || ((digits_p[-1] & check_sign_mask) == 0 && !input_bigint_sign))
259+
{
260+
new_size -= 1;
261+
}
262+
}
263+
264+
while (first_cell != 0)
265+
{
266+
if (result_number_p[first_cell] != 0)
267+
{
268+
break;
269+
}
270+
271+
first_cell++;
272+
}
273+
274+
if (first_cell == 0)
275+
{
276+
ecma_deref_bigint (result_p);
277+
ecma_deref_bigint (input_bigint_p);
278+
279+
return ECMA_BIGINT_ZERO;
280+
}
281+
282+
last_cell_negative = first_cell + (int32_t) last_cell;
283+
int16_t zero_section_cnt = 0;
284+
285+
while (last_cell_negative > first_cell)
286+
{
287+
if (result_number_p[last_cell_negative] == 0)
288+
{
289+
zero_section_cnt++;
290+
}
291+
292+
last_cell_negative--;
293+
}
294+
295+
uint32_t size_limit = sizeof (uint32_t);
296+
297+
if (zero_section_cnt >= 1)
298+
{
299+
size_limit = new_size - (uint32_t) zero_section_cnt * size_limit;
300+
new_size = (size_limit < sizeof (uint32_t)) ? (uint32_t) (JERRY_BITSINBYTE - size_limit) : size_limit;
301+
}
302+
303+
if (new_size < result_p->u.bigint_sign_and_size)
304+
{
305+
result_p->refs_and_type = ECMA_EXTENDED_PRIMITIVE_REF_ONE | ECMA_TYPE_BIGINT;
306+
uint32_t new_size_remainder = new_size % sizeof (uint32_t);
307+
ecma_extended_primitive_t *new_result_p = ecma_bigint_create (new_size - new_size_remainder);
308+
309+
new_result_p->u.bigint_sign_and_size += new_size_remainder;
310+
memcpy (new_result_p + 1, result_p + 1, new_size - new_size_remainder);
311+
312+
ecma_deref_bigint (result_p);
313+
ecma_deref_bigint (input_bigint_p);
314+
315+
return ecma_make_extended_primitive_value (new_result_p, ECMA_TYPE_BIGINT);
316+
}
317+
318+
result_p->u.bigint_sign_and_size = new_size;
319+
result_p->refs_and_type = ECMA_EXTENDED_PRIMITIVE_REF_ONE | ECMA_TYPE_BIGINT;
320+
321+
ecma_deref_bigint (input_bigint_p);
322+
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
323+
}
324+
325+
memcpy (result_p + 1, input_bigint_p + 1, exact_size);
326+
result_p->refs_and_type = ECMA_EXTENDED_PRIMITIVE_REF_ONE | ECMA_TYPE_BIGINT;
327+
328+
if (input_bigint_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
329+
{
330+
ecma_deref_bigint (input_bigint_p);
331+
return ecma_bigint_negate (result_p);
332+
}
333+
334+
ecma_deref_bigint (input_bigint_p);
335+
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
336+
} /* ecma_builtin_bigint_object_as_int_n */
337+
39338
/**
40339
* Handle calling [[Call]] of built-in BigInt object
41340
*
@@ -71,6 +370,38 @@ ecma_builtin_bigint_dispatch_construct (const ecma_value_t *arguments_list_p, /*
71370
return ecma_raise_type_error (ECMA_ERR_BIGINT_FUNCTION_NOT_CONSTRUCTOR);
72371
} /* ecma_builtin_bigint_dispatch_construct */
73372

373+
/**
374+
* Dispatcher of the built-in's routines
375+
*
376+
* @return ecma value
377+
* Returned value must be freed with ecma_free_value.
378+
*/
379+
ecma_value_t
380+
ecma_builtin_bigint_dispatch_routine (uint8_t builtin_routine_id, /**< built-in wide routine identifier */
381+
ecma_value_t this_arg, /**< 'this' argument value */
382+
const ecma_value_t arguments_list_p[], /**< list of arguments
383+
* passed to routine */
384+
uint32_t arguments_number) /**< length of arguments' list */
385+
{
386+
JERRY_UNUSED_2 (this_arg, arguments_number);
387+
388+
switch (builtin_routine_id)
389+
{
390+
case ECMA_BUILTIN_BIGINT_AS_INT_N:
391+
{
392+
return ecma_builtin_bigint_object_as_int_n (arguments_list_p[0], arguments_list_p[1], true);
393+
}
394+
case ECMA_BUILTIN_BIGINT_AS_U_INT_N:
395+
{
396+
return ecma_builtin_bigint_object_as_int_n (arguments_list_p[0], arguments_list_p[1], false);
397+
}
398+
default:
399+
{
400+
JERRY_UNREACHABLE ();
401+
}
402+
}
403+
} /* ecma_builtin_bigint_dispatch_routine */
404+
74405
/**
75406
* @}
76407
* @}

jerry-core/ecma/builtin-objects/ecma-builtin-bigint.inc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ STRING_VALUE (LIT_MAGIC_STRING_NAME, LIT_MAGIC_STRING_BIGINT_UL, ECMA_PROPERTY_F
3636
/* ECMA-262 v11, 20.2.2.3 */
3737
OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, ECMA_BUILTIN_ID_BIGINT_PROTOTYPE, ECMA_PROPERTY_FIXED)
3838

39+
/* Routine properties:
40+
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
41+
42+
ROUTINE (LIT_MAGIC_STRING_AS_INT_N, ECMA_BUILTIN_BIGINT_AS_INT_N, 2, 2)
43+
ROUTINE (LIT_MAGIC_STRING_AS_U_INT_N, ECMA_BUILTIN_BIGINT_AS_U_INT_N, 2, 2)
3944
#endif /* JERRY_BUILTIN_BIGINT */
4045

4146
#include "ecma-builtin-helpers-macro-undefs.inc.h"

jerry-core/lit/lit-magic-strings.inc.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SCRIPT_UL, "Script")
294294
#endif /* JERRY_PARSER */
295295
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_STRING_UL, "String")
296296
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL_UL, "Symbol")
297+
#if JERRY_BUILTIN_BIGINT
298+
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_AS_INT_N, "asIntN")
299+
#endif /* JERRY_BUILTIN_BIGINT */
297300
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASSIGN, "assign")
298301
#if JERRY_BUILTIN_BIGINT
299302
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BIGINT, "bigint")
@@ -411,6 +414,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKREF_UL, "WeakRef")
411414
#if JERRY_BUILTIN_CONTAINER
412415
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKSET_UL, "WeakSet")
413416
#endif /* JERRY_BUILTIN_CONTAINER */
417+
#if JERRY_BUILTIN_BIGINT
418+
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_AS_U_INT_N, "asUintN")
419+
#endif /* JERRY_BUILTIN_BIGINT */
414420
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BOOLEAN, "boolean")
415421
#if JERRY_BUILTIN_ANNEXB && JERRY_BUILTIN_REGEXP
416422
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMPILE, "compile")

jerry-core/lit/lit-magic-strings.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ LIT_MAGIC_STRING_THROW = "throw"
144144
LIT_MAGIC_STRING_TRUNC = "trunc"
145145
LIT_MAGIC_STRING_VALUE = "value"
146146
LIT_MAGIC_STRING_SOURCE_NAME_EVAL = "<eval>"
147+
LIT_MAGIC_STRING_AS_INT_N = "asIntN"
148+
LIT_MAGIC_STRING_AS_U_INT_N = "asUintN"
147149
LIT_MAGIC_STRING_BIGINT_UL = "BigInt"
148150
LIT_MAGIC_STRING_ERRORS_UL = "errors"
149151
LIT_MAGIC_STRING_HAS_OWN_UL = "hasOwn"

0 commit comments

Comments
 (0)