Files
jerryscript/src/libcoreint/opcodes.c
T
2014-07-21 20:36:08 +04:00

450 lines
16 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-exceptions.h"
#include "ecma-helpers.h"
#include "ecma-operations.h"
#include "interpreter.h"
#include "jerry-libc.h"
#include "mem-heap.h"
#include "opcodes.h"
/**
* 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_HeapAllocBlock( (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_HeapFreeBlock( str_lit_descr_p->str_p);
}
str_lit_descr_p->str_p = NULL;
return;
} /* free_string_literal */
#define OP_UNIMPLEMENTED_LIST(op) \
op(is_true_jmp) \
op(is_false_jmp) \
op(loop_init_num) \
op(loop_precond_begin_num) \
op(loop_precond_end_num) \
op(loop_postcond) \
op(call_2) \
op(call_n) \
op(func_decl_1) \
op(func_decl_2) \
op(func_decl_n) \
op(varg_1) \
op(varg_1_end) \
op(varg_2) \
op(varg_2_end) \
op(varg_3) \
op(varg_3_end) \
op(retval) \
op(ret) \
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) \
op(not_equal_value) \
op(equal_value_type) \
op(not_equal_value_type) \
op(less_than) \
op(greater_than) \
op(less_or_equal_than) \
op(greater_or_equal_than) \
op(addition) \
op(substraction) \
op(division) \
op(multiplication) \
op(remainder) \
op(jmp_up) \
op(jmp_down) \
op(nop)
#define DEFINE_UNIMPLEMENTED_OP(op) \
ecma_CompletionValue_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
ecma_CompletionValue_t
opfunc_loop_inf (OPCODE opdata, struct __int_data *int_data)
{
#ifdef __HOST
__printf ("%d::loop_inf:idx:%d\n",
int_data->pos,
opdata.data.loop_inf.loop_root);
#endif
int_data->pos = opdata.data.loop_inf.loop_root;
return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL,
ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_EMPTY),
ECMA_TARGET_ID_RESERVED);
}
ecma_CompletionValue_t
opfunc_call_1 (OPCODE opdata __unused, struct __int_data *int_data)
{
#ifdef __HOST
__printf ("%d::op_call_1:idx:%d:%d\n",
int_data->pos,
opdata.data.call_1.name_lit_idx,
opdata.data.call_1.arg1_lit_idx);
#endif
int_data->pos++;
// FIXME
return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL,
ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_EMPTY),
ECMA_TARGET_ID_RESERVED);
}
ecma_CompletionValue_t
opfunc_jmp (OPCODE opdata, struct __int_data *int_data)
{
#ifdef __HOST
__printf ("%d::op_jmp:idx:%d\n",
int_data->pos,
opdata.data.jmp.opcode_idx);
#endif
int_data->pos = opdata.data.jmp.opcode_idx;
return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL,
ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_EMPTY),
ECMA_TARGET_ID_RESERVED);
}
/**
* 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_CompletionValue_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_Value_t right_value;
switch ( type_value_right )
{
case OPCODE_ARG_TYPE_SIMPLE:
{
right_value = ecma_MakeSimpleValue( src_val_descr);
break;
}
case OPCODE_ARG_TYPE_STRING:
{
string_literal_copy str_value;
ecma_ArrayFirstChunk_t *ecma_string_p;
init_string_literal_copy( src_val_descr, &str_value);
ecma_string_p = ecma_NewEcmaString( str_value.str_p);
free_string_literal_copy( &str_value);
right_value.m_ValueType = ECMA_TYPE_STRING;
ecma_SetPointer( right_value.m_Value, ecma_string_p);
break;
}
case OPCODE_ARG_TYPE_VARIABLE:
{
string_literal_copy src_variable_name;
ecma_Reference_t src_reference;
init_string_literal_copy( src_val_descr, &src_variable_name);
src_reference = ecma_OpGetIdentifierReference( int_data->lex_env_p,
src_variable_name.str_p,
int_data->is_strict);
ecma_CompletionValue_t get_value_completion = ecma_op_get_value( &src_reference);
JERRY_ASSERT( get_value_completion.type == ECMA_COMPLETION_TYPE_NORMAL
|| get_value_completion.type == ECMA_COMPLETION_TYPE_THROW );
ecma_FreeReference( src_reference);
free_string_literal_copy( &src_variable_name);
if ( get_value_completion.type == ECMA_COMPLETION_TYPE_NORMAL )
{
right_value = get_value_completion.value;
} else
{
return get_value_completion;
}
break;
}
case OPCODE_ARG_TYPE_NUMBER:
{
ecma_Number_t *num_p = ecma_AllocNumber();
*num_p = get_number_by_idx( src_val_descr);
right_value.m_ValueType = ECMA_TYPE_NUMBER;
ecma_SetPointer( right_value.m_Value, num_p);
break;
}
case OPCODE_ARG_TYPE_SMALLINT:
{
ecma_Number_t *num_p = ecma_AllocNumber();
*num_p = src_val_descr;
right_value.m_ValueType = ECMA_TYPE_NUMBER;
ecma_SetPointer( right_value.m_Value, num_p);
break;
}
JERRY_UNIMPLEMENTED();
}
ecma_CompletionValue_t completion_value;
string_literal_copy dst_variable_name;
ecma_Reference_t dst_reference;
init_string_literal_copy( dst_var_idx, &dst_variable_name);
dst_reference = ecma_OpGetIdentifierReference( int_data->lex_env_p,
dst_variable_name.str_p,
int_data->is_strict);
FIXME( Move magic strings to header file and make them ecma_Char_t[] );
FIXME( Replace strcmp with ecma_Char_t[] comparator );
if ( dst_reference.is_strict
&& ( __strcmp( (char*)dst_reference.referenced_name_p, "eval") == 0
|| __strcmp( (char*)dst_reference.referenced_name_p, "arguments") == 0 )
&& ( dst_reference.base.m_ValueType == ECMA_TYPE_OBJECT )
&& ( ecma_GetPointer( dst_reference.base.m_Value) != NULL )
&& ( ( (ecma_Object_t*) ecma_GetPointer( dst_reference.base.m_Value) )->m_IsLexicalEnvironment ) )
{
completion_value = ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_SYNTAX));
} else
{
completion_value = ecma_op_put_value( &dst_reference, right_value);
}
ecma_FreeValue( right_value);
ecma_FreeReference( dst_reference);
free_string_literal_copy( &dst_variable_name);
return completion_value;
} /* opfunc_assignment */
/**
* 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_CompletionValue_t
opfunc_var_decl(OPCODE opdata, /**< operation data */
struct __int_data *int_data __unused) /**< interpreter context */
{
string_literal_copy variable_name;
init_string_literal_copy( opdata.data.var_decl.variable_name, &variable_name);
if ( ecma_IsCompletionValueNormalFalse( ecma_OpHasBinding( 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_OpCreateMutableBinding( int_data->lex_env_p,
variable_name.str_p,
false);
/* 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_OpGetBindingValue( 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_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL,
ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_EMPTY),
ECMA_TARGET_ID_RESERVED);
} /* opfunc_var_decl */
/**
* 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_CompletionValue_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_MakeSimpleValue( opdata.data.exitval.status_code == 0 ? ECMA_SIMPLE_VALUE_TRUE
: ECMA_SIMPLE_VALUE_FALSE);
return ecma_MakeCompletionValue( 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_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_1, name_lit_idx, arg1_lit_idx)
GETOP_IMPL_3 (call_2, name_lit_idx, arg1_lit_idx, arg2_lit_idx)
GETOP_IMPL_3 (call_n, name_lit_idx, arg1_lit_idx, arg2_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, arg1_lit_idx)
GETOP_IMPL_1 (varg_1_end, arg1_lit_idx)
GETOP_IMPL_2 (varg_2, arg1_lit_idx, arg2_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 (loop_inf, loop_root)
GETOP_IMPL_3 (loop_init_num, start, stop, step)
GETOP_IMPL_2 (loop_precond_begin_num, condition, after_loop_op)
GETOP_IMPL_3 (loop_precond_end_num, iterator, step, precond_begin)
GETOP_IMPL_2 (loop_postcond, condition, body_root)
GETOP_IMPL_1 (var_decl, variable_name)