Files
jerryscript/jerry-core/vm/vm.c
T
Dániel Bátyai 9860d66a56 Rework the public API (#4829)
Related to #4186.

Some notable changes:
  - The term 'Error' now strictly refers to native Error objects defined in
    the ECMA standard, which are ordinary objects. All other uses of
    'error' or 'error reference' where the term refers to a thrown value is
    now called 'exception'.

  - Simplified the naming scheme of many String API functions. These functions
    will now also take an 'encoding' argument to specify the desired
    encoding in which to operate.

  - Removed the substring-copy-to-buffer functions. These functions
    behaved awkwardly, as they use character index to specify the
    start/end positions, and were mostly used incorrectly with byte
    offsets instead. The functionality can still be replicated with
    other functions if necessary.

  - String-to-buffer functions will no longer fail if the buffer is not
    sufficiently large, the string will instead be cropped.

  - Fixed the usage of the '_sz' prefix in many API functions. The term
    'sz' means zero-terminated string in hungarian notation, this was
    used incorrectly in many cases.

  - Renamed most of the public API functions to have shorter, more on-point
    names, rather than the often too long descriptive names. Functions are now
    also grouped by the type of value they operate on, where this makes
    sense.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
2021-12-06 10:20:09 +01:00

5370 lines
178 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 "vm.h"
#include "ecma-alloc.h"
#include "ecma-arguments-object.h"
#include "ecma-array-object.h"
#include "ecma-bigint.h"
#include "ecma-builtin-object.h"
#include "ecma-builtins.h"
#include "ecma-comparison.h"
#include "ecma-conversion.h"
#include "ecma-errors.h"
#include "ecma-exceptions.h"
#include "ecma-function-object.h"
#include "ecma-gc.h"
#include "ecma-helpers.h"
#include "ecma-iterator-object.h"
#include "ecma-lcache.h"
#include "ecma-lex-env.h"
#include "ecma-objects-general.h"
#include "ecma-objects.h"
#include "ecma-promise-object.h"
#include "ecma-regexp-object.h"
#include "common.h"
#include "jcontext.h"
#include "opcodes.h"
#include "vm-stack.h"
/** \addtogroup vm Virtual machine
* @{
*
* \addtogroup vm_executor Executor
* @{
*/
JERRY_STATIC_ASSERT ((sizeof (vm_frame_ctx_t) % sizeof (ecma_value_t)) == 0,
sizeof_vm_frame_ctx_must_be_sizeof_ecma_value_t_aligned);
/**
* Get the value of object[property].
*
* @return ecma value
*/
static ecma_value_t
vm_op_get_value (ecma_value_t object, /**< base object */
ecma_value_t property) /**< property name */
{
if (ecma_is_value_object (object))
{
ecma_object_t *object_p = ecma_get_object_from_value (object);
ecma_string_t *property_name_p = NULL;
if (ecma_is_value_integer_number (property))
{
ecma_integer_value_t int_value = ecma_get_integer_from_value (property);
if (int_value >= 0 && int_value <= ECMA_DIRECT_STRING_MAX_IMM)
{
if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY)
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_object_p)
&& (uint32_t) int_value < ext_object_p->u.array.length))
{
ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
if (JERRY_LIKELY (!ecma_is_value_array_hole (values_p[int_value])))
{
return ecma_fast_copy_value (values_p[int_value]);
}
}
}
property_name_p = (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_UINT, (uintptr_t) int_value);
}
}
else if (ecma_is_value_string (property))
{
property_name_p = ecma_get_string_from_value (property);
}
#if JERRY_ESNEXT
if (ecma_is_value_symbol (property))
{
property_name_p = ecma_get_symbol_from_value (property);
}
#endif /* JERRY_ESNEXT */
if (property_name_p != NULL)
{
#if JERRY_LCACHE
ecma_property_t *property_p = ecma_lcache_lookup (object_p, property_name_p);
if (property_p != NULL && (*property_p & ECMA_PROPERTY_FLAG_DATA))
{
JERRY_ASSERT (!ECMA_PROPERTY_IS_INTERNAL (*property_p));
return ecma_fast_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
}
#endif /* JERRY_LCACHE */
/* There is no need to free the name. */
return ecma_op_object_get (object_p, property_name_p);
}
}
if (JERRY_UNLIKELY (ecma_is_value_undefined (object) || ecma_is_value_null (object)))
{
#if JERRY_ERROR_MESSAGES
ecma_value_t error_value =
ecma_raise_standard_error_with_format (JERRY_ERROR_TYPE, "Cannot read property '%' of %", property, object);
#else /* !JERRY_ERROR_MESSAGES */
ecma_value_t error_value = ecma_raise_type_error (ECMA_ERR_EMPTY);
#endif /* JERRY_ERROR_MESSAGES */
return error_value;
}
ecma_string_t *property_name_p = ecma_op_to_property_key (property);
if (property_name_p == NULL)
{
return ECMA_VALUE_ERROR;
}
ecma_value_t get_value_result = ecma_op_get_value_object_base (object, property_name_p);
ecma_deref_ecma_string (property_name_p);
return get_value_result;
} /* vm_op_get_value */
/**
* Set the value of object[property].
*
* Note:
* this function frees its object and property arguments
*
* @return an ecma value which contains an error
* if the property setting is unsuccessful
*/
static ecma_value_t
vm_op_set_value (ecma_value_t base, /**< base object */
ecma_value_t property, /**< property name */
ecma_value_t value, /**< ecma value */
bool is_strict) /**< strict mode */
{
ecma_value_t result = ECMA_VALUE_EMPTY;
ecma_object_t *object_p;
ecma_string_t *property_p;
if (JERRY_UNLIKELY (!ecma_is_value_object (base)))
{
if (JERRY_UNLIKELY (ecma_is_value_null (base) || ecma_is_value_undefined (base)))
{
#if JERRY_ERROR_MESSAGES
result = ecma_raise_standard_error_with_format (JERRY_ERROR_TYPE, "Cannot set property '%' of %", property, base);
#else /* !JERRY_ERROR_MESSAGES */
result = ecma_raise_type_error (ECMA_ERR_EMPTY);
#endif /* JERRY_ERROR_MESSAGES */
ecma_free_value (property);
return result;
}
if (JERRY_UNLIKELY (!ecma_is_value_prop_name (property)))
{
property_p = ecma_op_to_string (property);
ecma_fast_free_value (property);
if (JERRY_UNLIKELY (property_p == NULL))
{
ecma_free_value (base);
return ECMA_VALUE_ERROR;
}
}
else
{
property_p = ecma_get_prop_name_from_value (property);
}
ecma_value_t object = ecma_op_to_object (base);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (object));
object_p = ecma_get_object_from_value (object);
ecma_op_ordinary_object_prevent_extensions (object_p);
result = ecma_op_object_put_with_receiver (object_p, property_p, value, base, is_strict);
ecma_free_value (base);
}
else
{
object_p = ecma_get_object_from_value (base);
if (JERRY_UNLIKELY (!ecma_is_value_prop_name (property)))
{
property_p = ecma_op_to_string (property);
ecma_fast_free_value (property);
if (JERRY_UNLIKELY (property_p == NULL))
{
ecma_deref_object (object_p);
return ECMA_VALUE_ERROR;
}
}
else
{
property_p = ecma_get_prop_name_from_value (property);
}
if (!ecma_is_lexical_environment (object_p))
{
result = ecma_op_object_put_with_receiver (object_p, property_p, value, base, is_strict);
}
else
{
result = ecma_op_set_mutable_binding (object_p, property_p, value, is_strict);
}
}
ecma_deref_object (object_p);
ecma_deref_ecma_string (property_p);
return result;
} /* vm_op_set_value */
/** Compact bytecode define */
#define CBC_OPCODE(arg1, arg2, arg3, arg4) arg4,
/**
* Decode table for both opcodes and extended opcodes.
*/
static const uint16_t vm_decode_table[] JERRY_ATTR_CONST_DATA = { CBC_OPCODE_LIST CBC_EXT_OPCODE_LIST };
#undef CBC_OPCODE
/**
* Run global code
*
* Note:
* returned value must be freed with ecma_free_value, when it is no longer needed.
*
* @return ecma value
*/
ecma_value_t
vm_run_global (const ecma_compiled_code_t *bytecode_p, /**< pointer to bytecode to run */
ecma_object_t *function_object_p) /**< function object if available */
{
#if JERRY_BUILTIN_REALMS
ecma_object_t *global_obj_p = (ecma_object_t *) ecma_op_function_get_realm (bytecode_p);
#else /* !JERRY_BUILTIN_REALMS */
ecma_object_t *global_obj_p = ecma_builtin_get_global ();
#endif /* JERRY_BUILTIN_REALMS */
#if JERRY_ESNEXT
if (bytecode_p->status_flags & CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED)
{
ecma_create_global_lexical_block (global_obj_p);
}
#endif /* JERRY_ESNEXT */
ecma_object_t *const global_scope_p = ecma_get_global_scope (global_obj_p);
vm_frame_ctx_shared_t shared;
shared.bytecode_header_p = bytecode_p;
shared.function_object_p = function_object_p;
shared.status_flags = 0;
#if JERRY_BUILTIN_REALMS
ecma_value_t this_binding = ((ecma_global_object_t *) global_obj_p)->this_binding;
ecma_global_object_t *saved_global_object_p = JERRY_CONTEXT (global_object_p);
JERRY_CONTEXT (global_object_p) = (ecma_global_object_t *) global_obj_p;
#else /* !JERRY_BUILTIN_REALMS */
ecma_value_t this_binding = ecma_make_object_value (global_obj_p);
#endif /* JERRY_BUILTIN_REALMS */
ecma_value_t result = vm_run (&shared, this_binding, global_scope_p);
#if JERRY_BUILTIN_REALMS
JERRY_CONTEXT (global_object_p) = saved_global_object_p;
#endif /* JERRY_BUILTIN_REALMS */
return result;
} /* vm_run_global */
/**
* Run specified eval-mode bytecode
*
* @return ecma value
*/
ecma_value_t
vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */
uint32_t parse_opts) /**< ecma_parse_opts_t option bits */
{
ecma_value_t this_binding;
ecma_object_t *lex_env_p;
/* ECMA-262 v5, 10.4.2 */
if (parse_opts & ECMA_PARSE_DIRECT_EVAL)
{
this_binding = ecma_copy_value (JERRY_CONTEXT (vm_top_context_p)->this_binding);
lex_env_p = JERRY_CONTEXT (vm_top_context_p)->lex_env_p;
#if JERRY_DEBUGGER
uint32_t chain_index = parse_opts >> ECMA_PARSE_CHAIN_INDEX_SHIFT;
parse_opts &= (1 << ECMA_PARSE_CHAIN_INDEX_SHIFT) - 1;
while (chain_index != 0)
{
if (JERRY_UNLIKELY (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL))
{
ecma_bytecode_deref (bytecode_data_p);
ecma_free_value (this_binding);
return ecma_raise_range_error (ECMA_ERR_INVALID_SCOPE_CHAIN_INDEX_FOR_EVAL);
}
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
if ((ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
|| (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE))
{
chain_index--;
}
}
#endif /* JERRY_DEBUGGER */
}
else
{
#if JERRY_BUILTIN_REALMS
ecma_object_t *global_obj_p = (ecma_object_t *) ecma_op_function_get_realm (bytecode_data_p);
this_binding = ((ecma_global_object_t *) global_obj_p)->this_binding;
ecma_ref_object (ecma_get_object_from_value (this_binding));
#else /* !JERRY_BUILTIN_REALMS */
ecma_object_t *global_obj_p = ecma_builtin_get_global ();
ecma_ref_object (global_obj_p);
this_binding = ecma_make_object_value (global_obj_p);
#endif /* JERRY_BUILTIN_REALMS */
lex_env_p = ecma_get_global_scope (global_obj_p);
}
ecma_ref_object (lex_env_p);
if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0)
{
ecma_object_t *strict_lex_env_p = ecma_create_decl_lex_env (lex_env_p);
ecma_deref_object (lex_env_p);
lex_env_p = strict_lex_env_p;
}
if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED) != 0)
{
ecma_object_t *lex_block_p = ecma_create_decl_lex_env (lex_env_p);
lex_block_p->type_flags_refs |= ECMA_OBJECT_FLAG_BLOCK;
ecma_deref_object (lex_env_p);
lex_env_p = lex_block_p;
}
vm_frame_ctx_shared_t shared;
shared.bytecode_header_p = bytecode_data_p;
shared.function_object_p = NULL;
shared.status_flags = (parse_opts & ECMA_PARSE_DIRECT_EVAL) ? VM_FRAME_CTX_SHARED_DIRECT_EVAL : 0;
ecma_value_t completion_value = vm_run (&shared, this_binding, lex_env_p);
ecma_deref_object (lex_env_p);
ecma_free_value (this_binding);
#if JERRY_SNAPSHOT_EXEC
if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
{
ecma_bytecode_deref (bytecode_data_p);
}
#else /* !JERRY_SNAPSHOT_EXEC */
ecma_bytecode_deref (bytecode_data_p);
#endif /* JERRY_SNAPSHOT_EXEC */
return completion_value;
} /* vm_run_eval */
#if JERRY_MODULE_SYSTEM
/**
* Run module code
*
* Note:
* returned value must be freed with ecma_free_value, when it is no longer needed.
*
* @return ecma value
*/
ecma_value_t
vm_run_module (ecma_module_t *module_p) /**< module to be executed */
{
const ecma_value_t module_init_result = ecma_module_initialize (module_p);
if (ECMA_IS_VALUE_ERROR (module_init_result))
{
return module_init_result;
}
vm_frame_ctx_shared_t shared;
shared.bytecode_header_p = module_p->u.compiled_code_p;
shared.function_object_p = &module_p->header.object;
shared.status_flags = 0;
return vm_run (&shared, ECMA_VALUE_UNDEFINED, module_p->scope_p);
} /* vm_run_module */
#endif /* JERRY_MODULE_SYSTEM */
/**
* Construct object
*
* @return object value
*/
static ecma_value_t
vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
ecma_value_t lit_value) /**< literal */
{
ecma_compiled_code_t *bytecode_p;
#if JERRY_SNAPSHOT_EXEC
if (JERRY_LIKELY (!(frame_ctx_p->shared_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)))
{
#endif /* JERRY_SNAPSHOT_EXEC */
bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, lit_value);
#if JERRY_SNAPSHOT_EXEC
}
else
{
uint8_t *byte_p = ((uint8_t *) frame_ctx_p->shared_p->bytecode_header_p) + lit_value;
bytecode_p = (ecma_compiled_code_t *) byte_p;
}
#endif /* JERRY_SNAPSHOT_EXEC */
#if JERRY_BUILTIN_REGEXP
if (JERRY_UNLIKELY (!CBC_IS_FUNCTION (bytecode_p->status_flags)))
{
ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL);
if (JERRY_UNLIKELY (regexp_obj_p == NULL))
{
return ECMA_VALUE_ERROR;
}
return ecma_op_create_regexp_from_bytecode (regexp_obj_p, (re_compiled_code_t *) bytecode_p);
}
#else /* !JERRY_BUILTIN_REGEXP */
JERRY_ASSERT (CBC_IS_FUNCTION (bytecode_p->status_flags));
#endif /* JERRY_BUILTIN_REGEXP */
ecma_object_t *func_obj_p;
#if JERRY_ESNEXT
if (JERRY_UNLIKELY (CBC_FUNCTION_IS_ARROW (bytecode_p->status_flags)))
{
func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p, bytecode_p, frame_ctx_p->this_binding);
}
else
{
func_obj_p = ecma_op_create_any_function_object (frame_ctx_p->lex_env_p, bytecode_p);
}
#else /* !JERRY_ESNEXT */
func_obj_p = ecma_op_create_simple_function_object (frame_ctx_p->lex_env_p, bytecode_p);
#endif /* JERRY_ESNEXT */
return ecma_make_object_value (func_obj_p);
} /* vm_construct_literal_object */
/**
* Get implicit this value
*
* @return true - if the implicit 'this' value is updated,
* false - otherwise
*/
static inline bool JERRY_ATTR_ALWAYS_INLINE
vm_get_implicit_this_value (ecma_value_t *this_value_p) /**< [in,out] this value */
{
if (ecma_is_value_object (*this_value_p))
{
ecma_object_t *this_obj_p = ecma_get_object_from_value (*this_value_p);
if (ecma_is_lexical_environment (this_obj_p))
{
ecma_value_t completion_value = ecma_op_implicit_this_value (this_obj_p);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (completion_value));
*this_value_p = completion_value;
return true;
}
}
return false;
} /* vm_get_implicit_this_value */
/**
* Special bytecode sequence for error handling while the vm_loop
* is preserved for an execute operation
*/
static const uint8_t vm_error_byte_code_p[] = { CBC_EXT_OPCODE, CBC_EXT_ERROR };
#if JERRY_ESNEXT
static ecma_object_t *
vm_get_class_function (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
JERRY_ASSERT (frame_ctx_p != NULL);
if (frame_ctx_p->shared_p->status_flags & VM_FRAME_CTX_SHARED_NON_ARROW_FUNC)
{
return frame_ctx_p->shared_p->function_object_p;
}
ecma_environment_record_t *environment_record_p = ecma_op_get_environment_record (frame_ctx_p->lex_env_p);
JERRY_ASSERT (environment_record_p != NULL);
return ecma_get_object_from_value (environment_record_p->function_object);
} /* vm_get_class_function */
/**
* 'super(...)' function call handler.
*/
static void
vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
JERRY_ASSERT (frame_ctx_p->call_operation == VM_EXEC_SUPER_CALL);
JERRY_ASSERT (frame_ctx_p->byte_code_p[0] == CBC_EXT_OPCODE);
const uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 3;
uint8_t opcode = byte_code_p[-2];
uint32_t arguments_list_len;
bool spread_arguments = opcode >= CBC_EXT_SPREAD_SUPER_CALL;
ecma_collection_t *collection_p = NULL;
ecma_value_t *arguments_p;
if (spread_arguments)
{
ecma_value_t collection = *(--frame_ctx_p->stack_top_p);
collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, collection);
arguments_p = collection_p->buffer_p;
arguments_list_len = collection_p->item_count;
}
else
{
arguments_list_len = byte_code_p[-1];
arguments_p = frame_ctx_p->stack_top_p;
}
ecma_value_t func_value = *(--frame_ctx_p->stack_top_p);
ecma_value_t completion_value;
ecma_environment_record_t *environment_record_p = ecma_op_get_environment_record (frame_ctx_p->lex_env_p);
if (!ecma_is_constructor (func_value))
{
completion_value = ecma_raise_type_error (ECMA_ERR_VALUE_FOR_CLASS_HERITAGE_IS_NOT_A_CONSTRUCTOR);
}
else
{
ecma_object_t *func_obj_p = ecma_get_object_from_value (func_value);
completion_value =
ecma_op_function_construct (func_obj_p, JERRY_CONTEXT (current_new_target_p), arguments_p, arguments_list_len);
if (!ECMA_IS_VALUE_ERROR (completion_value) && ecma_op_this_binding_is_initialized (environment_record_p))
{
ecma_free_value (completion_value);
completion_value = ecma_raise_reference_error (ECMA_ERR_SUPER_CONSTRUCTOR_MAY_ONLY_BE_CALLED_ONCE);
}
}
/* Free registers. */
for (uint32_t i = 0; i < arguments_list_len; i++)
{
ecma_fast_free_value (arguments_p[i]);
}
if (collection_p != NULL)
{
ecma_collection_destroy (collection_p);
}
if (ecma_is_value_object (completion_value))
{
ecma_op_bind_this_value (environment_record_p, completion_value);
frame_ctx_p->this_binding = completion_value;
ecma_value_t fields_value = opfunc_init_class_fields (vm_get_class_function (frame_ctx_p), completion_value);
if (ECMA_IS_VALUE_ERROR (fields_value))
{
ecma_free_value (completion_value);
completion_value = ECMA_VALUE_ERROR;
}
}
ecma_free_value (func_value);
if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value)))
{
#if JERRY_DEBUGGER
JERRY_CONTEXT (debugger_exception_byte_code_p) = frame_ctx_p->byte_code_p;
#endif /* JERRY_DEBUGGER */
frame_ctx_p->byte_code_p = (uint8_t *) vm_error_byte_code_p;
}
else
{
frame_ctx_p->byte_code_p = byte_code_p;
uint32_t opcode_data = vm_decode_table[(CBC_END + 1) + opcode];
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{
ecma_fast_free_value (completion_value);
}
else if (opcode_data & VM_OC_PUT_STACK)
{
*frame_ctx_p->stack_top_p++ = completion_value;
}
else
{
ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, 0));
VM_GET_REGISTERS (frame_ctx_p)[0] = completion_value;
}
}
} /* vm_super_call */
/**
* Perform one of the following call/construct operation with spreaded argument list
* - f(...args)
* - o.f(...args)
* - new O(...args)
*/
static void
vm_spread_operation (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
JERRY_ASSERT (frame_ctx_p->byte_code_p[0] == CBC_EXT_OPCODE);
uint8_t opcode = frame_ctx_p->byte_code_p[1];
ecma_value_t completion_value;
ecma_value_t collection = *(--frame_ctx_p->stack_top_p);
ecma_collection_t *collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, collection);
ecma_value_t func_value = *(--frame_ctx_p->stack_top_p);
bool is_call_prop = opcode >= CBC_EXT_SPREAD_CALL_PROP;
if (frame_ctx_p->byte_code_p[1] == CBC_EXT_SPREAD_NEW)
{
ecma_error_msg_t constructor_message_id = ecma_check_constructor (func_value);
if (constructor_message_id != ECMA_IS_VALID_CONSTRUCTOR)
{
completion_value = ecma_raise_type_error (constructor_message_id);
}
else
{
ecma_object_t *constructor_obj_p = ecma_get_object_from_value (func_value);
completion_value = ecma_op_function_construct (constructor_obj_p,
constructor_obj_p,
collection_p->buffer_p,
collection_p->item_count);
}
}
else
{
ecma_value_t this_value = is_call_prop ? frame_ctx_p->stack_top_p[-2] : ECMA_VALUE_UNDEFINED;
if (!ecma_is_value_object (func_value) || !ecma_op_object_is_callable (ecma_get_object_from_value (func_value)))
{
completion_value = ecma_raise_type_error (ECMA_ERR_EXPECTED_A_FUNCTION);
}
else
{
ecma_object_t *func_obj_p = ecma_get_object_from_value (func_value);
completion_value =
ecma_op_function_call (func_obj_p, this_value, collection_p->buffer_p, collection_p->item_count);
}
if (is_call_prop)
{
ecma_free_value (*(--frame_ctx_p->stack_top_p));
ecma_free_value (*(--frame_ctx_p->stack_top_p));
}
}
ecma_collection_free (collection_p);
ecma_free_value (func_value);
if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value)))
{
#if JERRY_DEBUGGER
JERRY_CONTEXT (debugger_exception_byte_code_p) = frame_ctx_p->byte_code_p;
#endif /* JERRY_DEBUGGER */
frame_ctx_p->byte_code_p = (uint8_t *) vm_error_byte_code_p;
}
else
{
uint32_t opcode_data = vm_decode_table[(CBC_END + 1) + opcode];
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{
ecma_fast_free_value (completion_value);
}
else if (opcode_data & VM_OC_PUT_STACK)
{
*frame_ctx_p->stack_top_p++ = completion_value;
}
else
{
ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, 0));
VM_GET_REGISTERS (frame_ctx_p)[0] = completion_value;
}
/* EXT_OPCODE, SPREAD_OPCODE, BYTE_ARG */
frame_ctx_p->byte_code_p += 3;
}
} /* vm_spread_operation */
#endif /* JERRY_ESNEXT */
/**
* 'Function call' opcode handler.
*
* See also: ECMA-262 v5, 11.2.3
*/
static void
opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
const uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1;
uint8_t opcode = byte_code_p[-1];
uint32_t arguments_list_len;
if (opcode >= CBC_CALL0)
{
arguments_list_len = (unsigned int) ((opcode - CBC_CALL0) / 6);
}
else
{
arguments_list_len = *byte_code_p++;
}
bool is_call_prop = ((opcode - CBC_CALL) % 6) >= 3;
ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len;
ecma_value_t this_value = is_call_prop ? stack_top_p[-3] : ECMA_VALUE_UNDEFINED;
ecma_value_t func_value = stack_top_p[-1];
ecma_value_t completion_value =
ecma_op_function_validated_call (func_value, this_value, stack_top_p, arguments_list_len);
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL;
/* Free registers. */
for (uint32_t i = 0; i < arguments_list_len; i++)
{
ecma_fast_free_value (stack_top_p[i]);
}
if (is_call_prop)
{
ecma_free_value (*(--stack_top_p));
ecma_free_value (*(--stack_top_p));
}
if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value)))
{
#if JERRY_DEBUGGER
JERRY_CONTEXT (debugger_exception_byte_code_p) = frame_ctx_p->byte_code_p;
#endif /* JERRY_DEBUGGER */
frame_ctx_p->byte_code_p = (uint8_t *) vm_error_byte_code_p;
}
else
{
frame_ctx_p->byte_code_p = byte_code_p;
ecma_free_value (*(--stack_top_p));
uint32_t opcode_data = vm_decode_table[opcode];
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{
ecma_fast_free_value (completion_value);
}
else if (opcode_data & VM_OC_PUT_STACK)
{
*stack_top_p++ = completion_value;
}
else
{
ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, 0));
VM_GET_REGISTERS (frame_ctx_p)[0] = completion_value;
}
}
frame_ctx_p->stack_top_p = stack_top_p;
} /* opfunc_call */
/**
* 'Constructor call' opcode handler.
*
* See also: ECMA-262 v5, 11.2.2
*/
static void
opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
const uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1;
uint8_t opcode = byte_code_p[-1];
unsigned int arguments_list_len;
if (opcode >= CBC_NEW0)
{
arguments_list_len = (unsigned int) (opcode - CBC_NEW0);
}
else
{
arguments_list_len = *byte_code_p++;
}
ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len;
ecma_value_t constructor_value = stack_top_p[-1];
ecma_value_t completion_value;
ecma_error_msg_t constructor_message_id = ecma_check_constructor (constructor_value);
if (constructor_message_id != ECMA_IS_VALID_CONSTRUCTOR)
{
completion_value = ecma_raise_type_error (constructor_message_id);
}
else
{
ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor_value);
completion_value =
ecma_op_function_construct (constructor_obj_p, constructor_obj_p, stack_top_p, arguments_list_len);
}
/* Free registers. */
for (uint32_t i = 0; i < arguments_list_len; i++)
{
ecma_fast_free_value (stack_top_p[i]);
}
if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value)))
{
#if JERRY_DEBUGGER
JERRY_CONTEXT (debugger_exception_byte_code_p) = frame_ctx_p->byte_code_p;
#endif /* JERRY_DEBUGGER */
frame_ctx_p->byte_code_p = (uint8_t *) vm_error_byte_code_p;
}
else
{
ecma_free_value (stack_top_p[-1]);
frame_ctx_p->byte_code_p = byte_code_p;
stack_top_p[-1] = completion_value;
}
frame_ctx_p->stack_top_p = stack_top_p;
} /* opfunc_construct */
/**
* Read literal index from the byte code stream into destination.
*
* @param destination destination
*/
#define READ_LITERAL_INDEX(destination) \
do \
{ \
(destination) = *byte_code_p++; \
if ((destination) >= encoding_limit) \
{ \
(destination) = (uint16_t) ((((destination) << 8) | *byte_code_p++) - encoding_delta); \
} \
} while (0)
/**
* Get literal value by literal index.
*
* @param literal_index literal index
* @param target_value target value
*
* TODO: For performance reasons, we define this as a macro.
* When we are able to construct a function with similar speed,
* we can remove this macro.
*/
#define READ_LITERAL(literal_index, target_value) \
do \
{ \
if ((literal_index) < ident_end) \
{ \
if ((literal_index) < register_end) \
{ \
/* Note: There should be no specialization for arguments. */ \
(target_value) = ecma_fast_copy_value (VM_GET_REGISTER (frame_ctx_p, literal_index)); \
} \
else \
{ \
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); \
\
result = ecma_op_resolve_reference_value (frame_ctx_p->lex_env_p, name_p); \
\
if (ECMA_IS_VALUE_ERROR (result)) \
{ \
goto error; \
} \
(target_value) = result; \
} \
} \
else if (literal_index < const_literal_end) \
{ \
(target_value) = ecma_fast_copy_value (literal_start_p[literal_index]); \
} \
else \
{ \
/* Object construction. */ \
(target_value) = vm_construct_literal_object (frame_ctx_p, literal_start_p[literal_index]); \
} \
} while (0)
/**
* Store the original value for post increase/decrease operators
*
* @param value original value
*/
#define POST_INCREASE_DECREASE_PUT_RESULT(value) \
if (opcode_data & VM_OC_PUT_STACK) \
{ \
if (opcode_flags & VM_OC_IDENT_INCR_DECR_OPERATOR_FLAG) \
{ \
JERRY_ASSERT (opcode == CBC_POST_INCR_IDENT_PUSH_RESULT || opcode == CBC_POST_DECR_IDENT_PUSH_RESULT); \
*stack_top_p++ = (value); \
} \
else \
{ \
/* The parser ensures there is enough space for the \
* extra value on the stack. See js-parser-expr.c. */ \
JERRY_ASSERT (opcode == CBC_POST_INCR_PUSH_RESULT || opcode == CBC_POST_DECR_PUSH_RESULT); \
stack_top_p++; \
stack_top_p[-1] = stack_top_p[-2]; \
stack_top_p[-2] = stack_top_p[-3]; \
stack_top_p[-3] = (value); \
} \
opcode_data &= (uint32_t) ~VM_OC_PUT_STACK; \
} \
else \
{ \
JERRY_ASSERT (opcode_data &VM_OC_PUT_BLOCK); \
ecma_free_value (VM_GET_REGISTER (frame_ctx_p, 0)); \
VM_GET_REGISTERS (frame_ctx_p)[0] = (value); \
opcode_data &= (uint32_t) ~VM_OC_PUT_BLOCK; \
}
/**
* Get the end of the existing topmost context
*/
#define VM_LAST_CONTEXT_END() (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth)
/**
* Run generic byte code.
*
* @return ecma value
*/
static ecma_value_t JERRY_ATTR_NOINLINE
vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->shared_p->bytecode_header_p;
const uint8_t *byte_code_p = frame_ctx_p->byte_code_p;
ecma_value_t *literal_start_p = frame_ctx_p->literal_start_p;
ecma_value_t *stack_top_p;
uint16_t encoding_limit;
uint16_t encoding_delta;
uint16_t register_end;
uint16_t ident_end;
uint16_t const_literal_end;
int32_t branch_offset = 0;
uint8_t branch_offset_length = 0;
ecma_value_t left_value;
ecma_value_t right_value;
ecma_value_t result = ECMA_VALUE_EMPTY;
bool is_strict = ((bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0);
/* Prepare for byte code execution. */
if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_FULL_LITERAL_ENCODING))
{
encoding_limit = CBC_SMALL_LITERAL_ENCODING_LIMIT;
encoding_delta = CBC_SMALL_LITERAL_ENCODING_DELTA;
}
else
{
encoding_limit = CBC_FULL_LITERAL_ENCODING_LIMIT;
encoding_delta = CBC_FULL_LITERAL_ENCODING_DELTA;
}
if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) (bytecode_header_p);
register_end = args_p->register_end;
ident_end = args_p->ident_end;
const_literal_end = args_p->const_literal_end;
}
else
{
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) (bytecode_header_p);
register_end = args_p->register_end;
ident_end = args_p->ident_end;
const_literal_end = args_p->const_literal_end;
}
stack_top_p = frame_ctx_p->stack_top_p;
/* Outer loop for exception handling. */
while (true)
{
/* Internal loop for byte code execution. */
while (true)
{
const uint8_t *byte_code_start_p = byte_code_p;
uint8_t opcode = *byte_code_p++;
uint32_t opcode_data = opcode;
if (opcode == CBC_EXT_OPCODE)
{
opcode = *byte_code_p++;
opcode_data = (uint32_t) ((CBC_END + 1) + opcode);
}
opcode_data = vm_decode_table[opcode_data];
left_value = ECMA_VALUE_UNDEFINED;
right_value = ECMA_VALUE_UNDEFINED;
uint32_t operands = VM_OC_GET_ARGS_INDEX (opcode_data);
if (operands >= VM_OC_GET_LITERAL)
{
uint16_t literal_index;
READ_LITERAL_INDEX (literal_index);
READ_LITERAL (literal_index, left_value);
if (operands != VM_OC_GET_LITERAL)
{
switch (operands)
{
case VM_OC_GET_LITERAL_LITERAL:
{
uint16_t second_literal_index;
READ_LITERAL_INDEX (second_literal_index);
READ_LITERAL (second_literal_index, right_value);
break;
}
case VM_OC_GET_STACK_LITERAL:
{
JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end);
right_value = left_value;
left_value = *(--stack_top_p);
break;
}
default:
{
JERRY_ASSERT (operands == VM_OC_GET_THIS_LITERAL);
right_value = left_value;
left_value = ecma_copy_value (frame_ctx_p->this_binding);
break;
}
}
}
}
else if (operands >= VM_OC_GET_STACK)
{
JERRY_ASSERT (operands == VM_OC_GET_STACK || operands == VM_OC_GET_STACK_STACK);
JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end);
left_value = *(--stack_top_p);
if (operands == VM_OC_GET_STACK_STACK)
{
JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end);
right_value = left_value;
left_value = *(--stack_top_p);
}
}
else if (operands == VM_OC_GET_BRANCH)
{
branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (opcode);
JERRY_ASSERT (branch_offset_length >= 1 && branch_offset_length <= 3);
branch_offset = *(byte_code_p++);
if (JERRY_UNLIKELY (branch_offset_length != 1))
{
branch_offset <<= 8;
branch_offset |= *(byte_code_p++);
if (JERRY_UNLIKELY (branch_offset_length == 3))
{
branch_offset <<= 8;
branch_offset |= *(byte_code_p++);
}
}
if (opcode_data & VM_OC_BACKWARD_BRANCH)
{
#if JERRY_VM_HALT
if (JERRY_CONTEXT (vm_exec_stop_cb) != NULL && --JERRY_CONTEXT (vm_exec_stop_counter) == 0)
{
result = JERRY_CONTEXT (vm_exec_stop_cb) (JERRY_CONTEXT (vm_exec_stop_user_p));
if (ecma_is_value_undefined (result))
{
JERRY_CONTEXT (vm_exec_stop_counter) = JERRY_CONTEXT (vm_exec_stop_frequency);
}
else
{
JERRY_CONTEXT (vm_exec_stop_counter) = 1;
if (ecma_is_value_exception (result))
{
ecma_throw_exception (result);
}
else
{
jcontext_raise_exception (result);
}
JERRY_ASSERT (jcontext_has_pending_exception ());
jcontext_set_abort_flag (true);
result = ECMA_VALUE_ERROR;
goto error;
}
}
#endif /* JERRY_VM_HALT */
branch_offset = -branch_offset;
}
}
switch (VM_OC_GROUP_GET_INDEX (opcode_data))
{
case VM_OC_POP:
{
JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end);
ecma_free_value (*(--stack_top_p));
continue;
}
case VM_OC_POP_BLOCK:
{
ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, 0));
VM_GET_REGISTERS (frame_ctx_p)[0] = *(--stack_top_p);
continue;
}
case VM_OC_PUSH:
{
*stack_top_p++ = left_value;
continue;
}
case VM_OC_PUSH_TWO:
{
*stack_top_p++ = left_value;
*stack_top_p++ = right_value;
continue;
}
case VM_OC_PUSH_THREE:
{
uint16_t literal_index;
*stack_top_p++ = left_value;
left_value = ECMA_VALUE_UNDEFINED;
READ_LITERAL_INDEX (literal_index);
READ_LITERAL (literal_index, left_value);
*stack_top_p++ = right_value;
*stack_top_p++ = left_value;
continue;
}
case VM_OC_PUSH_UNDEFINED:
{
*stack_top_p++ = ECMA_VALUE_UNDEFINED;
continue;
}
case VM_OC_PUSH_TRUE:
{
*stack_top_p++ = ECMA_VALUE_TRUE;
continue;
}
case VM_OC_PUSH_FALSE:
{
*stack_top_p++ = ECMA_VALUE_FALSE;
continue;
}
case VM_OC_PUSH_NULL:
{
*stack_top_p++ = ECMA_VALUE_NULL;
continue;
}
case VM_OC_PUSH_THIS:
{
*stack_top_p++ = ecma_copy_value (frame_ctx_p->this_binding);
continue;
}
case VM_OC_PUSH_0:
{
*stack_top_p++ = ecma_make_integer_value (0);
continue;
}
case VM_OC_PUSH_POS_BYTE:
{
ecma_integer_value_t number = *byte_code_p++;
*stack_top_p++ = ecma_make_integer_value (number + 1);
continue;
}
case VM_OC_PUSH_NEG_BYTE:
{
ecma_integer_value_t number = *byte_code_p++;
*stack_top_p++ = ecma_make_integer_value (-(number + 1));
continue;
}
case VM_OC_PUSH_LIT_0:
{
stack_top_p[0] = left_value;
stack_top_p[1] = ecma_make_integer_value (0);
stack_top_p += 2;
continue;
}
case VM_OC_PUSH_LIT_POS_BYTE:
{
ecma_integer_value_t number = *byte_code_p++;
stack_top_p[0] = left_value;
stack_top_p[1] = ecma_make_integer_value (number + 1);
stack_top_p += 2;
continue;
}
case VM_OC_PUSH_LIT_NEG_BYTE:
{
ecma_integer_value_t number = *byte_code_p++;
stack_top_p[0] = left_value;
stack_top_p[1] = ecma_make_integer_value (-(number + 1));
stack_top_p += 2;
continue;
}
case VM_OC_PUSH_OBJECT:
{
ecma_object_t *obj_p =
ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), 0, ECMA_OBJECT_TYPE_GENERAL);
*stack_top_p++ = ecma_make_object_value (obj_p);
continue;
}
case VM_OC_PUSH_NAMED_FUNC_EXPR:
{
ecma_object_t *func_p = ecma_get_object_from_value (left_value);
JERRY_ASSERT (ecma_get_object_type (func_p) == ECMA_OBJECT_TYPE_FUNCTION);
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_p;
JERRY_ASSERT (frame_ctx_p->lex_env_p
== ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, ext_func_p->u.function.scope_cp));
ecma_object_t *name_lex_env = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p);
ecma_op_create_immutable_binding (name_lex_env, ecma_get_string_from_value (right_value), left_value);
ECMA_SET_NON_NULL_POINTER_TAG (ext_func_p->u.function.scope_cp, name_lex_env, 0);
ecma_free_value (right_value);
ecma_deref_object (name_lex_env);
*stack_top_p++ = left_value;
continue;
}
case VM_OC_CREATE_BINDING:
{
#if !JERRY_ESNEXT
JERRY_ASSERT (opcode == CBC_CREATE_VAR);
#endif /* !JERRY_ESNEXT */
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
JERRY_ASSERT (ecma_find_named_property (frame_ctx_p->lex_env_p, name_p) == NULL);
uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE;
#if JERRY_ESNEXT
if (opcode == CBC_CREATE_LET)
{
prop_attributes = ECMA_PROPERTY_ENUMERABLE_WRITABLE;
}
else if (opcode == CBC_CREATE_CONST)
{
prop_attributes = ECMA_PROPERTY_FLAG_ENUMERABLE;
}
ecma_property_value_t *property_value_p;
property_value_p = ecma_create_named_data_property (frame_ctx_p->lex_env_p, name_p, prop_attributes, NULL);
if (opcode != CBC_CREATE_VAR)
{
property_value_p->value = ECMA_VALUE_UNINITIALIZED;
}
#else /* !JERRY_ESNEXT */
ecma_create_named_data_property (frame_ctx_p->lex_env_p, name_p, prop_attributes, NULL);
#endif /* JERRY_ESNEXT */
continue;
}
case VM_OC_VAR_EVAL:
{
uint32_t literal_index;
ecma_value_t lit_value = ECMA_VALUE_UNDEFINED;
if (opcode == CBC_CREATE_VAR_FUNC_EVAL)
{
uint32_t value_index;
READ_LITERAL_INDEX (value_index);
JERRY_ASSERT (value_index >= const_literal_end);
lit_value = vm_construct_literal_object (frame_ctx_p, literal_start_p[value_index]);
}
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (literal_index >= register_end);
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK)
{
#if JERRY_ESNEXT && !(defined JERRY_NDEBUG)
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
JERRY_ASSERT (property_p == NULL || !(*property_p & ECMA_PROPERTY_FLAG_ENUMERABLE));
}
#endif /* JERRY_ESNEXT && !JERRY_NDEBUG */
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
}
#if JERRY_ESNEXT && !(defined JERRY_NDEBUG)
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
JERRY_ASSERT (property_p == NULL || !(*property_p & ECMA_PROPERTY_FLAG_ENUMERABLE));
}
#endif /* JERRY_ESNEXT && !JERRY_NDEBUG */
/* 'Variable declaration' */
result = ecma_op_has_binding (lex_env_p, name_p);
#if JERRY_BUILTIN_PROXY
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
#endif /* JERRY_BUILTIN_PROXY */
ecma_property_t *prop_p = NULL;
if (ecma_is_value_false (result))
{
bool is_configurable = (frame_ctx_p->status_flags & VM_FRAME_CTX_DIRECT_EVAL) != 0;
prop_p = ecma_op_create_mutable_binding (lex_env_p, name_p, is_configurable);
if (JERRY_UNLIKELY (prop_p == ECMA_PROPERTY_POINTER_ERROR))
{
result = ECMA_VALUE_ERROR;
goto error;
}
}
if (lit_value != ECMA_VALUE_UNDEFINED)
{
JERRY_ASSERT (ecma_is_value_object (lit_value));
if (prop_p != NULL)
{
JERRY_ASSERT (ecma_is_value_undefined (ECMA_PROPERTY_VALUE_PTR (prop_p)->value));
JERRY_ASSERT (ecma_is_property_writable (*prop_p));
ECMA_PROPERTY_VALUE_PTR (prop_p)->value = lit_value;
ecma_free_object (lit_value);
}
else
{
result = ecma_op_put_value_lex_env_base (lex_env_p, name_p, is_strict, lit_value);
ecma_free_object (lit_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
}
}
continue;
}
#if JERRY_ESNEXT
case VM_OC_EXT_VAR_EVAL:
{
uint32_t literal_index;
ecma_value_t lit_value = ECMA_VALUE_UNDEFINED;
JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE);
if (opcode == CBC_EXT_CREATE_VAR_FUNC_EVAL)
{
uint32_t value_index;
READ_LITERAL_INDEX (value_index);
JERRY_ASSERT (value_index >= const_literal_end);
lit_value = vm_construct_literal_object (frame_ctx_p, literal_start_p[value_index]);
}
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (literal_index >= register_end);
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
ecma_object_t *prev_lex_env_p = NULL;
while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK)
{
#if !(defined JERRY_NDEBUG)
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
JERRY_ASSERT (property_p == NULL || !(*property_p & ECMA_PROPERTY_FLAG_ENUMERABLE));
}
#endif /* !JERRY_NDEBUG */
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
prev_lex_env_p = lex_env_p;
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
}
JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
JERRY_ASSERT (prev_lex_env_p != NULL
&& ecma_get_lex_env_type (prev_lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
ecma_property_t *property_p = ecma_find_named_property (prev_lex_env_p, name_p);
ecma_property_value_t *property_value_p;
if (property_p == NULL)
{
property_value_p =
ecma_create_named_data_property (prev_lex_env_p, name_p, ECMA_PROPERTY_CONFIGURABLE_WRITABLE, NULL);
if (lit_value == ECMA_VALUE_UNDEFINED)
{
continue;
}
}
else
{
if (lit_value == ECMA_VALUE_UNDEFINED)
{
continue;
}
property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
ecma_free_value_if_not_object (property_value_p->value);
}
property_value_p->value = lit_value;
ecma_deref_object (ecma_get_object_from_value (lit_value));
continue;
}
#endif /* JERRY_ESNEXT */
case VM_OC_CREATE_ARGUMENTS:
{
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (frame_ctx_p->shared_p->status_flags & VM_FRAME_CTX_SHARED_HAS_ARG_LIST);
result = ecma_op_create_arguments_object ((vm_frame_ctx_shared_args_t *) (frame_ctx_p->shared_p),
frame_ctx_p->lex_env_p);
if (literal_index < register_end)
{
JERRY_ASSERT (VM_GET_REGISTER (frame_ctx_p, literal_index) == ECMA_VALUE_UNDEFINED);
VM_GET_REGISTER (frame_ctx_p, literal_index) = result;
continue;
}
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
JERRY_ASSERT (ecma_find_named_property (frame_ctx_p->lex_env_p, name_p) == NULL);
uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE;
ecma_property_value_t *property_value_p;
property_value_p = ecma_create_named_data_property (frame_ctx_p->lex_env_p, name_p, prop_attributes, NULL);
property_value_p->value = result;
ecma_deref_object (ecma_get_object_from_value (result));
continue;
}
#if JERRY_SNAPSHOT_EXEC
case VM_OC_SET_BYTECODE_PTR:
{
memcpy (&byte_code_p, byte_code_p++, sizeof (uintptr_t));
frame_ctx_p->byte_code_start_p = byte_code_p;
continue;
}
#endif /* JERRY_SNAPSHOT_EXEC */
case VM_OC_INIT_ARG_OR_FUNC:
{
uint32_t literal_index, value_index;
ecma_value_t lit_value;
bool release = false;
READ_LITERAL_INDEX (value_index);
if (value_index < register_end)
{
/* Take (not copy) the reference. */
lit_value = ecma_copy_value_if_not_object (VM_GET_REGISTER (frame_ctx_p, value_index));
}
else
{
lit_value = vm_construct_literal_object (frame_ctx_p, literal_start_p[value_index]);
release = true;
}
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (value_index != literal_index);
JERRY_ASSERT (value_index >= register_end || literal_index >= register_end);
if (literal_index < register_end)
{
ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, literal_index));
JERRY_ASSERT (release);
VM_GET_REGISTER (frame_ctx_p, literal_index) = lit_value;
continue;
}
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
JERRY_ASSERT (ecma_find_named_property (frame_ctx_p->lex_env_p, name_p) == NULL);
ecma_property_value_t *property_value_p;
property_value_p =
ecma_create_named_data_property (frame_ctx_p->lex_env_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL);
JERRY_ASSERT (property_value_p->value == ECMA_VALUE_UNDEFINED);
property_value_p->value = lit_value;
if (release)
{
ecma_deref_object (ecma_get_object_from_value (lit_value));
}
continue;
}
#if JERRY_ESNEXT
case VM_OC_CHECK_VAR:
{
JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (frame_ctx_p->shared_p->bytecode_header_p->status_flags)
== CBC_FUNCTION_SCRIPT);
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
if ((frame_ctx_p->lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) == 0)
{
continue;
}
ecma_string_t *const literal_name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_property_t *const binding_p = ecma_find_named_property (frame_ctx_p->lex_env_p, literal_name_p);
if (binding_p != NULL)
{
result = ecma_raise_syntax_error (ECMA_ERR_LOCAL_VARIABLE_IS_REDECLARED);
goto error;
}
continue;
}
case VM_OC_CHECK_LET:
{
JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (frame_ctx_p->shared_p->bytecode_header_p->status_flags)
== CBC_FUNCTION_SCRIPT);
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
ecma_string_t *literal_name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
if (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK)
{
result = opfunc_lexical_scope_has_restricted_binding (frame_ctx_p, literal_name_p);
if (!ecma_is_value_false (result))
{
if (ecma_is_value_true (result))
{
result = ecma_raise_syntax_error (ECMA_ERR_LOCAL_VARIABLE_IS_REDECLARED);
}
JERRY_ASSERT (ECMA_IS_VALUE_ERROR (result));
goto error;
}
continue;
}
result = ecma_op_has_binding (lex_env_p, literal_name_p);
#if JERRY_BUILTIN_PROXY
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
#endif /* JERRY_BUILTIN_PROXY */
if (ecma_is_value_true (result))
{
result = ecma_raise_syntax_error (ECMA_ERR_LOCAL_VARIABLE_IS_REDECLARED);
goto error;
}
continue;
}
case VM_OC_ASSIGN_LET_CONST:
{
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (literal_index >= register_end);
JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE
|| (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_CLASS
&& ECMA_LEX_ENV_CLASS_IS_MODULE (frame_ctx_p->lex_env_p)));
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_property_t *property_p = ecma_find_named_property (frame_ctx_p->lex_env_p, name_p);
JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_IS_RAW_DATA (*property_p)
&& (*property_p & ECMA_PROPERTY_FLAG_DATA));
JERRY_ASSERT (ECMA_PROPERTY_VALUE_PTR (property_p)->value == ECMA_VALUE_UNINITIALIZED);
ECMA_PROPERTY_VALUE_PTR (property_p)->value = left_value;
if (ecma_is_value_object (left_value))
{
ecma_deref_object (ecma_get_object_from_value (left_value));
}
continue;
}
case VM_OC_INIT_BINDING:
{
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (literal_index >= register_end);
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
JERRY_ASSERT (ecma_find_named_property (frame_ctx_p->lex_env_p, name_p) == NULL);
uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE;
if (opcode == CBC_INIT_LET)
{
prop_attributes = ECMA_PROPERTY_ENUMERABLE_WRITABLE;
}
else if (opcode == CBC_INIT_CONST)
{
prop_attributes = ECMA_PROPERTY_FLAG_ENUMERABLE;
}
ecma_property_value_t *property_value_p;
property_value_p = ecma_create_named_data_property (frame_ctx_p->lex_env_p, name_p, prop_attributes, NULL);
JERRY_ASSERT (property_value_p->value == ECMA_VALUE_UNDEFINED);
ecma_value_t value = *(--stack_top_p);
property_value_p->value = value;
ecma_deref_if_object (value);
continue;
}
case VM_OC_THROW_CONST_ERROR:
{
result = ecma_raise_type_error (ECMA_ERR_CONSTANT_BINDINGS_CANNOT_BE_REASSIGNED);
goto error;
}
case VM_OC_COPY_TO_GLOBAL:
{
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK)
{
#ifndef JERRY_NDEBUG
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
JERRY_ASSERT (property_p == NULL || !(*property_p & ECMA_PROPERTY_FLAG_ENUMERABLE));
}
#endif /* !JERRY_NDEBUG */
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
}
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
ecma_property_value_t *prop_value_p;
if (property_p == NULL)
{
prop_value_p = ecma_create_named_data_property (lex_env_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL);
}
else
{
#ifndef JERRY_NDEBUG
JERRY_ASSERT (!(*property_p & ECMA_PROPERTY_FLAG_ENUMERABLE));
#endif /* !JERRY_NDEBUG */
prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
}
ecma_named_data_property_assign_value (lex_env_p, prop_value_p, left_value);
}
else
{
result = ecma_op_set_mutable_binding (lex_env_p, name_p, left_value, is_strict);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
}
goto free_left_value;
}
case VM_OC_COPY_FROM_ARG:
{
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (literal_index >= register_end);
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
ecma_object_t *arg_lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
JERRY_ASSERT ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK)
&& ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
JERRY_ASSERT (arg_lex_env_p != NULL && !(arg_lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK)
&& ecma_get_lex_env_type (arg_lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
ecma_property_value_t *property_value_p;
property_value_p = ecma_create_named_data_property (lex_env_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL);
ecma_property_t *property_p = ecma_find_named_property (arg_lex_env_p, name_p);
JERRY_ASSERT (property_p != NULL);
ecma_property_value_t *arg_prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
property_value_p->value = ecma_copy_value_if_not_object (arg_prop_value_p->value);
continue;
}
case VM_OC_CLONE_CONTEXT:
{
JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE);
bool copy_values = (byte_code_start_p[1] == CBC_EXT_CLONE_FULL_CONTEXT);
frame_ctx_p->lex_env_p = ecma_clone_decl_lexical_environment (frame_ctx_p->lex_env_p, copy_values);
continue;
}
case VM_OC_SET__PROTO__:
{
result = ecma_builtin_object_object_set_proto (stack_top_p[-1], left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
goto free_left_value;
}
case VM_OC_PUSH_STATIC_FIELD_FUNC:
{
JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE
&& (byte_code_start_p[1] == CBC_EXT_PUSH_STATIC_FIELD_FUNC
|| byte_code_start_p[1] == CBC_EXT_PUSH_STATIC_COMPUTED_FIELD_FUNC));
bool push_computed = (byte_code_start_p[1] == CBC_EXT_PUSH_STATIC_COMPUTED_FIELD_FUNC);
ecma_value_t value = stack_top_p[-1];
if (!push_computed)
{
stack_top_p++;
}
memmove (stack_top_p - 3, stack_top_p - 4, 3 * sizeof (ecma_value_t));
stack_top_p[-4] = left_value;
ecma_object_t *class_object_p = ecma_get_object_from_value (stack_top_p[-2]);
ecma_object_t *initializer_func_p = ecma_get_object_from_value (left_value);
opfunc_bind_class_environment (frame_ctx_p->lex_env_p, class_object_p, class_object_p, initializer_func_p);
if (!push_computed)
{
continue;
}
left_value = value;
/* FALLTHRU */
}
case VM_OC_ADD_COMPUTED_FIELD:
{
JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE
&& (byte_code_start_p[1] == CBC_EXT_PUSH_STATIC_COMPUTED_FIELD_FUNC
|| byte_code_start_p[1] == CBC_EXT_ADD_COMPUTED_FIELD
|| byte_code_start_p[1] == CBC_EXT_ADD_STATIC_COMPUTED_FIELD));
int index = (byte_code_start_p[1] == CBC_EXT_ADD_COMPUTED_FIELD) ? -2 : -4;
result = opfunc_add_computed_field (stack_top_p[index], left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
goto free_left_value;
}
case VM_OC_COPY_DATA_PROPERTIES:
{
left_value = *(--stack_top_p);
if (ecma_is_value_undefined (left_value) || ecma_is_value_null (left_value))
{
continue;
}
result = opfunc_copy_data_properties (stack_top_p[-1], left_value, ECMA_VALUE_UNDEFINED);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
goto free_left_value;
}
case VM_OC_SET_COMPUTED_PROPERTY:
{
/* Swap values. */
left_value ^= right_value;
right_value ^= left_value;
left_value ^= right_value;
/* FALLTHRU */
}
#endif /* JERRY_ESNEXT */
case VM_OC_SET_PROPERTY:
{
JERRY_STATIC_ASSERT (VM_OC_NON_STATIC_FLAG == VM_OC_BACKWARD_BRANCH,
vm_oc_non_static_flag_must_be_equal_to_vm_oc_backward_branch);
JERRY_ASSERT ((opcode_data >> VM_OC_NON_STATIC_SHIFT) <= 0x1);
ecma_string_t *prop_name_p = ecma_op_to_property_key (right_value);
if (JERRY_UNLIKELY (prop_name_p == NULL))
{
result = ECMA_VALUE_ERROR;
goto error;
}
#if JERRY_ESNEXT
if (JERRY_UNLIKELY (ecma_compare_ecma_string_to_magic_id (prop_name_p, LIT_MAGIC_STRING_PROTOTYPE))
&& !(opcode_data & VM_OC_NON_STATIC_FLAG))
{
result = ecma_raise_type_error (ECMA_ERR_CLASS_IS_NON_CONFIGURABLE);
goto error;
}
const int index = (int) (opcode_data >> VM_OC_NON_STATIC_SHIFT) - 2;
#else /* !JERRY_ESNEXT */
const int index = -1;
#endif /* JERRY_ESNEXT */
ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[index]);
opfunc_set_data_property (object_p, prop_name_p, left_value);
ecma_deref_ecma_string (prop_name_p);
goto free_both_values;
}
case VM_OC_SET_GETTER:
case VM_OC_SET_SETTER:
{
JERRY_ASSERT ((opcode_data >> VM_OC_NON_STATIC_SHIFT) <= 0x1);
ecma_string_t *prop_name_p = ecma_op_to_property_key (left_value);
if (JERRY_UNLIKELY (prop_name_p == NULL))
{
result = ECMA_VALUE_ERROR;
goto error;
}
#if JERRY_ESNEXT
if (JERRY_UNLIKELY (ecma_compare_ecma_string_to_magic_id (prop_name_p, LIT_MAGIC_STRING_PROTOTYPE))
&& !(opcode_data & VM_OC_NON_STATIC_FLAG))
{
result = ecma_raise_type_error (ECMA_ERR_CLASS_IS_NON_CONFIGURABLE);
goto error;
}
const int index = (int) (opcode_data >> VM_OC_NON_STATIC_SHIFT) - 2;
#else /* !JERRY_ESNEXT */
const int index = -1;
#endif /* JERRY_ESNEXT */
opfunc_set_accessor (VM_OC_GROUP_GET_INDEX (opcode_data) == VM_OC_SET_GETTER,
stack_top_p[index],
prop_name_p,
right_value);
ecma_deref_ecma_string (prop_name_p);
goto free_both_values;
}
case VM_OC_PUSH_ARRAY:
{
/* Note: this operation cannot throw an exception */
*stack_top_p++ = ecma_make_object_value (ecma_op_new_array_object (0));
continue;
}
#if JERRY_ESNEXT
case VM_OC_LOCAL_EVAL:
{
ECMA_CLEAR_LOCAL_PARSE_OPTS ();
uint8_t parse_opts = *byte_code_p++;
ECMA_SET_LOCAL_PARSE_OPTS (parse_opts);
continue;
}
case VM_OC_SUPER_CALL:
{
uint8_t arguments_list_len = *byte_code_p++;
if (opcode >= CBC_EXT_SPREAD_SUPER_CALL)
{
stack_top_p -= arguments_list_len;
ecma_collection_t *arguments_p = opfunc_spread_arguments (stack_top_p, arguments_list_len);
if (JERRY_UNLIKELY (arguments_p == NULL))
{
result = ECMA_VALUE_ERROR;
goto error;
}
stack_top_p++;
ECMA_SET_INTERNAL_VALUE_POINTER (stack_top_p[-1], arguments_p);
}
else
{
stack_top_p -= arguments_list_len;
}
frame_ctx_p->call_operation = VM_EXEC_SUPER_CALL;
frame_ctx_p->byte_code_p = byte_code_start_p;
frame_ctx_p->stack_top_p = stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
case VM_OC_PUSH_CLASS_ENVIRONMENT:
{
uint16_t literal_index;
READ_LITERAL_INDEX (literal_index);
opfunc_push_class_environment (frame_ctx_p, &stack_top_p, literal_start_p[literal_index]);
continue;
}
case VM_OC_PUSH_IMPLICIT_CTOR:
{
*stack_top_p++ = opfunc_create_implicit_class_constructor (opcode, frame_ctx_p->shared_p->bytecode_header_p);
continue;
}
case VM_OC_DEFINE_FIELD:
{
result = opfunc_define_field (frame_ctx_p->this_binding, right_value, left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
goto free_both_values;
}
case VM_OC_ASSIGN_PRIVATE:
{
result = opfunc_private_set (stack_top_p[-3], stack_top_p[-2], stack_top_p[-1]);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_free_value (stack_top_p[-3]);
ecma_free_value (stack_top_p[-2]);
ecma_free_value (stack_top_p[-1]);
stack_top_p -= 3;
if (opcode_data & VM_OC_PUT_STACK)
{
*stack_top_p++ = result;
}
else if (opcode_data & VM_OC_PUT_BLOCK)
{
ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, 0));
VM_GET_REGISTERS (frame_ctx_p)[0] = result;
}
else
{
ecma_free_value (result);
}
goto free_both_values;
}
case VM_OC_PRIVATE_FIELD_ADD:
{
result = opfunc_private_field_add (frame_ctx_p->this_binding, right_value, left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
goto free_both_values;
}
case VM_OC_PRIVATE_PROP_GET:
{
result = opfunc_private_get (left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_PRIVATE_PROP_REFERENCE:
{
result = opfunc_private_get (stack_top_p[-1], left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = left_value;
*stack_top_p++ = result;
continue;
}
case VM_OC_PRIVATE_IN:
{
result = opfunc_private_in (left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_COLLECT_PRIVATE_PROPERTY:
{
opfunc_collect_private_properties (stack_top_p[-2], left_value, right_value, opcode);
continue;
}
case VM_OC_INIT_CLASS:
{
result = opfunc_init_class (frame_ctx_p, stack_top_p);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
continue;
}
case VM_OC_FINALIZE_CLASS:
{
JERRY_ASSERT (opcode == CBC_EXT_FINALIZE_NAMED_CLASS || opcode == CBC_EXT_FINALIZE_ANONYMOUS_CLASS);
if (opcode == CBC_EXT_FINALIZE_NAMED_CLASS)
{
uint16_t literal_index;
READ_LITERAL_INDEX (literal_index);
left_value = literal_start_p[literal_index];
}
opfunc_finalize_class (frame_ctx_p, &stack_top_p, left_value);
continue;
}
case VM_OC_SET_FIELD_INIT:
{
ecma_string_t *property_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_INIT);
ecma_object_t *proto_object_p = ecma_get_object_from_value (stack_top_p[-1]);
ecma_object_t *class_object_p = ecma_get_object_from_value (stack_top_p[-2]);
ecma_object_t *initializer_func_p = ecma_get_object_from_value (left_value);
opfunc_bind_class_environment (frame_ctx_p->lex_env_p, proto_object_p, class_object_p, initializer_func_p);
ecma_property_value_t *property_value_p =
ecma_create_named_data_property (class_object_p, property_name_p, ECMA_PROPERTY_FIXED, NULL);
property_value_p->value = left_value;
property_name_p = ecma_get_internal_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED);
ecma_property_t *property_p = ecma_find_named_property (class_object_p, property_name_p);
if (property_p != NULL)
{
property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
ecma_value_t *compact_collection_p =
ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t, property_value_p->value);
compact_collection_p = ecma_compact_collection_shrink (compact_collection_p);
ECMA_SET_INTERNAL_VALUE_POINTER (property_value_p->value, compact_collection_p);
}
goto free_left_value;
}
case VM_OC_RUN_FIELD_INIT:
{
JERRY_ASSERT (frame_ctx_p->shared_p->status_flags & VM_FRAME_CTX_SHARED_NON_ARROW_FUNC);
result = opfunc_init_class_fields (frame_ctx_p->shared_p->function_object_p, frame_ctx_p->this_binding);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
continue;
}
case VM_OC_RUN_STATIC_FIELD_INIT:
{
left_value = stack_top_p[-2];
stack_top_p[-2] = stack_top_p[-1];
stack_top_p--;
result = opfunc_init_static_class_fields (left_value, stack_top_p[-1]);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
goto free_left_value;
}
case VM_OC_SET_NEXT_COMPUTED_FIELD:
{
ecma_integer_value_t next_index = ecma_get_integer_from_value (stack_top_p[-2]) + 1;
stack_top_p[-2] = ecma_make_integer_value (next_index);
JERRY_ASSERT (frame_ctx_p->shared_p->status_flags & VM_FRAME_CTX_SHARED_HAS_CLASS_FIELDS);
ecma_value_t *computed_class_fields_p = VM_GET_COMPUTED_CLASS_FIELDS (frame_ctx_p);
JERRY_ASSERT ((ecma_value_t) next_index < ECMA_COMPACT_COLLECTION_GET_SIZE (computed_class_fields_p));
ecma_value_t prop_name = computed_class_fields_p[next_index];
if (opcode == CBC_EXT_SET_NEXT_COMPUTED_FIELD_ANONYMOUS_FUNC)
{
ecma_object_t *func_obj_p = ecma_get_object_from_value (result);
JERRY_ASSERT (ecma_find_named_property (func_obj_p, ecma_get_magic_string (LIT_MAGIC_STRING_NAME)) == NULL);
ecma_property_value_t *value_p;
value_p = ecma_create_named_data_property (func_obj_p,
ecma_get_magic_string (LIT_MAGIC_STRING_NAME),
ECMA_PROPERTY_FLAG_CONFIGURABLE,
NULL);
if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION)
{
ECMA_SET_SECOND_BIT_TO_POINTER_TAG (((ecma_extended_object_t *) func_obj_p)->u.function.scope_cp);
}
value_p->value = ecma_copy_value (prop_name);
}
result = opfunc_define_field (frame_ctx_p->this_binding, prop_name, stack_top_p[-1]);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_free_value (*(--stack_top_p));
continue;
}
case VM_OC_PUSH_SUPER_CONSTRUCTOR:
{
result = ecma_op_function_get_super_constructor (vm_get_class_function (frame_ctx_p));
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
continue;
}
case VM_OC_RESOLVE_LEXICAL_THIS:
{
result = ecma_op_get_this_binding (frame_ctx_p->lex_env_p);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
continue;
}
case VM_OC_OBJECT_LITERAL_HOME_ENV:
{
if (opcode == CBC_EXT_PUSH_OBJECT_SUPER_ENVIRONMENT)
{
ecma_value_t obj_value = stack_top_p[-1];
ecma_object_t *obj_env_p = ecma_create_lex_env_class (frame_ctx_p->lex_env_p, 0);
ECMA_SET_NON_NULL_POINTER (obj_env_p->u1.bound_object_cp, ecma_get_object_from_value (obj_value));
stack_top_p[-1] = ecma_make_object_value (obj_env_p);
*stack_top_p++ = obj_value;
}
else
{
JERRY_ASSERT (opcode == CBC_EXT_POP_OBJECT_SUPER_ENVIRONMENT);
ecma_deref_object (ecma_get_object_from_value (stack_top_p[-2]));
stack_top_p[-2] = stack_top_p[-1];
stack_top_p--;
}
continue;
}
case VM_OC_SET_HOME_OBJECT:
{
int offset = opcode == CBC_EXT_OBJECT_LITERAL_SET_HOME_OBJECT_COMPUTED ? -1 : 0;
opfunc_set_home_object (ecma_get_object_from_value (stack_top_p[-1]),
ecma_get_object_from_value (stack_top_p[-3 + offset]));
continue;
}
case VM_OC_SUPER_REFERENCE:
{
result = opfunc_form_super_reference (&stack_top_p, frame_ctx_p, left_value, opcode);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
goto free_left_value;
}
case VM_OC_SET_FUNCTION_NAME:
{
char *prefix_p = NULL;
lit_utf8_size_t prefix_size = 0;
if (opcode != CBC_EXT_SET_FUNCTION_NAME)
{
ecma_value_t prop_name_value;
if (opcode == CBC_EXT_SET_CLASS_NAME)
{
uint16_t literal_index;
READ_LITERAL_INDEX (literal_index);
prop_name_value = literal_start_p[literal_index];
}
else
{
prop_name_value = stack_top_p[-2];
}
ecma_string_t *prop_name_p = ecma_op_to_property_key (prop_name_value);
if (JERRY_UNLIKELY (prop_name_p == NULL))
{
result = ECMA_VALUE_ERROR;
goto error;
}
left_value = ecma_make_prop_name_value (prop_name_p);
if (opcode != CBC_EXT_SET_CLASS_NAME)
{
ecma_ref_ecma_string (prop_name_p);
ecma_free_value (stack_top_p[-2]);
stack_top_p[-2] = left_value;
}
if (opcode == CBC_EXT_SET_COMPUTED_GETTER_NAME || opcode == CBC_EXT_SET_COMPUTED_SETTER_NAME)
{
prefix_p = (opcode == CBC_EXT_SET_COMPUTED_GETTER_NAME) ? "get " : "set ";
prefix_size = 4;
}
}
ecma_object_t *func_obj_p = ecma_get_object_from_value (stack_top_p[-1]);
if (ecma_find_named_property (func_obj_p, ecma_get_magic_string (LIT_MAGIC_STRING_NAME)) != NULL)
{
ecma_free_value (left_value);
continue;
}
ecma_property_value_t *value_p;
value_p = ecma_create_named_data_property (func_obj_p,
ecma_get_magic_string (LIT_MAGIC_STRING_NAME),
ECMA_PROPERTY_FLAG_CONFIGURABLE,
NULL);
if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION)
{
ECMA_SET_SECOND_BIT_TO_POINTER_TAG (((ecma_extended_object_t *) func_obj_p)->u.function.scope_cp);
}
value_p->value =
ecma_op_function_form_name (ecma_get_prop_name_from_value (left_value), prefix_p, prefix_size);
ecma_free_value (left_value);
continue;
}
case VM_OC_PUSH_SPREAD_ELEMENT:
{
*stack_top_p++ = ECMA_VALUE_SPREAD_ELEMENT;
continue;
}
case VM_OC_PUSH_REST_OBJECT:
{
vm_frame_ctx_shared_t *shared_p = frame_ctx_p->shared_p;
JERRY_ASSERT (shared_p->status_flags & VM_FRAME_CTX_SHARED_HAS_ARG_LIST);
const ecma_value_t *arg_list_p = ((vm_frame_ctx_shared_args_t *) shared_p)->arg_list_p;
uint32_t arg_list_len = ((vm_frame_ctx_shared_args_t *) shared_p)->arg_list_len;
uint16_t argument_end;
if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
argument_end = ((cbc_uint16_arguments_t *) bytecode_header_p)->argument_end;
}
else
{
argument_end = ((cbc_uint8_arguments_t *) bytecode_header_p)->argument_end;
}
if (arg_list_len < argument_end)
{
arg_list_len = argument_end;
}
result = ecma_op_new_array_object_from_buffer (arg_list_p + argument_end, arg_list_len - argument_end);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (result));
*stack_top_p++ = result;
continue;
}
case VM_OC_ITERATOR_CONTEXT_CREATE:
{
result = ecma_op_get_iterator (stack_top_p[-1], ECMA_VALUE_SYNC_ITERATOR, &left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
uint32_t context_size =
(uint32_t) (stack_top_p + PARSER_ITERATOR_CONTEXT_STACK_ALLOCATION - VM_LAST_CONTEXT_END ());
stack_top_p += PARSER_ITERATOR_CONTEXT_STACK_ALLOCATION;
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, context_size);
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_ITERATOR, context_size) | VM_CONTEXT_CLOSE_ITERATOR;
stack_top_p[-2] = result;
stack_top_p[-3] = left_value;
continue;
}
case VM_OC_ITERATOR_STEP:
{
ecma_value_t *last_context_end_p = VM_LAST_CONTEXT_END ();
ecma_value_t iterator = last_context_end_p[-2];
ecma_value_t next_method = last_context_end_p[-3];
result = ecma_op_iterator_step (iterator, next_method);
if (ECMA_IS_VALUE_ERROR (result))
{
last_context_end_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
goto error;
}
ecma_value_t value = ECMA_VALUE_UNDEFINED;
if (!ecma_is_value_false (result))
{
value = ecma_op_iterator_value (result);
ecma_free_value (result);
if (ECMA_IS_VALUE_ERROR (value))
{
last_context_end_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
result = value;
goto error;
}
}
else
{
last_context_end_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
}
*stack_top_p++ = value;
continue;
}
case VM_OC_ITERATOR_CONTEXT_END:
{
JERRY_ASSERT (VM_LAST_CONTEXT_END () == stack_top_p);
if (stack_top_p[-1] & VM_CONTEXT_CLOSE_ITERATOR)
{
stack_top_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
result = ecma_op_iterator_close (stack_top_p[-2]);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
}
stack_top_p =
vm_stack_context_abort_variable_length (frame_ctx_p, stack_top_p, PARSER_ITERATOR_CONTEXT_STACK_ALLOCATION);
continue;
}
case VM_OC_DEFAULT_INITIALIZER:
{
JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end);
if (stack_top_p[-1] != ECMA_VALUE_UNDEFINED)
{
byte_code_p = byte_code_start_p + branch_offset;
continue;
}
stack_top_p--;
continue;
}
case VM_OC_REST_INITIALIZER:
{
ecma_object_t *array_p = ecma_op_new_array_object (0);
JERRY_ASSERT (ecma_op_object_is_fast_array (array_p));
ecma_value_t *last_context_end_p = VM_LAST_CONTEXT_END ();
ecma_value_t iterator = last_context_end_p[-2];
ecma_value_t next_method = last_context_end_p[-3];
uint32_t index = 0;
while (true)
{
result = ecma_op_iterator_step (iterator, next_method);
if (ECMA_IS_VALUE_ERROR (result))
{
last_context_end_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
ecma_deref_object (array_p);
goto error;
}
if (ecma_is_value_false (result))
{
last_context_end_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
break;
}
ecma_value_t value = ecma_op_iterator_value (result);
ecma_free_value (result);
if (ECMA_IS_VALUE_ERROR (value))
{
ecma_deref_object (array_p);
result = value;
goto error;
}
bool set_result = ecma_fast_array_set_property (array_p, index++, value);
JERRY_ASSERT (set_result);
ecma_free_value (value);
}
*stack_top_p++ = ecma_make_object_value (array_p);
continue;
}
case VM_OC_OBJ_INIT_CONTEXT_CREATE:
{
left_value = stack_top_p[-1];
vm_stack_context_type_t context_type = VM_CONTEXT_OBJ_INIT;
uint32_t context_stack_allocation = PARSER_OBJ_INIT_CONTEXT_STACK_ALLOCATION;
if (opcode == CBC_EXT_OBJ_INIT_REST_CONTEXT_CREATE)
{
context_type = VM_CONTEXT_OBJ_INIT_REST;
context_stack_allocation = PARSER_OBJ_INIT_REST_CONTEXT_STACK_ALLOCATION;
}
uint32_t context_size = (uint32_t) (stack_top_p + context_stack_allocation - VM_LAST_CONTEXT_END ());
stack_top_p += context_stack_allocation;
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, context_size);
stack_top_p[-1] = VM_CREATE_CONTEXT (context_type, context_size);
stack_top_p[-2] = left_value;
if (context_type == VM_CONTEXT_OBJ_INIT_REST)
{
stack_top_p[-3] = ecma_make_object_value (ecma_op_new_array_object (0));
}
continue;
}
case VM_OC_OBJ_INIT_CONTEXT_END:
{
JERRY_ASSERT (stack_top_p == VM_LAST_CONTEXT_END ());
uint32_t context_stack_allocation = PARSER_OBJ_INIT_CONTEXT_STACK_ALLOCATION;
if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_OBJ_INIT_REST)
{
context_stack_allocation = PARSER_OBJ_INIT_REST_CONTEXT_STACK_ALLOCATION;
}
stack_top_p = vm_stack_context_abort_variable_length (frame_ctx_p, stack_top_p, context_stack_allocation);
continue;
}
case VM_OC_OBJ_INIT_PUSH_REST:
{
ecma_value_t *last_context_end_p = VM_LAST_CONTEXT_END ();
if (!ecma_op_require_object_coercible (last_context_end_p[-2]))
{
result = ECMA_VALUE_ERROR;
goto error;
}
ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
ecma_object_t *result_object_p = ecma_create_object (prototype_p, 0, ECMA_OBJECT_TYPE_GENERAL);
left_value = ecma_make_object_value (result_object_p);
result = opfunc_copy_data_properties (left_value, last_context_end_p[-2], last_context_end_p[-3]);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_free_value (last_context_end_p[-3]);
last_context_end_p[-3] = last_context_end_p[-2];
last_context_end_p[-2] = ECMA_VALUE_UNDEFINED;
*stack_top_p++ = left_value;
continue;
}
case VM_OC_INITIALIZER_PUSH_NAME:
{
if (JERRY_UNLIKELY (!ecma_is_value_prop_name (left_value)))
{
ecma_string_t *property_key = ecma_op_to_property_key (left_value);
if (property_key == NULL)
{
result = ECMA_VALUE_ERROR;
goto error;
}
ecma_free_value (left_value);
left_value = ecma_make_string_value (property_key);
}
ecma_value_t *last_context_end_p = VM_LAST_CONTEXT_END ();
ecma_object_t *array_obj_p = ecma_get_object_from_value (last_context_end_p[-3]);
JERRY_ASSERT (ecma_get_object_type (array_obj_p) == ECMA_OBJECT_TYPE_ARRAY);
ecma_extended_object_t *ext_array_obj_p = (ecma_extended_object_t *) array_obj_p;
ecma_fast_array_set_property (array_obj_p, ext_array_obj_p->u.array.length, left_value);
/* FALLTHRU */
}
case VM_OC_INITIALIZER_PUSH_PROP:
{
ecma_value_t *last_context_end_p = VM_LAST_CONTEXT_END ();
ecma_value_t base = last_context_end_p[-2];
if (opcode == CBC_EXT_INITIALIZER_PUSH_PROP)
{
left_value = *last_context_end_p++;
while (last_context_end_p < stack_top_p)
{
last_context_end_p[-1] = *last_context_end_p;
last_context_end_p++;
}
stack_top_p--;
}
result = vm_op_get_value (base, left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_left_value;
}
case VM_OC_SPREAD_ARGUMENTS:
{
uint8_t arguments_list_len = *byte_code_p++;
stack_top_p -= arguments_list_len;
ecma_collection_t *arguments_p = opfunc_spread_arguments (stack_top_p, arguments_list_len);
if (JERRY_UNLIKELY (arguments_p == NULL))
{
result = ECMA_VALUE_ERROR;
goto error;
}
stack_top_p++;
ECMA_SET_INTERNAL_VALUE_POINTER (stack_top_p[-1], arguments_p);
frame_ctx_p->call_operation = VM_EXEC_SPREAD_OP;
frame_ctx_p->byte_code_p = byte_code_start_p;
frame_ctx_p->stack_top_p = stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
case VM_OC_CREATE_GENERATOR:
{
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = stack_top_p;
vm_executable_object_t *executable_object_p;
executable_object_p = opfunc_create_executable_object (frame_ctx_p, VM_CREATE_EXECUTABLE_OBJECT_GENERATOR);
return ecma_make_object_value ((ecma_object_t *) executable_object_p);
}
case VM_OC_YIELD:
{
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = --stack_top_p;
return *stack_top_p;
}
case VM_OC_ASYNC_YIELD:
{
ecma_extended_object_t *async_generator_object_p = VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
opfunc_async_generator_yield (async_generator_object_p, stack_top_p[-1]);
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = --stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
case VM_OC_ASYNC_YIELD_ITERATOR:
{
ecma_extended_object_t *async_generator_object_p = VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
JERRY_ASSERT (
!(async_generator_object_p->u.cls.u2.executable_obj_flags & ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD));
/* Byte code is executed at the first time. */
left_value = stack_top_p[-1];
result = ecma_op_get_iterator (left_value, ECMA_VALUE_ASYNC_ITERATOR, stack_top_p - 1);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_free_value (left_value);
left_value = result;
result = ecma_op_iterator_next (left_value, stack_top_p[-1], ECMA_VALUE_UNDEFINED);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
result = ecma_promise_async_await (async_generator_object_p, result);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
async_generator_object_p->u.cls.u2.executable_obj_flags |= ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD;
*VM_GET_EXECUTABLE_ITERATOR (frame_ctx_p) = left_value;
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
case VM_OC_AWAIT:
{
if (JERRY_UNLIKELY (!(frame_ctx_p->shared_p->status_flags & VM_FRAME_CTX_SHARED_EXECUTABLE)))
{
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = --stack_top_p;
result = opfunc_async_create_and_await (frame_ctx_p, *stack_top_p, 0);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
return result;
}
/* FALLTHRU */
}
case VM_OC_GENERATOR_AWAIT:
{
ecma_extended_object_t *async_generator_object_p = VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
result = ecma_promise_async_await (async_generator_object_p, *(--stack_top_p));
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
case VM_OC_EXT_RETURN:
{
result = left_value;
left_value = ECMA_VALUE_UNDEFINED;
ecma_value_t *stack_bottom_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth;
while (stack_top_p > stack_bottom_p)
{
ecma_fast_free_value (*(--stack_top_p));
}
goto error;
}
case VM_OC_ASYNC_EXIT:
{
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
if (!(frame_ctx_p->shared_p->status_flags & VM_FRAME_CTX_SHARED_EXECUTABLE))
{
result = ecma_op_create_promise_object (ECMA_VALUE_EMPTY, ECMA_VALUE_UNDEFINED, NULL);
}
else
{
result = *VM_GET_EXECUTABLE_ITERATOR (frame_ctx_p);
*VM_GET_EXECUTABLE_ITERATOR (frame_ctx_p) = ECMA_VALUE_UNDEFINED;
}
vm_stack_context_type_t context_type = VM_GET_CONTEXT_TYPE (stack_top_p[-1]);
if (context_type == VM_CONTEXT_TRY)
{
JERRY_ASSERT (frame_ctx_p->context_depth == PARSER_TRY_CONTEXT_STACK_ALLOCATION);
left_value = ECMA_VALUE_UNDEFINED;
}
else
{
JERRY_ASSERT (frame_ctx_p->context_depth == PARSER_FINALLY_CONTEXT_STACK_ALLOCATION);
left_value = stack_top_p[-2];
}
if (context_type == VM_CONTEXT_FINALLY_THROW)
{
ecma_reject_promise (result, left_value);
}
else
{
JERRY_ASSERT (context_type == VM_CONTEXT_TRY || context_type == VM_CONTEXT_FINALLY_RETURN);
ecma_fulfill_promise (result, left_value);
}
ecma_free_value (left_value);
frame_ctx_p->context_depth = 0;
frame_ctx_p->call_operation = VM_NO_EXEC_OP;
return result;
}
case VM_OC_STRING_CONCAT:
{
ecma_string_t *left_str_p = ecma_op_to_string (left_value);
if (JERRY_UNLIKELY (left_str_p == NULL))
{
result = ECMA_VALUE_ERROR;
goto error;
}
ecma_string_t *right_str_p = ecma_op_to_string (right_value);
if (JERRY_UNLIKELY (right_str_p == NULL))
{
ecma_deref_ecma_string (left_str_p);
result = ECMA_VALUE_ERROR;
goto error;
}
ecma_string_t *result_str_p = ecma_concat_ecma_strings (left_str_p, right_str_p);
ecma_deref_ecma_string (right_str_p);
*stack_top_p++ = ecma_make_string_value (result_str_p);
goto free_both_values;
}
case VM_OC_GET_TEMPLATE_OBJECT:
{
uint8_t tagged_idx = *byte_code_p++;
ecma_collection_t *collection_p = ecma_compiled_code_get_tagged_template_collection (bytecode_header_p);
JERRY_ASSERT (tagged_idx < collection_p->item_count);
*stack_top_p++ = ecma_copy_value (collection_p->buffer_p[tagged_idx]);
continue;
}
case VM_OC_PUSH_NEW_TARGET:
{
ecma_object_t *new_target_object_p = JERRY_CONTEXT (current_new_target_p);
if (new_target_object_p == NULL)
{
*stack_top_p++ = ECMA_VALUE_UNDEFINED;
}
else
{
ecma_ref_object (new_target_object_p);
*stack_top_p++ = ecma_make_object_value (new_target_object_p);
}
continue;
}
case VM_OC_REQUIRE_OBJECT_COERCIBLE:
{
if (!ecma_op_require_object_coercible (stack_top_p[-1]))
{
result = ECMA_VALUE_ERROR;
goto error;
}
continue;
}
case VM_OC_ASSIGN_SUPER:
{
result = opfunc_assign_super_reference (&stack_top_p, frame_ctx_p, opcode_data);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
continue;
}
#endif /* JERRY_ESNEXT */
case VM_OC_PUSH_ELISON:
{
*stack_top_p++ = ECMA_VALUE_ARRAY_HOLE;
continue;
}
case VM_OC_APPEND_ARRAY:
{
uint16_t values_length = *byte_code_p++;
stack_top_p -= values_length;
#if JERRY_ESNEXT
if (*byte_code_start_p == CBC_EXT_OPCODE)
{
values_length = (uint16_t) (values_length | OPFUNC_HAS_SPREAD_ELEMENT);
}
#endif /* JERRY_ESNEXT */
result = opfunc_append_array (stack_top_p, values_length);
#if JERRY_ESNEXT
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
#else /* !JERRY_ESNEXT */
JERRY_ASSERT (ecma_is_value_empty (result));
#endif /* JERRY_ESNEXT */
continue;
}
case VM_OC_IDENT_REFERENCE:
{
uint16_t literal_index;
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (literal_index < ident_end);
if (literal_index < register_end)
{
*stack_top_p++ = ECMA_VALUE_REGISTER_REF;
*stack_top_p++ = ecma_make_integer_value (literal_index);
*stack_top_p++ = ecma_fast_copy_value (VM_GET_REGISTER (frame_ctx_p, literal_index));
}
else
{
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_object_t *ref_base_lex_env_p;
result = ecma_op_get_value_lex_env_base (frame_ctx_p->lex_env_p, &ref_base_lex_env_p, name_p);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_ref_object (ref_base_lex_env_p);
ecma_ref_ecma_string (name_p);
*stack_top_p++ = ecma_make_object_value (ref_base_lex_env_p);
*stack_top_p++ = ecma_make_string_value (name_p);
*stack_top_p++ = result;
}
continue;
}
case VM_OC_PROP_GET:
{
result = vm_op_get_value (left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_PROP_REFERENCE:
{
/* Forms with reference requires preserving the base and offset. */
if (opcode == CBC_PUSH_PROP_REFERENCE)
{
left_value = stack_top_p[-2];
right_value = stack_top_p[-1];
}
else if (opcode == CBC_PUSH_PROP_LITERAL_REFERENCE)
{
*stack_top_p++ = left_value;
right_value = left_value;
left_value = stack_top_p[-2];
}
else
{
JERRY_ASSERT (opcode == CBC_PUSH_PROP_LITERAL_LITERAL_REFERENCE
|| opcode == CBC_PUSH_PROP_THIS_LITERAL_REFERENCE);
*stack_top_p++ = left_value;
*stack_top_p++ = right_value;
}
/* FALLTHRU */
}
case VM_OC_PROP_PRE_INCR:
case VM_OC_PROP_PRE_DECR:
case VM_OC_PROP_POST_INCR:
case VM_OC_PROP_POST_DECR:
{
result = vm_op_get_value (left_value, right_value);
if (opcode < CBC_PRE_INCR)
{
left_value = ECMA_VALUE_UNDEFINED;
right_value = ECMA_VALUE_UNDEFINED;
}
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
if (opcode < CBC_PRE_INCR)
{
break;
}
stack_top_p += 2;
left_value = result;
right_value = ECMA_VALUE_UNDEFINED;
/* FALLTHRU */
}
case VM_OC_PRE_INCR:
case VM_OC_PRE_DECR:
case VM_OC_POST_INCR:
case VM_OC_POST_DECR:
{
uint32_t opcode_flags = VM_OC_GROUP_GET_INDEX (opcode_data) - VM_OC_PROP_PRE_INCR;
ecma_number_t result_number;
byte_code_p = byte_code_start_p + 1;
if (ecma_is_value_integer_number (left_value))
{
result = left_value;
left_value = ECMA_VALUE_UNDEFINED;
ecma_integer_value_t int_value = (ecma_integer_value_t) result;
ecma_integer_value_t int_increase = 0;
if (opcode_flags & VM_OC_DECREMENT_OPERATOR_FLAG)
{
if (int_value > ECMA_INTEGER_NUMBER_MIN_SHIFTED)
{
int_increase = -(1 << ECMA_DIRECT_SHIFT);
}
}
else if (int_value < ECMA_INTEGER_NUMBER_MAX_SHIFTED)
{
int_increase = 1 << ECMA_DIRECT_SHIFT;
}
if (JERRY_LIKELY (int_increase != 0))
{
/* Postfix operators require the unmodifed number value. */
if (opcode_flags & VM_OC_POST_INCR_DECR_OPERATOR_FLAG)
{
POST_INCREASE_DECREASE_PUT_RESULT (result);
}
result = (ecma_value_t) (int_value + int_increase);
break;
}
result_number = (ecma_number_t) ecma_get_integer_from_value (result);
}
else if (ecma_is_value_float_number (left_value))
{
result = left_value;
left_value = ECMA_VALUE_UNDEFINED;
result_number = ecma_get_number_from_value (result);
}
else
{
result = ecma_op_to_numeric (left_value, &result_number, ECMA_TO_NUMERIC_ALLOW_BIGINT);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_free_value (left_value);
left_value = ECMA_VALUE_UNDEFINED;
#if JERRY_BUILTIN_BIGINT
if (JERRY_UNLIKELY (ecma_is_value_bigint (result)))
{
ecma_bigint_unary_operation_type operation_type = ECMA_BIGINT_UNARY_INCREASE;
if (opcode_flags & VM_OC_DECREMENT_OPERATOR_FLAG)
{
operation_type = ECMA_BIGINT_UNARY_DECREASE;
}
/* Postfix operators require the unmodifed number value. */
if (opcode_flags & VM_OC_POST_INCR_DECR_OPERATOR_FLAG)
{
POST_INCREASE_DECREASE_PUT_RESULT (result);
result = ecma_bigint_unary (result, operation_type);
}
else
{
ecma_value_t original_value = result;
result = ecma_bigint_unary (original_value, operation_type);
ecma_free_value (original_value);
}
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
break;
}
#endif /* JERRY_BUILTIN_BIGINT */
result = ecma_make_number_value (result_number);
}
ecma_number_t increase = ECMA_NUMBER_ONE;
if (opcode_flags & VM_OC_DECREMENT_OPERATOR_FLAG)
{
/* For decrement operators */
increase = ECMA_NUMBER_MINUS_ONE;
}
/* Postfix operators require the unmodifed number value. */
if (opcode_flags & VM_OC_POST_INCR_DECR_OPERATOR_FLAG)
{
POST_INCREASE_DECREASE_PUT_RESULT (result);
result = ecma_make_number_value (result_number + increase);
break;
}
if (ecma_is_value_integer_number (result))
{
result = ecma_make_number_value (result_number + increase);
}
else
{
result = ecma_update_float_number (result, result_number + increase);
}
break;
}
case VM_OC_ASSIGN:
{
result = left_value;
left_value = ECMA_VALUE_UNDEFINED;
break;
}
case VM_OC_MOV_IDENT:
{
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (literal_index < register_end);
JERRY_ASSERT (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)));
ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, literal_index));
VM_GET_REGISTER (frame_ctx_p, literal_index) = left_value;
continue;
}
case VM_OC_ASSIGN_PROP:
{
result = stack_top_p[-1];
stack_top_p[-1] = left_value;
left_value = ECMA_VALUE_UNDEFINED;
break;
}
case VM_OC_ASSIGN_PROP_THIS:
{
result = stack_top_p[-1];
stack_top_p[-1] = ecma_copy_value (frame_ctx_p->this_binding);
*stack_top_p++ = left_value;
left_value = ECMA_VALUE_UNDEFINED;
break;
}
case VM_OC_RETURN_FUNCTION_END:
{
if (CBC_FUNCTION_GET_TYPE (bytecode_header_p->status_flags) == CBC_FUNCTION_SCRIPT)
{
result = VM_GET_REGISTER (frame_ctx_p, 0);
VM_GET_REGISTERS (frame_ctx_p)[0] = ECMA_VALUE_UNDEFINED;
}
else
{
result = ECMA_VALUE_UNDEFINED;
}
goto error;
}
case VM_OC_RETURN:
{
JERRY_ASSERT (opcode == CBC_RETURN || opcode == CBC_RETURN_WITH_LITERAL);
result = left_value;
left_value = ECMA_VALUE_UNDEFINED;
goto error;
}
case VM_OC_THROW:
{
jcontext_raise_exception (left_value);
result = ECMA_VALUE_ERROR;
left_value = ECMA_VALUE_UNDEFINED;
goto error;
}
case VM_OC_THROW_REFERENCE_ERROR:
{
result = ecma_raise_reference_error (ECMA_ERR_UNDEFINED_REFERENCE);
goto error;
}
case VM_OC_EVAL:
{
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_DIRECT_EVAL;
JERRY_ASSERT ((*byte_code_p >= CBC_CALL && *byte_code_p <= CBC_CALL2_PROP_BLOCK)
|| (*byte_code_p == CBC_EXT_OPCODE && byte_code_p[1] >= CBC_EXT_SPREAD_CALL
&& byte_code_p[1] <= CBC_EXT_SPREAD_CALL_PROP_BLOCK));
continue;
}
case VM_OC_CALL:
{
frame_ctx_p->call_operation = VM_EXEC_CALL;
frame_ctx_p->byte_code_p = byte_code_start_p;
frame_ctx_p->stack_top_p = stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
case VM_OC_NEW:
{
frame_ctx_p->call_operation = VM_EXEC_CONSTRUCT;
frame_ctx_p->byte_code_p = byte_code_start_p;
frame_ctx_p->stack_top_p = stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
case VM_OC_ERROR:
{
JERRY_ASSERT (frame_ctx_p->byte_code_p[1] == CBC_EXT_ERROR);
#if JERRY_DEBUGGER
frame_ctx_p->byte_code_p = JERRY_CONTEXT (debugger_exception_byte_code_p);
#endif /* JERRY_DEBUGGER */
result = ECMA_VALUE_ERROR;
goto error;
}
case VM_OC_RESOLVE_BASE_FOR_CALL:
{
ecma_value_t this_value = stack_top_p[-3];
if (this_value == ECMA_VALUE_REGISTER_REF)
{
/* Lexical environment cannot be 'this' value. */
stack_top_p[-2] = ECMA_VALUE_UNDEFINED;
stack_top_p[-3] = ECMA_VALUE_UNDEFINED;
}
else if (vm_get_implicit_this_value (&this_value))
{
ecma_free_value (stack_top_p[-3]);
stack_top_p[-3] = this_value;
}
continue;
}
case VM_OC_PROP_DELETE:
{
result = vm_op_delete_prop (left_value, right_value, is_strict);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
JERRY_ASSERT (ecma_is_value_boolean (result));
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_DELETE:
{
uint16_t literal_index;
READ_LITERAL_INDEX (literal_index);
if (literal_index < register_end)
{
*stack_top_p++ = ECMA_VALUE_FALSE;
continue;
}
result = vm_op_delete_var (literal_start_p[literal_index], frame_ctx_p->lex_env_p);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
JERRY_ASSERT (ecma_is_value_boolean (result));
*stack_top_p++ = result;
continue;
}
case VM_OC_JUMP:
{
byte_code_p = byte_code_start_p + branch_offset;
continue;
}
case VM_OC_BRANCH_IF_STRICT_EQUAL:
{
ecma_value_t value = *(--stack_top_p);
JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end);
if (ecma_op_strict_equality_compare (value, stack_top_p[-1]))
{
byte_code_p = byte_code_start_p + branch_offset;
ecma_free_value (*--stack_top_p);
}
ecma_free_value (value);
continue;
}
case VM_OC_BRANCH_IF_TRUE:
case VM_OC_BRANCH_IF_FALSE:
case VM_OC_BRANCH_IF_LOGICAL_TRUE:
case VM_OC_BRANCH_IF_LOGICAL_FALSE:
{
uint32_t opcode_flags = VM_OC_GROUP_GET_INDEX (opcode_data) - VM_OC_BRANCH_IF_TRUE;
ecma_value_t value = *(--stack_top_p);
bool boolean_value = ecma_op_to_boolean (value);
if (opcode_flags & VM_OC_BRANCH_IF_FALSE_FLAG)
{
boolean_value = !boolean_value;
}
if (boolean_value)
{
byte_code_p = byte_code_start_p + branch_offset;
if (opcode_flags & VM_OC_LOGICAL_BRANCH_FLAG)
{
/* "Push" the value back to the stack. */
++stack_top_p;
continue;
}
}
ecma_fast_free_value (value);
continue;
}
#if JERRY_ESNEXT
case VM_OC_POP_REFERENCE:
{
ecma_free_value (stack_top_p[-2]);
ecma_free_value (stack_top_p[-3]);
stack_top_p[-3] = stack_top_p[-1];
stack_top_p -= 2;
continue;
}
case VM_OC_BRANCH_IF_NULLISH:
{
left_value = stack_top_p[-1];
if (!ecma_is_value_null (left_value) && !ecma_is_value_undefined (left_value))
{
byte_code_p = byte_code_start_p + branch_offset;
continue;
}
--stack_top_p;
continue;
}
#endif /* JERRY_ESNEXT */
case VM_OC_PLUS:
case VM_OC_MINUS:
{
result = opfunc_unary_operation (left_value, VM_OC_GROUP_GET_INDEX (opcode_data) == VM_OC_PLUS);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_left_value;
}
case VM_OC_NOT:
{
*stack_top_p++ = ecma_make_boolean_value (!ecma_op_to_boolean (left_value));
JERRY_ASSERT (ecma_is_value_boolean (stack_top_p[-1]));
goto free_left_value;
}
case VM_OC_BIT_NOT:
{
JERRY_STATIC_ASSERT (ECMA_DIRECT_TYPE_MASK == ((1 << ECMA_DIRECT_SHIFT) - 1),
direct_type_mask_must_fill_all_bits_before_the_value_starts);
if (ecma_is_value_integer_number (left_value))
{
*stack_top_p++ = (~ECMA_DIRECT_TYPE_MASK) ^ left_value;
goto free_left_value;
}
result = do_number_bitwise_not (left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_left_value;
}
case VM_OC_VOID:
{
*stack_top_p++ = ECMA_VALUE_UNDEFINED;
goto free_left_value;
}
case VM_OC_TYPEOF_IDENT:
{
uint16_t literal_index;
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (literal_index < ident_end);
if (literal_index < register_end)
{
left_value = ecma_copy_value (VM_GET_REGISTER (frame_ctx_p, literal_index));
}
else
{
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_object_t *ref_base_lex_env_p;
result = ecma_op_get_value_lex_env_base (frame_ctx_p->lex_env_p, &ref_base_lex_env_p, name_p);
if (ref_base_lex_env_p == NULL)
{
jcontext_release_exception ();
result = ECMA_VALUE_UNDEFINED;
}
else if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
left_value = result;
}
/* FALLTHRU */
}
case VM_OC_TYPEOF:
{
result = opfunc_typeof (left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_left_value;
}
case VM_OC_ADD:
{
if (ecma_are_values_integer_numbers (left_value, right_value))
{
ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value);
ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value);
*stack_top_p++ = ecma_make_int32_value ((int32_t) (left_integer + right_integer));
continue;
}
if (ecma_is_value_float_number (left_value) && ecma_is_value_number (right_value))
{
ecma_number_t new_value =
(ecma_get_float_from_value (left_value) + ecma_get_number_from_value (right_value));
*stack_top_p++ = ecma_update_float_number (left_value, new_value);
ecma_free_number (right_value);
continue;
}
if (ecma_is_value_float_number (right_value) && ecma_is_value_integer_number (left_value))
{
ecma_number_t new_value =
((ecma_number_t) ecma_get_integer_from_value (left_value) + ecma_get_float_from_value (right_value));
*stack_top_p++ = ecma_update_float_number (right_value, new_value);
continue;
}
result = opfunc_addition (left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_SUB:
{
JERRY_STATIC_ASSERT (ECMA_INTEGER_NUMBER_MAX * 2 <= INT32_MAX && ECMA_INTEGER_NUMBER_MIN * 2 >= INT32_MIN,
doubled_ecma_numbers_must_fit_into_int32_range);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) && !ECMA_IS_VALUE_ERROR (right_value));
if (ecma_are_values_integer_numbers (left_value, right_value))
{
ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value);
ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value);
*stack_top_p++ = ecma_make_int32_value ((int32_t) (left_integer - right_integer));
continue;
}
if (ecma_is_value_float_number (left_value) && ecma_is_value_number (right_value))
{
ecma_number_t new_value =
(ecma_get_float_from_value (left_value) - ecma_get_number_from_value (right_value));
*stack_top_p++ = ecma_update_float_number (left_value, new_value);
ecma_free_number (right_value);
continue;
}
if (ecma_is_value_float_number (right_value) && ecma_is_value_integer_number (left_value))
{
ecma_number_t new_value =
((ecma_number_t) ecma_get_integer_from_value (left_value) - ecma_get_float_from_value (right_value));
*stack_top_p++ = ecma_update_float_number (right_value, new_value);
continue;
}
result = do_number_arithmetic (NUMBER_ARITHMETIC_SUBTRACTION, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_MUL:
{
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) && !ECMA_IS_VALUE_ERROR (right_value));
JERRY_STATIC_ASSERT (ECMA_INTEGER_MULTIPLY_MAX * ECMA_INTEGER_MULTIPLY_MAX <= ECMA_INTEGER_NUMBER_MAX
&& -(ECMA_INTEGER_MULTIPLY_MAX * ECMA_INTEGER_MULTIPLY_MAX) >= ECMA_INTEGER_NUMBER_MIN,
square_of_integer_multiply_max_must_fit_into_integer_value_range);
if (ecma_are_values_integer_numbers (left_value, right_value))
{
ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value);
ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value);
if (-ECMA_INTEGER_MULTIPLY_MAX <= left_integer && left_integer <= ECMA_INTEGER_MULTIPLY_MAX
&& -ECMA_INTEGER_MULTIPLY_MAX <= right_integer && right_integer <= ECMA_INTEGER_MULTIPLY_MAX
&& left_integer != 0 && right_integer != 0)
{
*stack_top_p++ = ecma_integer_multiply (left_integer, right_integer);
continue;
}
ecma_number_t multiply = (ecma_number_t) left_integer * (ecma_number_t) right_integer;
*stack_top_p++ = ecma_make_number_value (multiply);
continue;
}
if (ecma_is_value_float_number (left_value) && ecma_is_value_number (right_value))
{
ecma_number_t new_value =
(ecma_get_float_from_value (left_value) * ecma_get_number_from_value (right_value));
*stack_top_p++ = ecma_update_float_number (left_value, new_value);
ecma_free_number (right_value);
continue;
}
if (ecma_is_value_float_number (right_value) && ecma_is_value_integer_number (left_value))
{
ecma_number_t new_value =
((ecma_number_t) ecma_get_integer_from_value (left_value) * ecma_get_float_from_value (right_value));
*stack_top_p++ = ecma_update_float_number (right_value, new_value);
continue;
}
result = do_number_arithmetic (NUMBER_ARITHMETIC_MULTIPLICATION, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_DIV:
{
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) && !ECMA_IS_VALUE_ERROR (right_value));
result = do_number_arithmetic (NUMBER_ARITHMETIC_DIVISION, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_MOD:
{
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) && !ECMA_IS_VALUE_ERROR (right_value));
if (ecma_are_values_integer_numbers (left_value, right_value))
{
ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value);
ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value);
if (right_integer != 0)
{
ecma_integer_value_t mod_result = left_integer % right_integer;
if (mod_result != 0 || left_integer >= 0)
{
*stack_top_p++ = ecma_make_integer_value (mod_result);
continue;
}
}
}
result = do_number_arithmetic (NUMBER_ARITHMETIC_REMAINDER, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
#if JERRY_ESNEXT
case VM_OC_EXP:
{
result = do_number_arithmetic (NUMBER_ARITHMETIC_EXPONENTIATION, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
#endif /* JERRY_ESNEXT */
case VM_OC_EQUAL:
{
result = opfunc_equality (left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_NOT_EQUAL:
{
result = opfunc_equality (left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = ecma_invert_boolean_value (result);
goto free_both_values;
}
case VM_OC_STRICT_EQUAL:
{
bool is_equal = ecma_op_strict_equality_compare (left_value, right_value);
result = ecma_make_boolean_value (is_equal);
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_STRICT_NOT_EQUAL:
{
bool is_equal = ecma_op_strict_equality_compare (left_value, right_value);
result = ecma_make_boolean_value (!is_equal);
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_BIT_OR:
{
JERRY_STATIC_ASSERT (ECMA_DIRECT_TYPE_MASK == ((1 << ECMA_DIRECT_SHIFT) - 1),
direct_type_mask_must_fill_all_bits_before_the_value_starts);
if (ecma_are_values_integer_numbers (left_value, right_value))
{
*stack_top_p++ = left_value | right_value;
continue;
}
result = do_number_bitwise_logic (NUMBER_BITWISE_LOGIC_OR, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_BIT_XOR:
{
JERRY_STATIC_ASSERT (ECMA_DIRECT_TYPE_MASK == ((1 << ECMA_DIRECT_SHIFT) - 1),
direct_type_mask_must_fill_all_bits_before_the_value_starts);
if (ecma_are_values_integer_numbers (left_value, right_value))
{
*stack_top_p++ = left_value ^ right_value;
continue;
}
result = do_number_bitwise_logic (NUMBER_BITWISE_LOGIC_XOR, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_BIT_AND:
{
JERRY_STATIC_ASSERT (ECMA_DIRECT_TYPE_MASK == ((1 << ECMA_DIRECT_SHIFT) - 1),
direct_type_mask_must_fill_all_bits_before_the_value_starts);
if (ecma_are_values_integer_numbers (left_value, right_value))
{
*stack_top_p++ = left_value & right_value;
continue;
}
result = do_number_bitwise_logic (NUMBER_BITWISE_LOGIC_AND, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_LEFT_SHIFT:
{
JERRY_STATIC_ASSERT (ECMA_DIRECT_TYPE_MASK == ((1 << ECMA_DIRECT_SHIFT) - 1),
direct_type_mask_must_fill_all_bits_before_the_value_starts);
if (ecma_are_values_integer_numbers (left_value, right_value))
{
ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value);
ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value);
*stack_top_p++ = ecma_make_int32_value ((int32_t) (left_integer << (right_integer & 0x1f)));
continue;
}
result = do_number_bitwise_logic (NUMBER_BITWISE_SHIFT_LEFT, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_RIGHT_SHIFT:
{
JERRY_STATIC_ASSERT (ECMA_DIRECT_TYPE_MASK == ((1 << ECMA_DIRECT_SHIFT) - 1),
direct_type_mask_must_fill_all_bits_before_the_value_starts);
if (ecma_are_values_integer_numbers (left_value, right_value))
{
ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value);
ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value);
*stack_top_p++ = ecma_make_integer_value (left_integer >> (right_integer & 0x1f));
continue;
}
result = do_number_bitwise_logic (NUMBER_BITWISE_SHIFT_RIGHT, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_UNS_RIGHT_SHIFT:
{
JERRY_STATIC_ASSERT (ECMA_DIRECT_TYPE_MASK == ((1 << ECMA_DIRECT_SHIFT) - 1),
direct_type_mask_must_fill_all_bits_before_the_value_starts);
if (ecma_are_values_integer_numbers (left_value, right_value))
{
uint32_t left_uint32 = (uint32_t) ecma_get_integer_from_value (left_value);
ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value);
*stack_top_p++ = ecma_make_uint32_value (left_uint32 >> (right_integer & 0x1f));
continue;
}
result = do_number_bitwise_logic (NUMBER_BITWISE_SHIFT_URIGHT, left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_LESS:
{
if (ecma_are_values_integer_numbers (left_value, right_value))
{
bool is_less = (ecma_integer_value_t) left_value < (ecma_integer_value_t) right_value;
#if !JERRY_VM_HALT
/* This is a lookahead to the next opcode to improve performance.
* If it is CBC_BRANCH_IF_TRUE_BACKWARD, execute it. */
if (*byte_code_p <= CBC_BRANCH_IF_TRUE_BACKWARD_3 && *byte_code_p >= CBC_BRANCH_IF_TRUE_BACKWARD)
{
byte_code_start_p = byte_code_p++;
branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (*byte_code_start_p);
JERRY_ASSERT (branch_offset_length >= 1 && branch_offset_length <= 3);
if (is_less)
{
branch_offset = *(byte_code_p++);
if (JERRY_UNLIKELY (branch_offset_length != 1))
{
branch_offset <<= 8;
branch_offset |= *(byte_code_p++);
if (JERRY_UNLIKELY (branch_offset_length == 3))
{
branch_offset <<= 8;
branch_offset |= *(byte_code_p++);
}
}
/* Note: The opcode is a backward branch. */
byte_code_p = byte_code_start_p - branch_offset;
}
else
{
byte_code_p += branch_offset_length;
}
continue;
}
#endif /* !JERRY_VM_HALT */
*stack_top_p++ = ecma_make_boolean_value (is_less);
continue;
}
if (ecma_is_value_number (left_value) && ecma_is_value_number (right_value))
{
ecma_number_t left_number = ecma_get_number_from_value (left_value);
ecma_number_t right_number = ecma_get_number_from_value (right_value);
*stack_top_p++ = ecma_make_boolean_value (left_number < right_number);
goto free_both_values;
}
result = opfunc_relation (left_value, right_value, true, false);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_GREATER:
{
if (ecma_are_values_integer_numbers (left_value, right_value))
{
ecma_integer_value_t left_integer = (ecma_integer_value_t) left_value;
ecma_integer_value_t right_integer = (ecma_integer_value_t) right_value;
*stack_top_p++ = ecma_make_boolean_value (left_integer > right_integer);
continue;
}
if (ecma_is_value_number (left_value) && ecma_is_value_number (right_value))
{
ecma_number_t left_number = ecma_get_number_from_value (left_value);
ecma_number_t right_number = ecma_get_number_from_value (right_value);
*stack_top_p++ = ecma_make_boolean_value (left_number > right_number);
goto free_both_values;
}
result = opfunc_relation (left_value, right_value, false, false);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_LESS_EQUAL:
{
if (ecma_are_values_integer_numbers (left_value, right_value))
{
ecma_integer_value_t left_integer = (ecma_integer_value_t) left_value;
ecma_integer_value_t right_integer = (ecma_integer_value_t) right_value;
*stack_top_p++ = ecma_make_boolean_value (left_integer <= right_integer);
continue;
}
if (ecma_is_value_number (left_value) && ecma_is_value_number (right_value))
{
ecma_number_t left_number = ecma_get_number_from_value (left_value);
ecma_number_t right_number = ecma_get_number_from_value (right_value);
*stack_top_p++ = ecma_make_boolean_value (left_number <= right_number);
goto free_both_values;
}
result = opfunc_relation (left_value, right_value, false, true);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_GREATER_EQUAL:
{
if (ecma_are_values_integer_numbers (left_value, right_value))
{
ecma_integer_value_t left_integer = (ecma_integer_value_t) left_value;
ecma_integer_value_t right_integer = (ecma_integer_value_t) right_value;
*stack_top_p++ = ecma_make_boolean_value (left_integer >= right_integer);
continue;
}
if (ecma_is_value_number (left_value) && ecma_is_value_number (right_value))
{
ecma_number_t left_number = ecma_get_number_from_value (left_value);
ecma_number_t right_number = ecma_get_number_from_value (right_value);
*stack_top_p++ = ecma_make_boolean_value (left_number >= right_number);
goto free_both_values;
}
result = opfunc_relation (left_value, right_value, true, true);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_IN:
{
result = opfunc_in (left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_INSTANCEOF:
{
result = opfunc_instanceof (left_value, right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_BLOCK_CREATE_CONTEXT:
{
#if JERRY_ESNEXT
ecma_value_t *stack_context_top_p;
stack_context_top_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth;
JERRY_ASSERT (stack_context_top_p == stack_top_p || stack_context_top_p == stack_top_p - 1);
if (byte_code_start_p[0] != CBC_EXT_OPCODE)
{
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
if (stack_context_top_p != stack_top_p)
{
/* Preserve the value of switch statement. */
stack_context_top_p[1] = stack_context_top_p[0];
}
stack_context_top_p[0] = VM_CREATE_CONTEXT_WITH_ENV (VM_CONTEXT_BLOCK, branch_offset);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_BLOCK_CONTEXT_STACK_ALLOCATION;
}
else
{
JERRY_ASSERT (byte_code_start_p[1] == CBC_EXT_TRY_CREATE_ENV);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_TRY
|| VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_CATCH
|| VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP
|| VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_FINALLY_THROW
|| VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_FINALLY_RETURN);
JERRY_ASSERT (!(stack_context_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV));
stack_context_top_p[-1] |= VM_CONTEXT_HAS_LEX_ENV;
}
#else /* !JERRY_ESNEXT */
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-2]) == VM_CONTEXT_CATCH
&& !(stack_top_p[-2] & VM_CONTEXT_HAS_LEX_ENV));
stack_top_p[-2] |= VM_CONTEXT_HAS_LEX_ENV;
#endif /* JERRY_ESNEXT */
frame_ctx_p->lex_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p);
frame_ctx_p->lex_env_p->type_flags_refs |= ECMA_OBJECT_FLAG_BLOCK;
continue;
}
case VM_OC_WITH:
{
ecma_value_t value = *(--stack_top_p);
ecma_object_t *object_p;
ecma_object_t *with_env_p;
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
result = ecma_op_to_object (value);
ecma_free_value (value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
object_p = ecma_get_object_from_value (result);
with_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p, object_p);
ecma_deref_object (object_p);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_WITH_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT_WITH_ENV (VM_CONTEXT_WITH, branch_offset);
with_env_p->type_flags_refs |= ECMA_OBJECT_FLAG_BLOCK;
frame_ctx_p->lex_env_p = with_env_p;
continue;
}
case VM_OC_FOR_IN_INIT:
{
ecma_value_t value = *(--stack_top_p);
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
ecma_value_t expr_obj_value = ECMA_VALUE_UNDEFINED;
ecma_collection_t *prop_names_p = opfunc_for_in (value, &expr_obj_value);
ecma_free_value (value);
if (prop_names_p == NULL)
{
#if JERRY_ESNEXT
if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (expr_obj_value)))
{
result = expr_obj_value;
goto error;
}
#endif /* JERRY_ESNEXT */
/* The collection is already released */
byte_code_p = byte_code_start_p + branch_offset;
continue;
}
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FOR_IN, branch_offset);
ECMA_SET_INTERNAL_VALUE_ANY_POINTER (stack_top_p[-2], prop_names_p);
stack_top_p[-3] = 0;
stack_top_p[-4] = expr_obj_value;
#if JERRY_ESNEXT
if (byte_code_p[0] == CBC_EXT_OPCODE && byte_code_p[1] == CBC_EXT_CLONE_CONTEXT)
{
/* No need to duplicate the first context. */
byte_code_p += 2;
}
#endif /* JERRY_ESNEXT */
continue;
}
case VM_OC_FOR_IN_GET_NEXT:
{
ecma_value_t *context_top_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth;
ecma_collection_t *collection_p;
collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, context_top_p[-2]);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (context_top_p[-1]) == VM_CONTEXT_FOR_IN);
uint32_t index = context_top_p[-3];
ecma_value_t *buffer_p = collection_p->buffer_p;
*stack_top_p++ = buffer_p[index];
context_top_p[-3]++;
continue;
}
case VM_OC_FOR_IN_HAS_NEXT:
{
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
ecma_collection_t *collection_p;
collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, stack_top_p[-2]);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FOR_IN);
ecma_value_t *buffer_p = collection_p->buffer_p;
ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[-4]);
uint32_t index = stack_top_p[-3];
while (index < collection_p->item_count)
{
ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (buffer_p[index]);
result = ecma_op_object_has_property (object_p, prop_name_p);
if (ECMA_IS_VALUE_ERROR (result))
{
stack_top_p[-3] = index;
goto error;
}
if (JERRY_LIKELY (ecma_is_value_true (result)))
{
byte_code_p = byte_code_start_p + branch_offset;
break;
}
ecma_deref_ecma_string (prop_name_p);
index++;
}
if (index == collection_p->item_count)
{
ecma_deref_object (object_p);
ecma_collection_destroy (collection_p);
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION);
stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION;
}
else
{
stack_top_p[-3] = index;
}
continue;
}
#if JERRY_ESNEXT
case VM_OC_FOR_OF_INIT:
{
ecma_value_t value = *(--stack_top_p);
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
ecma_value_t next_method;
ecma_value_t iterator = ecma_op_get_iterator (value, ECMA_VALUE_SYNC_ITERATOR, &next_method);
ecma_free_value (value);
if (ECMA_IS_VALUE_ERROR (iterator))
{
result = iterator;
goto error;
}
result = ecma_op_iterator_step (iterator, next_method);
if (ECMA_IS_VALUE_ERROR (result))
{
ecma_free_value (iterator);
ecma_free_value (next_method);
goto error;
}
if (ecma_is_value_false (result))
{
ecma_free_value (iterator);
ecma_free_value (next_method);
byte_code_p = byte_code_start_p + branch_offset;
continue;
}
ecma_value_t next_value = ecma_op_iterator_value (result);
ecma_free_value (result);
if (ECMA_IS_VALUE_ERROR (next_value))
{
result = next_value;
ecma_free_value (iterator);
ecma_free_value (next_method);
goto error;
}
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FOR_OF, branch_offset) | VM_CONTEXT_CLOSE_ITERATOR;
stack_top_p[-2] = next_value;
stack_top_p[-3] = iterator;
stack_top_p[-4] = next_method;
if (byte_code_p[0] == CBC_EXT_OPCODE && byte_code_p[1] == CBC_EXT_CLONE_CONTEXT)
{
/* No need to duplicate the first context. */
byte_code_p += 2;
}
continue;
}
case VM_OC_FOR_OF_GET_NEXT:
{
ecma_value_t *context_top_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth;
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (context_top_p[-1]) == VM_CONTEXT_FOR_OF
|| VM_GET_CONTEXT_TYPE (context_top_p[-1]) == VM_CONTEXT_FOR_AWAIT_OF);
JERRY_ASSERT (context_top_p[-1] & VM_CONTEXT_CLOSE_ITERATOR);
*stack_top_p++ = context_top_p[-2];
context_top_p[-2] = ECMA_VALUE_UNDEFINED;
continue;
}
case VM_OC_FOR_OF_HAS_NEXT:
{
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FOR_OF);
JERRY_ASSERT (stack_top_p[-1] & VM_CONTEXT_CLOSE_ITERATOR);
stack_top_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
result = ecma_op_iterator_step (stack_top_p[-3], stack_top_p[-4]);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
if (ecma_is_value_false (result))
{
ecma_free_value (stack_top_p[-2]);
ecma_free_value (stack_top_p[-3]);
ecma_free_value (stack_top_p[-4]);
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
stack_top_p -= PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION;
continue;
}
ecma_value_t next_value = ecma_op_iterator_value (result);
ecma_free_value (result);
if (ECMA_IS_VALUE_ERROR (next_value))
{
result = next_value;
goto error;
}
JERRY_ASSERT (stack_top_p[-2] == ECMA_VALUE_UNDEFINED);
stack_top_p[-1] |= VM_CONTEXT_CLOSE_ITERATOR;
stack_top_p[-2] = next_value;
byte_code_p = byte_code_start_p + branch_offset;
continue;
}
case VM_OC_FOR_AWAIT_OF_INIT:
{
ecma_value_t value = *(--stack_top_p);
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
ecma_value_t next_method;
result = ecma_op_get_iterator (value, ECMA_VALUE_ASYNC_ITERATOR, &next_method);
ecma_free_value (value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_value_t iterator = result;
result = ecma_op_iterator_next (result, next_method, ECMA_VALUE_EMPTY);
if (ECMA_IS_VALUE_ERROR (result))
{
ecma_free_value (iterator);
ecma_free_value (next_method);
goto error;
}
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_AWAIT_OF_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_FOR_AWAIT_OF_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FOR_AWAIT_OF, branch_offset);
stack_top_p[-2] = ECMA_VALUE_UNDEFINED;
stack_top_p[-3] = iterator;
stack_top_p[-4] = next_method;
if (byte_code_p[0] == CBC_EXT_OPCODE && byte_code_p[1] == CBC_EXT_CLONE_CONTEXT)
{
/* No need to duplicate the first context. */
byte_code_p += 2;
}
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = stack_top_p;
uint16_t extra_flags =
(ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD | (ECMA_AWAIT_FOR_NEXT << ECMA_AWAIT_STATE_SHIFT));
if (CBC_FUNCTION_GET_TYPE (bytecode_header_p->status_flags) == CBC_FUNCTION_ASYNC_GENERATOR
|| (frame_ctx_p->shared_p->status_flags & VM_FRAME_CTX_SHARED_EXECUTABLE))
{
ecma_extended_object_t *executable_object_p = VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
result = ecma_promise_async_await (executable_object_p, result);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
executable_object_p->u.cls.u2.executable_obj_flags |= extra_flags;
return ECMA_VALUE_UNDEFINED;
}
result = opfunc_async_create_and_await (frame_ctx_p, result, extra_flags);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
return result;
}
case VM_OC_FOR_AWAIT_OF_HAS_NEXT:
{
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FOR_AWAIT_OF);
JERRY_ASSERT (stack_top_p[-1] & VM_CONTEXT_CLOSE_ITERATOR);
stack_top_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
result = ecma_op_iterator_next (stack_top_p[-3], stack_top_p[-4], ECMA_VALUE_EMPTY);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_extended_object_t *executable_object_p = VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
result = ecma_promise_async_await (executable_object_p, result);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
uint16_t extra_flags =
(ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD | (ECMA_AWAIT_FOR_NEXT << ECMA_AWAIT_STATE_SHIFT));
executable_object_p->u.cls.u2.executable_obj_flags |= extra_flags;
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_start_p + branch_offset;
frame_ctx_p->stack_top_p = stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
#endif /* JERRY_ESNEXT */
case VM_OC_TRY:
{
/* Try opcode simply creates the try context. */
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_TRY_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_TRY, branch_offset);
continue;
}
case VM_OC_CATCH:
{
/* Catches are ignored and turned to jumps. */
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_TRY);
byte_code_p = byte_code_start_p + branch_offset;
continue;
}
case VM_OC_FINALLY:
{
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_TRY
|| VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH);
if (stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV)
{
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
ecma_deref_object (lex_env_p);
}
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FINALLY_CONTEXT_EXTRA_STACK_ALLOCATION);
stack_top_p += PARSER_FINALLY_CONTEXT_EXTRA_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FINALLY_JUMP, branch_offset);
stack_top_p[-2] = (ecma_value_t) branch_offset;
continue;
}
case VM_OC_CONTEXT_END:
{
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
JERRY_ASSERT (!(stack_top_p[-1] & VM_CONTEXT_CLOSE_ITERATOR));
ecma_value_t context_type = VM_GET_CONTEXT_TYPE (stack_top_p[-1]);
if (!VM_CONTEXT_IS_FINALLY (context_type))
{
stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p);
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
continue;
}
#if JERRY_ESNEXT
if (stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV)
{
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
ecma_deref_object (lex_env_p);
}
#endif /* JERRY_ESNEXT */
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FINALLY_CONTEXT_STACK_ALLOCATION);
stack_top_p -= PARSER_FINALLY_CONTEXT_STACK_ALLOCATION;
if (context_type == VM_CONTEXT_FINALLY_RETURN)
{
result = *stack_top_p;
goto error;
}
if (context_type == VM_CONTEXT_FINALLY_THROW)
{
jcontext_raise_exception (*stack_top_p);
#if JERRY_VM_THROW
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_ERROR_THROWN;
#endif /* JERRY_VM_THROW */
result = ECMA_VALUE_ERROR;
#if JERRY_DEBUGGER
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
#endif /* JERRY_DEBUGGER */
goto error;
}
JERRY_ASSERT (context_type == VM_CONTEXT_FINALLY_JUMP);
uint32_t jump_target = *stack_top_p;
vm_stack_found_type type =
vm_stack_find_finally (frame_ctx_p, stack_top_p, VM_CONTEXT_FINALLY_JUMP, jump_target);
stack_top_p = frame_ctx_p->stack_top_p;
switch (type)
{
case VM_CONTEXT_FOUND_FINALLY:
{
byte_code_p = frame_ctx_p->byte_code_p;
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP);
stack_top_p[-2] = jump_target;
break;
}
#if JERRY_ESNEXT
case VM_CONTEXT_FOUND_ERROR:
{
JERRY_ASSERT (jcontext_has_pending_exception ());
result = ECMA_VALUE_ERROR;
goto error;
}
case VM_CONTEXT_FOUND_AWAIT:
{
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP);
stack_top_p[-2] = jump_target;
return ECMA_VALUE_UNDEFINED;
}
#endif /* JERRY_ESNEXT */
default:
{
byte_code_p = frame_ctx_p->byte_code_start_p + jump_target;
break;
}
}
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
continue;
}
case VM_OC_JUMP_AND_EXIT_CONTEXT:
{
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
JERRY_ASSERT (!jcontext_has_pending_exception ());
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
vm_stack_found_type type =
vm_stack_find_finally (frame_ctx_p, stack_top_p, VM_CONTEXT_FINALLY_JUMP, (uint32_t) branch_offset);
stack_top_p = frame_ctx_p->stack_top_p;
switch (type)
{
case VM_CONTEXT_FOUND_FINALLY:
{
byte_code_p = frame_ctx_p->byte_code_p;
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP);
stack_top_p[-2] = (uint32_t) branch_offset;
break;
}
#if JERRY_ESNEXT
case VM_CONTEXT_FOUND_ERROR:
{
JERRY_ASSERT (jcontext_has_pending_exception ());
result = ECMA_VALUE_ERROR;
goto error;
}
case VM_CONTEXT_FOUND_AWAIT:
{
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP);
stack_top_p[-2] = (uint32_t) branch_offset;
return ECMA_VALUE_UNDEFINED;
}
#endif /* JERRY_ESNEXT */
default:
{
byte_code_p = frame_ctx_p->byte_code_start_p + branch_offset;
break;
}
}
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
continue;
}
#if JERRY_MODULE_SYSTEM
case VM_OC_MODULE_IMPORT:
{
left_value = *(--stack_top_p);
ecma_value_t user_value = ECMA_VALUE_UNDEFINED;
ecma_value_t script_value = ((cbc_uint8_arguments_t *) bytecode_header_p)->script_value;
#if JERRY_SNAPSHOT_EXEC
if (JERRY_UNLIKELY (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)))
{
#endif /* JERRY_SNAPSHOT_EXEC */
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)
{
user_value = CBC_SCRIPT_GET_USER_VALUE (script_p);
}
#if JERRY_SNAPSHOT_EXEC
}
#endif /* JERRY_SNAPSHOT_EXEC */
result = ecma_module_import (left_value, user_value);
ecma_free_value (left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
continue;
}
case VM_OC_MODULE_IMPORT_META:
{
ecma_value_t script_value = ((cbc_uint8_arguments_t *) bytecode_header_p)->script_value;
cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
JERRY_ASSERT (script_p->refs_and_type & CBC_SCRIPT_HAS_IMPORT_META);
ecma_value_t import_meta = CBC_SCRIPT_GET_IMPORT_META (script_p, script_p->refs_and_type);
ecma_object_t *import_meta_object_p = ecma_get_object_from_value (import_meta);
if (ecma_get_object_type (import_meta_object_p) != ECMA_OBJECT_TYPE_GENERAL)
{
JERRY_ASSERT (ecma_object_class_is (import_meta_object_p, ECMA_OBJECT_CLASS_MODULE));
ecma_value_t module = import_meta;
import_meta_object_p = ecma_create_object (NULL, 0, ECMA_OBJECT_TYPE_GENERAL);
import_meta = ecma_make_object_value (import_meta_object_p);
if (JERRY_CONTEXT (module_import_meta_callback_p) != NULL)
{
void *user_p = JERRY_CONTEXT (module_import_meta_callback_user_p);
JERRY_CONTEXT (module_import_meta_callback_p) (module, import_meta, user_p);
}
CBC_SCRIPT_GET_IMPORT_META (script_p, script_p->refs_and_type) = import_meta;
}
else
{
ecma_ref_object (import_meta_object_p);
}
*stack_top_p++ = import_meta;
continue;
}
#endif /* JERRY_MODULE_SYSTEM */
#if JERRY_DEBUGGER
case VM_OC_BREAKPOINT_ENABLED:
{
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE)
{
continue;
}
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
JERRY_ASSERT (!(frame_ctx_p->shared_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE));
frame_ctx_p->byte_code_p = byte_code_start_p;
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT);
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_EXCEPTION_THROWN)
{
result = ECMA_VALUE_ERROR;
goto error;
}
continue;
}
case VM_OC_BREAKPOINT_DISABLED:
{
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE)
{
continue;
}
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
JERRY_ASSERT (!(frame_ctx_p->shared_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE));
frame_ctx_p->byte_code_p = byte_code_start_p;
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_STOP)
&& (JERRY_CONTEXT (debugger_stop_context) == NULL
|| JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p)))
{
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT);
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_EXCEPTION_THROWN)
{
result = ECMA_VALUE_ERROR;
goto error;
}
continue;
}
if (JERRY_CONTEXT (debugger_message_delay) > 0)
{
JERRY_CONTEXT (debugger_message_delay)--;
continue;
}
JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY;
if (jerry_debugger_receive (NULL))
{
continue;
}
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_STOP)
&& (JERRY_CONTEXT (debugger_stop_context) == NULL
|| JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p)))
{
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT);
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_EXCEPTION_THROWN)
{
result = ECMA_VALUE_ERROR;
goto error;
}
}
continue;
}
#endif /* JERRY_DEBUGGER */
case VM_OC_NONE:
default:
{
JERRY_ASSERT (VM_OC_GROUP_GET_INDEX (opcode_data) == VM_OC_NONE);
jerry_fatal (ERR_DISABLED_BYTE_CODE);
}
}
JERRY_ASSERT (VM_OC_HAS_PUT_RESULT (opcode_data));
if (opcode_data & VM_OC_PUT_IDENT)
{
uint16_t literal_index;
READ_LITERAL_INDEX (literal_index);
if (literal_index < register_end)
{
ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, literal_index));
VM_GET_REGISTER (frame_ctx_p, literal_index) = result;
if (opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))
{
result = ecma_fast_copy_value (result);
}
}
else
{
ecma_string_t *var_name_str_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_value_t put_value_result =
ecma_op_put_value_lex_env_base (frame_ctx_p->lex_env_p, var_name_str_p, is_strict, result);
if (ECMA_IS_VALUE_ERROR (put_value_result))
{
ecma_free_value (result);
result = put_value_result;
goto error;
}
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{
ecma_fast_free_value (result);
}
}
}
else if (opcode_data & VM_OC_PUT_REFERENCE)
{
ecma_value_t property = *(--stack_top_p);
ecma_value_t base = *(--stack_top_p);
if (base == ECMA_VALUE_REGISTER_REF)
{
property = (ecma_value_t) ecma_get_integer_from_value (property);
ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, property));
VM_GET_REGISTER (frame_ctx_p, property) = result;
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{
goto free_both_values;
}
result = ecma_fast_copy_value (result);
}
else
{
ecma_value_t set_value_result = vm_op_set_value (base, property, result, is_strict);
if (ECMA_IS_VALUE_ERROR (set_value_result))
{
ecma_free_value (result);
result = set_value_result;
goto error;
}
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{
ecma_fast_free_value (result);
goto free_both_values;
}
}
}
if (opcode_data & VM_OC_PUT_STACK)
{
*stack_top_p++ = result;
}
else if (opcode_data & VM_OC_PUT_BLOCK)
{
ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, 0));
VM_GET_REGISTERS (frame_ctx_p)[0] = result;
}
free_both_values:
ecma_fast_free_value (right_value);
free_left_value:
ecma_fast_free_value (left_value);
}
error:
ecma_fast_free_value (left_value);
ecma_fast_free_value (right_value);
if (ECMA_IS_VALUE_ERROR (result))
{
JERRY_ASSERT (jcontext_has_pending_exception ());
ecma_value_t *stack_bottom_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth;
while (stack_top_p > stack_bottom_p)
{
ecma_value_t stack_item = *(--stack_top_p);
#if JERRY_ESNEXT
if (stack_item == ECMA_VALUE_RELEASE_LEX_ENV)
{
opfunc_pop_lexical_environment (frame_ctx_p);
continue;
}
#endif /* JERRY_ESNEXT */
ecma_fast_free_value (stack_item);
}
#if JERRY_VM_THROW
if (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_ERROR_THROWN))
{
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_ERROR_THROWN;
jerry_throw_cb_t vm_throw_callback_p = JERRY_CONTEXT (vm_throw_callback_p);
if (vm_throw_callback_p != NULL)
{
vm_throw_callback_p (JERRY_CONTEXT (error_value), JERRY_CONTEXT (vm_throw_callback_user_p));
}
}
#endif /* JERRY_VM_THROW */
#if JERRY_DEBUGGER
const uint32_t dont_stop =
(JERRY_DEBUGGER_VM_IGNORE_EXCEPTION | JERRY_DEBUGGER_VM_IGNORE | JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& !(frame_ctx_p->shared_p->bytecode_header_p->status_flags
& (CBC_CODE_FLAGS_DEBUGGER_IGNORE | CBC_CODE_FLAGS_STATIC_FUNCTION))
&& !(JERRY_CONTEXT (debugger_flags) & dont_stop))
{
/* Save the error to a local value, because the engine enters breakpoint mode after,
therefore an evaluation error, or user-created error throw would overwrite it. */
ecma_value_t current_error_value = JERRY_CONTEXT (error_value);
if (jerry_debugger_send_exception_string (current_error_value))
{
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_EXCEPTION_HIT);
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_EXCEPTION_THROWN)
{
ecma_free_value (current_error_value);
}
else
{
JERRY_CONTEXT (error_value) = current_error_value;
}
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
}
}
#endif /* JERRY_DEBUGGER */
}
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
if (frame_ctx_p->context_depth == 0)
{
/* In most cases there is no context. */
frame_ctx_p->call_operation = VM_NO_EXEC_OP;
return result;
}
if (!ECMA_IS_VALUE_ERROR (result))
{
switch (vm_stack_find_finally (frame_ctx_p, stack_top_p, VM_CONTEXT_FINALLY_RETURN, 0))
{
case VM_CONTEXT_FOUND_FINALLY:
{
stack_top_p = frame_ctx_p->stack_top_p;
byte_code_p = frame_ctx_p->byte_code_p;
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_RETURN);
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
stack_top_p[-2] = result;
continue;
}
#if JERRY_ESNEXT
case VM_CONTEXT_FOUND_ERROR:
{
JERRY_ASSERT (jcontext_has_pending_exception ());
ecma_free_value (result);
stack_top_p = frame_ctx_p->stack_top_p;
result = ECMA_VALUE_ERROR;
break;
}
case VM_CONTEXT_FOUND_AWAIT:
{
stack_top_p = frame_ctx_p->stack_top_p;
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_RETURN);
stack_top_p[-2] = result;
return ECMA_VALUE_UNDEFINED;
}
#endif /* JERRY_ESNEXT */
default:
{
goto finish;
}
}
}
JERRY_ASSERT (jcontext_has_pending_exception ());
if (!jcontext_has_pending_abort ())
{
switch (vm_stack_find_finally (frame_ctx_p, stack_top_p, VM_CONTEXT_FINALLY_THROW, 0))
{
case VM_CONTEXT_FOUND_FINALLY:
{
stack_top_p = frame_ctx_p->stack_top_p;
byte_code_p = frame_ctx_p->byte_code_p;
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
JERRY_ASSERT (!(stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV));
#if JERRY_DEBUGGER
JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
#endif /* JERRY_DEBUGGER */
result = jcontext_take_exception ();
if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_THROW)
{
stack_top_p[-2] = result;
continue;
}
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH);
*stack_top_p++ = result;
continue;
}
#if JERRY_ESNEXT
case VM_CONTEXT_FOUND_AWAIT:
{
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (frame_ctx_p->stack_top_p[-1]) == VM_CONTEXT_FINALLY_THROW);
return ECMA_VALUE_UNDEFINED;
}
#endif /* JERRY_ESNEXT */
default:
{
break;
}
}
}
else
{
do
{
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p);
} while (frame_ctx_p->context_depth > 0);
}
finish:
frame_ctx_p->call_operation = VM_NO_EXEC_OP;
return result;
}
} /* vm_loop */
#if JERRY_MODULE_SYSTEM
/**
* Create and initialize module scope with all data properties
*
* @return ECMA_VALUE_EMPTY on success,
* ECMA_VALUE_ERROR on failure
*/
ecma_value_t
vm_init_module_scope (ecma_module_t *module_p) /**< module without scope */
{
ecma_object_t *global_object_p;
#if JERRY_BUILTIN_REALMS
global_object_p = (ecma_object_t *) ecma_op_function_get_realm (module_p->u.compiled_code_p);
#else /* !JERRY_BUILTIN_REALMS */
global_object_p = ecma_builtin_get_global ();
#endif /* JERRY_BUILTIN_REALMS */
ecma_object_t *scope_p = ecma_create_lex_env_class (ecma_get_global_environment (global_object_p),
sizeof (ecma_lexical_environment_class_t));
const ecma_compiled_code_t *compiled_code_p = module_p->u.compiled_code_p;
ecma_value_t *literal_start_p;
uint8_t *byte_code_p;
uint16_t encoding_limit;
uint16_t encoding_delta;
((ecma_lexical_environment_class_t *) scope_p)->object_p = (ecma_object_t *) module_p;
((ecma_lexical_environment_class_t *) scope_p)->type = ECMA_LEX_ENV_CLASS_TYPE_MODULE;
module_p->scope_p = scope_p;
ecma_deref_object (scope_p);
if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) compiled_code_p;
literal_start_p = (ecma_value_t *) (args_p + 1);
literal_start_p -= args_p->register_end;
byte_code_p = (uint8_t *) (literal_start_p + args_p->literal_end);
}
else
{
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) compiled_code_p;
literal_start_p = (ecma_value_t *) (args_p + 1);
literal_start_p -= args_p->register_end;
byte_code_p = (uint8_t *) (literal_start_p + args_p->literal_end);
}
/* Prepare for byte code execution. */
if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FULL_LITERAL_ENCODING))
{
encoding_limit = CBC_SMALL_LITERAL_ENCODING_LIMIT;
encoding_delta = CBC_SMALL_LITERAL_ENCODING_DELTA;
}
else
{
encoding_limit = CBC_FULL_LITERAL_ENCODING_LIMIT;
encoding_delta = CBC_FULL_LITERAL_ENCODING_DELTA;
}
JERRY_ASSERT (*byte_code_p >= CBC_JUMP_FORWARD && *byte_code_p <= CBC_JUMP_FORWARD_3);
byte_code_p += 1 + CBC_BRANCH_OFFSET_LENGTH (*byte_code_p);
while (true)
{
uint8_t opcode = *byte_code_p++;
switch (opcode)
{
case CBC_CREATE_VAR:
case CBC_CREATE_LET:
case CBC_CREATE_CONST:
{
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
JERRY_ASSERT (ecma_find_named_property (scope_p, name_p) == NULL);
uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE;
if (opcode == CBC_CREATE_LET)
{
prop_attributes = ECMA_PROPERTY_ENUMERABLE_WRITABLE;
}
else if (opcode == CBC_CREATE_CONST)
{
prop_attributes = ECMA_PROPERTY_FLAG_ENUMERABLE;
}
ecma_property_value_t *property_value_p;
property_value_p = ecma_create_named_data_property (scope_p, name_p, prop_attributes, NULL);
if (opcode != CBC_CREATE_VAR)
{
property_value_p->value = ECMA_VALUE_UNINITIALIZED;
}
break;
}
case CBC_INIT_ARG_OR_FUNC:
{
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
ecma_compiled_code_t *function_bytecode_p;
#if JERRY_SNAPSHOT_EXEC
if (JERRY_LIKELY (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)))
{
#endif /* JERRY_SNAPSHOT_EXEC */
function_bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, literal_start_p[literal_index]);
#if JERRY_SNAPSHOT_EXEC
}
else
{
uint8_t *byte_p = ((uint8_t *) compiled_code_p) + literal_start_p[literal_index];
function_bytecode_p = (ecma_compiled_code_t *) byte_p;
}
#endif /* JERRY_SNAPSHOT_EXEC */
JERRY_ASSERT (CBC_IS_FUNCTION (function_bytecode_p->status_flags));
ecma_object_t *function_obj_p;
if (JERRY_UNLIKELY (CBC_FUNCTION_IS_ARROW (function_bytecode_p->status_flags)))
{
function_obj_p = ecma_op_create_arrow_function_object (scope_p, function_bytecode_p, ECMA_VALUE_UNDEFINED);
}
else
{
function_obj_p = ecma_op_create_any_function_object (scope_p, function_bytecode_p);
}
READ_LITERAL_INDEX (literal_index);
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
JERRY_ASSERT (ecma_find_named_property (scope_p, name_p) == NULL);
ecma_property_value_t *property_value_p;
property_value_p = ecma_create_named_data_property (scope_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL);
JERRY_ASSERT (property_value_p->value == ECMA_VALUE_UNDEFINED);
property_value_p->value = ecma_make_object_value (function_obj_p);
ecma_deref_object (function_obj_p);
break;
}
default:
{
JERRY_ASSERT (opcode == CBC_RETURN_FUNCTION_END);
return ECMA_VALUE_EMPTY;
}
}
}
} /* vm_init_module_scope */
#endif /* JERRY_MODULE_SYSTEM */
#undef READ_LITERAL
#undef READ_LITERAL_INDEX
JERRY_STATIC_ASSERT ((int) VM_FRAME_CTX_SHARED_DIRECT_EVAL == (int) VM_FRAME_CTX_DIRECT_EVAL,
vm_frame_ctx_shared_direct_eval_must_be_equal_to_frame_ctx_direct_eval);
JERRY_STATIC_ASSERT ((int) CBC_CODE_FLAGS_STRICT_MODE == (int) VM_FRAME_CTX_IS_STRICT,
cbc_code_flags_strict_mode_must_be_equal_to_vm_frame_ctx_is_strict);
/**
* Initialize code block execution
*
* @return ECMA_VALUE_ERROR - if the initialization fails
* ECMA_VALUE_EMPTY - otherwise
*/
static void JERRY_ATTR_NOINLINE
vm_init_exec (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
vm_frame_ctx_shared_t *shared_p = frame_ctx_p->shared_p;
const ecma_compiled_code_t *bytecode_header_p = shared_p->bytecode_header_p;
frame_ctx_p->prev_context_p = JERRY_CONTEXT (vm_top_context_p);
frame_ctx_p->context_depth = 0;
frame_ctx_p->status_flags = (uint8_t) ((shared_p->status_flags & VM_FRAME_CTX_DIRECT_EVAL)
| (bytecode_header_p->status_flags & VM_FRAME_CTX_IS_STRICT));
uint16_t argument_end, register_end;
ecma_value_t *literal_p;
if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p;
argument_end = args_p->argument_end;
register_end = args_p->register_end;
literal_p = (ecma_value_t *) (args_p + 1);
literal_p -= register_end;
frame_ctx_p->literal_start_p = literal_p;
literal_p += args_p->literal_end;
}
else
{
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p;
argument_end = args_p->argument_end;
register_end = args_p->register_end;
literal_p = (ecma_value_t *) (args_p + 1);
literal_p -= register_end;
frame_ctx_p->literal_start_p = literal_p;
literal_p += args_p->literal_end;
}
frame_ctx_p->byte_code_p = (uint8_t *) literal_p;
frame_ctx_p->byte_code_start_p = (uint8_t *) literal_p;
frame_ctx_p->stack_top_p = VM_GET_REGISTERS (frame_ctx_p) + register_end;
uint32_t arg_list_len = 0;
if (argument_end > 0)
{
JERRY_ASSERT (shared_p->status_flags & VM_FRAME_CTX_SHARED_HAS_ARG_LIST);
const ecma_value_t *arg_list_p = ((vm_frame_ctx_shared_args_t *) shared_p)->arg_list_p;
arg_list_len = ((vm_frame_ctx_shared_args_t *) shared_p)->arg_list_len;
if (arg_list_len > argument_end)
{
arg_list_len = argument_end;
}
for (uint32_t i = 0; i < arg_list_len; i++)
{
VM_GET_REGISTER (frame_ctx_p, i) = ecma_fast_copy_value (arg_list_p[i]);
}
}
/* The arg_list_len contains the end of the copied arguments.
* Fill everything else with undefined. */
if (register_end > arg_list_len)
{
ecma_value_t *stack_p = VM_GET_REGISTERS (frame_ctx_p) + arg_list_len;
for (uint32_t i = arg_list_len; i < register_end; i++)
{
*stack_p++ = ECMA_VALUE_UNDEFINED;
}
}
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL;
JERRY_CONTEXT (vm_top_context_p) = frame_ctx_p;
} /* vm_init_exec */
/**
* Resume execution of a code block.
*
* @return ecma value
*/
ecma_value_t JERRY_ATTR_NOINLINE
vm_execute (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
while (true)
{
ecma_value_t completion_value = vm_loop (frame_ctx_p);
switch (frame_ctx_p->call_operation)
{
case VM_EXEC_CALL:
{
opfunc_call (frame_ctx_p);
break;
}
#if JERRY_ESNEXT
case VM_EXEC_SUPER_CALL:
{
vm_super_call (frame_ctx_p);
break;
}
case VM_EXEC_SPREAD_OP:
{
vm_spread_operation (frame_ctx_p);
break;
}
case VM_EXEC_RETURN:
{
return completion_value;
}
#endif /* JERRY_ESNEXT */
case VM_EXEC_CONSTRUCT:
{
opfunc_construct (frame_ctx_p);
break;
}
default:
{
JERRY_ASSERT (frame_ctx_p->call_operation == VM_NO_EXEC_OP);
const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->shared_p->bytecode_header_p;
uint32_t register_end;
if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
register_end = ((cbc_uint16_arguments_t *) bytecode_header_p)->register_end;
}
else
{
register_end = ((cbc_uint8_arguments_t *) bytecode_header_p)->register_end;
}
/* Free arguments and registers */
ecma_value_t *registers_p = VM_GET_REGISTERS (frame_ctx_p);
for (uint32_t i = 0; i < register_end; i++)
{
ecma_fast_free_value (registers_p[i]);
}
#if JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p))
{
/* The engine will stop when the next breakpoint is reached. */
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_STOP);
JERRY_CONTEXT (debugger_stop_context) = NULL;
}
#endif /* JERRY_DEBUGGER */
JERRY_CONTEXT (vm_top_context_p) = frame_ctx_p->prev_context_p;
return completion_value;
}
}
}
} /* vm_execute */
/**
* Run the code.
*
* @return ecma value
*/
ecma_value_t
vm_run (vm_frame_ctx_shared_t *shared_p, /**< shared data */
ecma_value_t this_binding_value, /**< value of 'ThisBinding' */
ecma_object_t *lex_env_p) /**< lexical environment to use */
{
const ecma_compiled_code_t *bytecode_header_p = shared_p->bytecode_header_p;
vm_frame_ctx_t *frame_ctx_p;
size_t frame_size;
if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p;
frame_size = (size_t) (args_p->register_end + args_p->stack_limit);
}
else
{
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p;
frame_size = (size_t) (args_p->register_end + args_p->stack_limit);
}
JERRY_VLA (ecma_value_t, stack, frame_size + (sizeof (vm_frame_ctx_t) / sizeof (ecma_value_t)));
frame_ctx_p = (vm_frame_ctx_t *) stack;
frame_ctx_p->shared_p = shared_p;
frame_ctx_p->lex_env_p = lex_env_p;
frame_ctx_p->this_binding = this_binding_value;
vm_init_exec (frame_ctx_p);
return vm_execute (frame_ctx_p);
} /* vm_run */
/**
* @}
* @}
*/