Compact Byte Code parser and executor for Jerry.
JerryScript-DCO-1.0-Signed-off-by: László Langó llango.u-szeged@partner.samsung.com JerryScript-DCO-1.0-Signed-off-by: Tamas Gergely tgergely.u-szeged@partner.samsung.com JerryScript-DCO-1.0-Signed-off-by: Zsolt Borbély zsborbely.u-szeged@partner.samsung.com JerryScript-DCO-1.0-Signed-off-by: Roland Takacs rtakacs.u-szeged@partner.samsung.com JerryScript-DCO-1.0-Signed-off-by: István Kádár ikadar@inf.u-szeged.hu JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
@@ -1,217 +0,0 @@
|
||||
/* Copyright 2014-2015 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 "opcodes.h"
|
||||
#include "opcodes-ecma-support.h"
|
||||
|
||||
/**
|
||||
* 'Jump down if true' opcode handler.
|
||||
*
|
||||
* Note:
|
||||
* current instruction's position changes by adding specified offset
|
||||
* if argument evaluates to true.
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_is_true_jmp_down (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t cond_var_idx = instr.data.is_true_jmp_down.value;
|
||||
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.is_true_jmp_down.oc_idx_1,
|
||||
instr.data.is_true_jmp_down.oc_idx_2);
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (cond_value, get_variable_value (frame_ctx_p, cond_var_idx, false), ret_value);
|
||||
|
||||
ecma_completion_value_t to_bool_completion = ecma_op_to_boolean (cond_value);
|
||||
JERRY_ASSERT (ecma_is_completion_value_normal (to_bool_completion));
|
||||
|
||||
if (ecma_is_completion_value_normal_true (to_bool_completion))
|
||||
{
|
||||
JERRY_ASSERT ((uint32_t) frame_ctx_p->pos + offset < MAX_OPCODES);
|
||||
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_ctx_p->pos++;
|
||||
}
|
||||
|
||||
ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_FINALIZE (cond_value);
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
/* Likewise to opfunc_is_true_jmp_down, but jumps up. */
|
||||
ecma_completion_value_t
|
||||
opfunc_is_true_jmp_up (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t cond_var_idx = instr.data.is_true_jmp_up.value;
|
||||
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.is_true_jmp_up.oc_idx_1,
|
||||
instr.data.is_true_jmp_up.oc_idx_2);
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (cond_value, get_variable_value (frame_ctx_p, cond_var_idx, false), ret_value);
|
||||
|
||||
ecma_completion_value_t to_bool_completion = ecma_op_to_boolean (cond_value);
|
||||
JERRY_ASSERT (ecma_is_completion_value_normal (to_bool_completion));
|
||||
|
||||
if (ecma_is_completion_value_normal_true (to_bool_completion))
|
||||
{
|
||||
JERRY_ASSERT ((uint32_t) frame_ctx_p->pos >= offset);
|
||||
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos - offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_ctx_p->pos++;
|
||||
}
|
||||
|
||||
ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_FINALIZE (cond_value);
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'Jump down if false' opcode handler.
|
||||
*
|
||||
* Note:
|
||||
* current instruction's position changes by adding specified offset
|
||||
* if argument evaluates to false.
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_is_false_jmp_down (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t cond_var_idx = instr.data.is_false_jmp_down.value;
|
||||
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.is_false_jmp_down.oc_idx_1,
|
||||
instr.data.is_false_jmp_down.oc_idx_2);
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (cond_value, get_variable_value (frame_ctx_p, cond_var_idx, false), ret_value);
|
||||
|
||||
ecma_completion_value_t to_bool_completion = ecma_op_to_boolean (cond_value);
|
||||
JERRY_ASSERT (ecma_is_completion_value_normal (to_bool_completion));
|
||||
|
||||
if (!ecma_is_completion_value_normal_true (to_bool_completion))
|
||||
{
|
||||
JERRY_ASSERT ((uint32_t) frame_ctx_p->pos + offset < MAX_OPCODES);
|
||||
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_ctx_p->pos++;
|
||||
}
|
||||
|
||||
ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_FINALIZE (cond_value);
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
/* Likewise to opfunc_is_false_jmp_down, but jumps up. */
|
||||
ecma_completion_value_t
|
||||
opfunc_is_false_jmp_up (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t cond_var_idx = instr.data.is_false_jmp_up.value;
|
||||
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.is_false_jmp_up.oc_idx_1,
|
||||
instr.data.is_false_jmp_up.oc_idx_2);
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (cond_value, get_variable_value (frame_ctx_p, cond_var_idx, false), ret_value);
|
||||
|
||||
ecma_completion_value_t to_bool_completion = ecma_op_to_boolean (cond_value);
|
||||
JERRY_ASSERT (ecma_is_completion_value_normal (to_bool_completion));
|
||||
|
||||
if (!ecma_is_completion_value_normal_true (to_bool_completion))
|
||||
{
|
||||
JERRY_ASSERT ((uint32_t) frame_ctx_p->pos >= offset);
|
||||
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos - offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_ctx_p->pos++;
|
||||
}
|
||||
|
||||
ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_FINALIZE (cond_value);
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'Jump down' opcode handler.
|
||||
*
|
||||
* Note:
|
||||
* the opcode changes adds specified value to current instruction position
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_jmp_down (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.jmp_down.oc_idx_1,
|
||||
instr.data.jmp_down.oc_idx_2);
|
||||
|
||||
JERRY_ASSERT (((uint32_t) frame_ctx_p->pos + offset < MAX_OPCODES));
|
||||
|
||||
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos + offset);
|
||||
|
||||
return ecma_make_empty_completion_value ();
|
||||
}
|
||||
|
||||
/**
|
||||
* 'Jump up' opcode handler.
|
||||
*
|
||||
* Note:
|
||||
* the opcode changes substracts specified value from current instruction position
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_jmp_up (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.jmp_up.oc_idx_1,
|
||||
instr.data.jmp_up.oc_idx_2);
|
||||
JERRY_ASSERT ((uint32_t) frame_ctx_p->pos >= offset);
|
||||
|
||||
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos - offset);
|
||||
|
||||
return ecma_make_empty_completion_value ();
|
||||
}
|
||||
|
||||
/**
|
||||
* 'Break or continue jump' opcode handler.
|
||||
*
|
||||
* Note:
|
||||
* the opcode returns break-continue completion value with jump target
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_jmp_break_continue (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
vm_instr_counter_t target = frame_ctx_p->pos;
|
||||
target = (vm_instr_counter_t) (target + vm_calc_instr_counter_from_idx_idx (instr.data.jmp_down.oc_idx_1,
|
||||
instr.data.jmp_down.oc_idx_2));
|
||||
|
||||
return ecma_make_jump_completion_value (target);
|
||||
} /* opfunc_jmp_break_continue */
|
||||
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015-2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,22 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "opcodes.h"
|
||||
#include "opcodes-ecma-support.h"
|
||||
#include "ecma-alloc.h"
|
||||
#include "ecma-conversion.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-number-arithmetic.h"
|
||||
#include "ecma-try-catch-macro.h"
|
||||
#include "opcodes.h"
|
||||
#include "jrt-libc-includes.h"
|
||||
|
||||
/**
|
||||
* Number arithmetic operations.
|
||||
/** \addtogroup vm Virtual machine
|
||||
* @{
|
||||
*
|
||||
* \addtogroup vm_opcodes Opcodes
|
||||
* @{
|
||||
*/
|
||||
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.
|
||||
@@ -41,52 +40,48 @@ typedef enum
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
static ecma_completion_value_t
|
||||
do_number_arithmetic (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
|
||||
vm_idx_t dst_var_idx, /**< destination variable identifier */
|
||||
number_arithmetic_op op, /**< number arithmetic operation */
|
||||
ecma_completion_value_t
|
||||
do_number_arithmetic (number_arithmetic_op op, /**< number arithmetic operation */
|
||||
ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /** right value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
|
||||
ECMA_OP_TO_NUMBER_TRY_CATCH (num_right, right_value, ret_value);
|
||||
|
||||
ecma_number_t *res_p = frame_ctx_p->tmp_num_p;
|
||||
ecma_number_t *res_p = ecma_alloc_number ();
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case number_arithmetic_addition:
|
||||
case NUMBER_ARITHMETIC_ADDITION:
|
||||
{
|
||||
*res_p = ecma_number_add (num_left, num_right);
|
||||
break;
|
||||
}
|
||||
case number_arithmetic_substraction:
|
||||
case NUMBER_ARITHMETIC_SUBSTRACTION:
|
||||
{
|
||||
*res_p = ecma_number_substract (num_left, num_right);
|
||||
break;
|
||||
}
|
||||
case number_arithmetic_multiplication:
|
||||
case NUMBER_ARITHMETIC_MULTIPLICATION:
|
||||
{
|
||||
*res_p = ecma_number_multiply (num_left, num_right);
|
||||
break;
|
||||
}
|
||||
case number_arithmetic_division:
|
||||
case NUMBER_ARITHMETIC_DIVISION:
|
||||
{
|
||||
*res_p = ecma_number_divide (num_left, num_right);
|
||||
break;
|
||||
}
|
||||
case number_arithmetic_remainder:
|
||||
case NUMBER_ARITHMETIC_REMAINDER:
|
||||
{
|
||||
*res_p = ecma_op_number_remainder (num_left, num_right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos,
|
||||
dst_var_idx,
|
||||
ecma_make_number_value (res_p));
|
||||
ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, ecma_make_number_value (res_p));
|
||||
|
||||
ECMA_OP_TO_NUMBER_FINALIZE (num_right);
|
||||
ECMA_OP_TO_NUMBER_FINALIZE (num_left);
|
||||
@@ -103,17 +98,11 @@ do_number_arithmetic (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_addition (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_addition (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.addition.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.addition.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.addition.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (prim_left_value,
|
||||
ecma_op_to_primitive (left_value,
|
||||
ECMA_PREFERRED_TYPE_NO),
|
||||
@@ -134,172 +123,24 @@ opfunc_addition (vm_instr_t instr, /**< instruction */
|
||||
|
||||
ecma_string_t *concat_str_p = ecma_concat_ecma_strings (string1_p, string2_p);
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_string_value (concat_str_p));
|
||||
|
||||
ecma_deref_ecma_string (concat_str_p);
|
||||
ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, ecma_make_string_value (concat_str_p));
|
||||
|
||||
ECMA_FINALIZE (str_right_value);
|
||||
ECMA_FINALIZE (str_left_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_value = do_number_arithmetic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_arithmetic_addition,
|
||||
prim_left_value,
|
||||
prim_right_value);
|
||||
ret_value = do_number_arithmetic (NUMBER_ARITHMETIC_ADDITION,
|
||||
left_value,
|
||||
right_value);
|
||||
}
|
||||
|
||||
ECMA_FINALIZE (prim_right_value);
|
||||
ECMA_FINALIZE (prim_left_value);
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
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 (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.substraction.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.substraction.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.substraction.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_arithmetic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_arithmetic_substraction,
|
||||
left_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
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 (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.multiplication.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.multiplication.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.multiplication.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_arithmetic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_arithmetic_multiplication,
|
||||
left_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
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 (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.division.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.division.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.division.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_arithmetic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_arithmetic_division,
|
||||
left_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
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 (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.remainder.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.remainder.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.remainder.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_arithmetic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_arithmetic_remainder,
|
||||
left_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_remainder */
|
||||
|
||||
/**
|
||||
* 'Unary "+"' opcode handler.
|
||||
*
|
||||
@@ -309,30 +150,20 @@ opfunc_remainder (vm_instr_t instr, /**< instruction */
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_unary_plus (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_unary_plus (ecma_value_t left_value) /**< left value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.remainder.dst;
|
||||
const vm_idx_t var_idx = instr.data.remainder.var_left;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (var_value, get_variable_value (frame_ctx_p, var_idx, false), ret_value);
|
||||
ECMA_OP_TO_NUMBER_TRY_CATCH (num_var_value,
|
||||
var_value,
|
||||
left_value,
|
||||
ret_value);
|
||||
|
||||
ecma_number_t *tmp_p = frame_ctx_p->tmp_num_p;
|
||||
ecma_number_t *tmp_p = ecma_alloc_number ();
|
||||
|
||||
*tmp_p = num_var_value;
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos,
|
||||
dst_var_idx,
|
||||
ecma_make_number_value (tmp_p));
|
||||
ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, ecma_make_number_value (tmp_p));
|
||||
|
||||
ECMA_OP_TO_NUMBER_FINALIZE (num_var_value);
|
||||
ECMA_FINALIZE (var_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_unary_plus */
|
||||
@@ -346,30 +177,25 @@ opfunc_unary_plus (vm_instr_t instr, /**< instruction */
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_unary_minus (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_unary_minus (ecma_value_t left_value) /**< left value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.remainder.dst;
|
||||
const vm_idx_t var_idx = instr.data.remainder.var_left;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (var_value, get_variable_value (frame_ctx_p, var_idx, false), ret_value);
|
||||
ECMA_OP_TO_NUMBER_TRY_CATCH (num_var_value,
|
||||
var_value,
|
||||
left_value,
|
||||
ret_value);
|
||||
|
||||
ecma_number_t *tmp_p = frame_ctx_p->tmp_num_p;
|
||||
ecma_number_t *tmp_p = ecma_alloc_number ();
|
||||
|
||||
*tmp_p = ecma_number_negate (num_var_value);
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos,
|
||||
dst_var_idx,
|
||||
ecma_make_number_value (tmp_p));
|
||||
ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, ecma_make_number_value (tmp_p));
|
||||
|
||||
ECMA_OP_TO_NUMBER_FINALIZE (num_var_value);
|
||||
ECMA_FINALIZE (var_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_unary_minus */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015-2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,22 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ecma-alloc.h"
|
||||
#include "ecma-conversion.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-try-catch-macro.h"
|
||||
#include "opcodes.h"
|
||||
#include "opcodes-ecma-support.h"
|
||||
|
||||
/**
|
||||
* Number bitwise logic operations.
|
||||
/** \addtogroup vm Virtual machine
|
||||
* @{
|
||||
*
|
||||
* \addtogroup vm_opcodes Opcodes
|
||||
* @{
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
number_bitwise_logic_and, /**< bitwise AND calculation */
|
||||
number_bitwise_logic_or, /**< bitwise OR calculation */
|
||||
number_bitwise_logic_xor, /**< bitwise XOR calculation */
|
||||
number_bitwise_shift_left, /**< bitwise LEFT SHIFT calculation */
|
||||
number_bitwise_shift_right, /**< bitwise RIGHT_SHIFT calculation */
|
||||
number_bitwise_shift_uright, /**< bitwise UNSIGNED RIGHT SHIFT calculation */
|
||||
number_bitwise_not, /**< bitwise NOT calculation */
|
||||
} number_bitwise_logic_op;
|
||||
|
||||
/**
|
||||
* Perform ECMA number logic operation.
|
||||
@@ -41,10 +38,8 @@ typedef enum
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
static ecma_completion_value_t
|
||||
do_number_bitwise_logic (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
|
||||
vm_idx_t dst_var_idx, /**< destination variable identifier */
|
||||
number_bitwise_logic_op op, /**< number bitwise logic operation */
|
||||
ecma_completion_value_t
|
||||
do_number_bitwise_logic (number_bitwise_logic_op op, /**< number bitwise logic operation */
|
||||
ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /** right value */
|
||||
{
|
||||
@@ -53,56 +48,53 @@ do_number_bitwise_logic (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context *
|
||||
ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
|
||||
ECMA_OP_TO_NUMBER_TRY_CATCH (num_right, right_value, ret_value);
|
||||
|
||||
ecma_number_t* res_p = frame_ctx_p->tmp_num_p;
|
||||
ecma_number_t* res_p = ecma_alloc_number ();
|
||||
|
||||
int32_t left_int32 = ecma_number_to_int32 (num_left);
|
||||
// int32_t right_int32 = ecma_number_to_int32 (num_right);
|
||||
|
||||
uint32_t left_uint32 = ecma_number_to_uint32 (num_left);
|
||||
uint32_t right_uint32 = ecma_number_to_uint32 (num_right);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case number_bitwise_logic_and:
|
||||
case NUMBER_BITWISE_LOGIC_AND:
|
||||
{
|
||||
*res_p = ecma_int32_to_number ((int32_t) (left_uint32 & right_uint32));
|
||||
break;
|
||||
}
|
||||
case number_bitwise_logic_or:
|
||||
case NUMBER_BITWISE_LOGIC_OR:
|
||||
{
|
||||
*res_p = ecma_int32_to_number ((int32_t) (left_uint32 | right_uint32));
|
||||
break;
|
||||
}
|
||||
case number_bitwise_logic_xor:
|
||||
case NUMBER_BITWISE_LOGIC_XOR:
|
||||
{
|
||||
*res_p = ecma_int32_to_number ((int32_t) (left_uint32 ^ right_uint32));
|
||||
break;
|
||||
}
|
||||
case number_bitwise_shift_left:
|
||||
case NUMBER_BITWISE_SHIFT_LEFT:
|
||||
{
|
||||
*res_p = ecma_int32_to_number (left_int32 << (right_uint32 & 0x1F));
|
||||
break;
|
||||
}
|
||||
case number_bitwise_shift_right:
|
||||
case NUMBER_BITWISE_SHIFT_RIGHT:
|
||||
{
|
||||
*res_p = ecma_int32_to_number (left_int32 >> (right_uint32 & 0x1F));
|
||||
break;
|
||||
}
|
||||
case number_bitwise_shift_uright:
|
||||
case NUMBER_BITWISE_SHIFT_URIGHT:
|
||||
{
|
||||
*res_p = ecma_uint32_to_number (left_uint32 >> (right_uint32 & 0x1F));
|
||||
break;
|
||||
}
|
||||
case number_bitwise_not:
|
||||
case NUMBER_BITWISE_NOT:
|
||||
{
|
||||
*res_p = ecma_int32_to_number ((int32_t) ~right_uint32);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos,
|
||||
dst_var_idx,
|
||||
ecma_make_number_value (res_p));
|
||||
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (res_p));
|
||||
|
||||
ECMA_OP_TO_NUMBER_FINALIZE (num_right);
|
||||
ECMA_OP_TO_NUMBER_FINALIZE (num_left);
|
||||
@@ -111,243 +103,6 @@ do_number_bitwise_logic (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context *
|
||||
} /* do_number_bitwise_logic */
|
||||
|
||||
/**
|
||||
* 'Bitwise AND' opcode handler.
|
||||
*
|
||||
* See also: ECMA-262 v5, 11.10
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_b_and (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.b_and.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.b_and.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.b_and.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_bitwise_logic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_bitwise_logic_and,
|
||||
left_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_b_and */
|
||||
|
||||
/**
|
||||
* 'Bitwise OR' opcode handler.
|
||||
*
|
||||
* See also: ECMA-262 v5, 11.10
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_b_or (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.b_or.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.b_or.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.b_or.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_bitwise_logic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_bitwise_logic_or,
|
||||
left_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_b_or */
|
||||
|
||||
/**
|
||||
* 'Bitwise XOR' opcode handler.
|
||||
*
|
||||
* See also: ECMA-262 v5, 11.10
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_b_xor (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.b_xor.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.b_xor.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.b_xor.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_bitwise_logic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_bitwise_logic_xor,
|
||||
left_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_b_xor */
|
||||
|
||||
/**
|
||||
* 'Left Shift Operator' opcode handler.
|
||||
*
|
||||
* See also: ECMA-262 v5, 11.7.1
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_b_shift_left (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.b_shift_left.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.b_shift_left.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.b_shift_left.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_bitwise_logic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_bitwise_shift_left,
|
||||
left_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_b_shift_left */
|
||||
|
||||
/**
|
||||
* 'Right Shift Operator' opcode handler.
|
||||
*
|
||||
* See also: ECMA-262 v5, 11.7.2
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_b_shift_right (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.b_shift_right.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.b_shift_right.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.b_shift_right.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_bitwise_logic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_bitwise_shift_right,
|
||||
left_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_b_shift_right */
|
||||
|
||||
/**
|
||||
* 'Unsigned Right Shift Operator' opcode handler.
|
||||
*
|
||||
* See also: ECMA-262 v5, 11.7.3
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_b_shift_uright (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.b_shift_uright.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.b_shift_uright.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.b_shift_uright.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_bitwise_logic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_bitwise_shift_uright,
|
||||
left_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_b_shift_uright */
|
||||
|
||||
/**
|
||||
* 'Bitwise NOT Operator' opcode handler.
|
||||
*
|
||||
* See also: ECMA-262 v5, 10.4
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_b_not (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.b_not.dst;
|
||||
const vm_idx_t right_var_idx = instr.data.b_not.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
ret_value = do_number_bitwise_logic (frame_ctx_p,
|
||||
dst_var_idx,
|
||||
number_bitwise_not,
|
||||
right_value,
|
||||
right_value);
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_b_not */
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015-2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,8 +14,23 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ecma-builtins.h"
|
||||
#include "ecma-comparison.h"
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-function-object.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-lex-env.h"
|
||||
#include "ecma-try-catch-macro.h"
|
||||
#include "opcodes.h"
|
||||
#include "opcodes-ecma-support.h"
|
||||
#include "vm-defines.h"
|
||||
|
||||
/** \addtogroup vm Virtual machine
|
||||
* @{
|
||||
*
|
||||
* \addtogroup vm_opcodes Opcodes
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* 'Equals' opcode handler.
|
||||
@@ -25,17 +41,11 @@
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_equal_value (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_equal_value (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.equal_value.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.equal_value.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.equal_value.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (compare_result,
|
||||
ecma_op_abstract_equality_compare (left_value,
|
||||
right_value),
|
||||
@@ -43,14 +53,9 @@ opfunc_equal_value (vm_instr_t instr, /**< instruction */
|
||||
|
||||
JERRY_ASSERT (ecma_is_value_boolean (compare_result));
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx,
|
||||
compare_result);
|
||||
ret_value = ecma_make_normal_completion_value (compare_result);
|
||||
|
||||
ECMA_FINALIZE (compare_result);
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_equal_value */
|
||||
@@ -64,17 +69,11 @@ opfunc_equal_value (vm_instr_t instr, /**< instruction */
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_not_equal_value (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_not_equal_value (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.not_equal_value.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.not_equal_value.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.not_equal_value.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (compare_result,
|
||||
ecma_op_abstract_equality_compare (left_value, right_value),
|
||||
ret_value);
|
||||
@@ -83,15 +82,10 @@ opfunc_not_equal_value (vm_instr_t instr, /**< instruction */
|
||||
|
||||
bool is_equal = ecma_is_value_true (compare_result);
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx,
|
||||
ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE
|
||||
: ECMA_SIMPLE_VALUE_TRUE));
|
||||
ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE
|
||||
: ECMA_SIMPLE_VALUE_TRUE));
|
||||
|
||||
ECMA_FINALIZE (compare_result);
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_not_equal_value */
|
||||
@@ -105,30 +99,13 @@ opfunc_not_equal_value (vm_instr_t instr, /**< instruction */
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_equal_value_type (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_equal_value_type (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.equal_value_type.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.equal_value_type.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.equal_value_type.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
bool is_equal = ecma_op_strict_equality_compare (left_value, right_value);
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, 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);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
return ecma_make_normal_completion_value (ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE
|
||||
: ECMA_SIMPLE_VALUE_FALSE));
|
||||
} /* opfunc_equal_value_type */
|
||||
|
||||
/**
|
||||
@@ -140,29 +117,16 @@ opfunc_equal_value_type (vm_instr_t instr, /**< instruction */
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_not_equal_value_type (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_not_equal_value_type (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.not_equal_value_type.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.not_equal_value_type.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.not_equal_value_type.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
bool is_equal = ecma_op_strict_equality_compare (left_value, right_value);
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, 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);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
return ecma_make_normal_completion_value (ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE
|
||||
: ECMA_SIMPLE_VALUE_TRUE));
|
||||
} /* opfunc_not_equal_value_type */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015-2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,8 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ecma-comparison.h"
|
||||
#include "ecma-conversion.h"
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-objects.h"
|
||||
#include "ecma-try-catch-macro.h"
|
||||
#include "opcodes.h"
|
||||
#include "opcodes-ecma-support.h"
|
||||
|
||||
/** \addtogroup vm Virtual machine
|
||||
* @{
|
||||
*
|
||||
* \addtogroup vm_opcodes Opcodes
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* 'Less-than' opcode handler.
|
||||
@@ -25,17 +38,11 @@
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_less_than (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_less_than (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.less_than.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.less_than.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.less_than.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (compare_result,
|
||||
ecma_op_abstract_relational_compare (left_value, right_value, true),
|
||||
ret_value);
|
||||
@@ -53,13 +60,9 @@ opfunc_less_than (vm_instr_t instr, /**< instruction */
|
||||
res = (ecma_is_value_true (compare_result) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE);
|
||||
}
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_simple_value (res));
|
||||
ret_value = ecma_make_simple_completion_value (res);
|
||||
|
||||
ECMA_FINALIZE (compare_result);
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_less_than */
|
||||
@@ -73,17 +76,11 @@ opfunc_less_than (vm_instr_t instr, /**< instruction */
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_greater_than (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_greater_than (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.greater_than.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.greater_than.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.greater_than.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (compare_result,
|
||||
ecma_op_abstract_relational_compare (right_value, left_value, false),
|
||||
ret_value);
|
||||
@@ -101,13 +98,9 @@ opfunc_greater_than (vm_instr_t instr, /**< instruction */
|
||||
res = (ecma_is_value_true (compare_result) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE);
|
||||
}
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_simple_value (res));
|
||||
ret_value = ecma_make_simple_completion_value (res);
|
||||
|
||||
ECMA_FINALIZE (compare_result);
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_greater_than */
|
||||
@@ -121,17 +114,11 @@ opfunc_greater_than (vm_instr_t instr, /**< instruction */
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_less_or_equal_than (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_less_or_equal_than (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.less_or_equal_than.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.less_or_equal_than.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.less_or_equal_than.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (compare_result,
|
||||
ecma_op_abstract_relational_compare (right_value, left_value, false),
|
||||
ret_value);
|
||||
@@ -156,13 +143,9 @@ opfunc_less_or_equal_than (vm_instr_t instr, /**< instruction */
|
||||
}
|
||||
}
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_simple_value (res));
|
||||
ret_value = ecma_make_simple_completion_value (res);
|
||||
|
||||
ECMA_FINALIZE (compare_result);
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_less_or_equal_than */
|
||||
@@ -176,17 +159,11 @@ opfunc_less_or_equal_than (vm_instr_t instr, /**< instruction */
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_greater_or_equal_than (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
opfunc_greater_or_equal_than (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_var_idx = instr.data.greater_or_equal_than.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.greater_or_equal_than.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.greater_or_equal_than.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (compare_result,
|
||||
ecma_op_abstract_relational_compare (left_value, right_value, true),
|
||||
ret_value);
|
||||
@@ -211,13 +188,9 @@ opfunc_greater_or_equal_than (vm_instr_t instr, /**< instruction */
|
||||
}
|
||||
}
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_simple_value (res));
|
||||
ret_value = ecma_make_simple_completion_value (res);
|
||||
|
||||
ECMA_FINALIZE (compare_result);
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_greater_or_equal_than */
|
||||
@@ -231,18 +204,11 @@ opfunc_greater_or_equal_than (vm_instr_t instr, /**< instruction */
|
||||
* returned value must be freed with ecma_free_completion_value.
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_instanceof (vm_instr_t instr __attr_unused___, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p __attr_unused___) /**< interpreter context */
|
||||
opfunc_instanceof (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_idx = instr.data.instanceof.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.instanceof.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.instanceof.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
if (!ecma_is_value_object (right_value))
|
||||
{
|
||||
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
|
||||
@@ -255,16 +221,11 @@ opfunc_instanceof (vm_instr_t instr __attr_unused___, /**< instruction */
|
||||
ecma_op_object_has_instance (right_value_obj_p, left_value),
|
||||
ret_value);
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_idx, is_instance_of);
|
||||
ret_value = ecma_make_normal_completion_value (is_instance_of);
|
||||
|
||||
ECMA_FINALIZE (is_instance_of);
|
||||
}
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_instanceof */
|
||||
|
||||
@@ -277,18 +238,11 @@ opfunc_instanceof (vm_instr_t instr __attr_unused___, /**< instruction */
|
||||
* returned value must be freed with ecma_free_completion_value.
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_in (vm_instr_t instr __attr_unused___, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p __attr_unused___) /**< interpreter context */
|
||||
opfunc_in (ecma_value_t left_value, /**< left value */
|
||||
ecma_value_t right_value) /**< right value */
|
||||
{
|
||||
const vm_idx_t dst_idx = instr.data.in.dst;
|
||||
const vm_idx_t left_var_idx = instr.data.in.var_left;
|
||||
const vm_idx_t right_var_idx = instr.data.in.var_right;
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
|
||||
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
|
||||
|
||||
if (!ecma_is_value_object (right_value))
|
||||
{
|
||||
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
|
||||
@@ -310,17 +264,15 @@ opfunc_in (vm_instr_t instr __attr_unused___, /**< instruction */
|
||||
is_in = ECMA_SIMPLE_VALUE_FALSE;
|
||||
}
|
||||
|
||||
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos,
|
||||
dst_idx,
|
||||
ecma_make_simple_value (is_in));
|
||||
ret_value = ecma_make_simple_completion_value (is_in);
|
||||
|
||||
ECMA_FINALIZE (str_left_value);
|
||||
}
|
||||
|
||||
ECMA_FINALIZE (right_value);
|
||||
ECMA_FINALIZE (left_value);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_in */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/* Copyright 2014-2015 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.
|
||||
*/
|
||||
|
||||
#ifndef OPCODES_ECMA_SUPPORT_H
|
||||
#define OPCODES_ECMA_SUPPORT_H
|
||||
|
||||
#include "ecma-alloc.h"
|
||||
#include "ecma-array-object.h"
|
||||
#include "ecma-builtins.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-lex-env.h"
|
||||
#include "ecma-number-arithmetic.h"
|
||||
#include "ecma-objects.h"
|
||||
#include "ecma-objects-general.h"
|
||||
#include "ecma-reference.h"
|
||||
#include "ecma-regexp-object.h"
|
||||
#include "ecma-try-catch-macro.h"
|
||||
|
||||
bool vm_is_reg_variable (vm_idx_t);
|
||||
ecma_completion_value_t get_variable_value (vm_frame_ctx_t *, vm_idx_t, bool);
|
||||
ecma_completion_value_t set_variable_value (vm_frame_ctx_t *, vm_instr_counter_t, vm_idx_t, ecma_value_t);
|
||||
ecma_completion_value_t vm_fill_varg_list (vm_frame_ctx_t *, ecma_length_t, ecma_collection_header_t *);
|
||||
extern vm_instr_counter_t vm_fill_params_list (const bytecode_data_header_t *,
|
||||
vm_instr_counter_t,
|
||||
ecma_length_t,
|
||||
ecma_collection_header_t *);
|
||||
extern ecma_completion_value_t vm_function_declaration (const bytecode_data_header_t *bytecode_header_p,
|
||||
bool is_strict,
|
||||
bool is_eval_code,
|
||||
ecma_object_t *lex_env_p);
|
||||
#endif /* OPCODES_ECMA_SUPPORT_H */
|
||||
@@ -1,134 +0,0 @@
|
||||
/* Copyright 2014-2015 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 "bytecode-data.h"
|
||||
#include "jrt.h"
|
||||
#include "vm.h"
|
||||
#include "opcodes.h"
|
||||
#include "opcodes-ecma-support.h"
|
||||
|
||||
/**
|
||||
* 'Try' opcode handler.
|
||||
*
|
||||
* See also: ECMA-262 v5, 12.14
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_try_block (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t block_end_oc_idx_1 = instr.data.try_block.oc_idx_1;
|
||||
const vm_idx_t block_end_oc_idx_2 = instr.data.try_block.oc_idx_2;
|
||||
const vm_instr_counter_t try_end_oc = (vm_instr_counter_t) (
|
||||
vm_calc_instr_counter_from_idx_idx (block_end_oc_idx_1, block_end_oc_idx_2) + frame_ctx_p->pos);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
vm_run_scope_t run_scope_try = { frame_ctx_p->pos, try_end_oc };
|
||||
ecma_completion_value_t try_completion = vm_loop (frame_ctx_p, &run_scope_try);
|
||||
JERRY_ASSERT ((!ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos <= try_end_oc)
|
||||
|| (ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos == try_end_oc));
|
||||
frame_ctx_p->pos = try_end_oc;
|
||||
|
||||
vm_instr_t next_instr = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos);
|
||||
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
|
||||
|
||||
if (next_instr.data.meta.type == OPCODE_META_TYPE_CATCH)
|
||||
{
|
||||
const vm_instr_counter_t catch_end_oc = (vm_instr_counter_t) (
|
||||
vm_read_instr_counter_from_meta (OPCODE_META_TYPE_CATCH,
|
||||
frame_ctx_p->bytecode_header_p,
|
||||
frame_ctx_p->pos) + frame_ctx_p->pos);
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
if (ecma_is_completion_value_throw (try_completion))
|
||||
{
|
||||
next_instr = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos);
|
||||
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
|
||||
JERRY_ASSERT (next_instr.data.meta.type == OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER);
|
||||
|
||||
lit_cpointer_t catch_exc_val_var_name_lit_cp = bc_get_literal_cp_by_uid (next_instr.data.meta.data_1,
|
||||
frame_ctx_p->bytecode_header_p,
|
||||
frame_ctx_p->pos);
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
ecma_string_t *catch_exc_var_name_str_p = ecma_new_ecma_string_from_lit_cp (catch_exc_val_var_name_lit_cp);
|
||||
|
||||
ecma_object_t *old_env_p = frame_ctx_p->lex_env_p;
|
||||
ecma_object_t *catch_env_p = ecma_create_decl_lex_env (old_env_p);
|
||||
ecma_completion_value_t completion = ecma_op_create_mutable_binding (catch_env_p,
|
||||
catch_exc_var_name_str_p,
|
||||
false);
|
||||
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
|
||||
|
||||
completion = ecma_op_set_mutable_binding (catch_env_p,
|
||||
catch_exc_var_name_str_p,
|
||||
ecma_get_completion_value_value (try_completion),
|
||||
false);
|
||||
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
|
||||
|
||||
ecma_deref_ecma_string (catch_exc_var_name_str_p);
|
||||
|
||||
frame_ctx_p->lex_env_p = catch_env_p;
|
||||
|
||||
ecma_free_completion_value (try_completion);
|
||||
|
||||
vm_run_scope_t run_scope_catch = { frame_ctx_p->pos, catch_end_oc };
|
||||
try_completion = vm_loop (frame_ctx_p, &run_scope_catch);
|
||||
|
||||
frame_ctx_p->lex_env_p = old_env_p;
|
||||
|
||||
ecma_deref_object (catch_env_p);
|
||||
|
||||
JERRY_ASSERT ((!ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos <= catch_end_oc)
|
||||
|| (ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos == catch_end_oc));
|
||||
}
|
||||
|
||||
frame_ctx_p->pos = catch_end_oc;
|
||||
}
|
||||
|
||||
next_instr = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos);
|
||||
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
|
||||
|
||||
if (next_instr.data.meta.type == OPCODE_META_TYPE_FINALLY)
|
||||
{
|
||||
const vm_instr_counter_t finally_end_oc = (vm_instr_counter_t) (
|
||||
vm_read_instr_counter_from_meta (OPCODE_META_TYPE_FINALLY,
|
||||
frame_ctx_p->bytecode_header_p,
|
||||
frame_ctx_p->pos) + frame_ctx_p->pos);
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
vm_run_scope_t run_scope_finally = { frame_ctx_p->pos, finally_end_oc };
|
||||
ecma_completion_value_t finally_completion = vm_loop (frame_ctx_p, &run_scope_finally);
|
||||
|
||||
JERRY_ASSERT ((!ecma_is_completion_value_empty (finally_completion) && frame_ctx_p->pos <= finally_end_oc)
|
||||
|| (ecma_is_completion_value_empty (finally_completion) && frame_ctx_p->pos == finally_end_oc));
|
||||
frame_ctx_p->pos = finally_end_oc;
|
||||
|
||||
if (!ecma_is_completion_value_empty (finally_completion))
|
||||
{
|
||||
ecma_free_completion_value (try_completion);
|
||||
try_completion = finally_completion;
|
||||
}
|
||||
}
|
||||
|
||||
next_instr = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos++);
|
||||
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
|
||||
JERRY_ASSERT (next_instr.data.meta.type == OPCODE_META_TYPE_END_TRY_CATCH_FINALLY);
|
||||
|
||||
return try_completion;
|
||||
} /* opfunc_try_block */
|
||||
@@ -1,125 +0,0 @@
|
||||
/* Copyright 2015 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 "bytecode-data.h"
|
||||
#include "jrt.h"
|
||||
#include "opcodes.h"
|
||||
#include "opcodes-ecma-support.h"
|
||||
|
||||
/**
|
||||
* 'for-in' opcode handler
|
||||
*
|
||||
* See also:
|
||||
* ECMA-262 v5, 12.6.4
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
opfunc_for_in (vm_instr_t instr, /**< instruction */
|
||||
vm_frame_ctx_t *int_data_p) /**< interpreter context */
|
||||
{
|
||||
const vm_idx_t expr_idx = instr.data.for_in.expr;
|
||||
const vm_idx_t block_end_oc_idx_1 = instr.data.for_in.oc_idx_1;
|
||||
const vm_idx_t block_end_oc_idx_2 = instr.data.for_in.oc_idx_2;
|
||||
const vm_instr_counter_t for_in_end_oc = (vm_instr_counter_t) (
|
||||
vm_calc_instr_counter_from_idx_idx (block_end_oc_idx_1,
|
||||
block_end_oc_idx_2) + int_data_p->pos);
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
/* 1., 2. */
|
||||
ECMA_TRY_CATCH (expr_value,
|
||||
get_variable_value (int_data_p,
|
||||
expr_idx,
|
||||
false),
|
||||
ret_value);
|
||||
|
||||
int_data_p->pos++;
|
||||
|
||||
vm_instr_t meta_instr = vm_get_instr (int_data_p->bytecode_header_p->instrs_p, for_in_end_oc);
|
||||
JERRY_ASSERT (meta_instr.op_idx == VM_OP_META);
|
||||
JERRY_ASSERT (meta_instr.data.meta.type == OPCODE_META_TYPE_END_FOR_IN);
|
||||
|
||||
/* 3. */
|
||||
if (!ecma_is_value_undefined (expr_value)
|
||||
&& !ecma_is_value_null (expr_value))
|
||||
{
|
||||
/* 4. */
|
||||
ECMA_TRY_CATCH (obj_expr_value,
|
||||
ecma_op_to_object (expr_value),
|
||||
ret_value);
|
||||
|
||||
ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value);
|
||||
|
||||
ecma_collection_iterator_t names_iterator;
|
||||
ecma_collection_header_t *names_p = ecma_op_object_get_property_names (obj_p, false, true, true);
|
||||
|
||||
if (names_p != NULL)
|
||||
{
|
||||
ecma_collection_iterator_init (&names_iterator, names_p);
|
||||
|
||||
const vm_instr_counter_t for_in_body_begin_oc = int_data_p->pos;
|
||||
const vm_instr_counter_t for_in_body_end_oc = for_in_end_oc;
|
||||
|
||||
while (ecma_collection_iterator_next (&names_iterator))
|
||||
{
|
||||
ecma_value_t name_value = *names_iterator.current_value_p;
|
||||
|
||||
ecma_string_t *name_p = ecma_get_string_from_value (name_value);
|
||||
|
||||
if (ecma_op_object_get_property (obj_p, name_p) != NULL)
|
||||
{
|
||||
ecma_completion_value_t completion = set_variable_value (int_data_p,
|
||||
int_data_p->pos,
|
||||
VM_REG_SPECIAL_FOR_IN_PROPERTY_NAME,
|
||||
name_value);
|
||||
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
|
||||
|
||||
vm_run_scope_t run_scope_for_in = { for_in_body_begin_oc, for_in_body_end_oc };
|
||||
|
||||
ecma_completion_value_t for_in_body_completion = vm_loop (int_data_p, &run_scope_for_in);
|
||||
if (ecma_is_completion_value_empty (for_in_body_completion))
|
||||
{
|
||||
JERRY_ASSERT (int_data_p->pos == for_in_body_end_oc);
|
||||
|
||||
int_data_p->pos = for_in_body_begin_oc;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_completion_value_throw (for_in_body_completion)
|
||||
|| ecma_is_completion_value_return (for_in_body_completion)
|
||||
|| ecma_is_completion_value_jump (for_in_body_completion));
|
||||
JERRY_ASSERT (int_data_p->pos <= for_in_body_end_oc);
|
||||
|
||||
ret_value = for_in_body_completion;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ecma_free_values_collection (names_p, true);
|
||||
}
|
||||
|
||||
ECMA_FINALIZE (obj_expr_value);
|
||||
}
|
||||
|
||||
int_data_p->pos = (vm_instr_counter_t) (for_in_end_oc + 1u);
|
||||
|
||||
ECMA_FINALIZE (expr_value);
|
||||
|
||||
return ret_value;
|
||||
} /* opfunc_for_in */
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
/* Copyright 2014-2015 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 "bytecode-data.h"
|
||||
#include "opcodes-ecma-support.h"
|
||||
|
||||
#ifndef JERRY_NDEBUG
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static void
|
||||
do_strict_eval_arguments_check (ecma_object_t *ref_base_lex_env_p, /**< base of ECMA-reference
|
||||
(lexical environment) */
|
||||
ecma_string_t *var_name_string_p, /**< variable name */
|
||||
bool is_strict) /**< flag indicating strict mode */
|
||||
{
|
||||
bool is_check_failed = false;
|
||||
|
||||
if (is_strict)
|
||||
{
|
||||
if (ref_base_lex_env_p != NULL)
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_lexical_environment (ref_base_lex_env_p));
|
||||
|
||||
ecma_string_t* magic_string_eval = ecma_get_magic_string (LIT_MAGIC_STRING_EVAL);
|
||||
ecma_string_t* magic_string_arguments = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
|
||||
|
||||
is_check_failed = (ecma_compare_ecma_strings (var_name_string_p,
|
||||
magic_string_eval)
|
||||
|| ecma_compare_ecma_strings (var_name_string_p,
|
||||
magic_string_arguments));
|
||||
|
||||
ecma_deref_ecma_string (magic_string_eval);
|
||||
ecma_deref_ecma_string (magic_string_arguments);
|
||||
}
|
||||
}
|
||||
|
||||
JERRY_ASSERT (!is_check_failed);
|
||||
} /* do_strict_eval_arguments_check */
|
||||
#endif /* !JERRY_NDEBUG */
|
||||
|
||||
/**
|
||||
* Check if the variable is register variable.
|
||||
*
|
||||
* @return true - if var_idx is a register variable,
|
||||
* false - otherwise.
|
||||
*/
|
||||
bool
|
||||
vm_is_reg_variable (vm_idx_t var_idx) /**< variable identifier */
|
||||
{
|
||||
return (var_idx >= VM_REG_FIRST && var_idx <= VM_REG_LAST);
|
||||
} /* vm_is_reg_variable */
|
||||
|
||||
/**
|
||||
* Get variable's value.
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
get_variable_value (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
|
||||
vm_idx_t 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 = ecma_make_empty_completion_value ();
|
||||
|
||||
if (vm_is_reg_variable (var_idx))
|
||||
{
|
||||
ecma_value_t reg_value = vm_stack_frame_get_reg_value (&frame_ctx_p->stack_frame, var_idx);
|
||||
|
||||
JERRY_ASSERT (!ecma_is_value_empty (reg_value));
|
||||
|
||||
ret_value = ecma_make_normal_completion_value (ecma_copy_value (reg_value, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
ecma_string_t var_name_string;
|
||||
lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (var_idx,
|
||||
frame_ctx_p->bytecode_header_p,
|
||||
frame_ctx_p->pos);
|
||||
JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL);
|
||||
ecma_new_ecma_string_on_stack_from_lit_cp (&var_name_string, lit_cp);
|
||||
|
||||
ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p,
|
||||
&var_name_string);
|
||||
|
||||
if (do_eval_or_arguments_check)
|
||||
{
|
||||
#ifndef JERRY_NDEBUG
|
||||
do_strict_eval_arguments_check (ref_base_lex_env_p,
|
||||
&var_name_string,
|
||||
frame_ctx_p->is_strict);
|
||||
#endif /* !JERRY_NDEBUG */
|
||||
}
|
||||
|
||||
ret_value = ecma_op_get_value_lex_env_base (ref_base_lex_env_p,
|
||||
&var_name_string,
|
||||
frame_ctx_p->is_strict);
|
||||
|
||||
ecma_check_that_ecma_string_need_not_be_freed (&var_name_string);
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
} /* get_variable_value */
|
||||
|
||||
/**
|
||||
* Set variable's value.
|
||||
*
|
||||
* @return completion value
|
||||
* Returned value must be freed with ecma_free_completion_value
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
set_variable_value (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
|
||||
vm_instr_counter_t lit_oc, /**< instruction counter for literal */
|
||||
vm_idx_t var_idx, /**< variable identifier */
|
||||
ecma_value_t value) /**< value to set */
|
||||
{
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
if (vm_is_reg_variable (var_idx))
|
||||
{
|
||||
ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ecma_value_t reg_value = vm_stack_frame_get_reg_value (&frame_ctx_p->stack_frame, var_idx);
|
||||
|
||||
if (ecma_is_value_number (reg_value)
|
||||
&& ecma_is_value_number (value))
|
||||
{
|
||||
*ecma_get_number_from_value (reg_value) = *ecma_get_number_from_value (value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ecma_is_value_empty (reg_value))
|
||||
{
|
||||
ecma_free_value (reg_value, false);
|
||||
}
|
||||
|
||||
vm_stack_frame_set_reg_value (&frame_ctx_p->stack_frame, var_idx, ecma_copy_value (value, false));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ecma_string_t var_name_string;
|
||||
lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (var_idx, frame_ctx_p->bytecode_header_p, lit_oc);
|
||||
JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL);
|
||||
ecma_new_ecma_string_on_stack_from_lit_cp (&var_name_string, lit_cp);
|
||||
|
||||
ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p,
|
||||
&var_name_string);
|
||||
|
||||
#ifndef JERRY_NDEBUG
|
||||
do_strict_eval_arguments_check (ref_base_lex_env_p,
|
||||
&var_name_string,
|
||||
frame_ctx_p->is_strict);
|
||||
#endif /* !JERRY_NDEBUG */
|
||||
|
||||
ret_value = ecma_op_put_value_lex_env_base (ref_base_lex_env_p,
|
||||
&var_name_string,
|
||||
frame_ctx_p->is_strict,
|
||||
value);
|
||||
|
||||
ecma_check_that_ecma_string_need_not_be_freed (&var_name_string);
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
} /* set_variable_value */
|
||||
@@ -1,109 +0,0 @@
|
||||
/* Copyright 2014-2015 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 "bytecode-data.h"
|
||||
#include "jrt.h"
|
||||
#include "opcodes.h"
|
||||
#include "opcodes-ecma-support.h"
|
||||
#include "vm.h"
|
||||
|
||||
/**
|
||||
* Fill arguments' list
|
||||
*
|
||||
* @return empty completion value if argument list was filled successfully,
|
||||
* otherwise - not normal completion value indicating completion type
|
||||
* of last expression evaluated
|
||||
*/
|
||||
ecma_completion_value_t
|
||||
vm_fill_varg_list (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
|
||||
ecma_length_t args_number, /**< number of arguments */
|
||||
ecma_collection_header_t *arg_collection_p) /** collection to fill with argument values */
|
||||
{
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
|
||||
ecma_length_t arg_index;
|
||||
for (arg_index = 0;
|
||||
arg_index < args_number && ecma_is_completion_value_empty (ret_value);
|
||||
arg_index++)
|
||||
{
|
||||
ECMA_TRY_CATCH (evaluate_arg,
|
||||
vm_loop (frame_ctx_p, NULL),
|
||||
ret_value);
|
||||
|
||||
vm_instr_t next_instr = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos);
|
||||
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
|
||||
JERRY_ASSERT (next_instr.data.meta.type == OPCODE_META_TYPE_VARG);
|
||||
|
||||
const vm_idx_t varg_var_idx = next_instr.data.meta.data_1;
|
||||
|
||||
ECMA_TRY_CATCH (get_arg,
|
||||
get_variable_value (frame_ctx_p, varg_var_idx, false),
|
||||
ret_value);
|
||||
|
||||
ecma_append_to_values_collection (arg_collection_p,
|
||||
ecma_get_completion_value_value (get_arg_completion),
|
||||
true);
|
||||
|
||||
ECMA_FINALIZE (get_arg);
|
||||
|
||||
frame_ctx_p->pos++;
|
||||
|
||||
ECMA_FINALIZE (evaluate_arg);
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
} /* vm_fill_varg_list */
|
||||
|
||||
/**
|
||||
* Fill parameters' list
|
||||
*/
|
||||
vm_instr_counter_t
|
||||
vm_fill_params_list (const bytecode_data_header_t *bytecode_header_p, /**< header of byte-code */
|
||||
vm_instr_counter_t first_instr_pos, /**< position of the first instruction
|
||||
* with a formal parameter's name */
|
||||
ecma_length_t params_number, /**< number of parameters */
|
||||
ecma_collection_header_t *formal_params_collection_p) /**< collection to fill with
|
||||
* parameters' names */
|
||||
{
|
||||
vm_instr_counter_t instr_pos = first_instr_pos;
|
||||
|
||||
uint32_t param_index;
|
||||
for (param_index = 0;
|
||||
param_index < params_number;
|
||||
param_index++)
|
||||
{
|
||||
vm_instr_t next_instr = vm_get_instr (bytecode_header_p->instrs_p, instr_pos);
|
||||
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
|
||||
JERRY_ASSERT (next_instr.data.meta.type == OPCODE_META_TYPE_VARG);
|
||||
|
||||
const lit_cpointer_t param_name_lit_idx = bc_get_literal_cp_by_uid (next_instr.data.meta.data_1,
|
||||
bytecode_header_p,
|
||||
instr_pos);
|
||||
|
||||
ecma_string_t *param_name_str_p = ecma_new_ecma_string_from_lit_cp (param_name_lit_idx);
|
||||
ecma_value_t param_name_value = ecma_make_string_value (param_name_str_p);
|
||||
|
||||
ecma_append_to_values_collection (formal_params_collection_p, param_name_value, false);
|
||||
|
||||
ecma_deref_ecma_string (param_name_str_p);
|
||||
|
||||
instr_pos++;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (param_index == params_number);
|
||||
|
||||
return instr_pos;
|
||||
} /* vm_fill_params_list */
|
||||
+229
-1578
File diff suppressed because it is too large
Load Diff
+102
-266
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
|
||||
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015-2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,284 +18,119 @@
|
||||
#define OPCODES_H
|
||||
|
||||
#include "ecma-globals.h"
|
||||
#include "jrt.h"
|
||||
#include "vm-stack.h"
|
||||
#include "vm-defines.h"
|
||||
|
||||
/* Maximum opcodes number in bytecode. */
|
||||
#define MAX_OPCODES (256*256 - 1)
|
||||
|
||||
#define OP_0(action, name) \
|
||||
__##action (name, void, void, void)
|
||||
|
||||
#define OP_1(action, name, field1) \
|
||||
__##action (name, field1, void, void)
|
||||
|
||||
#define OP_2(action, name, field1, field2) \
|
||||
__##action (name, field1, field2, void)
|
||||
|
||||
#define OP_3(action, name, field1, field2, field3) \
|
||||
__##action (name, field1, field2, field3)
|
||||
|
||||
/**
|
||||
* Instruction counter / position
|
||||
*/
|
||||
typedef uint16_t vm_instr_counter_t;
|
||||
|
||||
/**
|
||||
* Opcode / argument value in an instruction ("idx")
|
||||
*/
|
||||
typedef uint8_t vm_idx_t;
|
||||
|
||||
/**
|
||||
* Description of vm_idx_t possible value ranges and special values
|
||||
*/
|
||||
enum : vm_idx_t
|
||||
{
|
||||
VM_IDX_GENERAL_VALUE_FIRST = 0, /**< first idx value that can be used for any argument value */
|
||||
VM_IDX_GENERAL_VALUE_LAST = 252, /**< last idx value that can be used for any argument value */
|
||||
|
||||
/*
|
||||
* Special values
|
||||
*/
|
||||
VM_IDX_REWRITE_GENERAL_CASE = 253, /**< intermediate value, used during byte-code generation,
|
||||
* indicating that the idx would be rewritten with a value
|
||||
* other than in-block literal identifier */
|
||||
VM_IDX_REWRITE_LITERAL_UID = 254, /**< intermediate value, used during byte-code generation,
|
||||
* indicating that the idx would be rewritten with in-block
|
||||
* literal identifier */
|
||||
VM_IDX_EMPTY = 255, /**< empty idx value, used when corresponding instruction argument is not set */
|
||||
|
||||
/*
|
||||
* Literals (variable names / strings / numbers) ranges
|
||||
*/
|
||||
VM_IDX_LITERAL_FIRST = VM_IDX_GENERAL_VALUE_FIRST, /**< index of first possible literals-related idx value */
|
||||
VM_IDX_LITERAL_LAST = VM_IDX_LITERAL_FIRST + 127, /**< index of last possible literals-related idx value */
|
||||
|
||||
/*
|
||||
* Registers (temp variables) ranges
|
||||
*/
|
||||
VM_IDX_REG_FIRST = VM_IDX_LITERAL_LAST + 1, /** identifier of first special register */
|
||||
VM_IDX_REG_LAST = VM_IDX_GENERAL_VALUE_LAST, /**< identifier of last register */
|
||||
};
|
||||
|
||||
/**
|
||||
* Ranges of registers (temporary variables)
|
||||
*/
|
||||
typedef enum : vm_idx_t
|
||||
{
|
||||
VM_REG_FIRST = VM_IDX_REG_FIRST, /** first register */
|
||||
VM_REG_LAST = VM_IDX_REG_LAST, /**< last register */
|
||||
|
||||
VM_REG_SPECIAL_FIRST = VM_REG_FIRST, /**< first special register */
|
||||
|
||||
VM_REG_SPECIAL_EVAL_RET = VM_REG_SPECIAL_FIRST, /**< eval return value */
|
||||
VM_REG_SPECIAL_FOR_IN_PROPERTY_NAME, /**< variable, containing property name,
|
||||
* at start of for-in loop body */
|
||||
VM_REG_SPECIAL_THIS_BINDING, /**< value of ThisBinding */
|
||||
|
||||
VM_REG_SPECIAL_LAST = VM_REG_SPECIAL_THIS_BINDING, /**< last special register */
|
||||
|
||||
VM_REG_GENERAL_FIRST, /** first non-special register */
|
||||
VM_REG_GENERAL_LAST = VM_IDX_REG_LAST /** last non-special register */
|
||||
} vm_reg_t;
|
||||
|
||||
/**
|
||||
* Number of special VM registers
|
||||
*/
|
||||
#define VM_SPECIAL_REGS_NUMBER (VM_REG_SPECIAL_LAST - VM_REG_SPECIAL_FIRST + 1u)
|
||||
|
||||
/**
|
||||
* Descriptor of assignment's second argument
|
||||
* that specifies type of third argument.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
OPCODE_ARG_TYPE_SIMPLE, /**< ecma_simple_value_t */
|
||||
OPCODE_ARG_TYPE_SMALLINT, /**< small integer: from 0 to 255 */
|
||||
OPCODE_ARG_TYPE_SMALLINT_NEGATE, /**< small integer: from -255 to -0 */
|
||||
OPCODE_ARG_TYPE_NUMBER, /**< index of number literal */
|
||||
OPCODE_ARG_TYPE_NUMBER_NEGATE, /**< index of number literal with negation */
|
||||
OPCODE_ARG_TYPE_STRING, /**< index of string literal */
|
||||
OPCODE_ARG_TYPE_VARIABLE, /**< index of string literal with variable name */
|
||||
OPCODE_ARG_TYPE_REGEXP /**< index of string literal with regular expression */
|
||||
} opcode_arg_type_operand;
|
||||
|
||||
/**
|
||||
* Types of data in 'meta' opcode.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
OPCODE_META_TYPE_UNDEFINED, /**< undefined meta (should be rewritten) */
|
||||
OPCODE_META_TYPE_CALL_SITE_INFO, /**< optional additional information about call site
|
||||
* (includes opcode_call_flags_t and can include 'this' argument) */
|
||||
OPCODE_META_TYPE_VARG, /**< element (var_idx) of arguments' list */
|
||||
OPCODE_META_TYPE_VARG_PROP_DATA, /**< name (lit_idx) and value (var_idx) for a data property descriptor */
|
||||
OPCODE_META_TYPE_VARG_PROP_GETTER, /**< name (lit_idx) and getter (var_idx) for an accessor property descriptor */
|
||||
OPCODE_META_TYPE_VARG_PROP_SETTER, /**< name (lit_idx) and setter (var_idx) for an accessor property descriptor */
|
||||
OPCODE_META_TYPE_END_WITH, /**< end of with statement */
|
||||
OPCODE_META_TYPE_FUNCTION_END, /**< offset to function end */
|
||||
OPCODE_META_TYPE_CATCH, /**< mark of beginning of catch block containing pointer to end of catch block */
|
||||
OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER, /**< literal index containing name of variable with exception object */
|
||||
OPCODE_META_TYPE_FINALLY, /**< mark of beginning of finally block containing pointer to end of finally block */
|
||||
OPCODE_META_TYPE_END_TRY_CATCH_FINALLY, /**< mark of end of try-catch, try-finally, try-catch-finally blocks */
|
||||
OPCODE_META_TYPE_END_FOR_IN /**< end of for-in statement */
|
||||
} opcode_meta_type;
|
||||
|
||||
typedef enum : vm_idx_t
|
||||
{
|
||||
OPCODE_CALL_FLAGS__EMPTY = (0u), /**< initializer for empty flag set */
|
||||
OPCODE_CALL_FLAGS_HAVE_THIS_ARG = (1u << 0), /**< flag, indicating that call is performed
|
||||
* with 'this' argument specified */
|
||||
OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM = (1u << 1) /**< flag, indicating that call is performed
|
||||
* in form 'eval (...)', i.e. through 'eval' string
|
||||
* without object base (i.e. with lexical environment
|
||||
* as base), so it can be a direct call to eval
|
||||
* See also: ECMA-262 v5, 15.1.2.1.1
|
||||
*/
|
||||
} opcode_call_flags_t;
|
||||
|
||||
/**
|
||||
* Types of byte-code instruction arguments, used for instruction description
|
||||
/** \addtogroup vm Virtual machine
|
||||
* @{
|
||||
*
|
||||
* See also:
|
||||
* vm-opcodes.inc.h
|
||||
* \addtogroup vm_opcodes Opcodes
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Number arithmetic operations.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
VM_OP_ARG_TYPE_EMPTY = (1u << 0), /**< empty argument (no value) */
|
||||
VM_OP_ARG_TYPE_REGISTER = (1u << 1), /**< register variable (index) */
|
||||
VM_OP_ARG_TYPE_IDENTIFIER = (1u << 2), /**< identifier - named variable (string literal) */
|
||||
VM_OP_ARG_TYPE_STRING = (1u << 3), /**< string constant value (string literal) */
|
||||
VM_OP_ARG_TYPE_NUMBER = (1u << 4), /**< number constant value (number literal) */
|
||||
VM_OP_ARG_TYPE_INTEGER_CONST = (1u << 5), /**< a 8-bit integer constant (any vm_idx_t) */
|
||||
VM_OP_ARG_TYPE_TYPE_OF_NEXT = (1u << 6), /**< opcode_arg_type_operand value,
|
||||
* representing type of argument encoded in next idx */
|
||||
|
||||
/** variable - an identifier or a register */
|
||||
VM_OP_ARG_TYPE_VARIABLE = (VM_OP_ARG_TYPE_REGISTER | VM_OP_ARG_TYPE_IDENTIFIER)
|
||||
} vm_op_arg_type_t;
|
||||
NUMBER_ARITHMETIC_ADDITION, /**< addition */
|
||||
NUMBER_ARITHMETIC_SUBSTRACTION, /**< substraction */
|
||||
NUMBER_ARITHMETIC_MULTIPLICATION, /**< multiplication */
|
||||
NUMBER_ARITHMETIC_DIVISION, /**< division */
|
||||
NUMBER_ARITHMETIC_REMAINDER, /**< remainder calculation */
|
||||
} number_arithmetic_op;
|
||||
|
||||
/**
|
||||
* Forward declaration of instruction structure
|
||||
* Number bitwise logic operations.
|
||||
*/
|
||||
struct vm_instr_t;
|
||||
|
||||
/**
|
||||
* Forward declaration of bytecode data header structure
|
||||
*/
|
||||
struct bytecode_data_header_t;
|
||||
|
||||
/**
|
||||
* Context of interpreter, related to a JS stack frame
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const bytecode_data_header_t *bytecode_header_p; /**< currently executed byte-code data */
|
||||
vm_instr_counter_t pos; /**< current position instruction to execute */
|
||||
ecma_object_t *lex_env_p; /**< current lexical environment */
|
||||
bool is_strict; /**< is current code execution mode strict? */
|
||||
bool is_eval_code; /**< is current code executed with eval */
|
||||
bool is_call_in_direct_eval_form; /** flag, indicating if there is call of 'Direct call to eval' form in
|
||||
* process (see also: OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM) */
|
||||
ecma_number_t *tmp_num_p; /**< an allocated number (to reduce temporary allocations) */
|
||||
vm_stack_frame_t stack_frame; /**< stack frame associated with the context */
|
||||
|
||||
#ifdef MEM_STATS
|
||||
size_t context_peak_allocated_heap_bytes;
|
||||
size_t context_peak_waste_heap_bytes;
|
||||
size_t context_peak_pools_count;
|
||||
size_t context_peak_allocated_pool_chunks;
|
||||
|
||||
mem_heap_stats_t heap_stats_context_enter;
|
||||
mem_pools_stats_t pools_stats_context_enter;
|
||||
#endif /* MEM_STATS */
|
||||
} vm_frame_ctx_t;
|
||||
|
||||
/**
|
||||
* Description of a run scope
|
||||
*
|
||||
* Note:
|
||||
* Run scope represents boundaries of byte-code block to run.
|
||||
*
|
||||
* Jumps within of the current run scope are performed by just changing instruction counter,
|
||||
* and outside of the run scope - by returning corresponding ECMA_COMPLETION_TYPE_BREAK_CONTINUE
|
||||
* completion value.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const vm_instr_counter_t start_oc; /**< instruction counter of the first instruction of the scope */
|
||||
const vm_instr_counter_t end_oc; /**< instruction counter of the last instruction of the scope */
|
||||
} vm_run_scope_t;
|
||||
|
||||
vm_instr_counter_t vm_calc_instr_counter_from_idx_idx (const vm_idx_t, const vm_idx_t);
|
||||
vm_instr_counter_t vm_read_instr_counter_from_meta (opcode_meta_type,
|
||||
const bytecode_data_header_t *,
|
||||
vm_instr_counter_t);
|
||||
|
||||
typedef struct vm_instr_t
|
||||
{
|
||||
vm_idx_t op_idx;
|
||||
union
|
||||
{
|
||||
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
|
||||
struct \
|
||||
{ \
|
||||
vm_idx_t arg1; \
|
||||
} opcode_name;
|
||||
|
||||
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
|
||||
struct \
|
||||
{ \
|
||||
vm_idx_t arg1; \
|
||||
vm_idx_t arg2; \
|
||||
} opcode_name;
|
||||
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
|
||||
struct \
|
||||
{ \
|
||||
vm_idx_t arg1; \
|
||||
vm_idx_t arg2; \
|
||||
vm_idx_t arg3; \
|
||||
} opcode_name;
|
||||
|
||||
#include "vm-opcodes.inc.h"
|
||||
|
||||
/**
|
||||
* Opcode-independent arguments accessor
|
||||
*
|
||||
* Note:
|
||||
* If opcode is statically known, opcode-specific way of accessing arguments should be used.
|
||||
*/
|
||||
vm_idx_t raw_args[3];
|
||||
} data;
|
||||
} vm_instr_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
|
||||
VM_OP_ ## opcode_name_uppercase,
|
||||
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
|
||||
VM_OP_ ## opcode_name_uppercase,
|
||||
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
|
||||
VM_OP_ ## opcode_name_uppercase,
|
||||
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
|
||||
VM_OP_ ## opcode_name_uppercase,
|
||||
NUMBER_BITWISE_LOGIC_AND, /**< bitwise AND calculation */
|
||||
NUMBER_BITWISE_LOGIC_OR, /**< bitwise OR calculation */
|
||||
NUMBER_BITWISE_LOGIC_XOR, /**< bitwise XOR calculation */
|
||||
NUMBER_BITWISE_SHIFT_LEFT, /**< bitwise LEFT SHIFT calculation */
|
||||
NUMBER_BITWISE_SHIFT_RIGHT, /**< bitwise RIGHT_SHIFT calculation */
|
||||
NUMBER_BITWISE_SHIFT_URIGHT, /**< bitwise UNSIGNED RIGHT SHIFT calculation */
|
||||
NUMBER_BITWISE_NOT, /**< bitwise NOT calculation */
|
||||
} number_bitwise_logic_op;
|
||||
|
||||
#include "vm-opcodes.inc.h"
|
||||
ecma_completion_value_t
|
||||
vm_var_decl (vm_frame_ctx_t *, ecma_string_t *);
|
||||
|
||||
VM_OP__COUNT /**< number of opcodes */
|
||||
} vm_op_t;
|
||||
ecma_completion_value_t
|
||||
opfunc_call_n (ecma_value_t,
|
||||
ecma_value_t,
|
||||
const ecma_value_t *,
|
||||
ecma_length_t);
|
||||
|
||||
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
|
||||
ecma_completion_value_t opfunc_##opcode_name (vm_instr_t, vm_frame_ctx_t *);
|
||||
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
|
||||
ecma_completion_value_t opfunc_##opcode_name (vm_instr_t, vm_frame_ctx_t *);
|
||||
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
|
||||
ecma_completion_value_t opfunc_##opcode_name (vm_instr_t, vm_frame_ctx_t *);
|
||||
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
|
||||
ecma_completion_value_t opfunc_##opcode_name (vm_instr_t, vm_frame_ctx_t *);
|
||||
ecma_completion_value_t
|
||||
opfunc_construct_n (ecma_value_t, uint8_t, ecma_value_t *);
|
||||
|
||||
#include "vm-opcodes.inc.h"
|
||||
ecma_completion_value_t
|
||||
opfunc_equal_value (ecma_value_t, ecma_value_t);
|
||||
|
||||
typedef ecma_completion_value_t (*opfunc) (vm_instr_t, vm_frame_ctx_t *);
|
||||
ecma_completion_value_t
|
||||
opfunc_not_equal_value (ecma_value_t, ecma_value_t);
|
||||
|
||||
#endif /* OPCODES_H */
|
||||
ecma_completion_value_t
|
||||
opfunc_equal_value_type (ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_not_equal_value_type (ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
do_number_arithmetic (number_arithmetic_op, ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_unary_plus (ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_unary_minus (ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
do_number_bitwise_logic (number_bitwise_logic_op, ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_addition (ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_less_than (ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_greater_than (ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_less_or_equal_than (ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_greater_or_equal_than (ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_in (ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_instanceof (ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_logical_not (ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
opfunc_typeof (ecma_value_t);
|
||||
|
||||
void
|
||||
opfunc_set_accessor (bool, ecma_value_t, ecma_value_t, ecma_value_t);
|
||||
|
||||
ecma_completion_value_t
|
||||
vm_op_delete_prop (ecma_value_t, ecma_value_t, bool);
|
||||
|
||||
ecma_completion_value_t
|
||||
vm_op_delete_var (lit_cpointer_t, ecma_object_t *, bool);
|
||||
|
||||
ecma_collection_header_t *
|
||||
opfunc_for_in (ecma_value_t, ecma_value_t *);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* !OPCODES_H */
|
||||
|
||||
@@ -1,583 +0,0 @@
|
||||
/* Copyright 2014-2015 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.
|
||||
*/
|
||||
|
||||
#ifdef JERRY_ENABLE_PRETTY_PRINTER
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "pretty-printer.h"
|
||||
#include "jrt-libc-includes.h"
|
||||
#include "lexer.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "lit-literal.h"
|
||||
|
||||
static const char* opcode_names[] =
|
||||
{
|
||||
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
|
||||
#opcode_name,
|
||||
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
|
||||
#opcode_name,
|
||||
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
|
||||
#opcode_name,
|
||||
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
|
||||
#opcode_name,
|
||||
|
||||
#include "vm-opcodes.inc.h"
|
||||
};
|
||||
|
||||
static uint8_t opcode_sizes[] =
|
||||
{
|
||||
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
|
||||
0,
|
||||
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
|
||||
1,
|
||||
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
|
||||
2,
|
||||
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
|
||||
3,
|
||||
|
||||
#include "vm-opcodes.inc.h"
|
||||
};
|
||||
|
||||
const bytecode_data_header_t *bc_to_print_header_p = NULL;
|
||||
|
||||
static char buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER];
|
||||
|
||||
static void
|
||||
clear_temp_buffer (void)
|
||||
{
|
||||
memset (buff, 0, ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER);
|
||||
}
|
||||
|
||||
static const char *
|
||||
lit_cp_to_str (lit_cpointer_t cp)
|
||||
{
|
||||
lit_literal_t lit = lit_get_literal_by_cp (cp);
|
||||
return lit_literal_to_str_internal_buf (lit);
|
||||
}
|
||||
|
||||
static const char *
|
||||
tmp_id_to_str (vm_idx_t id)
|
||||
{
|
||||
JERRY_ASSERT (id != VM_IDX_REWRITE_LITERAL_UID);
|
||||
JERRY_ASSERT (id >= 128);
|
||||
clear_temp_buffer ();
|
||||
strncpy (buff, "tmp", 3);
|
||||
if (id / 100 != 0)
|
||||
{
|
||||
buff[3] = (char) (id / 100 + '0');
|
||||
buff[4] = (char) ((id % 100) / 10 + '0');
|
||||
buff[5] = (char) (id % 10 + '0');
|
||||
}
|
||||
else if (id / 10 != 0)
|
||||
{
|
||||
buff[3] = (char) (id / 10 + '0');
|
||||
buff[4] = (char) (id % 10 + '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
buff[3] = (char) (id + '0');
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
static const char *
|
||||
var_to_str (vm_instr_t instr, lit_cpointer_t lit_ids[], vm_instr_counter_t oc, uint8_t current_arg)
|
||||
{
|
||||
JERRY_ASSERT (current_arg >= 1 && current_arg <= 3);
|
||||
|
||||
if (instr.data.raw_args[current_arg - 1] == VM_IDX_REWRITE_LITERAL_UID)
|
||||
{
|
||||
JERRY_ASSERT (lit_ids != NULL);
|
||||
JERRY_ASSERT (lit_ids[current_arg - 1].packed_value != MEM_CP_NULL);
|
||||
|
||||
return lit_cp_to_str (lit_ids[current_arg - 1]);
|
||||
}
|
||||
else if (instr.data.raw_args[current_arg - 1] >= 128)
|
||||
{
|
||||
return tmp_id_to_str (instr.data.raw_args[current_arg - 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return lit_cp_to_str (bc_get_literal_cp_by_uid (instr.data.raw_args[current_arg - 1],
|
||||
bc_to_print_header_p,
|
||||
oc));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pp_printf (const char *format, vm_instr_t instr, lit_cpointer_t lit_ids[], vm_instr_counter_t oc, uint8_t start_arg)
|
||||
{
|
||||
uint8_t current_arg = start_arg;
|
||||
JERRY_ASSERT (current_arg <= 3);
|
||||
while (*format)
|
||||
{
|
||||
if (*format != '%')
|
||||
{
|
||||
jerry_port_putchar (*format);
|
||||
format++;
|
||||
continue;
|
||||
}
|
||||
|
||||
format++;
|
||||
switch (*format)
|
||||
{
|
||||
case 'd':
|
||||
{
|
||||
JERRY_ASSERT (current_arg >= 1 && current_arg <= 3);
|
||||
printf ("%d", instr.data.raw_args[current_arg - 1]);
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
{
|
||||
printf ("%s", var_to_str (instr, lit_ids, oc, current_arg));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
jerry_port_putchar ('%');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
current_arg++;
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
#define PP_OP(op_name, format) \
|
||||
case op_name: pp_printf (format, opm.op, opm.lit_id, oc, 1); break;
|
||||
#define VAR(i) var_to_str (opm.op, opm.lit_id, oc, i)
|
||||
#define OC(i, j) __extension__({ vm_calc_instr_counter_from_idx_idx (opm.op.data.raw_args[i - 1], \
|
||||
opm.op.data.raw_args[j - 1]); })
|
||||
|
||||
static int vargs_num = 0;
|
||||
static int seen_vargs = 0;
|
||||
|
||||
static void
|
||||
dump_asm (vm_instr_counter_t oc, vm_instr_t instr)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
uint8_t opcode_id = instr.op_idx;
|
||||
printf ("%3d: %20s ", oc, opcode_names[opcode_id]);
|
||||
|
||||
for (i = 1; i <= opcode_sizes[opcode_id]; i++)
|
||||
{
|
||||
printf ("%4d ", instr.data.raw_args[i - 1]);
|
||||
}
|
||||
|
||||
for (; i < 4; i++)
|
||||
{
|
||||
printf (" ");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pp_op_meta (const bytecode_data_header_t *bytecode_data_p,
|
||||
vm_instr_counter_t oc,
|
||||
op_meta opm,
|
||||
bool rewrite)
|
||||
{
|
||||
bc_to_print_header_p = bytecode_data_p;
|
||||
|
||||
dump_asm (oc, opm.op);
|
||||
printf (" // ");
|
||||
|
||||
switch (opm.op.op_idx)
|
||||
{
|
||||
PP_OP (VM_OP_ADDITION, "%s = %s + %s;");
|
||||
PP_OP (VM_OP_SUBSTRACTION, "%s = %s - %s;");
|
||||
PP_OP (VM_OP_DIVISION, "%s = %s / %s;");
|
||||
PP_OP (VM_OP_MULTIPLICATION, "%s = %s * %s;");
|
||||
PP_OP (VM_OP_REMAINDER, "%s = %s %% %s;");
|
||||
PP_OP (VM_OP_UNARY_MINUS, "%s = -%s;");
|
||||
PP_OP (VM_OP_UNARY_PLUS, "%s = +%s;");
|
||||
PP_OP (VM_OP_B_SHIFT_LEFT, "%s = %s << %s;");
|
||||
PP_OP (VM_OP_B_SHIFT_RIGHT, "%s = %s >> %s;");
|
||||
PP_OP (VM_OP_B_SHIFT_URIGHT, "%s = %s >>> %s;");
|
||||
PP_OP (VM_OP_B_AND, "%s = %s & %s;");
|
||||
PP_OP (VM_OP_B_OR, "%s = %s | %s;");
|
||||
PP_OP (VM_OP_B_XOR, "%s = %s ^ %s;");
|
||||
PP_OP (VM_OP_B_NOT, "%s = ~ %s;");
|
||||
PP_OP (VM_OP_LOGICAL_NOT, "%s = ! %s;");
|
||||
PP_OP (VM_OP_EQUAL_VALUE, "%s = %s == %s;");
|
||||
PP_OP (VM_OP_NOT_EQUAL_VALUE, "%s = %s != %s;");
|
||||
PP_OP (VM_OP_EQUAL_VALUE_TYPE, "%s = %s === %s;");
|
||||
PP_OP (VM_OP_NOT_EQUAL_VALUE_TYPE, "%s = %s !== %s;");
|
||||
PP_OP (VM_OP_LESS_THAN, "%s = %s < %s;");
|
||||
PP_OP (VM_OP_GREATER_THAN, "%s = %s > %s;");
|
||||
PP_OP (VM_OP_LESS_OR_EQUAL_THAN, "%s = %s <= %s;");
|
||||
PP_OP (VM_OP_GREATER_OR_EQUAL_THAN, "%s = %s >= %s;");
|
||||
PP_OP (VM_OP_INSTANCEOF, "%s = %s instanceof %s;");
|
||||
PP_OP (VM_OP_IN, "%s = %s in %s;");
|
||||
PP_OP (VM_OP_POST_INCR, "%s = %s++;");
|
||||
PP_OP (VM_OP_POST_DECR, "%s = %s--;");
|
||||
PP_OP (VM_OP_PRE_INCR, "%s = ++%s;");
|
||||
PP_OP (VM_OP_PRE_DECR, "%s = --%s;");
|
||||
PP_OP (VM_OP_THROW_VALUE, "throw %s;");
|
||||
PP_OP (VM_OP_REG_VAR_DECL, "%d tmp regs, %d local variable regs, %d argument variable regs");
|
||||
PP_OP (VM_OP_VAR_DECL, "var %s;");
|
||||
PP_OP (VM_OP_RETVAL, "return %s;");
|
||||
PP_OP (VM_OP_RET, "ret;");
|
||||
PP_OP (VM_OP_PROP_GETTER, "%s = %s[%s];");
|
||||
PP_OP (VM_OP_PROP_SETTER, "%s[%s] = %s;");
|
||||
PP_OP (VM_OP_DELETE_VAR, "%s = delete %s;");
|
||||
PP_OP (VM_OP_DELETE_PROP, "%s = delete %s.%s;");
|
||||
PP_OP (VM_OP_TYPEOF, "%s = typeof %s;");
|
||||
PP_OP (VM_OP_WITH, "with (%s);");
|
||||
PP_OP (VM_OP_FOR_IN, "for_in (%s);");
|
||||
case VM_OP_IS_TRUE_JMP_UP: printf ("if (%s) goto %d;", VAR (1), oc - OC (2, 3)); break;
|
||||
case VM_OP_IS_FALSE_JMP_UP: printf ("if (%s == false) goto %d;", VAR (1), oc - OC (2, 3)); break;
|
||||
case VM_OP_IS_TRUE_JMP_DOWN: printf ("if (%s) goto %d;", VAR (1), oc + OC (2, 3)); break;
|
||||
case VM_OP_IS_FALSE_JMP_DOWN: printf ("if (%s == false) goto %d;", VAR (1), oc + OC (2, 3)); break;
|
||||
case VM_OP_JMP_UP: printf ("goto %d;", oc - OC (1, 2)); break;
|
||||
case VM_OP_JMP_DOWN: printf ("goto %d;", oc + OC (1, 2)); break;
|
||||
case VM_OP_JMP_BREAK_CONTINUE: printf ("goto_nested %d;", oc + OC (1, 2)); break;
|
||||
case VM_OP_TRY_BLOCK: printf ("try (end: %d);", oc + OC (1, 2)); break;
|
||||
case VM_OP_ASSIGNMENT:
|
||||
{
|
||||
printf ("%s = ", VAR (1));
|
||||
switch (opm.op.data.assignment.type_value_right)
|
||||
{
|
||||
case OPCODE_ARG_TYPE_STRING: printf ("'%s': STRING;", VAR (3)); break;
|
||||
case OPCODE_ARG_TYPE_NUMBER: printf ("%s: NUMBER;", VAR (3)); break;
|
||||
case OPCODE_ARG_TYPE_NUMBER_NEGATE: printf ("-%s: NUMBER;", VAR (3)); break;
|
||||
case OPCODE_ARG_TYPE_SMALLINT: printf ("%d: SMALLINT;", opm.op.data.assignment.value_right); break;
|
||||
case OPCODE_ARG_TYPE_SMALLINT_NEGATE: printf ("-%d: SMALLINT;", opm.op.data.assignment.value_right); break;
|
||||
case OPCODE_ARG_TYPE_VARIABLE: printf ("%s : TYPEOF(%s);", VAR (3), VAR (3)); break;
|
||||
case OPCODE_ARG_TYPE_SIMPLE:
|
||||
{
|
||||
switch (opm.op.data.assignment.value_right)
|
||||
{
|
||||
case ECMA_SIMPLE_VALUE_NULL: printf ("null"); break;
|
||||
case ECMA_SIMPLE_VALUE_FALSE: printf ("false"); break;
|
||||
case ECMA_SIMPLE_VALUE_TRUE: printf ("true"); break;
|
||||
case ECMA_SIMPLE_VALUE_UNDEFINED: printf ("undefined"); break;
|
||||
case ECMA_SIMPLE_VALUE_ARRAY_HOLE: printf ("hole"); break;
|
||||
default: JERRY_UNREACHABLE ();
|
||||
}
|
||||
printf (": SIMPLE;");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VM_OP_CALL_N:
|
||||
{
|
||||
vargs_num = opm.op.data.call_n.arg_list;
|
||||
seen_vargs = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
case VM_OP_CONSTRUCT_N:
|
||||
{
|
||||
if (opm.op.data.construct_n.arg_list == 0)
|
||||
{
|
||||
pp_printf ("%s = new %s;", opm.op, opm.lit_id, oc, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
vargs_num = opm.op.data.construct_n.arg_list;
|
||||
seen_vargs = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VM_OP_FUNC_DECL_N:
|
||||
{
|
||||
if (opm.op.data.func_decl_n.arg_list == 0)
|
||||
{
|
||||
printf ("function %s ();", VAR (1));
|
||||
}
|
||||
else
|
||||
{
|
||||
vargs_num = opm.op.data.func_decl_n.arg_list;
|
||||
seen_vargs = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VM_OP_FUNC_EXPR_REF:
|
||||
{
|
||||
printf ("%s = function ();", VAR (1));
|
||||
break;
|
||||
}
|
||||
case VM_OP_FUNC_EXPR_N:
|
||||
{
|
||||
if (opm.op.data.func_expr_n.arg_list == 0)
|
||||
{
|
||||
if (opm.op.data.func_expr_n.name_lit_idx == VM_IDX_EMPTY)
|
||||
{
|
||||
printf ("%s = function ();", VAR (1));
|
||||
}
|
||||
else
|
||||
{
|
||||
pp_printf ("%s = function %s ();", opm.op, opm.lit_id, oc, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vargs_num = opm.op.data.func_expr_n.arg_list;
|
||||
seen_vargs = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VM_OP_ARRAY_DECL:
|
||||
{
|
||||
if (opm.op.data.array_decl.list_1 == 0
|
||||
&& opm.op.data.array_decl.list_2 == 0)
|
||||
{
|
||||
printf ("%s = [];", VAR (1));
|
||||
}
|
||||
else
|
||||
{
|
||||
vargs_num = (((int) opm.op.data.array_decl.list_1 << JERRY_BITSINBYTE)
|
||||
+ (int) opm.op.data.array_decl.list_2);
|
||||
seen_vargs = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VM_OP_OBJ_DECL:
|
||||
{
|
||||
if (opm.op.data.obj_decl.list_1 == 0
|
||||
&& opm.op.data.obj_decl.list_2 == 0)
|
||||
{
|
||||
printf ("%s = {};", VAR (1));
|
||||
}
|
||||
else
|
||||
{
|
||||
vargs_num = (((int) opm.op.data.obj_decl.list_1 << JERRY_BITSINBYTE)
|
||||
+ (int) opm.op.data.obj_decl.list_2);
|
||||
seen_vargs = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VM_OP_META:
|
||||
{
|
||||
switch (opm.op.data.meta.type)
|
||||
{
|
||||
case OPCODE_META_TYPE_UNDEFINED:
|
||||
{
|
||||
printf ("unknown meta;");
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_CALL_SITE_INFO:
|
||||
case OPCODE_META_TYPE_VARG:
|
||||
case OPCODE_META_TYPE_VARG_PROP_DATA:
|
||||
case OPCODE_META_TYPE_VARG_PROP_GETTER:
|
||||
case OPCODE_META_TYPE_VARG_PROP_SETTER:
|
||||
{
|
||||
if (opm.op.data.meta.type != OPCODE_META_TYPE_CALL_SITE_INFO)
|
||||
{
|
||||
seen_vargs++;
|
||||
}
|
||||
|
||||
if (seen_vargs == vargs_num)
|
||||
{
|
||||
bool found = false;
|
||||
vm_instr_counter_t start = oc;
|
||||
while ((int16_t) start >= 0 && !found)
|
||||
{
|
||||
start--;
|
||||
switch (bc_get_instr (bytecode_data_p, start).op_idx)
|
||||
{
|
||||
case VM_OP_CALL_N:
|
||||
case VM_OP_CONSTRUCT_N:
|
||||
case VM_OP_FUNC_DECL_N:
|
||||
case VM_OP_FUNC_EXPR_N:
|
||||
case VM_OP_ARRAY_DECL:
|
||||
case VM_OP_OBJ_DECL:
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vm_instr_t start_op = bc_get_instr (bytecode_data_p, start);
|
||||
switch (start_op.op_idx)
|
||||
{
|
||||
case VM_OP_CALL_N:
|
||||
{
|
||||
pp_printf ("%s = %s (", start_op, NULL, start, 1);
|
||||
break;
|
||||
}
|
||||
case VM_OP_CONSTRUCT_N:
|
||||
{
|
||||
pp_printf ("%s = new %s (", start_op, NULL, start, 1);
|
||||
break;
|
||||
}
|
||||
case VM_OP_FUNC_DECL_N:
|
||||
{
|
||||
pp_printf ("function %s (", start_op, NULL, start, 1);
|
||||
break;
|
||||
}
|
||||
case VM_OP_FUNC_EXPR_N:
|
||||
{
|
||||
if (start_op.data.func_expr_n.name_lit_idx == VM_IDX_EMPTY)
|
||||
{
|
||||
pp_printf ("%s = function (", start_op, NULL, start, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pp_printf ("%s = function %s (", start_op, NULL, start, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VM_OP_ARRAY_DECL:
|
||||
{
|
||||
pp_printf ("%s = [", start_op, NULL, start, 1);
|
||||
break;
|
||||
}
|
||||
case VM_OP_OBJ_DECL:
|
||||
{
|
||||
pp_printf ("%s = {", start_op, NULL, start, 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_UNREACHABLE ();
|
||||
}
|
||||
}
|
||||
for (vm_instr_counter_t counter = start; counter <= oc; counter++)
|
||||
{
|
||||
vm_instr_t meta_op = bc_get_instr (bytecode_data_p, counter);
|
||||
|
||||
switch (meta_op.op_idx)
|
||||
{
|
||||
case VM_OP_META:
|
||||
{
|
||||
switch (meta_op.data.meta.type)
|
||||
{
|
||||
case OPCODE_META_TYPE_CALL_SITE_INFO:
|
||||
{
|
||||
opcode_call_flags_t call_flags = (opcode_call_flags_t) meta_op.data.meta.data_1;
|
||||
|
||||
if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
|
||||
{
|
||||
pp_printf ("this_arg = %s", meta_op, NULL, counter, 3);
|
||||
}
|
||||
if (call_flags & OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM)
|
||||
{
|
||||
printf ("['direct call to eval' form]");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_VARG:
|
||||
{
|
||||
pp_printf ("%s", meta_op, NULL, counter, 2);
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_VARG_PROP_DATA:
|
||||
{
|
||||
pp_printf ("%s:%s", meta_op, NULL, counter, 2);
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_VARG_PROP_GETTER:
|
||||
{
|
||||
pp_printf ("%s = get %s ();", meta_op, NULL, counter, 2);
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_VARG_PROP_SETTER:
|
||||
{
|
||||
pp_printf ("%s = set (%s);", meta_op, NULL, counter, 2);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (counter != oc)
|
||||
{
|
||||
printf (", ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (start_op.op_idx)
|
||||
{
|
||||
case VM_OP_ARRAY_DECL:
|
||||
{
|
||||
printf ("];");
|
||||
break;
|
||||
}
|
||||
case VM_OP_OBJ_DECL:
|
||||
{
|
||||
printf ("};");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
printf (");");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_END_WITH:
|
||||
{
|
||||
printf ("end with;");
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_END_FOR_IN:
|
||||
{
|
||||
printf ("end for-in;");
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_FUNCTION_END:
|
||||
{
|
||||
printf ("function end: %d;", oc + OC (2, 3));
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_CATCH:
|
||||
{
|
||||
printf ("catch end: %d;", oc + OC (2, 3));
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER:
|
||||
{
|
||||
printf ("catch (%s);", VAR (2));
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_FINALLY:
|
||||
{
|
||||
printf ("finally end: %d;", oc + OC (2, 3));
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_END_TRY_CATCH_FINALLY:
|
||||
{
|
||||
printf ("end try");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_UNREACHABLE ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_UNREACHABLE ();
|
||||
}
|
||||
}
|
||||
|
||||
if (rewrite)
|
||||
{
|
||||
printf (" // REWRITE");
|
||||
}
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
#endif /* JERRY_ENABLE_PRETTY_PRINTER */
|
||||
@@ -1,28 +0,0 @@
|
||||
/* Copyright 2014-2015 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.
|
||||
*/
|
||||
|
||||
#ifndef PRETTY_PRINTER
|
||||
#define PRETTY_PRINTER
|
||||
|
||||
#include "jrt.h"
|
||||
#ifdef JERRY_ENABLE_PRETTY_PRINTER
|
||||
#include "bytecode-data.h"
|
||||
#include "vm.h"
|
||||
#include "scopes-tree.h"
|
||||
|
||||
void pp_op_meta (const bytecode_data_header_t *, vm_instr_counter_t, op_meta, bool);
|
||||
#endif // JERRY_ENABLE_PRETTY_PRINTER
|
||||
|
||||
#endif // PRETTY_PRINTER
|
||||
@@ -0,0 +1,61 @@
|
||||
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015-2016 University of Szeged.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef VM_DEFINES_H
|
||||
#define VM_DEFINES_H
|
||||
|
||||
#include "byte-code.h"
|
||||
#include "ecma-globals.h"
|
||||
|
||||
/** \addtogroup vm Virtual machine
|
||||
* @{
|
||||
*
|
||||
* \addtogroup vm_executor Executor
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helpers for updating uint16_t values.
|
||||
*/
|
||||
#define VM_PLUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) + (value))
|
||||
#define VM_MINUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) - (value))
|
||||
|
||||
/**
|
||||
* Instruction counter / position
|
||||
*/
|
||||
typedef const uint8_t *vm_instr_counter_t;
|
||||
|
||||
/**
|
||||
* Context of interpreter, related to a JS stack frame
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const ecma_compiled_code_t *bytecode_header_p; /**< currently executed byte-code data */
|
||||
uint8_t *byte_code_p; /**< current byte code pointer */
|
||||
uint8_t *byte_code_start_p; /**< byte code start pointer */
|
||||
ecma_value_t *registers_p; /**< register start pointer */
|
||||
lit_cpointer_t *literal_start_p; /**< literal list start pointer */
|
||||
ecma_object_t *lex_env_p; /**< current lexical environment */
|
||||
ecma_value_t this_binding; /**< this binding */
|
||||
uint16_t context_depth; /**< current context depth */
|
||||
bool is_eval_code; /**< eval mode flag */
|
||||
} vm_frame_ctx_t;
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* !VM_DEFINES_H */
|
||||
@@ -1,317 +0,0 @@
|
||||
/* Copyright 2015 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* List of VM opcodes
|
||||
*/
|
||||
|
||||
#ifndef VM_OP_0
|
||||
# define VM_OP_0(opcode_name, opcode_name_uppercase)
|
||||
#endif /* !VM_OP_0 */
|
||||
|
||||
#ifndef VM_OP_1
|
||||
# define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type)
|
||||
#endif /* !VM_OP_1 */
|
||||
|
||||
#ifndef VM_OP_2
|
||||
# define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type)
|
||||
#endif /* !VM_OP_2 */
|
||||
|
||||
#ifndef VM_OP_3
|
||||
# define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type)
|
||||
#endif /* !VM_OP_3 */
|
||||
|
||||
VM_OP_3 (call_n, CALL_N,
|
||||
lhs, VM_OP_ARG_TYPE_VARIABLE,
|
||||
function_var_idx, VM_OP_ARG_TYPE_VARIABLE,
|
||||
arg_list, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (construct_n, CONSTRUCT_N,
|
||||
lhs, VM_OP_ARG_TYPE_VARIABLE,
|
||||
name_lit_idx, VM_OP_ARG_TYPE_VARIABLE,
|
||||
arg_list, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_2 (func_decl_n, FUNC_DECL_N,
|
||||
name_lit_idx, VM_OP_ARG_TYPE_STRING,
|
||||
arg_list, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (func_expr_n, FUNC_EXPR_N,
|
||||
lhs, VM_OP_ARG_TYPE_VARIABLE,
|
||||
name_lit_idx, VM_OP_ARG_TYPE_STRING |
|
||||
VM_OP_ARG_TYPE_EMPTY,
|
||||
arg_list, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (func_expr_ref, FUNC_EXPR_REF,
|
||||
lhs, VM_OP_ARG_TYPE_VARIABLE,
|
||||
idx1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
idx2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_1 (retval, RETVAL,
|
||||
ret_value, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_0 (ret, RET)
|
||||
|
||||
VM_OP_3 (array_decl, ARRAY_DECL,
|
||||
lhs, VM_OP_ARG_TYPE_VARIABLE,
|
||||
list_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
list_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (obj_decl, OBJ_DECL,
|
||||
lhs, VM_OP_ARG_TYPE_VARIABLE,
|
||||
list_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
list_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (prop_getter, PROP_GETTER,
|
||||
lhs, VM_OP_ARG_TYPE_VARIABLE,
|
||||
obj, VM_OP_ARG_TYPE_VARIABLE,
|
||||
prop, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (prop_setter, PROP_SETTER,
|
||||
obj, VM_OP_ARG_TYPE_VARIABLE,
|
||||
prop, VM_OP_ARG_TYPE_VARIABLE,
|
||||
rhs, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_2 (delete_var, DELETE_VAR,
|
||||
lhs, VM_OP_ARG_TYPE_VARIABLE,
|
||||
name, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (delete_prop, DELETE_PROP,
|
||||
lhs, VM_OP_ARG_TYPE_VARIABLE,
|
||||
base, VM_OP_ARG_TYPE_VARIABLE,
|
||||
name, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_2 (typeof, TYPEOF,
|
||||
lhs, VM_OP_ARG_TYPE_VARIABLE,
|
||||
obj, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (for_in, FOR_IN,
|
||||
expr, VM_OP_ARG_TYPE_VARIABLE,
|
||||
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (with, WITH,
|
||||
expr, VM_OP_ARG_TYPE_VARIABLE,
|
||||
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_2 (try_block, TRY_BLOCK,
|
||||
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_1 (throw_value, THROW_VALUE,
|
||||
var, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
|
||||
VM_OP_3 (assignment, ASSIGNMENT,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
type_value_right, VM_OP_ARG_TYPE_TYPE_OF_NEXT,
|
||||
value_right, VM_OP_ARG_TYPE_VARIABLE |
|
||||
VM_OP_ARG_TYPE_STRING |
|
||||
VM_OP_ARG_TYPE_NUMBER |
|
||||
VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
|
||||
VM_OP_3 (b_shift_left, B_SHIFT_LEFT,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (b_shift_right, B_SHIFT_RIGHT,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (b_shift_uright, B_SHIFT_URIGHT,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (b_and, B_AND,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (b_or, B_OR,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (b_xor, B_XOR,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_2 (b_not, B_NOT,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
|
||||
VM_OP_2 (logical_not, LOGICAL_NOT,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
|
||||
VM_OP_3 (equal_value, EQUAL_VALUE,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (not_equal_value, NOT_EQUAL_VALUE,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (equal_value_type, EQUAL_VALUE_TYPE,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (not_equal_value_type, NOT_EQUAL_VALUE_TYPE,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (less_than, LESS_THAN,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (greater_than, GREATER_THAN,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (less_or_equal_than, LESS_OR_EQUAL_THAN,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (greater_or_equal_than, GREATER_OR_EQUAL_THAN,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (instanceof, INSTANCEOF,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (in, IN,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_2 (post_incr, POST_INCR,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_2 (post_decr, POST_DECR,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_2 (pre_incr, PRE_INCR,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_2 (pre_decr, PRE_DECR,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (addition, ADDITION,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (substraction, SUBSTRACTION,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (division, DIVISION,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (multiplication, MULTIPLICATION,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_3 (remainder, REMAINDER,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_left, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var_right, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_2 (unary_minus, UNARY_MINUS,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_2 (unary_plus, UNARY_PLUS,
|
||||
dst, VM_OP_ARG_TYPE_VARIABLE,
|
||||
var, VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
VM_OP_2 (jmp_up, JMP_UP,
|
||||
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_2 (jmp_down, JMP_DOWN,
|
||||
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_2 (jmp_break_continue, JMP_BREAK_CONTINUE,
|
||||
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (is_true_jmp_up, IS_TRUE_JMP_UP,
|
||||
value, VM_OP_ARG_TYPE_VARIABLE,
|
||||
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (is_true_jmp_down, IS_TRUE_JMP_DOWN,
|
||||
value, VM_OP_ARG_TYPE_VARIABLE,
|
||||
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (is_false_jmp_up, IS_FALSE_JMP_UP,
|
||||
value, VM_OP_ARG_TYPE_VARIABLE,
|
||||
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (is_false_jmp_down, IS_FALSE_JMP_DOWN,
|
||||
value, VM_OP_ARG_TYPE_VARIABLE,
|
||||
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_1 (var_decl, VAR_DECL,
|
||||
variable_name, VM_OP_ARG_TYPE_STRING)
|
||||
|
||||
VM_OP_3 (reg_var_decl, REG_VAR_DECL,
|
||||
tmp_regs_num, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
local_var_regs_num, VM_OP_ARG_TYPE_INTEGER_CONST,
|
||||
arg_regs_num, VM_OP_ARG_TYPE_INTEGER_CONST)
|
||||
|
||||
VM_OP_3 (meta, META,
|
||||
type, VM_OP_ARG_TYPE_INTEGER_CONST |
|
||||
VM_OP_ARG_TYPE_TYPE_OF_NEXT,
|
||||
data_1, VM_OP_ARG_TYPE_INTEGER_CONST |
|
||||
VM_OP_ARG_TYPE_STRING |
|
||||
VM_OP_ARG_TYPE_VARIABLE,
|
||||
data_2, VM_OP_ARG_TYPE_INTEGER_CONST |
|
||||
VM_OP_ARG_TYPE_VARIABLE)
|
||||
|
||||
#undef VM_OP_0
|
||||
#undef VM_OP_1
|
||||
#undef VM_OP_2
|
||||
#undef VM_OP_3
|
||||
+195
-253
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015-2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,8 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-alloc.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "vm-defines.h"
|
||||
#include "vm-stack.h"
|
||||
|
||||
/** \addtogroup vm Virtual machine
|
||||
@@ -25,287 +28,226 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Size of a stack frame's dynamic chunk
|
||||
*/
|
||||
#define VM_STACK_DYNAMIC_CHUNK_SIZE (mem_heap_recommend_allocation_size (sizeof (vm_stack_chunk_header_t) + \
|
||||
sizeof (ecma_value_t)))
|
||||
|
||||
/**
|
||||
* Number of value slots in a stack frame's dynamic chunk
|
||||
*/
|
||||
#define VM_STACK_SLOTS_IN_DYNAMIC_CHUNK ((VM_STACK_DYNAMIC_CHUNK_SIZE - sizeof (vm_stack_chunk_header_t)) / \
|
||||
sizeof (ecma_value_t))
|
||||
|
||||
/**
|
||||
* The top-most stack frame
|
||||
*/
|
||||
vm_stack_frame_t* vm_stack_top_frame_p;
|
||||
|
||||
/**
|
||||
* Initialize stack
|
||||
*/
|
||||
void
|
||||
vm_stack_init (void)
|
||||
{
|
||||
vm_stack_top_frame_p = NULL;
|
||||
} /* vm_stack_init */
|
||||
|
||||
/**
|
||||
* Finalize stack
|
||||
*/
|
||||
void
|
||||
vm_stack_finalize ()
|
||||
{
|
||||
JERRY_ASSERT (vm_stack_top_frame_p == NULL);
|
||||
} /* vm_stack_finalize */
|
||||
|
||||
/**
|
||||
* Get stack's top frame
|
||||
* Abort (finalize) the current stack context, and remove it.
|
||||
*
|
||||
* @return pointer to the top frame descriptor
|
||||
* @return new stack top
|
||||
*/
|
||||
vm_stack_frame_t*
|
||||
vm_stack_get_top_frame (void)
|
||||
ecma_value_t *
|
||||
vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
|
||||
ecma_value_t *vm_stack_top_p) /**< current stack top */
|
||||
{
|
||||
return vm_stack_top_frame_p;
|
||||
} /* vm_stack_get_top_frame */
|
||||
|
||||
/**
|
||||
* Add the frame to stack
|
||||
*/
|
||||
void
|
||||
vm_stack_add_frame (vm_stack_frame_t *frame_p, /**< frame to initialize */
|
||||
ecma_value_t *regs_p, /**< array of register variables' values */
|
||||
uint32_t regs_num, /**< total number of register variables */
|
||||
uint32_t local_vars_regs_num, /**< number of register variables,
|
||||
* used for local variables */
|
||||
uint32_t arg_regs_num, /**< number of register variables,
|
||||
* used for arguments */
|
||||
ecma_collection_header_t *arguments_p) /**< collection of arguments
|
||||
* (for case, their values
|
||||
* are moved to registers) */
|
||||
{
|
||||
frame_p->prev_frame_p = vm_stack_top_frame_p;
|
||||
vm_stack_top_frame_p = frame_p;
|
||||
|
||||
frame_p->top_chunk_p = NULL;
|
||||
frame_p->dynamically_allocated_value_slots_p = frame_p->inlined_values;
|
||||
frame_p->current_slot_index = 0;
|
||||
frame_p->regs_p = regs_p;
|
||||
frame_p->regs_number = regs_num;
|
||||
|
||||
JERRY_ASSERT (regs_num >= VM_SPECIAL_REGS_NUMBER);
|
||||
|
||||
for (uint32_t i = 0; i < regs_num - local_vars_regs_num - arg_regs_num; i++)
|
||||
switch (VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]))
|
||||
{
|
||||
regs_p[i] = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);
|
||||
}
|
||||
|
||||
for (uint32_t i = regs_num - local_vars_regs_num - arg_regs_num;
|
||||
i < regs_num;
|
||||
i++)
|
||||
{
|
||||
regs_p[i] = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
|
||||
}
|
||||
|
||||
if (arg_regs_num != 0)
|
||||
{
|
||||
ecma_collection_iterator_t args_iterator;
|
||||
ecma_collection_iterator_init (&args_iterator, arguments_p);
|
||||
|
||||
for (uint32_t i = regs_num - arg_regs_num;
|
||||
i < regs_num && ecma_collection_iterator_next (&args_iterator);
|
||||
i++)
|
||||
case VM_CONTEXT_FINALLY_THROW:
|
||||
case VM_CONTEXT_FINALLY_RETURN:
|
||||
{
|
||||
regs_p[i] = ecma_copy_value (*args_iterator.current_value_p, false);
|
||||
ecma_free_value (vm_stack_top_p[-2], true);
|
||||
|
||||
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
|
||||
vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
|
||||
break;
|
||||
}
|
||||
case VM_CONTEXT_FINALLY_JUMP:
|
||||
case VM_CONTEXT_TRY:
|
||||
{
|
||||
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
|
||||
vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
|
||||
break;
|
||||
}
|
||||
case VM_CONTEXT_CATCH:
|
||||
case VM_CONTEXT_WITH:
|
||||
{
|
||||
ecma_deref_object (frame_ctx_p->lex_env_p);
|
||||
frame_ctx_p->lex_env_p = ecma_get_object_from_value (vm_stack_top_p[-2]);
|
||||
|
||||
JERRY_ASSERT (PARSER_TRY_CONTEXT_STACK_ALLOCATION == PARSER_WITH_CONTEXT_STACK_ALLOCATION);
|
||||
|
||||
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
|
||||
vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
|
||||
break;
|
||||
}
|
||||
case VM_CONTEXT_FOR_IN:
|
||||
{
|
||||
mem_cpointer_t current = (uint16_t) vm_stack_top_p[-2];
|
||||
|
||||
while (current != MEM_CP_NULL)
|
||||
{
|
||||
ecma_collection_chunk_t *chunk_p = MEM_CP_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
|
||||
current);
|
||||
|
||||
ecma_free_value (*(ecma_value_t *) chunk_p->data, true);
|
||||
|
||||
current = chunk_p->next_chunk_cp;
|
||||
ecma_dealloc_collection_chunk (chunk_p);
|
||||
}
|
||||
|
||||
ecma_free_value (vm_stack_top_p[-3], true);
|
||||
|
||||
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION);
|
||||
vm_stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_UNREACHABLE ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* vm_stack_add_frame */
|
||||
|
||||
return vm_stack_top_p;
|
||||
} /* vm_stack_context_abort */
|
||||
|
||||
/**
|
||||
* Free the stack frame
|
||||
* Decode branch offset.
|
||||
*
|
||||
* Note:
|
||||
* the frame should be the top-most frame
|
||||
* @return branch offset
|
||||
*/
|
||||
void
|
||||
vm_stack_free_frame (vm_stack_frame_t *frame_p) /**< frame to initialize */
|
||||
static uint32_t
|
||||
vm_decode_branch_offset (uint8_t *branch_offset_p, /**< start offset of byte code */
|
||||
uint32_t length) /**< length of the branch */
|
||||
{
|
||||
/* the frame should be the top-most frame */
|
||||
JERRY_ASSERT (vm_stack_top_frame_p == frame_p);
|
||||
uint32_t branch_offset = *branch_offset_p;
|
||||
|
||||
vm_stack_top_frame_p = frame_p->prev_frame_p;
|
||||
JERRY_ASSERT (length >= 1 && length <= 3);
|
||||
|
||||
while (frame_p->top_chunk_p != NULL)
|
||||
switch (length)
|
||||
{
|
||||
vm_stack_pop (frame_p);
|
||||
case 3:
|
||||
{
|
||||
branch_offset <<= 8;
|
||||
branch_offset |= *(branch_offset_p++);
|
||||
/* FALLTHRU */
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
branch_offset <<= 8;
|
||||
branch_offset |= *(branch_offset_p++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t reg_index = 0;
|
||||
reg_index < frame_p->regs_number;
|
||||
reg_index++)
|
||||
{
|
||||
ecma_free_value (frame_p->regs_p[reg_index], false);
|
||||
}
|
||||
} /* vm_stack_free_frame */
|
||||
return branch_offset;
|
||||
} /* vm_decode_branch_offset */
|
||||
|
||||
/**
|
||||
* Get value of specified register variable
|
||||
* Find a finally up to the end position.
|
||||
*
|
||||
* @return ecma-value
|
||||
* @return true if 'finally' found,
|
||||
* false otherwise
|
||||
*/
|
||||
ecma_value_t
|
||||
vm_stack_frame_get_reg_value (vm_stack_frame_t *frame_p, /**< frame */
|
||||
uint32_t reg_index) /**< index of register variable */
|
||||
bool
|
||||
vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
|
||||
ecma_value_t **vm_stack_top_ref_p, /**< current stack top */
|
||||
vm_stack_context_type_t finally_type, /**< searching this finally */
|
||||
uint32_t search_limit) /**< search up-to this byte code */
|
||||
{
|
||||
JERRY_ASSERT (reg_index >= VM_REG_FIRST && reg_index < VM_REG_FIRST + frame_p->regs_number);
|
||||
ecma_value_t *vm_stack_top_p = *vm_stack_top_ref_p;
|
||||
|
||||
return frame_p->regs_p[reg_index - VM_REG_FIRST];
|
||||
} /* vm_stack_frame_get_reg_value */
|
||||
JERRY_ASSERT (finally_type <= VM_CONTEXT_FINALLY_RETURN);
|
||||
|
||||
/**
|
||||
* Set value of specified register variable
|
||||
*/
|
||||
void
|
||||
vm_stack_frame_set_reg_value (vm_stack_frame_t *frame_p, /**< frame */
|
||||
uint32_t reg_index, /**< index of register variable */
|
||||
ecma_value_t value) /**< ecma-value */
|
||||
{
|
||||
JERRY_ASSERT (reg_index >= VM_REG_FIRST && reg_index < VM_REG_FIRST + frame_p->regs_number);
|
||||
|
||||
frame_p->regs_p[reg_index - VM_REG_FIRST] = value;
|
||||
} /* vm_stack_frame_set_reg_value */
|
||||
|
||||
/**
|
||||
* Calculate number of value slots in the top-most chunk of the frame
|
||||
*
|
||||
* @return number of value slots
|
||||
*/
|
||||
static size_t
|
||||
vm_stack_slots_in_top_chunk (vm_stack_frame_t *frame_p) /**< stack frame */
|
||||
{
|
||||
return ((frame_p->top_chunk_p == NULL) ? VM_STACK_FRAME_INLINED_VALUES_NUMBER : VM_STACK_SLOTS_IN_DYNAMIC_CHUNK);
|
||||
} /* vm_stack_slots_in_top_chunk */
|
||||
|
||||
/**
|
||||
* Longpath for vm_stack_push_value (for case current chunk may be doesn't have free slots)
|
||||
*/
|
||||
static void __attr_noinline___
|
||||
vm_stack_push_value_longpath (vm_stack_frame_t *frame_p) /**< stack frame */
|
||||
{
|
||||
JERRY_ASSERT (frame_p->current_slot_index >= JERRY_MIN (VM_STACK_FRAME_INLINED_VALUES_NUMBER,
|
||||
VM_STACK_SLOTS_IN_DYNAMIC_CHUNK));
|
||||
|
||||
const size_t slots_in_top_chunk = vm_stack_slots_in_top_chunk (frame_p);
|
||||
|
||||
if (frame_p->current_slot_index == slots_in_top_chunk)
|
||||
if (finally_type != VM_CONTEXT_FINALLY_JUMP)
|
||||
{
|
||||
vm_stack_chunk_header_t *chunk_p;
|
||||
chunk_p = (vm_stack_chunk_header_t *) mem_heap_alloc_block (VM_STACK_DYNAMIC_CHUNK_SIZE,
|
||||
MEM_HEAP_ALLOC_SHORT_TERM);
|
||||
|
||||
ECMA_SET_POINTER (chunk_p->prev_chunk_p, frame_p->top_chunk_p);
|
||||
|
||||
frame_p->top_chunk_p = chunk_p;
|
||||
frame_p->dynamically_allocated_value_slots_p = (ecma_value_t*) (frame_p->top_chunk_p + 1);
|
||||
frame_p->current_slot_index = 0;
|
||||
}
|
||||
} /* vm_stack_push_value_longpath */
|
||||
|
||||
/**
|
||||
* Push ecma-value to stack
|
||||
*/
|
||||
void
|
||||
vm_stack_push_value (vm_stack_frame_t *frame_p, /**< stack frame */
|
||||
ecma_value_t value) /**< ecma-value */
|
||||
{
|
||||
frame_p->current_slot_index++;
|
||||
|
||||
if (frame_p->current_slot_index >= JERRY_MIN (VM_STACK_FRAME_INLINED_VALUES_NUMBER,
|
||||
VM_STACK_SLOTS_IN_DYNAMIC_CHUNK))
|
||||
{
|
||||
vm_stack_push_value_longpath (frame_p);
|
||||
search_limit = 0xffffffffu;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (frame_p->current_slot_index < vm_stack_slots_in_top_chunk (frame_p));
|
||||
|
||||
frame_p->dynamically_allocated_value_slots_p[frame_p->current_slot_index] = value;
|
||||
} /* vm_stack_push_value */
|
||||
|
||||
/**
|
||||
* Get top value from stack
|
||||
*/
|
||||
ecma_value_t __attr_always_inline___
|
||||
vm_stack_top_value (vm_stack_frame_t *frame_p) /**< stack frame */
|
||||
{
|
||||
const size_t slots_in_top_chunk = vm_stack_slots_in_top_chunk (frame_p);
|
||||
|
||||
JERRY_ASSERT (frame_p->current_slot_index < slots_in_top_chunk);
|
||||
|
||||
return frame_p->dynamically_allocated_value_slots_p[frame_p->current_slot_index];
|
||||
} /* vm_stack_top_value */
|
||||
|
||||
/**
|
||||
* Longpath for vm_stack_pop (for case a dynamically allocated chunk needs to be deallocated)
|
||||
*/
|
||||
static void __attr_noinline___
|
||||
vm_stack_pop_longpath (vm_stack_frame_t *frame_p) /**< stack frame */
|
||||
{
|
||||
JERRY_ASSERT (frame_p->current_slot_index == 0 && frame_p->top_chunk_p != NULL);
|
||||
|
||||
vm_stack_chunk_header_t *chunk_to_free_p = frame_p->top_chunk_p;
|
||||
frame_p->top_chunk_p = ECMA_GET_POINTER (vm_stack_chunk_header_t,
|
||||
frame_p->top_chunk_p->prev_chunk_p);
|
||||
|
||||
if (frame_p->top_chunk_p != NULL)
|
||||
while (frame_ctx_p->context_depth > 0)
|
||||
{
|
||||
frame_p->dynamically_allocated_value_slots_p = (ecma_value_t*) (frame_p->top_chunk_p + 1);
|
||||
frame_p->current_slot_index = (uint32_t) (VM_STACK_SLOTS_IN_DYNAMIC_CHUNK - 1u);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_p->dynamically_allocated_value_slots_p = frame_p->inlined_values;
|
||||
frame_p->current_slot_index = (uint32_t) (VM_STACK_FRAME_INLINED_VALUES_NUMBER - 1u);
|
||||
vm_stack_context_type_t context_type;
|
||||
uint32_t context_end = VM_GET_CONTEXT_END (vm_stack_top_p[-1]);
|
||||
|
||||
if (search_limit < context_end)
|
||||
{
|
||||
*vm_stack_top_ref_p = vm_stack_top_p;
|
||||
return false;
|
||||
}
|
||||
|
||||
context_type = VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]);
|
||||
if (context_type == VM_CONTEXT_TRY || context_type == VM_CONTEXT_CATCH)
|
||||
{
|
||||
uint8_t *byte_code_p;
|
||||
uint32_t branch_offset_length;
|
||||
uint32_t branch_offset;
|
||||
|
||||
if (search_limit == context_end)
|
||||
{
|
||||
*vm_stack_top_ref_p = vm_stack_top_p;
|
||||
return false;
|
||||
}
|
||||
|
||||
byte_code_p = frame_ctx_p->byte_code_start_p + VM_GET_CONTEXT_END (vm_stack_top_p[-1]);
|
||||
|
||||
if (context_type == VM_CONTEXT_TRY)
|
||||
{
|
||||
JERRY_ASSERT (byte_code_p[0] == CBC_EXT_OPCODE);
|
||||
|
||||
if (byte_code_p[1] >= CBC_EXT_CATCH
|
||||
&& byte_code_p[1] <= CBC_EXT_CATCH_3)
|
||||
{
|
||||
branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (byte_code_p[1]);
|
||||
branch_offset = vm_decode_branch_offset (byte_code_p + 2,
|
||||
branch_offset_length);
|
||||
|
||||
if (finally_type == VM_CONTEXT_FINALLY_THROW)
|
||||
{
|
||||
branch_offset += (uint32_t) (byte_code_p - frame_ctx_p->byte_code_start_p);
|
||||
|
||||
vm_stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_CATCH, branch_offset);
|
||||
|
||||
byte_code_p += 2 + branch_offset_length;
|
||||
frame_ctx_p->byte_code_p = byte_code_p;
|
||||
|
||||
*vm_stack_top_ref_p = vm_stack_top_p;
|
||||
return true;
|
||||
}
|
||||
|
||||
byte_code_p += branch_offset;
|
||||
|
||||
if (*byte_code_p == CBC_CONTEXT_END)
|
||||
{
|
||||
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
|
||||
vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ecma_deref_object (frame_ctx_p->lex_env_p);
|
||||
frame_ctx_p->lex_env_p = ecma_get_object_from_value (vm_stack_top_p[-2]);
|
||||
|
||||
if (byte_code_p[0] == CBC_CONTEXT_END)
|
||||
{
|
||||
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
|
||||
vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
JERRY_ASSERT (byte_code_p[0] == CBC_EXT_OPCODE);
|
||||
JERRY_ASSERT (byte_code_p[1] >= CBC_EXT_FINALLY
|
||||
&& byte_code_p[1] <= CBC_EXT_FINALLY_3);
|
||||
|
||||
branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (byte_code_p[1]);
|
||||
branch_offset = vm_decode_branch_offset (byte_code_p + 2,
|
||||
branch_offset_length);
|
||||
|
||||
branch_offset += (uint32_t) (byte_code_p - frame_ctx_p->byte_code_start_p);
|
||||
|
||||
vm_stack_top_p[-1] = VM_CREATE_CONTEXT ((uint32_t) finally_type, branch_offset);
|
||||
|
||||
byte_code_p += 2 + branch_offset_length;
|
||||
frame_ctx_p->byte_code_p = byte_code_p;
|
||||
|
||||
*vm_stack_top_ref_p = vm_stack_top_p;
|
||||
return true;
|
||||
}
|
||||
|
||||
vm_stack_top_p = vm_stack_context_abort (frame_ctx_p, vm_stack_top_p);
|
||||
}
|
||||
|
||||
mem_heap_free_block (chunk_to_free_p);
|
||||
} /* vm_stack_pop_longpath */
|
||||
|
||||
/**
|
||||
* Pop top value from stack and free it
|
||||
*/
|
||||
void
|
||||
vm_stack_pop (vm_stack_frame_t *frame_p) /**< stack frame */
|
||||
{
|
||||
JERRY_ASSERT (frame_p->current_slot_index < vm_stack_slots_in_top_chunk (frame_p));
|
||||
|
||||
ecma_value_t value = vm_stack_top_value (frame_p);
|
||||
|
||||
if (unlikely (frame_p->current_slot_index == 0
|
||||
&& frame_p->top_chunk_p != NULL))
|
||||
{
|
||||
vm_stack_pop_longpath (frame_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_p->current_slot_index--;
|
||||
}
|
||||
|
||||
ecma_free_value (value, true);
|
||||
} /* vm_stack_pop */
|
||||
|
||||
/**
|
||||
* Pop multiple top values from stack and free them
|
||||
*/
|
||||
void
|
||||
vm_stack_pop_multiple (vm_stack_frame_t *frame_p, /**< stack frame */
|
||||
uint32_t number) /**< number of elements to pop */
|
||||
{
|
||||
for (uint32_t i = 0; i < number; i++)
|
||||
{
|
||||
vm_stack_pop (frame_p);
|
||||
}
|
||||
} /* vm_stack_pop_multiple */
|
||||
*vm_stack_top_ref_p = vm_stack_top_p;
|
||||
return false;
|
||||
} /* vm_stack_find_finally */
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
+26
-24
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015-2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,7 +37,7 @@
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t prev_chunk_p; /**< previous chunk of same frame */
|
||||
uint16_t prev_chunk_p; /**< previous chunk of same frame */
|
||||
} vm_stack_chunk_header_t;
|
||||
|
||||
/**
|
||||
@@ -44,30 +45,31 @@ typedef struct
|
||||
*/
|
||||
typedef struct vm_stack_frame_t
|
||||
{
|
||||
struct vm_stack_frame_t *prev_frame_p; /**< previous frame */
|
||||
vm_stack_chunk_header_t *top_chunk_p; /**< the top-most chunk of the frame */
|
||||
ecma_value_t *dynamically_allocated_value_slots_p; /**< pointer to dynamically allocated value slots
|
||||
* in the top-most chunk */
|
||||
uint32_t current_slot_index; /**< index of first free slot in the top chunk */
|
||||
ecma_value_t inlined_values[VM_STACK_FRAME_INLINED_VALUES_NUMBER]; /**< place for values inlined into stack frame
|
||||
* (instead of being placed on heap) */
|
||||
ecma_value_t *regs_p; /**< register variables */
|
||||
uint32_t regs_number; /**< number of register variables */
|
||||
struct vm_stack_frame_t *prev_frame_p; /**< previous frame */
|
||||
uint32_t regs_number; /**< number of register variables */
|
||||
} vm_stack_frame_t;
|
||||
|
||||
extern void vm_stack_init (void);
|
||||
extern void vm_stack_finalize (void);
|
||||
extern vm_stack_frame_t *
|
||||
vm_stack_get_top_frame (void);
|
||||
extern void
|
||||
vm_stack_add_frame (vm_stack_frame_t *, ecma_value_t *, uint32_t, uint32_t, uint32_t, ecma_collection_header_t *);
|
||||
extern void vm_stack_free_frame (vm_stack_frame_t *);
|
||||
extern ecma_value_t vm_stack_frame_get_reg_value (vm_stack_frame_t *, uint32_t);
|
||||
extern void vm_stack_frame_set_reg_value (vm_stack_frame_t *, uint32_t, ecma_value_t);
|
||||
extern void vm_stack_push_value (vm_stack_frame_t *, ecma_value_t);
|
||||
extern ecma_value_t vm_stack_top_value (vm_stack_frame_t *);
|
||||
extern void vm_stack_pop (vm_stack_frame_t *);
|
||||
extern void vm_stack_pop_multiple (vm_stack_frame_t *, uint32_t);
|
||||
#define VM_CREATE_CONTEXT(type, end_offset) ((ecma_value_t) ((type) | (end_offset) << 4))
|
||||
#define VM_GET_CONTEXT_TYPE(value) ((vm_stack_context_type_t) ((value) & 0xf))
|
||||
#define VM_GET_CONTEXT_END(value) ((value) >> 4)
|
||||
|
||||
/**
|
||||
* Context types for the vm stack.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
VM_CONTEXT_FINALLY_JUMP, /**< finally context with a jump */
|
||||
VM_CONTEXT_FINALLY_THROW, /**< finally context with a throw */
|
||||
VM_CONTEXT_FINALLY_RETURN, /**< finally context with a return */
|
||||
VM_CONTEXT_TRY, /**< try context */
|
||||
VM_CONTEXT_CATCH, /**< catch context */
|
||||
VM_CONTEXT_WITH, /**< with context */
|
||||
VM_CONTEXT_FOR_IN, /**< for-in context */
|
||||
} vm_stack_context_type_t;
|
||||
|
||||
extern ecma_value_t *vm_stack_context_abort (vm_frame_ctx_t *, ecma_value_t *);
|
||||
extern bool vm_stack_find_finally (vm_frame_ctx_t *, ecma_value_t **,
|
||||
vm_stack_context_type_t, uint32_t);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
+2368
-612
File diff suppressed because it is too large
Load Diff
+185
-13
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015-2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,25 +19,196 @@
|
||||
|
||||
#include "ecma-globals.h"
|
||||
#include "jrt.h"
|
||||
#include "opcodes.h"
|
||||
#include "vm-defines.h"
|
||||
|
||||
extern void vm_init (const bytecode_data_header_t *, bool);
|
||||
/** \addtogroup vm Virtual machine
|
||||
* @{
|
||||
*
|
||||
* \addtogroup vm_executor Executor
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define VM_OC_GET_DATA_SHIFT 24
|
||||
#define VM_OC_GET_DATA_MASK 0x1f
|
||||
#define VM_OC_GET_DATA_CREATE_ID(V) \
|
||||
(((V) & VM_OC_GET_DATA_MASK) << VM_OC_GET_DATA_SHIFT)
|
||||
#define VM_OC_GET_DATA_GET_ID(O) \
|
||||
(((O) >> VM_OC_GET_DATA_SHIFT) & VM_OC_GET_DATA_MASK)
|
||||
|
||||
/**
|
||||
* Argument getters that are part of the opcodes.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
VM_OC_GET_NONE = VM_OC_GET_DATA_CREATE_ID (0), /**< do nothing */
|
||||
VM_OC_GET_STACK = VM_OC_GET_DATA_CREATE_ID (1), /**< pop one elemnet from the stack */
|
||||
VM_OC_GET_STACK_STACK = VM_OC_GET_DATA_CREATE_ID (2), /**< pop two elemnets from the stack */
|
||||
VM_OC_GET_BYTE = VM_OC_GET_DATA_CREATE_ID (3), /**< read a byte */
|
||||
|
||||
VM_OC_GET_LITERAL = VM_OC_GET_DATA_CREATE_ID (4), /**< resolve literal */
|
||||
VM_OC_GET_STACK_LITERAL = VM_OC_GET_DATA_CREATE_ID (5), /**< pop one elemnet from the stack and resolve a literal*/
|
||||
VM_OC_GET_LITERAL_BYTE = VM_OC_GET_DATA_CREATE_ID (6), /**< pop one elemnet from stack and read a byte */
|
||||
VM_OC_GET_LITERAL_LITERAL = VM_OC_GET_DATA_CREATE_ID (7), /**< resolve two literals */
|
||||
VM_OC_GET_THIS_LITERAL = VM_OC_GET_DATA_CREATE_ID (8), /**< get this and resolve a literal */
|
||||
} vm_oc_get_types;
|
||||
|
||||
#define VM_OC_GROUP_MASK 0xff
|
||||
#define VM_OC_GROUP_GET_INDEX(O) \
|
||||
((O) & VM_OC_GROUP_MASK)
|
||||
|
||||
/**
|
||||
* Opcodes.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
VM_OC_NONE, /**< do nothing */
|
||||
VM_OC_POP, /**< pop from stack */
|
||||
VM_OC_POP_BLOCK, /**< pop block */
|
||||
VM_OC_PUSH, /**< push one element */
|
||||
VM_OC_PUSH_TWO, /**< push two elements onto the stack */
|
||||
VM_OC_PUSH_THREE, /**< push three elements onto the stack */
|
||||
VM_OC_PUSH_UNDEFINED, /**< push undefined value */
|
||||
VM_OC_PUSH_TRUE, /**< push true value */
|
||||
VM_OC_PUSH_FALSE, /**< push false value */
|
||||
VM_OC_PUSH_NULL, /**< push null value */
|
||||
VM_OC_PUSH_THIS, /**< push this */
|
||||
VM_OC_PUSH_NUMBER, /**< push number */
|
||||
VM_OC_PUSH_OBJECT, /**< push object */
|
||||
VM_OC_SET_PROPERTY, /**< set property */
|
||||
VM_OC_SET_GETTER, /**< set getter */
|
||||
VM_OC_SET_SETTER, /**< set setter */
|
||||
VM_OC_PUSH_UNDEFINED_BASE, /**< push undefined base */
|
||||
VM_OC_PUSH_ARRAY, /**< push array */
|
||||
VM_OC_PUSH_ELISON, /**< push elison */
|
||||
VM_OC_APPEND_ARRAY, /**< append array */
|
||||
VM_OC_IDENT_REFERENCE, /**< ident reference */
|
||||
VM_OC_PROP_REFERENCE, /**< prop reference */
|
||||
VM_OC_PROP_GET, /**< prop get */
|
||||
|
||||
/* These eight opcodes must be in this order. */
|
||||
VM_OC_PROP_PRE_INCR, /**< prefix increment of a property */
|
||||
VM_OC_PRE_INCR, /**< prefix increment */
|
||||
VM_OC_PROP_PRE_DECR, /**< prop prefix decrement of a property */
|
||||
VM_OC_PRE_DECR, /**< prefix decrement */
|
||||
VM_OC_PROP_POST_INCR, /**< prop postfix increment of a property */
|
||||
VM_OC_POST_INCR, /**< postfix increment */
|
||||
VM_OC_PROP_POST_DECR, /**< prop postfix decrement of a property */
|
||||
VM_OC_POST_DECR, /**< postfix decrement */
|
||||
|
||||
VM_OC_PROP_DELETE, /**< delete property */
|
||||
VM_OC_DELETE, /**< delete */
|
||||
|
||||
VM_OC_ASSIGN, /**< assign */
|
||||
VM_OC_ASSIGN_PROP, /**< assign property */
|
||||
VM_OC_ASSIGN_PROP_THIS, /**< assign prop this */
|
||||
|
||||
VM_OC_RET, /**< return */
|
||||
VM_OC_THROW, /**< throw */
|
||||
VM_OC_THROW_REFERENCE_ERROR, /**< throw reference error */
|
||||
|
||||
/* The PROP forms must get the highest opcodes. */
|
||||
VM_OC_EVAL, /**< eval */
|
||||
VM_OC_CALL_N, /**< call n */
|
||||
VM_OC_CALL, /**< call */
|
||||
VM_OC_CALL_PROP_N, /**< call property n */
|
||||
VM_OC_CALL_PROP, /**< call property */
|
||||
|
||||
VM_OC_NEW_N, /**< new n */
|
||||
VM_OC_NEW, /**< new */
|
||||
|
||||
VM_OC_JUMP, /**< jump */
|
||||
VM_OC_BRANCH_IF_STRICT_EQUAL, /**< branch if stric equal */
|
||||
|
||||
/* These four opcodes must be in this order. */
|
||||
VM_OC_BRANCH_IF_TRUE, /**< branch if true */
|
||||
VM_OC_BRANCH_IF_FALSE, /**< branch if false */
|
||||
VM_OC_BRANCH_IF_LOGICAL_TRUE, /**< branch if logical true */
|
||||
VM_OC_BRANCH_IF_LOGICAL_FALSE, /**< branch if logical false */
|
||||
|
||||
VM_OC_PLUS, /**< unary plus */
|
||||
VM_OC_MINUS, /**< unary minus */
|
||||
VM_OC_NOT, /**< not */
|
||||
VM_OC_BIT_NOT, /**< bitwise not */
|
||||
VM_OC_VOID, /**< void */
|
||||
VM_OC_TYPEOF_IDENT, /**< typeof identifier */
|
||||
VM_OC_TYPEOF, /**< typeof */
|
||||
|
||||
VM_OC_ADD, /**< binary add */
|
||||
VM_OC_SUB, /**< binary sub */
|
||||
VM_OC_MUL, /**< mul */
|
||||
VM_OC_DIV, /**< div */
|
||||
VM_OC_MOD, /**< mod */
|
||||
|
||||
VM_OC_EQUAL, /**< equal */
|
||||
VM_OC_NOT_EQUAL, /**< not equal */
|
||||
VM_OC_STRICT_EQUAL, /**< strict equal */
|
||||
VM_OC_STRICT_NOT_EQUAL, /**< strict not equal */
|
||||
VM_OC_LESS, /**< less */
|
||||
VM_OC_GREATER, /**< greater */
|
||||
VM_OC_LESS_EQUAL, /**< less equal */
|
||||
VM_OC_GREATER_EQUAL, /**< greater equal */
|
||||
VM_OC_IN, /**< in */
|
||||
VM_OC_INSTANCEOF, /**< instanceof */
|
||||
|
||||
VM_OC_BIT_OR, /**< bitwise or */
|
||||
VM_OC_BIT_XOR, /**< bitwise xor */
|
||||
VM_OC_BIT_AND, /**< bitwise and */
|
||||
VM_OC_LEFT_SHIFT, /**< left shift */
|
||||
VM_OC_RIGHT_SHIFT, /**< right shift */
|
||||
VM_OC_UNS_RIGHT_SHIFT, /**< unsigned right shift */
|
||||
|
||||
VM_OC_WITH, /**< with */
|
||||
VM_OC_FOR_IN_CREATE_CONTEXT, /**< for in create context */
|
||||
VM_OC_FOR_IN_GET_NEXT, /**< get next */
|
||||
VM_OC_FOR_IN_HAS_NEXT, /**< has next */
|
||||
VM_OC_TRY, /**< try */
|
||||
VM_OC_CATCH, /**< catch */
|
||||
VM_OC_FINALLY, /**< finally */
|
||||
VM_OC_CONTEXT_END, /**< context end */
|
||||
VM_OC_JUMP_AND_EXIT_CONTEXT, /**< jump and exit context */
|
||||
} vm_oc_types;
|
||||
|
||||
#define VM_OC_PUT_DATA_SHIFT 12
|
||||
#define VM_OC_PUT_DATA_MASK 0xf
|
||||
#define VM_OC_PUT_DATA_CREATE_FLAG(V) \
|
||||
(((V) & VM_OC_PUT_DATA_MASK) << VM_OC_PUT_DATA_SHIFT)
|
||||
|
||||
/**
|
||||
* Result writers that are part of the opcodes.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
VM_OC_PUT_IDENT = VM_OC_PUT_DATA_CREATE_FLAG (0x1),
|
||||
VM_OC_PUT_REFERENCE = VM_OC_PUT_DATA_CREATE_FLAG (0x2),
|
||||
VM_OC_PUT_STACK = VM_OC_PUT_DATA_CREATE_FLAG (0x4),
|
||||
VM_OC_PUT_BLOCK = VM_OC_PUT_DATA_CREATE_FLAG (0x8),
|
||||
} vm_oc_put_types;
|
||||
|
||||
extern void vm_init (ecma_compiled_code_t *, bool);
|
||||
extern void vm_finalize (void);
|
||||
extern jerry_completion_code_t vm_run_global (void);
|
||||
extern ecma_completion_value_t vm_run_eval (const bytecode_data_header_t *, bool);
|
||||
extern ecma_completion_value_t vm_run_eval (ecma_compiled_code_t *, bool);
|
||||
|
||||
extern ecma_completion_value_t vm_loop (vm_frame_ctx_t *, vm_run_scope_t *);
|
||||
extern ecma_completion_value_t vm_run_from_pos (const bytecode_data_header_t *, vm_instr_counter_t,
|
||||
ecma_value_t, ecma_object_t *, bool, bool, ecma_collection_header_t *);
|
||||
extern ecma_completion_value_t vm_loop (vm_frame_ctx_t *);
|
||||
extern ecma_completion_value_t vm_run (const ecma_compiled_code_t *,
|
||||
ecma_value_t,
|
||||
ecma_object_t *,
|
||||
bool,
|
||||
ecma_collection_header_t *);
|
||||
|
||||
extern vm_instr_t vm_get_instr (const vm_instr_t *, vm_instr_counter_t);
|
||||
extern uint8_t vm_get_scope_args_num (const bytecode_data_header_t *, vm_instr_counter_t);
|
||||
extern ecma_completion_value_t vm_run_array_args (const ecma_compiled_code_t *,
|
||||
ecma_value_t,
|
||||
ecma_object_t *,
|
||||
bool,
|
||||
const ecma_value_t *,
|
||||
ecma_length_t);
|
||||
|
||||
extern bool vm_is_strict_mode (void);
|
||||
extern bool vm_is_direct_eval_form_call (void);
|
||||
|
||||
extern ecma_value_t vm_get_this_binding (void);
|
||||
extern ecma_object_t *vm_get_lex_env (void);
|
||||
|
||||
#endif /* VM_H */
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* !VM_H */
|
||||
|
||||
Reference in New Issue
Block a user