diff --git a/src/libcoreint/opcodes.c b/src/libcoreint/opcodes.c index 783ab449f..b565ccc92 100644 --- a/src/libcoreint/opcodes.c +++ b/src/libcoreint/opcodes.c @@ -19,6 +19,7 @@ #include "ecma-helpers.h" #include "ecma-number-arithmetic.h" #include "ecma-operations.h" +#include "ecma-try-catch-macro.h" #include "globals.h" #include "interpreter.h" #include "jerry-libc.h" @@ -39,52 +40,19 @@ * * 1. At the beginning of the handler there should be declared opcode handler's 'return value' variable. * - * 2. All exceptionable operations except the last should be enclosed in TRY_CATCH macro. + * 2. All exceptionable operations except the last should be enclosed in ECMA_TRY_CATCH macro. * All subsequent operations in the opcode handler should be placed into block between - * the TRY_CATCH and corresponding FINALIZE. + * the ECMA_TRY_CATCH and corresponding ECMA_FINALIZE. * * 3. The last exceptionable's operation result should be assigned directly to opcode handler's - * 'return value' variable without using TRY_CATCH macro. + * 'return value' variable without using ECMA_TRY_CATCH macro. * - * 4. After last FINALIZE statement there should be only one operator. + * 4. After last ECMA_FINALIZE statement there should be only one operator. * The operator should return from the opcode handler with it's 'return value'. * * 5. No other operations with opcode handler's 'return value' variable should be performed. */ -/** - * The macro defines try-block that initializes variable 'var' with 'op' - * and checks for exceptions that might be thrown during initialization. - * - * If no exception was thrown, then code after the try-block is executed. - * Otherwise, throw-completion value is just copied to return_value. - * - * Note: - * Each TRY_CATCH should have it's own corresponding FINALIZE - * statement with same argument as corresponding TRY_CATCH's first argument. - */ -#define TRY_CATCH(var, op, return_value) \ - ecma_completion_value_t var = op; \ - if ( unlikely( ecma_is_completion_value_throw( var) ) ) \ - { \ - return_value = ecma_copy_completion_value( var); \ - } \ - else \ - { \ - JERRY_ASSERT( ecma_is_completion_value_normal( var) ) - -/** - * The macro marks end of code block that is executed if no exception - * was catched by corresponding TRY_CATCH and frees variable, - * initialized by the TRY_CATCH. - * - * Note: - * Each TRY_CATCH should be followed by FINALIZE with same - * argument as corresponding TRY_CATCH's first argument. - */ -#define FINALIZE(var) } \ - ecma_free_completion_value( var) - /** * String literal copy descriptor. */ @@ -312,8 +280,8 @@ do_number_arithmetic(struct __int_data *int_data, /**< interpreter context */ { ecma_completion_value_t ret_value; - TRY_CATCH(num_left_value, ecma_op_to_number( left_value), ret_value); - TRY_CATCH(num_right_value, ecma_op_to_number( right_value), ret_value); + ECMA_TRY_CATCH(num_left_value, ecma_op_to_number( left_value), ret_value); + ECMA_TRY_CATCH(num_right_value, ecma_op_to_number( right_value), ret_value); ecma_number_t *left_p, *right_p, *res_p; left_p = (ecma_number_t*)ecma_get_pointer( num_left_value.value.value); @@ -346,8 +314,8 @@ do_number_arithmetic(struct __int_data *int_data, /**< interpreter context */ ecma_dealloc_number( res_p); - FINALIZE( num_right_value); - FINALIZE( num_left_value); + ECMA_FINALIZE( num_right_value); + ECMA_FINALIZE( num_left_value); return ret_value; } /* do_number_arithmetic */ @@ -446,13 +414,13 @@ opfunc_call_1 (OPCODE opdata __unused, struct __int_data *int_data) if (!__strcmp ((const char*)str_value.str_p, "LEDToggle")) { - TRY_CATCH (cond_value, get_variable_value (int_data, opdata.data.call_1.arg1_lit_idx, false), ret_value); + ECMA_TRY_CATCH (cond_value, get_variable_value (int_data, opdata.data.call_1.arg1_lit_idx, false), ret_value); JERRY_ASSERT(cond_value.value.value_type == ECMA_TYPE_NUMBER ); ecma_number_t * num_p = (ecma_number_t*)ecma_get_pointer(cond_value.value.value); uint32_t int_num = (uint32_t)*num_p; led_blink_once (int_num); ret_value = ecma_make_empty_completion_value (); - FINALIZE (cond_value); + ECMA_FINALIZE (cond_value); } free_string_literal_copy (&str_value); @@ -476,7 +444,7 @@ opfunc_is_true_jmp (OPCODE opdata, /**< operation data */ ecma_completion_value_t ret_value; - TRY_CATCH(cond_value, get_variable_value( int_data, cond_var_idx, false), ret_value); + ECMA_TRY_CATCH(cond_value, get_variable_value( int_data, cond_var_idx, false), ret_value); ecma_completion_value_t to_bool_completion = ecma_op_to_boolean( cond_value.value); JERRY_ASSERT( ecma_is_completion_value_normal( to_bool_completion) ); @@ -492,7 +460,7 @@ opfunc_is_true_jmp (OPCODE opdata, /**< operation data */ ret_value = ecma_make_empty_completion_value(); - FINALIZE(cond_value); + ECMA_FINALIZE(cond_value); return ret_value; } /* opfunc_is_true_jmp */ @@ -513,7 +481,7 @@ opfunc_is_false_jmp (OPCODE opdata, /**< operation data */ ecma_completion_value_t ret_value; - TRY_CATCH(cond_value, get_variable_value( int_data, cond_var_idx, false), ret_value); + ECMA_TRY_CATCH(cond_value, get_variable_value( int_data, cond_var_idx, false), ret_value); ecma_completion_value_t to_bool_completion = ecma_op_to_boolean( cond_value.value); JERRY_ASSERT( ecma_is_completion_value_normal( to_bool_completion) ); @@ -529,7 +497,7 @@ opfunc_is_false_jmp (OPCODE opdata, /**< operation data */ ret_value = ecma_make_empty_completion_value(); - FINALIZE(cond_value); + ECMA_FINALIZE(cond_value); return ret_value; } /* opfunc_is_false_jmp */ @@ -700,10 +668,10 @@ opfunc_addition(OPCODE opdata, /**< operation data */ ecma_completion_value_t ret_value; - TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); - TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); - TRY_CATCH(prim_left_value, ecma_op_to_primitive( left_value.value), ret_value); - TRY_CATCH(prim_right_value, ecma_op_to_primitive( right_value.value), ret_value); + ECMA_TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); + ECMA_TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); + ECMA_TRY_CATCH(prim_left_value, ecma_op_to_primitive( left_value.value, ECMA_PREFERRED_TYPE_NO), ret_value); + ECMA_TRY_CATCH(prim_right_value, ecma_op_to_primitive( right_value.value, ECMA_PREFERRED_TYPE_NO), ret_value); if ( prim_left_value.value.value_type == ECMA_TYPE_STRING || prim_right_value.value.value_type == ECMA_TYPE_STRING ) @@ -719,10 +687,10 @@ opfunc_addition(OPCODE opdata, /**< operation data */ prim_right_value.value); } - FINALIZE(prim_right_value); - FINALIZE(prim_left_value); - FINALIZE(right_value); - FINALIZE(left_value); + ECMA_FINALIZE(prim_right_value); + ECMA_FINALIZE(prim_left_value); + ECMA_FINALIZE(right_value); + ECMA_FINALIZE(left_value); return ret_value; } /* opfunc_addition */ @@ -747,8 +715,8 @@ opfunc_substraction(OPCODE opdata, /**< operation data */ ecma_completion_value_t ret_value; - TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); - TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); + ECMA_TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); + ECMA_TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); ret_value = do_number_arithmetic(int_data, dst_var_idx, @@ -756,8 +724,8 @@ opfunc_substraction(OPCODE opdata, /**< operation data */ left_value.value, right_value.value); - FINALIZE(right_value); - FINALIZE(left_value); + ECMA_FINALIZE(right_value); + ECMA_FINALIZE(left_value); return ret_value; } /* opfunc_substraction */ @@ -782,8 +750,8 @@ opfunc_multiplication(OPCODE opdata, /**< operation data */ ecma_completion_value_t ret_value; - TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); - TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); + ECMA_TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); + ECMA_TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); ret_value = do_number_arithmetic(int_data, dst_var_idx, @@ -791,8 +759,8 @@ opfunc_multiplication(OPCODE opdata, /**< operation data */ left_value.value, right_value.value); - FINALIZE(right_value); - FINALIZE(left_value); + ECMA_FINALIZE(right_value); + ECMA_FINALIZE(left_value); return ret_value; } /* opfunc_multiplication */ @@ -817,8 +785,8 @@ opfunc_division(OPCODE opdata, /**< operation data */ ecma_completion_value_t ret_value; - TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); - TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); + ECMA_TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); + ECMA_TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); ret_value = do_number_arithmetic(int_data, dst_var_idx, @@ -826,8 +794,8 @@ opfunc_division(OPCODE opdata, /**< operation data */ left_value.value, right_value.value); - FINALIZE(right_value); - FINALIZE(left_value); + ECMA_FINALIZE(right_value); + ECMA_FINALIZE(left_value); return ret_value; } /* opfunc_division */ @@ -852,8 +820,8 @@ opfunc_remainder(OPCODE opdata, /**< operation data */ ecma_completion_value_t ret_value; - TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); - TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); + ECMA_TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); + ECMA_TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); ret_value = do_number_arithmetic(int_data, dst_var_idx, @@ -861,8 +829,8 @@ opfunc_remainder(OPCODE opdata, /**< operation data */ left_value.value, right_value.value); - FINALIZE(right_value); - FINALIZE(left_value); + ECMA_FINALIZE(right_value); + ECMA_FINALIZE(left_value); return ret_value; } /* opfunc_remainder */ diff --git a/src/libecmaoperations/ecma-comparison.c b/src/libecmaoperations/ecma-comparison.c index d07025431..134721326 100644 --- a/src/libecmaoperations/ecma-comparison.c +++ b/src/libecmaoperations/ecma-comparison.c @@ -14,7 +14,9 @@ */ #include "ecma-comparison.h" +#include "ecma-conversion.h" #include "ecma-globals.h" +#include "ecma-try-catch-macro.h" #include "globals.h" /** \addtogroup ecma ---TODO--- @@ -99,6 +101,74 @@ ecma_abstract_equality_compare(ecma_value_t x, /**< first operand */ } } /* ecma_abstract_equality_compare */ +/** + * ECMA abstract relational comparison routine. + * + * See also: ECMA-262 v5, 11.8.5 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +ecma_completion_value_t +ecma_abstract_relational_compare(ecma_value_t x, /**< first operand */ + ecma_value_t y, /**< second operand */ + bool left_first) /**< 'LeftFirst' flag */ +{ + ecma_completion_value_t ret_value, px, py; + + ecma_value_t first_converted_value = left_first ? x : y; + ecma_value_t second_converted_value = left_first ? y : x; + + // 1., 2. + ECMA_TRY_CATCH( prim_first_converted_value, ecma_op_to_primitive( first_converted_value, ECMA_PREFERRED_TYPE_NUMBER), ret_value); + ECMA_TRY_CATCH( prim_second_converted_value, ecma_op_to_primitive( second_converted_value, ECMA_PREFERRED_TYPE_NUMBER), ret_value); + + px = left_first ? prim_first_converted_value : prim_second_converted_value; + py = left_first ? prim_second_converted_value : prim_first_converted_value; + + const bool is_px_string = ( px.value.value_type == ECMA_TYPE_STRING ); + const bool is_py_string = ( py.value.value_type == ECMA_TYPE_STRING ); + + if ( !( is_px_string && is_py_string ) ) + { // 3. + // a. + ECMA_TRY_CATCH( nx, ecma_op_to_number( px.value), ret_value); + + // b. + ECMA_TRY_CATCH( ny, ecma_op_to_number( py.value), ret_value); + + ecma_number_t* num_x_p = (ecma_number_t*)ecma_get_pointer( nx.value.value); + ecma_number_t* num_y_p = (ecma_number_t*)ecma_get_pointer( ny.value.value); + + TODO( /* Implement according to ECMA */ ); + + if ( *num_x_p >= *num_y_p ) + { + ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, + ecma_make_simple_value( ECMA_SIMPLE_VALUE_FALSE), + ECMA_TARGET_ID_RESERVED); + } + else + { + ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, + ecma_make_simple_value( ECMA_SIMPLE_VALUE_TRUE), + ECMA_TARGET_ID_RESERVED); + } + + ECMA_FINALIZE( ny); + ECMA_FINALIZE( nx); + } + else + { // 4. + JERRY_UNIMPLEMENTED(); + } + + ECMA_FINALIZE( prim_second_converted_value); + ECMA_FINALIZE( prim_first_converted_value); + + return ret_value; +} /* ecma_abstract_relational_compare */ + /** * @} * @} diff --git a/src/libecmaoperations/ecma-comparison.h b/src/libecmaoperations/ecma-comparison.h index bdb305578..2e810f425 100644 --- a/src/libecmaoperations/ecma-comparison.h +++ b/src/libecmaoperations/ecma-comparison.h @@ -27,6 +27,7 @@ */ extern bool ecma_abstract_equality_compare( ecma_value_t x, ecma_value_t y); +extern ecma_completion_value_t ecma_abstract_relational_compare(ecma_value_t x, ecma_value_t y, bool left_first); /** * @} diff --git a/src/libecmaoperations/ecma-conversion.c b/src/libecmaoperations/ecma-conversion.c index df77f9b5a..b42a90f0b 100644 --- a/src/libecmaoperations/ecma-conversion.c +++ b/src/libecmaoperations/ecma-conversion.c @@ -91,7 +91,8 @@ ecma_op_check_object_coercible( ecma_value_t value) /**< ecma-value */ * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t -ecma_op_to_primitive( ecma_value_t value) /**< ecma-value */ +ecma_op_to_primitive( ecma_value_t value, /**< ecma-value */ + ecma_preferred_type_hint preferred_type) /**< preferred type hint */ { switch ( (ecma_type_t)value.value_type ) { @@ -105,7 +106,7 @@ ecma_op_to_primitive( ecma_value_t value) /**< ecma-value */ } case ECMA_TYPE_OBJECT: { - JERRY_UNIMPLEMENTED(); + JERRY_UNIMPLEMENTED_REF_UNUSED_VARS(preferred_type); } case ECMA_TYPE__COUNT: { @@ -215,7 +216,7 @@ ecma_op_to_number( ecma_value_t value) /**< ecma-value */ } case ECMA_TYPE_OBJECT: { - ecma_completion_value_t completion_to_primitive = ecma_op_to_primitive( value); + ecma_completion_value_t completion_to_primitive = ecma_op_to_primitive( value, ECMA_PREFERRED_TYPE_NUMBER); JERRY_ASSERT( ecma_is_completion_value_normal( completion_to_primitive) ); ecma_completion_value_t completion_to_number = ecma_op_to_number( completion_to_primitive.value); diff --git a/src/libecmaoperations/ecma-conversion.h b/src/libecmaoperations/ecma-conversion.h index eaa02eb39..1fbc67b01 100644 --- a/src/libecmaoperations/ecma-conversion.h +++ b/src/libecmaoperations/ecma-conversion.h @@ -26,8 +26,22 @@ * @{ */ +/** + * Second argument of 'ToPrimitive' operation that is a hint, + * specifying the preferred type of conversion result. + */ +typedef enum +{ + ECMA_PREFERRED_TYPE_NO, /**< no preferred type is specified */ + ECMA_PREFERRED_TYPE_UNDEFINED, /**< Undefined */ + ECMA_PREFERRED_TYPE_NULL, /**< Null */ + ECMA_PREFERRED_TYPE_BOOLEAN, /**< Boolean */ + ECMA_PREFERRED_TYPE_NUMBER, /**< Number */ + ECMA_PREFERRED_TYPE_STRING /**< String */ +} ecma_preferred_type_hint; + extern ecma_completion_value_t ecma_op_check_object_coercible( ecma_value_t value); -extern ecma_completion_value_t ecma_op_to_primitive( ecma_value_t value); +extern ecma_completion_value_t ecma_op_to_primitive( ecma_value_t value, ecma_preferred_type_hint preferred_type); extern ecma_completion_value_t ecma_op_to_boolean( ecma_value_t value); extern ecma_completion_value_t ecma_op_to_number( ecma_value_t value); extern ecma_completion_value_t ecma_op_to_object( ecma_value_t value);