diff --git a/src/libcoreint/interpreter.c b/src/libcoreint/interpreter.c index a9a4d5e74..63a52768e 100644 --- a/src/libcoreint/interpreter.c +++ b/src/libcoreint/interpreter.c @@ -47,14 +47,14 @@ run_int (void) JERRY_ASSERT( __program != NULL ); const interp_bytecode_idx start_pos = 0; - ecma_object_t *this_binding_p = NULL; + ecma_value_t this_binding_value = ecma_make_simple_value( ECMA_SIMPLE_VALUE_UNDEFINED); ecma_object_t *lex_env_p = ecma_create_lexical_environment (NULL, ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); FIXME( Strict mode ); const bool is_strict = false; ecma_completion_value_t completion = run_int_from_pos (start_pos, - this_binding_p, + this_binding_value, lex_env_p, is_strict); @@ -89,7 +89,7 @@ run_int (void) ecma_completion_value_t run_int_from_pos (interp_bytecode_idx start_pos, - ecma_object_t *this_binding_p, + ecma_value_t this_binding_value, ecma_object_t *lex_env_p, bool is_strict) { @@ -112,7 +112,7 @@ run_int_from_pos (interp_bytecode_idx start_pos, struct __int_data int_data; int_data.pos = (interp_bytecode_idx) (start_pos + 1); - int_data.this_binding_p = this_binding_p; + int_data.this_binding = this_binding_value; int_data.lex_env_p = lex_env_p; int_data.is_strict = is_strict; int_data.min_reg_num = min_reg_num; diff --git a/src/libcoreint/interpreter.h b/src/libcoreint/interpreter.h index d82473b10..0c524e4b2 100644 --- a/src/libcoreint/interpreter.h +++ b/src/libcoreint/interpreter.h @@ -25,7 +25,7 @@ typedef uint16_t interp_bytecode_idx; struct __int_data { interp_bytecode_idx pos; /**< current opcode to execute */ - ecma_object_t *this_binding_p; /**< this binding for current context */ + ecma_value_t this_binding; /**< this binding for current context */ ecma_object_t *lex_env_p; /**< current lexical environment */ bool is_strict; /**< is current code execution mode strict? */ T_IDX min_reg_num; /**< minimum idx used for register identification */ @@ -36,7 +36,7 @@ struct __int_data void init_int (const OPCODE* program_p); bool run_int (void); ecma_completion_value_t run_int_from_pos (interp_bytecode_idx start_pos, - ecma_object_t *this_binding_p, + ecma_value_t this_binding_value, ecma_object_t *lex_env_p, bool is_strict); diff --git a/src/libcoreint/opcodes.c b/src/libcoreint/opcodes.c index 34d307d33..e9e468fea 100644 --- a/src/libcoreint/opcodes.c +++ b/src/libcoreint/opcodes.c @@ -1397,7 +1397,7 @@ opfunc_call_0( OPCODE opdata, /**< operation data */ ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); ret_value = run_int_from_pos( code_idx, - NULL, + ecma_make_simple_value( ECMA_SIMPLE_VALUE_UNDEFINED), new_lex_env_p, false); diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index 8230d81ab..4091395a4 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -295,7 +295,8 @@ typedef enum { Arguments (10.6), Array (15.4) specification-defined objects and not host objects */ ECMA_OBJECT_TYPE_STRING, /**< String objects (15.5) */ - ECMA_OBJECT_TYPE_FUNCTION, /**< Function objects (15.3) */ + ECMA_OBJECT_TYPE_FUNCTION, /**< Function objects (15.3), created through 13.2 routine */ + ECMA_OBJECT_TYPE_BOUND_FUNCTION, /**< Function objects (15.3), created through 15.3.4.5 routine */ ECMA_OBJECT_TYPE_ARGUMENTS, /**< Arguments object (10.6) */ ECMA_OBJECT_TYPE_ARRAY, /**< Array object (15.4) */ ECMA_OBJECT_TYPE_HOST /**< Host object */ diff --git a/src/libecmaoperations/ecma-function-object.c b/src/libecmaoperations/ecma-function-object.c index 2ca90aaef..737d34c38 100644 --- a/src/libecmaoperations/ecma-function-object.c +++ b/src/libecmaoperations/ecma-function-object.c @@ -19,6 +19,8 @@ #include "ecma-helpers.h" #include "ecma-magic-strings.h" #include "ecma-objects-properties.h" +#include "ecma-try-catch-macro.h" +#include "globals.h" /** \addtogroup ecma ---TODO--- * @{ @@ -27,6 +29,51 @@ * @{ */ +/** + * Pack 'is_strict' flag and opcode index to value + * that can be stored in an [[Code]] internal property. + * + * @return packed value + */ +static uint32_t +ecma_pack_code_internal_property_value( bool is_strict, /**< is code strict? */ + interp_bytecode_idx opcode_idx) /**< index of first opcode */ +{ + uint32_t value = opcode_idx; + const uint32_t is_strict_bit_offset = sizeof(value) * JERRY_BITSINBYTE - 1; + + JERRY_ASSERT( ( ( value ) & ( 1u << is_strict_bit_offset ) ) == 0 ); + + if ( is_strict ) + { + value |= ( 1u << is_strict_bit_offset ); + } + + return value; +} /* ecma_pack_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 interp_bytecode_idx +ecma_unpack_code_internal_property_value( uint32_t value, /**< packed value */ + bool* out_is_strict_p) /**< out: is code strict? */ +{ + JERRY_ASSERT( out_is_strict_p != NULL ); + + const uint32_t is_strict_bit_offset = sizeof(value) * JERRY_BITSINBYTE - 1; + + bool is_strict = ( ( value & ( 1u << is_strict_bit_offset ) ) != 0 ); + *out_is_strict_p = is_strict; + + interp_bytecode_idx opcode_idx = (interp_bytecode_idx) ( value & ~( 1u << is_strict_bit_offset ) ); + + return opcode_idx; +} /* ecma_unpack_code_internal_property_value */ + /** * IsCallable operation. * @@ -48,7 +95,8 @@ ecma_op_is_callable( ecma_value_t value) /**< ecma-value */ JERRY_ASSERT( obj_p != NULL ); JERRY_ASSERT( !obj_p->is_lexical_environment ); - return true; + return ( obj_p->u.object.type == ECMA_OBJECT_TYPE_FUNCTION + || obj_p->u.object.type == ECMA_OBJECT_TYPE_BOUND_FUNCTION ); } /* ecma_op_is_callable */ /** @@ -95,7 +143,8 @@ ecma_op_create_function_object( const ecma_char_t* formal_parameter_list_p[], /* // 12. ecma_property_t *code_prop_p = ecma_create_internal_property( f, ECMA_INTERNAL_PROPERTY_CODE); - code_prop_p->u.internal_property.value = first_opcode_idx; + code_prop_p->u.internal_property.value = ecma_pack_code_internal_property_value( is_strict, + first_opcode_idx); // 16. FIXME( Use 'new Object()' instead ); @@ -181,6 +230,102 @@ ecma_op_create_function_object( const ecma_char_t* formal_parameter_list_p[], /* return f; } /* ecma_op_create_function_object */ +/** + * [[Call]] implementation for Function objects, + * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) + * or 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION). + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +ecma_completion_value_t +ecma_op_function_call( ecma_object_t *func_obj_p, /**< Function object */ + ecma_value_t this_arg_value, /**< 'this' argument's value */ + ecma_value_t* arguments_list_p, /**< arguments list */ + size_t arguments_list_len) /**< length of arguments list */ +{ + JERRY_ASSERT( func_obj_p != NULL && !func_obj_p->is_lexical_environment ); + JERRY_ASSERT( ecma_op_is_callable( ecma_make_object_value( func_obj_p)) ); + JERRY_ASSERT( arguments_list_len == 0 || arguments_list_p != NULL ); + + if ( func_obj_p->u.object.type == ECMA_OBJECT_TYPE_FUNCTION ) + { + ecma_completion_value_t ret_value; + + /* 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_pointer( scope_prop_p->u.internal_property.value); + uint32_t code_prop_value = code_prop_p->u.internal_property.value; + + bool is_strict; + // 8. + interp_bytecode_idx code_first_opcode_idx = ecma_unpack_code_internal_property_value( code_prop_value, &is_strict); + + ecma_value_t this_binding; + // 1. + if ( is_strict ) + { + this_binding = ecma_copy_value( this_arg_value); + } + else if ( ecma_is_value_undefined( this_arg_value) + || ecma_is_value_null( this_arg_value) ) + { + // 2. + FIXME( Assign Global object when it will be implemented ); + + this_binding = ecma_make_simple_value( ECMA_SIMPLE_VALUE_UNDEFINED); + } + else + { + // 3., 4. + ecma_completion_value_t completion = ecma_op_to_object( this_arg_value); + JERRY_ASSERT( ecma_is_completion_value_normal( completion) ); + + this_binding = completion.value; + } + + // 5. + ecma_object_t *local_env_p = ecma_create_lexical_environment( scope_p, ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + + // 9. + /* Declaration binding instantiation (ECMA-262 v5, 10.5), block 4 */ + TODO( Perform declaration binding instantion when [[FormalParameters]] list will be supported ); + if ( arguments_list_len != 0 ) + { + JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( arguments_list_p ); + } + + ecma_completion_value_t completion = run_int_from_pos( code_first_opcode_idx, + this_binding, + local_env_p, + is_strict); + if ( ecma_is_completion_value_normal( completion) ) + { + JERRY_ASSERT( ecma_is_empty_completion_value( completion) ); + + ret_value = ecma_make_simple_completion_value( ECMA_SIMPLE_VALUE_UNDEFINED); + } + else + { + ret_value = completion; + } + + ecma_deref_object( local_env_p); + ecma_free_value( this_binding); + + return ret_value; + } + else + { + JERRY_ASSERT( func_obj_p->u.object.type == ECMA_OBJECT_TYPE_BOUND_FUNCTION ); + + JERRY_UNIMPLEMENTED(); + } +} /* ecma_op_function_call */ + /** * Get [[ThrowTypeError]] Function Object * diff --git a/src/libecmaoperations/ecma-function-object.h b/src/libecmaoperations/ecma-function-object.h index 7983af7f8..7df749008 100644 --- a/src/libecmaoperations/ecma-function-object.h +++ b/src/libecmaoperations/ecma-function-object.h @@ -37,6 +37,11 @@ ecma_op_create_function_object( const ecma_char_t* formal_parameter_list_p[], extern ecma_object_t* ecma_op_get_throw_type_error( void); +extern ecma_completion_value_t ecma_op_function_call( ecma_object_t *func_obj_p, + ecma_value_t this_arg_value, + ecma_value_t* arguments_list_p, + size_t arguments_list_len); + /** * @} * @}