/* 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 __unused 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 __unused 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 */ { FIXME( Replace strcmp with ecma_char_t[] comparator ); return ( ref.is_strict && ( __strcmp( (char*)ref.referenced_name_p, (char*)ecma_get_magic_string( ECMA_MAGIC_STRING_EVAL)) == 0 || __strcmp( (char*)ref.referenced_name_p, (char*)ecma_get_magic_string( ECMA_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; /** * 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 */ #define OP_UNIMPLEMENTED_LIST(op) \ op(call_n) \ op(func_decl_1) \ op(func_decl_2) \ 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(b_and) \ op(b_or) \ op(b_xor) \ op(logical_and) \ op(logical_or) \ op(equal_value_type) \ op(not_equal_value_type) \ op(less_or_equal_than) \ op(greater_or_equal_than) \ 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_array_first_chunk_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 */ /** * '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 */ /** * '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 */ /** * '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 with no parameters' opcode handler. * * See also: ECMA-262 v5, 10.5 - Declaration binding instantiation (block 5). * * @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 */ { string_literal_copy function_name; init_string_literal_copy( opdata.data.func_decl_0.name_lit_idx, &function_name); TODO( Check if code of function itself is strict ); const bool is_strict = int_data->is_strict; const opcode_counter_t varg_first_opcode_idx = (opcode_counter_t) (int_data->pos + 1); int_data->pos = varg_first_opcode_idx; TODO( Iterate vargs ); 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); // a. const ecma_char_t *fn = function_name.str_p; // b. TODO( Pass formal parameter list ); ecma_object_t *fo = ecma_op_create_function_object( NULL, 0, int_data->lex_env_p, is_strict, function_code_opcode_idx); ecma_value_t fo_value = ecma_make_object_value( fo); // c. bool func_already_declared = ecma_is_completion_value_normal_true( ecma_op_has_binding (int_data->lex_env_p, fn)); // d. if ( !func_already_declared ) { 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, fn, false); JERRY_ASSERT( ecma_is_empty_completion_value( completion) ); } // e. TODO( Check if current lexical environment is global environment and implement the case ); // f. ecma_completion_value_t ret_value = ecma_op_set_mutable_binding( int_data->lex_env_p, fn, fo_value, is_strict); ecma_free_value( fo_value, true); free_string_literal_copy( &function_name); return ret_value; } /* opfunc_func_decl_0 */ /** * '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)