Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement operations of atomics #4956

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 14 additions & 16 deletions jerry-core/ecma/base/ecma-error-messages.inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,10 +257,11 @@ ECMA_ERROR_DEF (ECMA_ERR_UNSUPPORTED_BINARY_OPERATION, "Unsupported binary opera
#if JERRY_BUILTIN_REGEXP
ECMA_ERROR_DEF (ECMA_ERR_UNTERMINATED_CHARACTER_CLASS, "Unterminated character class")
#endif /* JERRY_BUILTIN_REGEXP */
#if JERRY_BUILTIN_DATAVIEW || JERRY_BUILTIN_TYPEDARRAY || JERRY_ESNEXT
#if JERRY_BUILTIN_ATOMICS || JERRY_BUILTIN_DATAVIEW || JERRY_BUILTIN_TYPEDARRAY || JERRY_ESNEXT
ECMA_ERROR_DEF (ECMA_ERR_ARRAYBUFFER_IS_DETACHED, "ArrayBuffer has been detached")
#endif /* JERRY_BUILTIN_DATAVIEW \
|| JERRY_BUILTIN_TYPEDARRAY \
#endif /* JERRY_BUILTIN_ATOMICS \
|| JERRY_BUILTIN_DATAVIEW \
|| JERRY_BUILTIN_TYPEDARRAY \
|| JERRY_ESNEXT */
#if JERRY_ESNEXT
ECMA_ERROR_DEF (ECMA_ERR_CONSTRUCTOR_NOT_AN_OBJECT, "Constructor must be an object")
Expand Down Expand Up @@ -290,9 +291,10 @@ ECMA_ERROR_DEF (ECMA_ERR_MODULE_CANNOT_BE_INSTANTIATED, "Module cannot be instan
ECMA_ERROR_DEF (ECMA_ERR_SPECIES_MUST_BE_A_CONSTRUCTOR, "Species must be a constructor")
#endif /* JERRY_ESNEXT */
ECMA_ERROR_DEF (ECMA_ERR_ARGUMENT_IS_NOT_A_PROXY, "Argument is not a Proxy object")
#if JERRY_BUILTIN_TYPEDARRAY
#if JERRY_BUILTIN_ATOMICS || JERRY_BUILTIN_TYPEDARRAY
ECMA_ERROR_DEF (ECMA_ERR_ARGUMENT_NOT_ARRAY_BUFFER, "Argument is not an ArrayBuffer")
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#endif /* JERRY_BUILTIN_ATOMICS \
|| JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_BUILTIN_CONTAINER
ECMA_ERROR_DEF (ECMA_ERR_CONSTRUCTOR_MAP_REQUIRES_NEW, "Constructor Map requires 'new'")
ECMA_ERROR_DEF (ECMA_ERR_CONSTRUCTOR_SET_REQUIRES_NEW, "Constructor Set requires 'new'")
Expand Down Expand Up @@ -383,9 +385,6 @@ ECMA_ERROR_DEF (ECMA_ERR_STATIC_SNAPSHOTS_ARE_NOT_ENABLED, "Static snapshots are
ECMA_ERROR_DEF (ECMA_ERR_WEAKREF_TARGET_MUST_BE_AN_OBJECT, "WeakRef target must be an object")
#endif /* JERRY_BUILTIN_WEAKREF */
ECMA_ERROR_DEF (ECMA_ERR_ARGUMENT_THIS_NOT_FUNCTION, "Argument 'this' is not a function")
#if JERRY_BUILTIN_ATOMICS
ECMA_ERROR_DEF (ECMA_ERR_ARGUMENT_NOT_SHARED_ARRAY_BUFFER, "Argument is not SharedArrayBuffer")
#endif /* JERRY_BUILTIN_ATOMICS */
#if JERRY_BUILTIN_ARRAY || JERRY_BUILTIN_CONTAINER || JERRY_BUILTIN_TYPEDARRAY
ECMA_ERROR_DEF (ECMA_ERR_CALLBACK_IS_NOT_CALLABLE, "Callback function is not callable")
#endif /* JERRY_BUILTIN_ARRAY \
Expand Down Expand Up @@ -434,9 +433,10 @@ ECMA_ERROR_DEF (ECMA_ERR_MAXIMUM_TYPEDARRAY_SIZE_IS_REACHED, "Maximum TypedArray
ECMA_ERROR_DEF (ECMA_ERR_THE_GIVEN_ARGUMENT_IS_NOT_A_SYMBOL, "The given argument is not a Symbol")
ECMA_ERROR_DEF (ECMA_ERR_PARAMETER_REJECT_MUST_BE_CALLABLE, "'reject' parameter must be callable")
#endif /* JERRY_ESNEXT */
#if JERRY_BUILTIN_TYPEDARRAY || JERRY_ESNEXT
#if JERRY_BUILTIN_ATOMICS || JERRY_BUILTIN_TYPEDARRAY || JERRY_ESNEXT
ECMA_ERROR_DEF (ECMA_ERR_ARGUMENT_THIS_NOT_TYPED_ARRAY, "Argument 'this' is not a TypedArray")
#endif /* JERRY_BUILTIN_TYPEDARRAY \
#endif /* JERRY_BUILTIN_ATOMICS \
|| JERRY_BUILTIN_TYPEDARRAY \
|| JERRY_ESNEXT */
#if JERRY_SNAPSHOT_SAVE
ECMA_ERROR_DEF (ECMA_ERR_CANNOT_ALLOCATE_MEMORY_LITERALS, "Cannot allocate memory for literals")
Expand Down Expand Up @@ -547,11 +547,6 @@ ECMA_ERROR_DEF (ECMA_ERR_CONSTRUCTOR_UINT32_ARRAY_REQUIRES_NEW, "Constructor Uin
#if JERRY_ESNEXT
ECMA_ERROR_DEF (ECMA_ERR_GENERATOR_IS_CURRENTLY_UNDER_EXECUTION, "Generator is currently under execution")
ECMA_ERROR_DEF (ECMA_ERR_ITERATOR_RETURN_RESULT_IS_NOT_OBJECT, "Iterator 'return' result is not object")
#endif /* JERRY_ESNEXT */
#if JERRY_BUILTIN_TYPEDARRAY
ECMA_ERROR_DEF (ECMA_ERR_RETURNED_ARRAYBUFFER_HAS_BEEN_DETACHED, "Returned ArrayBuffer has been detached")
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_ESNEXT
ECMA_ERROR_DEF (ECMA_ERR_SEARCH_STRING_CANNOT_BE_OF_TYPE_REGEXP, "Search string can't be of type: RegExp")
ECMA_ERROR_DEF (ECMA_ERR_VALUE_RECEIVED_BY_YIELD_IS_NOT_OBJECT, "Value received by yield* is not object")
#endif /* JERRY_ESNEXT */
Expand Down Expand Up @@ -595,8 +590,11 @@ ECMA_ERROR_DEF (ECMA_ERR_ARGUMENT_THIS_NOT_GENERATOR_OBJECT, "Argument 'this' is
ECMA_ERROR_DEF (ECMA_ERR_ARGUMENT_CANNOT_CONVERT_TO_OBJECT, "Argument cannot be converted to an object")
#if JERRY_BUILTIN_BIGINT
ECMA_ERROR_DEF (ECMA_ERR_ALLOCATE_BIGINT_VALUE, "Cannot allocate memory for a BigInt value")
ECMA_ERROR_DEF (ECMA_ERR_CONVERT_BIGINT_TO_NUMBER, "Cannot convert a BigInt value to a number")
#endif /* JERRY_BUILTIN_BIGINT */
#if JERRY_BUILTIN_ATOMICS || JERRY_BUILTIN_BIGINT
ECMA_ERROR_DEF (ECMA_ERR_CONVERT_BIGINT_TO_NUMBER, "Cannot convert a BigInt value to a number")
#endif /* JERRY_BUILTIN_ATOMICS \
|| JERRY_BUILTIN_BIGINT */
#if JERRY_ESNEXT
ECMA_ERROR_DEF (ECMA_ERR_CONVERT_SYMBOL_TO_NUMBER, "Cannot convert a Symbol value to a number")
ECMA_ERROR_DEF (ECMA_ERR_CONVERT_SYMBOL_TO_STRING, "Cannot convert a Symbol value to a string")
Expand Down
2 changes: 0 additions & 2 deletions jerry-core/ecma/base/ecma-error-messages.ini
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ ECMA_ERR_ARGUMENT_THIS_NOT_ITERATOR = "Argument 'this' is not an iterator"
ECMA_ERR_ARGUMENT_THIS_NOT_OBJECT = "Argument 'this' is not an object"
ECMA_ERR_ARGUMENT_THIS_NOT_SYMBOL = "Argument 'this' must be a Symbol"
ECMA_ERR_ARGUMENT_CANNOT_CONVERT_TO_OBJECT = "Argument cannot be converted to an object"
ECMA_ERR_ARGUMENT_NOT_SHARED_ARRAY_BUFFER = "Argument is not SharedArrayBuffer"
ECMA_ERR_ARGUMENT_NOT_ARRAY_BUFFER = "Argument is not an ArrayBuffer"
ECMA_ERR_ARGUMENT_NOT_SUPPORTED = "Argument is not supported"
ECMA_ERR_ARRAY_BUFFER_DETACHED = "ArrayBuffer has already been detached"
Expand Down Expand Up @@ -213,7 +212,6 @@ ECMA_ERR_RESOLVE_MUST_BE_UNDEFINED = "Resolve must be undefined"
ECMA_ERR_RESULT_OF_DEFAULTVALUE_IS_INVALID = "Result of [[DefaultValue]] is invalid"
ECMA_ERR_RETURN_VALUE_IS_NOT_AN_ARRAYBUFFER_OBJECT = "Return value is not an ArrayBuffer object"
ECMA_ERR_RETURN_VALUE_OF_EXEC_MUST_BE_AN_OBJECT_OR_NULL = "Return value of 'exec' must be an object or null"
ECMA_ERR_RETURNED_ARRAYBUFFER_HAS_BEEN_DETACHED = "Returned ArrayBuffer has been detached"
ECMA_ERR_RIGHT_VALUE_OF_IN_MUST_BE_AN_OBJECT = "Right value of 'in' must be an object"
ECMA_ERR_RIGHT_VALUE_OF_INSTANCEOF_MUST_BE_AN_OBJECT = "Right value of 'instanceof' must be an object"
ECMA_ERR_SEARCH_STRING_CANNOT_BE_OF_TYPE_REGEXP = "Search string can't be of type: RegExp"
Expand Down
246 changes: 236 additions & 10 deletions jerry-core/ecma/builtin-objects/ecma-builtin-atomics.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,17 @@
* limitations under the License.
*/

#include "ecma-arraybuffer-object.h"
#include "ecma-atomics-object.h"
#include "ecma-bigint.h"
#include "ecma-builtins.h"
#include "ecma-errors.h"
#include "ecma-exceptions.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-shared-arraybuffer-object.h"
#include "ecma-typedarray-object.h"

#include "jrt.h"

Expand Down Expand Up @@ -66,10 +73,50 @@ enum
* @{
*/

/**
* Convert ecma_number to the appropriate type according to the element type of typedarray.
*/
static ecma_value_t
ecma_convert_number_to_typed_array_type (ecma_number_t num, /**< ecma_number argument */
ecma_typedarray_type_t element_type) /**< element type of typedarray */
{
uint32_t value = ecma_typedarray_setter_number_to_uint32 (num);

switch (element_type)
{
case ECMA_INT8_ARRAY:
{
return ecma_make_number_value ((int8_t) value);
}
case ECMA_UINT8_ARRAY:
{
return ecma_make_number_value ((uint8_t) value);
}
case ECMA_INT16_ARRAY:
{
return ecma_make_number_value ((int16_t) value);
}
case ECMA_UINT16_ARRAY:
{
return ecma_make_number_value ((uint16_t) value);
}
case ECMA_INT32_ARRAY:
{
return ecma_make_number_value ((int32_t) value);
}
default:
{
JERRY_ASSERT (element_type == ECMA_UINT32_ARRAY);

return ecma_make_number_value (value);
}
}
} /* ecma_convert_number_to_typed_array_type */

/**
* The Atomics object's 'compareExchange' routine
*
* See also: ES11 24.4.4
* See also: ES12 25.4.4
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
Expand All @@ -80,12 +127,122 @@ ecma_builtin_atomics_compare_exchange (ecma_value_t typedarray, /**< typedArray
ecma_value_t expected_value, /**< expectedValue argument */
ecma_value_t replacement_value) /**< replacementValue argument*/
{
JERRY_UNUSED (typedarray);
JERRY_UNUSED (index);
JERRY_UNUSED (expected_value);
JERRY_UNUSED (replacement_value);
ecma_value_t buffer = ecma_validate_integer_typedarray (typedarray, false);

return ecma_make_uint32_value (0);
if (ECMA_IS_VALUE_ERROR (buffer))
{
return buffer;
}

uint32_t idx = ecma_validate_atomic_access (typedarray, index);

if (idx == ECMA_STRING_NOT_ARRAY_INDEX)
{
return ECMA_VALUE_ERROR;
}

ecma_object_t *typedarray_p = ecma_get_object_from_value (typedarray);
ecma_typedarray_info_t target_info = ecma_typedarray_get_info (typedarray_p);

if (ECMA_ARRAYBUFFER_LAZY_ALLOC (target_info.array_buffer_p))
{
return ECMA_VALUE_ERROR;
}

ecma_typedarray_type_t element_type = target_info.id;
ecma_value_t expected;
ecma_value_t replacement;

if (ECMA_TYPEDARRAY_IS_BIGINT_TYPE (element_type))
{
expected = ecma_bigint_to_bigint (expected_value, false);
repasics marked this conversation as resolved.
Show resolved Hide resolved

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

if (element_type == ECMA_BIGUINT64_ARRAY)
{
uint64_t num;
bool sign;

ecma_bigint_get_digits_and_sign (expected, &num, 1, &sign);

if (sign)
{
num = (uint64_t) (-(int64_t) num);
}

if (expected != ECMA_BIGINT_ZERO)
{
ecma_deref_bigint (ecma_get_extended_primitive_from_value (expected));
}

expected = ecma_bigint_create_from_digits (&num, 1, false);
}

replacement = ecma_bigint_to_bigint (replacement_value, false);

if (ECMA_IS_VALUE_ERROR (replacement))
{
ecma_free_value (expected);
return replacement;
}
}
else
{
ecma_number_t tmp_exp;
ecma_number_t tmp_rep;

expected = ecma_op_to_integer (expected_value, &tmp_exp);

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

expected = ecma_convert_number_to_typed_array_type (tmp_exp, element_type);

replacement = ecma_op_to_integer (replacement_value, &tmp_rep);

if (ECMA_IS_VALUE_ERROR (replacement))
{
ecma_free_value (expected);
return replacement;
}

replacement = ecma_make_number_value (tmp_rep);
}

uint8_t element_size = target_info.element_size;
uint32_t offset = target_info.offset;
uint32_t indexed_position = idx * element_size + offset;

if (ecma_arraybuffer_is_detached (ecma_get_object_from_value (buffer)))
{
ecma_free_value (expected);
ecma_free_value (replacement);
return ecma_raise_type_error (ECMA_ERR_ARRAYBUFFER_IS_DETACHED);
}

ecma_typedarray_getter_fn_t typedarray_getter_cb = ecma_get_typedarray_getter_fn (element_type);

ecma_object_t *buffer_obj_p = ecma_get_object_from_value (buffer);
lit_utf8_byte_t *pos = ecma_arraybuffer_get_buffer (buffer_obj_p) + indexed_position;
ecma_value_t stored_value = typedarray_getter_cb (pos);

// TODO: Handle shared array buffers differently.
if (ecma_op_same_value (stored_value, expected))
{
ecma_typedarray_setter_fn_t typedarray_setter_cb = ecma_get_typedarray_setter_fn (element_type);
typedarray_setter_cb (ecma_arraybuffer_get_buffer (buffer_obj_p) + indexed_position, replacement);
}

ecma_free_value (expected);
ecma_free_value (replacement);

return stored_value;
} /* ecma_builtin_atomics_compare_exchange */

/**
Expand Down Expand Up @@ -117,11 +274,80 @@ ecma_builtin_atomics_store (ecma_value_t typedarray, /**< typedArray argument */
ecma_value_t index, /**< index argument */
ecma_value_t value) /**< value argument */
{
JERRY_UNUSED (typedarray);
JERRY_UNUSED (index);
JERRY_UNUSED (value);
/* 1. */
ecma_value_t buffer = ecma_validate_integer_typedarray (typedarray, false);

return ecma_make_uint32_value (0);
if (ECMA_IS_VALUE_ERROR (buffer))
{
return buffer;
}

/* 2. */
uint32_t idx = ecma_validate_atomic_access (typedarray, index);

if (idx == ECMA_STRING_NOT_ARRAY_INDEX)
{
return ECMA_VALUE_ERROR;
}

ecma_object_t *typedarray_p = ecma_get_object_from_value (typedarray);
ecma_typedarray_info_t target_info = ecma_typedarray_get_info (typedarray_p);

if (ECMA_ARRAYBUFFER_LAZY_ALLOC (target_info.array_buffer_p))
{
return ECMA_VALUE_ERROR;
}

uint8_t element_size = target_info.element_size;

ecma_typedarray_type_t element_type = target_info.id;

uint32_t offset = target_info.offset;

uint32_t indexed_position = idx * element_size + offset;

ecma_typedarray_setter_fn_t typedarray_setter_cb = ecma_get_typedarray_setter_fn (element_type);
ecma_object_t *buffer_obj_p = ecma_get_object_from_value (buffer);

ecma_value_t value_to_store;
if (element_type == ECMA_BIGINT64_ARRAY || element_type == ECMA_BIGUINT64_ARRAY)
{
value_to_store = ecma_bigint_to_bigint (value, false);

if (ECMA_IS_VALUE_ERROR (value_to_store))
{
return value_to_store;
}
}
else
{
ecma_number_t num_int;

value_to_store = ecma_op_to_integer (value, &num_int);

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

if (ecma_number_is_zero (num_int) && ecma_number_is_negative (num_int))
{
num_int = (ecma_number_t) 0;
}

value_to_store = ecma_make_number_value (num_int);
}

if (ecma_arraybuffer_is_detached (ecma_get_object_from_value (buffer)))
{
ecma_free_value (value_to_store);
return ecma_raise_type_error (ECMA_ERR_ARRAYBUFFER_IS_DETACHED);
}

// TODO: Handle shared array buffers differently.
typedarray_setter_cb (ecma_arraybuffer_get_buffer (buffer_obj_p) + indexed_position, value_to_store);

return value_to_store;
} /* ecma_builtin_atomics_store */

/**
Expand Down