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..e14d512aa 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 *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 ef4e31f3f..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,6 +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, /**< 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 */ @@ -379,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; /** @@ -442,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) @@ -810,6 +811,11 @@ 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 10e5347fc..f2f299af0 100644 --- a/jerry-core/ecma/operations/ecma-function-object.cpp +++ b/jerry-core/ecma/operations/ecma-function-object.cpp @@ -26,6 +26,9 @@ #include "ecma-try-catch-macro.h" #include "jrt.h" +#define JERRY_INTERNAL +#include "jerry-internal.h" + /** \addtogroup ecma ECMA * @{ * @@ -101,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 */ @@ -124,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 */ /** @@ -282,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. * @@ -550,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); diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index 78dd7b088..0458c5f3f 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -35,6 +35,8 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], ecma_object_t *scope_p, bool is_strict, 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-objects.cpp b/jerry-core/ecma/operations/ecma-objects.cpp index 616e0f418..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) { @@ -484,15 +494,11 @@ ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */ case ECMA_OBJECT_TYPE_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 ce5f135e1..a957e3cc5 100644 --- a/jerry-core/jerry-api.h +++ b/jerry-core/jerry-api.h @@ -80,6 +80,15 @@ typedef struct jerry_api_value_t }; } jerry_api_value_t; +/** + * Jerry external function handler type + */ +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, char *buffer_p, @@ -101,6 +110,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_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 e8cf6c103..80b9a5ad8 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -31,6 +31,9 @@ #include "serializer.h" #include "vm.h" +#define JERRY_INTERNAL +#include "jerry-internal.h" + /** * Jerry engine build date */ @@ -341,6 +344,86 @@ 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_p) /**< pointer to native handler + * for the function */ +{ + 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/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; diff --git a/tests/unit/test_api.cpp b/tests/unit/test_api.cpp index e998c1026..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,6 +62,49 @@ 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 */ +/** + * 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 */ +{ + 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 main (void) { @@ -67,9 +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); @@ -182,6 +230,36 @@ main (void) 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); + + 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); + + // 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); jerry_cleanup ();