/* 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 "common.h" #include "ecma-alloc.h" #include "ecma-arguments-object.h" #include "ecma-array-object.h" #include "ecma-bigint.h" #include "ecma-builtins.h" #include "ecma-builtin-object.h" #include "ecma-comparison.h" #include "ecma-conversion.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.h" #include "ecma-objects-general.h" #include "ecma-promise-object.h" #include "ecma-regexp-object.h" #include "jcontext.h" #include "opcodes.h" #include "vm.h" #include "vm-stack.h" /** \addtogroup vm Virtual machine * @{ * * \addtogroup vm_executor Executor * @{ */ /** * 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 (ECMA_ERROR_TYPE, "Cannot read property '%' of %", property, object); #else /* !JERRY_ERROR_MESSAGES */ ecma_value_t error_value = ecma_raise_type_error (NULL); #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 (ECMA_ERROR_TYPE, "Cannot set property '%' of %", property, base); #else /* !JERRY_ERROR_MESSAGES */ result = ecma_raise_type_error (NULL); #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 #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->compiled_code_p; shared.status_flags = 0; return vm_run (&shared, ECMA_VALUE_UNDEFINED, module_p->scope_p); } /* vm_run_module */ #endif /* JERRY_MODULE_SYSTEM */ /** * 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 */ { #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.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_MSG ("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.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 */ /** * 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 VM_FRAME_CTX_GET_FUNCTION_OBJECT (frame_ctx_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_MSG ("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_MSG ("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_value_t current_function = ecma_make_object_value (vm_get_class_function (frame_ctx_p)); ecma_value_t fields_value = opfunc_init_class_fields (current_function, 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 { ecma_op_bind_this_value (environment_record_p, completion_value); frame_ctx_p->this_binding = completion_value; 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 (frame_ctx_p->block_result); frame_ctx_p->block_result = 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) { const char *constructor_message_p = ecma_check_constructor (func_value); if (constructor_message_p != ECMA_IS_VALID_CONSTRUCTOR) { completion_value = ecma_raise_type_error (constructor_message_p); } 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_MSG ("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 (frame_ctx_p->block_result); frame_ctx_p->block_result = 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; 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_MSG ("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, 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 (frame_ctx_p->block_result); frame_ctx_p->block_result = 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; const char *constructor_message_p = ecma_check_constructor (constructor_value); if (constructor_message_p != ECMA_IS_VALID_CONSTRUCTOR) { completion_value = ecma_raise_type_error (constructor_message_p); } 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 (frame_ctx_p->block_result); \ frame_ctx_p->block_result = (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_EXEC_STOP 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_error_reference (result)) { ecma_raise_error_from_error_reference (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_EXEC_STOP */ 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 (frame_ctx_p->block_result); frame_ctx_p->block_result = *(--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; READ_LITERAL_INDEX (value_index); READ_LITERAL_INDEX (literal_index); JERRY_ASSERT (value_index != literal_index); JERRY_ASSERT (value_index >= register_end || literal_index >= register_end); 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]); } 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) = 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 (value_index >= register_end) { ecma_free_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_MSG ("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_MSG ("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_MSG ("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_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)); 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_MSG ("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; 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_MSG ("Prototype property of a 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_MSG ("Prototype property of a 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); 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 *object_p = ecma_get_object_from_value (stack_top_p[-2]); ecma_property_value_t *property_value_p = ecma_create_named_data_property (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 (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 (ecma_make_object_value (VM_FRAME_CTX_GET_FUNCTION_OBJECT (frame_ctx_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); stack_top_p++; 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)); result = stack_top_p[-2]; stack_top_p[-1] = ecma_copy_value (computed_class_fields_p[next_index]); stack_top_p[-2] = ecma_copy_value (frame_ctx_p->this_binding); break; } 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_object_lex_env (frame_ctx_p->lex_env_p, ecma_get_object_from_value (obj_value), ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); 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_NATIVE_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.class_prop.extra_info & 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.class_prop.extra_info |= ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD; frame_ctx_p->block_result = 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->block_result == ECMA_VALUE_UNDEFINED)) { 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); result = frame_ctx_p->block_result; frame_ctx_p->block_result = ECMA_VALUE_UNDEFINED; if (result == ECMA_VALUE_UNDEFINED) { result = ecma_op_create_promise_object (ECMA_VALUE_EMPTY, ECMA_VALUE_UNDEFINED, NULL); } 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: { JERRY_ASSERT (opcode == CBC_RETURN || opcode == CBC_RETURN_WITH_BLOCK || opcode == CBC_RETURN_WITH_LITERAL); if (opcode == CBC_RETURN_WITH_BLOCK) { left_value = frame_ctx_p->block_result; frame_ctx_p->block_result = ECMA_VALUE_UNDEFINED; } 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_MSG ("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_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_EXEC_STOP /* 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_EXEC_STOP */ *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_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); 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)) { 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->block_result != ECMA_VALUE_UNDEFINED) { 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.class_prop.extra_info |= 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.class_prop.extra_info |= 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); 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_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 */ #if JERRY_LINE_INFO case VM_OC_LINE: { uint32_t value = 0; uint8_t byte; do { byte = *byte_code_p++; value = (value << 7) | (byte & CBC_LOWER_SEVEN_BIT_MASK); } while (byte & CBC_HIGHEST_BIT_MASK); frame_ctx_p->current_line = value; continue; } #endif /* JERRY_LINE_INFO */ 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 (frame_ctx_p->block_result); frame_ctx_p->block_result = 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_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. */ ecma_fast_free_value (frame_ctx_p->block_result); 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: ecma_free_value (frame_ctx_p->block_result); frame_ctx_p->call_operation = VM_NO_EXEC_OP; return result; } } /* vm_loop */ #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->block_result = ECMA_VALUE_UNDEFINED; #if JERRY_LINE_INFO frame_ctx_p->current_line = 0; #endif /* JERRY_LINE_INFO */ 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); } frame_size = frame_size * sizeof (ecma_value_t) + sizeof (vm_frame_ctx_t); frame_size = (frame_size + sizeof (uintptr_t) - 1) / sizeof (uintptr_t); /* Use JERRY_MAX() to avoid array declaration with size 0. */ JERRY_VLA (uintptr_t, stack, frame_size); 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 */ /** * @} * @} */