From 7b5764c44527016d540920f38d9d3044d121d0c0 Mon Sep 17 00:00:00 2001 From: Ilyong Cho Date: Fri, 3 Apr 2015 16:11:03 +0900 Subject: [PATCH 1/4] Storing global envorinment on global object's SCOPE internal property --- jerry-core/ecma/operations/ecma-lex-env.cpp | 25 +++++++++++++++++++++ jerry-core/ecma/operations/ecma-lex-env.h | 1 + 2 files changed, 26 insertions(+) diff --git a/jerry-core/ecma/operations/ecma-lex-env.cpp b/jerry-core/ecma/operations/ecma-lex-env.cpp index bf9509388..6dce07d43 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.cpp +++ b/jerry-core/ecma/operations/ecma-lex-env.cpp @@ -440,9 +440,34 @@ ecma_op_create_global_environment (ecma_object_t *glob_obj_p) /**< the Global ob ecma_object_t *glob_env_p = ecma_create_object_lex_env (NULL, glob_obj_p, false); #endif /* !CONFIG_ECMA_GLOBAL_ENVIRONMENT_DECLARATIVE */ + ecma_property_t *scope_prop_p = ecma_create_internal_property (glob_obj_p, ECMA_INTERNAL_PROPERTY_SCOPE); + ECMA_SET_POINTER (scope_prop_p->u.internal_property.value, glob_env_p); + return glob_env_p; } /* ecma_op_create_global_environment */ +/** + * Get global lexcial envorinment + * + * Note: + * This function should called after global environment was created. + * + * @return pointer to global lexical environment + */ +ecma_object_t* +ecma_get_globl_lexical_environment () +{ + ecma_object_t *glob_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL); + + ecma_property_t *scope_prop_p = ecma_get_internal_property (glob_p, ECMA_INTERNAL_PROPERTY_SCOPE); + + ecma_object_t *glob_env_p = ECMA_GET_POINTER (ecma_object_t, + scope_prop_p->u.internal_property.value); + JERRY_ASSERT (glob_env_p != NULL); + + return glob_env_p; +} + /** * Figure out whether the lexical environment is global. * diff --git a/jerry-core/ecma/operations/ecma-lex-env.h b/jerry-core/ecma/operations/ecma-lex-env.h index 5b40f1aeb..8c384a940 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.h +++ b/jerry-core/ecma/operations/ecma-lex-env.h @@ -66,6 +66,7 @@ extern void ecma_op_initialize_immutable_binding (ecma_object_t *lex_env_p, const ecma_value_t& value); extern ecma_object_t* ecma_op_create_global_environment (ecma_object_t *glob_obj_p); +extern ecma_object_t* ecma_get_globl_lexical_environment (); extern bool ecma_is_lexical_environment_global (ecma_object_t *lex_env_p); /** From 23ade8f4ff4c60a5e8685b67fe81f84b77bc8360 Mon Sep 17 00:00:00 2001 From: Ilyong Cho Date: Fri, 3 Apr 2015 18:11:21 +0900 Subject: [PATCH 2/4] wip: Implementing external function api --- jerry-core/ecma/base/ecma-alloc.cpp | 1 + jerry-core/ecma/base/ecma-alloc.h | 12 ++ jerry-core/ecma/base/ecma-globals.h | 5 + .../ecma/operations/ecma-function-object.cpp | 126 +++++++++++++++--- .../ecma/operations/ecma-function-object.h | 5 +- jerry-core/ecma/operations/ecma-objects.cpp | 1 + jerry-core/jerry-api.h | 10 ++ jerry-core/jerry.cpp | 21 +++ jerry-core/vm/opcodes.cpp | 4 +- tests/unit/test_api.cpp | 20 +++ 10 files changed, 183 insertions(+), 22 deletions(-) diff --git a/jerry-core/ecma/base/ecma-alloc.cpp b/jerry-core/ecma/base/ecma-alloc.cpp index 0dae9bdf5..c22f24e2e 100644 --- a/jerry-core/ecma/base/ecma-alloc.cpp +++ b/jerry-core/ecma/base/ecma-alloc.cpp @@ -89,6 +89,7 @@ DECLARE_ROUTINES_FOR (collection_chunk) DECLARE_ROUTINES_FOR (string) DECLARE_ROUTINES_FOR (label_descriptor) DECLARE_ROUTINES_FOR (getter_setter_pointers) +DECLARE_ROUTINES_FOR (external_pointer) /** * @} diff --git a/jerry-core/ecma/base/ecma-alloc.h b/jerry-core/ecma/base/ecma-alloc.h index 43a76a964..f40fd4f11 100644 --- a/jerry-core/ecma/base/ecma-alloc.h +++ b/jerry-core/ecma/base/ecma-alloc.h @@ -121,6 +121,18 @@ extern ecma_getter_setter_pointers_t *ecma_alloc_getter_setter_pointers (void); */ extern void ecma_dealloc_getter_setter_pointers (ecma_getter_setter_pointers_t *pointer_pair_p); +/** +* Allocate memory for external pointer +* +* @return pointer to allocated memory +*/ +extern ecma_external_pointer_t *ecma_alloc_external_pointer (void); + +/** +* Dealloc memory from external pointer +*/ +extern void ecma_dealloc_external_pointer (ecma_external_pointer_t *ptr_p); + #endif /* JERRY_ECMA_ALLOC_H */ diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index ef4e31f3f..e44abd2a2 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -372,6 +372,8 @@ typedef enum and not host objects */ ECMA_OBJECT_TYPE_STRING, /**< String objects (15.5) */ ECMA_OBJECT_TYPE_FUNCTION, /**< Function objects (15.3), created through 13.2 routine */ + ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION, /**< Function object (15.3), created through 13.2 routine + but [[Code]] is in external handler. */ ECMA_OBJECT_TYPE_BOUND_FUNCTION, /**< Function objects (15.3), created through 15.3.4.5 routine */ ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION, /** One of built-in functions described in section 15 of ECMA-262 v5 specification */ @@ -810,6 +812,9 @@ typedef struct ecma_string_t } u; } ecma_string_t; + +typedef uintptr_t ecma_external_pointer_t; + /** * @} */ diff --git a/jerry-core/ecma/operations/ecma-function-object.cpp b/jerry-core/ecma/operations/ecma-function-object.cpp index 10e5347fc..cb21f03a9 100644 --- a/jerry-core/ecma/operations/ecma-function-object.cpp +++ b/jerry-core/ecma/operations/ecma-function-object.cpp @@ -25,6 +25,7 @@ #include "ecma-objects-general.h" #include "ecma-try-catch-macro.h" #include "jrt.h" +#include "jerry-api.h" /** \addtogroup ecma ECMA * @{ @@ -78,6 +79,51 @@ ecma_unpack_code_internal_property_value (uint32_t value, /**< packed value */ return opcode_idx; } /* ecma_unpack_code_internal_property_value */ +/** + * Pack the pointer to external handler to value + * that can be stored in an [[Code]] internal property. + * + * @return packed value + */ +static uint32_t +ecma_pack_external_code_internal_property_value (jerry_external_handler_t handler) +{ + uint32_t value; + if (sizeof (jerry_external_handler_t) == sizeof (uint32_t)) + { + value = static_cast (reinterpret_cast (handler)); + } + else + { + ecma_external_pointer_t *handler_p = ecma_alloc_external_pointer (); + *handler_p = reinterpret_cast (handler); + ECMA_SET_POINTER (value, handler_p); + } + return value; +} /* ecma_pack_external_code_internal_property_value */ + +/** + * Unpack 'is_strict' flag and opcode index from value + * that can be stored in an [[Code]] internal property. + * + * @return opcode index + */ +static jerry_external_handler_t +ecma_unpack_external_code_internal_property_value (uint32_t value) /**< packed value */ +{ + jerry_external_handler_t handler; + if (sizeof (ecma_external_pointer_t) == sizeof (uint32_t)) + { + handler = reinterpret_cast (static_cast (value)); + } + else + { + ecma_external_pointer_t* handler_p = ECMA_GET_POINTER (ecma_external_pointer_t, value); + handler = reinterpret_cast (*handler_p); + } + return handler; +} /* ecma_unpack_code_internal_property_value */ + /** * IsCallable operation. * @@ -139,12 +185,21 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], /**< f ecma_length_t formal_parameters_number, /**< formal parameters list's length */ ecma_object_t *scope_p, /**< function's scope */ bool is_strict, /**< 'strict' flag */ - opcode_counter_t first_opcode_idx) /**< index of first opcode of function's body */ + bool is_external, /**< true if the function is an external */ + opcode_counter_t first_opcode_idx, /**< index of first opcode of function's body */ + jerry_external_handler_t external_handler) /**< external handler */ { + JERRY_ASSERT (!is_external || external_handler != NULL); + // 1., 4., 13. ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); - ecma_object_t *f = ecma_create_object (prototype_obj_p, true, ECMA_OBJECT_TYPE_FUNCTION); + ecma_object_type_t object_type = ECMA_OBJECT_TYPE_FUNCTION; + if (is_external) + { + object_type = ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION; + } + ecma_object_t *f = ecma_create_object (prototype_obj_p, true, object_type); ecma_deref_object (prototype_obj_p); @@ -179,8 +234,16 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], /**< f // 12. ecma_property_t *code_prop_p = ecma_create_internal_property (f, ECMA_INTERNAL_PROPERTY_CODE); - code_prop_p->u.internal_property.value = ecma_pack_code_internal_property_value (is_strict, - first_opcode_idx); + if (is_external) + { + code_prop_p->u.internal_property.value = ecma_pack_external_code_internal_property_value (external_handler); + } + else + { + code_prop_p->u.internal_property.value = ecma_pack_code_internal_property_value (is_strict, + first_opcode_idx); + } + // 14. ecma_number_t* len_p = ecma_alloc_number (); @@ -467,7 +530,8 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ ecma_completion_value_t ret_value; - if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION) + if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION + || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) { if (unlikely (ecma_get_object_is_builtin (func_obj_p))) { @@ -480,15 +544,24 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ { /* Entering Function Code (ECMA-262 v5, 10.4.3) */ ecma_property_t *scope_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_SCOPE); - ecma_property_t *code_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_CODE); - ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, scope_prop_p->u.internal_property.value); + + // 8. + bool is_strict; + opcode_counter_t code_first_opcode_idx = 0; + + ecma_property_t *code_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_CODE); uint32_t code_prop_value = code_prop_p->u.internal_property.value; - bool is_strict; - // 8. - opcode_counter_t code_first_opcode_idx = ecma_unpack_code_internal_property_value (code_prop_value, &is_strict); + if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION) + { + code_first_opcode_idx = ecma_unpack_code_internal_property_value (code_prop_value, &is_strict); + } + else /* ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION */ + { + is_strict = false; + } ecma_value_t this_binding; // 1. @@ -514,7 +587,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ // 5. ecma_object_t *local_env_p = ecma_create_decl_lex_env (scope_p); - // 9. + ECMA_TRY_CATCH (args_var_declaration_ret, ecma_function_call_setup_args_variables (func_obj_p, local_env_p, @@ -523,18 +596,29 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ is_strict), ret_value); - ecma_completion_value_t completion = run_int_from_pos (code_first_opcode_idx, - this_binding, - local_env_p, - is_strict, - false); - if (ecma_is_completion_value_return (completion)) + // 9. + if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION) { - ret_value = ecma_make_normal_completion_value (ecma_get_completion_value_value (completion)); + ecma_completion_value_t completion = run_int_from_pos (code_first_opcode_idx, + this_binding, + local_env_p, + is_strict, + false); + if (ecma_is_completion_value_return (completion)) + { + ret_value = ecma_make_normal_completion_value (ecma_get_completion_value_value (completion)); + } + else + { + ret_value = completion; + } + } else { - ret_value = completion; + jerry_external_handler_t handler = ecma_unpack_external_code_internal_property_value (code_prop_value); + handler (NULL, NULL, 0, NULL); + ret_value = 0; } ECMA_FINALIZE (args_var_declaration_ret); @@ -681,7 +765,9 @@ ecma_op_function_declaration (ecma_object_t *lex_env_p, /**< lexical environment formal_parameter_list_length, lex_env_p, is_strict, - function_code_opcode_idx); + false, + function_code_opcode_idx, + 0); // c. bool func_already_declared = ecma_op_has_binding (lex_env_p, function_name_p); diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index 78dd7b088..66fc830ae 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -18,6 +18,7 @@ #include "ecma-globals.h" #include "vm.h" +#include "jerry-api.h" /** \addtogroup ecma ECMA * @{ @@ -34,7 +35,9 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], ecma_length_t formal_parameters_number, ecma_object_t *scope_p, bool is_strict, - opcode_counter_t first_opcode_idx); + bool is_external, + opcode_counter_t first_opcode_idx, + jerry_external_handler_t external_handler); extern ecma_completion_value_t ecma_op_function_call (ecma_object_t *func_obj_p, diff --git a/jerry-core/ecma/operations/ecma-objects.cpp b/jerry-core/ecma/operations/ecma-objects.cpp index 616e0f418..0fe84da76 100644 --- a/jerry-core/ecma/operations/ecma-objects.cpp +++ b/jerry-core/ecma/operations/ecma-objects.cpp @@ -483,6 +483,7 @@ ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */ } case ECMA_OBJECT_TYPE_FUNCTION: + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION: { diff --git a/jerry-core/jerry-api.h b/jerry-core/jerry-api.h index ce5f135e1..86d27afd5 100644 --- a/jerry-core/jerry-api.h +++ b/jerry-core/jerry-api.h @@ -80,6 +80,14 @@ typedef struct jerry_api_value_t }; } jerry_api_value_t; +/** + * Jerry external function handler type + */ +typedef bool (*jerry_external_handler_t) (const jerry_api_value_t *this_p, + const jerry_api_value_t *args_p [], + const int16_t args_cnt, + jerry_api_value_t *ret_val_p); + extern EXTERN_C ssize_t jerry_api_string_to_char_buffer (const jerry_api_string_t *string_p, char *buffer_p, @@ -101,6 +109,8 @@ extern EXTERN_C jerry_api_string_t* jerry_api_create_string (const char *v); extern EXTERN_C jerry_api_object_t* jerry_api_create_object (void); +extern EXTERN_C +jerry_api_object_t* jerry_api_create_external_function (jerry_external_handler_t handler); extern EXTERN_C bool jerry_api_is_function (const jerry_api_object_t *object_p); diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index e8cf6c103..5596fec08 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -23,6 +23,7 @@ #include "ecma-gc.h" #include "ecma-helpers.h" #include "ecma-init-finalize.h" +#include "ecma-lex-env.h" #include "ecma-objects.h" #include "ecma-objects-general.h" #include "jerry.h" @@ -341,6 +342,26 @@ jerry_api_create_object (void) return ecma_op_create_object_object_noarg (); } /* jerry_api_create_object */ +/** + * Create an external function object + * + * Note: + * caller should release the object with jerry_api_release_object, just when the value becomes unnecessary. + * + * @return pointer to created external function object + */ +jerry_api_object_t* +jerry_api_create_external_function (jerry_external_handler_t handler) +{ + return ecma_op_create_function_object (NULL, + 0, + ecma_get_globl_lexical_environment (), + false, + 0, + true, + handler); +} /* jerry_api_create_object */ + /** * Check if the specified object is a function object. * diff --git a/jerry-core/vm/opcodes.cpp b/jerry-core/vm/opcodes.cpp index 8f74d2e77..f03031602 100644 --- a/jerry-core/vm/opcodes.cpp +++ b/jerry-core/vm/opcodes.cpp @@ -580,7 +580,9 @@ opfunc_func_expr_n (opcode_t opdata, /**< operation data */ params_number, scope_p, is_strict, - int_data->pos); + false, + int_data->pos, + 0); ret_value = set_variable_value (int_data, lit_oc, dst_var_idx, diff --git a/tests/unit/test_api.cpp b/tests/unit/test_api.cpp index e998c1026..eab1290bc 100644 --- a/tests/unit/test_api.cpp +++ b/tests/unit/test_api.cpp @@ -59,6 +59,17 @@ test_api_init_api_value_string (jerry_api_value_t *out_value_p, /**< out: API va out_value_p->v_string = jerry_api_create_string (v); } /* test_api_init_api_value_string */ +static bool +handler (const jerry_api_value_t *this_p, + const jerry_api_value_t *args_p [], + const int16_t args_cnt, + jerry_api_value_t *ret_val_p) +{ + printf("ok %p %p %d %p\n", this_p, args_p, args_cnt, ret_val_p); + return true; +} + + int main (void) { @@ -68,6 +79,7 @@ main (void) ssize_t sz; jerry_api_value_t val_t, val_foo, val_bar, val_A, val_A_prototype, val_a, val_a_foo; jerry_api_object_t* global_obj_p; + jerry_api_object_t* external_func_p; jerry_api_value_t res, args [2]; char buffer [16]; @@ -180,6 +192,14 @@ main (void) jerry_api_release_value (&res); jerry_api_release_value (&val_a_foo); + external_func_p = jerry_api_create_external_function (handler); + assert (external_func_p != NULL); + + is_ok = jerry_api_call_function (external_func_p, global_obj_p, &res, NULL, 0); + assert (is_ok); + + jerry_api_release_object (external_func_p); + jerry_api_release_value (&val_a); jerry_api_release_object (global_obj_p); From 5611c16117d9f9ec06262e7882904bb0f8e74943 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 3 Apr 2015 23:14:23 +0300 Subject: [PATCH 3/4] Fixing assertion in jrt_set_bit_field_value. --- jerry-core/jrt/jrt-bit-fields.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jerry-core/jrt/jrt-bit-fields.cpp b/jerry-core/jrt/jrt-bit-fields.cpp index 991d30f25..234d74148 100644 --- a/jerry-core/jrt/jrt-bit-fields.cpp +++ b/jerry-core/jrt/jrt-bit-fields.cpp @@ -52,7 +52,7 @@ jrt_set_bit_field_value (uint64_t container, /**< container to insert bit-field JERRY_ASSERT (lsb < JERRY_BITSINBYTE * sizeof (uint64_t)); JERRY_ASSERT (width < JERRY_BITSINBYTE * sizeof (uint64_t)); JERRY_ASSERT ((lsb + width) <= JERRY_BITSINBYTE * sizeof (uint64_t)); - JERRY_ASSERT (new_bit_field_value <= (1ull << width)); + JERRY_ASSERT (new_bit_field_value < (1ull << width)); uint64_t bit_field_mask = (1ull << width) - 1; uint64_t shifted_bit_field_mask = bit_field_mask << lsb; From 83730cd6bba142daee4951131bd832256b868de9 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 3 Apr 2015 23:14:55 +0300 Subject: [PATCH 4/4] Implementing dispatcher for calling native handlers associated with external function objects; implementing interface for unified storage of native pointers in ecma objects. --- jerry-core/ecma/base/ecma-alloc.h | 2 +- jerry-core/ecma/base/ecma-gc.cpp | 1 + jerry-core/ecma/base/ecma-globals.h | 13 +- .../base/ecma-helpers-external-pointers.cpp | 117 +++++++++++ jerry-core/ecma/base/ecma-helpers.cpp | 7 + jerry-core/ecma/base/ecma-helpers.h | 11 + .../ecma/operations/ecma-function-object.cpp | 194 ++++++++---------- .../ecma/operations/ecma-function-object.h | 7 +- jerry-core/ecma/operations/ecma-lex-env.cpp | 25 --- jerry-core/ecma/operations/ecma-lex-env.h | 1 - jerry-core/ecma/operations/ecma-objects.cpp | 91 ++++---- jerry-core/jerry-api.h | 11 +- jerry-core/jerry-internal.h | 33 +++ jerry-core/jerry.cpp | 82 +++++++- jerry-core/vm/opcodes.cpp | 4 +- tests/unit/test_api.cpp | 82 ++++++-- 16 files changed, 464 insertions(+), 217 deletions(-) create mode 100644 jerry-core/ecma/base/ecma-helpers-external-pointers.cpp create mode 100644 jerry-core/jerry-internal.h diff --git a/jerry-core/ecma/base/ecma-alloc.h b/jerry-core/ecma/base/ecma-alloc.h index f40fd4f11..e14d512aa 100644 --- a/jerry-core/ecma/base/ecma-alloc.h +++ b/jerry-core/ecma/base/ecma-alloc.h @@ -131,7 +131,7 @@ extern ecma_external_pointer_t *ecma_alloc_external_pointer (void); /** * Dealloc memory from external pointer */ -extern void ecma_dealloc_external_pointer (ecma_external_pointer_t *ptr_p); +extern void ecma_dealloc_external_pointer (ecma_external_pointer_t *external_pointer_p); #endif /* JERRY_ECMA_ALLOC_H */ diff --git a/jerry-core/ecma/base/ecma-gc.cpp b/jerry-core/ecma/base/ecma-gc.cpp index dd283a8de..3779361a4 100644 --- a/jerry-core/ecma/base/ecma-gc.cpp +++ b/jerry-core/ecma/base/ecma-gc.cpp @@ -318,6 +318,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */ case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */ case ECMA_INTERNAL_PROPERTY_CODE: /* an integer */ + case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */ diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index e44abd2a2..a7a0bac1e 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -204,6 +204,7 @@ typedef enum ECMA_INTERNAL_PROPERTY_SCOPE, /**< [[Scope]] */ ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP, /**< [[ParametersMap]] */ ECMA_INTERNAL_PROPERTY_CODE, /**< [[Code]] */ + ECMA_INTERNAL_PROPERTY_NATIVE_CODE, /**< native handler location descriptor */ ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS, /**< [[FormalParameters]] */ ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE, /**< [[Primitive value]] for String objects */ ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE, /**< [[Primitive value]] for Number objects */ @@ -372,8 +373,7 @@ typedef enum and not host objects */ ECMA_OBJECT_TYPE_STRING, /**< String objects (15.5) */ ECMA_OBJECT_TYPE_FUNCTION, /**< Function objects (15.3), created through 13.2 routine */ - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION, /**< Function object (15.3), created through 13.2 routine - but [[Code]] is in external handler. */ + ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION, /**< External (host) function object */ ECMA_OBJECT_TYPE_BOUND_FUNCTION, /**< Function objects (15.3), created through 15.3.4.5 routine */ ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION, /** One of built-in functions described in section 15 of ECMA-262 v5 specification */ @@ -381,8 +381,7 @@ typedef enum ECMA_OBJECT_TYPE_ARRAY, /**< Array object (15.4) */ ECMA_OBJECT_TYPE_EXTENSION, /**< Extension (implementation-defined) object * See also: ecma_extension_instantiate */ - // ECMA_OBJECT_TYPE_HOST, /**< Host object */ - ECMA_OBJECT_TYPE__COUNT /**< number of object types */ + // ECMA_OBJECT_TYPE_HOST /**< Host object */ } ecma_object_type_t; /** @@ -444,7 +443,7 @@ typedef struct ecma_object_t */ #define ECMA_OBJECT_OBJ_TYPE_POS (ECMA_OBJECT_OBJ_EXTENSIBLE_POS + \ ECMA_OBJECT_OBJ_EXTENSIBLE_WIDTH) -#define ECMA_OBJECT_OBJ_TYPE_WIDTH (3) +#define ECMA_OBJECT_OBJ_TYPE_WIDTH (4) /** * Compressed pointer to prototype object (ecma_object_t) @@ -812,7 +811,9 @@ typedef struct ecma_string_t } u; } ecma_string_t; - +/** + * Representation for native external pointer + */ typedef uintptr_t ecma_external_pointer_t; /** diff --git a/jerry-core/ecma/base/ecma-helpers-external-pointers.cpp b/jerry-core/ecma/base/ecma-helpers-external-pointers.cpp new file mode 100644 index 000000000..56315b860 --- /dev/null +++ b/jerry-core/ecma/base/ecma-helpers-external-pointers.cpp @@ -0,0 +1,117 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * + * 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. + */ + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmahelpers Helpers for operations with ECMA data types + * @{ + */ + +#include "ecma-alloc.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" + +/** + * Create internal property with specified identifier and store external pointer in the property. + * + * Note: + * property identifier should be one of the following: + * - ECMA_INTERNAL_PROPERTY_NATIVE_CODE + */ +void +ecma_create_external_pointer_property (ecma_object_t *obj_p, /**< object to create property in */ + ecma_internal_property_id_t id, /**< identifier of internal + * property to create */ + ecma_external_pointer_t ptr_value) /**< value to store in the property */ +{ + JERRY_ASSERT (id == ECMA_INTERNAL_PROPERTY_NATIVE_CODE); + + ecma_property_t *prop_p = ecma_create_internal_property (obj_p, id); + JERRY_STATIC_ASSERT (sizeof (uint32_t) <= sizeof (prop_p->u.internal_property.value)); + + if (sizeof (ecma_external_pointer_t) == sizeof (uint32_t)) + { + prop_p->u.internal_property.value = (uint32_t) ptr_value; + } + else + { + ecma_external_pointer_t *handler_p = ecma_alloc_external_pointer (); + *handler_p = ptr_value; + + ECMA_SET_NON_NULL_POINTER (prop_p->u.internal_property.value, handler_p); + } +} /* ecma_create_external_pointer_property */ + +/** + * Get value of external pointer stored in the object's property with specified identifier + * + * Note: + * property identifier should be one of the following: + * - ECMA_INTERNAL_PROPERTY_NATIVE_CODE + * + * @return value of the external pointer + */ +ecma_external_pointer_t +ecma_get_external_pointer_value (ecma_object_t *obj_p, /**< object to get property value from */ + ecma_internal_property_id_t id) /**< identifier of internal property + * to get value from */ +{ + JERRY_ASSERT (id == ECMA_INTERNAL_PROPERTY_NATIVE_CODE); + + ecma_property_t* prop_p = ecma_get_internal_property (obj_p, id); + JERRY_STATIC_ASSERT (sizeof (uint32_t) <= sizeof (prop_p->u.internal_property.value)); + + if (sizeof (ecma_external_pointer_t) == sizeof (uint32_t)) + { + return (ecma_external_pointer_t) prop_p->u.internal_property.value; + } + else + { + ecma_external_pointer_t *handler_p = ECMA_GET_NON_NULL_POINTER (ecma_external_pointer_t, + prop_p->u.internal_property.value); + return *handler_p; + } +} /* ecma_get_external_pointer_value */ + +/** + * Free memory associated with external pointer stored in the property + * + * Note: + * property identifier should be one of the following: + * - ECMA_INTERNAL_PROPERTY_NATIVE_CODE + */ +void +ecma_free_external_pointer_in_property (ecma_property_t *prop_p) /**< internal property */ +{ + JERRY_ASSERT (prop_p->u.internal_property.type == ECMA_INTERNAL_PROPERTY_NATIVE_CODE); + + if (sizeof (ecma_external_pointer_t) == sizeof (uint32_t)) + { + /* no additional memory was allocated for the pointer storage */ + } + else + { + ecma_external_pointer_t *handler_p = ECMA_GET_NON_NULL_POINTER (ecma_external_pointer_t, + prop_p->u.internal_property.value); + + ecma_dealloc_external_pointer (handler_p); + } +} /* ecma_free_external_pointer_in_property */ + +/** + * @} + * @} + */ diff --git a/jerry-core/ecma/base/ecma-helpers.cpp b/jerry-core/ecma/base/ecma-helpers.cpp index aceba31c9..eaa6694fb 100644 --- a/jerry-core/ecma/base/ecma-helpers.cpp +++ b/jerry-core/ecma/base/ecma-helpers.cpp @@ -778,6 +778,13 @@ ecma_free_internal_property (ecma_property_t *property_p) /**< the property */ break; } + case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */ + { + ecma_free_external_pointer_in_property (property_p); + + break; + } + case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */ case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */ diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 98457d4de..55884b92d 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -308,6 +308,17 @@ extern void ecma_set_property_lcached (ecma_property_t *prop_p, extern ecma_property_descriptor_t ecma_make_empty_property_descriptor (void); extern void ecma_free_property_descriptor (ecma_property_descriptor_t *prop_desc_p); +/* ecma-helpers-external-pointers.c */ +extern void +ecma_create_external_pointer_property (ecma_object_t *obj_p, + ecma_internal_property_id_t id, + ecma_external_pointer_t ptr_value); +extern ecma_external_pointer_t +ecma_get_external_pointer_value (ecma_object_t *obj_p, + ecma_internal_property_id_t id); +extern void +ecma_free_external_pointer_in_property (ecma_property_t *prop_p); + /* ecma-helpers-conversion.c */ extern ecma_number_t ecma_zt_string_to_number (const ecma_char_t *str_p); extern ssize_t ecma_uint32_to_string (uint32_t value, ecma_char_t *out_buffer_p, ssize_t buffer_size); diff --git a/jerry-core/ecma/operations/ecma-function-object.cpp b/jerry-core/ecma/operations/ecma-function-object.cpp index cb21f03a9..f2f299af0 100644 --- a/jerry-core/ecma/operations/ecma-function-object.cpp +++ b/jerry-core/ecma/operations/ecma-function-object.cpp @@ -25,7 +25,9 @@ #include "ecma-objects-general.h" #include "ecma-try-catch-macro.h" #include "jrt.h" -#include "jerry-api.h" + +#define JERRY_INTERNAL +#include "jerry-internal.h" /** \addtogroup ecma ECMA * @{ @@ -79,51 +81,6 @@ ecma_unpack_code_internal_property_value (uint32_t value, /**< packed value */ return opcode_idx; } /* ecma_unpack_code_internal_property_value */ -/** - * Pack the pointer to external handler to value - * that can be stored in an [[Code]] internal property. - * - * @return packed value - */ -static uint32_t -ecma_pack_external_code_internal_property_value (jerry_external_handler_t handler) -{ - uint32_t value; - if (sizeof (jerry_external_handler_t) == sizeof (uint32_t)) - { - value = static_cast (reinterpret_cast (handler)); - } - else - { - ecma_external_pointer_t *handler_p = ecma_alloc_external_pointer (); - *handler_p = reinterpret_cast (handler); - ECMA_SET_POINTER (value, handler_p); - } - return value; -} /* ecma_pack_external_code_internal_property_value */ - -/** - * Unpack 'is_strict' flag and opcode index from value - * that can be stored in an [[Code]] internal property. - * - * @return opcode index - */ -static jerry_external_handler_t -ecma_unpack_external_code_internal_property_value (uint32_t value) /**< packed value */ -{ - jerry_external_handler_t handler; - if (sizeof (ecma_external_pointer_t) == sizeof (uint32_t)) - { - handler = reinterpret_cast (static_cast (value)); - } - else - { - ecma_external_pointer_t* handler_p = ECMA_GET_POINTER (ecma_external_pointer_t, value); - handler = reinterpret_cast (*handler_p); - } - return handler; -} /* ecma_unpack_code_internal_property_value */ - /** * IsCallable operation. * @@ -147,6 +104,7 @@ ecma_op_is_callable (const ecma_value_t& value) /**< ecma-value */ return (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION || ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION + || ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION || ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION); } /* ecma_op_is_callable */ @@ -170,7 +128,8 @@ ecma_is_constructor (const ecma_value_t& value) /**< ecma-value */ JERRY_ASSERT(!ecma_is_lexical_environment (obj_p)); return (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION - || ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + || ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION + || ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); } /* ecma_is_constructor */ /** @@ -185,21 +144,12 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], /**< f ecma_length_t formal_parameters_number, /**< formal parameters list's length */ ecma_object_t *scope_p, /**< function's scope */ bool is_strict, /**< 'strict' flag */ - bool is_external, /**< true if the function is an external */ - opcode_counter_t first_opcode_idx, /**< index of first opcode of function's body */ - jerry_external_handler_t external_handler) /**< external handler */ + opcode_counter_t first_opcode_idx) /**< index of first opcode of function's body */ { - JERRY_ASSERT (!is_external || external_handler != NULL); - // 1., 4., 13. ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); - ecma_object_type_t object_type = ECMA_OBJECT_TYPE_FUNCTION; - if (is_external) - { - object_type = ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION; - } - ecma_object_t *f = ecma_create_object (prototype_obj_p, true, object_type); + ecma_object_t *f = ecma_create_object (prototype_obj_p, true, ECMA_OBJECT_TYPE_FUNCTION); ecma_deref_object (prototype_obj_p); @@ -234,16 +184,8 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], /**< f // 12. ecma_property_t *code_prop_p = ecma_create_internal_property (f, ECMA_INTERNAL_PROPERTY_CODE); - if (is_external) - { - code_prop_p->u.internal_property.value = ecma_pack_external_code_internal_property_value (external_handler); - } - else - { - code_prop_p->u.internal_property.value = ecma_pack_code_internal_property_value (is_strict, - first_opcode_idx); - } - + code_prop_p->u.internal_property.value = ecma_pack_code_internal_property_value (is_strict, + first_opcode_idx); // 14. ecma_number_t* len_p = ecma_alloc_number (); @@ -345,6 +287,56 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], /**< f return f; } /* ecma_op_create_function_object */ +/** + * External function object creation operation. + * + * Note: + * external function object is implementation-defined object type + * that represent functions implemented in native code, using Embedding API + * + * @return pointer to newly created external function object + */ +ecma_object_t* +ecma_op_create_external_function_object (ecma_external_pointer_t code_p) /**< pointer to external native handler */ +{ + ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + + ecma_object_t *function_obj_p = ecma_create_object (prototype_obj_p, true, ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + + ecma_deref_object (prototype_obj_p); + + ecma_property_t *class_prop_p = ecma_create_internal_property (function_obj_p, ECMA_INTERNAL_PROPERTY_CLASS); + class_prop_p->u.internal_property.value = ECMA_MAGIC_STRING_FUNCTION_UL; + + ecma_create_external_pointer_property (function_obj_p, + ECMA_INTERNAL_PROPERTY_NATIVE_CODE, + (ecma_external_pointer_t) code_p); + + ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); + { + prop_desc.is_value_defined = true; + prop_desc.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + + prop_desc.is_writable_defined = true; + prop_desc.is_writable = true; + + prop_desc.is_enumerable_defined = true; + prop_desc.is_enumerable = false; + + prop_desc.is_configurable_defined = true; + prop_desc.is_configurable = false; + } + + ecma_string_t *magic_string_prototype_p = ecma_get_magic_string (ECMA_MAGIC_STRING_PROTOTYPE); + ecma_op_object_define_own_property (function_obj_p, + magic_string_prototype_p, + &prop_desc, + false); + ecma_deref_ecma_string (magic_string_prototype_p); + + return function_obj_p; +} /* ecma_op_create_external_function_object */ + /** * Setup variables for arguments listed in formal parameter list. * @@ -530,8 +522,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ ecma_completion_value_t ret_value; - if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION - || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) + if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION) { if (unlikely (ecma_get_object_is_builtin (func_obj_p))) { @@ -544,24 +535,15 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ { /* Entering Function Code (ECMA-262 v5, 10.4.3) */ ecma_property_t *scope_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_SCOPE); + ecma_property_t *code_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_CODE); + ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, scope_prop_p->u.internal_property.value); - - // 8. - bool is_strict; - opcode_counter_t code_first_opcode_idx = 0; - - ecma_property_t *code_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_CODE); uint32_t code_prop_value = code_prop_p->u.internal_property.value; - if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION) - { - code_first_opcode_idx = ecma_unpack_code_internal_property_value (code_prop_value, &is_strict); - } - else /* ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION */ - { - is_strict = false; - } + bool is_strict; + // 8. + opcode_counter_t code_first_opcode_idx = ecma_unpack_code_internal_property_value (code_prop_value, &is_strict); ecma_value_t this_binding; // 1. @@ -587,7 +569,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ // 5. ecma_object_t *local_env_p = ecma_create_decl_lex_env (scope_p); - + // 9. ECMA_TRY_CATCH (args_var_declaration_ret, ecma_function_call_setup_args_variables (func_obj_p, local_env_p, @@ -596,29 +578,18 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ is_strict), ret_value); - // 9. - if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION) + ecma_completion_value_t completion = run_int_from_pos (code_first_opcode_idx, + this_binding, + local_env_p, + is_strict, + false); + if (ecma_is_completion_value_return (completion)) { - ecma_completion_value_t completion = run_int_from_pos (code_first_opcode_idx, - this_binding, - local_env_p, - is_strict, - false); - if (ecma_is_completion_value_return (completion)) - { - ret_value = ecma_make_normal_completion_value (ecma_get_completion_value_value (completion)); - } - else - { - ret_value = completion; - } - + ret_value = ecma_make_normal_completion_value (ecma_get_completion_value_value (completion)); } else { - jerry_external_handler_t handler = ecma_unpack_external_code_internal_property_value (code_prop_value); - handler (NULL, NULL, 0, NULL); - ret_value = 0; + ret_value = completion; } ECMA_FINALIZE (args_var_declaration_ret); @@ -634,6 +605,17 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ arguments_list_p, arguments_list_len); } + else if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) + { + ecma_external_pointer_t handler_p = ecma_get_external_pointer_value (func_obj_p, + ECMA_INTERNAL_PROPERTY_NATIVE_CODE); + + ret_value = jerry_dispatch_external_function (func_obj_p, + handler_p, + this_arg_value, + arguments_list_p, + arguments_list_len); + } else { JERRY_ASSERT(ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); @@ -765,9 +747,7 @@ ecma_op_function_declaration (ecma_object_t *lex_env_p, /**< lexical environment formal_parameter_list_length, lex_env_p, is_strict, - false, - function_code_opcode_idx, - 0); + function_code_opcode_idx); // c. bool func_already_declared = ecma_op_has_binding (lex_env_p, function_name_p); diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index 66fc830ae..0458c5f3f 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -18,7 +18,6 @@ #include "ecma-globals.h" #include "vm.h" -#include "jerry-api.h" /** \addtogroup ecma ECMA * @{ @@ -35,9 +34,9 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], ecma_length_t formal_parameters_number, ecma_object_t *scope_p, bool is_strict, - bool is_external, - opcode_counter_t first_opcode_idx, - jerry_external_handler_t external_handler); + opcode_counter_t first_opcode_idx); +extern ecma_object_t* +ecma_op_create_external_function_object (ecma_external_pointer_t code_p); extern ecma_completion_value_t ecma_op_function_call (ecma_object_t *func_obj_p, diff --git a/jerry-core/ecma/operations/ecma-lex-env.cpp b/jerry-core/ecma/operations/ecma-lex-env.cpp index 6dce07d43..bf9509388 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.cpp +++ b/jerry-core/ecma/operations/ecma-lex-env.cpp @@ -440,34 +440,9 @@ ecma_op_create_global_environment (ecma_object_t *glob_obj_p) /**< the Global ob ecma_object_t *glob_env_p = ecma_create_object_lex_env (NULL, glob_obj_p, false); #endif /* !CONFIG_ECMA_GLOBAL_ENVIRONMENT_DECLARATIVE */ - ecma_property_t *scope_prop_p = ecma_create_internal_property (glob_obj_p, ECMA_INTERNAL_PROPERTY_SCOPE); - ECMA_SET_POINTER (scope_prop_p->u.internal_property.value, glob_env_p); - return glob_env_p; } /* ecma_op_create_global_environment */ -/** - * Get global lexcial envorinment - * - * Note: - * This function should called after global environment was created. - * - * @return pointer to global lexical environment - */ -ecma_object_t* -ecma_get_globl_lexical_environment () -{ - ecma_object_t *glob_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL); - - ecma_property_t *scope_prop_p = ecma_get_internal_property (glob_p, ECMA_INTERNAL_PROPERTY_SCOPE); - - ecma_object_t *glob_env_p = ECMA_GET_POINTER (ecma_object_t, - scope_prop_p->u.internal_property.value); - JERRY_ASSERT (glob_env_p != NULL); - - return glob_env_p; -} - /** * Figure out whether the lexical environment is global. * diff --git a/jerry-core/ecma/operations/ecma-lex-env.h b/jerry-core/ecma/operations/ecma-lex-env.h index 8c384a940..5b40f1aeb 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.h +++ b/jerry-core/ecma/operations/ecma-lex-env.h @@ -66,7 +66,6 @@ extern void ecma_op_initialize_immutable_binding (ecma_object_t *lex_env_p, const ecma_value_t& value); extern ecma_object_t* ecma_op_create_global_environment (ecma_object_t *glob_obj_p); -extern ecma_object_t* ecma_get_globl_lexical_environment (); extern bool ecma_is_lexical_environment_global (ecma_object_t *lex_env_p); /** diff --git a/jerry-core/ecma/operations/ecma-objects.cpp b/jerry-core/ecma/operations/ecma-objects.cpp index 0fe84da76..643eac846 100644 --- a/jerry-core/ecma/operations/ecma-objects.cpp +++ b/jerry-core/ecma/operations/ecma-objects.cpp @@ -32,6 +32,23 @@ * @{ */ +/** + * Assert that specified object type value is valid + */ +static void +ecma_assert_object_type_is_valid (ecma_object_type_t type) /**< object's implementation-defined type */ +{ + JERRY_ASSERT (type == ECMA_OBJECT_TYPE_GENERAL + || type == ECMA_OBJECT_TYPE_ARRAY + || type == ECMA_OBJECT_TYPE_FUNCTION + || type == ECMA_OBJECT_TYPE_BOUND_FUNCTION + || type == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION + || type == ECMA_OBJECT_TYPE_STRING + || type == ECMA_OBJECT_TYPE_ARGUMENTS + || type == ECMA_OBJECT_TYPE_EXTENSION + || type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); +} /* ecma_assert_object_type_is_valid */ + /** * [[Get]] ecma object's operation * @@ -50,7 +67,7 @@ ecma_op_object_get (ecma_object_t *obj_p, /**< the object */ JERRY_ASSERT(property_name_p != NULL); const ecma_object_type_t type = ecma_get_object_type (obj_p); - JERRY_ASSERT (type < ECMA_OBJECT_TYPE__COUNT); + ecma_assert_object_type_is_valid (type); switch (type) { @@ -58,6 +75,7 @@ ecma_op_object_get (ecma_object_t *obj_p, /**< the object */ case ECMA_OBJECT_TYPE_ARRAY: case ECMA_OBJECT_TYPE_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION: case ECMA_OBJECT_TYPE_EXTENSION: case ECMA_OBJECT_TYPE_STRING: @@ -69,14 +87,11 @@ ecma_op_object_get (ecma_object_t *obj_p, /**< the object */ { return ecma_op_arguments_object_get (obj_p, property_name_p); } - - default: - { - JERRY_ASSERT (false); - - return ecma_make_empty_completion_value (); - } } + + JERRY_ASSERT (false); + + return ecma_make_empty_completion_value (); } /* ecma_op_object_get */ /** @@ -90,11 +105,11 @@ ecma_op_object_get_own_property_longpath (ecma_object_t *obj_p, /**< the object ecma_string_t *property_name_p) /**< property name */ { const ecma_object_type_t type = ecma_get_object_type (obj_p); - JERRY_ASSERT (type < ECMA_OBJECT_TYPE__COUNT); + ecma_assert_object_type_is_valid (type); const bool is_builtin = ecma_get_object_is_builtin (obj_p); - ecma_property_t *prop_p; + ecma_property_t *prop_p = NULL; switch (type) { @@ -102,6 +117,7 @@ ecma_op_object_get_own_property_longpath (ecma_object_t *obj_p, /**< the object case ECMA_OBJECT_TYPE_ARRAY: case ECMA_OBJECT_TYPE_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION: { prop_p = ecma_op_general_object_get_own_property (obj_p, property_name_p); @@ -129,13 +145,6 @@ ecma_op_object_get_own_property_longpath (ecma_object_t *obj_p, /**< the object break; } - - default: - { - JERRY_ASSERT (false); - - return NULL; - } } if (unlikely (prop_p == NULL)) @@ -198,7 +207,7 @@ ecma_op_object_get_property (ecma_object_t *obj_p, /**< the object */ JERRY_ASSERT(property_name_p != NULL); const ecma_object_type_t type = ecma_get_object_type (obj_p); - JERRY_ASSERT (type < ECMA_OBJECT_TYPE__COUNT); + ecma_assert_object_type_is_valid (type); /* * typedef ecma_property_t* (*get_property_ptr_t) (ecma_object_t *, ecma_string_t *); @@ -208,6 +217,7 @@ ecma_op_object_get_property (ecma_object_t *obj_p, /**< the object */ * [ECMA_OBJECT_TYPE_ARRAY] = &ecma_op_general_object_get_property, * [ECMA_OBJECT_TYPE_FUNCTION] = &ecma_op_general_object_get_property, * [ECMA_OBJECT_TYPE_BOUND_FUNCTION] = &ecma_op_general_object_get_property, + * [ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION] = &ecma_op_general_object_get_property, * [ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION] = &ecma_op_general_object_get_property, * [ECMA_OBJECT_TYPE_EXTENSION] = &ecma_op_general_object_get_property, * [ECMA_OBJECT_TYPE_ARGUMENTS] = &ecma_op_general_object_get_property, @@ -240,7 +250,7 @@ ecma_op_object_put (ecma_object_t *obj_p, /**< the object */ JERRY_ASSERT(property_name_p != NULL); const ecma_object_type_t type = ecma_get_object_type (obj_p); - JERRY_ASSERT (type < ECMA_OBJECT_TYPE__COUNT); + ecma_assert_object_type_is_valid (type); /* * typedef ecma_property_t* (*put_ptr_t) (ecma_object_t *, ecma_string_t *); @@ -250,6 +260,7 @@ ecma_op_object_put (ecma_object_t *obj_p, /**< the object */ * [ECMA_OBJECT_TYPE_ARRAY] = &ecma_op_general_object_put, * [ECMA_OBJECT_TYPE_FUNCTION] = &ecma_op_general_object_put, * [ECMA_OBJECT_TYPE_BOUND_FUNCTION] = &ecma_op_general_object_put, + * [ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION] = &ecma_op_general_object_put, * [ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION] = &ecma_op_general_object_put, * [ECMA_OBJECT_TYPE_EXTENSION] = &ecma_op_general_object_put, * [ECMA_OBJECT_TYPE_ARGUMENTS] = &ecma_op_general_object_put, @@ -280,7 +291,7 @@ ecma_op_object_can_put (ecma_object_t *obj_p, /**< the object */ JERRY_ASSERT(property_name_p != NULL); const ecma_object_type_t type = ecma_get_object_type (obj_p); - JERRY_ASSERT (type < ECMA_OBJECT_TYPE__COUNT); + ecma_assert_object_type_is_valid (type); /* * typedef ecma_property_t* (*can_put_ptr_t) (ecma_object_t *, ecma_string_t *); @@ -290,6 +301,7 @@ ecma_op_object_can_put (ecma_object_t *obj_p, /**< the object */ * [ECMA_OBJECT_TYPE_ARRAY] = &ecma_op_general_object_can_put, * [ECMA_OBJECT_TYPE_FUNCTION] = &ecma_op_general_object_can_put, * [ECMA_OBJECT_TYPE_BOUND_FUNCTION] = &ecma_op_general_object_can_put, + * [ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION] = &ecma_op_general_object_can_put, * [ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION] = &ecma_op_general_object_can_put, * [ECMA_OBJECT_TYPE_EXTENSION] = &ecma_op_general_object_can_put, * [ECMA_OBJECT_TYPE_ARGUMENTS] = &ecma_op_general_object_can_put, @@ -321,7 +333,7 @@ ecma_op_object_delete (ecma_object_t *obj_p, /**< the object */ JERRY_ASSERT(property_name_p != NULL); const ecma_object_type_t type = ecma_get_object_type (obj_p); - JERRY_ASSERT (type < ECMA_OBJECT_TYPE__COUNT); + ecma_assert_object_type_is_valid (type); switch (type) { @@ -329,6 +341,7 @@ ecma_op_object_delete (ecma_object_t *obj_p, /**< the object */ case ECMA_OBJECT_TYPE_ARRAY: case ECMA_OBJECT_TYPE_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION: case ECMA_OBJECT_TYPE_EXTENSION: case ECMA_OBJECT_TYPE_STRING: @@ -344,14 +357,11 @@ ecma_op_object_delete (ecma_object_t *obj_p, /**< the object */ property_name_p, is_throw); } - - default: - { - JERRY_ASSERT (false); - - return ecma_make_empty_completion_value (); - } } + + JERRY_ASSERT (false); + + return ecma_make_empty_completion_value (); } /* ecma_op_object_delete */ /** @@ -371,7 +381,7 @@ ecma_op_object_default_value (ecma_object_t *obj_p, /**< the object */ && !ecma_is_lexical_environment (obj_p)); const ecma_object_type_t type = ecma_get_object_type (obj_p); - JERRY_ASSERT (type < ECMA_OBJECT_TYPE__COUNT); + ecma_assert_object_type_is_valid (type); /* * typedef ecma_property_t* (*default_value_ptr_t) (ecma_object_t *, ecma_string_t *); @@ -381,6 +391,7 @@ ecma_op_object_default_value (ecma_object_t *obj_p, /**< the object */ * [ECMA_OBJECT_TYPE_ARRAY] = &ecma_op_general_object_default_value, * [ECMA_OBJECT_TYPE_FUNCTION] = &ecma_op_general_object_default_value, * [ECMA_OBJECT_TYPE_BOUND_FUNCTION] = &ecma_op_general_object_default_value, + * [ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION] = &ecma_op_general_object_default_value, * [ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION] = &ecma_op_general_object_default_value, * [ECMA_OBJECT_TYPE_EXTENSION] = &ecma_op_general_object_default_value, * [ECMA_OBJECT_TYPE_ARGUMENTS] = &ecma_op_general_object_default_value, @@ -414,13 +425,14 @@ ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */ JERRY_ASSERT(property_name_p != NULL); const ecma_object_type_t type = ecma_get_object_type (obj_p); - JERRY_ASSERT (type < ECMA_OBJECT_TYPE__COUNT); + ecma_assert_object_type_is_valid (type); switch (type) { case ECMA_OBJECT_TYPE_GENERAL: case ECMA_OBJECT_TYPE_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION: case ECMA_OBJECT_TYPE_EXTENSION: case ECMA_OBJECT_TYPE_STRING: @@ -446,14 +458,11 @@ ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */ property_desc_p, is_throw); } - - default: - { - JERRY_ASSERT (false); - - return ecma_make_empty_completion_value (); - } } + + JERRY_ASSERT (false); + + return ecma_make_empty_completion_value (); } /* ecma_op_object_define_own_property */ /** @@ -470,6 +479,7 @@ ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */ && !ecma_is_lexical_environment (obj_p)); const ecma_object_type_t type = ecma_get_object_type (obj_p); + ecma_assert_object_type_is_valid (type); switch (type) { @@ -483,17 +493,12 @@ ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */ } case ECMA_OBJECT_TYPE_FUNCTION: - case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION: { return ecma_op_function_has_instance (obj_p, value); } - - case ECMA_OBJECT_TYPE__COUNT: - { - break; - } } JERRY_UNREACHABLE(); diff --git a/jerry-core/jerry-api.h b/jerry-core/jerry-api.h index 86d27afd5..a957e3cc5 100644 --- a/jerry-core/jerry-api.h +++ b/jerry-core/jerry-api.h @@ -83,10 +83,11 @@ typedef struct jerry_api_value_t /** * Jerry external function handler type */ -typedef bool (*jerry_external_handler_t) (const jerry_api_value_t *this_p, - const jerry_api_value_t *args_p [], - const int16_t args_cnt, - jerry_api_value_t *ret_val_p); +typedef bool (*jerry_external_handler_t) (const jerry_api_object_t *function_obj_p, + const jerry_api_value_t *this_p, + jerry_api_value_t *ret_val_p, + const jerry_api_value_t args_p [], + const uint16_t args_count); extern EXTERN_C ssize_t jerry_api_string_to_char_buffer (const jerry_api_string_t *string_p, @@ -110,7 +111,7 @@ jerry_api_string_t* jerry_api_create_string (const char *v); extern EXTERN_C jerry_api_object_t* jerry_api_create_object (void); extern EXTERN_C -jerry_api_object_t* jerry_api_create_external_function (jerry_external_handler_t handler); +jerry_api_object_t* jerry_api_create_external_function (jerry_external_handler_t handler_p); extern EXTERN_C bool jerry_api_is_function (const jerry_api_object_t *object_p); diff --git a/jerry-core/jerry-internal.h b/jerry-core/jerry-internal.h new file mode 100644 index 000000000..ee4bb98c0 --- /dev/null +++ b/jerry-core/jerry-internal.h @@ -0,0 +1,33 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef JERRY_INTERNAL + # error "The header is for Jerry's internal interfaces" +#endif + +#ifndef JERRY_INTERNAL_H +#define JERRY_INTERNAL_H + +#include "ecma-globals.h" +#include "jerry-api.h" + +extern ecma_completion_value_t +jerry_dispatch_external_function (ecma_object_t *function_object_p, + ecma_external_pointer_t handler_p, + const ecma_value_t& this_arg_value, + const ecma_value_t args_p [], + ecma_length_t args_count); + +#endif /* !JERRY_INTERNAL_H */ diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index 5596fec08..80b9a5ad8 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -23,7 +23,6 @@ #include "ecma-gc.h" #include "ecma-helpers.h" #include "ecma-init-finalize.h" -#include "ecma-lex-env.h" #include "ecma-objects.h" #include "ecma-objects-general.h" #include "jerry.h" @@ -32,6 +31,9 @@ #include "serializer.h" #include "vm.h" +#define JERRY_INTERNAL +#include "jerry-internal.h" + /** * Jerry engine build date */ @@ -351,16 +353,76 @@ jerry_api_create_object (void) * @return pointer to created external function object */ jerry_api_object_t* -jerry_api_create_external_function (jerry_external_handler_t handler) +jerry_api_create_external_function (jerry_external_handler_t handler_p) /**< pointer to native handler + * for the function */ { - return ecma_op_create_function_object (NULL, - 0, - ecma_get_globl_lexical_environment (), - false, - 0, - true, - handler); -} /* jerry_api_create_object */ + return ecma_op_create_external_function_object ((ecma_external_pointer_t) handler_p); +} /* jerry_api_create_external_function */ + +/** + * Dispatch call to specified external function using the native handler + * + * Note: + * if called native handler returns true, then dispatcher just returns value received + * through 'return value' output argument, otherwise - throws the value as an exception. + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +ecma_completion_value_t +jerry_dispatch_external_function (ecma_object_t *function_object_p, /**< external function object */ + ecma_external_pointer_t handler_p, /**< pointer to the function's native handler */ + const ecma_value_t& this_arg_value, /**< 'this' argument */ + const ecma_value_t args_p [], /**< arguments list */ + ecma_length_t args_count) /**< number of arguments */ +{ + JERRY_STATIC_ASSERT (sizeof (args_count) == sizeof (uint16_t)); + + ecma_completion_value_t completion_value; + + MEM_DEFINE_LOCAL_ARRAY (api_arg_values, args_count, jerry_api_value_t); + + for (uint32_t i = 0; i < args_count; ++i) + { + jerry_api_convert_ecma_value_to_api_value (&api_arg_values [i], args_p [i]); + } + + jerry_api_value_t api_this_arg_value, api_ret_value; + jerry_api_convert_ecma_value_to_api_value (&api_this_arg_value, this_arg_value); + + // default return value + jerry_api_convert_ecma_value_to_api_value (&api_ret_value, + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); + + bool is_successful = ((jerry_external_handler_t) handler_p) (function_object_p, + &api_this_arg_value, + &api_ret_value, + api_arg_values, + args_count); + + ecma_value_t ret_value; + jerry_api_convert_api_value_to_ecma_value (&ret_value, &api_ret_value); + + if (is_successful) + { + completion_value = ecma_make_normal_completion_value (ret_value); + } + else + { + completion_value = ecma_make_throw_completion_value (ret_value); + } + + jerry_api_release_value (&api_ret_value); + jerry_api_release_value (&api_this_arg_value); + for (uint32_t i = 0; i < args_count; i++) + { + jerry_api_release_value (&api_arg_values [i]); + } + + MEM_FINALIZE_LOCAL_ARRAY (api_arg_values); + + return completion_value; +} /* jerry_dispatch_external_function */ /** * Check if the specified object is a function object. diff --git a/jerry-core/vm/opcodes.cpp b/jerry-core/vm/opcodes.cpp index f03031602..8f74d2e77 100644 --- a/jerry-core/vm/opcodes.cpp +++ b/jerry-core/vm/opcodes.cpp @@ -580,9 +580,7 @@ opfunc_func_expr_n (opcode_t opdata, /**< operation data */ params_number, scope_p, is_strict, - false, - int_data->pos, - 0); + int_data->pos); ret_value = set_variable_value (int_data, lit_oc, dst_var_idx, diff --git a/tests/unit/test_api.cpp b/tests/unit/test_api.cpp index eab1290bc..871f80c6f 100644 --- a/tests/unit/test_api.cpp +++ b/tests/unit/test_api.cpp @@ -34,7 +34,10 @@ const char *test_source = ( "this.t = 12; " "} " "this.A = A; " - "this.a = new A (); " + "this.a = new A ();" + "function call_external () {" + " return this.external ('1', true);" + "}" ); /** @@ -59,15 +62,47 @@ test_api_init_api_value_string (jerry_api_value_t *out_value_p, /**< out: API va out_value_p->v_string = jerry_api_create_string (v); } /* test_api_init_api_value_string */ -static bool -handler (const jerry_api_value_t *this_p, - const jerry_api_value_t *args_p [], - const int16_t args_cnt, - jerry_api_value_t *ret_val_p) +/** + * Initialize Jerry API value with specified object + */ +static void +test_api_init_api_value_object (jerry_api_value_t *out_value_p, /**< out: API value */ + jerry_api_object_t* v) /**< object value to initialize with */ { - printf("ok %p %p %d %p\n", this_p, args_p, args_cnt, ret_val_p); + jerry_api_acquire_object (v); + + out_value_p->type = JERRY_API_DATA_TYPE_OBJECT; + out_value_p->v_object = v; +} /* test_api_init_api_value_object */ + +static bool +handler (const jerry_api_object_t *function_obj_p, + const jerry_api_value_t *this_p, + jerry_api_value_t *ret_val_p, + const jerry_api_value_t args_p [], + const uint16_t args_cnt) +{ + char buffer [32]; + ssize_t sz; + + printf ("ok %p %p %p %d %p\n", function_obj_p, this_p, args_p, args_cnt, ret_val_p); + + assert (args_cnt == 2); + + assert (args_p [0].type == JERRY_API_DATA_TYPE_STRING); + sz = jerry_api_string_to_char_buffer (args_p [0].v_string, NULL, 0); + assert (sz == -2); + sz = jerry_api_string_to_char_buffer (args_p [0].v_string, buffer, -sz); + assert (sz == 2); + assert (!strcmp (buffer, "1")); + + assert (args_p [1].type == JERRY_API_DATA_TYPE_BOOLEAN); + assert (args_p [1].v_bool == true); + + test_api_init_api_value_string (ret_val_p, "string from handler"); + return true; -} +} /* handler */ int @@ -78,10 +113,11 @@ main (void) bool is_ok; ssize_t sz; jerry_api_value_t val_t, val_foo, val_bar, val_A, val_A_prototype, val_a, val_a_foo; + jerry_api_value_t val_external, val_call_external; jerry_api_object_t* global_obj_p; jerry_api_object_t* external_func_p; jerry_api_value_t res, args [2]; - char buffer [16]; + char buffer [32]; is_ok = jerry_parse (NULL, test_source, strlen (test_source)); assert (is_ok); @@ -192,15 +228,37 @@ main (void) jerry_api_release_value (&res); jerry_api_release_value (&val_a_foo); + jerry_api_release_value (&val_a); + + // Create native handler bound function object and set it to 'external' variable external_func_p = jerry_api_create_external_function (handler); assert (external_func_p != NULL); - is_ok = jerry_api_call_function (external_func_p, global_obj_p, &res, NULL, 0); + test_api_init_api_value_object (&val_external, external_func_p); + is_ok = jerry_api_set_object_field_value (global_obj_p, + "external", + &val_external); assert (is_ok); - + jerry_api_release_value (&val_external); jerry_api_release_object (external_func_p); - jerry_api_release_value (&val_a); + // Call 'call_external' function that should call external function created above + is_ok = jerry_api_get_object_field_value (global_obj_p, "call_external", &val_call_external); + assert (is_ok + && val_call_external.type == JERRY_API_DATA_TYPE_OBJECT); + is_ok = jerry_api_call_function (val_call_external.v_object, + global_obj_p, + &res, + NULL, 0); + jerry_api_release_value (&val_call_external); + assert (is_ok + && res.type == JERRY_API_DATA_TYPE_STRING); + sz = jerry_api_string_to_char_buffer (res.v_string, NULL, 0); + assert (sz == -20); + sz = jerry_api_string_to_char_buffer (res.v_string, buffer, -sz); + assert (sz == 20); + jerry_api_release_value (&res); + assert (!strcmp (buffer, "string from handler")); jerry_api_release_object (global_obj_p);