From 41337dbd598b5095d457538a9934cea2c8dbd54b Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Wed, 6 Jul 2016 00:00:03 -0700 Subject: [PATCH] Small performance optimizations of the interpreter. Short summary of the changes: - The ecma_reference_t is removed, and its helper functions are deleted. - The delete operation does not depend on ecma_reference_t anymore. - A new resolve function is added which returns the current value of a named binding in the context chain. - The vm_op_set_value does not perform type conversions when its arguments has the appropriate types. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/ecma/operations/ecma-reference.c | 107 ++++++++++---------- jerry-core/ecma/operations/ecma-reference.h | 20 +--- jerry-core/vm/opcodes.c | 26 +---- jerry-core/vm/opcodes.h | 2 +- jerry-core/vm/vm.c | 96 ++++++++++-------- 5 files changed, 112 insertions(+), 139 deletions(-) diff --git a/jerry-core/ecma/operations/ecma-reference.c b/jerry-core/ecma/operations/ecma-reference.c index 032a298f0..3d2b95636 100644 --- a/jerry-core/ecma/operations/ecma-reference.c +++ b/jerry-core/ecma/operations/ecma-reference.c @@ -14,10 +14,12 @@ * limitations under the License. */ +#include "ecma-exceptions.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-lex-env.h" +#include "ecma-objects.h" #include "ecma-reference.h" #include "jrt.h" @@ -57,69 +59,64 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical } /* ecma_op_resolve_reference_base */ /** - * Resolve syntactic reference to ECMA-reference. + * Resolve value corresponding to reference. * - * @return ECMA-reference - * Returned value must be freed through ecma_free_reference. + * @return value of the reference */ -ecma_reference_t -ecma_op_get_identifier_reference (ecma_object_t *lex_env_p, /**< lexical environment */ - ecma_string_t *name_p, /**< identifier's name */ - bool is_strict) /**< strict reference flag */ +ecma_value_t +ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical environment */ + ecma_string_t *name_p, /**< identifier's name */ + bool is_strict) /**< strict mode */ { JERRY_ASSERT (lex_env_p != NULL); - ecma_object_t *base_lex_env_p = ecma_op_resolve_reference_base (lex_env_p, name_p); - - if (base_lex_env_p != NULL) + while (lex_env_p != NULL) { - return ecma_make_reference (ecma_make_object_value (base_lex_env_p), - name_p, - is_strict); + 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); + + if (property_p != NULL) + { + ecma_value_t prop_value = ecma_get_named_data_property_value (property_p); + + /* is the binding mutable? */ + if (unlikely (!ecma_is_property_writable (property_p) + && ecma_is_value_empty (prop_value))) + { + /* unitialized mutable binding */ + if (is_strict) + { + return ecma_raise_reference_error (ECMA_ERR_MSG ("")); + } + else + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + } + } + return ecma_fast_copy_value (prop_value); + } + } + else + { + JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND + || ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); + + ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + + ecma_property_t *property_p = ecma_op_object_get_property (binding_obj_p, name_p); + + if (property_p != NULL) + { + return ecma_op_object_get (binding_obj_p, name_p); + } + } + + lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p); } - else - { - return ecma_make_reference (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), - name_p, - is_strict); - } -} /* ecma_op_get_identifier_reference */ -/** - * ECMA-reference constructor. - * - * @return ECMA-reference - * Returned value must be freed through ecma_free_reference. - */ -ecma_reference_t -ecma_make_reference (ecma_value_t base, /**< base value */ - ecma_string_t *name_p, /**< referenced name */ - bool is_strict) /**< strict reference flag */ -{ - ecma_ref_ecma_string (name_p); - - ecma_reference_t ref; - ref.base = ecma_copy_value (base); - ref.is_strict = (is_strict != 0); - - ECMA_SET_POINTER (ref.referenced_name_cp, name_p); - - return ref; -} /* ecma_make_reference */ - -/** - * Free specified ECMA-reference. - * - * Warning: - * freeing invalidates all copies of the reference. - */ -void -ecma_free_reference (ecma_reference_t ref) /**< reference */ -{ - ecma_free_value (ref.base); - ecma_deref_ecma_string (ECMA_GET_NON_NULL_POINTER (ecma_string_t, - ref.referenced_name_cp)); -} /* ecma_free_reference */ + return ecma_raise_reference_error (ECMA_ERR_MSG ("")); +} /* ecma_op_resolve_reference_value */ /** * @} diff --git a/jerry-core/ecma/operations/ecma-reference.h b/jerry-core/ecma/operations/ecma-reference.h index f32dcf1e7..e44ff7334 100644 --- a/jerry-core/ecma/operations/ecma-reference.h +++ b/jerry-core/ecma/operations/ecma-reference.h @@ -26,26 +26,8 @@ * @{ */ -/** - * ECMA-reference (see also: ECMA-262 v5, 8.7). - */ -typedef struct -{ - /** base value */ - ecma_value_t base; - - /** referenced name */ - __extension__ jmem_cpointer_t referenced_name_cp : ECMA_POINTER_FIELD_WIDTH; - - /** strict reference flag */ - unsigned int is_strict : 1; -} ecma_reference_t; - extern ecma_object_t *ecma_op_resolve_reference_base (ecma_object_t *, ecma_string_t *); - -extern ecma_reference_t ecma_op_get_identifier_reference (ecma_object_t *, ecma_string_t *, bool); -extern ecma_reference_t ecma_make_reference (ecma_value_t, ecma_string_t *, bool); -extern void ecma_free_reference (ecma_reference_t); +extern ecma_value_t ecma_op_resolve_reference_value (ecma_object_t *, ecma_string_t *, bool); /** * @} diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 1ea03ea0a..1d6ad42c4 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -260,43 +260,25 @@ vm_op_delete_prop (ecma_value_t object, /**< base object */ */ ecma_value_t vm_op_delete_var (jmem_cpointer_t name_literal, /**< name literal */ - ecma_object_t *lex_env_p, /**< lexical environment */ - bool is_strict) /**< strict mode */ + ecma_object_t *lex_env_p) /**< lexical environment */ { ecma_value_t completion_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ecma_string_t *var_name_str_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, name_literal); - ecma_reference_t ref = ecma_op_get_identifier_reference (lex_env_p, - var_name_str_p, - is_strict); + ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (lex_env_p, var_name_str_p); - JERRY_ASSERT (!ref.is_strict); - - if (ecma_is_value_undefined (ref.base)) + if (ref_base_lex_env_p == NULL) { completion_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } else { - ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (lex_env_p, var_name_str_p); - JERRY_ASSERT (ecma_is_lexical_environment (ref_base_lex_env_p)); - ECMA_TRY_CATCH (delete_op_ret_val, - ecma_op_delete_binding (ref_base_lex_env_p, - ECMA_GET_NON_NULL_POINTER (ecma_string_t, - ref.referenced_name_cp)), - completion_value); - - completion_value = delete_op_ret_val; - - ECMA_FINALIZE (delete_op_ret_val); - + completion_value = ecma_op_delete_binding (ref_base_lex_env_p, var_name_str_p); } - ecma_free_reference (ref); - return completion_value; } /* vm_op_delete_var */ diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 61285e519..25219eaff 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -107,7 +107,7 @@ ecma_value_t vm_op_delete_prop (ecma_value_t, ecma_value_t, bool); ecma_value_t -vm_op_delete_var (jmem_cpointer_t, ecma_object_t *, bool); +vm_op_delete_var (jmem_cpointer_t, ecma_object_t *); ecma_collection_header_t * opfunc_for_in (ecma_value_t, ecma_value_t *); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index c86f5520e..c95a5e270 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -128,7 +128,11 @@ vm_op_get_value (ecma_value_t object, /**< base object */ /** * Set the value of object[property]. * - * @return ecma value + * 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 object, /**< base object */ @@ -136,36 +140,55 @@ vm_op_set_value (ecma_value_t object, /**< base object */ ecma_value_t value, /**< ecma value */ bool is_strict) /**< strict mode */ { + if (unlikely (!ecma_is_value_object (object))) + { + ecma_value_t to_object = ecma_op_to_object (object); + ecma_free_value (object); + + if (ECMA_IS_VALUE_ERROR (to_object)) + { + ecma_free_value (property); + return to_object; + } + + object = to_object; + } + + if (!ecma_is_value_string (property)) + { + ecma_value_t to_string = ecma_op_to_string (property); + ecma_fast_free_value (property); + + if (ECMA_IS_VALUE_ERROR (property)) + { + ecma_free_value (object); + return to_string; + } + + property = to_string; + } + + ecma_object_t *object_p = ecma_get_object_from_value (object); + ecma_string_t *property_p = ecma_get_string_from_value (property); ecma_value_t completion_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); - ECMA_TRY_CATCH (obj_val, - ecma_op_to_object (object), - completion_value); - - ECMA_TRY_CATCH (property_val, - ecma_op_to_string (property), - completion_value); - - ecma_object_t *object_p = ecma_get_object_from_value (obj_val); - ecma_string_t *property_p = ecma_get_string_from_value (property_val); - - if (ecma_is_lexical_environment (object_p)) - { - completion_value = ecma_op_put_value_lex_env_base (object_p, - property_p, - is_strict, - value); - } - else + if (!ecma_is_lexical_environment (object_p)) { completion_value = ecma_op_object_put (object_p, property_p, value, is_strict); } + else + { + completion_value = ecma_op_set_mutable_binding (object_p, + property_p, + value, + is_strict); + } - ECMA_FINALIZE (property_val); - ECMA_FINALIZE (obj_val); + ecma_free_value (object); + ecma_free_value (property); return completion_value; } /* vm_op_set_value */ @@ -505,18 +528,9 @@ opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { \ ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, \ literal_start_p[literal_index]); \ - ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p, \ - name_p); \ - if (ref_base_lex_env_p != NULL) \ - { \ - result = ecma_op_get_value_lex_env_base (ref_base_lex_env_p, \ - name_p, \ - is_strict); \ - } \ - else \ - { \ - result = ecma_raise_reference_error (ECMA_ERR_MSG ("")); \ - } \ + result = ecma_op_resolve_reference_value (frame_ctx_p->lex_env_p, \ + name_p, \ + is_strict); \ \ if (ECMA_IS_VALUE_ERROR (result)) \ { \ @@ -1103,7 +1117,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { *stack_top_p++ = ecma_make_simple_value (ECMA_SIMPLE_VALUE_REGISTER_REF); *stack_top_p++ = literal_index; - *stack_top_p++ = ecma_copy_value (frame_ctx_p->registers_p[literal_index]); + *stack_top_p++ = ecma_fast_copy_value (frame_ctx_p->registers_p[literal_index]); } else { @@ -1486,8 +1500,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } result = vm_op_delete_var (literal_start_p[literal_index], - frame_ctx_p->lex_env_p, - is_strict); + frame_ctx_p->lex_env_p); if (ECMA_IS_VALUE_ERROR (result)) { @@ -2406,10 +2419,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ frame_ctx_p->registers_p[property] = result; - if (opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)) + if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))) { - result = ecma_fast_copy_value (result); + goto free_both_values; } + result = ecma_fast_copy_value (result); } else { @@ -2418,9 +2432,6 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ result, is_strict); - ecma_free_value (object); - ecma_free_value (property); - if (ECMA_IS_VALUE_ERROR (set_value_result)) { ecma_free_value (result); @@ -2431,6 +2442,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))) { ecma_fast_free_value (result); + goto free_both_values; } } }