aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZoltan Herczeg <zherczeg.u-szeged@partner.samsung.com>2020-07-30 12:08:34 +0200
committerGitHub <noreply@github.com>2020-07-30 12:08:34 +0200
commitdf2f7782f7d26537c138acde2ee2e3fb124a17e7 (patch)
tree84edbda91c7f0995828d81d8c9c74d66575e0e09
parent3eb69075f78b7712fbef15200648e8424f37cfb6 (diff)
Implement BigInt primitve type and some of its operations (#4062)
Supported operations: - parse BigInt (decimal, hexadecimal, binary) - toString with any radix between 2 and 36 - arithmetic operations: negate, add, subtract, multiply, divide, modulo - left and right shift JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
-rw-r--r--jerry-core/api/jerry.c15
-rw-r--r--jerry-core/config.h8
-rw-r--r--jerry-core/ecma/base/ecma-gc.c7
-rw-r--r--jerry-core/ecma/base/ecma-globals.h65
-rw-r--r--jerry-core/ecma/base/ecma-helpers-value.c76
-rw-r--r--jerry-core/ecma/base/ecma-helpers.c123
-rw-r--r--jerry-core/ecma/base/ecma-helpers.h16
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-bigint-prototype.c134
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-bigint-prototype.inc.h44
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-bigint.c93
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-bigint.inc.h47
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h7
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtins.inc.h17
-rw-r--r--jerry-core/ecma/operations/ecma-big-uint.c1252
-rw-r--r--jerry-core/ecma/operations/ecma-big-uint.h88
-rw-r--r--jerry-core/ecma/operations/ecma-bigint-object.c66
-rw-r--r--jerry-core/ecma/operations/ecma-bigint-object.h39
-rw-r--r--jerry-core/ecma/operations/ecma-bigint.c508
-rw-r--r--jerry-core/ecma/operations/ecma-bigint.h39
-rw-r--r--jerry-core/ecma/operations/ecma-conversion.c70
-rw-r--r--jerry-core/ecma/operations/ecma-get-put-value.c6
-rw-r--r--jerry-core/ecma/operations/ecma-objects.c6
-rw-r--r--jerry-core/include/jerryscript-core.h1
-rw-r--r--jerry-core/lit/lit-magic-strings.inc.h8
-rw-r--r--jerry-core/lit/lit-magic-strings.ini2
-rw-r--r--jerry-core/vm/opcodes-ecma-arithmetics.c205
-rw-r--r--jerry-core/vm/opcodes-ecma-bitwise.c157
-rw-r--r--tests/jerry/es.next/bigint1.js237
-rw-r--r--tests/jerry/es.next/bigint2.js61
29 files changed, 3221 insertions, 176 deletions
diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c
index 3b1b5754..6a4423a7 100644
--- a/jerry-core/api/jerry.c
+++ b/jerry-core/api/jerry.c
@@ -652,9 +652,9 @@ jerry_value_is_abort (const jerry_value_t value) /**< api value */
return false;
}
- ecma_error_reference_t *error_ref_p = ecma_get_error_reference_from_value (value);
+ ecma_extended_primitive_t *error_ref_p = ecma_get_extended_primitive_from_value (value);
- return (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT) != 0;
+ return ECMA_EXTENDED_PRIMITIVE_GET_TYPE (error_ref_p) == ECMA_EXTENDED_PRIMITIVE_ABORT;
} /* jerry_value_is_abort */
/**
@@ -998,6 +998,9 @@ jerry_is_feature_enabled (const jerry_feature_t feature) /**< feature to check *
#if ENABLED (JERRY_BUILTIN_WEAKSET)
|| feature == JERRY_FEATURE_WEAKSET
#endif /* ENABLED (JERRY_BUILTIN_WEAKSET) */
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ || feature == JERRY_FEATURE_BIGINT
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
);
} /* jerry_is_feature_enabled */
@@ -1166,7 +1169,7 @@ jerry_get_value_from_error (jerry_value_t value, /**< api value */
return release ? value : ecma_copy_value (value);
}
- jerry_value_t ret_val = jerry_acquire_value (ecma_get_error_reference_from_value (value)->value);
+ jerry_value_t ret_val = jerry_acquire_value (ecma_get_extended_primitive_from_value (value)->u.value);
if (release)
{
@@ -1186,7 +1189,7 @@ jerry_get_error_type (jerry_value_t value) /**< api value */
{
if (JERRY_UNLIKELY (ecma_is_value_error_reference (value)))
{
- value = ecma_get_error_reference_from_value (value)->value;
+ value = ecma_get_extended_primitive_from_value (value)->u.value;
}
if (!ecma_is_value_object (value))
@@ -1360,7 +1363,7 @@ jerry_acquire_value (jerry_value_t value) /**< API value */
if (JERRY_UNLIKELY (ecma_is_value_error_reference (value)))
{
- ecma_ref_error_reference (ecma_get_error_reference_from_value (value));
+ ecma_ref_extended_primitive (ecma_get_extended_primitive_from_value (value));
return value;
}
@@ -1377,7 +1380,7 @@ jerry_release_value (jerry_value_t value) /**< API value */
if (JERRY_UNLIKELY (ecma_is_value_error_reference (value)))
{
- ecma_deref_error_reference (ecma_get_error_reference_from_value (value));
+ ecma_deref_error_reference (ecma_get_extended_primitive_from_value (value));
return;
}
diff --git a/jerry-core/config.h b/jerry-core/config.h
index 3d848f79..c8c1be01 100644
--- a/jerry-core/config.h
+++ b/jerry-core/config.h
@@ -115,6 +115,10 @@
# define JERRY_BUILTIN_TYPEDARRAY JERRY_ESNEXT
#endif /* !defined (JERRY_BUILTIN_TYPEDARRAY) */
+#ifndef JERRY_BUILTIN_BIGINT
+# define JERRY_BUILTIN_BIGINT JERRY_ESNEXT
+#endif /* !defined (JERRY_BUILTIN_BIGINT) */
+
#ifndef JERRY_MODULE_SYSTEM
# define JERRY_MODULE_SYSTEM JERRY_ESNEXT
#endif /* !defined (JERRY_MODULE_SYSTEM) */
@@ -555,6 +559,10 @@
|| ((JERRY_BUILTIN_TYPEDARRAY != 0) && (JERRY_BUILTIN_TYPEDARRAY != 1))
# error "Invalid value for JERRY_BUILTIN_TYPEDARRAY macro."
#endif
+#if !defined (JERRY_BUILTIN_BIGINT) \
+|| ((JERRY_BUILTIN_BIGINT != 0) && (JERRY_BUILTIN_BIGINT != 1))
+# error "Invalid value for JERRY_BUILTIN_BIGINT macro."
+#endif
#if !defined (JERRY_MODULE_SYSTEM) \
|| ((JERRY_MODULE_SYSTEM != 0) && (JERRY_MODULE_SYSTEM != 1))
# error "Invalid value for JERRY_MODULE_SYSTEM macro."
diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c
index b0d46bb0..60d0386f 100644
--- a/jerry-core/ecma/base/ecma-gc.c
+++ b/jerry-core/ecma/base/ecma-gc.c
@@ -1202,11 +1202,14 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
switch (ext_object_p->u.class_prop.class_id)
{
+ case LIT_MAGIC_STRING_STRING_UL:
+ case LIT_MAGIC_STRING_NUMBER_UL:
#if ENABLED (JERRY_ESNEXT)
case LIT_MAGIC_STRING_SYMBOL_UL:
#endif /* ENABLED (JERRY_ESNEXT) */
- case LIT_MAGIC_STRING_STRING_UL:
- case LIT_MAGIC_STRING_NUMBER_UL:
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ case LIT_MAGIC_STRING_BIGINT_UL:
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
{
ecma_free_value (ext_object_p->u.class_prop.u.value);
break;
diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h
index c1e5f903..06af59c7 100644
--- a/jerry-core/ecma/base/ecma-globals.h
+++ b/jerry-core/ecma/base/ecma-globals.h
@@ -85,6 +85,7 @@ typedef enum
ECMA_TYPE_OBJECT = 3, /**< pointer to description of an object */
ECMA_TYPE_SYMBOL = 4, /**< pointer to description of a symbol */
ECMA_TYPE_DIRECT_STRING = 5, /**< directly encoded string values */
+ ECMA_TYPE_BIGINT = 6, /**< pointer to a bigint primitive */
ECMA_TYPE_ERROR = 7, /**< pointer to description of an error reference (only supported by C API) */
ECMA_TYPE_SNAPSHOT_OFFSET = ECMA_TYPE_ERROR, /**< offset to a snapshot number/string */
ECMA_TYPE___MAX = ECMA_TYPE_ERROR /** highest value for ecma types */
@@ -1710,28 +1711,44 @@ typedef struct
} ecma_stringbuilder_t;
/**
- * Abort flag for error reference.
+ * Types for extended primitive values.
*/
-#define ECMA_ERROR_REF_ABORT 0x1
+typedef enum
+{
+#ifndef JERRY_BUILTIN_BIGINT
+ ECMA_EXTENDED_PRIMITIVE_BIGINT, /**< BigInt value */
+#endif /* !defined (JERRY_BUILTIN_BIGINT) */
+ ECMA_EXTENDED_PRIMITIVE_ERROR, /**< external API error reference */
+ ECMA_EXTENDED_PRIMITIVE_ABORT, /**< external API abort reference */
+} ecma_extended_primitive_type_t;
/**
- * Value for increasing or decreasing the reference counter.
+ * Representation of a thrown value on API level.
*/
-#define ECMA_ERROR_REF_ONE (1u << 1)
+typedef struct
+{
+ uint32_t refs_and_type; /**< reference counter and type */
+ union
+ {
+ ecma_value_t value; /**< referenced value */
+ uint32_t bigint_sign_and_size; /**< BigInt properties */
+ } u;
+} ecma_extended_primitive_t;
/**
- * Maximum value of the reference counter.
+ * Get the type of an extended primitve value.
*/
-#define ECMA_ERROR_MAX_REF (UINT32_MAX - 1u)
+#define ECMA_EXTENDED_PRIMITIVE_GET_TYPE(primitve_p) ((primitve_p)->refs_and_type & 0x7)
/**
- * Representation of a thrown value on API level.
+ * Value for increasing or decreasing the reference counter.
*/
-typedef struct
-{
- uint32_t refs_and_flags; /**< reference counter */
- ecma_value_t value; /**< referenced value */
-} ecma_error_reference_t;
+#define ECMA_EXTENDED_PRIMITIVE_REF_ONE (1u << 3)
+
+/**
+ * Maximum value of the reference counter.
+ */
+#define ECMA_EXTENDED_PRIMITIVE_MAX_REF (UINT32_MAX - (ECMA_EXTENDED_PRIMITIVE_REF_ONE - 1))
#if ENABLED (JERRY_PROPRETY_HASHMAP)
@@ -2009,7 +2026,7 @@ typedef struct
ecma_object_t *buffer_p; /**< [[ViewedArrayBuffer]] internal slot */
uint32_t byte_offset; /**< [[ByteOffset]] internal slot */
} ecma_dataview_object_t;
-#endif /* ENABLED (JERRY_BUILTIN_DATAVIEW */
+#endif /* ENABLED (JERRY_BUILTIN_DATAVIEW) */
/**
* Flag for indicating whether the symbol is a well known symbol
@@ -2091,6 +2108,28 @@ typedef uint64_t ecma_length_t;
typedef uint32_t ecma_length_t;
#endif /* ENABLED (JERRY_ESNEXT) */
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+/**
+ * BigUInt data is a sequence of uint32_t numbers.
+ */
+typedef uint32_t ecma_bigint_digit_t;
+
+/**
+ * Return the size of a BigInt value in ecma_bigint_data_t units.
+ */
+#define ECMA_BIGINT_GET_SIZE(value_p) \
+ ((value_p)->u.bigint_sign_and_size & ~(uint32_t) (sizeof (ecma_bigint_digit_t) - 1))
+
+/**
+ * Size of memory needs to be allocated for the digits of a BigInt.
+ * The value is rounded up for two digits.
+ */
+#define ECMA_BIGINT_GET_BYTE_SIZE(size) \
+ (size_t) (((size) + sizeof (ecma_bigint_digit_t)) & ~(2 * sizeof (ecma_bigint_digit_t) - 1))
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
/**
* Struct for counting the different types properties in objects
*/
diff --git a/jerry-core/ecma/base/ecma-helpers-value.c b/jerry-core/ecma/base/ecma-helpers-value.c
index 428d3cff..8cd97d42 100644
--- a/jerry-core/ecma/base/ecma-helpers-value.c
+++ b/jerry-core/ecma/base/ecma-helpers-value.c
@@ -330,6 +330,22 @@ ecma_is_value_symbol (ecma_value_t value) /**< ecma value */
} /* ecma_is_value_symbol */
#endif /* ENABLED (JERRY_ESNEXT) */
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+/**
+ * Check if the value is bigint.
+ *
+ * @return true - if the value contains bigint value,
+ * false - otherwise
+ */
+inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
+ecma_is_value_bigint (ecma_value_t value) /**< ecma value */
+{
+ return (ecma_get_value_type_field (value) == ECMA_TYPE_BIGINT);
+} /* ecma_is_value_bigint */
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
/**
* Check if the value can be property name.
*
@@ -401,13 +417,29 @@ ecma_is_value_error_reference (ecma_value_t value) /**< ecma value */
void
ecma_check_value_type_is_spec_defined (ecma_value_t value) /**< ecma value */
{
+#if ENABLED (JERRY_ESNEXT)
+#define ECMA_CHECK_IS_VALUE_SYMBOL(value) ecma_is_value_symbol(value)
+#else /* !ENABLED (JERRY_ESNEXT) */
+#define ECMA_CHECK_IS_VALUE_SYMBOL(value) false
+#endif /* ENABLED (JERRY_ESNEXT) */
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+#define ECMA_CHECK_IS_VALUE_BIGINT(value) ecma_is_value_bigint(value)
+#else /* !ENABLED (JERRY_BUILTIN_BIGINT) */
+#define ECMA_CHECK_IS_VALUE_BIGINT(value) false
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
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_ASSERT_VALUE_IS_SYMBOL (value)
+ || ECMA_CHECK_IS_VALUE_SYMBOL (value)
+ || ECMA_CHECK_IS_VALUE_BIGINT (value)
|| ecma_is_value_object (value));
+
+#undef ECMA_CHECK_IS_VALUE_SYMBOL
+#undef ECMA_CHECK_IS_VALUE_BIGINT
} /* ecma_check_value_type_is_spec_defined */
/**
@@ -686,12 +718,14 @@ ecma_make_object_value (const ecma_object_t *object_p) /**< object to reference
* @return ecma-value representation of the Error reference
*/
inline ecma_value_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
-ecma_make_error_reference_value (const ecma_error_reference_t *error_ref_p) /**< error reference */
+ecma_make_extended_primitive_value (const ecma_extended_primitive_t *primitve_p, /**< extended primitve value */
+ uint32_t type) /**< ecma type of extended primitve value */
{
- JERRY_ASSERT (error_ref_p != NULL);
+ JERRY_ASSERT (primitve_p != NULL);
+ JERRY_ASSERT (type == ECMA_TYPE_BIGINT || type == ECMA_TYPE_ERROR);
- return ecma_pointer_to_ecma_value (error_ref_p) | ECMA_TYPE_ERROR;
-} /* ecma_make_error_reference_value */
+ return ecma_pointer_to_ecma_value (primitve_p) | type;
+} /* ecma_make_extended_primitive_value */
/**
* Get integer value from an integer ecma value
@@ -817,13 +851,14 @@ ecma_get_object_from_value (ecma_value_t value) /**< ecma value */
*
* @return the pointer
*/
-inline ecma_error_reference_t *JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
-ecma_get_error_reference_from_value (ecma_value_t value) /**< ecma value */
+inline ecma_extended_primitive_t *JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE
+ecma_get_extended_primitive_from_value (ecma_value_t value) /**< ecma value */
{
- JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_ERROR);
+ JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_BIGINT
+ || ecma_get_value_type_field (value) == ECMA_TYPE_ERROR);
- return (ecma_error_reference_t *) ecma_get_pointer_from_ecma_value (value);
-} /* ecma_get_error_reference_from_value */
+ return (ecma_extended_primitive_t *) ecma_get_pointer_from_ecma_value (value);
+} /* ecma_get_extended_primitive_from_value */
/**
* Invert a boolean value
@@ -866,6 +901,13 @@ ecma_copy_value (ecma_value_t value) /**< value description */
return value;
}
#endif /* ENABLED (JERRY_ESNEXT) */
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ case ECMA_TYPE_BIGINT:
+ {
+ ecma_ref_extended_primitive (ecma_get_extended_primitive_from_value (value));
+ return value;
+ }
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
case ECMA_TYPE_OBJECT:
{
ecma_ref_object (ecma_get_object_from_value (value));
@@ -1093,6 +1135,14 @@ ecma_free_value (ecma_value_t value) /**< value description */
break;
}
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ case ECMA_TYPE_BIGINT:
+ {
+ ecma_deref_bigint (ecma_get_extended_primitive_from_value (value));
+ break;
+ }
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
default:
{
JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT
@@ -1192,6 +1242,12 @@ ecma_get_typeof_lit_id (ecma_value_t value) /**< input ecma value */
ret_value = LIT_MAGIC_STRING_SYMBOL;
}
#endif /* ENABLED (JERRY_ESNEXT) */
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ else if (ecma_is_value_bigint (value))
+ {
+ ret_value = LIT_MAGIC_STRING_BIGINT;
+ }
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
else
{
JERRY_ASSERT (ecma_is_value_object (value));
diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c
index 1f7ee990..059edb41 100644
--- a/jerry-core/ecma/base/ecma-helpers.c
+++ b/jerry-core/ecma/base/ecma-helpers.c
@@ -1216,10 +1216,74 @@ ecma_free_property_descriptor (ecma_property_descriptor_t *prop_desc_p) /**< pro
/**
* The size of error reference must be 8 bytes to use jmem_pools_alloc().
*/
-JERRY_STATIC_ASSERT (sizeof (ecma_error_reference_t) == 8,
+JERRY_STATIC_ASSERT (sizeof (ecma_extended_primitive_t) == 8,
ecma_error_reference_size_must_be_8_bytes);
/**
+ * Increase ref count of an extended primitve value.
+ */
+void
+ecma_ref_extended_primitive (ecma_extended_primitive_t *primitve_p) /**< extended primitve value */
+{
+ if (JERRY_LIKELY (primitve_p->refs_and_type < ECMA_EXTENDED_PRIMITIVE_MAX_REF))
+ {
+ primitve_p->refs_and_type += ECMA_EXTENDED_PRIMITIVE_REF_ONE;
+ }
+ else
+ {
+ jerry_fatal (ERR_REF_COUNT_LIMIT);
+ }
+} /* ecma_ref_extended_primitive */
+
+/**
+ * Decrease ref count of an error reference.
+ */
+void
+ecma_deref_error_reference (ecma_extended_primitive_t *error_ref_p) /**< error reference */
+{
+ JERRY_ASSERT (error_ref_p->refs_and_type >= ECMA_EXTENDED_PRIMITIVE_REF_ONE);
+
+ error_ref_p->refs_and_type -= ECMA_EXTENDED_PRIMITIVE_REF_ONE;
+
+ if (error_ref_p->refs_and_type < ECMA_EXTENDED_PRIMITIVE_REF_ONE)
+ {
+ ecma_free_value (error_ref_p->u.value);
+ jmem_pools_free (error_ref_p, sizeof (ecma_extended_primitive_t));
+ }
+} /* ecma_deref_error_reference */
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+/**
+ * Decrease ref count of a bigint value.
+ */
+void
+ecma_deref_bigint (ecma_extended_primitive_t *bigint_p) /**< bigint value */
+{
+ JERRY_ASSERT (bigint_p->refs_and_type >= ECMA_EXTENDED_PRIMITIVE_REF_ONE);
+
+ bigint_p->refs_and_type -= ECMA_EXTENDED_PRIMITIVE_REF_ONE;
+
+ if (bigint_p->refs_and_type >= ECMA_EXTENDED_PRIMITIVE_REF_ONE)
+ {
+ return;
+ }
+
+ uint32_t size = ECMA_BIGINT_GET_SIZE (bigint_p);
+
+ if (size == 0)
+ {
+ jmem_pools_free (bigint_p, sizeof (ecma_extended_primitive_t));
+ return;
+ }
+
+ size_t mem_size = ECMA_BIGINT_GET_BYTE_SIZE (size) + sizeof (ecma_extended_primitive_t);
+ jmem_heap_free_block (bigint_p, mem_size);
+} /* ecma_deref_bigint */
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
+/**
* Create an error reference from a given value.
*
* Note:
@@ -1231,11 +1295,13 @@ ecma_value_t
ecma_create_error_reference (ecma_value_t value, /**< referenced value */
bool is_exception) /**< error reference is an exception */
{
- ecma_error_reference_t *error_ref_p = (ecma_error_reference_t *) jmem_pools_alloc (sizeof (ecma_error_reference_t));
+ ecma_extended_primitive_t *error_ref_p;
+ error_ref_p = (ecma_extended_primitive_t *) jmem_pools_alloc (sizeof (ecma_extended_primitive_t));
- error_ref_p->refs_and_flags = ECMA_ERROR_REF_ONE | (is_exception ? 0 : ECMA_ERROR_REF_ABORT);
- error_ref_p->value = value;
- return ecma_make_error_reference_value (error_ref_p);
+ error_ref_p->refs_and_type = (ECMA_EXTENDED_PRIMITIVE_REF_ONE
+ | (is_exception ? ECMA_EXTENDED_PRIMITIVE_ERROR : ECMA_EXTENDED_PRIMITIVE_ABORT));
+ error_ref_p->u.value = value;
+ return ecma_make_extended_primitive_value (error_ref_p, ECMA_TYPE_ERROR);
} /* ecma_create_error_reference */
/**
@@ -1270,39 +1336,6 @@ ecma_create_error_object_reference (ecma_object_t *object_p) /**< referenced obj
} /* ecma_create_error_object_reference */
/**
- * Increase ref count of an error reference.
- */
-void
-ecma_ref_error_reference (ecma_error_reference_t *error_ref_p) /**< error reference */
-{
- if (JERRY_LIKELY (error_ref_p->refs_and_flags < ECMA_ERROR_MAX_REF))
- {
- error_ref_p->refs_and_flags += ECMA_ERROR_REF_ONE;
- }
- else
- {
- jerry_fatal (ERR_REF_COUNT_LIMIT);
- }
-} /* ecma_ref_error_reference */
-
-/**
- * Decrease ref count of an error reference.
- */
-void
-ecma_deref_error_reference (ecma_error_reference_t *error_ref_p) /**< error reference */
-{
- JERRY_ASSERT (error_ref_p->refs_and_flags >= ECMA_ERROR_REF_ONE);
-
- error_ref_p->refs_and_flags -= ECMA_ERROR_REF_ONE;
-
- if (error_ref_p->refs_and_flags < ECMA_ERROR_REF_ONE)
- {
- ecma_free_value (error_ref_p->value);
- jmem_pools_free (error_ref_p, sizeof (ecma_error_reference_t));
- }
-} /* ecma_deref_error_reference */
-
-/**
* Raise error from the given error reference.
*
* Note: the error reference's ref count is also decreased
@@ -1311,23 +1344,23 @@ void
ecma_raise_error_from_error_reference (ecma_value_t value) /**< error reference */
{
JERRY_ASSERT (!jcontext_has_pending_exception () && !jcontext_has_pending_abort ());
- ecma_error_reference_t *error_ref_p = ecma_get_error_reference_from_value (value);
+ ecma_extended_primitive_t *error_ref_p = ecma_get_extended_primitive_from_value (value);
- JERRY_ASSERT (error_ref_p->refs_and_flags >= ECMA_ERROR_REF_ONE);
+ JERRY_ASSERT (error_ref_p->refs_and_type >= ECMA_EXTENDED_PRIMITIVE_REF_ONE);
- ecma_value_t referenced_value = error_ref_p->value;
+ ecma_value_t referenced_value = error_ref_p->u.value;
jcontext_set_exception_flag (true);
- jcontext_set_abort_flag (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT);
+ jcontext_set_abort_flag (ECMA_EXTENDED_PRIMITIVE_GET_TYPE (error_ref_p) == ECMA_EXTENDED_PRIMITIVE_ABORT);
- if (error_ref_p->refs_and_flags >= 2 * ECMA_ERROR_REF_ONE)
+ if (error_ref_p->refs_and_type >= 2 * ECMA_EXTENDED_PRIMITIVE_REF_ONE)
{
- error_ref_p->refs_and_flags -= ECMA_ERROR_REF_ONE;
+ error_ref_p->refs_and_type -= ECMA_EXTENDED_PRIMITIVE_REF_ONE;
referenced_value = ecma_copy_value (referenced_value);
}
else
{
- jmem_pools_free (error_ref_p, sizeof (ecma_error_reference_t));
+ jmem_pools_free (error_ref_p, sizeof (ecma_extended_primitive_t));
}
JERRY_CONTEXT (error_value) = referenced_value;
diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h
index 1e012917..728f7f29 100644
--- a/jerry-core/ecma/base/ecma-helpers.h
+++ b/jerry-core/ecma/base/ecma-helpers.h
@@ -243,6 +243,9 @@ bool JERRY_ATTR_CONST ecma_is_value_string (ecma_value_t value);
#if ENABLED (JERRY_ESNEXT)
bool JERRY_ATTR_CONST ecma_is_value_symbol (ecma_value_t value);
#endif /* ENABLED (JERRY_ESNEXT) */
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+bool JERRY_ATTR_CONST ecma_is_value_bigint (ecma_value_t value);
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
bool JERRY_ATTR_CONST ecma_is_value_prop_name (ecma_value_t value);
bool JERRY_ATTR_CONST ecma_is_value_direct_string (ecma_value_t value);
bool JERRY_ATTR_CONST ecma_is_value_non_direct_string (ecma_value_t value);
@@ -267,7 +270,8 @@ ecma_value_t JERRY_ATTR_PURE ecma_make_symbol_value (const ecma_string_t *ecma_s
ecma_value_t JERRY_ATTR_PURE ecma_make_prop_name_value (const ecma_string_t *ecma_prop_name_p);
ecma_value_t JERRY_ATTR_PURE ecma_make_magic_string_value (lit_magic_string_id_t id);
ecma_value_t JERRY_ATTR_PURE ecma_make_object_value (const ecma_object_t *object_p);
-ecma_value_t JERRY_ATTR_PURE ecma_make_error_reference_value (const ecma_error_reference_t *error_ref_p);
+ecma_value_t JERRY_ATTR_PURE ecma_make_extended_primitive_value (const ecma_extended_primitive_t *primitve_p,
+ uint32_t type);
ecma_integer_value_t JERRY_ATTR_CONST ecma_get_integer_from_value (ecma_value_t value);
ecma_number_t JERRY_ATTR_PURE ecma_get_float_from_value (ecma_value_t value);
ecma_number_t * ecma_get_pointer_from_float_value (ecma_value_t value);
@@ -278,7 +282,7 @@ ecma_string_t JERRY_ATTR_PURE *ecma_get_symbol_from_value (ecma_value_t value);
#endif /* ENABLED (JERRY_ESNEXT) */
ecma_string_t JERRY_ATTR_PURE *ecma_get_prop_name_from_value (ecma_value_t value);
ecma_object_t JERRY_ATTR_PURE *ecma_get_object_from_value (ecma_value_t value);
-ecma_error_reference_t JERRY_ATTR_PURE *ecma_get_error_reference_from_value (ecma_value_t value);
+ecma_extended_primitive_t JERRY_ATTR_PURE *ecma_get_extended_primitive_from_value (ecma_value_t value);
ecma_value_t JERRY_ATTR_CONST ecma_invert_boolean_value (ecma_value_t value);
ecma_value_t ecma_copy_value (ecma_value_t value);
ecma_value_t ecma_fast_copy_value (ecma_value_t value);
@@ -498,11 +502,15 @@ void ecma_set_property_lcached (ecma_property_t *property_p, bool is_lcached);
ecma_property_descriptor_t ecma_make_empty_property_descriptor (void);
void ecma_free_property_descriptor (ecma_property_descriptor_t *prop_desc_p);
+void ecma_ref_extended_primitive (ecma_extended_primitive_t *primitve_p);
+void ecma_deref_error_reference (ecma_extended_primitive_t *error_ref_p);
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+void ecma_deref_bigint (ecma_extended_primitive_t *bigint_p);
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
ecma_value_t ecma_create_error_reference (ecma_value_t value, bool is_exception);
ecma_value_t ecma_create_error_reference_from_context (void);
ecma_value_t ecma_create_error_object_reference (ecma_object_t *object_p);
-void ecma_ref_error_reference (ecma_error_reference_t *error_ref_p);
-void ecma_deref_error_reference (ecma_error_reference_t *error_ref_p);
void ecma_raise_error_from_error_reference (ecma_value_t value);
void ecma_bytecode_ref (ecma_compiled_code_t *bytecode_p);
diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-bigint-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-bigint-prototype.c
new file mode 100644
index 00000000..99d98e86
--- /dev/null
+++ b/jerry-core/ecma/builtin-objects/ecma-builtin-bigint-prototype.c
@@ -0,0 +1,134 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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-bigint.h"
+#include "ecma-exceptions.h"
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+#define ECMA_BUILTINS_INTERNAL
+#include "ecma-builtins-internal.h"
+
+/**
+ * This object has a custom dispatch function.
+ */
+#define BUILTIN_INC_HEADER_NAME "ecma-builtin-bigint-prototype.inc.h"
+#define BUILTIN_UNDERSCORED_ID bigint_prototype
+#include "ecma-builtin-internal-routines-template.inc.h"
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmabuiltins
+ * @{
+ *
+ * \addtogroup bigint ECMA BigInt object built-in
+ * @{
+ */
+
+/**
+ * The BigInt.prototype object's 'valueOf' routine
+ *
+ * See also:
+ * ECMA-262 v11, 20.2.3.4
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_bigint_prototype_object_value_of (ecma_value_t this_arg) /**< this argument */
+{
+ if (ecma_is_value_bigint (this_arg))
+ {
+ return ecma_copy_value (this_arg);
+ }
+
+ if (ecma_is_value_object (this_arg))
+ {
+ ecma_object_t *object_p = ecma_get_object_from_value (this_arg);
+
+ if (ecma_object_class_is (object_p, LIT_MAGIC_STRING_BIGINT_UL))
+ {
+ ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
+
+ JERRY_ASSERT (ecma_is_value_bigint (ext_object_p->u.class_prop.u.value));
+
+ return ecma_copy_value (ext_object_p->u.class_prop.u.value);
+ }
+ }
+
+ return ecma_raise_type_error (ECMA_ERR_MSG ("BigInt value expected."));
+} /* ecma_builtin_bigint_prototype_object_value_of */
+
+/**
+ * The BigInt.prototype object's 'toString' routine
+ *
+ * See also:
+ * ECMA-262 v11, 20.2.3.3
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_builtin_bigint_prototype_object_to_string (ecma_value_t this_arg, /**< this argument */
+ const ecma_value_t *arguments_list_p, /**< arguments list */
+ uint32_t arguments_list_len) /**< number of arguments */
+{
+ ecma_value_t bigint = ecma_builtin_bigint_prototype_object_value_of (this_arg);
+
+ if (ECMA_IS_VALUE_ERROR (bigint))
+ {
+ return bigint;
+ }
+
+ uint32_t radix = 10;
+
+ if (arguments_list_len > 0 && !ecma_is_value_undefined (arguments_list_p[0]))
+ {
+ ecma_number_t arg_num;
+
+ if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arguments_list_p[0], &arg_num)))
+ {
+ ecma_free_value (bigint);
+ return ECMA_VALUE_ERROR;
+ }
+
+ if (arg_num < 2 || arg_num > 36)
+ {
+ ecma_free_value (bigint);
+ return ecma_raise_range_error (ECMA_ERR_MSG ("Radix must be between 2 and 36."));
+ }
+
+ radix = (uint32_t) arg_num;
+ }
+
+ ecma_string_t *string_p = ecma_bigint_to_string (bigint, radix);
+ ecma_free_value (bigint);
+
+ if (string_p == NULL)
+ {
+ return ECMA_VALUE_ERROR;
+ }
+
+ return ecma_make_string_value (string_p);
+} /* ecma_builtin_bigint_prototype_object_to_string */
+
+/**
+ * @}
+ * @}
+ * @}
+ */
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-bigint-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-bigint-prototype.inc.h
new file mode 100644
index 00000000..8496198a
--- /dev/null
+++ b/jerry-core/ecma/builtin-objects/ecma-builtin-bigint-prototype.inc.h
@@ -0,0 +1,44 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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.
+ */
+
+/*
+ * BigInt.prototype built-in description
+ */
+
+#include "ecma-builtin-helpers-macro-defines.inc.h"
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+/* Object properties:
+ * (property name, object pointer getter) */
+
+/* ECMA-262 v11, 20.2.3.1 */
+OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
+ ECMA_BUILTIN_ID_BIGINT,
+ ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
+
+/* ECMA-262 v11, 20.2.3.5 */
+STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
+ LIT_MAGIC_STRING_BIGINT_UL,
+ ECMA_PROPERTY_FLAG_CONFIGURABLE)
+
+/* Routine properties:
+ * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
+ROUTINE (LIT_MAGIC_STRING_VALUE_OF_UL, ecma_builtin_bigint_prototype_object_value_of, 0, 0)
+ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ecma_builtin_bigint_prototype_object_to_string, NON_FIXED, 1)
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
+#include "ecma-builtin-helpers-macro-undefs.inc.h"
diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-bigint.c b/jerry-core/ecma/builtin-objects/ecma-builtin-bigint.c
new file mode 100644
index 00000000..343805fa
--- /dev/null
+++ b/jerry-core/ecma/builtin-objects/ecma-builtin-bigint.c
@@ -0,0 +1,93 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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-bigint.h"
+#include "ecma-builtins.h"
+#include "ecma-exceptions.h"
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+#define ECMA_BUILTINS_INTERNAL
+#include "ecma-builtins-internal.h"
+
+#define BUILTIN_INC_HEADER_NAME "ecma-builtin-bigint.inc.h"
+#define BUILTIN_UNDERSCORED_ID bigint
+#include "ecma-builtin-internal-routines-template.inc.h"
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmabuiltins
+ * @{
+ *
+ * \addtogroup bigint ECMA BigInt object built-in
+ * @{
+ */
+
+/**
+ * Handle calling [[Call]] of built-in BigInt object
+ *
+ * See also:
+ * ECMA-262 v11, 20.2.1.1
+ *
+ * @return ecma value
+ */
+ecma_value_t
+ecma_builtin_bigint_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */
+ uint32_t arguments_list_len) /**< number of arguments */
+{
+ JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
+
+ ecma_value_t value = (arguments_list_len == 0) ? ECMA_VALUE_UNDEFINED : arguments_list_p[0];
+
+ if (!ecma_is_value_string (value))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("TODO: Only strings are supported now"));
+ }
+
+ ecma_string_t *string_p = ecma_get_string_from_value (value);
+
+ ECMA_STRING_TO_UTF8_STRING (string_p, string_buffer_p, string_buffer_size);
+
+ ecma_value_t result = ecma_bigint_parse_string (string_buffer_p, string_buffer_size);
+
+ ECMA_FINALIZE_UTF8_STRING (string_buffer_p, string_buffer_size);
+ return result;
+} /* ecma_builtin_bigint_dispatch_call */
+
+/**
+ * Handle calling [[Construct]] of built-in BigInt object
+ *
+ * See also:
+ * ECMA-262 v11, 20.2.1
+ *
+ * @return ecma value
+ */
+ecma_value_t
+ecma_builtin_bigint_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
+ uint32_t arguments_list_len) /**< number of arguments */
+{
+ JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
+
+ return ecma_raise_type_error (ECMA_ERR_MSG ("BigInt function is not a constructor."));
+} /* ecma_builtin_bigint_dispatch_construct */
+
+/**
+ * @}
+ * @}
+ * @}
+ */
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-bigint.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-bigint.inc.h
new file mode 100644
index 00000000..c851c5cc
--- /dev/null
+++ b/jerry-core/ecma/builtin-objects/ecma-builtin-bigint.inc.h
@@ -0,0 +1,47 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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.
+ */
+
+/*
+ * BigInt built-in description
+ */
+
+#include "ecma-builtin-helpers-macro-defines.inc.h"
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+/* Number properties:
+ * (property name, number value, writable, enumerable, configurable) */
+
+/* ECMA-262 v11, 20.2.1 */
+NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
+ 1,
+ ECMA_PROPERTY_FLAG_CONFIGURABLE)
+
+/* ECMA-262 v11, 20.2.1 */
+STRING_VALUE (LIT_MAGIC_STRING_NAME,
+ LIT_MAGIC_STRING_BIGINT_UL,
+ ECMA_PROPERTY_FLAG_CONFIGURABLE)
+
+/* Object properties:
+ * (property name, object pointer getter) */
+
+/* ECMA-262 v11, 20.2.2.3 */
+OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
+ ECMA_BUILTIN_ID_BIGINT_PROTOTYPE,
+ ECMA_PROPERTY_FIXED)
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
+#include "ecma-builtin-helpers-macro-undefs.inc.h"
diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h
index 9dba8647..99c085bf 100644
--- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h
+++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h
@@ -253,6 +253,13 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROXY_UL,
ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+/* ECMA-262 v11, 20.2.1 */
+OBJECT_VALUE (LIT_MAGIC_STRING_BIGINT_UL,
+ ECMA_BUILTIN_ID_BIGINT,
+ ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
/* Routine properties:
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h
index a3b4a005..8cf86362 100644
--- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h
+++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h
@@ -677,6 +677,23 @@ BUILTIN (ECMA_BUILTIN_ID_MAP_ITERATOR_PROTOTYPE,
true,
map_iterator_prototype)
#endif /* ENABLED (JERRY_BUILTIN_SET) */
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+/* The %BigInt.prototype% object */
+BUILTIN (ECMA_BUILTIN_ID_BIGINT_PROTOTYPE,
+ ECMA_OBJECT_TYPE_GENERAL,
+ ECMA_BUILTIN_ID_OBJECT_PROTOTYPE,
+ true,
+ bigint_prototype)
+
+/* The %BigInt% object */
+BUILTIN_ROUTINE (ECMA_BUILTIN_ID_BIGINT,
+ ECMA_OBJECT_TYPE_FUNCTION,
+ ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE,
+ true,
+ bigint)
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
#endif /* ENABLED (JERRY_ESNEXT) */
#if ENABLED (JERRY_BUILTIN_DATAVIEW)
diff --git a/jerry-core/ecma/operations/ecma-big-uint.c b/jerry-core/ecma/operations/ecma-big-uint.c
new file mode 100644
index 00000000..81158f83
--- /dev/null
+++ b/jerry-core/ecma/operations/ecma-big-uint.c
@@ -0,0 +1,1252 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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-big-uint.h"
+#include "ecma-helpers.h"
+#include "jmem.h"
+#include "lit-char-helpers.h"
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+JERRY_STATIC_ASSERT (sizeof (ecma_bigint_two_digits_t) == 2 * sizeof (ecma_bigint_digit_t),
+ ecma_big_int_two_digits_must_be_twice_as_long_as_ecma_big_int_digit);
+
+JERRY_STATIC_ASSERT ((1 << ECMA_BIGINT_DIGIT_SHIFT) == (8 * sizeof (ecma_bigint_digit_t)),
+ ecma_bigint_digit_shift_is_incorrect);
+
+/**
+ * Create a new BigInt value
+ *
+ * @return new BigInt value, NULL on error
+ */
+ecma_extended_primitive_t *
+ecma_bigint_create (uint32_t size) /**< size of the new BigInt value */
+{
+ JERRY_ASSERT ((size % sizeof (ecma_bigint_digit_t)) == 0);
+
+ if (JERRY_UNLIKELY (size > ECMA_BIGINT_MAX_SIZE))
+ {
+ return NULL;
+ }
+
+ ecma_extended_primitive_t *value_p;
+
+ if (size == 0)
+ {
+ value_p = (ecma_extended_primitive_t *) jmem_pools_alloc (sizeof (ecma_extended_primitive_t));
+ }
+ else
+ {
+ size_t mem_size = ECMA_BIGINT_GET_BYTE_SIZE (size) + sizeof (ecma_extended_primitive_t);
+ value_p = (ecma_extended_primitive_t *) jmem_heap_alloc_block_null_on_error (mem_size);
+ }
+
+ if (JERRY_UNLIKELY (value_p == NULL))
+ {
+ return NULL;
+ }
+
+ value_p->refs_and_type = ECMA_EXTENDED_PRIMITIVE_REF_ONE | ECMA_TYPE_BIGINT;
+ value_p->u.bigint_sign_and_size = size;
+ return value_p;
+} /* ecma_bigint_create */
+
+/**
+ * Extend a BigInt value with a new data prefix value
+ *
+ * @return new BigInt value, NULL on error
+ */
+ecma_extended_primitive_t *
+ecma_big_uint_extend (ecma_extended_primitive_t *value_p, /**< BigInt value */
+ ecma_bigint_digit_t digit) /**< new digit */
+{
+ uint32_t old_size = ECMA_BIGINT_GET_SIZE (value_p);
+
+ if (ECMA_BIGINT_SIZE_IS_ODD (old_size))
+ {
+ value_p->u.bigint_sign_and_size += (uint32_t) sizeof (ecma_bigint_digit_t);
+ *ECMA_BIGINT_GET_DIGITS (value_p, old_size) = digit;
+ return value_p;
+ }
+
+ ecma_extended_primitive_t *result_p = ecma_bigint_create (old_size + (uint32_t) sizeof (ecma_bigint_digit_t));
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ ecma_deref_bigint (value_p);
+ return NULL;
+ }
+
+ memcpy (result_p + 1, value_p + 1, old_size);
+ ecma_deref_bigint (value_p);
+
+ *ECMA_BIGINT_GET_DIGITS (result_p, old_size) = digit;
+ return result_p;
+} /* ecma_big_uint_extend */
+
+/**
+ * Compare two BigUInt numbers
+ *
+ * return -1, if value1 < value2, 0 if they are equal, and 1 otherwise
+ */
+int
+ecma_big_uint_compare (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */
+ ecma_extended_primitive_t *right_value_p) /**< right BigUInt value */
+{
+ uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_value_p);
+ uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_value_p);
+
+ JERRY_ASSERT (left_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) != 0);
+ JERRY_ASSERT (right_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (right_value_p, right_size) != 0);
+
+ if (left_size > right_size)
+ {
+ return 1;
+ }
+
+ if (left_size < right_size)
+ {
+ return -1;
+ }
+
+ ecma_bigint_digit_t *start_p = ECMA_BIGINT_GET_DIGITS (left_value_p, 0);
+ ecma_bigint_digit_t *left_p = ECMA_BIGINT_GET_DIGITS (left_value_p, left_size);
+ ecma_bigint_digit_t *right_p = ECMA_BIGINT_GET_DIGITS (right_value_p, left_size);
+
+ do
+ {
+ ecma_bigint_digit_t left_value = *(--left_p);
+ ecma_bigint_digit_t right_value = *(--right_p);
+
+ if (left_value < right_value)
+ {
+ return -1;
+ }
+
+ if (left_value > right_value)
+ {
+ return 1;
+ }
+ }
+ while (left_p > start_p);
+
+ return 0;
+} /* ecma_big_uint_compare */
+
+/**
+ * In-place multiply and addition operation with digit
+ *
+ * return updated value on success, NULL if no memory is available
+ */
+ecma_extended_primitive_t *
+ecma_big_uint_mul_digit (ecma_extended_primitive_t *value_p, /**< BigUInt value */
+ ecma_bigint_digit_t mul, /**< multiply value */
+ ecma_bigint_digit_t add) /**< addition value */
+{
+ JERRY_ASSERT (mul > 1);
+ JERRY_ASSERT (add < mul);
+
+ if (JERRY_UNLIKELY (value_p == NULL))
+ {
+ JERRY_ASSERT (add > 0);
+
+ value_p = ecma_bigint_create (sizeof (ecma_bigint_digit_t));
+
+ if (JERRY_UNLIKELY (value_p == NULL))
+ {
+ return NULL;
+ }
+
+ *ECMA_BIGINT_GET_DIGITS (value_p, 0) = add;
+ return value_p;
+ }
+
+ uint32_t size = ECMA_BIGINT_GET_SIZE (value_p);
+
+ JERRY_ASSERT (size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (value_p, size) != 0);
+
+ ecma_bigint_digit_t *current_p = ECMA_BIGINT_GET_DIGITS (value_p, 0);
+ ecma_bigint_digit_t *end_p = ECMA_BIGINT_GET_DIGITS (value_p, size);
+ ecma_bigint_digit_t carry = add;
+
+ do
+ {
+ ecma_bigint_two_digits_t multiply_result = ((ecma_bigint_two_digits_t) *current_p) * mul;
+ ecma_bigint_digit_t multiply_result_low, new_carry;
+
+ multiply_result_low = (ecma_bigint_digit_t) multiply_result;
+ new_carry = (ecma_bigint_digit_t) (multiply_result >> (8 * sizeof (ecma_bigint_digit_t)));
+
+ multiply_result_low += carry;
+ if (multiply_result_low < carry)
+ {
+ new_carry++;
+ }
+
+ *current_p++ = multiply_result_low;
+ carry = new_carry;
+ }
+ while (current_p < end_p);
+
+ if (carry == 0)
+ {
+ return value_p;
+ }
+
+ return ecma_big_uint_extend (value_p, carry);
+} /* ecma_big_uint_mul_digit */
+
+/**
+ * Convert a BigUInt to a human readable number
+ *
+ * return char sequence on success, NULL otherwise
+ */
+lit_utf8_byte_t *
+ecma_big_uint_to_string (ecma_extended_primitive_t *value_p, /**< BigUInt value */
+ uint32_t radix, /**< radix number between 2 and 36 */
+ uint32_t *char_start_p, /**< [out] start offset of numbers */
+ uint32_t *char_size_p) /**< [out] size of the output buffer */
+{
+ uint32_t size = ECMA_BIGINT_GET_SIZE (value_p);
+
+ JERRY_ASSERT (radix >= 2 && radix <= 36);
+ JERRY_ASSERT (size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (value_p, size) != 0);
+
+ uint32_t max_size = size * 8;
+
+ if (radix < 16)
+ {
+ if (radix >= 8)
+ {
+ /* Most frequent case. */
+ max_size = (max_size + 2) / 3;
+ }
+ else if (radix >= 4)
+ {
+ max_size = (max_size + 1) >> 1;
+ }
+ }
+ else if (radix < 32)
+ {
+ max_size = (max_size + 3) >> 2;
+ }
+ else
+ {
+ max_size = (max_size + 4) / 5;
+ }
+
+ /* This space can be used to store a sign. */
+ max_size += (uint32_t) (2 * sizeof (ecma_bigint_digit_t) - 1);
+ max_size &= ~(uint32_t) (sizeof (ecma_bigint_digit_t) - 1);
+ *char_size_p = max_size;
+
+ lit_utf8_byte_t *result_p = (lit_utf8_byte_t *) jmem_heap_alloc_block_null_on_error (max_size);
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return NULL;
+ }
+
+ memcpy (result_p, value_p + 1, size);
+
+ ecma_bigint_digit_t *start_p = (ecma_bigint_digit_t *) (result_p + size);
+ ecma_bigint_digit_t *end_p = (ecma_bigint_digit_t *) result_p;
+ lit_utf8_byte_t *string_p = result_p + max_size;
+
+ do
+ {
+ ecma_bigint_digit_t *current_p = (ecma_bigint_digit_t *) start_p;
+ ecma_bigint_digit_t remainder = 0;
+
+ if (sizeof (uintptr_t) == sizeof (ecma_bigint_two_digits_t))
+ {
+ do
+ {
+ ecma_bigint_two_digits_t result = *(--current_p) | ECMA_BIGINT_HIGH_DIGIT (remainder);
+
+ *current_p = (ecma_bigint_digit_t) (result / radix);
+ remainder = (ecma_bigint_digit_t) (result % radix);
+ }
+ while (current_p > end_p);
+ }
+ else
+ {
+ if (ECMA_BIGINT_SIZE_IS_ODD ((uintptr_t) current_p - (uintptr_t) end_p))
+ {
+ ecma_bigint_digit_t result = *(--current_p);
+ *current_p = result / radix;
+ remainder = result % radix;
+ }
+
+ while (current_p > end_p)
+ {
+ /* The following algorithm splits the 64 bit input into three numbers, extend
+ * them with remainder, divide them by radix, and updates the three bit ranges
+ * corresponding to the three numbers. */
+
+ const uint32_t extract_bits_low = 10;
+ const uint32_t extract_bits_low_mask = (uint32_t) ((1 << extract_bits_low) - 1);
+ const uint32_t extract_bits_high = (uint32_t) ((sizeof (ecma_bigint_digit_t) * 8) - extract_bits_low);
+ const uint32_t extract_bits_high_mask = (uint32_t) ((1 << extract_bits_high) - 1);
+
+ ecma_bigint_digit_t result_high = current_p[-1];
+ ecma_bigint_digit_t result_mid = (result_high & extract_bits_low_mask) << extract_bits_low;
+
+ result_high = (result_high >> extract_bits_low) | (remainder << extract_bits_high);
+ result_mid |= (result_high % radix) << (extract_bits_low * 2);
+ result_high = (result_high / radix) << extract_bits_low;
+
+ ecma_bigint_digit_t result_low = current_p[-2];
+ result_mid |= result_low >> extract_bits_high;
+ result_low = (result_low & extract_bits_high_mask) | ((result_mid % radix) << extract_bits_high);
+
+ result_mid = result_mid / radix;
+
+ current_p[-1] = result_high | (result_mid >> extract_bits_low);
+ current_p[-2] = (result_low / radix) | (result_mid << extract_bits_high);
+
+ remainder = result_low % radix;
+ current_p -= 2;
+ }
+ }
+
+ *(--string_p) = (lit_utf8_byte_t) ((remainder < 10) ? (remainder + LIT_CHAR_0)
+ : (remainder + (LIT_CHAR_LOWERCASE_A - 10)));
+ JERRY_ASSERT (string_p >= (lit_utf8_byte_t *) start_p);
+
+ if (start_p[-1] == 0)
+ {
+ start_p--;
+ }
+ }
+ while (start_p > end_p);
+
+ *char_start_p = (uint32_t) (string_p - result_p);
+ return result_p;
+} /* ecma_big_uint_to_string */
+
+/**
+ * Add right BigUInt value to the left BigUInt value
+ *
+ * return new BigInt value, NULL on error
+ */
+ecma_extended_primitive_t *
+ecma_big_uint_add (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */
+ ecma_extended_primitive_t *right_value_p) /**< right BigUInt value */
+{
+ uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_value_p);
+ uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_value_p);
+
+ JERRY_ASSERT (left_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) != 0);
+ JERRY_ASSERT (right_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (right_value_p, right_size) != 0);
+
+ if (left_size < right_size)
+ {
+ /* Swap values. */
+ ecma_extended_primitive_t *tmp_value_p = left_value_p;
+ left_value_p = right_value_p;
+ right_value_p = tmp_value_p;
+
+ uint32_t tmp_size = left_size;
+ left_size = right_size;
+ right_size = tmp_size;
+ }
+
+ ecma_extended_primitive_t *result_p = ecma_bigint_create (left_size);
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return NULL;
+ }
+
+ ecma_bigint_digit_t *current_p = ECMA_BIGINT_GET_DIGITS (result_p, 0);
+ ecma_bigint_digit_t *end_p = ECMA_BIGINT_GET_DIGITS (result_p, right_size);
+ ecma_bigint_digit_t *left_p = ECMA_BIGINT_GET_DIGITS (left_value_p, 0);
+ ecma_bigint_digit_t *right_p = ECMA_BIGINT_GET_DIGITS (right_value_p, 0);
+ ecma_bigint_digit_t carry = 0;
+
+ left_size -= right_size;
+
+ do
+ {
+ ecma_bigint_digit_t left = *left_p++;
+
+ if (carry == 0 || left != ~(ecma_bigint_digit_t) 0)
+ {
+ left += carry;
+ carry = 0;
+ }
+ else
+ {
+ left = 0;
+ carry = 1;
+ }
+
+ ecma_bigint_digit_t right = *right_p++;
+ left += right;
+
+ if (left < right)
+ {
+ JERRY_ASSERT (carry == 0);
+ carry = 1;
+ }
+
+ *current_p++ = left;
+ }
+ while (current_p < end_p);
+
+ end_p = (ecma_bigint_digit_t *) (((uint8_t *) end_p) + left_size);
+
+ if (carry != 0)
+ {
+ while (true)
+ {
+ if (JERRY_UNLIKELY (current_p == end_p))
+ {
+ return ecma_big_uint_extend (result_p, 1);
+ }
+
+ ecma_bigint_digit_t value = *left_p++;
+
+ if (value != ~(ecma_bigint_digit_t) 0)
+ {
+ *current_p++ = value + 1;
+ break;
+ }
+
+ *current_p++ = 0;
+ }
+ }
+
+ if (current_p < end_p)
+ {
+ memcpy (current_p, left_p, (size_t) ((uint8_t *) end_p - (uint8_t *) current_p));
+ }
+
+ return result_p;
+} /* ecma_big_uint_add */
+
+/**
+ * Substract right BigUInt value from the left BigUInt value
+ *
+ * return new BigInt value, NULL on error
+ */
+ecma_extended_primitive_t *
+ecma_big_uint_sub (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */
+ ecma_extended_primitive_t *right_value_p) /**< right BigUInt value */
+{
+ uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_value_p);
+ uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_value_p);
+
+ JERRY_ASSERT (left_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) != 0);
+ JERRY_ASSERT (right_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (right_value_p, right_size) != 0);
+ JERRY_ASSERT (left_size >= right_size);
+
+ ecma_extended_primitive_t *result_p = ecma_bigint_create (left_size);
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return NULL;
+ }
+
+ ecma_bigint_digit_t *current_p = ECMA_BIGINT_GET_DIGITS (result_p, 0);
+ ecma_bigint_digit_t *end_p = ECMA_BIGINT_GET_DIGITS (result_p, right_size);
+ ecma_bigint_digit_t *left_p = ECMA_BIGINT_GET_DIGITS (left_value_p, 0);
+ ecma_bigint_digit_t *right_p = ECMA_BIGINT_GET_DIGITS (right_value_p, 0);
+ ecma_bigint_digit_t carry = 0;
+
+ left_size -= right_size;
+
+ do
+ {
+ ecma_bigint_digit_t left = *left_p++;
+ ecma_bigint_digit_t right = *right_p++;
+
+ if (carry == 0 || left != 0)
+ {
+ left -= carry;
+ carry = left < right;
+ }
+ else
+ {
+ left = ~(ecma_bigint_digit_t) 0;
+ carry = 1;
+ }
+
+ *current_p++ = left - right;
+ }
+ while (current_p < end_p);
+
+ end_p = (ecma_bigint_digit_t *) (((uint8_t *) end_p) + left_size);
+
+ if (carry != 0)
+ {
+ while (true)
+ {
+ JERRY_ASSERT (current_p < end_p);
+
+ ecma_bigint_digit_t value = *left_p++;
+
+ if (value != 0)
+ {
+ *current_p++ = value - 1;
+ break;
+ }
+
+ *current_p++ = ~(ecma_bigint_digit_t) 0;
+ }
+ }
+
+ if (current_p < end_p)
+ {
+ memcpy (current_p, left_p, (size_t) ((uint8_t *) end_p - (uint8_t *) current_p));
+ return result_p;
+ }
+
+ ecma_bigint_digit_t *new_end_p = current_p;
+
+ if (new_end_p[-1] != 0)
+ {
+ return result_p;
+ }
+
+ do
+ {
+ new_end_p--;
+
+ JERRY_ASSERT (new_end_p > ECMA_BIGINT_GET_DIGITS (result_p, 0));
+ }
+ while (new_end_p[-1] == 0);
+
+ ecma_bigint_digit_t *result_data_p = ECMA_BIGINT_GET_DIGITS (result_p, 0);
+ uint32_t old_size = ECMA_BIGINT_GET_SIZE (result_p);
+ uint32_t new_size = (uint32_t) ((uint8_t *) new_end_p - (uint8_t *) result_data_p);
+
+ if (ECMA_BIGINT_SIZE_IS_ODD (new_size) && ((new_size + sizeof (ecma_bigint_digit_t)) == old_size))
+ {
+ result_p->u.bigint_sign_and_size -= (uint32_t) sizeof (ecma_bigint_digit_t);
+ return result_p;
+ }
+
+ ecma_extended_primitive_t *new_result_p = ecma_bigint_create (new_size);
+
+ if (JERRY_UNLIKELY (new_result_p == NULL))
+ {
+ ecma_deref_bigint (result_p);
+ return NULL;
+ }
+
+ memcpy (ECMA_BIGINT_GET_DIGITS (new_result_p, 0), result_data_p, new_size);
+ ecma_deref_bigint (result_p);
+
+ return new_result_p;
+} /* ecma_big_uint_sub */
+
+/**
+ * Multiply two BigUInt values
+ *
+ * return new BigInt value, NULL on error
+ */
+ecma_extended_primitive_t *
+ecma_big_uint_mul (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */
+ ecma_extended_primitive_t *right_value_p) /**< right BigUInt value */
+{
+ uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_value_p);
+ uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_value_p);
+
+ JERRY_ASSERT (left_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) != 0);
+ JERRY_ASSERT (right_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (right_value_p, right_size) != 0);
+
+ if (left_size < right_size)
+ {
+ /* Swap values. */
+ ecma_extended_primitive_t *tmp_value_p = left_value_p;
+ left_value_p = right_value_p;
+ right_value_p = tmp_value_p;
+
+ uint32_t tmp_size = left_size;
+ left_size = right_size;
+ right_size = tmp_size;
+ }
+
+ uint32_t result_size = left_size + right_size - (uint32_t) sizeof (ecma_bigint_digit_t);
+
+ ecma_extended_primitive_t *result_p = ecma_bigint_create (result_size);
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return NULL;
+ }
+
+ memset (ECMA_BIGINT_GET_DIGITS (result_p, 0), 0, result_size);
+
+ /* Lower amount of space is allocated by default. This value provides extra space if needed. */
+ ecma_bigint_digit_t extra_space[1] = { 0 };
+
+ ecma_bigint_digit_t *right_p = ECMA_BIGINT_GET_DIGITS (right_value_p, 0);
+ ecma_bigint_digit_t *right_end_p = ECMA_BIGINT_GET_DIGITS (right_value_p, right_size);
+ ecma_bigint_digit_t *left_start_p = ECMA_BIGINT_GET_DIGITS (left_value_p, 0);
+ ecma_bigint_digit_t *left_end_p = ECMA_BIGINT_GET_DIGITS (left_value_p, left_size);
+
+ ecma_bigint_digit_t *result_start_p = ECMA_BIGINT_GET_DIGITS (result_p, 0);
+ ecma_bigint_digit_t *result_end_p = ECMA_BIGINT_GET_DIGITS (result_p, result_size);
+
+ do
+ {
+ ecma_bigint_two_digits_t right = *right_p++;
+
+ if (right == 0)
+ {
+ result_start_p++;
+ continue;
+ }
+
+ ecma_bigint_digit_t *left_p = left_start_p;
+ ecma_bigint_digit_t *destination_p = result_start_p;
+ ecma_bigint_digit_t carry = 0;
+
+ do
+ {
+ JERRY_ASSERT (destination_p != (ecma_bigint_digit_t *) (extra_space + 1));
+
+ ecma_bigint_two_digits_t multiply_result;
+ ecma_bigint_digit_t multiply_result_low, new_carry;
+ ecma_bigint_digit_t value = *destination_p;
+
+ multiply_result = ((ecma_bigint_two_digits_t) (*left_p++)) * ((ecma_bigint_two_digits_t) right);
+ multiply_result_low = (ecma_bigint_digit_t) multiply_result;
+ value += multiply_result_low;
+ new_carry = (ecma_bigint_digit_t) (multiply_result >> (8 * sizeof (ecma_bigint_digit_t)));
+
+ /* The new_carry can never overflow because:
+ * a) If left or right is less than 0xff..ff, new_carry will be less than or equal to
+ * 0xff...fd, and increasing it by maximum of two (carries) cannot overflow.
+ * b) If left and right are both equal to 0xff..ff, multiply_result_low will be 1,
+ * and computing value + carry + 1 can only increase new_carry at most once. */
+
+ if (value < multiply_result_low)
+ {
+ JERRY_ASSERT (new_carry < ~(ecma_bigint_digit_t) 0);
+ new_carry++;
+ }
+
+ value += carry;
+
+ if (value < carry)
+ {
+ JERRY_ASSERT (new_carry < ~(ecma_bigint_digit_t) 0);
+ new_carry++;
+ }
+
+ carry = new_carry;
+ *destination_p++ = value;
+
+ if (destination_p == result_end_p)
+ {
+ destination_p = (ecma_bigint_digit_t *) extra_space;
+ }
+ }
+ while (left_p < left_end_p);
+
+ while (carry > 0)
+ {
+ JERRY_ASSERT (destination_p != (ecma_bigint_digit_t *) (extra_space + 1));
+
+ ecma_bigint_digit_t value = *destination_p;
+
+ value += carry;
+ carry = (value < carry);
+
+ *destination_p++ = value;
+
+ if (destination_p == result_end_p)
+ {
+ destination_p = (ecma_bigint_digit_t *) extra_space;
+ }
+ }
+
+ result_start_p++;
+ }
+ while (right_p < right_end_p);
+
+ if (extra_space[0] == 0)
+ {
+ return result_p;
+ }
+
+ return ecma_big_uint_extend (result_p, extra_space[0]);
+} /* ecma_big_uint_mul */
+
+/**
+ * Count the number of leading zero bits of a digit
+ *
+ * return new BigInt value, NULL on error
+ */
+static ecma_bigint_digit_t
+ecma_big_uint_count_leading_zero (ecma_bigint_digit_t digit) /**< digit value */
+{
+ ecma_bigint_digit_t shift = 4 * sizeof (ecma_bigint_digit_t);
+ ecma_bigint_digit_t result = 8 * sizeof (ecma_bigint_digit_t);
+
+ do
+ {
+ ecma_bigint_digit_t value = digit >> shift;
+ if (value > 0)
+ {
+ digit = value;
+ result -= shift;
+ }
+ shift >>= 1;
+ }
+ while (shift > 0);
+
+ return result - digit;
+} /* ecma_big_uint_count_leading_zero */
+
+/**
+ * Divide left BigUInt value with right digit value
+ *
+ * return new BigInt value, NULL on error
+ */
+static ecma_extended_primitive_t *
+ecma_big_uint_div_digit (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */
+ ecma_bigint_digit_t divisor_digit, /**< divisor value */
+ bool is_mod) /**< true if return with remainder */
+{
+ uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_value_p);
+
+ JERRY_ASSERT (left_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) != 0);
+ JERRY_ASSERT (divisor_digit > 0);
+
+ ecma_bigint_digit_t *left_p = ECMA_BIGINT_GET_DIGITS (left_value_p, left_size - sizeof (ecma_bigint_digit_t));
+ ecma_bigint_digit_t *end_p = ECMA_BIGINT_GET_DIGITS (left_value_p, 0);
+
+ ecma_bigint_digit_t last_digit = *left_p;
+ ecma_bigint_digit_t remainder = last_digit % divisor_digit;
+
+ last_digit = last_digit / divisor_digit;
+
+ ecma_bigint_digit_t result_size = 0;
+ ecma_extended_primitive_t *result_p = NULL;
+ ecma_bigint_digit_t *current_p = NULL;
+
+ if (!is_mod)
+ {
+ result_size = left_size;
+
+ if (last_digit == 0)
+ {
+ result_size -= (uint32_t) sizeof (ecma_bigint_digit_t);
+ }
+
+ result_p = ecma_bigint_create (result_size);
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return NULL;
+ }
+
+ current_p = ECMA_BIGINT_GET_DIGITS (result_p, result_size);
+
+ if (last_digit != 0)
+ {
+ *(--current_p) = last_digit;
+ }
+ }
+
+ while (left_p > end_p)
+ {
+ const uint32_t shift = 1 << ECMA_BIGINT_DIGIT_SHIFT;
+
+ ecma_bigint_two_digits_t result = *(--left_p) | (((ecma_bigint_two_digits_t) remainder) << shift);
+
+ if (!is_mod)
+ {
+ *(--current_p) = (ecma_bigint_digit_t) (result / divisor_digit);
+ }
+
+ remainder = (ecma_bigint_digit_t) (result % divisor_digit);
+ }
+
+ if (!is_mod)
+ {
+ JERRY_ASSERT (current_p == ECMA_BIGINT_GET_DIGITS (result_p, 0));
+ return result_p;
+ }
+
+ if (remainder == 0)
+ {
+ return ecma_bigint_create (0);
+ }
+
+ result_p = ecma_bigint_create (sizeof (ecma_bigint_digit_t));
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return NULL;
+ }
+
+ *ECMA_BIGINT_GET_DIGITS (result_p, 0) = remainder;
+ return result_p;
+} /* ecma_big_uint_div_digit */
+
+/**
+ * Shift left BigInt digits
+ *
+ * return newly allocated buffer, NULL on error
+ */
+static ecma_bigint_digit_t *
+ecma_big_uint_div_shift_left (ecma_extended_primitive_t *value_p, /**< BigUInt value */
+ ecma_bigint_digit_t shift_left, /**< left shift */
+ bool extend) /**< extend the result with an extra digit */
+{
+ uint32_t size = ECMA_BIGINT_GET_SIZE (value_p);
+
+ JERRY_ASSERT (size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (value_p, size) != 0);
+
+ ecma_bigint_digit_t *source_p = ECMA_BIGINT_GET_DIGITS (value_p, 0);
+ ecma_bigint_digit_t *end_p = ECMA_BIGINT_GET_DIGITS (value_p, size);
+
+ if (extend)
+ {
+ size += (uint32_t) sizeof (ecma_bigint_digit_t);
+ }
+
+ ecma_bigint_digit_t *result_p = (ecma_bigint_digit_t *) jmem_heap_alloc_block_null_on_error (size);
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return result_p;
+ }
+
+ if (shift_left == 0)
+ {
+ JERRY_ASSERT (extend);
+
+ size -= (uint32_t) sizeof (ecma_bigint_digit_t);
+ *(ecma_bigint_digit_t *) (((uint8_t *) result_p) + size) = 0;
+
+ memcpy (result_p, source_p, size);
+ return result_p;
+ }
+
+ ecma_bigint_digit_t *destination_p = result_p;
+ ecma_bigint_digit_t carry = 0;
+ uint32_t shift_right = (1 << ECMA_BIGINT_DIGIT_SHIFT) - shift_left;
+
+ do
+ {
+ ecma_bigint_digit_t value = *source_p++;
+
+ *destination_p++ = (value << shift_left) | carry;
+ carry = value >> shift_right;
+ }
+ while (source_p < end_p);
+
+ if (extend)
+ {
+ *destination_p++ = carry;
+ }
+
+ return result_p;
+} /* ecma_big_uint_div_shift_left */
+
+/**
+ * Divide left BigUInt value with right BigUInt value
+ *
+ * return new BigInt value, NULL on error
+ */
+ecma_extended_primitive_t *
+ecma_big_uint_div_mod (ecma_extended_primitive_t *dividend_value_p, /**< divider BigUInt value */
+ ecma_extended_primitive_t *divisor_value_p, /**< divisor BigUInt value */
+ bool is_mod) /**< true if return with remainder instead of quotient */
+{
+ /* This algorithm is based on Donald Knuth’s "Algorithm D" */
+ uint32_t divisor_size = ECMA_BIGINT_GET_SIZE (divisor_value_p);
+
+ JERRY_ASSERT (divisor_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (divisor_value_p, divisor_size) != 0);
+
+ /* The divisor must have at least two digits, so the single digit case is handled separately. */
+ if (divisor_size == sizeof (ecma_bigint_digit_t))
+ {
+ return ecma_big_uint_div_digit (dividend_value_p, *ECMA_BIGINT_GET_DIGITS (divisor_value_p, 0), is_mod);
+ }
+
+ /* D1. [Normalize] */
+ ecma_bigint_digit_t divisor_high = ECMA_BIGINT_GET_LAST_DIGIT (divisor_value_p, divisor_size);
+ ecma_bigint_digit_t shift_left = ecma_big_uint_count_leading_zero (divisor_high);
+ ecma_bigint_digit_t *buffer_p = ecma_big_uint_div_shift_left (dividend_value_p, shift_left, true);
+
+ if (JERRY_UNLIKELY (buffer_p == NULL))
+ {
+ return NULL;
+ }
+
+ uint32_t dividend_size = ECMA_BIGINT_GET_SIZE (dividend_value_p);
+ ecma_extended_primitive_t *result_p = NULL;
+ ecma_bigint_digit_t *divisor_p;
+
+ JERRY_ASSERT (dividend_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (dividend_value_p, dividend_size) != 0);
+ JERRY_ASSERT (dividend_size >= divisor_size);
+
+ if (shift_left > 0)
+ {
+ divisor_p = ecma_big_uint_div_shift_left (divisor_value_p, shift_left, false);
+
+ if (JERRY_UNLIKELY (divisor_p == NULL))
+ {
+ goto error;
+ }
+ }
+ else
+ {
+ divisor_p = ECMA_BIGINT_GET_DIGITS (divisor_value_p, 0);
+ }
+
+ ecma_bigint_digit_t *dividend_end_p = (ecma_bigint_digit_t *) (((uint8_t *) buffer_p) + dividend_size);
+ ecma_bigint_digit_t *dividend_p = (ecma_bigint_digit_t *) (((uint8_t *) dividend_end_p) - divisor_size);
+ ecma_bigint_digit_t *divisor_end_p = (ecma_bigint_digit_t *) (((uint8_t *) divisor_p) + divisor_size);
+ ecma_bigint_digit_t divisor_low = divisor_end_p[-2];
+
+ divisor_high = divisor_end_p[-1];
+ JERRY_ASSERT ((divisor_high & (((ecma_bigint_digit_t) 1) << (8 * sizeof (ecma_bigint_digit_t) - 1))) != 0);
+
+ do
+ {
+ /* D3. [Calculate Q′] */
+ ecma_bigint_digit_t result_div;
+
+ /* This do-while(false) statement allows local declarations and early exit. */
+ do
+ {
+ ecma_bigint_digit_t result_mod;
+
+ if (dividend_end_p[0] < divisor_high)
+ {
+ ecma_bigint_two_digits_t dividend = dividend_end_p[-1] | ECMA_BIGINT_HIGH_DIGIT (dividend_end_p[0]);
+ result_div = (ecma_bigint_digit_t) (dividend / divisor_high);
+ result_mod = (ecma_bigint_digit_t) (dividend % divisor_high);
+ }
+ else
+ {
+ JERRY_ASSERT (dividend_end_p[0] == divisor_high && dividend_end_p[-1] < divisor_high);
+
+ result_div = ~((ecma_bigint_digit_t) 0);
+ result_mod = dividend_end_p[-1] + divisor_high;
+
+ if (result_mod < divisor_high)
+ {
+ break;
+ }
+ }
+
+ ecma_bigint_two_digits_t low_digits = ((ecma_bigint_two_digits_t) result_div) * divisor_low;
+
+ while (low_digits > (ECMA_BIGINT_HIGH_DIGIT (result_mod) | divisor_low))
+ {
+ result_div--;
+ result_mod += divisor_high;
+
+ /* If result_mod becomes a two digit long number, the condition of the loop must be true,
+ * so the loop can be aborted. This loop stops after maximum of two iterations, since
+ * the highest bit of divisor_high is set. */
+ if (result_mod < divisor_high)
+ {
+ break;
+ }
+
+ /* Subtraction is faster than recomputing result_div * divisor_low. */
+ low_digits -= divisor_low;
+ }
+ }
+ while (false);
+
+ /* D4. [Multiply and subtract] */
+ ecma_bigint_digit_t *destination_p = dividend_p;
+ ecma_bigint_digit_t *source_p = divisor_p;
+ ecma_bigint_digit_t carry = 0;
+
+ do
+ {
+ ecma_bigint_two_digits_t multiply_result = ((ecma_bigint_two_digits_t) (*source_p++)) * result_div;
+ ecma_bigint_digit_t multiply_result_low, new_carry;
+ ecma_bigint_digit_t value = *destination_p;
+
+ /* The new carry never overflows. See the comment in ecma_big_uint_mul. */
+ new_carry = (ecma_bigint_digit_t) (multiply_result >> (8 * sizeof (ecma_bigint_digit_t)));
+ multiply_result_low = (ecma_bigint_digit_t) multiply_result;
+
+ if (value < multiply_result_low)
+ {
+ new_carry++;
+ }
+
+ value -= multiply_result_low;
+
+ if (value < carry)
+ {
+ new_carry++;
+ }
+
+ *destination_p++ = value - carry;
+ carry = new_carry;
+ }
+ while (source_p < divisor_end_p);
+
+ bool negative_result = *destination_p < carry;
+ *destination_p -= carry;
+
+ if (negative_result)
+ {
+ /* D6. [Add back] */
+ result_div--;
+
+ destination_p = dividend_p;
+ source_p = divisor_p;
+ carry = 0;
+
+ do
+ {
+ ecma_bigint_digit_t left = *destination_p;
+
+ if (carry == 0 || left != ~(ecma_bigint_digit_t) 0)
+ {
+ left += carry;
+ carry = 0;
+ }
+ else
+ {
+ left = 0;
+ carry = 1;
+ }
+
+ ecma_bigint_digit_t right = *source_p++;
+ left += right;
+
+ if (left < right)
+ {
+ JERRY_ASSERT (carry == 0);
+ carry = 1;
+ }
+
+ *destination_p++ = left;
+ }
+ while (source_p < divisor_end_p);
+ }
+
+ *dividend_end_p = result_div;
+
+ dividend_p--;
+ dividend_end_p--;
+ }
+ while (dividend_p >= buffer_p);
+
+ ecma_bigint_digit_t *source_p;
+ ecma_bigint_digit_t *source_end_p;
+
+ if (is_mod)
+ {
+ source_p = buffer_p;
+ source_end_p = dividend_end_p;
+
+ while (source_end_p > source_p && *source_end_p == 0)
+ {
+ source_end_p--;
+ }
+
+ if ((*source_end_p >> shift_left) != 0)
+ {
+ source_end_p++;
+ /* This is required to reset carry below. */
+ *source_end_p = 0;
+ }
+ }
+ else
+ {
+ source_p = dividend_end_p + 1;
+ source_end_p = (ecma_bigint_digit_t *) (((uint8_t *) buffer_p) + dividend_size);
+
+ if (*source_end_p != 0)
+ {
+ source_end_p++;
+ }
+ }
+
+ result_p = ecma_bigint_create ((uint32_t) ((uint8_t *) source_end_p - (uint8_t *) source_p));
+
+ if (result_p != NULL && source_p != source_end_p)
+ {
+ ecma_bigint_digit_t *destination_p = ECMA_BIGINT_GET_DIGITS (result_p, 0);
+
+ if (is_mod && shift_left > 0)
+ {
+ ecma_bigint_digit_t shift_right = shift_left;
+
+ shift_left = (ecma_bigint_digit_t) (8 * (sizeof (ecma_bigint_digit_t)) - shift_left);
+ destination_p += source_end_p - source_p;
+
+ ecma_bigint_digit_t carry = *source_end_p << shift_left;
+
+ do
+ {
+ ecma_bigint_digit_t value = *(--source_end_p);
+
+ *(--destination_p) = (value >> shift_right) | carry;
+ carry = value << shift_left;
+ }
+ while (source_end_p > source_p);
+ }
+ else
+ {
+ memcpy (destination_p, source_p, (size_t) ((uint8_t *) source_end_p - (uint8_t *) source_p));
+ }
+ }
+
+error:
+ jmem_heap_free_block (buffer_p, dividend_size + sizeof (ecma_bigint_digit_t));
+
+ if (shift_left > 0 && divisor_p != NULL)
+ {
+ jmem_heap_free_block (divisor_p, divisor_size);
+ }
+
+ return result_p;
+} /* ecma_big_uint_div_mod */
+
+/**
+ * Shift left BigInt values by an uint32 value
+ *
+ * return new BigInt value, NULL on error
+ */
+ecma_extended_primitive_t *
+ecma_big_uint_shift_left (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */
+ uint32_t right_value) /**< shift value */
+{
+ JERRY_ASSERT (right_value > 0);
+
+ uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_value_p);
+ JERRY_ASSERT (left_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) != 0);
+
+ uint32_t zero_size = (right_value >> ECMA_BIGINT_DIGIT_SHIFT) * (uint32_t) sizeof (ecma_bigint_digit_t);
+ uint32_t result_size = left_size + zero_size;
+
+ uint32_t shift_left = right_value & ((1 << ECMA_BIGINT_DIGIT_SHIFT) - 1);
+ uint32_t shift_right = (1 << ECMA_BIGINT_DIGIT_SHIFT) - shift_left;
+
+ if (shift_left > 0 && (ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) >> shift_right) != 0)
+ {
+ result_size += (uint32_t) sizeof (ecma_bigint_digit_t);
+ }
+
+ if (result_size > ECMA_BIGINT_MAX_SIZE)
+ {
+ return NULL;
+ }
+
+ ecma_extended_primitive_t *result_value_p = ecma_bigint_create (result_size);
+ ecma_bigint_digit_t *left_p = ECMA_BIGINT_GET_DIGITS (left_value_p, 0);
+ ecma_bigint_digit_t *result_p = ECMA_BIGINT_GET_DIGITS (result_value_p, 0);
+
+ if (zero_size > 0)
+ {
+ memset (result_p, 0, zero_size);
+ result_p = (ecma_bigint_digit_t *) (((uint8_t *) result_p) + zero_size);
+ }
+
+ if (shift_left == 0)
+ {
+ /* Shift by full digits. */
+ memcpy (result_p, left_p, left_size);
+ return result_value_p;
+ }
+
+ ecma_bigint_digit_t *left_end_p = ECMA_BIGINT_GET_DIGITS (left_value_p, left_size);
+ ecma_bigint_digit_t carry = 0;
+
+ do
+ {
+ ecma_bigint_digit_t value = *left_p++;
+
+ *result_p++ = (value << shift_left) | carry;
+ carry = value >> shift_right;
+ }
+ while (left_p < left_end_p);
+
+ if (carry > 0)
+ {
+ *result_p = carry;
+ }
+
+ return result_value_p;
+} /* ecma_big_uint_shift_left */
+
+/**
+ * Shift right BigInt values by an uint32 value
+ *
+ * return new BigInt value, NULL on error
+ */
+ecma_extended_primitive_t *
+ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */
+ uint32_t right_value) /**< shift value */
+{
+ JERRY_ASSERT (right_value > 0);
+
+ uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_value_p);
+ JERRY_ASSERT (left_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) != 0);
+
+ uint32_t crop_size = (right_value >> ECMA_BIGINT_DIGIT_SHIFT) * (uint32_t) sizeof (ecma_bigint_digit_t);
+
+ uint32_t shift_right = right_value & ((1 << ECMA_BIGINT_DIGIT_SHIFT) - 1);
+ uint32_t shift_left = (1 << ECMA_BIGINT_DIGIT_SHIFT) - shift_right;
+ ecma_bigint_digit_t carry = 0;
+
+ if (shift_right > 0
+ && (ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) >> shift_right) == 0)
+ {
+ carry = ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) << shift_left;
+ left_size -= (uint32_t) sizeof (ecma_bigint_digit_t);
+ }
+
+ if (left_size <= crop_size)
+ {
+ return ecma_bigint_create (0);
+ }
+
+ uint32_t size = left_size - crop_size;
+ ecma_extended_primitive_t *result_value_p = ecma_bigint_create (size);
+
+ if (shift_right == 0)
+ {
+ memcpy (ECMA_BIGINT_GET_DIGITS (result_value_p, 0), ECMA_BIGINT_GET_DIGITS (left_value_p, crop_size), size);
+ return result_value_p;
+ }
+
+ ecma_bigint_digit_t *left_p = ECMA_BIGINT_GET_DIGITS (left_value_p, left_size);
+ ecma_bigint_digit_t *result_p = ECMA_BIGINT_GET_DIGITS (result_value_p, size);
+ ecma_bigint_digit_t *end_p = ECMA_BIGINT_GET_DIGITS (result_value_p, 0);
+
+ do
+ {
+ ecma_bigint_digit_t value = *(--left_p);
+
+ *(--result_p) = (value >> shift_right) | carry;
+ carry = value << shift_left;
+ }
+ while (result_p > end_p);
+
+ return result_value_p;
+} /* ecma_big_uint_shift_right */
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
diff --git a/jerry-core/ecma/operations/ecma-big-uint.h b/jerry-core/ecma/operations/ecma-big-uint.h
new file mode 100644
index 00000000..a8e16af8
--- /dev/null
+++ b/jerry-core/ecma/operations/ecma-big-uint.h
@@ -0,0 +1,88 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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_BIG_UINT_H
+#define ECMA_BIG_UINT_H
+
+#include "ecma-globals.h"
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+/**
+ * Limit of BigUInt memory allocation in JerryScript.
+ */
+#define ECMA_BIGINT_MAX_SIZE 0x10000
+
+/**
+ * Unsigned type which can hold two digits.
+ */
+typedef uint64_t ecma_bigint_two_digits_t;
+
+/**
+ * Shift used by left/right shifting of a value.
+ */
+#define ECMA_BIGINT_DIGIT_SHIFT 5
+
+/**
+ * Return with the digits of a BigInt value.
+ */
+#define ECMA_BIGINT_GET_DIGITS(value_p, offset) \
+ ((ecma_bigint_digit_t *) (((uint8_t *) (value_p)) + sizeof (ecma_extended_primitive_t) + (offset)))
+
+/**
+ * Return with the digits of a BigInt value.
+ */
+#define ECMA_BIGINT_GET_LAST_DIGIT(value_p, size) \
+ *ECMA_BIGINT_GET_DIGITS (value_p, size - sizeof (ecma_bigint_digit_t))
+
+/**
+ * Returns true if size is an odd number.
+ */
+#define ECMA_BIGINT_SIZE_IS_ODD(size) \
+ (((size) & sizeof (ecma_bigint_digit_t)) != 0)
+
+/**
+ * Returns a two digit value where the high digit is set to the passed digit.
+ */
+#define ECMA_BIGINT_HIGH_DIGIT(digit) \
+ (((ecma_bigint_two_digits_t) digit) << (8 * sizeof (ecma_bigint_digit_t)))
+
+ecma_extended_primitive_t *ecma_bigint_create (uint32_t size);
+ecma_extended_primitive_t *ecma_big_uint_extend (ecma_extended_primitive_t *value_p, ecma_bigint_digit_t digit);
+
+int ecma_big_uint_compare (ecma_extended_primitive_t *left_value_p, ecma_extended_primitive_t *right_value_p);
+
+ecma_extended_primitive_t *ecma_big_uint_mul_digit (ecma_extended_primitive_t *value_p,
+ ecma_bigint_digit_t mul, ecma_bigint_digit_t add);
+
+uint8_t *ecma_big_uint_to_string (ecma_extended_primitive_t *value_p, uint32_t radix,
+ uint32_t *char_start_p, uint32_t *char_size_p);
+
+ecma_extended_primitive_t *ecma_big_uint_add (ecma_extended_primitive_t *left_value_p,
+ ecma_extended_primitive_t *right_value_p);
+ecma_extended_primitive_t *ecma_big_uint_sub (ecma_extended_primitive_t *left_value_p,
+ ecma_extended_primitive_t *right_value_p);
+ecma_extended_primitive_t *ecma_big_uint_mul (ecma_extended_primitive_t *left_value_p,
+ ecma_extended_primitive_t *right_value_p);
+ecma_extended_primitive_t *ecma_big_uint_div_mod (ecma_extended_primitive_t *dividend_value_p,
+ ecma_extended_primitive_t *divisor_value_p,
+ bool is_mod);
+
+ecma_extended_primitive_t *ecma_big_uint_shift_left (ecma_extended_primitive_t *left_value_p, uint32_t right_value);
+ecma_extended_primitive_t *ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, uint32_t right_value);
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
+#endif /* ECMA_BIG_UINT_H */
diff --git a/jerry-core/ecma/operations/ecma-bigint-object.c b/jerry-core/ecma/operations/ecma-bigint-object.c
new file mode 100644
index 00000000..fbce1938
--- /dev/null
+++ b/jerry-core/ecma/operations/ecma-bigint-object.c
@@ -0,0 +1,66 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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-bigint-object.h"
+#include "ecma-builtins.h"
+#include "ecma-exceptions.h"
+#include "ecma-gc.h"
+#include "ecma-globals.h"
+#include "ecma-helpers.h"
+#include "ecma-objects.h"
+#include "ecma-objects-general.h"
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmabigintobject ECMA BigInt object related routines
+ * @{
+ */
+
+/**
+ * BigInt object creation operation.
+ *
+ * See also: ECMA-262 v11, 7.1.18
+ *
+ * @return ecma value
+ * Returned value must be freed with ecma_free_value
+ */
+ecma_value_t
+ecma_op_create_bigint_object (ecma_value_t arg) /**< argument passed to the toObject operation */
+{
+ JERRY_ASSERT (ecma_is_value_bigint (arg));
+
+ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_BIGINT_PROTOTYPE);
+
+ ecma_object_t *object_p = ecma_create_object (prototype_obj_p,
+ sizeof (ecma_extended_object_t),
+ ECMA_OBJECT_TYPE_CLASS);
+
+ ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
+ ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_BIGINT_UL;
+ ext_object_p->u.class_prop.u.value = ecma_copy_value (arg);
+
+ return ecma_make_object_value (object_p);
+} /* ecma_op_create_bigint_object */
+
+/**
+ * @}
+ * @}
+ */
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
diff --git a/jerry-core/ecma/operations/ecma-bigint-object.h b/jerry-core/ecma/operations/ecma-bigint-object.h
new file mode 100644
index 00000000..254e7598
--- /dev/null
+++ b/jerry-core/ecma/operations/ecma-bigint-object.h
@@ -0,0 +1,39 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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_BIGINT_OBJECT_H
+#define ECMA_BIGINT_OBJECT_H
+
+#include "ecma-globals.h"
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmabigintobject ECMA BigInt object related routines
+ * @{
+ */
+
+ecma_value_t ecma_op_create_bigint_object (ecma_value_t arg);
+
+/**
+ * @}
+ * @}
+ */
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
+#endif /* !ECMA_BIGINT_OBJECT_H */
diff --git a/jerry-core/ecma/operations/ecma-bigint.c b/jerry-core/ecma/operations/ecma-bigint.c
new file mode 100644
index 00000000..207f6fda
--- /dev/null
+++ b/jerry-core/ecma/operations/ecma-bigint.c
@@ -0,0 +1,508 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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-bigint.h"
+#include "ecma-big-uint.h"
+#include "ecma-exceptions.h"
+#include "ecma-helpers.h"
+#include "lit-char-helpers.h"
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+/**
+ * Raise a not enough memory error
+ *
+ * @return ECMA_VALUE_ERROR
+ * Returned value must be freed with ecma_free_value.
+ */
+static ecma_value_t
+ecma_bigint_raise_memory_error (void)
+{
+ return ecma_raise_range_error (ECMA_ERR_MSG ("Cannot allocate memory for a BigInt value"));
+} /* ecma_bigint_raise_memory_error */
+
+/**
+ * Parse a string and create a BigInt value
+ *
+ * @return ecma BigInt value or ECMA_VALUE_ERROR
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represenation of the BigInt */
+ lit_utf8_size_t size) /**< string size */
+{
+ ecma_bigint_digit_t radix = 10;
+ uint32_t sign = 0;
+
+ if (size >= 3 && string_p[0] == LIT_CHAR_0)
+ {
+ if (string_p[1] == LIT_CHAR_LOWERCASE_X || string_p[1] == LIT_CHAR_UPPERCASE_X)
+ {
+ radix = 16;
+ string_p += 2;
+ size -= 2;
+ }
+ else if (string_p[1] == LIT_CHAR_LOWERCASE_B || string_p[1] == LIT_CHAR_UPPERCASE_B)
+ {
+ radix = 2;
+ string_p += 2;
+ size -= 2;
+ }
+ }
+ else if (size >= 2)
+ {
+ if (string_p[0] == LIT_CHAR_PLUS)
+ {
+ size--;
+ string_p++;
+ }
+ else if (string_p[0] == LIT_CHAR_MINUS)
+ {
+ sign = ECMA_BIGINT_SIGN;
+ size--;
+ string_p++;
+ }
+ }
+ else if (size == 0)
+ {
+ return ecma_raise_syntax_error (ECMA_ERR_MSG ("BigInt cannot be constructed from empty string"));
+ }
+
+ const lit_utf8_byte_t *string_end_p = string_p + size;
+
+ while (string_p < string_end_p && *string_p == LIT_CHAR_0)
+ {
+ string_p++;
+ }
+
+ ecma_extended_primitive_t *result_p = NULL;
+
+ if (string_p == string_end_p)
+ {
+ result_p = ecma_bigint_create (0);
+ }
+ else
+ {
+ do
+ {
+ ecma_bigint_digit_t digit = radix;
+
+ if (*string_p >= LIT_CHAR_0 && *string_p <= LIT_CHAR_9)
+ {
+ digit = (ecma_bigint_digit_t) (*string_p - LIT_CHAR_0);
+ }
+ else
+ {
+ lit_utf8_byte_t character = (lit_utf8_byte_t) LEXER_TO_ASCII_LOWERCASE (*string_p);
+
+ if (character >= LIT_CHAR_LOWERCASE_A && character <= LIT_CHAR_LOWERCASE_F)
+ {
+ digit = (ecma_bigint_digit_t) (character - (LIT_CHAR_LOWERCASE_A - 10));
+ }
+ }
+
+ if (digit >= radix)
+ {
+ if (result_p != NULL)
+ {
+ ecma_deref_bigint (result_p);
+ }
+ return ecma_raise_syntax_error (ECMA_ERR_MSG ("String cannot be converted to BigInt value"));
+ }
+
+ result_p = ecma_big_uint_mul_digit (result_p, radix, digit);
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ break;
+ }
+ }
+ while (++string_p < string_end_p);
+ }
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return ecma_bigint_raise_memory_error ();
+ }
+
+ result_p->u.bigint_sign_and_size |= sign;
+ return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
+} /* ecma_bigint_parse_string */
+
+/**
+ * Create a string representation for a BigInt value
+ *
+ * @return ecma string or ECMA_VALUE_ERROR
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_string_t *
+ecma_bigint_to_string (ecma_value_t value, /**< BigInt value */
+ ecma_bigint_digit_t radix) /**< conversion radix */
+{
+ JERRY_ASSERT (ecma_is_value_bigint (value));
+
+ ecma_extended_primitive_t *bigint_p = ecma_get_extended_primitive_from_value (value);
+
+ if (ECMA_BIGINT_GET_SIZE (bigint_p) == 0)
+ {
+ return ecma_new_ecma_string_from_code_unit (LIT_CHAR_0);
+ }
+
+ uint32_t char_start_p, char_size_p;
+ lit_utf8_byte_t *string_buffer_p = ecma_big_uint_to_string (bigint_p, radix, &char_start_p, &char_size_p);
+
+ if (JERRY_UNLIKELY (string_buffer_p == NULL))
+ {
+ ecma_raise_range_error (ECMA_ERR_MSG ("Cannot allocate memory for a string representation of a BigInt value"));
+ return NULL;
+ }
+
+ JERRY_ASSERT (char_start_p > 0);
+
+ if (bigint_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
+ {
+ string_buffer_p[--char_start_p] = LIT_CHAR_MINUS;
+ }
+
+ ecma_string_t *string_p;
+ string_p = ecma_new_ecma_string_from_utf8 (string_buffer_p + char_start_p, char_size_p - char_start_p);
+
+ jmem_heap_free_block (string_buffer_p, char_size_p);
+ return string_p;
+} /* ecma_bigint_to_string */
+
+/**
+ * Negate a non-zero BigInt value
+ *
+ * @return ecma BigInt value or ECMA_VALUE_ERROR
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_bigint_negate (ecma_extended_primitive_t *value_p) /**< BigInt value */
+{
+ uint32_t size = ECMA_BIGINT_GET_SIZE (value_p);
+
+ JERRY_ASSERT (size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (value_p, size) != 0);
+
+ ecma_extended_primitive_t *result_p = ecma_bigint_create (size);
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return ecma_bigint_raise_memory_error ();
+ }
+
+ memcpy (result_p + 1, value_p + 1, size);
+ result_p->refs_and_type = ECMA_EXTENDED_PRIMITIVE_REF_ONE | ECMA_TYPE_BIGINT;
+ result_p->u.bigint_sign_and_size = value_p->u.bigint_sign_and_size ^ ECMA_BIGINT_SIGN;
+
+ return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
+} /* ecma_bigint_negate */
+
+/**
+ * Add/subtract right BigInt value to/from left BigInt value
+ *
+ * @return ecma BigInt value or ECMA_VALUE_ERROR
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_bigint_add_sub (ecma_value_t left_value, /**< left BigInt value */
+ ecma_value_t right_value, /**< right BigInt value */
+ bool is_add) /**< true if add operation should be performed */
+{
+ JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));
+
+ ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
+ ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);
+ uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_p);
+ uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_p);
+
+ if (right_size == 0)
+ {
+ ecma_ref_extended_primitive (left_p);
+ return left_value;
+ }
+
+ if (left_size == 0)
+ {
+ if (!is_add)
+ {
+ return ecma_bigint_negate (right_p);
+ }
+
+ ecma_ref_extended_primitive (right_p);
+ return right_value;
+ }
+
+ uint32_t sign = is_add ? 0 : ECMA_BIGINT_SIGN;
+
+ if (((left_p->u.bigint_sign_and_size ^ right_p->u.bigint_sign_and_size) & ECMA_BIGINT_SIGN) == sign)
+ {
+ ecma_extended_primitive_t *result_p = ecma_big_uint_add (left_p, right_p);
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return ecma_bigint_raise_memory_error ();
+ }
+
+ result_p->u.bigint_sign_and_size |= left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
+ return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
+ }
+
+ int compare_result = ecma_big_uint_compare (left_p, right_p);
+ ecma_extended_primitive_t *result_p;
+
+ if (compare_result == 0)
+ {
+ sign = 0;
+ result_p = ecma_bigint_create (0);
+ }
+ else if (compare_result > 0)
+ {
+ sign = left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
+ result_p = ecma_big_uint_sub (left_p, right_p);
+ }
+ else
+ {
+ sign = right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
+
+ if (!is_add)
+ {
+ sign ^= ECMA_BIGINT_SIGN;
+ }
+
+ result_p = ecma_big_uint_sub (right_p, left_p);
+ }
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return ecma_bigint_raise_memory_error ();
+ }
+
+ result_p->u.bigint_sign_and_size |= sign;
+ return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
+} /* ecma_bigint_add_sub */
+
+/**
+ * Multiply two BigInt values
+ *
+ * @return ecma BigInt value or ECMA_VALUE_ERROR
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_bigint_mul (ecma_value_t left_value, /**< left BigInt value */
+ ecma_value_t right_value) /**< right BigInt value */
+{
+ JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));
+
+ ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
+ ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);
+ uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_p);
+ uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_p);
+
+ if (left_size == 0)
+ {
+ ecma_ref_extended_primitive (left_p);
+ return left_value;
+ }
+
+ if (right_size == 0)
+ {
+ ecma_ref_extended_primitive (right_p);
+ return right_value;
+ }
+
+ if (left_size == sizeof (ecma_bigint_digit_t)
+ && ECMA_BIGINT_GET_LAST_DIGIT (left_p, sizeof (ecma_bigint_digit_t)) == 1)
+ {
+ if (left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
+ {
+ return ecma_bigint_negate (right_p);
+ }
+
+ ecma_ref_extended_primitive (right_p);
+ return right_value;
+ }
+
+ if (right_size == sizeof (ecma_bigint_digit_t)
+ && ECMA_BIGINT_GET_LAST_DIGIT (right_p, sizeof (ecma_bigint_digit_t)) == 1)
+ {
+ if (right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
+ {
+ return ecma_bigint_negate (left_p);
+ }
+
+ ecma_ref_extended_primitive (left_p);
+ return left_value;
+ }
+
+ ecma_extended_primitive_t *result_p = ecma_big_uint_mul (left_p, right_p);
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return ecma_bigint_raise_memory_error ();
+ }
+
+ uint32_t sign = (left_p->u.bigint_sign_and_size ^ right_p->u.bigint_sign_and_size) & ECMA_BIGINT_SIGN;
+ result_p->u.bigint_sign_and_size |= sign;
+ return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
+} /* ecma_bigint_mul */
+
+/**
+ * Divide two BigInt values
+ *
+ * @return ecma BigInt value or ECMA_VALUE_ERROR
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_bigint_div_mod (ecma_value_t left_value, /**< left BigInt value */
+ ecma_value_t right_value, /**< right BigInt value */
+ bool is_mod) /**< true if return with remainder */
+{
+ JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));
+
+ ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
+ ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);
+ uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_p);
+ uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_p);
+
+ if (right_size == 0)
+ {
+ return ecma_raise_range_error (ECMA_ERR_MSG ("BigInt division by zero"));
+ }
+
+ if (left_size == 0)
+ {
+ ecma_ref_extended_primitive (left_p);
+ return left_value;
+ }
+
+ int compare_result = ecma_big_uint_compare (left_p, right_p);
+ ecma_extended_primitive_t *result_p;
+
+ if (compare_result < 0)
+ {
+ if (is_mod)
+ {
+ ecma_ref_extended_primitive (left_p);
+ return left_value;
+ }
+ else
+ {
+ result_p = ecma_bigint_create (0);
+ }
+ }
+ else if (compare_result == 0)
+ {
+ if (is_mod)
+ {
+ result_p = ecma_bigint_create (0);
+ }
+ else
+ {
+ result_p = ecma_bigint_create (sizeof (ecma_bigint_digit_t));
+
+ if (result_p != NULL)
+ {
+ *ECMA_BIGINT_GET_DIGITS (result_p, 0) = 1;
+ }
+ }
+ }
+ else
+ {
+ result_p = ecma_big_uint_div_mod (left_p, right_p, is_mod);
+ }
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return ecma_bigint_raise_memory_error ();
+ }
+
+ if (ECMA_BIGINT_GET_SIZE (result_p) == 0)
+ {
+ return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
+ }
+
+ if (is_mod)
+ {
+ result_p->u.bigint_sign_and_size |= left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
+ }
+ else
+ {
+ uint32_t sign = (left_p->u.bigint_sign_and_size ^ right_p->u.bigint_sign_and_size) & ECMA_BIGINT_SIGN;
+ result_p->u.bigint_sign_and_size |= sign;
+ }
+
+ return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
+} /* ecma_bigint_div_mod */
+
+/**
+ * Shift left BigInt value to left or right
+ *
+ * @return ecma BigInt value or ECMA_VALUE_ERROR
+ * Returned value must be freed with ecma_free_value.
+ */
+ecma_value_t
+ecma_bigint_shift (ecma_value_t left_value, /**< left BigInt value */
+ ecma_value_t right_value, /**< right BigInt value */
+ bool is_left) /**< true if left shift operation should be performed */
+{
+ JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));
+
+ ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
+ ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);
+ uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_p);
+
+ if (right_size == 0 || ECMA_BIGINT_GET_SIZE (left_p) == 0)
+ {
+ ecma_ref_extended_primitive (left_p);
+ return left_value;
+ }
+
+ if (right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
+ {
+ is_left = !is_left;
+ }
+
+ if (right_size > sizeof (ecma_bigint_digit_t))
+ {
+ if (is_left)
+ {
+ return ecma_bigint_raise_memory_error ();
+ }
+
+ return ecma_make_extended_primitive_value (ecma_bigint_create (0), ECMA_TYPE_BIGINT);
+ }
+
+ ecma_extended_primitive_t *result_p;
+ ecma_bigint_digit_t shift = ECMA_BIGINT_GET_LAST_DIGIT (right_p, sizeof (ecma_bigint_digit_t));
+
+ if (is_left)
+ {
+ result_p = ecma_big_uint_shift_left (left_p, shift);
+ }
+ else
+ {
+ result_p = ecma_big_uint_shift_right (left_p, shift);
+ }
+
+ if (JERRY_UNLIKELY (result_p == NULL))
+ {
+ return ecma_bigint_raise_memory_error ();
+ }
+
+ result_p->u.bigint_sign_and_size |= left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
+ return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
+} /* ecma_bigint_shift */
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
diff --git a/jerry-core/ecma/operations/ecma-bigint.h b/jerry-core/ecma/operations/ecma-bigint.h
new file mode 100644
index 00000000..e88be173
--- /dev/null
+++ b/jerry-core/ecma/operations/ecma-bigint.h
@@ -0,0 +1,39 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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_BIG_INT_H
+#define ECMA_BIG_INT_H
+
+#include "ecma-globals.h"
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+
+/**
+ * Sign bit of a BigInt value. The number is negative, if this bit is set.
+ */
+#define ECMA_BIGINT_SIGN 0x1
+
+ecma_value_t ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, lit_utf8_size_t size);
+ecma_string_t *ecma_bigint_to_string (ecma_value_t value, ecma_bigint_digit_t radix);
+
+ecma_value_t ecma_bigint_negate (ecma_extended_primitive_t *value_p);
+ecma_value_t ecma_bigint_add_sub (ecma_value_t left_value, ecma_value_t right_value, bool is_add);
+ecma_value_t ecma_bigint_mul (ecma_value_t left_value, ecma_value_t right_value);
+ecma_value_t ecma_bigint_div_mod (ecma_value_t left_value, ecma_value_t right_value, bool is_mod);
+ecma_value_t ecma_bigint_shift (ecma_value_t left_value, ecma_value_t right_value, bool is_left);
+
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
+#endif /* ECMA_BIG_INT_H */
diff --git a/jerry-core/ecma/operations/ecma-conversion.c b/jerry-core/ecma/operations/ecma-conversion.c
index c3a3ee2f..f1aeb781 100644
--- a/jerry-core/ecma/operations/ecma-conversion.c
+++ b/jerry-core/ecma/operations/ecma-conversion.c
@@ -20,6 +20,8 @@
#include <math.h>
#include "ecma-alloc.h"
+#include "ecma-bigint.h"
+#include "ecma-bigint-object.h"
#include "ecma-boolean-object.h"
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
@@ -279,12 +281,6 @@ ecma_op_to_number (ecma_value_t value) /**< ecma value */
ecma_string_t *str_p = ecma_get_string_from_value (value);
return ecma_make_number_value (ecma_string_to_number (str_p));
}
-#if ENABLED (JERRY_ESNEXT)
- if (ecma_is_value_symbol (value))
- {
- return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a number."));
- }
-#endif /* ENABLED (JERRY_ESNEXT) */
if (ecma_is_value_undefined (value))
{
@@ -301,6 +297,20 @@ ecma_op_to_number (ecma_value_t value) /**< ecma value */
return ecma_make_integer_value (ecma_is_value_true (value) ? 1 : 0);
}
+#if ENABLED (JERRY_ESNEXT)
+ if (ecma_is_value_symbol (value))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a number"));
+ }
+#endif /* ENABLED (JERRY_ESNEXT) */
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ if (ecma_is_value_bigint (value))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a BigInt value to a number"));
+ }
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
JERRY_ASSERT (ecma_is_value_object (value));
ecma_object_t *obj_p = ecma_get_object_from_value (value);
@@ -364,13 +374,6 @@ ecma_get_number (ecma_value_t value, /**< ecma value*/
return ECMA_VALUE_EMPTY;
}
-#if ENABLED (JERRY_ESNEXT)
- if (ecma_is_value_symbol (value))
- {
- return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a number."));
- }
-#endif /* ENABLED (JERRY_ESNEXT) */
-
if (ecma_is_value_true (value))
{
*number_p = 1;
@@ -383,6 +386,20 @@ ecma_get_number (ecma_value_t value, /**< ecma value*/
return ECMA_VALUE_EMPTY;
}
+#if ENABLED (JERRY_ESNEXT)
+ if (ecma_is_value_symbol (value))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a number."));
+ }
+#endif /* ENABLED (JERRY_ESNEXT) */
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ if (ecma_is_value_bigint (value))
+ {
+ return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a BigInt value to a number"));
+ }
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
JERRY_ASSERT (ecma_is_value_object (value));
ecma_object_t *obj_p = ecma_get_object_from_value (value);
@@ -452,6 +469,16 @@ ecma_op_to_string (ecma_value_t value) /**< ecma value */
return ecma_get_magic_string (LIT_MAGIC_STRING_NULL);
}
+ if (ecma_is_value_true (value))
+ {
+ return ecma_get_magic_string (LIT_MAGIC_STRING_TRUE);
+ }
+
+ if (ecma_is_value_false (value))
+ {
+ return ecma_get_magic_string (LIT_MAGIC_STRING_FALSE);
+ }
+
#if ENABLED (JERRY_ESNEXT)
if (ecma_is_value_symbol (value))
{
@@ -460,15 +487,12 @@ ecma_op_to_string (ecma_value_t value) /**< ecma value */
}
#endif /* ENABLED (JERRY_ESNEXT) */
- if (ecma_is_value_true (value))
- {
- return ecma_get_magic_string (LIT_MAGIC_STRING_TRUE);
- }
-
- if (ecma_is_value_false (value))
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ if (ecma_is_value_bigint (value))
{
- return ecma_get_magic_string (LIT_MAGIC_STRING_FALSE);
+ return ecma_bigint_to_string (value, 10);
}
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
JERRY_ASSERT (ecma_is_value_object (value));
@@ -567,6 +591,12 @@ ecma_op_to_object (ecma_value_t value) /**< ecma value */
return ecma_op_create_symbol_object (value);
}
#endif /* ENABLED (JERRY_ESNEXT) */
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ else if (ecma_is_value_bigint (value))
+ {
+ return ecma_op_create_bigint_object (value);
+ }
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
else
{
if (ecma_is_value_undefined (value)
diff --git a/jerry-core/ecma/operations/ecma-get-put-value.c b/jerry-core/ecma/operations/ecma-get-put-value.c
index 36f1a580..1667184a 100644
--- a/jerry-core/ecma/operations/ecma-get-put-value.c
+++ b/jerry-core/ecma/operations/ecma-get-put-value.c
@@ -174,6 +174,12 @@ ecma_op_get_value_object_base (ecma_value_t base_value, /**< base value */
id = ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE;
}
#endif /* ENABLED (JERRY_ESNEXT) */
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ else if (ecma_is_value_bigint (base_value))
+ {
+ id = ECMA_BUILTIN_ID_BIGINT_PROTOTYPE;
+ }
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
else
{
JERRY_ASSERT (ecma_is_value_boolean (base_value));
diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c
index c270cb31..a8bac03c 100644
--- a/jerry-core/ecma/operations/ecma-objects.c
+++ b/jerry-core/ecma/operations/ecma-objects.c
@@ -2648,6 +2648,12 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */
return LIT_MAGIC_STRING_FUNCTION_UL;
}
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ case ECMA_BUILTIN_ID_BIGINT:
+ {
+ return LIT_MAGIC_STRING_FUNCTION_UL;
+ }
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
default:
{
JERRY_ASSERT (ecma_object_check_class_name_is_object (obj_p));
diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h
index 99075458..f88b0100 100644
--- a/jerry-core/include/jerryscript-core.h
+++ b/jerry-core/include/jerryscript-core.h
@@ -104,6 +104,7 @@ typedef enum
JERRY_FEATURE_SET, /**< Set support */
JERRY_FEATURE_WEAKMAP, /**< WeakMap support */
JERRY_FEATURE_WEAKSET, /**< WeakSet support */
+ JERRY_FEATURE_BIGINT, /**< BigInt support */
JERRY_FEATURE__COUNT /**< number of features. NOTE: must be at the end of the list */
} jerry_feature_t;
diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h
index 40bdab6f..e9893ec8 100644
--- a/jerry-core/lit/lit-magic-strings.inc.h
+++ b/jerry-core/lit/lit-magic-strings.inc.h
@@ -307,6 +307,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_VALUE, "value")
#if ENABLED (JERRY_PARSER)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RESOURCE_EVAL, "<eval>")
#endif
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BIGINT_UL, "BigInt")
+#endif
#if ENABLED (JERRY_BUILTIN_MATH)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LOG10E_U, "LOG10E")
#endif
@@ -318,6 +321,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_STRING_UL, "String")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL_UL, "Symbol")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASSIGN, "assign")
#endif
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BIGINT, "bigint")
+#endif
#if ENABLED (JERRY_BUILTIN_DATAVIEW) \
|| ENABLED (JERRY_BUILTIN_TYPEDARRAY)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BUFFER, "buffer")
@@ -981,6 +987,8 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (4, LIT_MAGIC_STRING_DATE_UL)
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (5, LIT_MAGIC_STRING_ARRAY_UL)
#if ENABLED (JERRY_PARSER)
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (6, LIT_MAGIC_STRING_RESOURCE_EVAL)
+#elif ENABLED (JERRY_BUILTIN_BIGINT)
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (6, LIT_MAGIC_STRING_BIGINT_UL)
#elif ENABLED (JERRY_BUILTIN_MATH)
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (6, LIT_MAGIC_STRING_LOG10E_U)
#else
diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini
index 6778a886..06964823 100644
--- a/jerry-core/lit/lit-magic-strings.ini
+++ b/jerry-core/lit/lit-magic-strings.ini
@@ -132,6 +132,7 @@ LIT_MAGIC_STRING_THROW = "throw"
LIT_MAGIC_STRING_TRUNC = "trunc"
LIT_MAGIC_STRING_VALUE = "value"
LIT_MAGIC_STRING_RESOURCE_EVAL = "<eval>"
+LIT_MAGIC_STRING_BIGINT_UL = "BigInt"
LIT_MAGIC_STRING_LOG10E_U = "LOG10E"
LIT_MAGIC_STRING_NUMBER_UL = "Number"
LIT_MAGIC_STRING_OBJECT_UL = "Object"
@@ -139,6 +140,7 @@ LIT_MAGIC_STRING_REGEXP_UL = "RegExp"
LIT_MAGIC_STRING_STRING_UL = "String"
LIT_MAGIC_STRING_SYMBOL_UL = "Symbol"
LIT_MAGIC_STRING_ASSIGN = "assign"
+LIT_MAGIC_STRING_BIGINT = "bigint"
LIT_MAGIC_STRING_BUFFER = "buffer"
LIT_MAGIC_STRING_CALLEE = "callee"
LIT_MAGIC_STRING_CALLER = "caller"
diff --git a/jerry-core/vm/opcodes-ecma-arithmetics.c b/jerry-core/vm/opcodes-ecma-arithmetics.c
index 89482a36..cb0ea169 100644
--- a/jerry-core/vm/opcodes-ecma-arithmetics.c
+++ b/jerry-core/vm/opcodes-ecma-arithmetics.c
@@ -14,7 +14,9 @@
*/
#include "ecma-alloc.h"
+#include "ecma-bigint.h"
#include "ecma-conversion.h"
+#include "ecma-exceptions.h"
#include "ecma-helpers.h"
#include "ecma-number-arithmetic.h"
#include "ecma-objects.h"
@@ -45,48 +47,128 @@ do_number_arithmetic (number_arithmetic_op op, /**< number arithmetic operation
ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
-
- ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
- ECMA_OP_TO_NUMBER_TRY_CATCH (num_right, right_value, ret_value);
-
- ecma_number_t result = ECMA_NUMBER_ZERO;
+ bool free_left_value = false;
+ bool free_right_value = false;
- switch (op)
+ if (ecma_is_value_object (left_value))
{
- case NUMBER_ARITHMETIC_SUBTRACTION:
- {
- result = num_left - num_right;
- break;
- }
- case NUMBER_ARITHMETIC_MULTIPLICATION:
+ ecma_object_t *obj_p = ecma_get_object_from_value (left_value);
+ left_value = ecma_op_object_default_value (obj_p, ECMA_PREFERRED_TYPE_NUMBER);
+ free_left_value = true;
+
+ if (ECMA_IS_VALUE_ERROR (left_value))
{
- result = num_left * num_right;
- break;
+ return left_value;
}
- case NUMBER_ARITHMETIC_DIVISION:
+ }
+
+ if (ecma_is_value_object (right_value))
+ {
+ ecma_object_t *obj_p = ecma_get_object_from_value (right_value);
+ right_value = ecma_op_object_default_value (obj_p, ECMA_PREFERRED_TYPE_NUMBER);
+ free_right_value = true;
+
+ if (ECMA_IS_VALUE_ERROR (right_value))
{
- result = num_left / num_right;
- break;
+ if (free_left_value)
+ {
+ ecma_free_value (left_value);
+ }
+ return right_value;
}
- case NUMBER_ARITHMETIC_REMAINDER:
+ }
+
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ if (JERRY_LIKELY (!ecma_is_value_bigint (left_value))
+ || JERRY_LIKELY (!ecma_is_value_bigint (right_value)))
+ {
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+ ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
+ ECMA_OP_TO_NUMBER_TRY_CATCH (num_right, right_value, ret_value);
+
+ ecma_number_t result = ECMA_NUMBER_ZERO;
+
+ switch (op)
{
- result = ecma_op_number_remainder (num_left, num_right);
- break;
- }
+ case NUMBER_ARITHMETIC_SUBTRACTION:
+ {
+ result = num_left - num_right;
+ break;
+ }
+ case NUMBER_ARITHMETIC_MULTIPLICATION:
+ {
+ result = num_left * num_right;
+ break;
+ }
+ case NUMBER_ARITHMETIC_DIVISION:
+ {
+ result = num_left / num_right;
+ break;
+ }
+ case NUMBER_ARITHMETIC_REMAINDER:
+ {
+ result = ecma_op_number_remainder (num_left, num_right);
+ break;
+ }
#if ENABLED (JERRY_ESNEXT)
- case NUMBER_ARITHMETIC_EXPONENTIATION:
+ case NUMBER_ARITHMETIC_EXPONENTIATION:
+ {
+ result = ecma_number_pow (num_left, num_right);
+ break;
+ }
+#endif /* ENABLED (JERRY_ESNEXT) */
+ }
+
+ ret_value = ecma_make_number_value (result);
+
+ ECMA_OP_TO_NUMBER_FINALIZE (num_right);
+ ECMA_OP_TO_NUMBER_FINALIZE (num_left);
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ }
+ else
+ {
+ switch (op)
{
- result = ecma_number_pow (num_left, num_right);
- break;
+ case NUMBER_ARITHMETIC_SUBTRACTION:
+ {
+ ret_value = ecma_bigint_add_sub (left_value, right_value, false);
+ break;
+ }
+ case NUMBER_ARITHMETIC_MULTIPLICATION:
+ {
+ ret_value = ecma_bigint_mul (left_value, right_value);
+ break;
+ }
+ case NUMBER_ARITHMETIC_DIVISION:
+ {
+ ret_value = ecma_bigint_div_mod (left_value, right_value, false);
+ break;
+ }
+ case NUMBER_ARITHMETIC_REMAINDER:
+ {
+ ret_value = ecma_bigint_div_mod (left_value, right_value, true);
+ break;
+ }
+ default:
+ {
+ ret_value = ecma_raise_common_error (ECMA_ERR_MSG ("Not supported BigInt operation"));
+ break;
+ }
}
-#endif /* ENABLED (JERRY_ESNEXT) */
}
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
- ret_value = ecma_make_number_value (result);
+ if (free_left_value)
+ {
+ ecma_free_value (left_value);
+ }
- ECMA_OP_TO_NUMBER_FINALIZE (num_right);
- ECMA_OP_TO_NUMBER_FINALIZE (num_left);
+ if (free_right_value)
+ {
+ ecma_free_value (right_value);
+ }
return ret_value;
} /* do_number_arithmetic */
@@ -175,6 +257,13 @@ opfunc_addition (ecma_value_t left_value, /**< left value */
ecma_deref_ecma_string (string2_p);
}
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ else if (JERRY_UNLIKELY (ecma_is_value_bigint (left_value))
+ && JERRY_UNLIKELY (ecma_is_value_bigint (right_value)))
+ {
+ ret_value = ecma_bigint_add_sub (left_value, right_value, true);
+ }
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
else
{
ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
@@ -211,15 +300,63 @@ ecma_value_t
opfunc_unary_operation (ecma_value_t left_value, /**< left value */
bool is_plus) /**< unary plus flag */
{
+ bool free_left_value = false;
+
+ if (ecma_is_value_object (left_value))
+ {
+ ecma_object_t *obj_p = ecma_get_object_from_value (left_value);
+ left_value = ecma_op_object_default_value (obj_p, ECMA_PREFERRED_TYPE_NUMBER);
+ free_left_value = true;
+
+ if (ECMA_IS_VALUE_ERROR (left_value))
+ {
+ return left_value;
+ }
+ }
+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
- ECMA_OP_TO_NUMBER_TRY_CATCH (num_var_value,
- left_value,
- ret_value);
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ if (JERRY_LIKELY (!ecma_is_value_bigint (left_value)))
+ {
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+ ECMA_OP_TO_NUMBER_TRY_CATCH (num_var_value,
+ left_value,
+ ret_value);
+
+ ret_value = ecma_make_number_value (is_plus ? num_var_value : -num_var_value);
- ret_value = ecma_make_number_value (is_plus ? num_var_value : -num_var_value);
+ ECMA_OP_TO_NUMBER_FINALIZE (num_var_value);
- ECMA_OP_TO_NUMBER_FINALIZE (num_var_value);
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ }
+ else
+ {
+ if (is_plus)
+ {
+ ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Unary operation plus is not allowed for BigInt numbers"));
+ }
+ else
+ {
+ ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
+
+ if (ECMA_BIGINT_GET_SIZE (left_p) == 0)
+ {
+ ecma_ref_extended_primitive (left_p);
+ ret_value = left_value;
+ }
+ else
+ {
+ ret_value = ecma_bigint_negate (left_p);
+ }
+ }
+ }
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+
+ if (free_left_value)
+ {
+ ecma_free_value (left_value);
+ }
return ret_value;
} /* opfunc_unary_operation */
diff --git a/jerry-core/vm/opcodes-ecma-bitwise.c b/jerry-core/vm/opcodes-ecma-bitwise.c
index ac328167..233f306c 100644
--- a/jerry-core/vm/opcodes-ecma-bitwise.c
+++ b/jerry-core/vm/opcodes-ecma-bitwise.c
@@ -14,8 +14,11 @@
*/
#include "ecma-alloc.h"
+#include "ecma-bigint.h"
#include "ecma-conversion.h"
+#include "ecma-exceptions.h"
#include "ecma-helpers.h"
+#include "ecma-objects.h"
#include "ecma-try-catch-macro.h"
#include "opcodes.h"
@@ -45,61 +48,131 @@ do_number_bitwise_logic (number_bitwise_logic_op op, /**< number bitwise logic o
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value)
&& !ECMA_IS_VALUE_ERROR (right_value));
- ecma_value_t ret_value = ECMA_VALUE_EMPTY;
-
- ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
- ECMA_OP_TO_NUMBER_TRY_CATCH (num_right, right_value, ret_value);
+ bool free_left_value = false;
+ bool free_right_value = false;
- ecma_number_t result = ECMA_NUMBER_ZERO;
- uint32_t right_uint32 = ecma_number_to_uint32 (num_right);
-
- switch (op)
+ if (ecma_is_value_object (left_value))
{
- case NUMBER_BITWISE_LOGIC_AND:
- {
- uint32_t left_uint32 = ecma_number_to_uint32 (num_left);
- result = (ecma_number_t) ((int32_t) (left_uint32 & right_uint32));
- break;
- }
- case NUMBER_BITWISE_LOGIC_OR:
- {
- uint32_t left_uint32 = ecma_number_to_uint32 (num_left);
- result = (ecma_number_t) ((int32_t) (left_uint32 | right_uint32));
- break;
- }
- case NUMBER_BITWISE_LOGIC_XOR:
- {
- uint32_t left_uint32 = ecma_number_to_uint32 (num_left);
- result = (ecma_number_t) ((int32_t) (left_uint32 ^ right_uint32));
- break;
- }
- case NUMBER_BITWISE_SHIFT_LEFT:
+ ecma_object_t *obj_p = ecma_get_object_from_value (left_value);
+ left_value = ecma_op_object_default_value (obj_p, ECMA_PREFERRED_TYPE_NUMBER);
+ free_left_value = true;
+
+ if (ECMA_IS_VALUE_ERROR (left_value))
{
- result = (ecma_number_t) (ecma_number_to_int32 (num_left) << (right_uint32 & 0x1F));
- break;
+ return left_value;
}
- case NUMBER_BITWISE_SHIFT_RIGHT:
+ }
+
+ if (ecma_is_value_object (right_value))
+ {
+ ecma_object_t *obj_p = ecma_get_object_from_value (right_value);
+ right_value = ecma_op_object_default_value (obj_p, ECMA_PREFERRED_TYPE_NUMBER);
+ free_right_value = true;
+
+ if (ECMA_IS_VALUE_ERROR (right_value))
{
- result = (ecma_number_t) (ecma_number_to_int32 (num_left) >> (right_uint32 & 0x1F));
- break;
+ if (free_left_value)
+ {
+ ecma_free_value (left_value);
+ }
+ return right_value;
}
- case NUMBER_BITWISE_SHIFT_URIGHT:
+ }
+
+ ecma_value_t ret_value = ECMA_VALUE_EMPTY;
+
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ if (JERRY_LIKELY (!ecma_is_value_bigint (left_value))
+ || JERRY_LIKELY (!ecma_is_value_bigint (right_value)))
+ {
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
+ ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
+ ECMA_OP_TO_NUMBER_TRY_CATCH (num_right, right_value, ret_value);
+
+ ecma_number_t result = ECMA_NUMBER_ZERO;
+ uint32_t right_uint32 = ecma_number_to_uint32 (num_right);
+
+ switch (op)
{
- uint32_t left_uint32 = ecma_number_to_uint32 (num_left);
- result = (ecma_number_t) (left_uint32 >> (right_uint32 & 0x1F));
- break;
+ case NUMBER_BITWISE_LOGIC_AND:
+ {
+ uint32_t left_uint32 = ecma_number_to_uint32 (num_left);
+ result = (ecma_number_t) ((int32_t) (left_uint32 & right_uint32));
+ break;
+ }
+ case NUMBER_BITWISE_LOGIC_OR:
+ {
+ uint32_t left_uint32 = ecma_number_to_uint32 (num_left);
+ result = (ecma_number_t) ((int32_t) (left_uint32 | right_uint32));
+ break;
+ }
+ case NUMBER_BITWISE_LOGIC_XOR:
+ {
+ uint32_t left_uint32 = ecma_number_to_uint32 (num_left);
+ result = (ecma_number_t) ((int32_t) (left_uint32 ^ right_uint32));
+ break;
+ }
+ case NUMBER_BITWISE_SHIFT_LEFT:
+ {
+ result = (ecma_number_t) (ecma_number_to_int32 (num_left) << (right_uint32 & 0x1F));
+ break;
+ }
+ case NUMBER_BITWISE_SHIFT_RIGHT:
+ {
+ result = (ecma_number_t) (ecma_number_to_int32 (num_left) >> (right_uint32 & 0x1F));
+ break;
+ }
+ case NUMBER_BITWISE_SHIFT_URIGHT:
+ {
+ uint32_t left_uint32 = ecma_number_to_uint32 (num_left);
+ result = (ecma_number_t) (left_uint32 >> (right_uint32 & 0x1F));
+ break;
+ }
+ case NUMBER_BITWISE_NOT:
+ {
+ result = (ecma_number_t) ((int32_t) ~right_uint32);
+ break;
+ }
}
- case NUMBER_BITWISE_NOT:
+
+ ret_value = ecma_make_number_value (result);
+
+ ECMA_OP_TO_NUMBER_FINALIZE (num_right);
+ ECMA_OP_TO_NUMBER_FINALIZE (num_left);
+#if ENABLED (JERRY_BUILTIN_BIGINT)
+ }
+ else
+ {
+ switch (op)
{
- result = (ecma_number_t) ((int32_t) ~right_uint32);
- break;
+ case NUMBER_BITWISE_SHIFT_LEFT:
+ {
+ ret_value = ecma_bigint_shift (left_value, right_value, true);
+ break;
+ }
+ case NUMBER_BITWISE_SHIFT_RIGHT:
+ {
+ ret_value = ecma_bigint_shift (left_value, right_value, false);
+ break;
+ }
+ default:
+ {
+ ret_value = ecma_raise_common_error (ECMA_ERR_MSG ("Not supported BigInt operation"));
+ break;
+ }
}
}
+#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
- ret_value = ecma_make_number_value (result);
+ if (free_left_value)
+ {
+ ecma_free_value (left_value);
+ }
- ECMA_OP_TO_NUMBER_FINALIZE (num_right);
- ECMA_OP_TO_NUMBER_FINALIZE (num_left);
+ if (free_right_value)
+ {
+ ecma_free_value (right_value);
+ }
return ret_value;
} /* do_number_bitwise_logic */
diff --git a/tests/jerry/es.next/bigint1.js b/tests/jerry/es.next/bigint1.js
new file mode 100644
index 00000000..47f24cad
--- /dev/null
+++ b/tests/jerry/es.next/bigint1.js
@@ -0,0 +1,237 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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.
+ */
+
+function check_result(bigint, expected)
+{
+ assert(bigint.toString() === expected)
+}
+
+function check_result16(bigint, expected)
+{
+ assert(bigint.toString(16) === expected)
+}
+
+function check_syntax_error(code)
+{
+ try {
+ eval(code)
+ assert(false)
+ } catch (e) {
+ assert(e instanceof SyntaxError)
+ }
+}
+
+assert(typeof BigInt("0") == "bigint")
+
+// Test BigInt string parsing and toString
+
+check_syntax_error("BigInt('-0x5')");
+check_syntax_error("BigInt('-')");
+check_syntax_error("BigInt('00x5')");
+check_syntax_error("BigInt('11a')");
+check_syntax_error("BigInt('0b2')");
+check_syntax_error("BigInt('1n')");
+
+check_result(BigInt("0"), "0")
+check_result(BigInt("-0"), "0")
+check_result(BigInt("100000000000000000000000000000000000000"), "100000000000000000000000000000000000000")
+check_result(BigInt("-1234567890123456789012345678901234567890"), "-1234567890123456789012345678901234567890")
+check_result(BigInt("+1"), "1")
+check_result(BigInt("+000000000000000000001"), "1")
+check_result(BigInt("-000000000000000000000"), "0")
+check_result(BigInt("0x00abcdefABCDEF0123456789000000000000000"), "239460437713606077082343926293727858623774720")
+check_result(BigInt("0b00100000000000010000000000010000000000010"), "274911469570")
+
+assert(BigInt("100000000000000000000000000000000000000").toString(22) === "2ci67fiek1bkhec5fig7aiii9hf8c")
+check_result16(BigInt("239460437713606077082343926293727858623774720"), "abcdefabcdef0123456789000000000000000")
+
+// Test negate
+
+check_result(-BigInt("0"), "0")
+check_result(-BigInt("100"), "-100")
+check_result(-BigInt("-100"), "100")
+check_result(-BigInt("100000000000000000000000000000000000000000000"), "-100000000000000000000000000000000000000000000")
+check_result(-BigInt("-100000000000000000000000000000000000000000000"), "100000000000000000000000000000000000000000000")
+
+// Test addition
+
+check_result(BigInt("0") + BigInt("0"), "0")
+check_result(BigInt("1") + BigInt("1"), "2")
+check_result(BigInt("0") + BigInt("100"), "100")
+check_result(BigInt("0") + BigInt("-100"), "-100")
+check_result(BigInt("100") + BigInt("0"), "100")
+check_result(BigInt("-100") + BigInt("0"), "-100")
+
+check_result(BigInt("100000000000000000000000000000000000000") + BigInt("100000000000000000000000000000000000000"),
+ "200000000000000000000000000000000000000");
+check_result(BigInt("-100000000000000000000000000000000000000") + BigInt("-100000000000000000000000000000000000000"),
+ "-200000000000000000000000000000000000000");
+check_result(BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3") + BigInt("0xd"),
+ "115792089237316195423570985008687907853269984665640564039457584007913129639936");
+check_result(BigInt("0xd") + BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3"),
+ "115792089237316195423570985008687907853269984665640564039457584007913129639936");
+
+check_result(BigInt("100000000000000000000000000000000000000") + BigInt("-100000000000000000000000000000000000000"), "0")
+check_result(BigInt("100000000000000000000000000000000000001") + BigInt("-100000000000000000000000000000000000000"), "1")
+check_result(BigInt("100000000000000000000000000000000000000") + BigInt("-100000000000000000000000000000000000001"), "-1")
+check_result(BigInt("-100000000000000000000000000000000000000") + BigInt("100000000000000000000000000000000000000"), "0")
+check_result(BigInt("-100000000000000000000000000000000000001") + BigInt("100000000000000000000000000000000000000"), "-1")
+check_result(BigInt("-100000000000000000000000000000000000000") + BigInt("100000000000000000000000000000000000001"), "1")
+
+// Test substraction
+
+check_result(BigInt("0") - BigInt("0"), "0")
+check_result(BigInt("2") - BigInt("1"), "1")
+check_result(BigInt("0") - BigInt("100"), "-100")
+check_result(BigInt("0") - BigInt("-100"), "100")
+check_result(BigInt("100") - BigInt("0"), "100")
+check_result(BigInt("-100") - BigInt("0"), "-100")
+
+check_result(BigInt("100000000000000000000000000000000000000") - BigInt("-100000000000000000000000000000000000000"),
+ "200000000000000000000000000000000000000");
+check_result(BigInt("-100000000000000000000000000000000000000") - BigInt("100000000000000000000000000000000000000"),
+ "-200000000000000000000000000000000000000");
+check_result(BigInt("100000000000000000000000000000000000000") - BigInt("-1"),
+ "100000000000000000000000000000000000001");
+check_result(BigInt("-100000000000000000000000000000000000000") - BigInt("1"),
+ "-100000000000000000000000000000000000001");
+check_result(BigInt("1") - BigInt("-100000000000000000000000000000000000000"),
+ "100000000000000000000000000000000000001");
+check_result(BigInt("-1") - BigInt("100000000000000000000000000000000000000"),
+ "-100000000000000000000000000000000000001");
+
+check_result(BigInt("100000000000000000000000000000000000000") - BigInt("100000000000000000000000000000000000000"), "0")
+check_result(BigInt("100000000000000000000000000000000000001") - BigInt("100000000000000000000000000000000000000"), "1")
+check_result(BigInt("100000000000000000000000000000000000000") - BigInt("100000000000000000000000000000000000001"), "-1")
+check_result(BigInt("-100000000000000000000000000000000000000") - BigInt("-100000000000000000000000000000000000000"), "0")
+check_result(BigInt("-100000000000000000000000000000000000001") - BigInt("-100000000000000000000000000000000000000"), "-1")
+check_result(BigInt("-100000000000000000000000000000000000000") - BigInt("-100000000000000000000000000000000000001"), "1")
+
+// Test multiplication
+
+check_result(BigInt("0") * BigInt("0"), "0")
+check_result(BigInt("1000") * BigInt("0"), "0")
+check_result(BigInt("0") * BigInt("1000"), "0")
+check_result(BigInt("1") * BigInt("100000000000000000000000000000000000000"), "100000000000000000000000000000000000000")
+check_result(BigInt("1") * BigInt("-100000000000000000000000000000000000000"), "-100000000000000000000000000000000000000")
+check_result(BigInt("-1") * BigInt("100000000000000000000000000000000000000"), "-100000000000000000000000000000000000000")
+check_result(BigInt("-1") * BigInt("-100000000000000000000000000000000000000"), "100000000000000000000000000000000000000")
+check_result(BigInt("100000000000000000000000000000000000000") * BigInt("1"), "100000000000000000000000000000000000000")
+check_result(BigInt("-100000000000000000000000000000000000000") * BigInt("1"), "-100000000000000000000000000000000000000")
+check_result(BigInt("100000000000000000000000000000000000000") * BigInt("-1"), "-100000000000000000000000000000000000000")
+check_result(BigInt("-100000000000000000000000000000000000000") * BigInt("-1"), "100000000000000000000000000000000000000")
+
+check_result(BigInt("100000000000000000000000000000000000000") * BigInt("100000000000000000000000000000000000000"),
+ "10000000000000000000000000000000000000000000000000000000000000000000000000000")
+check_result(BigInt("100000000000000000000000000000000000000") * BigInt("-100000000000000000000000000000000000000"),
+ "-10000000000000000000000000000000000000000000000000000000000000000000000000000")
+check_result(BigInt("-100000000000000000000000000000000000000") * BigInt("100000000000000000000000000000000000000"),
+ "-10000000000000000000000000000000000000000000000000000000000000000000000000000")
+check_result(BigInt("-100000000000000000000000000000000000000") * BigInt("-100000000000000000000000000000000000000"),
+ "10000000000000000000000000000000000000000000000000000000000000000000000000000")
+
+// Test divide
+
+try {
+ BigInt("32") / BigInt("0")
+ assert(false)
+} catch (e) {
+ assert(e instanceof RangeError)
+}
+
+try {
+ BigInt("32") % BigInt("0")
+ assert(false)
+} catch (e) {
+ assert(e instanceof RangeError)
+}
+
+check_result(BigInt("0") / BigInt("1234"), "0")
+check_result(BigInt("0") % BigInt("1234"), "0")
+
+check_result(BigInt("100") / BigInt("70"), "1")
+check_result(BigInt("100") % BigInt("70"), "30")
+check_result(BigInt("-100") / BigInt("70"), "-1")
+check_result(BigInt("-100") % BigInt("70"), "-30")
+check_result(BigInt("100") / BigInt("-70"), "-1")
+check_result(BigInt("100") % BigInt("-70"), "30")
+check_result(BigInt("-100") / BigInt("-70"), "1")
+check_result(BigInt("-100") % BigInt("-70"), "-30")
+
+check_result(BigInt("100") / BigInt("100"), "1")
+check_result(BigInt("100") % BigInt("100"), "0")
+check_result(BigInt("-100") / BigInt("100"), "-1")
+check_result(BigInt("-100") % BigInt("100"), "0")
+check_result(BigInt("100") / BigInt("-100"), "-1")
+check_result(BigInt("100") % BigInt("-100"), "0")
+check_result(BigInt("-100") / BigInt("-100"), "1")
+check_result(BigInt("-100") % BigInt("-100"), "0")
+
+/* Division by small value. */
+check_result(BigInt("100000000000000000000") / BigInt("1000000"), "100000000000000")
+check_result(BigInt("100000000000000000000") % BigInt("1000000"), "0")
+check_result(BigInt("12345678901234567890") / BigInt("1000000"), "12345678901234")
+check_result(BigInt("12345678901234567890") % BigInt("1000000"), "567890")
+
+/* Division by large value. */
+check_result(BigInt("100000000000000000000") / BigInt("100000000000000000"), "1000")
+check_result(BigInt("100000000000000000000") % BigInt("100000000000000000"), "0")
+check_result(BigInt("12345678901234567890123456789012345678901234567890123456789012345678901234567890") / BigInt("10000000000000000000000000000000000000"),
+ "1234567890123456789012345678901234567890123")
+check_result(BigInt("12345678901234567890123456789012345678901234567890123456789012345678901234567890") % BigInt("10000000000000000000000000000000000000"),
+ "4567890123456789012345678901234567890")
+check_result16(BigInt("0xffffffffffffffffffffffff") / BigInt("0x100000000"), "ffffffffffffffff")
+check_result16(BigInt("0xffffffffffffffffffffffff") % BigInt("0x100000000"), "ffffffff")
+
+/* Triggers a corner case. */
+check_result(BigInt("170141183420855150493001878992821682176") / BigInt("39614081266355540842216685573"), "4294967293")
+check_result(BigInt("170141183420855150493001878992821682176") % BigInt("39614081266355540842216685573"), "39614081266355540837921718287")
+
+// Test shift
+
+check_result(BigInt("0") << BigInt("10000000"), "0")
+check_result(BigInt("0") >> BigInt("10000000"), "0")
+check_result(BigInt("10000000") << BigInt("0"), "10000000")
+check_result(BigInt("10000000") >> BigInt("0"), "10000000")
+
+check_result(BigInt("4096") << BigInt("2"), "16384")
+check_result(BigInt("4096") << BigInt("-2"), "1024")
+check_result(BigInt("4096") >> BigInt("2"), "1024")
+check_result(BigInt("4096") >> BigInt("-2"), "16384")
+
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") << BigInt("1"), "11fdebf9fffdebf9fffdebf9fffdebf9fe")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") << BigInt("19"), "47f7afe7fff7afe7fff7afe7fff7afe7f80000")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") << BigInt("31"), "47f7afe7fff7afe7fff7afe7fff7afe7f80000000")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") << BigInt("32"), "8fef5fcfffef5fcfffef5fcfffef5fcff00000000")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") << BigInt("51"), "47f7afe7fff7afe7fff7afe7fff7afe7f8000000000000")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") << BigInt("63"), "47f7afe7fff7afe7fff7afe7fff7afe7f8000000000000000")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") << BigInt("64"), "8fef5fcfffef5fcfffef5fcfffef5fcff0000000000000000")
+
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("1"), "47f7afe7fff7afe7fff7afe7fff7afe7f")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("19"), "11fdebf9fffdebf9fffdebf9fffde")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("31"), "11fdebf9fffdebf9fffdebf9ff")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("32"), "8fef5fcfffef5fcfffef5fcff")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("51"), "11fdebf9fffdebf9fffde")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("63"), "11fdebf9fffdebf9ff")
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("64"), "8fef5fcfffef5fcff")
+
+check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("10000000000000000000000000"), "0")
+
+try {
+ BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") << BigInt("10000000000000000000000000");
+ assert(false)
+} catch (e) {
+ assert(e instanceof RangeError)
+}
diff --git a/tests/jerry/es.next/bigint2.js b/tests/jerry/es.next/bigint2.js
new file mode 100644
index 00000000..9b4e9cf1
--- /dev/null
+++ b/tests/jerry/es.next/bigint2.js
@@ -0,0 +1,61 @@
+/* Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * 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.
+ */
+
+try {
+ new BigInt("1")
+ assert(false)
+} catch (e) {
+ assert(e instanceof TypeError)
+}
+
+function check_type_error (code)
+{
+ try {
+ eval(code)
+ assert(false)
+ } catch (e) {
+ assert(e instanceof TypeError)
+ }
+}
+
+check_type_error("+BigInt('0')")
+
+check_type_error("BigInt('1') + 1")
+check_type_error("BigInt('2') - 2")
+check_type_error("BigInt('3') * 3")
+check_type_error("BigInt('4') / 4")
+check_type_error("BigInt('5') % 5")
+check_type_error("BigInt('6') ** 6")
+
+check_type_error("1 + BigInt('1')")
+check_type_error("2 - BigInt('2')")
+check_type_error("3 * BigInt('3')")
+check_type_error("4 / BigInt('4')")
+check_type_error("5 % BigInt('5')")
+check_type_error("6 ** BigInt('6')")
+
+check_type_error("BigInt('1') & 1")
+check_type_error("BigInt('2') | 2")
+check_type_error("BigInt('3') ^ 3")
+check_type_error("BigInt('4') << 4")
+check_type_error("BigInt('5') >> 5")
+check_type_error("BigInt('6') >>> 6")
+
+check_type_error("1 & BigInt('1')")
+check_type_error("2 | BigInt('2')")
+check_type_error("3 ^ BigInt('3')")
+check_type_error("4 << BigInt('4')")
+check_type_error("5 >> BigInt('5')")
+check_type_error("6 >>> BigInt('6')")