1559 lines
53 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 __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)