2014-08-15 18:30:47 +04:00

1979 lines
66 KiB
C

/* Copyright 2014 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.
*/
#include "ecma-alloc.h"
#include "ecma-comparison.h"
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
#include "ecma-function-object.h"
#include "ecma-gc.h"
#include "ecma-helpers.h"
#include "ecma-magic-strings.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"
#include "mem-heap.h"
#include "opcodes.h"
#include "actuators.h"
#include "common-io.h"
#include "sensors.h"
/**
* Note:
* The note describes exception handling in opcode handlers that perform operations,
* that can throw exceptions, and do not themself handle the exceptions.
*
* Generally, each opcode handler consists of sequence of operations.
* Some of these operations (exceptionable operations) can throw exceptions and other - cannot.
*
* 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 ECMA_TRY_CATCH macro.
* All subsequent operations in the opcode handler should be placed into block between
* 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 ECMA_TRY_CATCH macro.
*
* 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.
*/
/**
* String literal copy descriptor.
*/
typedef struct
{
ecma_char_t *str_p; /**< pointer to copied string literal */
ecma_char_t literal_copy[32]; /**< buffer with string literal,
if it is stored locally
(i.e. not in the heap) */
} string_literal_copy;
/**
* Initialize string literal copy.
*/
static void
init_string_literal_copy (T_IDX idx, /**< literal identifier */
string_literal_copy *str_lit_descr_p) /**< pointer to string literal copy descriptor */
{
JERRY_ASSERT (str_lit_descr_p != NULL);
ssize_t sz = try_get_string_by_idx (idx,
str_lit_descr_p->literal_copy,
sizeof (str_lit_descr_p->literal_copy));
if (sz > 0)
{
str_lit_descr_p->str_p = str_lit_descr_p->literal_copy;
}
else
{
JERRY_ASSERT (sz < 0);
ssize_t req_sz = -sz;
str_lit_descr_p->str_p = mem_heap_alloc_block ((size_t) req_sz,
MEM_HEAP_ALLOC_SHORT_TERM);
sz = try_get_string_by_idx (idx,
str_lit_descr_p->str_p,
req_sz);
JERRY_ASSERT (sz > 0);
}
} /* init_string_literal */
/**
* Free string literal copy.
*/
static void
free_string_literal_copy (string_literal_copy *str_lit_descr_p) /**< string literal copy descriptor */
{
JERRY_ASSERT (str_lit_descr_p != NULL);
JERRY_ASSERT (str_lit_descr_p->str_p != NULL);
if (str_lit_descr_p->str_p == str_lit_descr_p->literal_copy)
{
/* copy is inside descriptor */
}
else
{
mem_heap_free_block (str_lit_descr_p->str_p);
}
str_lit_descr_p->str_p = NULL;
return;
} /* free_string_literal */
/**
* Perform so-called 'strict eval or arguments reference' check
* that is used in definition of several statement handling algorithms,
* but has no ECMA-defined name.
*
* @return true - if ref is strict reference
* and it's base is lexical environment
* and it's referenced name is 'eval' or 'arguments';
* false - otherwise.
*/
static bool
do_strict_eval_arguments_check (ecma_reference_t ref) /**< ECMA-reference */
{
const ecma_char_t* magic_string_eval = ecma_get_magic_string (ECMA_MAGIC_STRING_EVAL);
const ecma_char_t* magic_string_arguments = ecma_get_magic_string (ECMA_MAGIC_STRING_ARGUMENTS);
return (ref.is_strict
&& (ecma_compare_zt_string_to_zt_string (ref.referenced_name_p,
magic_string_eval) == 0
|| ecma_compare_zt_string_to_zt_string (ref.referenced_name_p,
magic_string_arguments) == 0)
&& (ref.base.value_type == ECMA_TYPE_OBJECT)
&& (ECMA_GET_POINTER (ref.base.value) != NULL)
&& (((ecma_object_t*) ECMA_GET_POINTER (ref.base.value))->is_lexical_environment));
} /* do_strict_eval_arguments_check */
/**
* Get variable's value.
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
static ecma_completion_value_t
get_variable_value (struct __int_data *int_data, /**< interpreter context */
T_IDX var_idx, /**< variable identifier */
bool do_eval_or_arguments_check) /** run 'strict eval or arguments reference' check
See also: do_strict_eval_arguments_check */
{
ecma_completion_value_t ret_value;
if (var_idx >= int_data->min_reg_num
&& var_idx <= int_data->max_reg_num)
{
ecma_value_t reg_value = int_data->regs_p[ var_idx - int_data->min_reg_num ];
JERRY_ASSERT (!ecma_is_value_empty (reg_value));
ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL,
ecma_copy_value (reg_value, true),
ECMA_TARGET_ID_RESERVED);
}
else
{
string_literal_copy var_name;
ecma_reference_t ref;
init_string_literal_copy (var_idx, &var_name);
ref = ecma_op_get_identifier_reference (int_data->lex_env_p,
var_name.str_p,
int_data->is_strict);
if (unlikely (do_eval_or_arguments_check
&& do_strict_eval_arguments_check (ref)))
{
ret_value = ecma_make_throw_value (ecma_new_standard_error (ECMA_ERROR_SYNTAX));
}
else
{
ret_value = ecma_op_get_value (ref);
}
ecma_free_reference (ref);
free_string_literal_copy (&var_name);
}
return ret_value;
} /* get_variable_value */
/**
* Set variable's value.
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
static ecma_completion_value_t
set_variable_value (struct __int_data *int_data, /**< interpreter context */
T_IDX var_idx, /**< variable identifier */
ecma_value_t value) /**< value to set */
{
ecma_completion_value_t ret_value;
if (var_idx >= int_data->min_reg_num
&& var_idx <= int_data->max_reg_num)
{
ecma_value_t reg_value = int_data->regs_p[ var_idx - int_data->min_reg_num ];
if (!ecma_is_value_empty (reg_value))
{
ecma_free_value (reg_value, true);
}
int_data->regs_p[ var_idx - int_data->min_reg_num ] = ecma_copy_value (value, true);
ret_value = ecma_make_empty_completion_value ();
}
else
{
string_literal_copy var_name;
ecma_reference_t ref;
init_string_literal_copy (var_idx, &var_name);
ref = ecma_op_get_identifier_reference (int_data->lex_env_p,
var_name.str_p,
int_data->is_strict);
if (unlikely (do_strict_eval_arguments_check (ref)))
{
ret_value = ecma_make_throw_value (ecma_new_standard_error (ECMA_ERROR_SYNTAX));
}
else
{
ret_value = ecma_op_put_value (ref, value);
}
ecma_free_reference (ref);
free_string_literal_copy (&var_name);
}
return ret_value;
} /* set_variable_value */
/**
* Number arithmetic operations.
*/
typedef enum
{
number_arithmetic_addition, /**< addition */
number_arithmetic_substraction, /**< substraction */
number_arithmetic_multiplication, /**< multiplication */
number_arithmetic_division, /**< division */
number_arithmetic_remainder, /**< remainder calculation */
} number_arithmetic_op;
/**
* Number bitwise logic operations.
*/
typedef enum
{
number_bitwise_logic_and, /**< bitwise AND calculation */
number_bitwise_logic_or, /**< bitwise OR calculation */
number_bitwise_logic_xor, /**< bitwise XOR calculation */
} number_bitwise_logic_op;
/**
* Perform ECMA number arithmetic operation.
*
* The algorithm of the operation is following:
* leftNum = ToNumber (leftValue);
* rightNum = ToNumber (rightValue);
* result = leftNum ArithmeticOp rightNum;
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
static ecma_completion_value_t
do_number_arithmetic (struct __int_data *int_data, /**< interpreter context */
T_IDX dst_var_idx, /**< destination variable identifier */
number_arithmetic_op op, /**< number arithmetic operation */
ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /** right value */
{
ecma_completion_value_t 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);
right_p = (ecma_number_t*) ECMA_GET_POINTER (num_right_value.value.value);
res_p = ecma_alloc_number ();
switch (op)
{
case number_arithmetic_addition:
{
*res_p = ecma_op_number_add (*left_p, *right_p);
break;
}
case number_arithmetic_substraction:
{
*res_p = ecma_op_number_substract (*left_p, *right_p);
break;
}
case number_arithmetic_multiplication:
{
*res_p = ecma_op_number_multiply (*left_p, *right_p);
break;
}
case number_arithmetic_division:
{
*res_p = ecma_op_number_divide (*left_p, *right_p);
break;
}
case number_arithmetic_remainder:
{
*res_p = ecma_op_number_remainder (*left_p, *right_p);
break;
}
}
ret_value = set_variable_value (int_data,
dst_var_idx,
ecma_make_number_value (res_p));
ecma_dealloc_number (res_p);
ECMA_FINALIZE (num_right_value);
ECMA_FINALIZE (num_left_value);
return ret_value;
} /* do_number_arithmetic */
/**
* Perform ECMA number logic operation.
*
* The algorithm of the operation is following:
* leftNum = ToNumber (leftValue);
* rightNum = ToNumber (rightValue);
* result = leftNum BitwiseLogicOp rightNum;
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
static ecma_completion_value_t
do_number_bitwise_logic (struct __int_data *int_data, /**< interpreter context */
T_IDX dst_var_idx, /**< destination variable identifier */
number_bitwise_logic_op op, /**< number bitwise logic operation */
ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /** right value */
{
ecma_completion_value_t 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;
left_p = (ecma_number_t*) ECMA_GET_POINTER (num_left_value.value.value);
right_p = (ecma_number_t*) ECMA_GET_POINTER (num_right_value.value.value);
uint32_t left_uint32, right_uint32, res = 0;
left_uint32 = ecma_number_to_uint32 (*left_p);
right_uint32 = ecma_number_to_uint32 (*right_p);
switch (op)
{
case number_bitwise_logic_and:
{
res = left_uint32 & right_uint32;
break;
}
case number_bitwise_logic_or:
{
res = left_uint32 | right_uint32;
break;
}
case number_bitwise_logic_xor:
{
res = left_uint32 ^ right_uint32;
break;
}
}
ecma_number_t* res_p = ecma_alloc_number ();
*res_p = ecma_uint32_to_number (res);
ret_value = set_variable_value (int_data,
dst_var_idx,
ecma_make_number_value (res_p));
ecma_dealloc_number (res_p);
ECMA_FINALIZE (num_right_value);
ECMA_FINALIZE (num_left_value);
return ret_value;
} /* do_number_bitwise_logic */
#define OP_UNIMPLEMENTED_LIST(op) \
op (call_n) \
op (func_decl_n) \
op (varg_1_end) \
op (varg_2_end) \
op (varg_3) \
op (varg_3_end) \
op (retval) \
op (b_shift_left) \
op (b_shift_right) \
op (b_shift_uright) \
op (logical_and) \
op (logical_or) \
op (construct_0) \
op (construct_1) \
op (construct_n) \
op (func_expr_0) \
op (func_expr_1) \
op (func_expr_n) \
op (array_0) \
op (array_1) \
op (array_2) \
op (array_n) \
op (prop) \
op (prop_access) \
op (prop_get_decl) \
op (prop_set_decl) \
op (obj_0) \
op (obj_1) \
op (obj_2) \
op (obj_n) \
op (this) \
op (delete) \
op (typeof) \
op (with) \
op (end_with) \
op (logical_not) \
op (b_not) \
op (instanceof) \
op (in) \
static char __unused unimplemented_list_end
#define DEFINE_UNIMPLEMENTED_OP(op) \
ecma_completion_value_t opfunc_ ## op (OPCODE opdata, struct __int_data *int_data) \
{ \
JERRY_UNIMPLEMENTED_REF_UNUSED_VARS (opdata, int_data); \
}
OP_UNIMPLEMENTED_LIST (DEFINE_UNIMPLEMENTED_OP);
#undef DEFINE_UNIMPLEMENTED_OP
/**
* 'Nop' opcode handler.
*/
ecma_completion_value_t
opfunc_nop (OPCODE opdata __unused, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
int_data->pos++;
return ecma_make_empty_completion_value ();
} /* opfunc_nop */
ecma_completion_value_t
opfunc_call_1 (OPCODE opdata __unused, struct __int_data *int_data)
{
ecma_completion_value_t ret_value;
ret_value = ecma_make_empty_completion_value ();
#ifdef __TARGET_HOST_x64
__printf ("%d::op_call_1:idx:%d:%d\t",
int_data->pos,
opdata.data.call_1.name_lit_idx,
opdata.data.call_1.arg1_lit_idx);
#endif
int_data->pos++;
string_literal_copy str_value;
init_string_literal_copy (opdata.data.call_1.name_lit_idx, &str_value);
#ifdef __TARGET_HOST_x64
__printf ("%s\n", str_value.str_p);
#endif
if (!__strcmp ((const char*) str_value.str_p, "LEDToggle"))
{
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_toggle (int_num);
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
}
if (!__strcmp ((const char*) str_value.str_p, "LEDOn"))
{
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_on (int_num);
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
}
if (!__strcmp ((const char*) str_value.str_p, "LEDOff"))
{
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_off (int_num);
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
}
if (!__strcmp ((const char*) str_value.str_p, "LEDOnce"))
{
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 ();
ECMA_FINALIZE (cond_value);
}
if (!__strcmp ((const char*) str_value.str_p, "wait"))
{
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;
wait_ms (int_num);
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
}
if (!__strcmp ((const char *) str_value.str_p, "exit"))
{
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);
opfunc_exitval (getop_exitval ((T_IDX) * num_p), int_data);
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
}
free_string_literal_copy (&str_value);
return ret_value;
}
/**
* 'Jump if true' opcode handler.
*
* Note:
* the opcode changes current opcode position to specified opcode index
* if argument evaluates to true.
*/
ecma_completion_value_t
opfunc_is_true_jmp (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX cond_var_idx = opdata.data.is_true_jmp.value;
const T_IDX dst_opcode_idx = opdata.data.is_true_jmp.opcode;
ecma_completion_value_t 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));
if (ecma_is_value_true (to_bool_completion.value))
{
int_data->pos = dst_opcode_idx;
}
else
{
int_data->pos++;
}
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
return ret_value;
} /* opfunc_is_true_jmp */
/**
* 'Jump if false' opcode handler.
*
* Note:
* the opcode changes current opcode position to specified opcode index
* if argument evaluates to false.
*/
ecma_completion_value_t
opfunc_is_false_jmp (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX cond_var_idx = opdata.data.is_false_jmp.value;
const T_IDX dst_opcode_idx = opdata.data.is_false_jmp.opcode;
ecma_completion_value_t 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));
if (!ecma_is_value_true (to_bool_completion.value))
{
int_data->pos = dst_opcode_idx;
}
else
{
int_data->pos++;
}
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
return ret_value;
} /* opfunc_is_false_jmp */
/**
* 'Jump' opcode handler.
*
* Note:
* the opcode changes current opcode position to specified opcode index
*/
ecma_completion_value_t
opfunc_jmp (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
int_data->pos = opdata.data.jmp.opcode_idx;
return ecma_make_empty_completion_value ();
} /* opfunc_jmp */
/**
* 'Jump down' opcode handler.
*
* Note:
* the opcode changes adds specified value to current opcode position
*/
ecma_completion_value_t
opfunc_jmp_down (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
JERRY_ASSERT (int_data->pos <= int_data->pos + opdata.data.jmp_up.opcode_count);
int_data->pos = (opcode_counter_t) (int_data->pos + opdata.data.jmp_down.opcode_count);
return ecma_make_empty_completion_value ();
} /* opfunc_jmp_down */
/**
* 'Jump up' opcode handler.
*
* Note:
* the opcode changes substracts specified value from current opcode position
*/
ecma_completion_value_t
opfunc_jmp_up (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
JERRY_ASSERT (int_data->pos >= opdata.data.jmp_up.opcode_count);
int_data->pos = (opcode_counter_t) (int_data->pos - opdata.data.jmp_down.opcode_count);
return ecma_make_empty_completion_value ();
} /* opfunc_jmp_up */
/**
* 'Assignment' opcode handler.
*
* Note:
* This handler implements case of assignment of a literal's or a variable's
* value to a variable. Assignment to an object's property is not implemented
* by this opcode.
*
* FIXME: Add cross link with 'property accessor assignment` opcode.
*
* See also: ECMA-262 v5, 11.13.1
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_assignment (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.assignment.var_left;
const opcode_arg_type_operand type_value_right = opdata.data.assignment.type_value_right;
const T_IDX src_val_descr = opdata.data.assignment.value_right;
int_data->pos++;
ecma_completion_value_t get_value_completion;
switch (type_value_right)
{
case OPCODE_ARG_TYPE_SIMPLE:
{
get_value_completion = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL,
ecma_make_simple_value (src_val_descr),
ECMA_TARGET_ID_RESERVED);
break;
}
case OPCODE_ARG_TYPE_STRING:
{
string_literal_copy str_value;
ecma_string_t *ecma_string_p;
init_string_literal_copy (src_val_descr, &str_value);
ecma_string_p = ecma_new_ecma_string (str_value.str_p);
free_string_literal_copy (&str_value);
get_value_completion = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL,
ecma_make_string_value (ecma_string_p),
ECMA_TARGET_ID_RESERVED);
break;
}
case OPCODE_ARG_TYPE_VARIABLE:
{
get_value_completion = get_variable_value (int_data,
src_val_descr,
false);
break;
}
case OPCODE_ARG_TYPE_NUMBER:
{
ecma_number_t *num_p = ecma_alloc_number ();
*num_p = get_number_by_idx (src_val_descr);
get_value_completion = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL,
ecma_make_number_value (num_p),
ECMA_TARGET_ID_RESERVED);
break;
}
case OPCODE_ARG_TYPE_SMALLINT:
{
ecma_number_t *num_p = ecma_alloc_number ();
*num_p = src_val_descr;
get_value_completion = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL,
ecma_make_number_value (num_p),
ECMA_TARGET_ID_RESERVED);
break;
}
JERRY_UNIMPLEMENTED ();
}
if (unlikely (ecma_is_completion_value_throw (get_value_completion)))
{
return get_value_completion;
}
else
{
JERRY_ASSERT (ecma_is_completion_value_normal (get_value_completion));
ecma_completion_value_t assignment_completion_value = set_variable_value (int_data,
dst_var_idx,
get_value_completion.value);
ecma_free_completion_value (get_value_completion);
return assignment_completion_value;
}
} /* opfunc_assignment */
/**
* 'Addition' opcode handler.
*
* See also: ECMA-262 v5, 11.6.1
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_addition (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.addition.dst;
const T_IDX left_var_idx = opdata.data.addition.var_left;
const T_IDX right_var_idx = opdata.data.addition.var_right;
int_data->pos++;
ecma_completion_value_t 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)
{
JERRY_UNIMPLEMENTED ();
}
else
{
ret_value = do_number_arithmetic (int_data,
dst_var_idx,
number_arithmetic_addition,
prim_left_value.value,
prim_right_value.value);
}
ECMA_FINALIZE (prim_right_value);
ECMA_FINALIZE (prim_left_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_addition */
/**
* 'Substraction' opcode handler.
*
* See also: ECMA-262 v5, 11.6.2
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_substraction (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.substraction.dst;
const T_IDX left_var_idx = opdata.data.substraction.var_left;
const T_IDX right_var_idx = opdata.data.substraction.var_right;
int_data->pos++;
ecma_completion_value_t 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,
number_arithmetic_substraction,
left_value.value,
right_value.value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_substraction */
/**
* 'Multiplication' opcode handler.
*
* See also: ECMA-262 v5, 11.5, 11.5.1
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_multiplication (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.multiplication.dst;
const T_IDX left_var_idx = opdata.data.multiplication.var_left;
const T_IDX right_var_idx = opdata.data.multiplication.var_right;
int_data->pos++;
ecma_completion_value_t 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,
number_arithmetic_multiplication,
left_value.value,
right_value.value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_multiplication */
/**
* 'Division' opcode handler.
*
* See also: ECMA-262 v5, 11.5, 11.5.2
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_division (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.division.dst;
const T_IDX left_var_idx = opdata.data.division.var_left;
const T_IDX right_var_idx = opdata.data.division.var_right;
int_data->pos++;
ecma_completion_value_t 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,
number_arithmetic_division,
left_value.value,
right_value.value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_division */
/**
* 'Remainder calculation' opcode handler.
*
* See also: ECMA-262 v5, 11.5, 11.5.3
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_remainder (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.remainder.dst;
const T_IDX left_var_idx = opdata.data.remainder.var_left;
const T_IDX right_var_idx = opdata.data.remainder.var_right;
int_data->pos++;
ecma_completion_value_t 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,
number_arithmetic_remainder,
left_value.value,
right_value.value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_remainder */
/**
* 'Bitwise AND' opcode handler.
*
* See also: ECMA-262 v5, 11.10
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_b_and (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.b_and.dst;
const T_IDX left_var_idx = opdata.data.b_and.var_left;
const T_IDX right_var_idx = opdata.data.b_and.var_right;
int_data->pos++;
ecma_completion_value_t 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_bitwise_logic (int_data,
dst_var_idx,
number_bitwise_logic_and,
left_value.value,
right_value.value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_b_and */
/**
* 'Bitwise OR' opcode handler.
*
* See also: ECMA-262 v5, 11.10
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_b_or (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.b_or.dst;
const T_IDX left_var_idx = opdata.data.b_or.var_left;
const T_IDX right_var_idx = opdata.data.b_or.var_right;
int_data->pos++;
ecma_completion_value_t 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_bitwise_logic (int_data,
dst_var_idx,
number_bitwise_logic_or,
left_value.value,
right_value.value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_b_or */
/**
* 'Bitwise XOR' opcode handler.
*
* See also: ECMA-262 v5, 11.10
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_b_xor (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.b_xor.dst;
const T_IDX left_var_idx = opdata.data.b_xor.var_left;
const T_IDX right_var_idx = opdata.data.b_xor.var_right;
int_data->pos++;
ecma_completion_value_t 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_bitwise_logic (int_data,
dst_var_idx,
number_bitwise_logic_xor,
left_value.value,
right_value.value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_b_xor */
/**
* 'Pre increment' opcode handler.
*
* See also: ECMA-262 v5, 11.4.4
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_pre_incr (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.pre_incr.dst;
const T_IDX incr_var_idx = opdata.data.pre_incr.var_right;
int_data->pos++;
ecma_completion_value_t ret_value;
// 1., 2., 3.
ECMA_TRY_CATCH (old_value, get_variable_value (int_data, incr_var_idx, true), ret_value);
ECMA_TRY_CATCH (old_num_value, ecma_op_to_number (old_value.value), ret_value);
// 4.
ecma_number_t* new_num_p = ecma_alloc_number ();
ecma_number_t* old_num_p = (ecma_number_t*) ECMA_GET_POINTER (old_num_value.value.value);
*new_num_p = ecma_op_number_add (*old_num_p, ECMA_NUMBER_ONE);
ecma_value_t new_num_value = ecma_make_number_value (new_num_p);
// 5.
ret_value = set_variable_value (int_data,
incr_var_idx,
new_num_value);
// assignment of operator result to register variable
ecma_completion_value_t reg_assignment_res = set_variable_value (int_data,
dst_var_idx,
new_num_value);
JERRY_ASSERT (ecma_is_empty_completion_value (reg_assignment_res));
ecma_dealloc_number (new_num_p);
ECMA_FINALIZE (old_num_value);
ECMA_FINALIZE (old_value);
return ret_value;
} /* opfunc_pre_incr */
/**
* 'Pre decrement' opcode handler.
*
* See also: ECMA-262 v5, 11.4.4
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_pre_decr (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.pre_decr.dst;
const T_IDX decr_var_idx = opdata.data.pre_decr.var_right;
int_data->pos++;
ecma_completion_value_t ret_value;
// 1., 2., 3.
ECMA_TRY_CATCH (old_value, get_variable_value (int_data, decr_var_idx, true), ret_value);
ECMA_TRY_CATCH (old_num_value, ecma_op_to_number (old_value.value), ret_value);
// 4.
ecma_number_t* new_num_p = ecma_alloc_number ();
ecma_number_t* old_num_p = (ecma_number_t*) ECMA_GET_POINTER (old_num_value.value.value);
*new_num_p = ecma_op_number_substract (*old_num_p, ECMA_NUMBER_ONE);
ecma_value_t new_num_value = ecma_make_number_value (new_num_p);
// 5.
ret_value = set_variable_value (int_data,
decr_var_idx,
new_num_value);
// assignment of operator result to register variable
ecma_completion_value_t reg_assignment_res = set_variable_value (int_data,
dst_var_idx,
new_num_value);
JERRY_ASSERT (ecma_is_empty_completion_value (reg_assignment_res));
ecma_dealloc_number (new_num_p);
ECMA_FINALIZE (old_num_value);
ECMA_FINALIZE (old_value);
return ret_value;
} /* opfunc_pre_decr */
/**
* 'Post increment' opcode handler.
*
* See also: ECMA-262 v5, 11.3.1
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_post_incr (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.post_incr.dst;
const T_IDX incr_var_idx = opdata.data.post_incr.var_right;
int_data->pos++;
ecma_completion_value_t ret_value;
// 1., 2., 3.
ECMA_TRY_CATCH (old_value, get_variable_value (int_data, incr_var_idx, true), ret_value);
ECMA_TRY_CATCH (old_num_value, ecma_op_to_number (old_value.value), ret_value);
// 4.
ecma_number_t* new_num_p = ecma_alloc_number ();
ecma_number_t* old_num_p = (ecma_number_t*) ECMA_GET_POINTER (old_num_value.value.value);
*new_num_p = ecma_op_number_add (*old_num_p, ECMA_NUMBER_ONE);
// 5.
ret_value = set_variable_value (int_data,
incr_var_idx,
ecma_make_number_value (new_num_p));
ecma_dealloc_number (new_num_p);
// assignment of operator result to register variable
ecma_completion_value_t reg_assignment_res = set_variable_value (int_data,
dst_var_idx,
old_value.value);
JERRY_ASSERT (ecma_is_empty_completion_value (reg_assignment_res));
ECMA_FINALIZE (old_num_value);
ECMA_FINALIZE (old_value);
return ret_value;
} /* opfunc_post_incr */
/**
* 'Post decrement' opcode handler.
*
* See also: ECMA-262 v5, 11.3.2
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_post_decr (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.post_decr.dst;
const T_IDX decr_var_idx = opdata.data.post_decr.var_right;
int_data->pos++;
ecma_completion_value_t ret_value;
// 1., 2., 3.
ECMA_TRY_CATCH (old_value, get_variable_value (int_data, decr_var_idx, true), ret_value);
ECMA_TRY_CATCH (old_num_value, ecma_op_to_number (old_value.value), ret_value);
// 4.
ecma_number_t* new_num_p = ecma_alloc_number ();
ecma_number_t* old_num_p = (ecma_number_t*) ECMA_GET_POINTER (old_num_value.value.value);
*new_num_p = ecma_op_number_substract (*old_num_p, ECMA_NUMBER_ONE);
// 5.
ret_value = set_variable_value (int_data,
decr_var_idx,
ecma_make_number_value (new_num_p));
ecma_dealloc_number (new_num_p);
// assignment of operator result to register variable
ecma_completion_value_t reg_assignment_res = set_variable_value (int_data,
dst_var_idx,
old_value.value);
JERRY_ASSERT (ecma_is_empty_completion_value (reg_assignment_res));
ECMA_FINALIZE (old_num_value);
ECMA_FINALIZE (old_value);
return ret_value;
} /* opfunc_post_decr */
/**
* 'Equals' opcode handler.
*
* See also: ECMA-262 v5, 11.9.1
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_equal_value (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.equal_value.dst;
const T_IDX left_var_idx = opdata.data.equal_value.var_left;
const T_IDX right_var_idx = opdata.data.equal_value.var_right;
int_data->pos++;
ecma_completion_value_t 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);
bool is_equal = ecma_op_abstract_equality_compare (left_value.value, right_value.value);
ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE
: ECMA_SIMPLE_VALUE_FALSE));
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_equal_value */
/**
* 'Does-not-equals' opcode handler.
*
* See also: ECMA-262 v5, 11.9.2
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_not_equal_value (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.not_equal_value.dst;
const T_IDX left_var_idx = opdata.data.not_equal_value.var_left;
const T_IDX right_var_idx = opdata.data.not_equal_value.var_right;
int_data->pos++;
ecma_completion_value_t 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);
bool is_equal = ecma_op_abstract_equality_compare (left_value.value, right_value.value);
ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE
: ECMA_SIMPLE_VALUE_TRUE));
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_not_equal_value */
/**
* 'Strict Equals' opcode handler.
*
* See also: ECMA-262 v5, 11.9.4
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_equal_value_type (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.equal_value_type.dst;
const T_IDX left_var_idx = opdata.data.equal_value_type.var_left;
const T_IDX right_var_idx = opdata.data.equal_value_type.var_right;
int_data->pos++;
ecma_completion_value_t 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);
bool is_equal = ecma_op_strict_equality_compare (left_value.value, right_value.value);
ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE
: ECMA_SIMPLE_VALUE_FALSE));
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_equal_value_type */
/**
* 'Strict Does-not-equals' opcode handler.
*
* See also: ECMA-262 v5, 11.9.5
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_not_equal_value_type (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.not_equal_value_type.dst;
const T_IDX left_var_idx = opdata.data.not_equal_value_type.var_left;
const T_IDX right_var_idx = opdata.data.not_equal_value_type.var_right;
int_data->pos++;
ecma_completion_value_t 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);
bool is_equal = ecma_op_strict_equality_compare (left_value.value, right_value.value);
ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE
: ECMA_SIMPLE_VALUE_TRUE));
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_not_equal_value_type */
/**
* 'Less-than' opcode handler.
*
* See also: ECMA-262 v5, 11.8.1
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_less_than (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.less_than.dst;
const T_IDX left_var_idx = opdata.data.less_than.var_left;
const T_IDX right_var_idx = opdata.data.less_than.var_right;
int_data->pos++;
ecma_completion_value_t 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 (compare_result,
ecma_op_abstract_relational_compare (left_value.value,
right_value.value,
true),
ret_value);
ecma_simple_value_t res;
if (ecma_is_value_undefined (compare_result.value))
{
res = ECMA_SIMPLE_VALUE_FALSE;
}
else
{
JERRY_ASSERT (ecma_is_value_boolean (compare_result.value));
res = compare_result.value.value;
}
ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (res));
ECMA_FINALIZE (compare_result);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_less_than */
/**
* 'Greater-than' opcode handler.
*
* See also: ECMA-262 v5, 11.8.2
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_greater_than (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.greater_than.dst;
const T_IDX left_var_idx = opdata.data.greater_than.var_left;
const T_IDX right_var_idx = opdata.data.greater_than.var_right;
int_data->pos++;
ecma_completion_value_t 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 (compare_result,
ecma_op_abstract_relational_compare (right_value.value,
left_value.value,
false),
ret_value);
ecma_simple_value_t res;
if (ecma_is_value_undefined (compare_result.value))
{
res = ECMA_SIMPLE_VALUE_FALSE;
}
else
{
JERRY_ASSERT (ecma_is_value_boolean (compare_result.value));
res = compare_result.value.value;
}
ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (res));
ECMA_FINALIZE (compare_result);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_greater_than */
/**
* 'Less-than-or-equal' opcode handler.
*
* See also: ECMA-262 v5, 11.8.3
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_less_or_equal_than (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.less_or_equal_than.dst;
const T_IDX left_var_idx = opdata.data.less_or_equal_than.var_left;
const T_IDX right_var_idx = opdata.data.less_or_equal_than.var_right;
int_data->pos++;
ecma_completion_value_t 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 (compare_result,
ecma_op_abstract_relational_compare (right_value.value,
left_value.value,
false),
ret_value);
ecma_simple_value_t res;
if (ecma_is_value_undefined (compare_result.value))
{
res = ECMA_SIMPLE_VALUE_FALSE;
}
else
{
JERRY_ASSERT (ecma_is_value_boolean (compare_result.value));
if (compare_result.value.value == ECMA_SIMPLE_VALUE_TRUE)
{
res = ECMA_SIMPLE_VALUE_FALSE;
}
else
{
res = ECMA_SIMPLE_VALUE_TRUE;
}
}
ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (res));
ECMA_FINALIZE (compare_result);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_less_or_equal_than */
/**
* 'Greater-than-or-equal' opcode handler.
*
* See also: ECMA-262 v5, 11.8.4
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_greater_or_equal_than (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.greater_or_equal_than.dst;
const T_IDX left_var_idx = opdata.data.greater_or_equal_than.var_left;
const T_IDX right_var_idx = opdata.data.greater_or_equal_than.var_right;
int_data->pos++;
ecma_completion_value_t 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 (compare_result,
ecma_op_abstract_relational_compare (left_value.value,
right_value.value,
true),
ret_value);
ecma_simple_value_t res;
if (ecma_is_value_undefined (compare_result.value))
{
res = ECMA_SIMPLE_VALUE_FALSE;
}
else
{
JERRY_ASSERT (ecma_is_value_boolean (compare_result.value));
if (compare_result.value.value == ECMA_SIMPLE_VALUE_TRUE)
{
res = ECMA_SIMPLE_VALUE_FALSE;
}
else
{
res = ECMA_SIMPLE_VALUE_TRUE;
}
}
ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (res));
ECMA_FINALIZE (compare_result);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
return ret_value;
} /* opfunc_greater_or_equal_than */
/**
* 'Register variable declaration' opcode handler.
*
* The opcode is meta-opcode that is not supposed to be executed.
*/
ecma_completion_value_t
opfunc_reg_var_decl (OPCODE opdata __unused, /**< operation data */
struct __int_data *int_data __unused) /**< interpreter context */
{
JERRY_UNREACHABLE ();
} /* opfunc_reg_var_decl */
/**
* 'Variable declaration' opcode handler.
*
* See also: ECMA-262 v5, 10.5 - Declaration binding instantiation (block 8).
*
* @return completion value
* Returned value is simple and so need not be freed.
* However, ecma_free_completion_value may be called for it, but it is a no-op.
*/
ecma_completion_value_t
opfunc_var_decl (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
string_literal_copy variable_name;
init_string_literal_copy (opdata.data.var_decl.variable_name, &variable_name);
if (ecma_is_completion_value_normal_false (ecma_op_has_binding (int_data->lex_env_p,
variable_name.str_p)))
{
FIXME ("Pass configurableBindings that is true if and only if current code is eval code");
ecma_completion_value_t completion = ecma_op_create_mutable_binding (int_data->lex_env_p,
variable_name.str_p,
false);
JERRY_ASSERT (ecma_is_empty_completion_value (completion));
/* Skipping SetMutableBinding as we have already checked that there were not
* any binding with specified name in current lexical environment
* and CreateMutableBinding sets the created binding's value to undefined */
JERRY_ASSERT (ecma_is_completion_value_normal_simple_value (ecma_op_get_binding_value (int_data->lex_env_p,
variable_name.str_p,
true),
ECMA_SIMPLE_VALUE_UNDEFINED));
}
free_string_literal_copy (&variable_name);
int_data->pos++;
return ecma_make_empty_completion_value ();
} /* opfunc_var_decl */
/**
* Function declaration helper
*
* @return completion value
* returned value must be freed with ecma_free_completion_value.
*/
static ecma_completion_value_t
function_declaration (struct __int_data *int_data, /**< interpreter context */
T_IDX function_name_lit_idx, /**< identifier of literal with function name */
ecma_string_t* args_names[], /**< names of arguments */
ecma_length_t args_number) /**< number of arguments */
{
TODO ("Check if code of function itself is strict");
const bool is_strict = int_data->is_strict;
const bool is_configurable_bindings = int_data->is_eval_code;
const opcode_counter_t jmp_down_opcode_idx = (opcode_counter_t) (int_data->pos);
OPCODE jmp_down_opcode = read_opcode (jmp_down_opcode_idx);
JERRY_ASSERT (jmp_down_opcode.op_idx == __op__idx_jmp_down);
int_data->pos = (opcode_counter_t) (jmp_down_opcode_idx + jmp_down_opcode.data.jmp_down.opcode_count);
const opcode_counter_t function_code_opcode_idx = (opcode_counter_t) (jmp_down_opcode_idx + 1);
string_literal_copy function_name;
init_string_literal_copy (function_name_lit_idx, &function_name);
ecma_completion_value_t ret_value = ecma_op_function_declaration (int_data->lex_env_p,
function_name.str_p,
function_code_opcode_idx,
args_names,
args_number,
is_strict,
is_configurable_bindings);
free_string_literal_copy (&function_name);
return ret_value;
} /* function_declaration */
/**
* 'Function declaration with no parameters' opcode handler.
*
* @return completion value
* returned value must be freed with ecma_free_completion_value.
*/
ecma_completion_value_t
opfunc_func_decl_0 (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
int_data->pos++;
return function_declaration (int_data,
opdata.data.func_decl_0.name_lit_idx,
NULL,
0);
} /* opfunc_func_decl_0 */
/**
* 'Function declaration with one parameter' opcode handler.
*
* @return completion value
* returned value must be freed with ecma_free_completion_value.
*/
ecma_completion_value_t
opfunc_func_decl_1 (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
int_data->pos++;
string_literal_copy argument_name;
init_string_literal_copy (opdata.data.func_decl_1.arg1_lit_idx, &argument_name);
ecma_string_t *arg_name_string_p = ecma_new_ecma_string (argument_name.str_p);
free_string_literal_copy (&argument_name);
ecma_completion_value_t ret_value = function_declaration (int_data,
opdata.data.func_decl_1.name_lit_idx,
&arg_name_string_p,
1);
ecma_free_string (arg_name_string_p);
return ret_value;
} /* opfunc_func_decl_1 */
/**
* 'Function declaration with two parameters' opcode handler.
*
* @return completion value
* returned value must be freed with ecma_free_completion_value.
*/
ecma_completion_value_t
opfunc_func_decl_2 (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
int_data->pos++;
string_literal_copy argument1_name, argument2_name;
init_string_literal_copy (opdata.data.func_decl_2.arg1_lit_idx, &argument1_name);
init_string_literal_copy (opdata.data.func_decl_2.arg2_lit_idx, &argument2_name);
ecma_string_t* arg_names_strings[2] =
{
ecma_new_ecma_string (argument1_name.str_p),
ecma_new_ecma_string (argument2_name.str_p)
};
free_string_literal_copy (&argument2_name);
free_string_literal_copy (&argument1_name);
ecma_completion_value_t ret_value = function_declaration (int_data,
opdata.data.func_decl_1.name_lit_idx,
arg_names_strings,
2);
ecma_free_string (arg_names_strings[0]);
ecma_free_string (arg_names_strings[1]);
return ret_value;
} /* opfunc_func_decl_2 */
/**
* Function call with no arguments' opcode handler.
*
* See also: ECMA-262 v5, 11.2.3
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value.
*/
ecma_completion_value_t
opfunc_call_0 (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX func_name_lit_idx = opdata.data.call_0.name_lit_idx;
const T_IDX lhs_var_idx = opdata.data.call_0.lhs;
int_data->pos++;
ecma_completion_value_t ret_value;
ECMA_TRY_CATCH (func_value, get_variable_value (int_data, func_name_lit_idx, false), ret_value);
if (!ecma_op_is_callable (func_value.value))
{
ret_value = ecma_make_throw_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
}
else
{
ecma_object_t *func_obj_p = ECMA_GET_POINTER (func_value.value.value);
ECMA_TRY_CATCH (this_value, ecma_op_implicit_this_value (int_data->lex_env_p), ret_value);
ret_value = ecma_op_function_call (func_obj_p, this_value.value, NULL, 0);
if (ret_value.type == ECMA_COMPLETION_TYPE_RETURN)
{
ecma_value_t returned_value = ret_value.value;
ret_value = set_variable_value (int_data, lhs_var_idx, returned_value);
ecma_free_value (returned_value, true);
}
ECMA_FINALIZE (this_value);
}
ECMA_FINALIZE (func_value);
return ret_value;
} /* opfunc_call_0 */
/**
* 'Return with no expression' opcode handler.
*
* See also: ECMA-262 v5, 12.9
*
* @return completion value
* Returned value is simple and so need not be freed.
* However, ecma_free_completion_value may be called for it, but it is a no-op.
*/
ecma_completion_value_t
opfunc_ret (OPCODE opdata __unused, /**< operation data */
struct __int_data *int_data __unused) /**< interpreter context */
{
return ecma_make_completion_value (ECMA_COMPLETION_TYPE_RETURN,
ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED),
ECMA_TARGET_ID_RESERVED);
} /* opfunc_ret */
/**
* Exit from script with specified status code:
* 0 - for successful completion
* 1 - to indicate failure.
*
* Note: this is not ECMA specification-defined, but internal
* implementation-defined opcode for end of script
* and assertions inside of unit tests.
*
* @return completion value
* Returned value is simple and so need not be freed.
* However, ecma_free_completion_value may be called for it, but it is a no-op.
*/
ecma_completion_value_t
opfunc_exitval (OPCODE opdata, /**< operation data */
struct __int_data *int_data __unused) /**< interpreter context */
{
JERRY_ASSERT (opdata.data.exitval.status_code == 0
|| opdata.data.exitval.status_code == 1);
ecma_value_t exit_status = ecma_make_simple_value (opdata.data.exitval.status_code == 0 ? ECMA_SIMPLE_VALUE_TRUE
: ECMA_SIMPLE_VALUE_FALSE);
return ecma_make_completion_value (ECMA_COMPLETION_TYPE_EXIT,
exit_status,
ECMA_TARGET_ID_RESERVED);
} /* opfunc_exitval */
/** Opcode generators. */
GETOP_IMPL_2 (is_true_jmp, value, opcode)
GETOP_IMPL_2 (is_false_jmp, value, opcode)
GETOP_IMPL_1 (jmp, opcode_idx)
GETOP_IMPL_1 (jmp_up, opcode_count)
GETOP_IMPL_1 (jmp_down, opcode_count)
GETOP_IMPL_3 (addition, dst, var_left, var_right)
GETOP_IMPL_2 (post_incr, dst, var_right)
GETOP_IMPL_2 (post_decr, dst, var_right)
GETOP_IMPL_2 (pre_incr, dst, var_right)
GETOP_IMPL_2 (pre_decr, dst, var_right)
GETOP_IMPL_3 (substraction, dst, var_left, var_right)
GETOP_IMPL_3 (division, dst, var_left, var_right)
GETOP_IMPL_3 (multiplication, dst, var_left, var_right)
GETOP_IMPL_3 (remainder, dst, var_left, var_right)
GETOP_IMPL_3 (b_shift_left, dst, var_left, var_right)
GETOP_IMPL_3 (b_shift_right, dst, var_left, var_right)
GETOP_IMPL_3 (b_shift_uright, dst, var_left, var_right)
GETOP_IMPL_3 (b_and, dst, var_left, var_right)
GETOP_IMPL_3 (b_or, dst, var_left, var_right)
GETOP_IMPL_3 (b_xor, dst, var_left, var_right)
GETOP_IMPL_3 (logical_and, dst, var_left, var_right)
GETOP_IMPL_3 (logical_or, dst, var_left, var_right)
GETOP_IMPL_3 (equal_value, dst, var_left, var_right)
GETOP_IMPL_3 (not_equal_value, dst, var_left, var_right)
GETOP_IMPL_3 (equal_value_type, dst, var_left, var_right)
GETOP_IMPL_3 (not_equal_value_type, dst, var_left, var_right)
GETOP_IMPL_3 (less_than, dst, var_left, var_right)
GETOP_IMPL_3 (greater_than, dst, var_left, var_right)
GETOP_IMPL_3 (less_or_equal_than, dst, var_left, var_right)
GETOP_IMPL_3 (greater_or_equal_than, dst, var_left, var_right)
GETOP_IMPL_3 (assignment, var_left, type_value_right, value_right)
GETOP_IMPL_2 (call_0, lhs, name_lit_idx)
GETOP_IMPL_3 (call_1, lhs, name_lit_idx, arg1_lit_idx)
GETOP_IMPL_3 (call_n, lhs, name_lit_idx, arg1_lit_idx)
GETOP_IMPL_2 (func_decl_1, name_lit_idx, arg1_lit_idx)
GETOP_IMPL_3 (func_decl_2, name_lit_idx, arg1_lit_idx, arg2_lit_idx)
GETOP_IMPL_3 (func_decl_n, name_lit_idx, arg1_lit_idx, arg2_lit_idx)
GETOP_IMPL_1 (varg_1_end, arg1_lit_idx)
GETOP_IMPL_2 (varg_2_end, arg1_lit_idx, arg2_lit_idx)
GETOP_IMPL_3 (varg_3, arg1_lit_idx, arg2_lit_idx, arg3_lit_idx)
GETOP_IMPL_3 (varg_3_end, arg1_lit_idx, arg2_lit_idx, arg3_lit_idx)
GETOP_IMPL_1 (exitval, status_code)
GETOP_IMPL_1 (retval, ret_value)
GETOP_IMPL_0 (ret)
GETOP_IMPL_0 (nop)
GETOP_IMPL_1 (var_decl, variable_name)
GETOP_IMPL_2 (b_not, dst, var_right)
GETOP_IMPL_2 (logical_not, dst, var_right)
GETOP_IMPL_3 (instanceof, dst, var_left, var_right)
GETOP_IMPL_3 (in, dst, var_left, var_right)
GETOP_IMPL_2 (construct_0, lhs, name_lit_idx)
GETOP_IMPL_3 (construct_1, lhs, name_lit_idx, arg1_lit_idx)
GETOP_IMPL_3 (construct_n, lhs, name_lit_idx, arg1_lit_idx)
GETOP_IMPL_1 (func_decl_0, name_lit_idx)
GETOP_IMPL_2 (func_expr_0, lhs, name_lit_idx)
GETOP_IMPL_3 (func_expr_1, lhs, name_lit_idx, arg1_lit_idx)
GETOP_IMPL_3 (func_expr_n, lhs, name_lit_idx, arg1_lit_idx)
GETOP_IMPL_1 (array_0, lhs)
GETOP_IMPL_2 (array_1, lhs, elem1)
GETOP_IMPL_3 (array_2, lhs, elem1, elem2)
GETOP_IMPL_3 (array_n, lhs, elem1, elem2)
GETOP_IMPL_3 (prop, lhs, name, value)
GETOP_IMPL_3 (prop_access, lhs, obj, prop)
GETOP_IMPL_2 (prop_get_decl, lhs, prop)
GETOP_IMPL_3 (prop_set_decl, lhs, prop, arg)
GETOP_IMPL_1 (obj_0, lhs)
GETOP_IMPL_2 (obj_1, lhs, arg1)
GETOP_IMPL_3 (obj_2, lhs, arg1, arg2)
GETOP_IMPL_3 (obj_n, lhs, arg1, arg2)
GETOP_IMPL_1 (this, lhs)
GETOP_IMPL_2 (delete, lhs, obj)
GETOP_IMPL_2 (typeof, lhs, obj)
GETOP_IMPL_1 (with, expr)
GETOP_IMPL_0 (end_with)
GETOP_IMPL_2 (reg_var_decl, min, max)