jerryscript/jerry-core/api/jerryscript.c
Dániel Bátyai ac1c48eeff
Update jerry-port and jerry-ext (#4907)
Notable changes:
  - Updated and the port API interface, new functions have been added
    and some have been changed. The port library is now cleaned up to
    not have any dependency on jerry-core, as it should be. The port library
    is now strictly a collection of functions that implement
    embedding/platform specific behavior.
  - The default port implementation has been split for windows and unix.
    Implemented port functions have been categorized and reorganized,
    and marked with attribute((weak)) for better reusability.
  - External context allocation has been moved to the port API instead
    of a core API callback. The iterface has also been extended with a
    function to free the allocated context. When external context is
    enabled, jerry_init now automatically calls the port implementation
    to allocate the context and jerry_cleanup automatically calls the port
    to free the context.
  - jerry_port_log has been changed to no longer require formatting to
    be implemented by the port. The reason beind this is that it was vague what
    format specifiers were used by the engine, and in what manner. The port
    function now takes a zero-terminated string, and should only implement
    how the string should be logged.
  - Logging and log message formatting is now handled by the core jerry library
    where it can be implemented as necessary. Logging can be done through a new
    core API function, which uses the port to output the final log message.
  - Log level has been moved into jerry-core, and an API function has
    been added to set the log level. It should be the library that
    filters log messages based on the requested log level, instead of
    logging everything and requiring the user to do so.
  - Module resolving logic has been moved into jerry-core. There's no
    reason to have it in the port library and requiring embedders to
    duplicate the code. It also added an unnecessary dependency on
    jerry-core to the port. Platform specific behavior is still used through
    the port API, like resolving module specifiers, and reading source file
    contents. If necessary, the resolving logic can still be overridden as
    previously.
  - The jerry-ext library has also been cleaned up, and many utility
    functions have been added that previously were implemented in
    jerry-main. This allows easier reusability for some common operations,
    like printing unhandled exceptions or providing a repl console.
  - Debugger interaction with logged/printed messages has been fixed, so
    that it's no longer the port implementations responsibility to send
    the output to the debugger, as the port should have no notion of what a
    debugger is.  The printing and logging functions will now pass the
    result message to the debugger, if connected.
  - Cleaned up TZA handling in the date port implementation, and simplified
    the API function prototype.
  - Moved property access helper functions that use ASCII strings as
    keys from jerry-ext to the core API.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
2022-01-20 13:53:47 +01:00

7287 lines
217 KiB
C

/* 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 "jerryscript.h"
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include "jerryscript-debugger-transport.h"
#include "ecma-alloc.h"
#include "ecma-array-object.h"
#include "ecma-arraybuffer-object.h"
#include "ecma-bigint.h"
#include "ecma-builtin-helpers.h"
#include "ecma-builtins.h"
#include "ecma-comparison.h"
#include "ecma-container-object.h"
#include "ecma-dataview-object.h"
#include "ecma-errors.h"
#include "ecma-eval.h"
#include "ecma-exceptions.h"
#include "ecma-extended-info.h"
#include "ecma-function-object.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-init-finalize.h"
#include "ecma-iterator-object.h"
#include "ecma-lex-env.h"
#include "ecma-line-info.h"
#include "ecma-literal-storage.h"
#include "ecma-objects-general.h"
#include "ecma-objects.h"
#include "ecma-promise-object.h"
#include "ecma-proxy-object.h"
#include "ecma-regexp-object.h"
#include "ecma-shared-arraybuffer-object.h"
#include "ecma-symbol-object.h"
#include "ecma-typedarray-object.h"
#include "debugger.h"
#include "jcontext.h"
#include "jmem.h"
#include "jrt.h"
#include "js-parser.h"
#include "lit-char-helpers.h"
#include "opcodes.h"
#include "re-compiler.h"
JERRY_STATIC_ASSERT (sizeof (jerry_value_t) == sizeof (ecma_value_t),
size_of_jerry_value_t_must_be_equal_to_size_of_ecma_value_t);
#if JERRY_BUILTIN_REGEXP
JERRY_STATIC_ASSERT ((int) RE_FLAG_GLOBAL == (int) JERRY_REGEXP_FLAG_GLOBAL
&& (int) RE_FLAG_MULTILINE == (int) JERRY_REGEXP_FLAG_MULTILINE
&& (int) RE_FLAG_IGNORE_CASE == (int) JERRY_REGEXP_FLAG_IGNORE_CASE
&& (int) RE_FLAG_STICKY == (int) JERRY_REGEXP_FLAG_STICKY
&& (int) RE_FLAG_UNICODE == (int) JERRY_REGEXP_FLAG_UNICODE
&& (int) RE_FLAG_DOTALL == (int) JERRY_REGEXP_FLAG_DOTALL,
re_flags_t_must_be_equal_to_jerry_regexp_flags_t);
#endif /* JERRY_BUILTIN_REGEXP */
#if JERRY_ESNEXT
/* The internal ECMA_PROMISE_STATE_* values are "one byte away" from the API values */
JERRY_STATIC_ASSERT ((int) ECMA_PROMISE_IS_PENDING == (int) JERRY_PROMISE_STATE_PENDING
&& (int) ECMA_PROMISE_IS_FULFILLED == (int) JERRY_PROMISE_STATE_FULFILLED,
promise_internal_state_matches_external);
#endif /* JERRY_ESNEXT */
/**
* Offset between internal and external arithmetic operator types
*/
#define ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET (JERRY_BIN_OP_SUB - NUMBER_ARITHMETIC_SUBTRACTION)
JERRY_STATIC_ASSERT (((NUMBER_ARITHMETIC_SUBTRACTION + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET) == JERRY_BIN_OP_SUB)
&& ((NUMBER_ARITHMETIC_MULTIPLICATION + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET)
== JERRY_BIN_OP_MUL)
&& ((NUMBER_ARITHMETIC_DIVISION + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET) == JERRY_BIN_OP_DIV)
&& ((NUMBER_ARITHMETIC_REMAINDER + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET) == JERRY_BIN_OP_REM),
number_arithmetics_operation_type_matches_external);
#if !JERRY_PARSER && !JERRY_SNAPSHOT_EXEC
#error "JERRY_SNAPSHOT_EXEC must be enabled if JERRY_PARSER is disabled!"
#endif /* !JERRY_PARSER && !JERRY_SNAPSHOT_EXEC */
/** \addtogroup jerry Jerry engine interface
* @{
*/
/**
* Assert that it is correct to call API in current state.
*
* Note:
* By convention, there are some states when API could not be invoked.
*
* The API can be and only be invoked when the ECMA_STATUS_API_ENABLED
* flag is set.
*
* This procedure checks whether the API is available, and terminates
* the engine if it is unavailable. Otherwise it is a no-op.
*
* Note:
* The API could not be invoked in the following cases:
* - before jerry_init and after jerry_cleanup
* - between enter to and return from a native free callback
*/
static inline void JERRY_ATTR_ALWAYS_INLINE
jerry_assert_api_enabled (void)
{
JERRY_ASSERT (JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_ENABLED);
} /* jerry_assert_api_enabled */
/**
* Turn on API availability
*/
static inline void JERRY_ATTR_ALWAYS_INLINE
jerry_api_enable (void)
{
#ifndef JERRY_NDEBUG
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_API_ENABLED;
#endif /* JERRY_NDEBUG */
} /* jerry_make_api_available */
/**
* Turn off API availability
*/
static inline void JERRY_ATTR_ALWAYS_INLINE
jerry_api_disable (void)
{
#ifndef JERRY_NDEBUG
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_API_ENABLED;
#endif /* JERRY_NDEBUG */
} /* jerry_make_api_unavailable */
/**
* Create an API compatible return value.
*
* @return return value for Jerry API functions
*/
static jerry_value_t
jerry_return (const jerry_value_t value) /**< return value */
{
if (ECMA_IS_VALUE_ERROR (value))
{
return ecma_create_exception_from_context ();
}
return value;
} /* jerry_return */
/**
* Jerry engine initialization
*/
void
jerry_init (jerry_init_flag_t flags) /**< combination of Jerry flags */
{
#if JERRY_EXTERNAL_CONTEXT
size_t total_size = jerry_port_context_alloc (sizeof (jerry_context_t));
JERRY_UNUSED (total_size);
#endif /* JERRY_EXTERNAL_CONTEXT */
jerry_context_t *context_p = &JERRY_CONTEXT_STRUCT;
memset (context_p, 0, sizeof (jerry_context_t));
#if JERRY_EXTERNAL_CONTEXT && !JERRY_SYSTEM_ALLOCATOR
uint32_t heap_start_offset = JERRY_ALIGNUP (sizeof (jerry_context_t), JMEM_ALIGNMENT);
uint8_t *heap_p = ((uint8_t *) context_p) + heap_start_offset;
uint32_t heap_size = JERRY_ALIGNDOWN (total_size - heap_start_offset, JMEM_ALIGNMENT);
JERRY_ASSERT (heap_p + heap_size <= ((uint8_t *) context_p) + total_size);
context_p->heap_p = (jmem_heap_t *) heap_p;
context_p->heap_size = heap_size;
#endif /* JERRY_EXTERNAL_CONTEXT && !JERRY_SYSTEM_ALLOCATOR */
JERRY_CONTEXT (jerry_init_flags) = flags;
jerry_api_enable ();
jmem_init ();
ecma_init ();
} /* jerry_init */
/**
* Terminate Jerry engine
*/
void
jerry_cleanup (void)
{
jerry_assert_api_enabled ();
#if JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
jerry_debugger_send_type (JERRY_DEBUGGER_CLOSE_CONNECTION);
jerry_debugger_transport_close ();
}
#endif /* JERRY_DEBUGGER */
for (jerry_context_data_header_t *this_p = JERRY_CONTEXT (context_data_p); this_p != NULL; this_p = this_p->next_p)
{
if (this_p->manager_p->deinit_cb)
{
void *data = (this_p->manager_p->bytes_needed > 0) ? JERRY_CONTEXT_DATA_HEADER_USER_DATA (this_p) : NULL;
this_p->manager_p->deinit_cb (data);
}
}
#if JERRY_ESNEXT
ecma_free_all_enqueued_jobs ();
#endif /* JERRY_ESNEXT */
ecma_finalize ();
jerry_api_disable ();
for (jerry_context_data_header_t *this_p = JERRY_CONTEXT (context_data_p), *next_p = NULL; this_p != NULL;
this_p = next_p)
{
next_p = this_p->next_p;
if (this_p->manager_p->finalize_cb)
{
void *data = (this_p->manager_p->bytes_needed > 0) ? JERRY_CONTEXT_DATA_HEADER_USER_DATA (this_p) : NULL;
this_p->manager_p->finalize_cb (data);
}
jmem_heap_free_block (this_p, sizeof (jerry_context_data_header_t) + this_p->manager_p->bytes_needed);
}
jmem_finalize ();
#if JERRY_EXTERNAL_CONTEXT
jerry_port_context_free ();
#endif /* JERRY_EXTERNAL_CONTEXT */
} /* jerry_cleanup */
/**
* Retrieve a context data item, or create a new one.
*
* @param manager_p pointer to the manager whose context data item should be returned.
*
* @return a pointer to the user-provided context-specific data item for the given manager, creating such a pointer if
* none was found.
*/
void *
jerry_context_data (const jerry_context_data_manager_t *manager_p)
{
void *ret = NULL;
jerry_context_data_header_t *item_p;
for (item_p = JERRY_CONTEXT (context_data_p); item_p != NULL; item_p = item_p->next_p)
{
if (item_p->manager_p == manager_p)
{
return (manager_p->bytes_needed > 0) ? JERRY_CONTEXT_DATA_HEADER_USER_DATA (item_p) : NULL;
}
}
item_p = jmem_heap_alloc_block (sizeof (jerry_context_data_header_t) + manager_p->bytes_needed);
item_p->manager_p = manager_p;
item_p->next_p = JERRY_CONTEXT (context_data_p);
JERRY_CONTEXT (context_data_p) = item_p;
if (manager_p->bytes_needed > 0)
{
ret = JERRY_CONTEXT_DATA_HEADER_USER_DATA (item_p);
memset (ret, 0, manager_p->bytes_needed);
}
if (manager_p->init_cb)
{
manager_p->init_cb (ret);
}
return ret;
} /* jerry_context_data */
/**
* Register external magic string array
*/
void
jerry_register_magic_strings (const jerry_char_t *const *ext_strings_p, /**< character arrays, representing
* external magic strings' contents */
uint32_t count, /**< number of the strings */
const jerry_length_t *str_lengths_p) /**< lengths of all strings */
{
jerry_assert_api_enabled ();
lit_magic_strings_ex_set ((const lit_utf8_byte_t *const *) ext_strings_p,
count,
(const lit_utf8_size_t *) str_lengths_p);
} /* jerry_register_magic_strings */
/**
* Run garbage collection
*/
void
jerry_heap_gc (jerry_gc_mode_t mode) /**< operational mode */
{
jerry_assert_api_enabled ();
if (mode == JERRY_GC_PRESSURE_LOW)
{
/* Call GC directly, because 'ecma_free_unused_memory' might decide it's not yet worth it. */
ecma_gc_run ();
return;
}
ecma_free_unused_memory (JMEM_PRESSURE_HIGH);
} /* jerry_heap_gc */
/**
* Get heap memory stats.
*
* @return true - get the heap stats successful
* false - otherwise. Usually it is because the MEM_STATS feature is not enabled.
*/
bool
jerry_heap_stats (jerry_heap_stats_t *out_stats_p) /**< [out] heap memory stats */
{
#if JERRY_MEM_STATS
if (out_stats_p == NULL)
{
return false;
}
jmem_heap_stats_t jmem_heap_stats;
memset (&jmem_heap_stats, 0, sizeof (jmem_heap_stats));
jmem_heap_get_stats (&jmem_heap_stats);
*out_stats_p = (jerry_heap_stats_t){ .version = 1,
.size = jmem_heap_stats.size,
.allocated_bytes = jmem_heap_stats.allocated_bytes,
.peak_allocated_bytes = jmem_heap_stats.peak_allocated_bytes };
return true;
#else /* !JERRY_MEM_STATS */
JERRY_UNUSED (out_stats_p);
return false;
#endif /* JERRY_MEM_STATS */
} /* jerry_heap_stats */
#if JERRY_PARSER
/**
* Common code for parsing a script, module, or function.
*
* @return function object value - if script was parsed successfully,
* thrown error - otherwise
*/
static jerry_value_t
jerry_parse_common (void *source_p, /**< script source */
const jerry_parse_options_t *options_p, /**< parsing options, can be NULL if not used */
uint32_t parse_opts) /**< internal parsing options */
{
jerry_assert_api_enabled ();
if (options_p != NULL)
{
const uint32_t allowed_options =
(JERRY_PARSE_STRICT_MODE | JERRY_PARSE_MODULE | JERRY_PARSE_HAS_ARGUMENT_LIST | JERRY_PARSE_HAS_SOURCE_NAME
| JERRY_PARSE_HAS_START | JERRY_PARSE_HAS_USER_VALUE);
uint32_t options = options_p->options;
if ((options & ~allowed_options) != 0
|| ((options_p->options & JERRY_PARSE_HAS_ARGUMENT_LIST)
&& ((options_p->options & JERRY_PARSE_MODULE) || !ecma_is_value_string (options_p->argument_list)))
|| ((options_p->options & JERRY_PARSE_HAS_SOURCE_NAME) && !ecma_is_value_string (options_p->source_name)))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
}
#if JERRY_DEBUGGER
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && options_p != NULL
&& (options_p->options & JERRY_PARSE_HAS_SOURCE_NAME) && ecma_is_value_string (options_p->source_name))
{
ECMA_STRING_TO_UTF8_STRING (ecma_get_string_from_value (options_p->source_name),
source_name_start_p,
source_name_size);
jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE_NAME,
JERRY_DEBUGGER_NO_SUBTYPE,
source_name_start_p,
source_name_size);
ECMA_FINALIZE_UTF8_STRING (source_name_start_p, source_name_size);
}
#endif /* JERRY_DEBUGGER */
if (options_p != NULL)
{
parse_opts |= options_p->options & (JERRY_PARSE_STRICT_MODE | JERRY_PARSE_MODULE);
}
if ((parse_opts & JERRY_PARSE_MODULE) != 0)
{
#if JERRY_MODULE_SYSTEM
JERRY_CONTEXT (module_current_p) = ecma_module_create ();
#else /* !JERRY_MODULE_SYSTEM */
return jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
#endif /* JERRY_MODULE_SYSTEM */
}
ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = parser_parse_script (source_p, parse_opts, options_p);
if (JERRY_UNLIKELY (bytecode_data_p == NULL))
{
#if JERRY_MODULE_SYSTEM
if ((parse_opts & JERRY_PARSE_MODULE) != 0)
{
ecma_module_cleanup_context ();
}
#endif /* JERRY_MODULE_SYSTEM */
return ecma_create_exception_from_context ();
}
#if JERRY_MODULE_SYSTEM
if (JERRY_UNLIKELY (parse_opts & JERRY_PARSE_MODULE))
{
ecma_module_t *module_p = JERRY_CONTEXT (module_current_p);
module_p->u.compiled_code_p = bytecode_data_p;
JERRY_CONTEXT (module_current_p) = NULL;
return ecma_make_object_value ((ecma_object_t *) module_p);
}
#endif /* JERRY_MODULE_SYSTEM */
if (JERRY_UNLIKELY (options_p != NULL && (options_p->options & JERRY_PARSE_HAS_ARGUMENT_LIST)))
{
ecma_object_t *global_object_p = ecma_builtin_get_global ();
#if JERRY_BUILTIN_REALMS
JERRY_ASSERT (global_object_p == (ecma_object_t *) ecma_op_function_get_realm (bytecode_data_p));
#endif /* JERRY_BUILTIN_REALMS */
ecma_object_t *lex_env_p = ecma_get_global_environment (global_object_p);
ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_data_p);
ecma_bytecode_deref (bytecode_data_p);
return ecma_make_object_value (func_obj_p);
}
ecma_object_t *object_p = ecma_create_object (NULL, 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.cls.type = ECMA_OBJECT_CLASS_SCRIPT;
ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.cls.u3.value, bytecode_data_p);
return ecma_make_object_value (object_p);
} /* jerry_parse_common */
#endif /* JERRY_PARSER */
/**
* Parse a script, module, or function and create a compiled code using a character string
*
* @return function object value - if script was parsed successfully,
* thrown error - otherwise
*/
jerry_value_t
jerry_parse (const jerry_char_t *source_p, /**< script source */
size_t source_size, /**< script source size */
const jerry_parse_options_t *options_p) /**< parsing options, can be NULL if not used */
{
#if JERRY_PARSER
parser_source_char_t source_char;
source_char.source_p = source_p;
source_char.source_size = source_size;
return jerry_parse_common ((void *) &source_char, options_p, JERRY_PARSE_NO_OPTS);
#else /* !JERRY_PARSER */
JERRY_UNUSED (source_p);
JERRY_UNUSED (source_size);
JERRY_UNUSED (options_p);
return jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_PARSER_NOT_SUPPORTED));
#endif /* JERRY_PARSER */
} /* jerry_parse */
/**
* Parse a script, module, or function and create a compiled code using a string value
*
* @return function object value - if script was parsed successfully,
* thrown error - otherwise
*/
jerry_value_t
jerry_parse_value (const jerry_value_t source, /**< script source */
const jerry_parse_options_t *options_p) /**< parsing options, can be NULL if not used */
{
#if JERRY_PARSER
if (!ecma_is_value_string (source))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
return jerry_parse_common ((void *) &source, options_p, ECMA_PARSE_HAS_SOURCE_VALUE);
#else /* !JERRY_PARSER */
JERRY_UNUSED (source);
JERRY_UNUSED (options_p);
return jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_PARSER_NOT_SUPPORTED));
#endif /* JERRY_PARSER */
} /* jerry_parse_value */
/**
* Run a Script or Module created by jerry_parse.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return result of bytecode - if run was successful
* thrown error - otherwise
*/
jerry_value_t
jerry_run (const jerry_value_t script) /**< script or module to run */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (script))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_object_t *object_p = ecma_get_object_from_value (script);
if (!ecma_object_class_is (object_p, ECMA_OBJECT_CLASS_SCRIPT))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ext_object_p->u.cls.u3.value);
JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) == CBC_FUNCTION_SCRIPT);
return jerry_return (vm_run_global (bytecode_data_p, object_p));
} /* jerry_run */
/**
* Perform eval
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return result of eval, may be error value.
*/
jerry_value_t
jerry_eval (const jerry_char_t *source_p, /**< source code */
size_t source_size, /**< length of source code */
uint32_t flags) /**< jerry_parse_opts_t flags */
{
jerry_assert_api_enabled ();
uint32_t allowed_parse_options = JERRY_PARSE_STRICT_MODE;
if ((flags & ~allowed_parse_options) != 0)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
parser_source_char_t source_char;
source_char.source_p = source_p;
source_char.source_size = source_size;
return jerry_return (ecma_op_eval_chars_buffer ((void *) &source_char, flags));
} /* jerry_eval */
/**
* Link modules to their dependencies. The dependencies are resolved by a user callback.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return true - if linking is successful, error - otherwise
*/
jerry_value_t
jerry_module_link (const jerry_value_t module, /**< root module */
jerry_module_resolve_cb_t callback, /**< resolve module callback, uses
* jerry_module_resolve when NULL is passed */
void *user_p) /**< pointer passed to the resolve callback */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
if (callback == NULL)
{
callback = jerry_module_resolve;
}
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
if (module_p == NULL)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
}
return jerry_return (ecma_module_link (module_p, callback, user_p));
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module);
JERRY_UNUSED (callback);
JERRY_UNUSED (user_p);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_link */
/**
* Evaluate a module and its dependencies. The module must be in linked state.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return result of module bytecode execution - if evaluation was successful
* error - otherwise
*/
jerry_value_t
jerry_module_evaluate (const jerry_value_t module) /**< root module */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
if (module_p == NULL)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
}
if (module_p->header.u.cls.u1.module_state != JERRY_MODULE_STATE_LINKED)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_MUST_BE_IN_LINKED_STATE));
}
return jerry_return (ecma_module_evaluate (module_p));
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_evaluate */
/**
* Returns the current status of a module
*
* @return current status - if module is a module,
* JERRY_MODULE_STATE_INVALID - otherwise
*/
jerry_module_state_t
jerry_module_state (const jerry_value_t module) /**< module object */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
if (module_p == NULL)
{
return JERRY_MODULE_STATE_INVALID;
}
return (jerry_module_state_t) module_p->header.u.cls.u1.module_state;
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module);
return JERRY_MODULE_STATE_INVALID;
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_state */
/**
* Sets a callback which is called after a module state is changed to linked, evaluated, or error.
*/
void
jerry_module_on_state_changed (jerry_module_state_changed_cb_t callback, /**< callback */
void *user_p) /**< pointer passed to the callback */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
JERRY_CONTEXT (module_state_changed_callback_p) = callback;
JERRY_CONTEXT (module_state_changed_callback_user_p) = user_p;
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (callback);
JERRY_UNUSED (user_p);
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_on_state_changed */
/**
* Sets a callback which is called when an import.meta expression of a module is evaluated the first time.
*/
void
jerry_module_on_import_meta (jerry_module_import_meta_cb_t callback, /**< callback */
void *user_p) /**< pointer passed to the callback */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
JERRY_CONTEXT (module_import_meta_callback_p) = callback;
JERRY_CONTEXT (module_import_meta_callback_user_p) = user_p;
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (callback);
JERRY_UNUSED (user_p);
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_on_import_meta */
/**
* Returns the number of import/export requests of a module
*
* @return number of import/export requests of a module
*/
size_t
jerry_module_request_count (const jerry_value_t module) /**< module */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
if (module_p == NULL)
{
return 0;
}
size_t number_of_requests = 0;
ecma_module_node_t *node_p = module_p->imports_p;
while (node_p != NULL)
{
number_of_requests++;
node_p = node_p->next_p;
}
return number_of_requests;
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module);
return 0;
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_request_count */
/**
* Returns the module request specified by the request_index argument
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return string - if the request has not been resolved yet,
* module object - if the request has been resolved successfully,
* error - otherwise
*/
jerry_value_t
jerry_module_request (const jerry_value_t module, /**< module */
size_t request_index) /**< request index */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
if (module_p == NULL)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
}
ecma_module_node_t *node_p = module_p->imports_p;
while (node_p != NULL)
{
if (request_index == 0)
{
return ecma_copy_value (node_p->u.path_or_module);
}
--request_index;
node_p = node_p->next_p;
}
return jerry_throw_sz (JERRY_ERROR_RANGE, ecma_get_error_msg (ECMA_ERR_REQUEST_IS_NOT_AVAILABLE));
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module);
JERRY_UNUSED (request_index);
return jerry_throw_sz (JERRY_ERROR_RANGE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_request */
/**
* Returns the namespace object of a module
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return object - if namespace object is available,
* error - otherwise
*/
jerry_value_t
jerry_module_namespace (const jerry_value_t module) /**< module */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
if (module_p == NULL)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
}
if (module_p->header.u.cls.u1.module_state < JERRY_MODULE_STATE_LINKED
|| module_p->header.u.cls.u1.module_state > JERRY_MODULE_STATE_EVALUATED)
{
return jerry_throw_sz (JERRY_ERROR_RANGE, ecma_get_error_msg (ECMA_ERR_NAMESPACE_OBJECT_IS_NOT_AVAILABLE));
}
JERRY_ASSERT (module_p->namespace_object_p != NULL);
ecma_ref_object (module_p->namespace_object_p);
return ecma_make_object_value (module_p->namespace_object_p);
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_namespace */
/**
* Sets the callback which is called when dynamic imports are resolved
*/
void
jerry_module_on_import (jerry_module_import_cb_t callback_p, /**< callback which handles
* dynamic import calls */
void *user_p) /**< user pointer passed to the callback */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
JERRY_CONTEXT (module_import_callback_p) = callback_p;
JERRY_CONTEXT (module_import_callback_user_p) = user_p;
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (callback_p);
JERRY_UNUSED (user_p);
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_on_import */
/**
* Creates a native module with a list of exports. The initial state of the module is linked.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return native module - if the module is successfully created,
* error - otherwise
*/
jerry_value_t
jerry_native_module (jerry_native_module_evaluate_cb_t callback, /**< evaluation callback for
* native modules */
const jerry_value_t *const exports_p, /**< list of the exported bindings of the module,
* must be valid string identifiers */
size_t export_count) /**< number of exports in the exports_p list */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
ecma_object_t *global_object_p = ecma_builtin_get_global ();
ecma_object_t *scope_p = ecma_create_decl_lex_env (ecma_get_global_environment (global_object_p));
ecma_module_names_t *local_exports_p = NULL;
for (size_t i = 0; i < export_count; i++)
{
if (!ecma_is_value_string (exports_p[i]))
{
ecma_deref_object (scope_p);
ecma_module_release_module_names (local_exports_p);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_EXPORTS_MUST_BE_STRING_VALUES));
}
ecma_string_t *name_str_p = ecma_get_string_from_value (exports_p[i]);
bool valid_identifier = false;
ECMA_STRING_TO_UTF8_STRING (name_str_p, name_start_p, name_size);
if (name_size > 0)
{
const lit_utf8_byte_t *name_p = name_start_p;
const lit_utf8_byte_t *name_end_p = name_start_p + name_size;
lit_code_point_t code_point;
lit_utf8_size_t size = lit_read_code_point_from_cesu8 (name_p, name_end_p, &code_point);
if (lit_code_point_is_identifier_start (code_point))
{
name_p += size;
valid_identifier = true;
while (name_p < name_end_p)
{
size = lit_read_code_point_from_cesu8 (name_p, name_end_p, &code_point);
if (!lit_code_point_is_identifier_part (code_point))
{
valid_identifier = false;
break;
}
name_p += size;
}
}
}
ECMA_FINALIZE_UTF8_STRING (name_start_p, name_size);
if (!valid_identifier)
{
ecma_deref_object (scope_p);
ecma_module_release_module_names (local_exports_p);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_EXPORTS_MUST_BE_VALID_IDENTIFIERS));
}
if (ecma_find_named_property (scope_p, name_str_p) != NULL)
{
continue;
}
ecma_create_named_data_property (scope_p, name_str_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL);
ecma_module_names_t *new_export_p;
new_export_p = (ecma_module_names_t *) jmem_heap_alloc_block (sizeof (ecma_module_names_t));
new_export_p->next_p = local_exports_p;
local_exports_p = new_export_p;
ecma_ref_ecma_string (name_str_p);
new_export_p->imex_name_p = name_str_p;
ecma_ref_ecma_string (name_str_p);
new_export_p->local_name_p = name_str_p;
}
ecma_module_t *module_p = ecma_module_create ();
module_p->header.u.cls.u2.module_flags |= ECMA_MODULE_IS_NATIVE;
module_p->scope_p = scope_p;
module_p->local_exports_p = local_exports_p;
module_p->u.callback = callback;
ecma_deref_object (scope_p);
return ecma_make_object_value (&module_p->header.object);
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (callback);
JERRY_UNUSED (exports_p);
JERRY_UNUSED (export_count);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_native_module */
/**
* Gets the value of an export which belongs to a native module.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the export - if success
* error - otherwise
*/
jerry_value_t
jerry_native_module_get (const jerry_value_t native_module, /**< a native module object */
const jerry_value_t export_name) /**< string identifier of the export */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (native_module);
if (module_p == NULL)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
}
if (!(module_p->header.u.cls.u2.module_flags & ECMA_MODULE_IS_NATIVE) || !ecma_is_value_string (export_name))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_property_t *property_p = ecma_find_named_property (module_p->scope_p, ecma_get_string_from_value (export_name));
if (property_p == NULL)
{
return jerry_throw_sz (JERRY_ERROR_REFERENCE, ecma_get_error_msg (ECMA_ERR_UNKNOWN_EXPORT));
}
return ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (native_module);
JERRY_UNUSED (export_name);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_native_module_get */
/**
* Sets the value of an export which belongs to a native module.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return true value - if the operation was successful
* error - otherwise
*/
jerry_value_t
jerry_native_module_set (jerry_value_t native_module, /**< a native module object */
const jerry_value_t export_name, /**< string identifier of the export */
const jerry_value_t value) /**< new value of the export */
{
jerry_assert_api_enabled ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (native_module);
if (module_p == NULL)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
}
if (!(module_p->header.u.cls.u2.module_flags & ECMA_MODULE_IS_NATIVE) || !ecma_is_value_string (export_name)
|| ecma_is_value_exception (value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_property_t *property_p = ecma_find_named_property (module_p->scope_p, ecma_get_string_from_value (export_name));
if (property_p == NULL)
{
return jerry_throw_sz (JERRY_ERROR_REFERENCE, ecma_get_error_msg (ECMA_ERR_UNKNOWN_EXPORT));
}
ecma_named_data_property_assign_value (module_p->scope_p, ECMA_PROPERTY_VALUE_PTR (property_p), value);
return ECMA_VALUE_TRUE;
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (native_module);
JERRY_UNUSED (export_name);
JERRY_UNUSED (value);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_native_module_set */
/**
* Run enqueued microtasks created by Promise or AsyncFunction objects.
* Tasks are executed until an exception is thrown or all tasks are executed.
*
* Note: returned value must be freed with jerry_value_free
*
* @return result of last executed job, possibly an exception.
*/
jerry_value_t
jerry_run_jobs (void)
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
return jerry_return (ecma_process_all_enqueued_jobs ());
#else /* !JERRY_ESNEXT */
return ECMA_VALUE_UNDEFINED;
#endif /* JERRY_ESNEXT */
} /* jerry_run_jobs */
/**
* Get global object
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return api value of global object
*/
jerry_value_t
jerry_current_realm (void)
{
jerry_assert_api_enabled ();
ecma_object_t *global_obj_p = ecma_builtin_get_global ();
ecma_ref_object (global_obj_p);
return ecma_make_object_value (global_obj_p);
} /* jerry_current_realm */
/**
* Check if the specified value is an abort value.
*
* @return true - if both the error and abort values are set,
* false - otherwise
*/
bool
jerry_value_is_abort (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_exception (value))
{
return false;
}
ecma_extended_primitive_t *error_ref_p = ecma_get_extended_primitive_from_value (value);
return (error_ref_p->refs_and_type & ECMA_ERROR_API_FLAG_ABORT) != 0;
} /* jerry_value_is_abort */
/**
* Check if the specified value is an array object value.
*
* @return true - if the specified value is an array object,
* false - otherwise
*/
bool
jerry_value_is_array (const jerry_value_t value) /**< jerry api value */
{
jerry_assert_api_enabled ();
return (ecma_is_value_object (value)
&& ecma_get_object_base_type (ecma_get_object_from_value (value)) == ECMA_OBJECT_BASE_TYPE_ARRAY);
} /* jerry_value_is_array */
/**
* Check if the specified value is boolean.
*
* @return true - if the specified value is boolean,
* false - otherwise
*/
bool
jerry_value_is_boolean (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
return ecma_is_value_boolean (value);
} /* jerry_value_is_boolean */
/**
* Check if the specified value is true.
*
* @return true - if the specified value is true
* false - otherwise
*/
bool
jerry_value_is_true (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
return ecma_is_value_true (value);
} /* jerry_value_is_true */
/**
* Check if the specified value is false.
*
* @return true - if the specified value is false
* false - otherwise
*/
bool
jerry_value_is_false (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
return ecma_is_value_false (value);
} /* jerry_value_is_false */
/**
* Check if the specified value is a constructor function object value.
*
* @return true - if the specified value is a function value that implements [[Construct]],
* false - otherwise
*/
bool
jerry_value_is_constructor (const jerry_value_t value) /**< jerry api value */
{
jerry_assert_api_enabled ();
return ecma_is_constructor (value);
} /* jerry_value_is_constructor */
/**
* Check if the specified value is an error or abort value.
*
* @return true - if the specified value is an error value,
* false - otherwise
*/
bool
jerry_value_is_exception (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
return ecma_is_value_exception (value);
} /* jerry_value_is_exception */
/**
* Check if the specified value is a function object value.
*
* @return true - if the specified value is callable,
* false - otherwise
*/
bool
jerry_value_is_function (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
return ecma_op_is_callable (value);
} /* jerry_value_is_function */
/**
* Check if the specified value is an async function object value.
*
* @return true - if the specified value is an async function,
* false - otherwise
*/
bool
jerry_value_is_async_function (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
if (ecma_is_value_object (value))
{
ecma_object_t *obj_p = ecma_get_object_from_value (value);
if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION)
{
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) obj_p);
uint16_t type = CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags);
return (type == CBC_FUNCTION_ASYNC || type == CBC_FUNCTION_ASYNC_ARROW || type == CBC_FUNCTION_ASYNC_GENERATOR);
}
}
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (value);
#endif /* JERRY_ESNEXT */
return false;
} /* jerry_value_is_async_function */
/**
* Check if the specified value is number.
*
* @return true - if the specified value is number,
* false - otherwise
*/
bool
jerry_value_is_number (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
return ecma_is_value_number (value);
} /* jerry_value_is_number */
/**
* Check if the specified value is null.
*
* @return true - if the specified value is null,
* false - otherwise
*/
bool
jerry_value_is_null (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
return ecma_is_value_null (value);
} /* jerry_value_is_null */
/**
* Check if the specified value is object.
*
* @return true - if the specified value is object,
* false - otherwise
*/
bool
jerry_value_is_object (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
return ecma_is_value_object (value);
} /* jerry_value_is_object */
/**
* Check if the specified value is promise.
*
* @return true - if the specified value is promise,
* false - otherwise
*/
bool
jerry_value_is_promise (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
return (ecma_is_value_object (value) && ecma_is_promise (ecma_get_object_from_value (value)));
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (value);
return false;
#endif /* JERRY_ESNEXT */
} /* jerry_value_is_promise */
/**
* Check if the specified value is a proxy object.
*
* @return true - if the specified value is a proxy object,
* false - otherwise
*/
bool
jerry_value_is_proxy (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_PROXY
return (ecma_is_value_object (value) && ECMA_OBJECT_IS_PROXY (ecma_get_object_from_value (value)));
#else /* !JERRY_BUILTIN_PROXY */
JERRY_UNUSED (value);
return false;
#endif /* JERRY_BUILTIN_PROXY */
} /* jerry_value_is_proxy */
/**
* Check if the specified value is string.
*
* @return true - if the specified value is string,
* false - otherwise
*/
bool
jerry_value_is_string (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
return ecma_is_value_string (value);
} /* jerry_value_is_string */
/**
* Check if the specified value is symbol.
*
* @return true - if the specified value is symbol,
* false - otherwise
*/
bool
jerry_value_is_symbol (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
return ecma_is_value_symbol (value);
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (value);
return false;
#endif /* JERRY_ESNEXT */
} /* jerry_value_is_symbol */
/**
* Check if the specified value is BigInt.
*
* @return true - if the specified value is BigInt,
* false - otherwise
*/
bool
jerry_value_is_bigint (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_BIGINT
return ecma_is_value_bigint (value);
#else /* !JERRY_BUILTIN_BIGINT */
JERRY_UNUSED (value);
return false;
#endif /* JERRY_BUILTIN_BIGINT */
} /* jerry_value_is_bigint */
/**
* Check if the specified value is undefined.
*
* @return true - if the specified value is undefined,
* false - otherwise
*/
bool
jerry_value_is_undefined (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
return ecma_is_value_undefined (value);
} /* jerry_value_is_undefined */
/**
* Perform the base type of the JavaScript value.
*
* @return jerry_type_t value
*/
jerry_type_t
jerry_value_type (const jerry_value_t value) /**< input value to check */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (value))
{
return JERRY_TYPE_EXCEPTION;
}
lit_magic_string_id_t lit_id = ecma_get_typeof_lit_id (value);
JERRY_ASSERT (lit_id != LIT_MAGIC_STRING__EMPTY);
switch (lit_id)
{
case LIT_MAGIC_STRING_UNDEFINED:
{
return JERRY_TYPE_UNDEFINED;
}
case LIT_MAGIC_STRING_BOOLEAN:
{
return JERRY_TYPE_BOOLEAN;
}
case LIT_MAGIC_STRING_NUMBER:
{
return JERRY_TYPE_NUMBER;
}
case LIT_MAGIC_STRING_STRING:
{
return JERRY_TYPE_STRING;
}
#if JERRY_ESNEXT
case LIT_MAGIC_STRING_SYMBOL:
{
return JERRY_TYPE_SYMBOL;
}
#endif /* JERRY_ESNEXT */
case LIT_MAGIC_STRING_FUNCTION:
{
return JERRY_TYPE_FUNCTION;
}
#if JERRY_BUILTIN_BIGINT
case LIT_MAGIC_STRING_BIGINT:
{
return JERRY_TYPE_BIGINT;
}
#endif /* JERRY_BUILTIN_BIGINT */
default:
{
JERRY_ASSERT (lit_id == LIT_MAGIC_STRING_OBJECT);
/* Based on the ECMA 262 5.1 standard the 'null' value is an object.
* Thus we'll do an extra check for 'null' here.
*/
return ecma_is_value_null (value) ? JERRY_TYPE_NULL : JERRY_TYPE_OBJECT;
}
}
} /* jerry_value_type */
/**
* Used by jerry_object_type to get the type of class objects
*/
static const uint8_t jerry_class_object_type[] = {
/* These objects require custom property resolving. */
JERRY_OBJECT_TYPE_STRING, /**< type of ECMA_OBJECT_CLASS_STRING */
JERRY_OBJECT_TYPE_ARGUMENTS, /**< type of ECMA_OBJECT_CLASS_ARGUMENTS */
#if JERRY_BUILTIN_TYPEDARRAY
JERRY_OBJECT_TYPE_TYPEDARRAY, /**< type of ECMA_OBJECT_CLASS_TYPEDARRAY */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_MODULE_SYSTEM
JERRY_OBJECT_TYPE_MODULE_NAMESPACE, /**< type of ECMA_OBJECT_CLASS_MODULE_NAMESPACE */
#endif /* JERRY_MODULE_SYSTEM */
/* These objects are marked by Garbage Collector. */
#if JERRY_ESNEXT
JERRY_OBJECT_TYPE_GENERATOR, /**< type of ECMA_OBJECT_CLASS_GENERATOR */
JERRY_OBJECT_TYPE_GENERATOR, /**< type of ECMA_OBJECT_CLASS_ASYNC_GENERATOR */
JERRY_OBJECT_TYPE_ITERATOR, /**< type of ECMA_OBJECT_CLASS_ARRAY_ITERATOR */
JERRY_OBJECT_TYPE_ITERATOR, /**< type of ECMA_OBJECT_CLASS_SET_ITERATOR */
JERRY_OBJECT_TYPE_ITERATOR, /**< type of ECMA_OBJECT_CLASS_MAP_ITERATOR */
#if JERRY_BUILTIN_REGEXP
JERRY_OBJECT_TYPE_ITERATOR, /**< type of ECMA_OBJECT_CLASS_REGEXP_STRING_ITERATOR */
#endif /* JERRY_BUILTIN_REGEXP */
#endif /* JERRY_ESNEXT */
#if JERRY_MODULE_SYSTEM
JERRY_OBJECT_TYPE_MODULE, /**< type of ECMA_OBJECT_CLASS_MODULE */
#endif /* JERRY_MODULE_SYSTEM */
#if JERRY_ESNEXT
JERRY_OBJECT_TYPE_PROMISE, /**< type of ECMA_OBJECT_CLASS_PROMISE */
JERRY_OBJECT_TYPE_GENERIC, /**< type of ECMA_OBJECT_CLASS_PROMISE_CAPABILITY */
JERRY_OBJECT_TYPE_GENERIC, /**< type of ECMA_OBJECT_CLASS_ASYNC_FROM_SYNC_ITERATOR */
#endif /* JERRY_ESNEXT */
#if JERRY_BUILTIN_DATAVIEW
JERRY_OBJECT_TYPE_DATAVIEW, /**< type of ECMA_OBJECT_CLASS_DATAVIEW */
#endif /* JERRY_BUILTIN_DATAVIEW */
#if JERRY_BUILTIN_CONTAINER
JERRY_OBJECT_TYPE_CONTAINER, /**< type of ECMA_OBJECT_CLASS_CONTAINER */
#endif /* JERRY_BUILTIN_CONTAINER */
/* Normal objects. */
JERRY_OBJECT_TYPE_BOOLEAN, /**< type of ECMA_OBJECT_CLASS_BOOLEAN */
JERRY_OBJECT_TYPE_NUMBER, /**< type of ECMA_OBJECT_CLASS_NUMBER */
JERRY_OBJECT_TYPE_ERROR, /**< type of ECMA_OBJECT_CLASS_ERROR */
JERRY_OBJECT_TYPE_GENERIC, /**< type of ECMA_OBJECT_CLASS_INTERNAL_OBJECT */
#if JERRY_PARSER
JERRY_OBJECT_TYPE_SCRIPT, /**< type of ECMA_OBJECT_CLASS_SCRIPT */
#endif /* JERRY_PARSER */
#if JERRY_BUILTIN_DATE
JERRY_OBJECT_TYPE_DATE, /**< type of ECMA_OBJECT_CLASS_DATE */
#endif /* JERRY_BUILTIN_DATE */
#if JERRY_BUILTIN_REGEXP
JERRY_OBJECT_TYPE_REGEXP, /**< type of ECMA_OBJECT_CLASS_REGEXP */
#endif /* JERRY_BUILTIN_REGEXP */
#if JERRY_ESNEXT
JERRY_OBJECT_TYPE_SYMBOL, /**< type of ECMA_OBJECT_CLASS_SYMBOL */
JERRY_OBJECT_TYPE_ITERATOR, /**< type of ECMA_OBJECT_CLASS_STRING_ITERATOR */
#endif /* JERRY_ESNEXT */
#if JERRY_BUILTIN_TYPEDARRAY
JERRY_OBJECT_TYPE_ARRAYBUFFER, /**< type of ECMA_OBJECT_CLASS_ARRAY_BUFFER */
#if JERRY_BUILTIN_SHAREDARRAYBUFFER
JERRY_OBJECT_TYPE_SHARED_ARRAY_BUFFER, /**< type of ECMA_OBJECT_CLASS_SHARED_ARRAY_BUFFER */
#endif /* JERRY_BUILTIN_SHAREDARRAYBUFFER */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_BUILTIN_BIGINT
JERRY_OBJECT_TYPE_BIGINT, /**< type of ECMA_OBJECT_CLASS_BIGINT */
#endif /* JERRY_BUILTIN_BIGINT */
#if JERRY_BUILTIN_WEAKREF
JERRY_OBJECT_TYPE_WEAKREF, /**< type of ECMA_OBJECT_CLASS_WEAKREF */
#endif /* JERRY_BUILTIN_WEAKREF */
};
JERRY_STATIC_ASSERT (sizeof (jerry_class_object_type) == ECMA_OBJECT_CLASS__MAX,
jerry_class_object_type_must_have_object_class_max_elements);
/**
* Get the object type of the given value
*
* @return JERRY_OBJECT_TYPE_NONE - if the given value is not an object
* jerry_object_type_t value - otherwise
*/
jerry_object_type_t
jerry_object_type (const jerry_value_t value) /**< input value to check */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (value))
{
return JERRY_OBJECT_TYPE_NONE;
}
ecma_object_t *obj_p = ecma_get_object_from_value (value);
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
switch (ecma_get_object_type (obj_p))
{
case ECMA_OBJECT_TYPE_CLASS:
case ECMA_OBJECT_TYPE_BUILT_IN_CLASS:
{
JERRY_ASSERT (ext_obj_p->u.cls.type < ECMA_OBJECT_CLASS__MAX);
return jerry_class_object_type[ext_obj_p->u.cls.type];
}
case ECMA_OBJECT_TYPE_ARRAY:
case ECMA_OBJECT_TYPE_BUILT_IN_ARRAY:
{
return JERRY_OBJECT_TYPE_ARRAY;
}
#if JERRY_ESNEXT
case ECMA_OBJECT_TYPE_PROXY:
{
return JERRY_OBJECT_TYPE_PROXY;
}
#endif /* JERRY_ESNEXT */
case ECMA_OBJECT_TYPE_FUNCTION:
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
case ECMA_OBJECT_TYPE_NATIVE_FUNCTION:
case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
{
return JERRY_OBJECT_TYPE_FUNCTION;
}
default:
{
break;
}
}
return JERRY_OBJECT_TYPE_GENERIC;
} /* jerry_object_type */
/**
* Get the function type of the given value
*
* @return JERRY_FUNCTION_TYPE_NONE - if the given value is not a function object
* jerry_function_type_t value - otherwise
*/
jerry_function_type_t
jerry_function_type (const jerry_value_t value) /**< input value to check */
{
jerry_assert_api_enabled ();
if (ecma_is_value_object (value))
{
ecma_object_t *obj_p = ecma_get_object_from_value (value);
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
switch (ecma_get_object_type (obj_p))
{
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
return JERRY_FUNCTION_TYPE_BOUND;
}
case ECMA_OBJECT_TYPE_NATIVE_FUNCTION:
case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
{
return JERRY_FUNCTION_TYPE_GENERIC;
}
case ECMA_OBJECT_TYPE_FUNCTION:
{
const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_obj_p);
switch (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags))
{
#if JERRY_ESNEXT
case CBC_FUNCTION_ARROW:
case CBC_FUNCTION_ASYNC_ARROW:
{
return JERRY_FUNCTION_TYPE_ARROW;
}
case CBC_FUNCTION_GENERATOR:
case CBC_FUNCTION_ASYNC_GENERATOR:
{
return JERRY_FUNCTION_TYPE_GENERATOR;
}
#endif /* JERRY_ESNEXT */
case CBC_FUNCTION_ACCESSOR:
{
return JERRY_FUNCTION_TYPE_ACCESSOR;
}
default:
{
break;
}
}
return JERRY_FUNCTION_TYPE_GENERIC;
}
default:
{
break;
}
}
}
return JERRY_FUNCTION_TYPE_NONE;
} /* jerry_function_type */
/**
* Get the itearator type of the given value
*
* @return JERRY_ITERATOR_TYPE_NONE - if the given value is not an iterator object
* jerry_iterator_type_t value - otherwise
*/
jerry_iterator_type_t
jerry_iterator_type (const jerry_value_t value) /**< input value to check */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
if (ecma_is_value_object (value))
{
ecma_object_t *obj_p = ecma_get_object_from_value (value);
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_CLASS)
{
switch (ext_obj_p->u.cls.type)
{
case ECMA_OBJECT_CLASS_ARRAY_ITERATOR:
{
return JERRY_ITERATOR_TYPE_ARRAY;
}
#if JERRY_BUILTIN_CONTAINER
case ECMA_OBJECT_CLASS_SET_ITERATOR:
{
return JERRY_ITERATOR_TYPE_SET;
}
case ECMA_OBJECT_CLASS_MAP_ITERATOR:
{
return JERRY_ITERATOR_TYPE_MAP;
}
#endif /* JERRY_BUILTIN_CONTAINER */
case ECMA_OBJECT_CLASS_STRING_ITERATOR:
{
return JERRY_ITERATOR_TYPE_STRING;
}
default:
{
break;
}
}
}
}
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (value);
#endif /* JERRY_ESNEXT */
return JERRY_ITERATOR_TYPE_NONE;
} /* jerry_iterator_type */
/**
* Check if the specified feature is enabled.
*
* @return true - if the specified feature is enabled,
* false - otherwise
*/
bool
jerry_feature_enabled (const jerry_feature_t feature) /**< feature to check */
{
JERRY_ASSERT (feature < JERRY_FEATURE__COUNT);
return (false
#if JERRY_CPOINTER_32_BIT
|| feature == JERRY_FEATURE_CPOINTER_32_BIT
#endif /* JERRY_CPOINTER_32_BIT */
#if JERRY_ERROR_MESSAGES
|| feature == JERRY_FEATURE_ERROR_MESSAGES
#endif /* JERRY_ERROR_MESSAGES */
#if JERRY_PARSER
|| feature == JERRY_FEATURE_JS_PARSER
#endif /* JERRY_PARSER */
#if JERRY_MEM_STATS
|| feature == JERRY_FEATURE_HEAP_STATS
#endif /* JERRY_MEM_STATS */
#if JERRY_PARSER_DUMP_BYTE_CODE
|| feature == JERRY_FEATURE_PARSER_DUMP
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */
#if JERRY_REGEXP_DUMP_BYTE_CODE
|| feature == JERRY_FEATURE_REGEXP_DUMP
#endif /* JERRY_REGEXP_DUMP_BYTE_CODE */
#if JERRY_SNAPSHOT_SAVE
|| feature == JERRY_FEATURE_SNAPSHOT_SAVE
#endif /* JERRY_SNAPSHOT_SAVE */
#if JERRY_SNAPSHOT_EXEC
|| feature == JERRY_FEATURE_SNAPSHOT_EXEC
#endif /* JERRY_SNAPSHOT_EXEC */
#if JERRY_DEBUGGER
|| feature == JERRY_FEATURE_DEBUGGER
#endif /* JERRY_DEBUGGER */
#if JERRY_VM_HALT
|| feature == JERRY_FEATURE_VM_EXEC_STOP
#endif /* JERRY_VM_HALT */
#if JERRY_VM_THROW
|| feature == JERRY_FEATURE_VM_THROW
#endif /* JERRY_VM_THROW */
#if JERRY_BUILTIN_JSON
|| feature == JERRY_FEATURE_JSON
#endif /* JERRY_BUILTIN_JSON */
#if JERRY_ESNEXT
|| feature == JERRY_FEATURE_PROMISE || feature == JERRY_FEATURE_SYMBOL
#endif /* JERRY_ESNEXT */
#if JERRY_BUILTIN_TYPEDARRAY
|| feature == JERRY_FEATURE_TYPEDARRAY
#endif /* JERRY_BUILTIN_TYPEDARRAY */
#if JERRY_BUILTIN_DATAVIEW
|| feature == JERRY_FEATURE_DATAVIEW
#endif /* JERRY_BUILTIN_DATAVIEW */
#if JERRY_BUILTIN_PROXY
|| feature == JERRY_FEATURE_PROXY
#endif /* JERRY_BUILTIN_PROXY */
#if JERRY_BUILTIN_DATE
|| feature == JERRY_FEATURE_DATE
#endif /* JERRY_BUILTIN_DATE */
#if JERRY_BUILTIN_REGEXP
|| feature == JERRY_FEATURE_REGEXP
#endif /* JERRY_BUILTIN_REGEXP */
#if JERRY_LINE_INFO
|| feature == JERRY_FEATURE_LINE_INFO
#endif /* JERRY_LINE_INFO */
#if JERRY_LOGGING
|| feature == JERRY_FEATURE_LOGGING
#endif /* JERRY_LOGGING */
#if JERRY_BUILTIN_GLOBAL_THIS
|| feature == JERRY_FEATURE_GLOBAL_THIS
#endif /* JERRY_BUILTIN_GLOBAL_THIS */
#if JERRY_BUILTIN_CONTAINER
|| feature == JERRY_FEATURE_MAP || feature == JERRY_FEATURE_SET || feature == JERRY_FEATURE_WEAKMAP
|| feature == JERRY_FEATURE_WEAKSET
#endif /* JERRY_BUILTIN_CONTAINER */
#if JERRY_BUILTIN_WEAKREF
|| feature == JERRY_FEATURE_WEAKREF
#endif /* JERRY_BUILTIN_WEAKREF */
#if JERRY_BUILTIN_BIGINT
|| feature == JERRY_FEATURE_BIGINT
#endif /* JERRY_BUILTIN_BIGINT */
#if JERRY_BUILTIN_REALMS
|| feature == JERRY_FEATURE_REALM
#endif /* JERRY_BUILTIN_REALMS */
#if JERRY_PROMISE_CALLBACK
|| feature == JERRY_FEATURE_PROMISE_CALLBACK
#endif /* JERRY_PROMISE_CALLBACK */
#if JERRY_MODULE_SYSTEM
|| feature == JERRY_FEATURE_MODULE
#endif /* JERRY_MODULE_SYSTEM */
#if JERRY_FUNCTION_TO_STRING
|| feature == JERRY_FEATURE_FUNCTION_TO_STRING
#endif /* JERRY_FUNCTION_TO_STRING */
);
} /* jerry_feature_enabled */
/**
* Perform binary operation on the given operands (==, ===, <, >, etc.).
*
* @return error - if argument has an error flag or operation is unsuccessful or unsupported
* true/false - the result of the binary operation on the given operands otherwise
*/
jerry_value_t
jerry_binary_op (jerry_binary_op_t operation, /**< operation */
const jerry_value_t lhs, /**< first operand */
const jerry_value_t rhs) /**< second operand */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (lhs) || ecma_is_value_exception (rhs))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
switch (operation)
{
case JERRY_BIN_OP_EQUAL:
{
return jerry_return (ecma_op_abstract_equality_compare (lhs, rhs));
}
case JERRY_BIN_OP_STRICT_EQUAL:
{
return ecma_make_boolean_value (ecma_op_strict_equality_compare (lhs, rhs));
}
case JERRY_BIN_OP_LESS:
{
return jerry_return (opfunc_relation (lhs, rhs, true, false));
}
case JERRY_BIN_OP_LESS_EQUAL:
{
return jerry_return (opfunc_relation (lhs, rhs, false, true));
}
case JERRY_BIN_OP_GREATER:
{
return jerry_return (opfunc_relation (lhs, rhs, false, false));
}
case JERRY_BIN_OP_GREATER_EQUAL:
{
return jerry_return (opfunc_relation (lhs, rhs, true, true));
}
case JERRY_BIN_OP_INSTANCEOF:
{
if (!ecma_is_value_object (lhs) || !ecma_op_is_callable (rhs))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_object_t *proto_obj_p = ecma_get_object_from_value (rhs);
return jerry_return (ecma_op_object_has_instance (proto_obj_p, lhs));
}
case JERRY_BIN_OP_ADD:
{
return jerry_return (opfunc_addition (lhs, rhs));
}
case JERRY_BIN_OP_SUB:
case JERRY_BIN_OP_MUL:
case JERRY_BIN_OP_DIV:
case JERRY_BIN_OP_REM:
{
return jerry_return (do_number_arithmetic (operation - ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET, lhs, rhs));
}
default:
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_UNSUPPORTED_BINARY_OPERATION));
}
}
} /* jerry_binary_op */
/**
* Create an abort value containing the argument value. If the second argument is true
* the function will take ownership ofthe input value, otherwise the value will be copied.
*
* @return api abort value
*/
jerry_value_t
jerry_throw_abort (jerry_value_t value, /**< api value */
bool take_ownership) /**< release api value */
{
jerry_assert_api_enabled ();
if (JERRY_UNLIKELY (ecma_is_value_exception (value)))
{
/* This is a rare case so it is optimized for
* binary size rather than performance. */
if (jerry_value_is_abort (value))
{
return take_ownership ? value : jerry_value_copy (value);
}
value = jerry_exception_value (value, take_ownership);
take_ownership = true;
}
if (!take_ownership)
{
value = ecma_copy_value (value);
}
return ecma_create_exception (value, ECMA_ERROR_API_FLAG_ABORT);
} /* jerry_throw_abort */
/**
* Create an exception value containing the argument value. If the second argument is true
* the function will take ownership ofthe input value, otherwise the value will be copied.
*
* @return exception value
*/
jerry_value_t
jerry_throw_value (jerry_value_t value, /**< value */
bool take_ownership) /**< take ownership of the value */
{
jerry_assert_api_enabled ();
if (JERRY_UNLIKELY (ecma_is_value_exception (value)))
{
/* This is a rare case so it is optimized for
* binary size rather than performance. */
if (!jerry_value_is_abort (value))
{
return take_ownership ? value : jerry_value_copy (value);
}
value = jerry_exception_value (value, take_ownership);
take_ownership = true;
}
if (!take_ownership)
{
value = ecma_copy_value (value);
}
return ecma_create_exception (value, ECMA_ERROR_API_FLAG_NONE);
} /* jerry_throw_value */
/**
* Get the value contained in an exception. If the second argument is true
* it will release the argument exception value in the process.
*
* @return value in exception
*/
jerry_value_t
jerry_exception_value (jerry_value_t value, /**< api value */
bool free_exception) /**< release api value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_exception (value))
{
return free_exception ? value : ecma_copy_value (value);
}
jerry_value_t ret_val = jerry_value_copy (ecma_get_extended_primitive_from_value (value)->u.value);
if (free_exception)
{
jerry_value_free (value);
}
return ret_val;
} /* jerry_exception_value */
/**
* Set new decorator callback for Error objects. The decorator can
* create or update any properties of the newly created Error object.
*/
void
jerry_error_on_created (jerry_error_object_created_cb_t callback, /**< new callback */
void *user_p) /**< user pointer passed to the callback */
{
jerry_assert_api_enabled ();
JERRY_CONTEXT (error_object_created_callback_p) = callback;
JERRY_CONTEXT (error_object_created_callback_user_p) = user_p;
} /* jerry_error_on_created */
/**
* When JERRY_VM_THROW is enabled, the callback passed to this
* function is called when an error is thrown in ECMAScript code.
*/
void
jerry_on_throw (jerry_throw_cb_t callback, /**< callback which is called on throws */
void *user_p) /**< pointer passed to the function */
{
#if JERRY_VM_THROW
JERRY_CONTEXT (vm_throw_callback_p) = callback;
JERRY_CONTEXT (vm_throw_callback_user_p) = user_p;
#else /* !JERRY_VM_THROW */
JERRY_UNUSED (callback);
JERRY_UNUSED (user_p);
#endif /* JERRY_VM_THROW */
} /* jerry_on_throw */
/**
* Checks whether the callback set by jerry_on_throw captured the error
*
* @return true, if the vm throw callback captured the error
* false, otherwise
*/
bool
jerry_exception_is_captured (const jerry_value_t value) /**< exception value */
{
jerry_assert_api_enabled ();
#if JERRY_VM_THROW
if (!ecma_is_value_exception (value))
{
return false;
}
ecma_extended_primitive_t *error_ref_p = ecma_get_extended_primitive_from_value (value);
return (error_ref_p->refs_and_type & ECMA_ERROR_API_FLAG_THROW_CAPTURED) != 0;
#else /* !JERRY_VM_THROW */
JERRY_UNUSED (value);
return false;
#endif /* JERRY_VM_THROW */
} /* jerry_exception_is_captured */
/**
* Sets whether the callback set by jerry_on_throw should capture the exception or not
*/
void
jerry_exception_allow_capture (jerry_value_t value, /**< exception value */
bool should_capture) /**< callback should capture this error */
{
jerry_assert_api_enabled ();
#if JERRY_VM_THROW
if (!ecma_is_value_exception (value))
{
return;
}
ecma_extended_primitive_t *error_ref_p = ecma_get_extended_primitive_from_value (value);
if (should_capture)
{
error_ref_p->refs_and_type &= ~(uint32_t) ECMA_ERROR_API_FLAG_THROW_CAPTURED;
return;
}
error_ref_p->refs_and_type |= ECMA_ERROR_API_FLAG_THROW_CAPTURED;
#else /* !JERRY_VM_THROW */
JERRY_UNUSED (value);
JERRY_UNUSED (should_capture);
#endif /* JERRY_VM_THROW */
} /* jerry_exception_allow_capture */
/**
* Check if the given value is an Error object.
*
* @return true - if it is an Error object
* false - otherwise
*/
bool
jerry_value_is_error (const jerry_value_t value) /**< api value */
{
return ecma_is_value_object (value)
&& ecma_object_class_is (ecma_get_object_from_value (value), ECMA_OBJECT_CLASS_ERROR);
} /* jerry_value_is_error */
/**
* Return the type of the Error object if possible.
*
* @return one of the jerry_error_t value as the type of the Error object
* JERRY_ERROR_NONE - if the input value is not an Error object
*/
jerry_error_t
jerry_error_type (jerry_value_t value) /**< api value */
{
if (JERRY_UNLIKELY (ecma_is_value_exception (value)))
{
value = ecma_get_extended_primitive_from_value (value)->u.value;
}
if (!ecma_is_value_object (value))
{
return JERRY_ERROR_NONE;
}
ecma_object_t *object_p = ecma_get_object_from_value (value);
/* TODO(check if error object) */
jerry_error_t error_type = ecma_get_error_type (object_p);
return (jerry_error_t) error_type;
} /* jerry_error_type */
/**
* Get number from the specified value as a double.
*
* @return stored number as double
*/
double
jerry_value_as_number (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_number (value))
{
return 0;
}
return (double) ecma_get_number_from_value (value);
} /* jerry_value_as_number */
/**
* Call ToBoolean operation on the api value.
*
* @return true - if the logical value is true
* false - otherwise
*/
bool
jerry_value_to_boolean (const jerry_value_t value) /**< input value */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (value))
{
return false;
}
return ecma_op_to_boolean (value);
} /* jerry_value_to_boolean */
/**
* Call ToNumber operation on the api value.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return converted number value - if success
* thrown error - otherwise
*/
jerry_value_t
jerry_value_to_number (const jerry_value_t value) /**< input value */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
ecma_number_t num;
ecma_value_t ret_value = ecma_op_to_number (value, &num);
if (ECMA_IS_VALUE_ERROR (ret_value))
{
return ecma_create_exception_from_context ();
}
return ecma_make_number_value (num);
} /* jerry_value_to_number */
/**
* Call ToObject operation on the api value.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return converted object value - if success
* thrown error - otherwise
*/
jerry_value_t
jerry_value_to_object (const jerry_value_t value) /**< input value */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
return jerry_return (ecma_op_to_object (value));
} /* jerry_value_to_object */
/**
* Call ToPrimitive operation on the api value.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return converted primitive value - if success
* thrown error - otherwise
*/
jerry_value_t
jerry_value_to_primitive (const jerry_value_t value) /**< input value */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
return jerry_return (ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_NO));
} /* jerry_value_to_primitive */
/**
* Call the ToString ecma builtin operation on the api value.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return converted string value - if success
* thrown error - otherwise
*/
jerry_value_t
jerry_value_to_string (const jerry_value_t value) /**< input value */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
ecma_string_t *str_p = ecma_op_to_string (value);
if (JERRY_UNLIKELY (str_p == NULL))
{
return ecma_create_exception_from_context ();
}
return ecma_make_string_value (str_p);
} /* jerry_value_to_string */
/**
* Call the BigInt constructor ecma builtin operation on the api value.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return BigInt value - if success
* thrown error - otherwise
*/
jerry_value_t
jerry_value_to_bigint (const jerry_value_t value) /**< input value */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_BIGINT
if (ecma_is_value_exception (value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
return jerry_return (ecma_bigint_to_bigint (value, true));
#else /* !JERRY_BUILTIN_BIGINT */
JERRY_UNUSED (value);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_BIGINT_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_BIGINT */
} /* jerry_value_to_bigint */
/**
* Convert any number to integer number.
*
* Note:
* For non-number values 0 is returned.
*
* @return integer representation of the number.
*/
double
jerry_value_as_integer (const jerry_value_t value) /**< input value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_number (value))
{
return 0;
}
double number = ecma_get_number_from_value (value);
if (ecma_number_is_nan (number))
{
return ECMA_NUMBER_ZERO;
}
if (ecma_number_is_zero (number) || ecma_number_is_infinity (number))
{
return number;
}
ecma_number_t floor_fabs = (ecma_number_t) floor (fabs (number));
return ecma_number_is_negative (number) ? -floor_fabs : floor_fabs;
} /* jerry_value_as_integer */
/**
* Convert any number to int32 number.
*
* Note:
* For non-number values 0 is returned.
*
* @return int32 representation of the number.
*/
int32_t
jerry_value_as_int32 (const jerry_value_t value) /**< input value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_number (value))
{
return 0;
}
return ecma_number_to_int32 (ecma_get_number_from_value (value));
} /* jerry_value_as_int32 */
/**
* Convert any number to uint32 number.
*
* Note:
* For non-number values 0 is returned.
*
* @return uint32 representation of the number.
*/
uint32_t
jerry_value_as_uint32 (const jerry_value_t value) /**< input value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_number (value))
{
return 0;
}
return ecma_number_to_uint32 (ecma_get_number_from_value (value));
} /* jerry_value_as_uint32 */
/**
* Take additional ownership over the argument value.
* The value will be copied by reference when possible, changes made to the new value will be reflected
* in the original.
*
* @return copied value
*/
jerry_value_t
jerry_value_copy (const jerry_value_t value) /**< value */
{
jerry_assert_api_enabled ();
if (JERRY_UNLIKELY (ecma_is_value_exception (value)))
{
ecma_ref_extended_primitive (ecma_get_extended_primitive_from_value (value));
return value;
}
return ecma_copy_value (value);
} /* jerry_value_copy */
/**
* Release ownership of the argument value
*/
void
jerry_value_free (jerry_value_t value) /**< value */
{
jerry_assert_api_enabled ();
if (JERRY_UNLIKELY (ecma_is_value_exception (value)))
{
ecma_deref_exception (ecma_get_extended_primitive_from_value (value));
return;
}
ecma_free_value (value);
} /* jerry_value_free */
/**
* Create an array object value
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the constructed array object
*/
jerry_value_t
jerry_array (jerry_length_t length) /**< length of array */
{
jerry_assert_api_enabled ();
ecma_object_t *array_p = ecma_op_new_array_object (length);
return ecma_make_object_value (array_p);
} /* jerry_array */
/**
* Create a jerry_value_t representing a boolean value from the given boolean parameter.
*
* @return value of the created boolean
*/
jerry_value_t
jerry_boolean (bool value) /**< bool value from which a jerry_value_t will be created */
{
jerry_assert_api_enabled ();
return ecma_make_boolean_value (value);
} /* jerry_boolean */
/**
* Create an Error object with the provided string value as the error message.
* If the message value is not a string, the created error will not have a message property.
*
* @return Error object
*/
jerry_value_t
jerry_error (jerry_error_t error_type, /**< type of error */
const jerry_value_t message) /**< message of the error */
{
jerry_assert_api_enabled ();
ecma_string_t *message_p = NULL;
if (ecma_is_value_string (message))
{
message_p = ecma_get_string_from_value (message);
}
ecma_object_t *error_object_p = ecma_new_standard_error ((jerry_error_t) error_type, message_p);
return ecma_make_object_value (error_object_p);
} /* jerry_error */
/**
* Create an Error object with a zero-terminated string as a message. If the message string is NULL, the created error
* will not have a message property.
*
* @return Error object
*/
jerry_value_t
jerry_error_sz (jerry_error_t error_type, /**< type of error */
const char *message_p) /**< value of 'message' property
* of constructed error object */
{
jerry_value_t message = ECMA_VALUE_UNDEFINED;
if (message_p != NULL)
{
message = jerry_string_sz (message_p);
}
ecma_value_t error = jerry_error (error_type, message);
ecma_free_value (message);
return error;
} /* jerry_error_sz */
/**
* Create an exception by constructing an Error object with the specified type and the provided string value as the
* error message. If the message value is not a string, the created error will not have a message property.
*
* @return exception value
*/
jerry_value_t
jerry_throw (jerry_error_t error_type, /**< type of error */
const jerry_value_t message) /**< message value */
{
return jerry_throw_value (jerry_error (error_type, message), true);
} /* jerry_throw */
/**
* Create an exception by constructing an Error object with the specified type and the provided zero-terminated ASCII
* string as the error message. If the message string is NULL, the created error will not have a message property.
*
* @return exception value
*/
jerry_value_t
jerry_throw_sz (jerry_error_t error_type, /**< type of error */
const char *message_p) /**< value of 'message' property
* of constructed error object */
{
return jerry_throw_value (jerry_error_sz (error_type, message_p), true);
} /* jerry_throw_sz */
/**
* Create an external function object
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the constructed function object
*/
jerry_value_t
jerry_function_external (jerry_external_handler_t handler) /**< native handler
* for the function */
{
jerry_assert_api_enabled ();
ecma_object_t *func_obj_p = ecma_op_create_external_function_object (handler);
return ecma_make_object_value (func_obj_p);
} /* jerry_function_external */
/**
* Creates a jerry_value_t representing a number value.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return jerry_value_t created from the given double argument.
*/
jerry_value_t
jerry_number (double value) /**< double value from which a jerry_value_t will be created */
{
jerry_assert_api_enabled ();
return ecma_make_number_value ((ecma_number_t) value);
} /* jerry_number */
/**
* Creates a jerry_value_t representing a positive or negative infinity value.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return jerry_value_t representing an infinity value.
*/
jerry_value_t
jerry_infinity (bool sign) /**< true for negative Infinity
* false for positive Infinity */
{
jerry_assert_api_enabled ();
return ecma_make_number_value (ecma_number_make_infinity (sign));
} /* jerry_infinity */
/**
* Creates a jerry_value_t representing a not-a-number value.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return jerry_value_t representing a not-a-number value.
*/
jerry_value_t
jerry_nan (void)
{
jerry_assert_api_enabled ();
return ecma_make_nan_value ();
} /* jerry_nan */
/**
* Creates a jerry_value_t representing an undefined value.
*
* @return value of undefined
*/
jerry_value_t
jerry_undefined (void)
{
jerry_assert_api_enabled ();
return ECMA_VALUE_UNDEFINED;
} /* jerry_undefined */
/**
* Creates and returns a jerry_value_t with type null object.
*
* @return jerry_value_t representing null
*/
jerry_value_t
jerry_null (void)
{
jerry_assert_api_enabled ();
return ECMA_VALUE_NULL;
} /* jerry_null */
/**
* Create new JavaScript object, like with new Object().
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the created object
*/
jerry_value_t
jerry_object (void)
{
jerry_assert_api_enabled ();
return ecma_make_object_value (ecma_op_create_object_object_noarg ());
} /* jerry_object */
/**
* Create an empty Promise object which can be resolved/rejected later
* by calling jerry_promise_resolve or jerry_promise_reject.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the created object
*/
jerry_value_t
jerry_promise (void)
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
return jerry_return (ecma_op_create_promise_object (ECMA_VALUE_EMPTY, ECMA_VALUE_UNDEFINED, NULL));
#else /* !JERRY_ESNEXT */
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROMISE_NOT_SUPPORTED));
#endif /* JERRY_ESNEXT */
} /* jerry_promise */
/**
* Create a new Proxy object with the given target and handler
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the created Proxy object
*/
jerry_value_t
jerry_proxy (const jerry_value_t target, /**< target argument */
const jerry_value_t handler) /**< handler argument */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (target) || ecma_is_value_exception (handler))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
#if JERRY_BUILTIN_PROXY
ecma_object_t *proxy_p = ecma_proxy_create (target, handler, 0);
if (proxy_p == NULL)
{
return ecma_create_exception_from_context ();
}
return ecma_make_object_value (proxy_p);
#else /* !JERRY_BUILTIN_PROXY */
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROXY_IS_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_PROXY */
} /* jerry_proxy */
#if JERRY_BUILTIN_PROXY
JERRY_STATIC_ASSERT ((int) JERRY_PROXY_SKIP_RESULT_VALIDATION == (int) ECMA_PROXY_SKIP_RESULT_VALIDATION,
jerry_and_ecma_proxy_skip_result_validation_must_be_equal);
#endif /* JERRY_BUILTIN_PROXY */
/**
* Create a new Proxy object with the given target, handler, and special options
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the created Proxy object
*/
jerry_value_t
jerry_proxy_custom (const jerry_value_t target, /**< target argument */
const jerry_value_t handler, /**< handler argument */
uint32_t flags) /**< jerry_proxy_custom_behavior_t option bits */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (target) || ecma_is_value_exception (handler))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
#if JERRY_BUILTIN_PROXY
flags &= JERRY_PROXY_SKIP_RESULT_VALIDATION;
ecma_object_t *proxy_p = ecma_proxy_create (target, handler, flags);
if (proxy_p == NULL)
{
return ecma_create_exception_from_context ();
}
return ecma_make_object_value (proxy_p);
#else /* !JERRY_BUILTIN_PROXY */
JERRY_UNUSED (flags);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROXY_IS_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_PROXY */
} /* jerry_proxy_custom */
/**
* Create string value from the input zero-terminated ASCII string.
*
* @return created string
*/
jerry_value_t
jerry_string_sz (const char *str_p) /**< pointer to string */
{
const jerry_char_t *data_p = (const jerry_char_t *) str_p;
return jerry_string (data_p, lit_zt_utf8_string_size (data_p), JERRY_ENCODING_CESU8);
} /* jerry_string_sz */
/**
* Create a string value from the input buffer using the specified encoding.
* The content of the buffer is assumed to be valid in the specified encoding, it's the callers responsibility to
* validate the input.
*
* See also: jerry_validate_string
*
* @return created string
*/
jerry_value_t
jerry_string (const jerry_char_t *buffer_p, /**< pointer to buffer */
jerry_size_t buffer_size, /**< buffer size */
jerry_encoding_t encoding) /**< buffer encoding */
{
jerry_assert_api_enabled ();
ecma_string_t *ecma_str_p = NULL;
JERRY_ASSERT (jerry_validate_string (buffer_p, buffer_size, encoding));
switch (encoding)
{
case JERRY_ENCODING_CESU8:
{
ecma_str_p = ecma_new_ecma_string_from_utf8 (buffer_p, buffer_size);
break;
}
case JERRY_ENCODING_UTF8:
{
ecma_str_p = ecma_new_ecma_string_from_utf8_converted_to_cesu8 (buffer_p, buffer_size);
break;
}
default:
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INVALID_ENCODING));
}
}
return ecma_make_string_value (ecma_str_p);
} /* jerry_string */
/**
* Create external string from input zero-terminated ASCII string.
*
* @return created external string
*/
jerry_value_t
jerry_string_external_sz (const char *str_p, /**< pointer to string */
void *user_p) /**< user pointer passed to the callback when the string is freed */
{
const jerry_char_t *data_p = (const jerry_char_t *) str_p;
return jerry_string_external (data_p, lit_zt_utf8_string_size (data_p), user_p);
} /* jerry_string_external_sz */
/**
* Create external string from a valid CESU-8 encoded string.
* The content of the buffer is assumed be encoded correctly, it's the callers responsibility to
* validate the input.
*
* See also: jerry_validate_string
*
* @return created external string
*/
jerry_value_t
jerry_string_external (const jerry_char_t *buffer_p, /**< pointer to string */
jerry_size_t buffer_size, /**< string size */
void *user_p) /**< user pointer passed to the callback when the string is freed */
{
jerry_assert_api_enabled ();
JERRY_ASSERT (jerry_validate_string (buffer_p, buffer_size, JERRY_ENCODING_CESU8));
ecma_string_t *ecma_str_p = ecma_new_ecma_external_string_from_cesu8 (buffer_p, buffer_size, user_p);
return ecma_make_string_value (ecma_str_p);
} /* jerry_string_external_sz_sz */
/**
* Create symbol with a description value
*
* Note: The given argument is converted to string. This operation can throw an exception.
*
* @return created symbol,
* or thrown exception
*/
jerry_value_t
jerry_symbol_with_description (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
#if JERRY_ESNEXT
return jerry_return (ecma_op_create_symbol (&value, 1));
#else /* !JERRY_ESNEXT */
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SYMBOL_NOT_SUPPORTED));
#endif /* JERRY_ESNEXT */
} /* jerry_symbol_with_description */
/**
* Create BigInt from a sequence of uint64 digits.
*
* Note: This operation can throw an exception.
*
* @return created bigint,
* or thrown exception
*/
jerry_value_t
jerry_bigint (const uint64_t *digits_p, /**< BigInt digits (lowest digit first) */
uint32_t digit_count, /**< number of BigInt digits */
bool sign) /**< sign bit, true if the result should be negative */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_BIGINT
return jerry_return (ecma_bigint_create_from_digits (digits_p, digit_count, sign));
#else /* !JERRY_BUILTIN_BIGINT */
JERRY_UNUSED (digits_p);
JERRY_UNUSED (digit_count);
JERRY_UNUSED (sign);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_BIGINT_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_BIGINT */
} /* jerry_bigint */
/**
* Creates a RegExp object with the given ASCII pattern and flags.
*
* @return value of the constructed RegExp object.
*/
jerry_value_t
jerry_regexp_sz (const char *pattern_p, /**< RegExp pattern as zero-terminated ASCII string */
uint16_t flags) /**< RegExp flags */
{
jerry_assert_api_enabled ();
jerry_value_t pattern = jerry_string_sz (pattern_p);
jerry_value_t result = jerry_regexp (pattern, flags);
jerry_value_free (pattern);
return jerry_return (result);
} /* jerry_regexp_sz */
/**
* Creates a RegExp object with the given pattern and flags.
*
* @return value of the constructed RegExp object.
*/
jerry_value_t
jerry_regexp (const jerry_value_t pattern, /**< pattern string */
uint16_t flags) /**< RegExp flags */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_REGEXP
if (!ecma_is_value_string (pattern))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL);
if (JERRY_UNLIKELY (regexp_obj_p == NULL))
{
return ecma_create_exception_from_context ();
}
jerry_value_t result = ecma_op_create_regexp_with_flags (regexp_obj_p, pattern, flags);
return jerry_return (result);
#else /* !JERRY_BUILTIN_REGEXP */
JERRY_UNUSED (pattern);
JERRY_UNUSED (flags);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_REGEXP_IS_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_REGEXP */
} /* jerry_regexp */
/**
* Creates a new realm (global object).
*
* @return new realm object
*/
jerry_value_t
jerry_realm (void)
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_REALMS
ecma_global_object_t *global_object_p = ecma_builtin_create_global_object ();
return ecma_make_object_value ((ecma_object_t *) global_object_p);
#else /* !JERRY_BUILTIN_REALMS */
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_REALMS_ARE_DISABLED));
#endif /* JERRY_BUILTIN_REALMS */
} /* jerry_realm */
/**
* Get length of an array object
*
* Note:
* Returns 0, if the value parameter is not an array object.
*
* @return length of the given array
*/
jerry_length_t
jerry_array_length (const jerry_value_t value) /**< api value */
{
jerry_assert_api_enabled ();
if (!jerry_value_is_object (value))
{
return 0;
}
ecma_object_t *object_p = ecma_get_object_from_value (value);
if (JERRY_LIKELY (ecma_get_object_base_type (object_p) == ECMA_OBJECT_BASE_TYPE_ARRAY))
{
return ecma_array_get_length (object_p);
}
return 0;
} /* jerry_array_length */
/**
* Get the size of a string value in the specified encoding.
*
* @return number of bytes required by the string,
* 0 - if value is not a string
*/
jerry_size_t
jerry_string_size (const jerry_value_t value, /**< input string */
jerry_encoding_t encoding) /**< encoding */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_string (value))
{
return 0;
}
switch (encoding)
{
case JERRY_ENCODING_CESU8:
{
return ecma_string_get_size (ecma_get_string_from_value (value));
}
case JERRY_ENCODING_UTF8:
{
return ecma_string_get_utf8_size (ecma_get_string_from_value (value));
}
default:
{
return 0;
}
}
} /* jerry_string_size */
/**
* Get length of a string value
*
* @return number of characters in the string
* 0 - if value is not a string
*/
jerry_length_t
jerry_string_length (const jerry_value_t value) /**< input string */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_string (value))
{
return 0;
}
return ecma_string_get_length (ecma_get_string_from_value (value));
} /* jerry_string_length */
/**
* Copy the characters of a string into the specified buffer using the specified encoding. The string is truncated to
* fit the buffer. If the value is not a string, nothing will be copied to the buffer.
*
* @return number of bytes copied to the buffer
*/
jerry_size_t
jerry_string_to_buffer (const jerry_value_t value, /**< input string value */
jerry_encoding_t encoding, /**< output encoding */
jerry_char_t *buffer_p, /**< [out] output characters buffer */
jerry_size_t buffer_size) /**< size of output buffer */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_string (value) || buffer_p == NULL)
{
return 0;
}
ecma_string_t *str_p = ecma_get_string_from_value (value);
return ecma_string_copy_to_buffer (str_p, (lit_utf8_byte_t *) buffer_p, buffer_size, encoding);
} /* jerry_string_to_char_buffer */
/**
* Create a substring of the input string value.
* Return an empty string if input value is not a string.
*
* @param value the input string value
* @param start start position of the substring
* @param end end position of the substring
*
* @return created string
*/
jerry_value_t
jerry_string_substr (const jerry_value_t value, jerry_length_t start, jerry_length_t end)
{
if (!ecma_is_value_string (value))
{
return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
}
return ecma_make_string_value (ecma_string_substr (ecma_get_string_from_value (value), start, end));
} /* jerry_string_substr */
/**
* Iterate over the input string value in the specified encoding, visiting each unit of the encoded string once. If
* the input value is not a string, the function will do nothing.
*
* @param value the input string value
* @param callback callback function called for each byte of the encoded string.
* @param encoding the requested encoding for the string
* @param user_p User pointer passed to the callback function
*/
void
jerry_string_iterate (const jerry_value_t value,
jerry_encoding_t encoding,
jerry_string_iterate_cb_t callback,
void *user_p)
{
if (!ecma_is_value_string (value))
{
return;
}
ecma_string_t *str_p = ecma_get_string_from_value (value);
ECMA_STRING_TO_UTF8_STRING (str_p, buffer_p, buffer_size);
const lit_utf8_byte_t *current_p = buffer_p;
const lit_utf8_byte_t *end_p = buffer_p + buffer_size;
switch (encoding)
{
case JERRY_ENCODING_UTF8:
{
while (current_p < end_p)
{
if (JERRY_UNLIKELY (*current_p >= LIT_UTF8_3_BYTE_MARKER))
{
lit_code_point_t cp;
lit_utf8_size_t read_size = lit_read_code_point_from_cesu8 (current_p, end_p, &cp);
lit_utf8_byte_t bytes[LIT_UTF8_MAX_BYTES_IN_CODE_POINT];
lit_utf8_size_t encoded_size = lit_code_point_to_utf8 (cp, bytes);
for (uint32_t i = 0; i < encoded_size; i++)
{
callback (bytes[i], user_p);
}
current_p += read_size;
continue;
}
callback (*current_p++, user_p);
}
break;
}
case JERRY_ENCODING_CESU8:
{
while (current_p < end_p)
{
callback (*current_p++, user_p);
}
break;
}
default:
{
break;
}
}
ECMA_FINALIZE_UTF8_STRING (buffer_p, buffer_size);
} /* jerry_string_iterate */
/**
* Sets the global callback which is called when an external string is freed.
*/
void
jerry_string_external_on_free (jerry_external_string_free_cb_t callback) /**< free callback */
{
JERRY_CONTEXT (external_string_free_callback_p) = callback;
} /* jerry_string_external_on_free */
/**
* Returns the user pointer assigned to an external string.
*
* @return user pointer, if value is an external string
* NULL, otherwise
*/
void *
jerry_string_user_ptr (const jerry_value_t value, /**< string value */
bool *is_external) /**< [out] true - if value is an external string,
* false - otherwise */
{
if (is_external != NULL)
{
*is_external = false;
}
if (!ecma_is_value_string (value))
{
return NULL;
}
ecma_string_t *string_p = ecma_get_string_from_value (value);
if (ECMA_IS_DIRECT_STRING (string_p)
|| ECMA_STRING_GET_CONTAINER (string_p) != ECMA_STRING_CONTAINER_LONG_OR_EXTERNAL_STRING)
{
return NULL;
}
ecma_long_string_t *long_string_p = (ecma_long_string_t *) string_p;
if (long_string_p->string_p == ECMA_LONG_STRING_BUFFER_START (long_string_p))
{
return NULL;
}
if (is_external != NULL)
{
*is_external = true;
}
return ((ecma_external_string_t *) string_p)->user_p;
} /* jerry_string_user_ptr */
/**
* Checks whether the object or it's prototype objects have the given property.
*
* @return raised error - if the operation fail
* true/false API value - depend on whether the property exists
*/
jerry_value_t
jerry_object_has (const jerry_value_t object, /**< object value */
const jerry_value_t key) /**< property name (string value) */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return ECMA_VALUE_FALSE;
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (key);
return jerry_return (ecma_op_object_has_property (obj_p, prop_name_p));
} /* jerry_object_has */
/**
* Checks whether the object or it's prototype objects have the given property.
*
* @return raised error - if the operation fail
* true/false API value - depend on whether the property exists
*/
jerry_value_t
jerry_object_has_sz (const jerry_value_t object, /**< object value */
const char *key_p) /**< property key */
{
jerry_assert_api_enabled ();
jerry_value_t key_str = jerry_string_sz (key_p);
jerry_value_t result = jerry_object_has (object, key_str);
ecma_free_value (key_str);
return result;
} /* jerry_object_has */
/**
* Checks whether the object has the given property.
*
* @return ECMA_VALUE_ERROR - if the operation raises error
* ECMA_VALUE_{TRUE, FALSE} - based on whether the property exists
*/
jerry_value_t
jerry_object_has_own (const jerry_value_t object, /**< object value */
const jerry_value_t key) /**< property name (string value) */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return ECMA_VALUE_FALSE;
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (key);
return jerry_return (ecma_op_object_has_own_property (obj_p, prop_name_p));
} /* jerry_has_own_property */
/**
* Checks whether the object has the given internal property.
*
* @return true - if the internal property exists
* false - otherwise
*/
bool
jerry_object_has_internal (const jerry_value_t object, /**< object value */
const jerry_value_t key) /**< property name value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return false;
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL);
if (ecma_op_object_is_fast_array (obj_p))
{
return false;
}
ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p);
if (property_p == NULL)
{
return false;
}
ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (key));
return property_p != NULL;
} /* jerry_object_has_internal */
/**
* Delete a property from an object.
*
* @return boolean value - wether the property was deleted successfully
* exception - otherwise
*/
jerry_value_t
jerry_object_delete (jerry_value_t object, /**< object value */
const jerry_value_t key) /**< property name (string value) */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return false;
}
return ecma_op_object_delete (ecma_get_object_from_value (object), ecma_get_prop_name_from_value (key), false);
} /* jerry_object_delete */
/**
* Delete a property from an object.
*
* @return boolean value - wether the property was deleted successfully
* exception - otherwise
*/
jerry_value_t
jerry_object_delete_sz (jerry_value_t object, /**< object value */
const char *key_p) /**< property key */
{
jerry_assert_api_enabled ();
jerry_value_t key_str = jerry_string_sz (key_p);
jerry_value_t result = jerry_object_delete (object, key_str);
ecma_free_value (key_str);
return result;
} /* jerry_object_delete */
/**
* Delete indexed property from the specified object.
*
* @return boolean value - wether the property was deleted successfully
* false - otherwise
*/
jerry_value_t
jerry_object_delete_index (jerry_value_t object, /**< object value */
uint32_t index) /**< index to be written */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object))
{
return false;
}
ecma_string_t *str_idx_p = ecma_new_ecma_string_from_uint32 (index);
ecma_value_t ret_value = ecma_op_object_delete (ecma_get_object_from_value (object), str_idx_p, false);
ecma_deref_ecma_string (str_idx_p);
return ret_value;
} /* jerry_object_delete_index */
/**
* Delete an internal property from an object.
*
* @return true - if property was deleted successfully
* false - otherwise
*/
bool
jerry_object_delete_internal (jerry_value_t object, /**< object value */
const jerry_value_t key) /**< property name value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return false;
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL);
if (ecma_op_object_is_fast_array (obj_p))
{
return true;
}
ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p);
if (property_p == NULL)
{
return true;
}
ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (key));
if (property_p == NULL)
{
return true;
}
ecma_delete_property (internal_object_p, ECMA_PROPERTY_VALUE_PTR (property_p));
return true;
} /* jerry_object_delete_internal */
/**
* Get value of a property to the specified object with the given name.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the property - if success
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_get (const jerry_value_t object, /**< object value */
const jerry_value_t key) /**< property name (string value) */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
jerry_value_t ret_value =
ecma_op_object_get (ecma_get_object_from_value (object), ecma_get_prop_name_from_value (key));
return jerry_return (ret_value);
} /* jerry_object_get */
/**
* Get value of a property to the specified object with the given name.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the property - if success
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_get_sz (const jerry_value_t object, /**< object value */
const char *key_p) /**< property key */
{
jerry_assert_api_enabled ();
jerry_value_t key_str = jerry_string_sz (key_p);
jerry_value_t result = jerry_object_get (object, key_str);
ecma_free_value (key_str);
return result;
} /* jerry_object_get */
/**
* Get value by an index from the specified object.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the property specified by the index - if success
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_get_index (const jerry_value_t object, /**< object value */
uint32_t index) /**< index to be written */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_value_t ret_value = ecma_op_object_get_by_index (ecma_get_object_from_value (object), index);
return jerry_return (ret_value);
} /* jerry_object_get_index */
/**
* Get the own property value of an object with the given name.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the property - if success
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_find_own (const jerry_value_t object, /**< object value */
const jerry_value_t key, /**< property name (string value) */
const jerry_value_t receiver, /**< receiver object value */
bool *found_p) /**< [out] true, if the property is found
* or object is a Proxy object, false otherwise */
{
jerry_assert_api_enabled ();
if (found_p != NULL)
{
*found_p = false;
}
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key) || !ecma_is_value_object (receiver))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_object_t *object_p = ecma_get_object_from_value (object);
ecma_string_t *property_name_p = ecma_get_prop_name_from_value (key);
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (object_p))
{
if (found_p != NULL)
{
*found_p = true;
}
return jerry_return (ecma_proxy_object_get (object_p, property_name_p, receiver));
}
#endif /* JERRY_BUILTIN_PROXY */
ecma_value_t ret_value = ecma_op_object_find_own (receiver, object_p, property_name_p);
if (ecma_is_value_found (ret_value))
{
if (found_p != NULL)
{
*found_p = true;
}
return jerry_return (ret_value);
}
return ECMA_VALUE_UNDEFINED;
} /* jerry_object_find_own */
/**
* Get value of an internal property to the specified object with the given name.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return value of the internal property - if the internal property exists
* undefined value - if the internal does not property exists
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_get_internal (const jerry_value_t object, /**< object value */
const jerry_value_t key) /**< property name value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL);
if (ecma_op_object_is_fast_array (obj_p))
{
return jerry_return (ECMA_VALUE_UNDEFINED);
}
ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p);
if (property_p == NULL)
{
return jerry_return (ECMA_VALUE_UNDEFINED);
}
ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (key));
if (property_p == NULL)
{
return jerry_return (ECMA_VALUE_UNDEFINED);
}
return jerry_return (ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value));
} /* jerry_object_get_internal */
/**
* Set a property to the specified object with the given name.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return true value - if the operation was successful
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_set (jerry_value_t object, /**< object value */
const jerry_value_t key, /**< property name (string value) */
const jerry_value_t value) /**< value to set */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (value) || !ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
return jerry_return (
ecma_op_object_put (ecma_get_object_from_value (object), ecma_get_prop_name_from_value (key), value, true));
} /* jerry_object_set */
/**
* Set a property to the specified object with the given name.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return true value - if the operation was successful
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_set_sz (jerry_value_t object, /**< object value */
const char *key_p, /**< property key */
const jerry_value_t value) /**< value to set */
{
jerry_assert_api_enabled ();
jerry_value_t key_str = jerry_string_sz (key_p);
jerry_value_t result = jerry_object_set (object, key_str, value);
ecma_free_value (key_str);
return result;
} /* jerry_object_set */
/**
* Set indexed value in the specified object
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return true value - if the operation was successful
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_set_index (jerry_value_t object, /**< object value */
uint32_t index, /**< index to be written */
const jerry_value_t value) /**< value to set */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (value) || !ecma_is_value_object (object))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_value_t ret_value = ecma_op_object_put_by_index (ecma_get_object_from_value (object), index, value, true);
return jerry_return (ret_value);
} /* jerry_object_set_index */
/**
* Set an internal property to the specified object with the given name.
*
* Note:
* - the property cannot be accessed from the JavaScript context, only from the public API
* - returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return true value - if the operation was successful
* value marked with error flag - otherwise
*/
bool
jerry_object_set_internal (jerry_value_t object, /**< object value */
const jerry_value_t key, /**< property name value */
const jerry_value_t value) /**< value to set */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (value) || !ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return false;
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL);
if (ecma_op_object_is_fast_array (obj_p))
{
ecma_fast_array_convert_to_normal (obj_p);
}
ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p);
ecma_object_t *internal_object_p;
if (property_p == NULL)
{
ecma_property_value_t *value_p =
ecma_create_named_data_property (obj_p, internal_string_p, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL);
internal_object_p = ecma_create_object (NULL, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS);
{
ecma_extended_object_t *container_p = (ecma_extended_object_t *) internal_object_p;
container_p->u.cls.type = ECMA_OBJECT_CLASS_INTERNAL_OBJECT;
}
value_p->value = ecma_make_object_value (internal_object_p);
ecma_deref_object (internal_object_p);
}
else
{
internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
}
ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (key);
property_p = ecma_find_named_property (internal_object_p, prop_name_p);
if (property_p == NULL)
{
ecma_property_value_t *value_p = ecma_create_named_data_property (internal_object_p,
prop_name_p,
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
NULL);
value_p->value = ecma_copy_value_if_not_object (value);
}
else
{
ecma_named_data_property_assign_value (internal_object_p, ECMA_PROPERTY_VALUE_PTR (property_p), value);
}
return true;
} /* jerry_object_set_internal */
/**
* Construct empty property descriptor, i.e.:
* property descriptor with all is_defined flags set to false and the rest - to default value.
*
* @return empty property descriptor
*/
jerry_property_descriptor_t
jerry_property_descriptor (void)
{
jerry_property_descriptor_t prop_desc;
prop_desc.flags = JERRY_PROP_NO_OPTS;
prop_desc.value = ECMA_VALUE_UNDEFINED;
prop_desc.getter = ECMA_VALUE_UNDEFINED;
prop_desc.setter = ECMA_VALUE_UNDEFINED;
return prop_desc;
} /* jerry_property_descriptor */
/**
* Convert a ecma_property_descriptor_t to a jerry_property_descriptor_t
*
* if error occurs the property descriptor's value field is filled with ECMA_VALUE_ERROR
*
* @return jerry_property_descriptor_t
*/
static jerry_property_descriptor_t
jerry_property_descriptor_from_ecma (const ecma_property_descriptor_t *prop_desc_p) /**<[out] property_descriptor */
{
jerry_property_descriptor_t prop_desc = jerry_property_descriptor ();
prop_desc.flags = prop_desc_p->flags;
if (prop_desc.flags & (JERRY_PROP_IS_VALUE_DEFINED))
{
prop_desc.value = prop_desc_p->value;
}
if (prop_desc_p->flags & JERRY_PROP_IS_GET_DEFINED)
{
prop_desc.getter = ECMA_VALUE_NULL;
if (prop_desc_p->get_p != NULL)
{
prop_desc.getter = ecma_make_object_value (prop_desc_p->get_p);
JERRY_ASSERT (ecma_op_is_callable (prop_desc.getter));
}
}
if (prop_desc_p->flags & JERRY_PROP_IS_SET_DEFINED)
{
prop_desc.setter = ECMA_VALUE_NULL;
if (prop_desc_p->set_p != NULL)
{
prop_desc.setter = ecma_make_object_value (prop_desc_p->set_p);
JERRY_ASSERT (ecma_op_is_callable (prop_desc.setter));
}
}
return prop_desc;
} /* jerry_property_descriptor_from_ecma */
/**
* Convert a jerry_property_descriptor_t to a ecma_property_descriptor_t
*
* Note:
* if error occurs the property descriptor's value field
* is set to ECMA_VALUE_ERROR, but no error is thrown
*
* @return ecma_property_descriptor_t
*/
static ecma_property_descriptor_t
jerry_property_descriptor_to_ecma (const jerry_property_descriptor_t *prop_desc_p) /**< input property_descriptor */
{
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
prop_desc.flags = prop_desc_p->flags;
/* Copy data property info. */
if (prop_desc_p->flags & JERRY_PROP_IS_VALUE_DEFINED)
{
if (ecma_is_value_exception (prop_desc_p->value)
|| (prop_desc_p->flags & (JERRY_PROP_IS_GET_DEFINED | JERRY_PROP_IS_SET_DEFINED)))
{
prop_desc.value = ECMA_VALUE_ERROR;
return prop_desc;
}
prop_desc.value = prop_desc_p->value;
}
/* Copy accessor property info. */
if (prop_desc_p->flags & JERRY_PROP_IS_GET_DEFINED)
{
ecma_value_t getter = prop_desc_p->getter;
if (ecma_is_value_exception (getter))
{
prop_desc.value = ECMA_VALUE_ERROR;
return prop_desc;
}
if (ecma_op_is_callable (getter))
{
prop_desc.get_p = ecma_get_object_from_value (getter);
}
else if (!ecma_is_value_null (getter))
{
prop_desc.value = ECMA_VALUE_ERROR;
return prop_desc;
}
}
if (prop_desc_p->flags & JERRY_PROP_IS_SET_DEFINED)
{
ecma_value_t setter = prop_desc_p->setter;
if (ecma_is_value_exception (setter))
{
prop_desc.value = ECMA_VALUE_ERROR;
return prop_desc;
}
if (ecma_op_is_callable (setter))
{
prop_desc.set_p = ecma_get_object_from_value (setter);
}
else if (!ecma_is_value_null (setter))
{
prop_desc.value = ECMA_VALUE_ERROR;
return prop_desc;
}
}
const uint16_t configurable_mask = JERRY_PROP_IS_CONFIGURABLE | JERRY_PROP_IS_CONFIGURABLE_DEFINED;
const uint16_t enumerable_mask = JERRY_PROP_IS_ENUMERABLE | JERRY_PROP_IS_ENUMERABLE_DEFINED;
const uint16_t writable_mask = JERRY_PROP_IS_WRITABLE | JERRY_PROP_IS_WRITABLE_DEFINED;
if ((prop_desc_p->flags & configurable_mask) == JERRY_PROP_IS_CONFIGURABLE
|| (prop_desc_p->flags & enumerable_mask) == JERRY_PROP_IS_ENUMERABLE
|| (prop_desc_p->flags & writable_mask) == JERRY_PROP_IS_WRITABLE)
{
prop_desc.value = ECMA_VALUE_ERROR;
return prop_desc;
}
prop_desc.flags |= (uint16_t) (prop_desc_p->flags | JERRY_PROP_SHOULD_THROW);
return prop_desc;
} /* jerry_property_descriptor_to_ecma */
/** Helper function to return false value or error depending on the given flag.
*
* @return value marked with error flag - if is_throw is true
* false value - otherwise
*/
static jerry_value_t
jerry_type_error_or_false (ecma_error_msg_t msg, /**< message */
uint16_t flags) /**< property descriptor flags */
{
if (!(flags & JERRY_PROP_SHOULD_THROW))
{
return ECMA_VALUE_FALSE;
}
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (msg));
} /* jerry_type_error_or_false */
/**
* Define a property to the specified object with the given name.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return true value - if the operation was successful
* false value - if the property cannot be defined and JERRY_PROP_SHOULD_THROW is not set
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_define_own_prop (jerry_value_t object, /**< object value */
const jerry_value_t key, /**< property name (string value) */
const jerry_property_descriptor_t *prop_desc_p) /**< property descriptor */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return jerry_type_error_or_false (ECMA_ERR_WRONG_ARGS_MSG, prop_desc_p->flags);
}
if (prop_desc_p->flags & (JERRY_PROP_IS_WRITABLE_DEFINED | JERRY_PROP_IS_VALUE_DEFINED)
&& prop_desc_p->flags & (JERRY_PROP_IS_GET_DEFINED | JERRY_PROP_IS_SET_DEFINED))
{
return jerry_type_error_or_false (ECMA_ERR_WRONG_ARGS_MSG, prop_desc_p->flags);
}
ecma_property_descriptor_t prop_desc = jerry_property_descriptor_to_ecma (prop_desc_p);
if (ECMA_IS_VALUE_ERROR (prop_desc.value))
{
return jerry_type_error_or_false (ECMA_ERR_WRONG_ARGS_MSG, prop_desc_p->flags);
}
return jerry_return (ecma_op_object_define_own_property (ecma_get_object_from_value (object),
ecma_get_prop_name_from_value (key),
&prop_desc));
} /* jerry_object_define_own_prop */
/**
* Construct property descriptor from specified property.
*
* @return true - if success, the prop_desc_p fields contains the property info
* false - otherwise, the prop_desc_p is unchanged
*/
jerry_value_t
jerry_object_get_own_prop (const jerry_value_t object, /**< object value */
const jerry_value_t key, /**< property name (string value) */
jerry_property_descriptor_t *prop_desc_p) /**< property descriptor */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
{
return ECMA_VALUE_FALSE;
}
ecma_property_descriptor_t prop_desc;
ecma_value_t status = ecma_op_object_get_own_property_descriptor (ecma_get_object_from_value (object),
ecma_get_prop_name_from_value (key),
&prop_desc);
#if JERRY_BUILTIN_PROXY
if (ECMA_IS_VALUE_ERROR (status))
{
return ecma_create_exception_from_context ();
}
#endif /* JERRY_BUILTIN_PROXY */
if (!ecma_is_value_true (status))
{
return ECMA_VALUE_FALSE;
}
/* The flags are always filled in the returned descriptor. */
JERRY_ASSERT (
(prop_desc.flags & JERRY_PROP_IS_CONFIGURABLE_DEFINED) && (prop_desc.flags & JERRY_PROP_IS_ENUMERABLE_DEFINED)
&& ((prop_desc.flags & JERRY_PROP_IS_WRITABLE_DEFINED) || !(prop_desc.flags & JERRY_PROP_IS_VALUE_DEFINED)));
prop_desc_p->flags = prop_desc.flags;
prop_desc_p->value = ECMA_VALUE_UNDEFINED;
prop_desc_p->getter = ECMA_VALUE_UNDEFINED;
prop_desc_p->setter = ECMA_VALUE_UNDEFINED;
if (prop_desc_p->flags & JERRY_PROP_IS_VALUE_DEFINED)
{
prop_desc_p->value = prop_desc.value;
}
if (prop_desc_p->flags & JERRY_PROP_IS_GET_DEFINED)
{
if (prop_desc.get_p != NULL)
{
prop_desc_p->getter = ecma_make_object_value (prop_desc.get_p);
}
else
{
prop_desc_p->getter = ECMA_VALUE_NULL;
}
}
if (prop_desc_p->flags & JERRY_PROP_IS_SET_DEFINED)
{
if (prop_desc.set_p != NULL)
{
prop_desc_p->setter = ecma_make_object_value (prop_desc.set_p);
}
else
{
prop_desc_p->setter = ECMA_VALUE_NULL;
}
}
return ECMA_VALUE_TRUE;
} /* jerry_object_get_own_prop */
/**
* Free fields of property descriptor (setter, getter and value).
*/
void
jerry_property_descriptor_free (jerry_property_descriptor_t *prop_desc_p) /**< property descriptor */
{
if (prop_desc_p->flags & JERRY_PROP_IS_VALUE_DEFINED)
{
jerry_value_free (prop_desc_p->value);
}
if (prop_desc_p->flags & JERRY_PROP_IS_GET_DEFINED)
{
jerry_value_free (prop_desc_p->getter);
}
if (prop_desc_p->flags & JERRY_PROP_IS_SET_DEFINED)
{
jerry_value_free (prop_desc_p->setter);
}
} /* jerry_property_descriptor_free */
/**
* Call function specified by a function value
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
* error flag must not be set for any arguments of this function.
*
* @return returned jerry value of the called function
*/
jerry_value_t
jerry_call (const jerry_value_t func_object, /**< function object to call */
const jerry_value_t this_value, /**< object for 'this' binding */
const jerry_value_t *args_p, /**< function's call arguments */
jerry_size_t args_count) /**< number of the arguments */
{
jerry_assert_api_enabled ();
if (ecma_is_value_exception (this_value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
for (jerry_size_t i = 0; i < args_count; i++)
{
if (ecma_is_value_exception (args_p[i]))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
}
return jerry_return (ecma_op_function_validated_call (func_object, this_value, args_p, args_count));
} /* jerry_call */
/**
* Construct object value invoking specified function value as a constructor
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
* error flag must not be set for any arguments of this function.
*
* @return returned jerry value of the invoked constructor
*/
jerry_value_t
jerry_construct (const jerry_value_t func_object, /**< function object to call */
const jerry_value_t *args_p, /**< function's call arguments
* (NULL if arguments number is zero) */
jerry_size_t args_count) /**< number of the arguments */
{
jerry_assert_api_enabled ();
if (!jerry_value_is_constructor (func_object))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
for (jerry_size_t i = 0; i < args_count; i++)
{
if (ecma_is_value_exception (args_p[i]))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
}
return jerry_return (ecma_op_function_construct (ecma_get_object_from_value (func_object),
ecma_get_object_from_value (func_object),
args_p,
args_count));
} /* jerry_construct */
/**
* Get keys of the specified object value
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return array object value - if success
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_keys (const jerry_value_t object) /**< object value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_collection_t *prop_names =
ecma_op_object_get_enumerable_property_names (ecma_get_object_from_value (object), ECMA_ENUMERABLE_PROPERTY_KEYS);
#if JERRY_BUILTIN_PROXY
if (JERRY_UNLIKELY (prop_names == NULL))
{
return ecma_create_exception_from_context ();
}
#endif /* JERRY_BUILTIN_PROXY */
return ecma_op_new_array_object_from_collection (prop_names, false);
} /* jerry_object_keys */
/**
* Get the prototype of the specified object
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return prototype object or null value - if success
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_proto (const jerry_value_t object) /**< object value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (obj_p))
{
return jerry_return (ecma_proxy_object_get_prototype_of (obj_p));
}
#endif /* JERRY_BUILTIN_PROXY */
if (obj_p->u2.prototype_cp == JMEM_CP_NULL)
{
return ECMA_VALUE_NULL;
}
ecma_object_t *proto_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_p->u2.prototype_cp);
ecma_ref_object (proto_obj_p);
return ecma_make_object_value (proto_obj_p);
} /* jerry_object_proto */
/**
* Set the prototype of the specified object
*
* @return true value - if success
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_set_proto (jerry_value_t object, /**< object value */
const jerry_value_t proto) /**< prototype object value */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object) || ecma_is_value_exception (proto)
|| (!ecma_is_value_object (proto) && !ecma_is_value_null (proto)))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (obj_p))
{
return jerry_return (ecma_proxy_object_set_prototype_of (obj_p, proto));
}
#endif /* JERRY_BUILTIN_PROXY */
return ecma_op_ordinary_object_set_prototype_of (obj_p, proto);
} /* jerry_object_set_proto */
/**
* Utility to check if a given object can be used for the foreach api calls.
*
* Some objects/classes uses extra internal objects to correctly store data.
* These extre object should never be exposed externally to the API user.
*
* @returns true - if the user can access the object in the callback.
* false - if the object is an internal object which should no be accessed by the user.
*/
static bool
jerry_object_is_valid_foreach (ecma_object_t *object_p) /**< object to test */
{
if (ecma_is_lexical_environment (object_p))
{
return false;
}
ecma_object_type_t object_type = ecma_get_object_type (object_p);
if (object_type == ECMA_OBJECT_TYPE_CLASS)
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
switch (ext_object_p->u.cls.type)
{
/* An object's internal property object should not be iterable by foreach. */
case ECMA_OBJECT_CLASS_INTERNAL_OBJECT:
{
return false;
}
}
}
return true;
} /* jerry_object_is_valid_foreach */
/**
* Traverse objects.
*
* @return true - traversal was interrupted by the callback.
* false - otherwise - traversal visited all objects.
*/
bool
jerry_foreach_live_object (jerry_foreach_live_object_cb_t callback, /**< function pointer of the iterator function */
void *user_data_p) /**< pointer to user data */
{
jerry_assert_api_enabled ();
JERRY_ASSERT (callback != NULL);
jmem_cpointer_t iter_cp = JERRY_CONTEXT (ecma_gc_objects_cp);
while (iter_cp != JMEM_CP_NULL)
{
ecma_object_t *iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, iter_cp);
if (jerry_object_is_valid_foreach (iter_p) && !callback (ecma_make_object_value (iter_p), user_data_p))
{
return true;
}
iter_cp = iter_p->gc_next_cp;
}
return false;
} /* jerry_foreach_live_object */
/**
* Traverse objects having a given native type info.
*
* @return true - traversal was interrupted by the callback.
* false - otherwise - traversal visited all objects.
*/
bool
jerry_foreach_live_object_with_info (const jerry_object_native_info_t *native_info_p, /**< the type info
* of the native pointer */
jerry_foreach_live_object_with_info_cb_t callback, /**< function to apply for
* each matching object */
void *user_data_p) /**< pointer to user data */
{
jerry_assert_api_enabled ();
JERRY_ASSERT (native_info_p != NULL);
JERRY_ASSERT (callback != NULL);
ecma_native_pointer_t *native_pointer_p;
jmem_cpointer_t iter_cp = JERRY_CONTEXT (ecma_gc_objects_cp);
while (iter_cp != JMEM_CP_NULL)
{
ecma_object_t *iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, iter_cp);
if (jerry_object_is_valid_foreach (iter_p))
{
native_pointer_p = ecma_get_native_pointer_value (iter_p, (void *) native_info_p);
if (native_pointer_p && !callback (ecma_make_object_value (iter_p), native_pointer_p->native_p, user_data_p))
{
return true;
}
}
iter_cp = iter_p->gc_next_cp;
}
return false;
} /* jerry_foreach_live_object_with_info */
/**
* Get native pointer and its type information, associated with the given native type info.
*
* Note:
* If native pointer is present, its type information is returned in out_native_pointer_p
*
* @return found native pointer,
* or NULL
*/
void *
jerry_object_get_native_ptr (const jerry_value_t object, /**< object to get native pointer from */
const jerry_object_native_info_t *native_info_p) /**< the type info
* of the native pointer */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object))
{
return NULL;
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
ecma_native_pointer_t *native_pointer_p = ecma_get_native_pointer_value (obj_p, (void *) native_info_p);
if (native_pointer_p == NULL)
{
return NULL;
}
return native_pointer_p->native_p;
} /* jerry_object_get_native_ptr */
/**
* Set native pointer and an optional type info for the specified object.
*
*
* Note:
* If native pointer was already set for the object, its value is updated.
*
* Note:
* If a non-NULL free callback is specified in the native type info,
* it will be called by the garbage collector when the object is freed.
* Referred values by this method must have at least 1 reference. (Correct API usage satisfies this condition)
* The type info always overwrites the previous value, so passing
* a NULL value deletes the current type info.
*/
void
jerry_object_set_native_ptr (jerry_value_t object, /**< object to set native pointer in */
const jerry_object_native_info_t *native_info_p, /**< object's native type info */
void *native_pointer_p) /**< native pointer */
{
jerry_assert_api_enabled ();
if (ecma_is_value_object (object))
{
ecma_object_t *object_p = ecma_get_object_from_value (object);
ecma_create_native_pointer_property (object_p, native_pointer_p, native_info_p);
}
} /* jerry_object_set_native_ptr */
/**
* Checks wether the argument object has a native poitner set for the specified native type info.
*
* @return true if the native pointer has been set,
* false otherwise
*/
bool
jerry_object_has_native_ptr (const jerry_value_t object, /**< object to set native pointer in */
const jerry_object_native_info_t *native_info_p) /**< object's native type info */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object))
{
return false;
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
ecma_native_pointer_t *native_pointer_p = ecma_get_native_pointer_value (obj_p, (void *) native_info_p);
return native_pointer_p != NULL;
} /* jerry_object_has_native_ptr */
/**
* Delete the previously set native pointer by the native type info from the specified object.
*
* Note:
* If the specified object has no matching native pointer for the given native type info
* the function has no effect.
*
* Note:
* This operation cannot throw an exception.
*
* @return true - if the native pointer has been deleted succesfully
* false - otherwise
*/
bool
jerry_object_delete_native_ptr (jerry_value_t object, /**< object to delete native pointer from */
const jerry_object_native_info_t *native_info_p) /**< object's native type info */
{
jerry_assert_api_enabled ();
if (ecma_is_value_object (object))
{
ecma_object_t *object_p = ecma_get_object_from_value (object);
return ecma_delete_native_pointer_property (object_p, (void *) native_info_p);
}
return false;
} /* jerry_object_delete_native_ptr */
/**
* Initialize the references stored in a buffer pointed by a native pointer.
* The references are initialized to undefined.
*/
void
jerry_native_ptr_init (void *native_pointer_p, /**< a valid non-NULL pointer to a native buffer */
const jerry_object_native_info_t *native_info_p) /**< the type info of
* the native pointer */
{
jerry_assert_api_enabled ();
if (native_pointer_p == NULL || native_info_p == NULL)
{
return;
}
ecma_value_t *value_p = (ecma_value_t *) (((uint8_t *) native_pointer_p) + native_info_p->offset_of_references);
ecma_value_t *end_p = value_p + native_info_p->number_of_references;
while (value_p < end_p)
{
*value_p++ = ECMA_VALUE_UNDEFINED;
}
} /* jerry_native_ptr_init */
/**
* Release the value references after a buffer pointed by a native pointer
* is not attached to an object anymore. All references are set to undefined
* similar to jerry_native_ptr_init.
*/
void
jerry_native_ptr_free (void *native_pointer_p, /**< a valid non-NULL pointer to a native buffer */
const jerry_object_native_info_t *native_info_p) /**< the type info of
* the native pointer */
{
jerry_assert_api_enabled ();
if (native_pointer_p == NULL || native_info_p == NULL)
{
return;
}
ecma_value_t *value_p = (ecma_value_t *) (((uint8_t *) native_pointer_p) + native_info_p->offset_of_references);
ecma_value_t *end_p = value_p + native_info_p->number_of_references;
while (value_p < end_p)
{
ecma_free_value_if_not_object (*value_p);
*value_p++ = ECMA_VALUE_UNDEFINED;
}
} /* jerry_native_ptr_free */
/**
* Updates a value reference inside the area specified by the number_of_references and
* offset_of_references fields in its corresponding jerry_object_native_info_t data.
* The area must be part of a buffer which is currently assigned to an object.
*
* Note:
* Error references are not supported, they are replaced by undefined values.
*/
void
jerry_native_ptr_set (jerry_value_t *reference_p, /**< a valid non-NULL pointer to
* a reference in a native buffer. */
const jerry_value_t value) /**< new value of the reference */
{
jerry_assert_api_enabled ();
if (reference_p == NULL)
{
return;
}
ecma_free_value_if_not_object (*reference_p);
if (ecma_is_value_exception (value))
{
*reference_p = ECMA_VALUE_UNDEFINED;
return;
}
*reference_p = ecma_copy_value_if_not_object (value);
} /* jerry_native_ptr_set */
/**
* Applies the given function to the every property in the object.
*
* @return true - if object fields traversal was performed successfully, i.e.:
* - no unhandled exceptions were thrown in object fields traversal;
* - object fields traversal was stopped on callback that returned false;
* false - otherwise,
* if getter of field threw a exception or unhandled exceptions were thrown during traversal;
*/
bool
jerry_object_foreach (const jerry_value_t object, /**< object value */
jerry_object_property_foreach_cb_t foreach_p, /**< foreach function */
void *user_data_p) /**< user data for foreach function */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object))
{
return false;
}
ecma_object_t *object_p = ecma_get_object_from_value (object);
ecma_collection_t *names_p = ecma_op_object_enumerate (object_p);
#if JERRY_BUILTIN_PROXY
if (names_p == NULL)
{
// TODO: Due to Proxies the return value must be changed to jerry_value_t on next release
jcontext_release_exception ();
return false;
}
#endif /* JERRY_BUILTIN_PROXY */
ecma_value_t *buffer_p = names_p->buffer_p;
ecma_value_t property_value = ECMA_VALUE_EMPTY;
bool continuous = true;
for (uint32_t i = 0; continuous && (i < names_p->item_count); i++)
{
ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]);
property_value = ecma_op_object_get (object_p, property_name_p);
if (ECMA_IS_VALUE_ERROR (property_value))
{
break;
}
continuous = foreach_p (buffer_p[i], property_value, user_data_p);
ecma_free_value (property_value);
}
ecma_collection_free (names_p);
if (!ECMA_IS_VALUE_ERROR (property_value))
{
return true;
}
jcontext_release_exception ();
return false;
} /* jerry_object_foreach */
/**
* Gets the property keys for the given object using the selected filters.
*
* @return array containing the filtered property keys in successful operation
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_object_property_names (const jerry_value_t object, /**< object */
jerry_property_filter_t filter) /**< property filter options */
{
jerry_assert_api_enabled ();
if (!ecma_is_value_object (object))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_object_t *obj_p = ecma_get_object_from_value (object);
ecma_object_t *obj_iter_p = obj_p;
ecma_collection_t *result_p = ecma_new_collection ();
ecma_ref_object (obj_iter_p);
while (true)
{
/* Step 1. Get Object.[[OwnKeys]] */
ecma_collection_t *prop_names_p = ecma_op_object_own_property_keys (obj_iter_p, filter);
#if JERRY_BUILTIN_PROXY
if (prop_names_p == NULL)
{
ecma_deref_object (obj_iter_p);
return ecma_create_exception_from_context ();
}
#endif /* JERRY_BUILTIN_PROXY */
for (uint32_t i = 0; i < prop_names_p->item_count; i++)
{
ecma_value_t key = prop_names_p->buffer_p[i];
ecma_string_t *key_p = ecma_get_prop_name_from_value (key);
uint32_t index = ecma_string_get_array_index (key_p);
/* Step 2. Filter by key type */
if (filter
& (JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS | JERRY_PROPERTY_FILTER_EXCLUDE_SYMBOLS
| JERRY_PROPERTY_FILTER_EXCLUDE_INTEGER_INDICES))
{
if (ecma_is_value_symbol (key))
{
if (filter & JERRY_PROPERTY_FILTER_EXCLUDE_SYMBOLS)
{
continue;
}
}
else if (index != ECMA_STRING_NOT_ARRAY_INDEX)
{
if ((filter & JERRY_PROPERTY_FILTER_EXCLUDE_INTEGER_INDICES)
|| ((filter & JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS)
&& !(filter & JERRY_PROPERTY_FILTER_INTEGER_INDICES_AS_NUMBER)))
{
continue;
}
}
else if (filter & JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS)
{
continue;
}
}
/* Step 3. Filter property attributes */
if (filter
& (JERRY_PROPERTY_FILTER_EXCLUDE_NON_CONFIGURABLE | JERRY_PROPERTY_FILTER_EXCLUDE_NON_ENUMERABLE
| JERRY_PROPERTY_FILTER_EXCLUDE_NON_WRITABLE))
{
ecma_property_descriptor_t prop_desc;
ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_iter_p, key_p, &prop_desc);
#if JERRY_BUILTIN_PROXY
if (ECMA_IS_VALUE_ERROR (status))
{
ecma_collection_free (prop_names_p);
ecma_collection_free (result_p);
ecma_deref_object (obj_iter_p);
return ecma_create_exception_from_context ();
}
#endif /* JERRY_BUILTIN_PROXY */
JERRY_ASSERT (ecma_is_value_true (status));
uint16_t flags = prop_desc.flags;
ecma_free_property_descriptor (&prop_desc);
if ((!(flags & JERRY_PROP_IS_CONFIGURABLE) && (filter & JERRY_PROPERTY_FILTER_EXCLUDE_NON_CONFIGURABLE))
|| (!(flags & JERRY_PROP_IS_ENUMERABLE) && (filter & JERRY_PROPERTY_FILTER_EXCLUDE_NON_ENUMERABLE))
|| (!(flags & JERRY_PROP_IS_WRITABLE) && (filter & JERRY_PROPERTY_FILTER_EXCLUDE_NON_WRITABLE)))
{
continue;
}
}
if (index != ECMA_STRING_NOT_ARRAY_INDEX && (filter & JERRY_PROPERTY_FILTER_INTEGER_INDICES_AS_NUMBER))
{
ecma_deref_ecma_string (key_p);
key = ecma_make_uint32_value (index);
}
else
{
ecma_ref_ecma_string (key_p);
}
if ((filter & JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN) && obj_iter_p != obj_p)
{
uint32_t duplicate_idx = 0;
while (duplicate_idx < result_p->item_count)
{
ecma_value_t value = result_p->buffer_p[duplicate_idx];
JERRY_ASSERT (ecma_is_value_prop_name (value) || ecma_is_value_number (value));
if (JERRY_UNLIKELY (ecma_is_value_number (value)))
{
if (ecma_get_number_from_value (value) == ecma_get_number_from_value (key))
{
break;
}
}
else if (ecma_compare_ecma_strings (ecma_get_prop_name_from_value (value), key_p))
{
break;
}
duplicate_idx++;
}
if (duplicate_idx == result_p->item_count)
{
ecma_collection_push_back (result_p, key);
}
}
else
{
ecma_collection_push_back (result_p, key);
}
}
ecma_collection_free (prop_names_p);
/* Step 4: Traverse prototype chain */
if ((filter & JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN) != JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN)
{
break;
}
ecma_object_t *proto_p = ecma_op_object_get_prototype_of (obj_iter_p);
if (proto_p == NULL)
{
break;
}
ecma_deref_object (obj_iter_p);
if (JERRY_UNLIKELY (proto_p == ECMA_OBJECT_POINTER_ERROR))
{
ecma_collection_free (result_p);
return ecma_create_exception_from_context ();
}
obj_iter_p = proto_p;
}
ecma_deref_object (obj_iter_p);
return ecma_op_new_array_object_from_collection (result_p, false);
} /* jerry_object_property_names */
/**
* FromPropertyDescriptor abstract operation.
*
* @return new jerry_value_t - if success
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_property_descriptor_to_object (const jerry_property_descriptor_t *src_prop_desc_p) /**< property descriptor */
{
jerry_assert_api_enabled ();
ecma_property_descriptor_t prop_desc = jerry_property_descriptor_to_ecma (src_prop_desc_p);
if (ECMA_IS_VALUE_ERROR (prop_desc.value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_object_t *desc_obj_p = ecma_op_from_property_descriptor (&prop_desc);
return ecma_make_object_value (desc_obj_p);
} /* jerry_property_descriptor_to_object */
/**
* ToPropertyDescriptor abstract operation.
*
* @return true - if the conversion is successful
* thrown error - otherwise
*/
jerry_value_t
jerry_property_descriptor_from_object (const jerry_value_t object, /**< object value */
jerry_property_descriptor_t *out_prop_desc_p) /**< [out] filled property
* descriptor if return value is
* true, unmodified otherwise */
{
jerry_assert_api_enabled ();
ecma_property_descriptor_t prop_desc;
jerry_value_t result = ecma_op_to_property_descriptor (object, &prop_desc);
if (ECMA_IS_VALUE_ERROR (result))
{
return ecma_create_exception_from_context ();
}
JERRY_ASSERT (result == ECMA_VALUE_EMPTY);
*out_prop_desc_p = jerry_property_descriptor_from_ecma (&prop_desc);
return ECMA_VALUE_TRUE;
} /* jerry_property_descriptor_from_object */
/**
* Resolve a promise value with an argument.
*
* @return undefined - if success,
* exception - otherwise
*/
jerry_value_t
jerry_promise_resolve (jerry_value_t promise, /**< the promise value */
const jerry_value_t argument) /**< the argument */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
if (!jerry_value_is_promise (promise))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
if (ecma_is_value_exception (argument))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
return ecma_fulfill_promise_with_checks (promise, argument);
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (promise);
JERRY_UNUSED (argument);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROMISE_NOT_SUPPORTED));
#endif /* JERRY_ESNEXT */
} /* jerry_promise_resolve */
/**
* Reject a promise value with an argument.
*
* @return undefined - if success,
* exception - otherwise
*/
jerry_value_t
jerry_promise_reject (jerry_value_t promise, /**< the promise value */
const jerry_value_t argument) /**< the argument */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
if (!jerry_value_is_promise (promise))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
if (ecma_is_value_exception (argument))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
return ecma_reject_promise_with_checks (promise, argument);
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (promise);
JERRY_UNUSED (argument);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROMISE_NOT_SUPPORTED));
#endif /* JERRY_ESNEXT */
} /* jerry_promise_reject */
/**
* Get the result of a promise.
*
* @return - Promise result
* - Type error if the promise support was not enabled or the input was not a promise object
*/
jerry_value_t
jerry_promise_result (const jerry_value_t promise) /**< promise object to get the result from */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
if (!jerry_value_is_promise (promise))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
return ecma_promise_get_result (ecma_get_object_from_value (promise));
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (promise);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROMISE_NOT_SUPPORTED));
#endif /* JERRY_ESNEXT */
} /* jerry_promise_result */
/**
* Get the state of a promise object.
*
* @return - the state of the promise (one of the jerry_promise_state_t enum values)
* - JERRY_PROMISE_STATE_NONE is only returned if the input is not a promise object
* or the promise support was not enabled.
*/
jerry_promise_state_t
jerry_promise_state (const jerry_value_t promise) /**< promise object to get the state from */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
if (!jerry_value_is_promise (promise))
{
return JERRY_PROMISE_STATE_NONE;
}
uint16_t flags = ecma_promise_get_flags (ecma_get_object_from_value (promise));
flags &= (ECMA_PROMISE_IS_PENDING | ECMA_PROMISE_IS_FULFILLED);
return (flags ? flags : JERRY_PROMISE_STATE_REJECTED);
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (promise);
return JERRY_PROMISE_STATE_NONE;
#endif /* JERRY_ESNEXT */
} /* jerry_promise_state */
/**
* Sets a callback for tracking Promise and async operations.
*
* Note:
* the previous callback is overwritten
*/
void
jerry_promise_on_event (jerry_promise_event_filter_t filters, /**< combination of event filters */
jerry_promise_event_cb_t callback, /**< notification callback */
void *user_p) /**< user pointer passed to the callback */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT && JERRY_PROMISE_CALLBACK
if (filters == JERRY_PROMISE_EVENT_FILTER_DISABLE || callback == NULL)
{
JERRY_CONTEXT (promise_callback_filters) = JERRY_PROMISE_EVENT_FILTER_DISABLE;
return;
}
JERRY_CONTEXT (promise_callback_filters) = (uint32_t) filters;
JERRY_CONTEXT (promise_callback) = callback;
JERRY_CONTEXT (promise_callback_user_p) = user_p;
#else /* !JERRY_ESNEXT && !JERRY_PROMISE_CALLBACK */
JERRY_UNUSED (filters);
JERRY_UNUSED (callback);
JERRY_UNUSED (user_p);
#endif /* JERRY_ESNEXT && JERRY_PROMISE_CALLBACK */
} /* jerry_promise_on_event */
/**
* Get the well-knwon symbol represented by the given `symbol` enum value.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return undefined value - if invalid well-known symbol was requested
* well-known symbol value - otherwise
*/
jerry_value_t
jerry_symbol (jerry_well_known_symbol_t symbol) /**< jerry_well_known_symbol_t enum value */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
lit_magic_string_id_t id = (lit_magic_string_id_t) (LIT_GLOBAL_SYMBOL__FIRST + symbol);
if (!LIT_IS_GLOBAL_SYMBOL (id))
{
return ECMA_VALUE_UNDEFINED;
}
return ecma_make_symbol_value (ecma_op_get_global_symbol (id));
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (symbol);
return ECMA_VALUE_UNDEFINED;
#endif /* JERRY_ESNEXT */
} /* jerry_symbol */
/**
* Returns the description internal property of a symbol.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return string or undefined value containing the symbol's description - if success
* thrown error - otherwise
*/
jerry_value_t
jerry_symbol_description (const jerry_value_t symbol) /**< symbol value */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
if (!ecma_is_value_symbol (symbol))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
/* Note: This operation cannot throw an error */
return ecma_copy_value (ecma_get_symbol_description (ecma_get_symbol_from_value (symbol)));
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (symbol);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SYMBOL_NOT_SUPPORTED));
#endif /* JERRY_ESNEXT */
} /* jerry_symbol_description */
/**
* Call the SymbolDescriptiveString ecma builtin operation on the symbol value.
*
* Note:
* returned value must be freed with jerry_value_free, when it is no longer needed.
*
* @return string value containing the symbol's descriptive string - if success
* thrown error - otherwise
*/
jerry_value_t
jerry_symbol_descriptive_string (const jerry_value_t symbol) /**< symbol value */
{
jerry_assert_api_enabled ();
#if JERRY_ESNEXT
if (!ecma_is_value_symbol (symbol))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
/* Note: This operation cannot throw an error */
return ecma_get_symbol_descriptive_string (symbol);
#else /* !JERRY_ESNEXT */
JERRY_UNUSED (symbol);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SYMBOL_NOT_SUPPORTED));
#endif /* JERRY_ESNEXT */
} /* jerry_symbol_descriptive_string */
/**
* Get the number of uint64 digits of a BigInt value
*
* @return number of uint64 digits
*/
uint32_t
jerry_bigint_digit_count (const jerry_value_t value) /**< BigInt value */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_BIGINT
if (!ecma_is_value_bigint (value))
{
return 0;
}
return ecma_bigint_get_size_in_digits (value);
#else /* !JERRY_BUILTIN_BIGINT */
JERRY_UNUSED (value);
return 0;
#endif /* JERRY_BUILTIN_BIGINT */
} /* jerry_bigint_digit_count */
/**
* Get the uint64 digits of a BigInt value (lowest digit first)
*/
void
jerry_bigint_to_digits (const jerry_value_t value, /**< BigInt value */
uint64_t *digits_p, /**< [out] buffer for digits */
uint32_t digit_count, /**< buffer size in digits */
bool *sign_p) /**< [out] sign of BigInt */
{
#if JERRY_BUILTIN_BIGINT
if (!ecma_is_value_bigint (value))
{
if (sign_p != NULL)
{
*sign_p = false;
}
memset (digits_p, 0, digit_count * sizeof (uint64_t));
}
ecma_bigint_get_digits_and_sign (value, digits_p, digit_count, sign_p);
#else /* !JERRY_BUILTIN_BIGINT */
JERRY_UNUSED (value);
if (sign_p != NULL)
{
*sign_p = false;
}
memset (digits_p, 0, digit_count * sizeof (uint64_t));
#endif /* JERRY_BUILTIN_BIGINT */
} /* jerry_bigint_to_digits */
/**
* Get the target object of a Proxy object
*
* @return type error - if proxy_value is not a Proxy object
* target object - otherwise
*/
jerry_value_t
jerry_proxy_target (const jerry_value_t proxy_value) /**< proxy value */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_PROXY
if (ecma_is_value_object (proxy_value))
{
ecma_object_t *object_p = ecma_get_object_from_value (proxy_value);
if (ECMA_OBJECT_IS_PROXY (object_p))
{
ecma_proxy_object_t *proxy_object_p = (ecma_proxy_object_t *) object_p;
if (!ecma_is_value_null (proxy_object_p->target))
{
ecma_ref_object (ecma_get_object_from_value (proxy_object_p->target));
}
return proxy_object_p->target;
}
}
#else /* !JERRY_BUILTIN_PROXY */
JERRY_UNUSED (proxy_value);
#endif /* JERRY_BUILTIN_PROXY */
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_ARGUMENT_IS_NOT_A_PROXY));
} /* jerry_proxy_target */
/**
* Get the handler object of a Proxy object
*
* @return type error - if proxy_value is not a Proxy object
* handler object - otherwise
*/
jerry_value_t
jerry_proxy_handler (const jerry_value_t proxy_value) /**< proxy value */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_PROXY
if (ecma_is_value_object (proxy_value))
{
ecma_object_t *object_p = ecma_get_object_from_value (proxy_value);
if (ECMA_OBJECT_IS_PROXY (object_p))
{
ecma_proxy_object_t *proxy_object_p = (ecma_proxy_object_t *) object_p;
if (!ecma_is_value_null (proxy_object_p->handler))
{
ecma_ref_object (ecma_get_object_from_value (proxy_object_p->handler));
}
return proxy_object_p->handler;
}
}
#else /* !JERRY_BUILTIN_PROXY */
JERRY_UNUSED (proxy_value);
#endif /* JERRY_BUILTIN_PROXY */
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_ARGUMENT_IS_NOT_A_PROXY));
} /* jerry_proxy_handler */
/**
* Validate string buffer for the specified encoding
*
* @return true - if string is well-formed
* false - otherwise
*/
bool
jerry_validate_string (const jerry_char_t *buffer_p, /**< string buffer */
jerry_size_t buffer_size, /**< buffer size */
jerry_encoding_t encoding) /**< buffer encoding */
{
switch (encoding)
{
case JERRY_ENCODING_CESU8:
{
return lit_is_valid_cesu8_string (buffer_p, buffer_size);
}
case JERRY_ENCODING_UTF8:
{
return lit_is_valid_utf8_string (buffer_p, buffer_size, true);
}
default:
{
return false;
}
}
} /* jerry_validate_string */
/**
* Set the log level of the engine.
*
* Log messages with lower significance than the current log level will be ignored by `jerry_log`.
*
* @param level: requested log level
*/
void
jerry_log_set_level (jerry_log_level_t level)
{
JERRY_CONTEXT (log_level) = level;
} /* jerry_log_set_level */
/**
* Log buffer size
*/
#define JERRY_LOG_BUFFER_SIZE 64
/**
* Log a zero-terminated string message.
*
* @param str_p: message
*/
static void
jerry_log_string (const char *str_p)
{
jerry_port_log (str_p);
#if JERRY_DEBUGGER
if (jerry_debugger_is_connected ())
{
jerry_debugger_send_string (JERRY_DEBUGGER_OUTPUT_RESULT,
JERRY_DEBUGGER_OUTPUT_LOG,
(const uint8_t *) str_p,
strlen (str_p));
}
#endif /* JERRY_DEBUGGER */
} /* jerry_log_string */
/**
* Log an unsigned number.
*
* @param num: number
* @param buffer_p: buffer used to construct the number string
*/
static void
jerry_log_unsigned (unsigned int num, char *buffer_p)
{
char *cursor_p = buffer_p + JERRY_LOG_BUFFER_SIZE;
*(--cursor_p) = '\0';
while (num > 0)
{
*(--cursor_p) = (char) ((num % 10) + '0');
num /= 10;
}
jerry_log_string (cursor_p);
} /* jerry_log_unsigned */
/**
* Log a zero-terminated formatted message with the specified log level.
*
* Supported format specifiers:
* %s: zero-terminated string
* %c: character
* %u: unsigned int
*
* @param format_p: format string
* @param level: message log level
*/
void
jerry_log (jerry_log_level_t level, const char *format_p, ...)
{
if (level > JERRY_CONTEXT (log_level))
{
return;
}
va_list vl;
char buffer_p[JERRY_LOG_BUFFER_SIZE];
uint32_t buffer_index = 0;
const char *cursor_p = format_p;
va_start (vl, format_p);
while (*cursor_p != '\0')
{
if (*cursor_p == '%' || buffer_index > JERRY_LOG_BUFFER_SIZE - 2)
{
buffer_p[buffer_index] = '\0';
jerry_log_string (buffer_p);
buffer_index = 0;
}
if (*cursor_p != '%')
{
buffer_p[buffer_index++] = *cursor_p++;
continue;
}
++cursor_p;
if (*cursor_p == '\0')
{
buffer_p[buffer_index++] = '%';
break;
}
switch (*cursor_p++)
{
case 's':
{
jerry_log_string (va_arg (vl, char *));
break;
}
case 'c':
{
/* Arguments of types narrower than int are promoted to int for variadic functions */
buffer_p[buffer_index++] = (char) va_arg (vl, int);
break;
}
case 'u':
{
/* The buffer is always flushed before a substitution, and can be reused to print the number. */
jerry_log_unsigned (va_arg (vl, unsigned int), buffer_p);
break;
}
default:
{
buffer_p[buffer_index++] = '%';
break;
}
}
}
if (buffer_index > 0)
{
buffer_p[buffer_index] = '\0';
jerry_log_string (buffer_p);
}
va_end (vl);
} /* jerry_log */
/**
* Allocate memory on the engine's heap.
*
* Note:
* This function may take away memory from the executed JavaScript code.
* If any other dynamic memory allocation API is available (e.g., libc
* malloc), it should be used instead.
*
* @return allocated memory on success
* NULL otherwise
*/
void *
jerry_heap_alloc (jerry_size_t size) /**< size of the memory block */
{
jerry_assert_api_enabled ();
return jmem_heap_alloc_block_null_on_error (size);
} /* jerry_heap_alloc */
/**
* Free memory allocated on the engine's heap.
*/
void
jerry_heap_free (void *mem_p, /**< value returned by jerry_heap_alloc */
jerry_size_t size) /**< same size as passed to jerry_heap_alloc */
{
jerry_assert_api_enabled ();
jmem_heap_free_block (mem_p, size);
} /* jerry_heap_free */
/**
* When JERRY_VM_HALT is enabled, the callback passed to this function
* is periodically called with the user_p argument. If interval is greater
* than 1, the callback is only called at every interval ticks.
*/
void
jerry_halt_handler (uint32_t interval, /**< interval of the function call */
jerry_halt_cb_t callback, /**< periodically called user function */
void *user_p) /**< pointer passed to the function */
{
#if JERRY_VM_HALT
if (interval == 0)
{
interval = 1;
}
JERRY_CONTEXT (vm_exec_stop_frequency) = interval;
JERRY_CONTEXT (vm_exec_stop_counter) = interval;
JERRY_CONTEXT (vm_exec_stop_cb) = callback;
JERRY_CONTEXT (vm_exec_stop_user_p) = user_p;
#else /* !JERRY_VM_HALT */
JERRY_UNUSED (interval);
JERRY_UNUSED (callback);
JERRY_UNUSED (user_p);
#endif /* JERRY_VM_HALT */
} /* jerry_halt_handler */
/**
* Get backtrace. The backtrace is an array of strings where
* each string contains the position of the corresponding frame.
* The array length is zero if the backtrace is not available.
*
* @return array value
*/
jerry_value_t
jerry_backtrace (uint32_t max_depth) /**< depth limit of the backtrace */
{
return vm_get_backtrace (max_depth);
} /* jerry_backtrace */
/**
* Low-level function to capture each backtrace frame.
* The captured frame data is passed to a callback function.
*/
void
jerry_backtrace_capture (jerry_backtrace_cb_t callback, /**< callback function */
void *user_p) /**< user pointer passed to the callback function */
{
jerry_frame_t frame;
vm_frame_ctx_t *context_p = JERRY_CONTEXT (vm_top_context_p);
while (context_p != NULL)
{
frame.context_p = context_p;
frame.frame_type = JERRY_BACKTRACE_FRAME_JS;
if (!callback (&frame, user_p))
{
return;
}
context_p = context_p->prev_context_p;
}
} /* jerry_backtrace */
/**
* Returns with the type of the backtrace frame.
*
* @return frame type listed in jerry_frame_type_t
*/
jerry_frame_type_t
jerry_frame_type (const jerry_frame_t *frame_p) /**< frame pointer */
{
return (jerry_frame_type_t) frame_p->frame_type;
} /* jerry_frame_type */
/**
* Initialize and return with the location private field of a backtrace frame.
*
* @return pointer to the location private field - if the location is available,
* NULL - otherwise
*/
const jerry_frame_location_t *
jerry_frame_location (jerry_frame_t *frame_p) /**< frame pointer */
{
JERRY_UNUSED (frame_p);
#if JERRY_LINE_INFO
if (frame_p->frame_type == JERRY_BACKTRACE_FRAME_JS)
{
vm_frame_ctx_t *context_p = frame_p->context_p;
const ecma_compiled_code_t *bytecode_header_p = context_p->shared_p->bytecode_header_p;
if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_LINE_INFO))
{
return NULL;
}
frame_p->location.source_name = ecma_get_source_name (bytecode_header_p);
ecma_line_info_get (ecma_compiled_code_get_line_info (bytecode_header_p),
(uint32_t) (context_p->byte_code_p - context_p->byte_code_start_p),
&frame_p->location);
return &frame_p->location;
}
#endif /* JERRY_LINE_INFO */
return NULL;
} /* jerry_frame_location */
/**
* Initialize and return with the called function private field of a backtrace frame.
* The backtrace frame is created for running the code bound to this function.
*
* @return pointer to the called function - if the function is available,
* NULL - otherwise
*/
const jerry_value_t *
jerry_frame_callee (jerry_frame_t *frame_p) /**< frame pointer */
{
if (frame_p->frame_type == JERRY_BACKTRACE_FRAME_JS)
{
vm_frame_ctx_t *context_p = frame_p->context_p;
if (context_p->shared_p->function_object_p != NULL)
{
frame_p->function = ecma_make_object_value (context_p->shared_p->function_object_p);
return &frame_p->function;
}
}
return NULL;
} /* jerry_frame_callee */
/**
* Initialize and return with the 'this' binding private field of a backtrace frame.
* The 'this' binding is a hidden value passed to the called function. As for arrow
* functions, the 'this' binding is assigned at function creation.
*
* @return pointer to the 'this' binding - if the binding is available,
* NULL - otherwise
*/
const jerry_value_t *
jerry_frame_this (jerry_frame_t *frame_p) /**< frame pointer */
{
if (frame_p->frame_type == JERRY_BACKTRACE_FRAME_JS)
{
frame_p->this_binding = frame_p->context_p->this_binding;
return &frame_p->this_binding;
}
return NULL;
} /* jerry_frame_this */
/**
* Returns true, if the code bound to the backtrace frame is strict mode code.
*
* @return true - if strict mode code is bound to the frame,
* false - otherwise
*/
bool
jerry_frame_is_strict (jerry_frame_t *frame_p) /**< frame pointer */
{
return (frame_p->frame_type == JERRY_BACKTRACE_FRAME_JS
&& (frame_p->context_p->status_flags & VM_FRAME_CTX_IS_STRICT) != 0);
} /* jerry_frame_is_strict */
/**
* Get the source name (usually a file name) of the currently executed script or the given function object
*
* Note: returned value must be freed with jerry_value_free, when it is no longer needed
*
* @return JS string constructed from
* - the currently executed function object's source name, if the given value is undefined
* - source name of the function object, if the given value is a function object
* - "<anonymous>", otherwise
*/
jerry_value_t
jerry_source_name (const jerry_value_t value) /**< jerry api value */
{
#if JERRY_SOURCE_NAME
if (ecma_is_value_undefined (value) && JERRY_CONTEXT (vm_top_context_p) != NULL)
{
return ecma_copy_value (ecma_get_source_name (JERRY_CONTEXT (vm_top_context_p)->shared_p->bytecode_header_p));
}
ecma_value_t script_value = ecma_script_get_from_value (value);
if (script_value == JMEM_CP_NULL)
{
return ecma_make_magic_string_value (LIT_MAGIC_STRING_SOURCE_NAME_ANON);
}
const cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
return ecma_copy_value (script_p->source_name);
#else /* !JERRY_SOURCE_NAME */
JERRY_UNUSED (value);
return ecma_make_magic_string_value (LIT_MAGIC_STRING_SOURCE_NAME_ANON);
#endif /* JERRY_SOURCE_NAME */
} /* jerry_source_name */
/**
* Returns the user value assigned to a script / module / function.
*
* Note:
* This value is usually set by the parser when
* the JERRY_PARSE_HAS_USER_VALUE flag is passed.
*
* @return user value
*/
jerry_value_t
jerry_source_user_value (const jerry_value_t value) /**< jerry api value */
{
ecma_value_t script_value = ecma_script_get_from_value (value);
if (script_value == JMEM_CP_NULL)
{
return ECMA_VALUE_UNDEFINED;
}
const cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
if (!(script_p->refs_and_type & CBC_SCRIPT_HAS_USER_VALUE))
{
return ECMA_VALUE_UNDEFINED;
}
return ecma_copy_value (CBC_SCRIPT_GET_USER_VALUE (script_p));
} /* jerry_source_user_value */
/**
* Checks whether an ECMAScript code is compiled by eval
* like (eval, new Function, jerry_eval, etc.) command.
*
* @return true, if code is compiled by eval like command
* false, otherwise
*/
bool
jerry_function_is_dynamic (const jerry_value_t value) /**< jerry api value */
{
ecma_value_t script_value = ecma_script_get_from_value (value);
if (script_value == JMEM_CP_NULL)
{
return false;
}
const cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
return (script_p->refs_and_type & CBC_SCRIPT_IS_EVAL_CODE) != 0;
} /* jerry_function_is_dynamic */
/**
* Returns a newly created source info structure corresponding to the passed script/module/function.
*
* @return a newly created source info, if at least one field is available, NULL otherwise
*/
jerry_source_info_t *
jerry_source_info (const jerry_value_t value) /**< jerry api value */
{
jerry_assert_api_enabled ();
#if JERRY_FUNCTION_TO_STRING
if (!ecma_is_value_object (value))
{
return NULL;
}
jerry_source_info_t source_info;
source_info.enabled_fields = 0;
source_info.source_code = ECMA_VALUE_UNDEFINED;
source_info.function_arguments = ECMA_VALUE_UNDEFINED;
source_info.source_range_start = 0;
source_info.source_range_length = 0;
ecma_object_t *object_p = ecma_get_object_from_value (value);
cbc_script_t *script_p = NULL;
while (true)
{
switch (ecma_get_object_type (object_p))
{
case ECMA_OBJECT_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
const ecma_compiled_code_t *bytecode_p = NULL;
if (ext_object_p->u.cls.type == ECMA_OBJECT_CLASS_SCRIPT)
{
bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ext_object_p->u.cls.u3.value);
}
#if JERRY_MODULE_SYSTEM
else if (ext_object_p->u.cls.type == ECMA_OBJECT_CLASS_MODULE)
{
ecma_module_t *module_p = (ecma_module_t *) object_p;
if (!(module_p->header.u.cls.u2.module_flags & ECMA_MODULE_IS_NATIVE))
{
bytecode_p = module_p->u.compiled_code_p;
}
}
#endif /* JERRY_MODULE_SYSTEM */
if (bytecode_p == NULL)
{
return NULL;
}
ecma_value_t script_value = ((cbc_uint8_arguments_t *) bytecode_p)->script_value;
script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
break;
}
case ECMA_OBJECT_TYPE_FUNCTION:
{
const ecma_compiled_code_t *bytecode_p;
bytecode_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p);
ecma_value_t script_value = ((cbc_uint8_arguments_t *) bytecode_p)->script_value;
script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
if (bytecode_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO)
{
uint8_t *extended_info_p = ecma_compiled_code_resolve_extended_info (bytecode_p);
uint8_t extended_info = *extended_info_p;
#if JERRY_ESNEXT
if (extended_info & CBC_EXTENDED_CODE_FLAGS_HAS_ARGUMENT_LENGTH)
{
ecma_extended_info_decode_vlq (&extended_info_p);
}
#endif /* JERRY_ESNEXT */
if (extended_info & CBC_EXTENDED_CODE_FLAGS_SOURCE_CODE_IN_ARGUMENTS)
{
ecma_value_t function_arguments = CBC_SCRIPT_GET_FUNCTION_ARGUMENTS (script_p, script_p->refs_and_type);
ecma_ref_ecma_string (ecma_get_string_from_value (function_arguments));
source_info.enabled_fields |= JERRY_SOURCE_INFO_HAS_SOURCE_CODE;
source_info.source_code = function_arguments;
script_p = NULL;
}
source_info.enabled_fields |= JERRY_SOURCE_INFO_HAS_SOURCE_RANGE;
source_info.source_range_start = ecma_extended_info_decode_vlq (&extended_info_p);
source_info.source_range_length = ecma_extended_info_decode_vlq (&extended_info_p);
}
JERRY_ASSERT (script_p != NULL || (source_info.enabled_fields & JERRY_SOURCE_INFO_HAS_SOURCE_CODE));
if (source_info.enabled_fields == 0 && (script_p->refs_and_type & CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS))
{
ecma_value_t function_arguments = CBC_SCRIPT_GET_FUNCTION_ARGUMENTS (script_p, script_p->refs_and_type);
ecma_ref_ecma_string (ecma_get_string_from_value (function_arguments));
source_info.enabled_fields |= JERRY_SOURCE_INFO_HAS_FUNCTION_ARGUMENTS;
source_info.function_arguments = function_arguments;
}
break;
}
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
object_p =
ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, ext_object_p->u.bound_function.target_function);
continue;
}
#if JERRY_ESNEXT
case ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION:
{
ecma_value_t script_value = ((ecma_extended_object_t *) object_p)->u.constructor_function.script_value;
script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
break;
}
#endif /* JERRY_ESNEXT */
default:
{
return NULL;
}
}
break;
}
jerry_source_info_t *source_info_p = jmem_heap_alloc_block_null_on_error (sizeof (jerry_source_info_t));
if (source_info_p == NULL)
{
return NULL;
}
if (script_p != NULL)
{
ecma_ref_ecma_string (ecma_get_string_from_value (script_p->source_code));
source_info.enabled_fields |= JERRY_SOURCE_INFO_HAS_SOURCE_CODE;
source_info.source_code = script_p->source_code;
}
JERRY_ASSERT (source_info.enabled_fields != 0);
*source_info_p = source_info;
return source_info_p;
#else /* !JERRY_FUNCTION_TO_STRING */
JERRY_UNUSED (value);
return NULL;
#endif /* JERRY_FUNCTION_TO_STRING */
} /* jerry_source_info */
/**
* Frees the the source info structure returned by jerry_source_info.
*/
void
jerry_source_info_free (jerry_source_info_t *source_info_p) /**< source info block */
{
jerry_assert_api_enabled ();
#if JERRY_FUNCTION_TO_STRING
if (source_info_p != NULL)
{
ecma_free_value (source_info_p->source_code);
ecma_free_value (source_info_p->function_arguments);
jmem_heap_free_block (source_info_p, sizeof (jerry_source_info_t));
}
#else /* !JERRY_FUNCTION_TO_STRING */
JERRY_UNUSED (source_info_p);
#endif /* JERRY_FUNCTION_TO_STRING */
} /* jerry_source_info_free */
/**
* Replaces the currently active realm with another realm.
*
* The replacement should be temporary, and the original realm must be
* restored after the tasks are completed. During the replacement, the
* realm must be referenced by the application (i.e. the gc must not
* reclaim it). This is also true to the returned previously active
* realm, so there is no need to free the value after the restoration.
*
* @return previous realm value - if the passed value is a realm
* exception - otherwise
*/
jerry_value_t
jerry_set_realm (jerry_value_t realm_value) /**< jerry api value */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_REALMS
if (ecma_is_value_object (realm_value))
{
ecma_object_t *object_p = ecma_get_object_from_value (realm_value);
if (ecma_builtin_is_global (object_p))
{
ecma_global_object_t *previous_global_object_p = JERRY_CONTEXT (global_object_p);
JERRY_CONTEXT (global_object_p) = (ecma_global_object_t *) object_p;
return ecma_make_object_value ((ecma_object_t *) previous_global_object_p);
}
}
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PASSED_ARGUMENT_IS_NOT_A_REALM));
#else /* !JERRY_BUILTIN_REALMS */
JERRY_UNUSED (realm_value);
return jerry_throw_sz (JERRY_ERROR_REFERENCE, ecma_get_error_msg (ECMA_ERR_REALM_IS_NOT_AVAILABLE));
#endif /* JERRY_BUILTIN_REALMS */
} /* jerry_set_realm */
/**
* Gets the 'this' binding of a realm
*
* @return type error - if realm_value is not a realm
* this value - otherwise
*/
jerry_value_t
jerry_realm_this (jerry_value_t realm) /**< realm value */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_REALMS
if (ecma_is_value_object (realm))
{
ecma_object_t *object_p = ecma_get_object_from_value (realm);
if (ecma_builtin_is_global (object_p))
{
ecma_global_object_t *global_object_p = (ecma_global_object_t *) object_p;
ecma_ref_object (ecma_get_object_from_value (global_object_p->this_binding));
return global_object_p->this_binding;
}
}
#else /* !JERRY_BUILTIN_REALMS */
ecma_object_t *global_object_p = ecma_builtin_get_global ();
if (realm == ecma_make_object_value (global_object_p))
{
ecma_ref_object (global_object_p);
return realm;
}
#endif /* JERRY_BUILTIN_REALMS */
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PASSED_ARGUMENT_IS_NOT_A_REALM));
} /* jerry_realm_this */
/**
* Sets the 'this' binding of a realm
*
* This function must be called before executing any script on the realm.
* Otherwise the operation is undefined.
*
* @return type error - if realm_value is not a realm or this_value is not object
* true - otherwise
*/
jerry_value_t
jerry_realm_set_this (jerry_value_t realm, /**< realm value */
jerry_value_t this_value) /**< this value */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_REALMS
if (!ecma_is_value_object (this_value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SECOND_ARGUMENT_MUST_BE_AN_OBJECT));
}
if (ecma_is_value_object (realm))
{
ecma_object_t *object_p = ecma_get_object_from_value (realm);
if (ecma_builtin_is_global (object_p))
{
ecma_global_object_t *global_object_p = (ecma_global_object_t *) object_p;
global_object_p->this_binding = this_value;
ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL, ecma_get_object_from_value (this_value));
ECMA_SET_NON_NULL_POINTER (global_object_p->global_env_cp, global_lex_env_p);
#if JERRY_ESNEXT
global_object_p->global_scope_cp = global_object_p->global_env_cp;
#endif /* JERRY_ESNEXT */
ecma_deref_object (global_lex_env_p);
return ECMA_VALUE_TRUE;
}
}
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_FIRST_ARGUMENT_IS_NOT_A_REALM));
#else /* !JERRY_BUILTIN_REALMS */
JERRY_UNUSED (realm);
JERRY_UNUSED (this_value);
return jerry_throw_sz (JERRY_ERROR_REFERENCE, ecma_get_error_msg (ECMA_ERR_REALM_IS_NOT_AVAILABLE));
#endif /* JERRY_BUILTIN_REALMS */
} /* jerry_realm_set_this */
/**
* Check if the given value is an ArrayBuffer object.
*
* @return true - if it is an ArrayBuffer object
* false - otherwise
*/
bool
jerry_value_is_arraybuffer (const jerry_value_t value) /**< value to check if it is an ArrayBuffer */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
return ecma_is_arraybuffer (value);
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
return false;
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_value_is_arraybuffer */
/**
* Creates an ArrayBuffer object with the given length (size).
*
* Notes:
* * the length is specified in bytes.
* * returned value must be freed with jerry_value_free, when it is no longer needed.
* * if the typed arrays are disabled this will return a TypeError.
*
* @return value of the constructed ArrayBuffer object
*/
jerry_value_t
jerry_arraybuffer (const jerry_length_t size) /**< size of the backing store allocated
* for the array buffer in bytes */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
return jerry_return (ecma_make_object_value (ecma_arraybuffer_new_object (size)));
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (size);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_arraybuffer */
/**
* Creates an ArrayBuffer object with user specified buffer.
*
* Notes:
* * the size is specified in bytes.
* * the buffer passed should be at least the specified bytes big.
* * if the typed arrays are disabled this will return a TypeError.
* * if the size is zero or buffer_p is a null pointer this will return an empty ArrayBuffer.
*
* @return value of the newly constructed array buffer object
*/
jerry_value_t
jerry_arraybuffer_external (uint8_t *buffer_p, /**< the backing store used by the array buffer object */
jerry_length_t size, /**< size of the buffer in bytes */
void *user_p) /**< user pointer assigned to the array buffer object */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
ecma_object_t *arraybuffer_p;
if (JERRY_UNLIKELY (size == 0))
{
arraybuffer_p = ecma_arraybuffer_new_object (0);
}
else
{
arraybuffer_p = ecma_arraybuffer_create_object_with_buffer (ECMA_OBJECT_CLASS_ARRAY_BUFFER, size);
ecma_arraybuffer_pointer_t *arraybuffer_pointer_p = (ecma_arraybuffer_pointer_t *) arraybuffer_p;
arraybuffer_pointer_p->arraybuffer_user_p = user_p;
if (buffer_p != NULL)
{
arraybuffer_pointer_p->extended_object.u.cls.u1.array_buffer_flags |= ECMA_ARRAYBUFFER_ALLOCATED;
arraybuffer_pointer_p->buffer_p = buffer_p;
}
}
return jerry_return (ecma_make_object_value (arraybuffer_p));
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (size);
JERRY_UNUSED (buffer_p);
JERRY_UNUSED (user_p);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_arraybuffer_external */
/**
* Check if the given value is a SharedArrayBuffer object.
*
* @return true - if it is a SharedArrayBuffer object
* false - otherwise
*/
bool
jerry_value_is_shared_arraybuffer (const jerry_value_t value) /**< value to check if it is a SharedArrayBuffer */
{
jerry_assert_api_enabled ();
return ecma_is_shared_arraybuffer (value);
} /* jerry_value_is_shared_arraybuffer */
/**
* Creates a SharedArrayBuffer object with the given length (size).
*
* Notes:
* * the length is specified in bytes.
* * returned value must be freed with jerry_value_free, when it is no longer needed.
* * if the typed arrays are disabled this will return a TypeError.
*
* @return value of the constructed SharedArrayBuffer object
*/
jerry_value_t
jerry_shared_arraybuffer (jerry_length_t size) /**< size of the backing store allocated
* for the shared array buffer in bytes */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_SHAREDARRAYBUFFER
return jerry_return (ecma_make_object_value (ecma_shared_arraybuffer_new_object (size)));
#else /* !JERRY_BUILTIN_SHAREDARRAYBUFFER */
JERRY_UNUSED (size);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SHARED_ARRAYBUFFER_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_SHAREDARRAYBUFFER */
} /* jerry_shared_arraybuffer */
/**
* Creates a SharedArrayBuffer object with user specified buffer.
*
* Notes:
* * the size is specified in bytes.
* * the buffer passed should be at least the specified bytes big.
* * if the typed arrays are disabled this will return a TypeError.
* * if the size is zero or buffer_p is a null pointer this will return an empty SharedArrayBuffer.
*
* @return value of the newly constructed shared array buffer object
*/
jerry_value_t
jerry_shared_arraybuffer_external (uint8_t *buffer_p, /**< the backing store used by the
* shared array buffer object */
jerry_length_t size, /**< size of the buffer in bytes */
void *user_p) /**< user pointer assigned to the
* shared array buffer object */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_SHAREDARRAYBUFFER
ecma_object_t *shared_arraybuffer_p;
if (JERRY_UNLIKELY (size == 0))
{
shared_arraybuffer_p = ecma_shared_arraybuffer_new_object (0);
}
else
{
shared_arraybuffer_p = ecma_arraybuffer_create_object_with_buffer (ECMA_OBJECT_CLASS_SHARED_ARRAY_BUFFER, size);
ecma_arraybuffer_pointer_t *shared_arraybuffer_pointer_p = (ecma_arraybuffer_pointer_t *) shared_arraybuffer_p;
shared_arraybuffer_pointer_p->arraybuffer_user_p = user_p;
if (buffer_p != NULL)
{
shared_arraybuffer_pointer_p->extended_object.u.cls.u1.array_buffer_flags |= ECMA_ARRAYBUFFER_ALLOCATED;
shared_arraybuffer_pointer_p->buffer_p = buffer_p;
}
}
return ecma_make_object_value (shared_arraybuffer_p);
#else /* !JERRY_BUILTIN_SHAREDARRAYBUFFER */
JERRY_UNUSED (size);
JERRY_UNUSED (buffer_p);
JERRY_UNUSED (user_p);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SHARED_ARRAYBUFFER_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_SHAREDARRAYBUFFER */
} /* jerry_shared_arraybuffer_external */
#if JERRY_BUILTIN_TYPEDARRAY
/**
* Allocate a backing store for an array buffer, ignores allocation fails.
*
* @return true on success,
* false otherwise
*/
static bool
jerry_arraybuffer_allocate_buffer_no_throw (ecma_object_t *arraybuffer_p) /**< ArrayBuffer object */
{
JERRY_ASSERT (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED));
if (ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_DETACHED)
{
return false;
}
return ecma_arraybuffer_allocate_buffer (arraybuffer_p) != ECMA_VALUE_ERROR;
} /* jerry_arraybuffer_allocate_buffer_no_throw */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
/**
* Copy bytes into the ArrayBuffer or SharedArrayBuffer from a buffer.
*
* Note:
* * returns 0, if the passed object is not an ArrayBuffer or SharedArrayBuffer
*
* @return number of bytes copied into the ArrayBuffer or SharedArrayBuffer.
*/
jerry_length_t
jerry_arraybuffer_write (jerry_value_t value, /**< target ArrayBuffer or SharedArrayBuffer */
jerry_length_t offset, /**< start offset of the ArrayBuffer */
const uint8_t *buf_p, /**< buffer to copy from */
jerry_length_t buf_size) /**< number of bytes to copy from the buffer */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (!(ecma_is_arraybuffer (value) || ecma_is_shared_arraybuffer (value)))
{
return 0;
}
ecma_object_t *arraybuffer_p = ecma_get_object_from_value (value);
if (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)
&& !jerry_arraybuffer_allocate_buffer_no_throw (arraybuffer_p))
{
return 0;
}
jerry_length_t length = ecma_arraybuffer_get_length (arraybuffer_p);
if (offset >= length)
{
return 0;
}
jerry_length_t copy_count = JERRY_MIN (length - offset, buf_size);
if (copy_count > 0)
{
lit_utf8_byte_t *buffer_p = ecma_arraybuffer_get_buffer (arraybuffer_p);
memcpy ((void *) (buffer_p + offset), (void *) buf_p, copy_count);
}
return copy_count;
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
JERRY_UNUSED (offset);
JERRY_UNUSED (buf_p);
JERRY_UNUSED (buf_size);
return 0;
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_arraybuffer_write */
/**
* Copy bytes from a buffer into an ArrayBuffer or SharedArrayBuffer.
*
* Note:
* * if the object passed is not an ArrayBuffer or SharedArrayBuffer will return 0.
*
* @return number of bytes read from the ArrayBuffer.
*/
jerry_length_t
jerry_arraybuffer_read (const jerry_value_t value, /**< ArrayBuffer or SharedArrayBuffer to read from */
jerry_length_t offset, /**< start offset of the ArrayBuffer or SharedArrayBuffer */
uint8_t *buf_p, /**< destination buffer to copy to */
jerry_length_t buf_size) /**< number of bytes to copy into the buffer */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (!(ecma_is_arraybuffer (value) || ecma_is_shared_arraybuffer (value)))
{
return 0;
}
ecma_object_t *arraybuffer_p = ecma_get_object_from_value (value);
if (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)
&& !jerry_arraybuffer_allocate_buffer_no_throw (arraybuffer_p))
{
return 0;
}
jerry_length_t length = ecma_arraybuffer_get_length (arraybuffer_p);
if (offset >= length)
{
return 0;
}
jerry_length_t copy_count = JERRY_MIN (length - offset, buf_size);
if (copy_count > 0)
{
lit_utf8_byte_t *buffer_p = ecma_arraybuffer_get_buffer (arraybuffer_p);
memcpy ((void *) buf_p, (void *) (buffer_p + offset), copy_count);
}
return copy_count;
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
JERRY_UNUSED (offset);
JERRY_UNUSED (buf_p);
JERRY_UNUSED (buf_size);
return 0;
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_arraybuffer_read */
/**
* Get the length (size) of the ArrayBuffer or SharedArrayBuffer in bytes.
*
* Note:
* This is the 'byteLength' property of an ArrayBuffer or SharedArrayBuffer.
*
* @return the length of the ArrayBuffer in bytes.
*/
jerry_length_t
jerry_arraybuffer_size (const jerry_value_t value) /**< ArrayBuffer or SharedArrayBuffer */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (ecma_is_arraybuffer (value) || ecma_is_shared_arraybuffer (value))
{
ecma_object_t *arraybuffer_p = ecma_get_object_from_value (value);
return ecma_arraybuffer_get_length (arraybuffer_p);
}
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
#endif /* JERRY_BUILTIN_TYPEDARRAY */
return 0;
} /* jerry_arraybuffer_size */
/**
* Get a pointer for the start of the ArrayBuffer.
*
* Note:
* * This is a high-risk operation as the bounds are not checked
* when accessing the pointer elements.
*
* @return pointer to the back-buffer of the ArrayBuffer.
* pointer is NULL if:
* - the parameter is not an ArrayBuffer
* - an external ArrayBuffer has been detached
*/
uint8_t *
jerry_arraybuffer_data (const jerry_value_t array_buffer) /**< Array Buffer to use */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (!(ecma_is_arraybuffer (array_buffer) || ecma_is_shared_arraybuffer (array_buffer)))
{
return NULL;
}
ecma_object_t *arraybuffer_p = ecma_get_object_from_value (array_buffer);
if (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)
&& !jerry_arraybuffer_allocate_buffer_no_throw (arraybuffer_p))
{
return NULL;
}
return (uint8_t *) ecma_arraybuffer_get_buffer (arraybuffer_p);
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (array_buffer);
#endif /* JERRY_BUILTIN_TYPEDARRAY */
return NULL;
} /* jerry_arraybuffer_data */
/**
* Get if the ArrayBuffer is detachable.
*
* @return boolean value - if success
* value marked with error flag - otherwise
*/
bool
jerry_arraybuffer_is_detachable (const jerry_value_t value) /**< ArrayBuffer */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (ecma_is_arraybuffer (value))
{
ecma_object_t *buffer_p = ecma_get_object_from_value (value);
return !ecma_arraybuffer_is_detached (buffer_p);
}
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
#endif /* JERRY_BUILTIN_TYPEDARRAY */
return false;
} /* jerry_arraybuffer_is_detachable */
/**
* Detach the underlying data block from ArrayBuffer and set its bytelength to 0.
*
* Note: if the ArrayBuffer has a separate data buffer, the free callback set by
* jerry_arraybuffer_set_allocation_callbacks is called for this buffer
*
* @return null value - if success
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_arraybuffer_detach (jerry_value_t value) /**< ArrayBuffer */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (ecma_is_arraybuffer (value))
{
ecma_object_t *buffer_p = ecma_get_object_from_value (value);
if (ecma_arraybuffer_detach (buffer_p))
{
return ECMA_VALUE_NULL;
}
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_ARRAY_BUFFER_DETACHED));
}
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
#endif /* JERRY_BUILTIN_TYPEDARRAY */
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_EXPECTED_AN_ARRAYBUFFER));
} /* jerry_arraybuffer_detach */
/**
* Checks whether a buffer is currently allocated for an array buffer or typed array.
*
* @return true, if a buffer is allocated for an array buffer or typed array
* false, otherwise
*/
bool
jerry_arraybuffer_has_buffer (const jerry_value_t value) /**< array buffer or typed array value */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (!ecma_is_value_object (value))
{
return false;
}
ecma_object_t *object_p = ecma_get_object_from_value (value);
if (ecma_object_is_typedarray (object_p))
{
object_p = ecma_typedarray_get_arraybuffer (object_p);
}
else if (!(ecma_object_class_is (object_p, ECMA_OBJECT_CLASS_ARRAY_BUFFER)
|| ecma_object_is_shared_arraybuffer (object_p)))
{
return false;
}
return (ECMA_ARRAYBUFFER_GET_FLAGS (object_p) & ECMA_ARRAYBUFFER_ALLOCATED) != 0;
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
return false;
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_arraybuffer_has_buffer */
/**
* Array buffers which size is less or equal than the limit passed to this function are allocated in
* a single memory block. The allocator callbacks set by jerry_arraybuffer_set_allocation_callbacks
* are not called for these array buffers. The default limit is 256 bytes.
*/
void
jerry_arraybuffer_heap_allocation_limit (jerry_length_t allocation_limit) /**< maximum size of
* compact allocation */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
JERRY_CONTEXT (arraybuffer_compact_allocation_limit) = allocation_limit;
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (allocation_limit);
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_arraybuffer_heap_allocation_limit */
/**
* Set callbacks for allocating and freeing backing stores for array buffer objects.
*/
void
jerry_arraybuffer_allocator (jerry_arraybuffer_allocate_cb_t allocate_callback, /**< callback for allocating
* array buffer memory */
jerry_arraybuffer_free_cb_t free_callback, /**< callback for freeing
* array buffer memory */
void *user_p) /**< user pointer passed to the callbacks */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
JERRY_CONTEXT (arraybuffer_allocate_callback) = allocate_callback;
JERRY_CONTEXT (arraybuffer_free_callback) = free_callback;
JERRY_CONTEXT (arraybuffer_allocate_callback_user_p) = user_p;
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (allocate_callback);
JERRY_UNUSED (free_callback);
JERRY_UNUSED (user_p);
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_arraybuffer_allocator */
/**
* DataView related functions
*/
/**
* Creates a DataView object with the given ArrayBuffer, ByteOffset and ByteLength arguments.
*
* Notes:
* * returned value must be freed with jerry_value_free, when it is no longer needed.
* * if the DataView bulitin is disabled this will return a TypeError.
*
* @return value of the constructed DataView object - if success
* created error - otherwise
*/
jerry_value_t
jerry_dataview (const jerry_value_t array_buffer, /**< arraybuffer to create DataView from */
jerry_length_t byte_offset, /**< offset in bytes, to the first byte in the buffer */
jerry_length_t byte_length) /**< number of elements in the byte array */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_DATAVIEW
if (ecma_is_value_exception (array_buffer))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_value_t arguments_p[3] = { array_buffer,
ecma_make_uint32_value (byte_offset),
ecma_make_uint32_value (byte_length) };
ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target_p);
if (old_new_target_p == NULL)
{
JERRY_CONTEXT (current_new_target_p) = ecma_builtin_get (ECMA_BUILTIN_ID_DATAVIEW);
}
ecma_value_t dataview_value = ecma_op_dataview_create (arguments_p, 3);
JERRY_CONTEXT (current_new_target_p) = old_new_target_p;
return jerry_return (dataview_value);
#else /* !JERRY_BUILTIN_DATAVIEW */
JERRY_UNUSED (array_buffer);
JERRY_UNUSED (byte_offset);
JERRY_UNUSED (byte_length);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_DATA_VIEW_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_DATAVIEW */
} /* jerry_dataview */
/**
* Check if the given value is a DataView object.
*
* @return true - if it is a DataView object
* false - otherwise
*/
bool
jerry_value_is_dataview (const jerry_value_t value) /**< value to check if it is a DataView object */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_DATAVIEW
return ecma_is_dataview (value);
#else /* !JERRY_BUILTIN_DATAVIEW */
JERRY_UNUSED (value);
return false;
#endif /* JERRY_BUILTIN_DATAVIEW */
} /* jerry_value_is_dataview */
/**
* Get the underlying ArrayBuffer from a DataView.
*
* Additionally the byteLength and byteOffset properties are also returned
* which were specified when the DataView was created.
*
* Note:
* the returned value must be freed with a jerry_value_free call
*
* @return ArrayBuffer of a DataView
* TypeError if the object is not a DataView.
*/
jerry_value_t
jerry_dataview_buffer (const jerry_value_t value, /**< DataView to get the arraybuffer from */
jerry_length_t *byte_offset, /**< [out] byteOffset property */
jerry_length_t *byte_length) /**< [out] byteLength property */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_DATAVIEW
if (ecma_is_value_exception (value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
ecma_dataview_object_t *dataview_p = ecma_op_dataview_get_object (value);
if (JERRY_UNLIKELY (dataview_p == NULL))
{
return ecma_create_exception_from_context ();
}
if (byte_offset != NULL)
{
*byte_offset = dataview_p->byte_offset;
}
if (byte_length != NULL)
{
*byte_length = dataview_p->header.u.cls.u3.length;
}
ecma_object_t *arraybuffer_p = dataview_p->buffer_p;
ecma_ref_object (arraybuffer_p);
return ecma_make_object_value (arraybuffer_p);
#else /* !JERRY_BUILTIN_DATAVIEW */
JERRY_UNUSED (value);
JERRY_UNUSED (byte_offset);
JERRY_UNUSED (byte_length);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_DATA_VIEW_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_DATAVIEW */
} /* jerry_dataview_buffer */
/**
* TypedArray related functions
*/
/**
* Check if the given value is a TypedArray object.
*
* @return true - if it is a TypedArray object
* false - otherwise
*/
bool
jerry_value_is_typedarray (const jerry_value_t value) /**< value to check if it is a TypedArray */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
return ecma_is_typedarray (value);
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
return false;
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_value_is_typedarray */
#if JERRY_BUILTIN_TYPEDARRAY
/**
* TypedArray mapping type
*/
typedef struct
{
jerry_typedarray_type_t api_type; /**< api type */
ecma_builtin_id_t prototype_id; /**< prototype ID */
ecma_typedarray_type_t id; /**< typedArray ID */
uint8_t element_size_shift; /**< element size shift */
} jerry_typedarray_mapping_t;
/**
* List of TypedArray mappings
*/
static jerry_typedarray_mapping_t jerry_typedarray_mappings[] = {
#define TYPEDARRAY_ENTRY(NAME, LIT_NAME, SIZE_SHIFT) \
{ \
JERRY_TYPEDARRAY_##NAME, ECMA_BUILTIN_ID_##NAME##ARRAY_PROTOTYPE, ECMA_##LIT_NAME##_ARRAY, SIZE_SHIFT \
}
TYPEDARRAY_ENTRY (UINT8, UINT8, 0), TYPEDARRAY_ENTRY (UINT8CLAMPED, UINT8_CLAMPED, 0),
TYPEDARRAY_ENTRY (INT8, INT8, 0), TYPEDARRAY_ENTRY (UINT16, UINT16, 1),
TYPEDARRAY_ENTRY (INT16, INT16, 1), TYPEDARRAY_ENTRY (UINT32, UINT32, 2),
TYPEDARRAY_ENTRY (INT32, INT32, 2), TYPEDARRAY_ENTRY (FLOAT32, FLOAT32, 2),
#if JERRY_NUMBER_TYPE_FLOAT64
TYPEDARRAY_ENTRY (FLOAT64, FLOAT64, 3),
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
#if JERRY_BUILTIN_BIGINT
TYPEDARRAY_ENTRY (BIGINT64, BIGINT64, 3), TYPEDARRAY_ENTRY (BIGUINT64, BIGUINT64, 3),
#endif /* JERRY_BUILTIN_BIGINT */
#undef TYPEDARRAY_ENTRY
};
/**
* Helper function to get the TypedArray prototype, typedArray id, and element size shift
* information.
*
* @return true - if the TypedArray information was found
* false - if there is no such TypedArray type
*/
static bool
jerry_typedarray_find_by_type (jerry_typedarray_type_t type_name, /**< type of the TypedArray */
ecma_builtin_id_t *prototype_id, /**< [out] found prototype object id */
ecma_typedarray_type_t *id, /**< [out] found typedArray id */
uint8_t *element_size_shift) /**< [out] found element size shift value */
{
JERRY_ASSERT (prototype_id != NULL);
JERRY_ASSERT (id != NULL);
JERRY_ASSERT (element_size_shift != NULL);
for (uint32_t i = 0; i < sizeof (jerry_typedarray_mappings) / sizeof (jerry_typedarray_mappings[0]); i++)
{
if (type_name == jerry_typedarray_mappings[i].api_type)
{
*prototype_id = jerry_typedarray_mappings[i].prototype_id;
*id = jerry_typedarray_mappings[i].id;
*element_size_shift = jerry_typedarray_mappings[i].element_size_shift;
return true;
}
}
return false;
} /* jerry_typedarray_find_by_type */
#endif /* JERRY_BUILTIN_TYPEDARRAY */
/**
* Create a TypedArray object with a given type and length.
*
* Notes:
* * returns TypeError if an incorrect type (type_name) is specified.
* * byteOffset property will be set to 0.
* * byteLength property will be a multiple of the length parameter (based on the type).
*
* @return - new TypedArray object
*/
jerry_value_t
jerry_typedarray (jerry_typedarray_type_t type_name, /**< type of TypedArray to create */
jerry_length_t length) /**< element count of the new TypedArray */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
ecma_builtin_id_t prototype_id = 0;
ecma_typedarray_type_t id = 0;
uint8_t element_size_shift = 0;
if (!jerry_typedarray_find_by_type (type_name, &prototype_id, &id, &element_size_shift))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_FOR_TYPEDARRAY));
}
ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id);
ecma_value_t array_value =
ecma_typedarray_create_object_with_length (length, NULL, prototype_obj_p, element_size_shift, id);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (array_value));
return array_value;
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (type_name);
JERRY_UNUSED (length);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_typedarray */
/**
* Create a TypedArray object using the given arraybuffer and size information.
*
* Notes:
* * returns TypeError if an incorrect type (type_name) is specified.
* * this is the 'new %TypedArray%(arraybuffer, byteOffset, length)' equivalent call.
*
* @return - new TypedArray object
*/
jerry_value_t
jerry_typedarray_with_buffer_span (jerry_typedarray_type_t type, /**< type of TypedArray to create */
const jerry_value_t arraybuffer, /**< ArrayBuffer to use */
jerry_length_t byte_offset, /**< offset for the ArrayBuffer */
jerry_length_t length) /**< number of elements to use from ArrayBuffer */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (ecma_is_value_exception (arraybuffer))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
ecma_builtin_id_t prototype_id = 0;
ecma_typedarray_type_t id = 0;
uint8_t element_size_shift = 0;
if (!jerry_typedarray_find_by_type (type, &prototype_id, &id, &element_size_shift))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_FOR_TYPEDARRAY));
}
if (!ecma_is_arraybuffer (arraybuffer))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_ARGUMENT_NOT_ARRAY_BUFFER));
}
ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id);
ecma_value_t arguments_p[3] = { arraybuffer, ecma_make_uint32_value (byte_offset), ecma_make_uint32_value (length) };
ecma_value_t array_value = ecma_op_create_typedarray (arguments_p, 3, prototype_obj_p, element_size_shift, id);
ecma_free_value (arguments_p[1]);
ecma_free_value (arguments_p[2]);
return jerry_return (array_value);
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (type);
JERRY_UNUSED (arraybuffer);
JERRY_UNUSED (byte_offset);
JERRY_UNUSED (length);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_typedarray_with_buffer_span */
/**
* Create a TypedArray object using the given arraybuffer and size information.
*
* Notes:
* * returns TypeError if an incorrect type (type_name) is specified.
* * this is the 'new %TypedArray%(arraybuffer)' equivalent call.
*
* @return - new TypedArray object
*/
jerry_value_t
jerry_typedarray_with_buffer (jerry_typedarray_type_t type, /**< type of TypedArray to create */
const jerry_value_t arraybuffer) /**< ArrayBuffer to use */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (ecma_is_value_exception (arraybuffer))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
jerry_length_t byte_length = jerry_arraybuffer_size (arraybuffer);
return jerry_typedarray_with_buffer_span (type, arraybuffer, 0, byte_length);
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (type);
JERRY_UNUSED (arraybuffer);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_typedarray_with_buffer */
/**
* Get the type of the TypedArray.
*
* @return - type of the TypedArray
* - JERRY_TYPEDARRAY_INVALID if the argument is not a TypedArray
*/
jerry_typedarray_type_t
jerry_typedarray_type (const jerry_value_t value) /**< object to get the TypedArray type */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (!ecma_is_typedarray (value))
{
return JERRY_TYPEDARRAY_INVALID;
}
ecma_object_t *array_p = ecma_get_object_from_value (value);
ecma_typedarray_type_t class_type = ecma_get_typedarray_id (array_p);
for (uint32_t i = 0; i < sizeof (jerry_typedarray_mappings) / sizeof (jerry_typedarray_mappings[0]); i++)
{
if (class_type == jerry_typedarray_mappings[i].id)
{
return jerry_typedarray_mappings[i].api_type;
}
}
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
#endif /* JERRY_BUILTIN_TYPEDARRAY */
return JERRY_TYPEDARRAY_INVALID;
} /* jerry_typedarray_type */
/**
* Get the element count of the TypedArray.
*
* @return length of the TypedArray.
*/
jerry_length_t
jerry_typedarray_length (const jerry_value_t value) /**< TypedArray to query */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (ecma_is_typedarray (value))
{
ecma_object_t *array_p = ecma_get_object_from_value (value);
return ecma_typedarray_get_length (array_p);
}
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
#endif /* JERRY_BUILTIN_TYPEDARRAY */
return 0;
} /* jerry_typedarray_length */
/**
* Get the underlying ArrayBuffer from a TypedArray.
*
* Additionally the byteLength and byteOffset properties are also returned
* which were specified when the TypedArray was created.
*
* Note:
* the returned value must be freed with a jerry_value_free call
*
* @return ArrayBuffer of a TypedArray
* TypeError if the object is not a TypedArray.
*/
jerry_value_t
jerry_typedarray_buffer (const jerry_value_t value, /**< TypedArray to get the arraybuffer from */
jerry_length_t *byte_offset, /**< [out] byteOffset property */
jerry_length_t *byte_length) /**< [out] byteLength property */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_TYPEDARRAY
if (!ecma_is_typedarray (value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_OBJECT_IS_NOT_A_TYPEDARRAY));
}
ecma_object_t *array_p = ecma_get_object_from_value (value);
uint8_t shift = ecma_typedarray_get_element_size_shift (array_p);
if (byte_length != NULL)
{
*byte_length = (jerry_length_t) (ecma_typedarray_get_length (array_p) << shift);
}
if (byte_offset != NULL)
{
*byte_offset = (jerry_length_t) ecma_typedarray_get_offset (array_p);
}
ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (array_p);
ecma_ref_object (arraybuffer_p);
return jerry_return (ecma_make_object_value (arraybuffer_p));
#else /* !JERRY_BUILTIN_TYPEDARRAY */
JERRY_UNUSED (value);
JERRY_UNUSED (byte_length);
JERRY_UNUSED (byte_offset);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_TYPEDARRAY */
} /* jerry_typedarray_buffer */
/**
* Parse the given input buffer as a JSON string. The behaviour is equivalent with the "JSON.parse(string)" JS
* call. The input buffer can be encoded as either cesu-8 or utf-8, but it is the callers responsibility to make sure
* the encoding is valid.
*
*
* @return object value, or exception
*/
jerry_value_t
jerry_json_parse (const jerry_char_t *string_p, /**< json string */
jerry_size_t string_size) /**< json string size */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_JSON
ecma_value_t ret_value = ecma_builtin_json_parse_buffer (string_p, string_size);
if (ecma_is_value_undefined (ret_value))
{
ret_value = jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_JSON_STRING_PARSE_ERROR));
}
return jerry_return (ret_value);
#else /* !JERRY_BUILTIN_JSON */
JERRY_UNUSED (string_p);
JERRY_UNUSED (string_size);
return jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_JSON_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_JSON */
} /* jerry_json_parse */
/**
* Create a JSON string from a JavaScript value.
*
* The behaviour is equivalent with the "JSON.stringify(input_value)" JS call.
*
* Note:
* The returned value must be freed with jerry_value_free,
*
* @return - jerry_value_t containing a JSON string.
* - Error value if there was a problem during the stringification.
*/
jerry_value_t
jerry_json_stringify (const jerry_value_t input_value) /**< a value to stringify */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_JSON
if (ecma_is_value_exception (input_value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
ecma_value_t ret_value = ecma_builtin_json_stringify_no_opts (input_value);
if (ecma_is_value_undefined (ret_value))
{
ret_value = jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_JSON_STRINGIFY_ERROR));
}
return jerry_return (ret_value);
#else /* JERRY_BUILTIN_JSON */
JERRY_UNUSED (input_value);
return jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_JSON_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_JSON */
} /* jerry_json_stringify */
/**
* Create a container type specified in jerry_container_type_t.
* The container can be created with a list of arguments, which will be passed to the container constructor to be
* inserted to the container.
*
* Note:
* The returned value must be freed with jerry_value_free
* @return jerry_value_t representing a container with the given type.
*/
jerry_value_t
jerry_container (jerry_container_type_t container_type, /**< Type of the container */
const jerry_value_t *arguments_list_p, /**< arguments list */
jerry_length_t arguments_list_len) /**< Length of arguments list */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_CONTAINER
for (jerry_length_t i = 0; i < arguments_list_len; i++)
{
if (ecma_is_value_exception (arguments_list_p[i]))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
}
}
lit_magic_string_id_t lit_id;
ecma_builtin_id_t proto_id;
ecma_builtin_id_t ctor_id;
switch (container_type)
{
case JERRY_CONTAINER_TYPE_MAP:
{
lit_id = LIT_MAGIC_STRING_MAP_UL;
proto_id = ECMA_BUILTIN_ID_MAP_PROTOTYPE;
ctor_id = ECMA_BUILTIN_ID_MAP;
break;
}
case JERRY_CONTAINER_TYPE_SET:
{
lit_id = LIT_MAGIC_STRING_SET_UL;
proto_id = ECMA_BUILTIN_ID_SET_PROTOTYPE;
ctor_id = ECMA_BUILTIN_ID_SET;
break;
}
case JERRY_CONTAINER_TYPE_WEAKMAP:
{
lit_id = LIT_MAGIC_STRING_WEAKMAP_UL;
proto_id = ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE;
ctor_id = ECMA_BUILTIN_ID_WEAKMAP;
break;
}
case JERRY_CONTAINER_TYPE_WEAKSET:
{
lit_id = LIT_MAGIC_STRING_WEAKSET_UL;
proto_id = ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE;
ctor_id = ECMA_BUILTIN_ID_WEAKSET;
break;
}
default:
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INVALID_CONTAINER_TYPE));
}
}
ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target_p);
if (old_new_target_p == NULL)
{
JERRY_CONTEXT (current_new_target_p) = ecma_builtin_get (ctor_id);
}
ecma_value_t container_value = ecma_op_container_create (arguments_list_p, arguments_list_len, lit_id, proto_id);
JERRY_CONTEXT (current_new_target_p) = old_new_target_p;
return jerry_return (container_value);
#else /* !JERRY_BUILTIN_CONTAINER */
JERRY_UNUSED (arguments_list_p);
JERRY_UNUSED (arguments_list_len);
JERRY_UNUSED (container_type);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_CONTAINER */
} /* jerry_container */
/**
* Get the type of the given container object.
*
* @return Corresponding type to the given container object.
*/
jerry_container_type_t
jerry_container_type (const jerry_value_t value) /**< the container object */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_CONTAINER
if (ecma_is_value_object (value))
{
ecma_object_t *obj_p = ecma_get_object_from_value (value);
if (ecma_object_class_is (obj_p, ECMA_OBJECT_CLASS_CONTAINER))
{
switch (((ecma_extended_object_t *) obj_p)->u.cls.u2.container_id)
{
case LIT_MAGIC_STRING_MAP_UL:
{
return JERRY_CONTAINER_TYPE_MAP;
}
case LIT_MAGIC_STRING_SET_UL:
{
return JERRY_CONTAINER_TYPE_SET;
}
case LIT_MAGIC_STRING_WEAKMAP_UL:
{
return JERRY_CONTAINER_TYPE_WEAKMAP;
}
case LIT_MAGIC_STRING_WEAKSET_UL:
{
return JERRY_CONTAINER_TYPE_WEAKSET;
}
default:
{
return JERRY_CONTAINER_TYPE_INVALID;
}
}
}
}
#else /* !JERRY_BUILTIN_CONTAINER */
JERRY_UNUSED (value);
#endif /* JERRY_BUILTIN_CONTAINER */
return JERRY_CONTAINER_TYPE_INVALID;
} /* jerry_container_type */
/**
* Return a new array containing elements from a Container or a Container Iterator.
* Sets the boolean input value to `true` if the container object has key/value pairs.
*
* Note:
* the returned value must be freed with a jerry_value_free call
*
* @return an array of items for maps/sets or their iterators, error otherwise
*/
jerry_value_t
jerry_container_to_array (const jerry_value_t value, /**< the container or iterator object */
bool *is_key_value_p) /**< [out] is key-value structure */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_CONTAINER
if (!ecma_is_value_object (value))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NEEDED));
}
ecma_object_t *obj_p = ecma_get_object_from_value (value);
if (ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_CLASS)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NEEDED));
}
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
uint32_t entry_count;
uint8_t entry_size;
uint32_t index = 0;
uint8_t iterator_kind = ECMA_ITERATOR__COUNT;
ecma_value_t *start_p;
*is_key_value_p = false;
if (ext_obj_p->u.cls.type == ECMA_OBJECT_CLASS_MAP_ITERATOR
|| ext_obj_p->u.cls.type == ECMA_OBJECT_CLASS_SET_ITERATOR)
{
ecma_value_t iterated_value = ext_obj_p->u.cls.u3.iterated_value;
if (ecma_is_value_empty (iterated_value))
{
return ecma_op_new_array_object_from_collection (ecma_new_collection (), false);
}
ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) (ecma_get_object_from_value (iterated_value));
ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, map_object_p->u.cls.u3.value);
entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
index = ext_obj_p->u.cls.u2.iterator_index;
entry_size = ecma_op_container_entry_size (map_object_p->u.cls.u2.container_id);
start_p = ECMA_CONTAINER_START (container_p);
iterator_kind = ext_obj_p->u.cls.u1.iterator_kind;
}
else if (jerry_container_type (value) != JERRY_CONTAINER_TYPE_INVALID)
{
ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, ext_obj_p->u.cls.u3.value);
entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
entry_size = ecma_op_container_entry_size (ext_obj_p->u.cls.u2.container_id);
index = 0;
iterator_kind = ECMA_ITERATOR_KEYS;
start_p = ECMA_CONTAINER_START (container_p);
if (ext_obj_p->u.cls.u2.container_id == LIT_MAGIC_STRING_MAP_UL
|| ext_obj_p->u.cls.u2.container_id == LIT_MAGIC_STRING_WEAKMAP_UL)
{
iterator_kind = ECMA_ITERATOR_ENTRIES;
}
}
else
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NEEDED));
}
*is_key_value_p = (iterator_kind == ECMA_ITERATOR_ENTRIES);
ecma_collection_t *collection_buffer = ecma_new_collection ();
for (uint32_t i = index; i < entry_count; i += entry_size)
{
ecma_value_t *entry_p = start_p + i;
if (ecma_is_value_empty (*entry_p))
{
continue;
}
if (iterator_kind != ECMA_ITERATOR_VALUES)
{
ecma_collection_push_back (collection_buffer, ecma_copy_value_if_not_object (entry_p[0]));
}
if (iterator_kind != ECMA_ITERATOR_KEYS)
{
ecma_collection_push_back (collection_buffer, ecma_copy_value_if_not_object (entry_p[1]));
}
}
return ecma_op_new_array_object_from_collection (collection_buffer, false);
#else /* !JERRY_BUILTIN_CONTAINER */
JERRY_UNUSED (value);
JERRY_UNUSED (is_key_value_p);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_CONTAINER */
} /* jerry_container_to_array */
/**
* Perform container operation on the given operands (add, get, set, has, delete, size, clear).
*
* @return error - if argument is invalid or operation is unsuccessful or unsupported
* result of the container operation - otherwise.
*/
jerry_value_t
jerry_container_op (jerry_container_op_t operation, /**< container operation */
jerry_value_t container, /**< container */
const jerry_value_t *arguments, /**< list of arguments */
uint32_t arguments_number) /**< number of arguments */
{
jerry_assert_api_enabled ();
#if JERRY_BUILTIN_CONTAINER
if (!ecma_is_value_object (container))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_IS_NOT_AN_OBJECT));
}
ecma_object_t *obj_p = ecma_get_object_from_value (container);
if (ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_CLASS)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_IS_NOT_A_CONTAINER_OBJECT));
}
uint16_t type = ((ecma_extended_object_t *) obj_p)->u.cls.u2.container_id;
ecma_extended_object_t *container_object_p = ecma_op_container_get_object (container, type);
if (container_object_p == NULL)
{
return ecma_create_exception_from_context ();
}
switch (operation)
{
case JERRY_CONTAINER_OP_ADD:
case JERRY_CONTAINER_OP_DELETE:
case JERRY_CONTAINER_OP_GET:
case JERRY_CONTAINER_OP_HAS:
{
if (arguments_number != 1 || ecma_is_value_exception (arguments[0]))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
break;
}
case JERRY_CONTAINER_OP_SET:
{
if (arguments_number != 2 || ecma_is_value_exception (arguments[0]) || ecma_is_value_exception (arguments[1]))
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
break;
}
case JERRY_CONTAINER_OP_CLEAR:
case JERRY_CONTAINER_OP_SIZE:
{
if (arguments_number != 0)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
break;
}
default:
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
}
}
jerry_value_t result;
switch (operation)
{
case JERRY_CONTAINER_OP_ADD:
{
if (type == LIT_MAGIC_STRING_MAP_UL || type == LIT_MAGIC_STRING_WEAKMAP_UL)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_CALL));
}
result = ecma_op_container_set (container_object_p, arguments[0], arguments[0], type);
break;
}
case JERRY_CONTAINER_OP_GET:
{
if (type == LIT_MAGIC_STRING_SET_UL || type == LIT_MAGIC_STRING_WEAKSET_UL)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_CALL));
}
result = ecma_op_container_get (container_object_p, arguments[0], type);
break;
}
case JERRY_CONTAINER_OP_SET:
{
if (type == LIT_MAGIC_STRING_SET_UL || type == LIT_MAGIC_STRING_WEAKSET_UL)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_CALL));
}
result = ecma_op_container_set (container_object_p, arguments[0], arguments[1], type);
break;
}
case JERRY_CONTAINER_OP_HAS:
{
result = ecma_op_container_has (container_object_p, arguments[0], type);
break;
}
case JERRY_CONTAINER_OP_DELETE:
{
if (type == LIT_MAGIC_STRING_WEAKMAP_UL || type == LIT_MAGIC_STRING_WEAKSET_UL)
{
result = ecma_op_container_delete_weak (container_object_p, arguments[0], type);
break;
}
result = ecma_op_container_delete (container_object_p, arguments[0], type);
break;
}
case JERRY_CONTAINER_OP_SIZE:
{
result = ecma_op_container_size (container_object_p);
break;
}
case JERRY_CONTAINER_OP_CLEAR:
{
if (type == LIT_MAGIC_STRING_WEAKSET_UL || type == LIT_MAGIC_STRING_WEAKMAP_UL)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_CALL));
}
result = ecma_op_container_clear (container_object_p);
break;
}
default:
{
result = jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_UNSUPPORTED_CONTAINER_OPERATION));
break;
}
}
return jerry_return (result);
#else /* !JERRY_BUILTIN_CONTAINER */
JERRY_UNUSED (operation);
JERRY_UNUSED (container);
JERRY_UNUSED (arguments);
JERRY_UNUSED (arguments_number);
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NOT_SUPPORTED));
#endif /* JERRY_BUILTIN_CONTAINER */
} /* jerry_container_op */
/**
* @}
*/