jerryscript/jerry-core/parser/js/opcodes-dumper.cpp

2483 lines
67 KiB
C++

/* 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-dumper.h"
#include "serializer.h"
#include "stack.h"
#include "jsp-early-error.h"
/**
* Register allocator's counter
*/
static vm_idx_t jsp_reg_next;
/**
* Maximum identifier of a register, allocated for intermediate value storage
*
* See also:
* dumper_new_scope, dumper_finish_scope
*/
static vm_idx_t jsp_reg_max_for_temps;
/**
* Maximum identifier of a register, allocated for storage of a variable value.
*
* The value can be VM_IDX_EMPTY, indicating that no registers were allocated for variable values.
*
* Note:
* Registers for variable values are always allocated after registers for temporary values,
* so the value, if not equal to VM_IDX_EMPTY, is always greater than jsp_reg_max_for_temps.
*
* See also:
* dumper_try_replace_var_with_reg
*/
static vm_idx_t jsp_reg_max_for_local_var;
enum
{
U8_global_size
};
STATIC_STACK (U8, uint8_t)
enum
{
varg_headers_global_size
};
STATIC_STACK (varg_headers, vm_instr_counter_t)
enum
{
function_ends_global_size
};
STATIC_STACK (function_ends, vm_instr_counter_t)
enum
{
logical_and_checks_global_size
};
STATIC_STACK (logical_and_checks, vm_instr_counter_t)
enum
{
logical_or_checks_global_size
};
STATIC_STACK (logical_or_checks, vm_instr_counter_t)
enum
{
conditional_checks_global_size
};
STATIC_STACK (conditional_checks, vm_instr_counter_t)
enum
{
jumps_to_end_global_size
};
STATIC_STACK (jumps_to_end, vm_instr_counter_t)
enum
{
prop_getters_global_size
};
STATIC_STACK (prop_getters, op_meta)
enum
{
next_iterations_global_size
};
STATIC_STACK (next_iterations, vm_instr_counter_t)
enum
{
case_clauses_global_size
};
STATIC_STACK (case_clauses, vm_instr_counter_t)
enum
{
tries_global_size
};
STATIC_STACK (tries, vm_instr_counter_t)
enum
{
catches_global_size
};
STATIC_STACK (catches, vm_instr_counter_t)
enum
{
finallies_global_size
};
STATIC_STACK (finallies, vm_instr_counter_t)
enum
{
jsp_reg_id_stack_global_size
};
STATIC_STACK (jsp_reg_id_stack, vm_idx_t)
enum
{
reg_var_decls_global_size
};
STATIC_STACK (reg_var_decls, vm_instr_counter_t)
/**
* Allocate next register for intermediate value
*
* @return identifier of the allocated register
*/
static vm_idx_t
jsp_alloc_reg_for_temp (void)
{
JERRY_ASSERT (jsp_reg_max_for_local_var == VM_IDX_EMPTY);
vm_idx_t next_reg = jsp_reg_next++;
if (next_reg > VM_REG_GENERAL_LAST)
{
/*
* FIXME:
* Implement mechanism, allowing reusage of register variables
*/
PARSE_ERROR (JSP_EARLY_ERROR_SYNTAX, "Not enough register variables", LIT_ITERATOR_POS_ZERO);
}
if (jsp_reg_max_for_temps < next_reg)
{
jsp_reg_max_for_temps = next_reg;
}
return next_reg;
} /* jsp_alloc_reg_for_temp */
#ifdef CONFIG_PARSER_ENABLE_PARSE_TIME_BYTE_CODE_OPTIMIZER
/**
* Try to move local variable to a register
*
* Note:
* First instruction of the scope should be either func_decl_n or func_expr_n, as the scope is function scope,
* and the optimization is not applied to 'new Function ()'-like constructed functions.
*
* See also:
* parse_source_element_list
* parser_parse_program
*
* @return true, if optimization performed successfully, i.e.:
* - there is a free register to use;
* - the variable name is not equal to any of the function's argument names;
* false - otherwise.
*/
bool
dumper_try_replace_var_with_reg (scopes_tree tree, /**< a function scope, created for
* function declaration or function expresssion */
op_meta *var_decl_om_p) /**< operation meta of corresponding variable declaration */
{
JERRY_ASSERT (tree->type == SCOPE_TYPE_FUNCTION);
JERRY_ASSERT (var_decl_om_p->op.op_idx == VM_OP_VAR_DECL);
JERRY_ASSERT (var_decl_om_p->lit_id[0].packed_value != NOT_A_LITERAL.packed_value);
JERRY_ASSERT (var_decl_om_p->lit_id[1].packed_value == NOT_A_LITERAL.packed_value);
JERRY_ASSERT (var_decl_om_p->lit_id[2].packed_value == NOT_A_LITERAL.packed_value);
vm_instr_counter_t instr_pos = 0;
op_meta header_opm = scopes_tree_op_meta (tree, instr_pos++);
JERRY_ASSERT (header_opm.op.op_idx == VM_OP_FUNC_EXPR_N || header_opm.op.op_idx == VM_OP_FUNC_DECL_N);
while (true)
{
op_meta meta_opm = scopes_tree_op_meta (tree, instr_pos++);
JERRY_ASSERT (meta_opm.op.op_idx == VM_OP_META);
opcode_meta_type meta_type = (opcode_meta_type) meta_opm.op.data.meta.type;
if (meta_type == OPCODE_META_TYPE_FUNCTION_END)
{
/* marker of function argument list end reached */
break;
}
else
{
JERRY_ASSERT (meta_type == OPCODE_META_TYPE_VARG);
/* the varg specifies argument name, and so should be a string literal */
JERRY_ASSERT (meta_opm.op.data.meta.data_1 == VM_IDX_REWRITE_LITERAL_UID);
JERRY_ASSERT (meta_opm.lit_id[1].packed_value != NOT_A_LITERAL.packed_value);
if (meta_opm.lit_id[1].packed_value == var_decl_om_p->lit_id[0].packed_value)
{
/*
* Optimization is not performed, because the variable's name is equal to an argument name,
* and the argument's value would be initialized by its name in run-time.
*
* See also:
* parser_parse_program
*/
return false;
}
}
}
if (jsp_reg_max_for_local_var == VM_IDX_EMPTY)
{
jsp_reg_max_for_local_var = jsp_reg_max_for_temps;
}
if (jsp_reg_max_for_local_var == VM_REG_GENERAL_LAST)
{
/* not enough registers */
return false;
}
JERRY_ASSERT (jsp_reg_max_for_local_var < VM_REG_GENERAL_LAST);
vm_idx_t reg = ++jsp_reg_max_for_local_var;
lit_cpointer_t lit_cp = var_decl_om_p->lit_id[0];
for (vm_instr_counter_t instr_pos = 0;
instr_pos < tree->instrs_count;
instr_pos++)
{
op_meta om = scopes_tree_op_meta (tree, instr_pos);
vm_op_t opcode = (vm_op_t) om.op.op_idx;
int args_num = 0;
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
if (opcode == VM_OP_ ## opcode_name_uppercase) \
{ \
args_num = 0; \
}
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
if (opcode == VM_OP_ ## opcode_name_uppercase) \
{ \
JERRY_STATIC_ASSERT (((arg1_type) & VM_OP_ARG_TYPE_TYPE_OF_NEXT) == 0); \
args_num = 1; \
}
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
if (opcode == VM_OP_ ## opcode_name_uppercase) \
{ \
JERRY_STATIC_ASSERT (((arg1_type) & VM_OP_ARG_TYPE_TYPE_OF_NEXT) == 0); \
JERRY_STATIC_ASSERT (((arg2_type) & VM_OP_ARG_TYPE_TYPE_OF_NEXT) == 0); \
args_num = 2; \
}
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
if (opcode == VM_OP_ ## opcode_name_uppercase) \
{ \
JERRY_STATIC_ASSERT (((arg1_type) & VM_OP_ARG_TYPE_TYPE_OF_NEXT) == 0); \
\
/*
* See also:
* The loop below
*/ \
\
JERRY_ASSERT ((opcode == VM_OP_ASSIGNMENT && (arg2_type) == VM_OP_ARG_TYPE_TYPE_OF_NEXT) \
|| (opcode != VM_OP_ASSIGNMENT && ((arg2_type) & VM_OP_ARG_TYPE_TYPE_OF_NEXT) == 0)); \
JERRY_STATIC_ASSERT (((arg3_type) & VM_OP_ARG_TYPE_TYPE_OF_NEXT) == 0); \
args_num = 3; \
}
#include "vm-opcodes.inc.h"
for (int arg_index = 0; arg_index < args_num; arg_index++)
{
/*
* This is the only opcode with statically unspecified argument type (checked by assertions above)
*/
if (opcode == VM_OP_ASSIGNMENT
&& arg_index == 1
&& om.op.data.assignment.type_value_right != VM_OP_ARG_TYPE_VARIABLE)
{
break;
}
if (om.lit_id[arg_index].packed_value == lit_cp.packed_value)
{
om.lit_id[arg_index] = NOT_A_LITERAL;
JERRY_ASSERT (om.op.data.raw_args[arg_index] == VM_IDX_REWRITE_LITERAL_UID);
om.op.data.raw_args[arg_index] = reg;
}
}
scopes_tree_set_op_meta (tree, instr_pos, om);
}
return true;
} /* dumper_try_replace_var_with_reg */
#endif /* CONFIG_PARSER_ENABLE_PARSE_TIME_BYTE_CODE_OPTIMIZER */
/**
* Generate instruction with specified opcode and operands
*
* @return VM instruction
*/
static vm_instr_t
jsp_dmp_gen_instr (vm_op_t opcode, /**< operation code */
jsp_operand_t ops[], /**< operands */
size_t ops_num) /**< operands number */
{
vm_instr_t instr;
instr.op_idx = opcode;
for (size_t i = 0; i < ops_num; i++)
{
if (ops[i].is_empty_operand ())
{
instr.data.raw_args[i] = VM_IDX_EMPTY;
}
else if (ops[i].is_unknown_operand ())
{
instr.data.raw_args[i] = VM_IDX_REWRITE_GENERAL_CASE;
}
else if (ops[i].is_idx_const_operand ())
{
instr.data.raw_args[i] = ops[i].get_idx_const ();
}
else if (ops[i].is_register_operand ())
{
instr.data.raw_args[i] = ops[i].get_idx ();
}
else
{
JERRY_ASSERT (ops[i].is_literal_operand ());
instr.data.raw_args[i] = VM_IDX_REWRITE_LITERAL_UID;
}
}
for (size_t i = ops_num; i < 3; i++)
{
instr.data.raw_args[i] = VM_IDX_EMPTY;
}
return instr;
} /* jsp_dmp_gen_instr */
/**
* Create intermediate instruction description, containing pointers to literals,
* associated with the instruction's arguments, if there are any.
*
* @return intermediate operation description
*/
static op_meta
jsp_dmp_create_op_meta (vm_op_t opcode, /**< opcode */
jsp_operand_t ops[], /**< operands */
size_t ops_num) /**< operands number */
{
op_meta ret;
ret.op = jsp_dmp_gen_instr (opcode, ops, ops_num);
for (size_t i = 0; i < ops_num; i++)
{
if (ops[i].is_literal_operand ())
{
ret.lit_id[i] = ops[i].get_literal ();
}
else
{
ret.lit_id[i] = NOT_A_LITERAL;
}
}
for (size_t i = ops_num; i < 3; i++)
{
ret.lit_id[i] = NOT_A_LITERAL;
}
return ret;
} /* jsp_dmp_create_op_meta */
/**
* Create intermediate instruction description (for instructions without arguments)
*
* See also:
* jsp_dmp_create_op_meta
*
* @return intermediate instruction description
*/
static op_meta
jsp_dmp_create_op_meta_0 (vm_op_t opcode) /**< opcode */
{
return jsp_dmp_create_op_meta (opcode, NULL, 0);
} /* jsp_dmp_create_op_meta_0 */
/**
* Create intermediate instruction description (for instructions with 1 argument)
*
* See also:
* jsp_dmp_create_op_meta
*
* @return intermediate instruction description
*/
static op_meta
jsp_dmp_create_op_meta_1 (vm_op_t opcode, /**< opcode */
jsp_operand_t operand1) /**< first operand */
{
return jsp_dmp_create_op_meta (opcode, &operand1, 1);
} /* jsp_dmp_create_op_meta_1 */
/**
* Create intermediate instruction description (for instructions with 2 arguments)
*
* See also:
* jsp_dmp_create_op_meta
*
* @return intermediate instruction description
*/
static op_meta
jsp_dmp_create_op_meta_2 (vm_op_t opcode, /**< opcode */
jsp_operand_t operand1, /**< first operand */
jsp_operand_t operand2) /**< second operand */
{
jsp_operand_t ops[] = { operand1, operand2 };
return jsp_dmp_create_op_meta (opcode, ops, 2);
} /* jsp_dmp_create_op_meta_2 */
/**
* Create intermediate instruction description (for instructions with 3 arguments)
*
* See also:
* jsp_dmp_create_op_meta
*
* @return intermediate instruction description
*/
static op_meta
jsp_dmp_create_op_meta_3 (vm_op_t opcode, /**< opcode */
jsp_operand_t operand1, /**< first operand */
jsp_operand_t operand2, /**< second operand */
jsp_operand_t operand3) /**< third operand */
{
jsp_operand_t ops[] = { operand1, operand2, operand3 };
return jsp_dmp_create_op_meta (opcode, ops, 3);
} /* jsp_dmp_create_op_meta_3 */
static jsp_operand_t
tmp_operand (void)
{
return jsp_operand_t::make_reg_operand (jsp_alloc_reg_for_temp ());
}
static void
split_instr_counter (vm_instr_counter_t oc, vm_idx_t *id1, vm_idx_t *id2)
{
JERRY_ASSERT (id1 != NULL);
JERRY_ASSERT (id2 != NULL);
*id1 = (vm_idx_t) (oc >> JERRY_BITSINBYTE);
*id2 = (vm_idx_t) (oc & ((1 << JERRY_BITSINBYTE) - 1));
JERRY_ASSERT (oc == vm_calc_instr_counter_from_idx_idx (*id1, *id2));
}
static op_meta
last_dumped_op_meta (void)
{
return serializer_get_op_meta ((vm_instr_counter_t) (serializer_get_current_instr_counter () - 1));
}
static void
dump_single_address (vm_op_t opcode,
jsp_operand_t op)
{
serializer_dump_op_meta (jsp_dmp_create_op_meta_1 (opcode, op));
}
static void
dump_double_address (vm_op_t opcode,
jsp_operand_t res,
jsp_operand_t obj)
{
serializer_dump_op_meta (jsp_dmp_create_op_meta_2 (opcode, res, obj));
}
static void
dump_triple_address (vm_op_t opcode,
jsp_operand_t res,
jsp_operand_t lhs,
jsp_operand_t rhs)
{
serializer_dump_op_meta (jsp_dmp_create_op_meta_3 (opcode, res, lhs, rhs));
}
static jsp_operand_t
create_operand_from_tmp_and_lit (vm_idx_t tmp, lit_cpointer_t lit_id)
{
if (tmp != VM_IDX_REWRITE_LITERAL_UID)
{
JERRY_ASSERT (lit_id.packed_value == MEM_CP_NULL);
return jsp_operand_t::make_reg_operand (tmp);
}
else
{
JERRY_ASSERT (lit_id.packed_value != MEM_CP_NULL);
return jsp_operand_t::make_lit_operand (lit_id);
}
}
static void
dump_prop_setter_op_meta (op_meta last, jsp_operand_t op)
{
JERRY_ASSERT (last.op.op_idx == VM_OP_PROP_GETTER);
dump_triple_address (VM_OP_PROP_SETTER,
create_operand_from_tmp_and_lit (last.op.data.prop_getter.obj,
last.lit_id[1]),
create_operand_from_tmp_and_lit (last.op.data.prop_getter.prop,
last.lit_id[2]),
op);
}
static jsp_operand_t
dump_triple_address_and_prop_setter_res (vm_op_t opcode, /**< opcode of triple address operation */
op_meta last,
jsp_operand_t op)
{
JERRY_ASSERT (last.op.op_idx == VM_OP_PROP_GETTER);
const jsp_operand_t obj = create_operand_from_tmp_and_lit (last.op.data.prop_getter.obj, last.lit_id[1]);
const jsp_operand_t prop = create_operand_from_tmp_and_lit (last.op.data.prop_getter.prop, last.lit_id[2]);
const jsp_operand_t tmp = dump_prop_getter_res (obj, prop);
dump_triple_address (opcode, tmp, tmp, op);
dump_prop_setter (obj, prop, tmp);
return tmp;
}
static jsp_operand_t
dump_prop_setter_or_triple_address_res (vm_op_t opcode,
jsp_operand_t res,
jsp_operand_t op)
{
const op_meta last = STACK_TOP (prop_getters);
if (last.op.op_idx == VM_OP_PROP_GETTER)
{
res = dump_triple_address_and_prop_setter_res (opcode, last, op);
}
else
{
if (res.is_register_operand ())
{
/*
* FIXME:
* Implement correct handling of references through parser operands
*/
PARSE_ERROR (JSP_EARLY_ERROR_REFERENCE, "Invalid left-hand-side expression", LIT_ITERATOR_POS_ZERO);
}
dump_triple_address (opcode, res, res, op);
}
STACK_DROP (prop_getters, 1);
return res;
}
static vm_instr_counter_t
get_diff_from (vm_instr_counter_t oc)
{
return (vm_instr_counter_t) (serializer_get_current_instr_counter () - oc);
}
jsp_operand_t
empty_operand (void)
{
return jsp_operand_t::make_empty_operand ();
}
jsp_operand_t
literal_operand (lit_cpointer_t lit_cp)
{
return jsp_operand_t::make_lit_operand (lit_cp);
}
/**
* Creates operand for eval's return value
*
* @return constructed operand
*/
jsp_operand_t
eval_ret_operand (void)
{
return jsp_operand_t::make_reg_operand (VM_REG_SPECIAL_EVAL_RET);
} /* eval_ret_operand */
/**
* Creates operand for taking iterator value (next property name)
* from for-in instr handler.
*
* @return constructed operand
*/
jsp_operand_t
jsp_create_operand_for_in_special_reg (void)
{
return jsp_operand_t::make_reg_operand (VM_REG_SPECIAL_FOR_IN_PROPERTY_NAME);
} /* jsp_create_operand_for_in_special_reg */
bool
operand_is_empty (jsp_operand_t op)
{
return op.is_empty_operand ();
}
void
dumper_new_statement (void)
{
jsp_reg_next = VM_REG_GENERAL_FIRST;
}
void
dumper_new_scope (void)
{
JERRY_ASSERT (jsp_reg_max_for_local_var == VM_IDX_EMPTY);
STACK_PUSH (jsp_reg_id_stack, jsp_reg_next);
STACK_PUSH (jsp_reg_id_stack, jsp_reg_max_for_temps);
jsp_reg_next = VM_REG_GENERAL_FIRST;
jsp_reg_max_for_temps = jsp_reg_next;
}
void
dumper_finish_scope (void)
{
JERRY_ASSERT (jsp_reg_max_for_local_var == VM_IDX_EMPTY);
jsp_reg_max_for_temps = STACK_TOP (jsp_reg_id_stack);
STACK_DROP (jsp_reg_id_stack, 1);
jsp_reg_next = STACK_TOP (jsp_reg_id_stack);
STACK_DROP (jsp_reg_id_stack, 1);
}
/**
* Handle start of argument preparation instruction sequence generation
*
* Note:
* Values of registers, allocated for the code sequence, are not used outside of the sequence,
* so they can be reused, reducing register pressure.
*
* To reuse the registers, counter of register allocator is saved, and restored then,
* after finishing generation of the code sequence, using dumper_finish_varg_code_sequence.
*
* FIXME:
* Implement general register allocation mechanism
*
* See also:
* dumper_finish_varg_code_sequence
*/
void
dumper_start_varg_code_sequence (void)
{
STACK_PUSH (jsp_reg_id_stack, jsp_reg_next);
} /* dumper_start_varg_code_sequence */
/**
* Handle finish of argument preparation instruction sequence generation
*
* See also:
* dumper_start_varg_code_sequence
*/
void
dumper_finish_varg_code_sequence (void)
{
jsp_reg_next = STACK_TOP (jsp_reg_id_stack);
STACK_DROP (jsp_reg_id_stack, 1);
} /* dumper_finish_varg_code_sequence */
/**
* Check that byte-code operand refers to 'eval' string
*
* @return true - if specified byte-code operand's type is literal, and value of corresponding
* literal is equal to LIT_MAGIC_STRING_EVAL string,
* false - otherwise.
*/
bool
dumper_is_eval_literal (jsp_operand_t obj) /**< byte-code operand */
{
/*
* FIXME: Switch to corresponding magic string
*/
bool is_eval_lit = (obj.is_literal_operand ()
&& lit_literal_equal_type_cstr (lit_get_literal_by_cp (obj.get_literal ()), "eval"));
return is_eval_lit;
} /* dumper_is_eval_literal */
/**
* Dump assignment of an array-hole simple value to a register
*
* @return register number, to which the value vas assigned
*/
jsp_operand_t
dump_array_hole_assignment_res (void)
{
jsp_operand_t op, type_operand, value_operand;
op = tmp_operand ();
type_operand = jsp_operand_t::make_idx_const_operand (OPCODE_ARG_TYPE_SIMPLE);
value_operand = jsp_operand_t::make_idx_const_operand (ECMA_SIMPLE_VALUE_ARRAY_HOLE);
dump_triple_address (VM_OP_ASSIGNMENT, op, type_operand, value_operand);
return op;
} /* dump_array_hole_assignment_res */
void
dump_boolean_assignment (jsp_operand_t op, bool is_true)
{
jsp_operand_t type_operand, value_operand;
type_operand = jsp_operand_t::make_idx_const_operand (OPCODE_ARG_TYPE_SIMPLE);
value_operand = jsp_operand_t::make_idx_const_operand (is_true ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE);
dump_triple_address (VM_OP_ASSIGNMENT, op, type_operand, value_operand);
}
jsp_operand_t
dump_boolean_assignment_res (bool is_true)
{
jsp_operand_t op = tmp_operand ();
dump_boolean_assignment (op, is_true);
return op;
}
void
dump_string_assignment (jsp_operand_t op, lit_cpointer_t lit_id)
{
jsp_operand_t type_operand, value_operand;
type_operand = jsp_operand_t::make_idx_const_operand (OPCODE_ARG_TYPE_STRING);
value_operand = jsp_operand_t::make_lit_operand (lit_id);
dump_triple_address (VM_OP_ASSIGNMENT, op, type_operand, value_operand);
}
jsp_operand_t
dump_string_assignment_res (lit_cpointer_t lit_id)
{
jsp_operand_t op = tmp_operand ();
dump_string_assignment (op, lit_id);
return op;
}
void
dump_number_assignment (jsp_operand_t op, lit_cpointer_t lit_id)
{
jsp_operand_t type_operand, value_operand;
type_operand = jsp_operand_t::make_idx_const_operand (OPCODE_ARG_TYPE_NUMBER);
value_operand = jsp_operand_t::make_lit_operand (lit_id);
dump_triple_address (VM_OP_ASSIGNMENT, op, type_operand, value_operand);
}
jsp_operand_t
dump_number_assignment_res (lit_cpointer_t lit_id)
{
jsp_operand_t op = tmp_operand ();
dump_number_assignment (op, lit_id);
return op;
}
void
dump_regexp_assignment (jsp_operand_t op, lit_cpointer_t lit_id)
{
jsp_operand_t type_operand, value_operand;
type_operand = jsp_operand_t::make_idx_const_operand (OPCODE_ARG_TYPE_REGEXP);
value_operand = jsp_operand_t::make_lit_operand (lit_id);
dump_triple_address (VM_OP_ASSIGNMENT, op, type_operand, value_operand);
}
jsp_operand_t
dump_regexp_assignment_res (lit_cpointer_t lit_id)
{
jsp_operand_t op = tmp_operand ();
dump_regexp_assignment (op, lit_id);
return op;
}
void
dump_smallint_assignment (jsp_operand_t op, vm_idx_t uid)
{
jsp_operand_t type_operand, value_operand;
type_operand = jsp_operand_t::make_idx_const_operand (OPCODE_ARG_TYPE_SMALLINT);
value_operand = jsp_operand_t::make_idx_const_operand (uid);
dump_triple_address (VM_OP_ASSIGNMENT, op, type_operand, value_operand);
}
jsp_operand_t
dump_smallint_assignment_res (vm_idx_t uid)
{
jsp_operand_t op = tmp_operand ();
dump_smallint_assignment (op, uid);
return op;
}
void
dump_undefined_assignment (jsp_operand_t op)
{
jsp_operand_t type_operand, value_operand;
type_operand = jsp_operand_t::make_idx_const_operand (OPCODE_ARG_TYPE_SIMPLE);
value_operand = jsp_operand_t::make_idx_const_operand (ECMA_SIMPLE_VALUE_UNDEFINED);
dump_triple_address (VM_OP_ASSIGNMENT, op, type_operand, value_operand);
}
jsp_operand_t
dump_undefined_assignment_res (void)
{
jsp_operand_t op = tmp_operand ();
dump_undefined_assignment (op);
return op;
}
void
dump_null_assignment (jsp_operand_t op)
{
jsp_operand_t type_operand, value_operand;
type_operand = jsp_operand_t::make_idx_const_operand (OPCODE_ARG_TYPE_SIMPLE);
value_operand = jsp_operand_t::make_idx_const_operand (ECMA_SIMPLE_VALUE_NULL);
dump_triple_address (VM_OP_ASSIGNMENT, op, type_operand, value_operand);
}
jsp_operand_t
dump_null_assignment_res (void)
{
jsp_operand_t op = tmp_operand ();
dump_null_assignment (op);
return op;
}
void
dump_variable_assignment (jsp_operand_t res, jsp_operand_t var)
{
jsp_operand_t type_operand;
type_operand = jsp_operand_t::make_idx_const_operand (OPCODE_ARG_TYPE_VARIABLE);
dump_triple_address (VM_OP_ASSIGNMENT, res, type_operand, var);
}
jsp_operand_t
dump_variable_assignment_res (jsp_operand_t var)
{
jsp_operand_t op = tmp_operand ();
dump_variable_assignment (op, var);
return op;
}
void
dump_varg_header_for_rewrite (varg_list_type vlt, jsp_operand_t obj)
{
STACK_PUSH (varg_headers, serializer_get_current_instr_counter ());
switch (vlt)
{
case VARG_FUNC_EXPR:
{
dump_triple_address (VM_OP_FUNC_EXPR_N,
jsp_operand_t::make_unknown_operand (),
obj,
jsp_operand_t::make_unknown_operand ());
break;
}
case VARG_CONSTRUCT_EXPR:
{
dump_triple_address (VM_OP_CONSTRUCT_N,
jsp_operand_t::make_unknown_operand (),
obj,
jsp_operand_t::make_unknown_operand ());
break;
}
case VARG_CALL_EXPR:
{
dump_triple_address (VM_OP_CALL_N,
jsp_operand_t::make_unknown_operand (),
obj,
jsp_operand_t::make_unknown_operand ());
break;
}
case VARG_FUNC_DECL:
{
dump_double_address (VM_OP_FUNC_DECL_N,
obj,
jsp_operand_t::make_unknown_operand ());
break;
}
case VARG_ARRAY_DECL:
{
dump_double_address (VM_OP_ARRAY_DECL,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
break;
}
case VARG_OBJ_DECL:
{
dump_double_address (VM_OP_OBJ_DECL,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
break;
}
}
}
jsp_operand_t
rewrite_varg_header_set_args_count (size_t args_count)
{
/*
* FIXME:
* Remove formal parameters / arguments number from instruction,
* after ecma-values collection would become extendable (issue #310).
* In the case, each 'varg' instruction would just append corresponding
* argument / formal parameter name to values collection.
*/
op_meta om = serializer_get_op_meta (STACK_TOP (varg_headers));
switch (om.op.op_idx)
{
case VM_OP_FUNC_EXPR_N:
case VM_OP_CONSTRUCT_N:
case VM_OP_CALL_N:
{
if (args_count > 255)
{
PARSE_ERROR (JSP_EARLY_ERROR_SYNTAX,
"No more than 255 formal parameters / arguments are currently supported",
LIT_ITERATOR_POS_ZERO);
}
const jsp_operand_t res = tmp_operand ();
om.op.data.func_expr_n.arg_list = (vm_idx_t) args_count;
om.op.data.func_expr_n.lhs = res.get_idx ();
serializer_rewrite_op_meta (STACK_TOP (varg_headers), om);
STACK_DROP (varg_headers, 1);
return res;
}
case VM_OP_FUNC_DECL_N:
{
if (args_count > 255)
{
PARSE_ERROR (JSP_EARLY_ERROR_SYNTAX,
"No more than 255 formal parameters are currently supported",
LIT_ITERATOR_POS_ZERO);
}
om.op.data.func_decl_n.arg_list = (vm_idx_t) args_count;
serializer_rewrite_op_meta (STACK_TOP (varg_headers), om);
STACK_DROP (varg_headers, 1);
return empty_operand ();
}
case VM_OP_ARRAY_DECL:
case VM_OP_OBJ_DECL:
{
if (args_count > 65535)
{
PARSE_ERROR (JSP_EARLY_ERROR_SYNTAX,
"No more than 65535 formal parameters are currently supported",
LIT_ITERATOR_POS_ZERO);
}
const jsp_operand_t res = tmp_operand ();
om.op.data.obj_decl.list_1 = (vm_idx_t) (args_count >> 8);
om.op.data.obj_decl.list_2 = (vm_idx_t) (args_count & 0xffu);
om.op.data.obj_decl.lhs = res.get_idx ();
serializer_rewrite_op_meta (STACK_TOP (varg_headers), om);
STACK_DROP (varg_headers, 1);
return res;
}
default:
{
JERRY_UNREACHABLE ();
}
}
}
/**
* Dump 'meta' instruction of 'call additional information' type,
* containing call flags and, optionally, 'this' argument
*/
void
dump_call_additional_info (opcode_call_flags_t flags, /**< call flags */
jsp_operand_t this_arg) /**< 'this' argument - if flags
* include OPCODE_CALL_FLAGS_HAVE_THIS_ARG,
* or empty operand - otherwise */
{
if (flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
{
JERRY_ASSERT (this_arg.is_register_operand ());
JERRY_ASSERT (!operand_is_empty (this_arg));
}
else
{
JERRY_ASSERT (operand_is_empty (this_arg));
}
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_CALL_SITE_INFO),
jsp_operand_t::make_idx_const_operand (flags),
this_arg);
} /* dump_call_additional_info */
void
dump_varg (jsp_operand_t op)
{
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_VARG),
op,
jsp_operand_t::make_empty_operand ());
}
void
dump_prop_name_and_value (jsp_operand_t name, jsp_operand_t value)
{
JERRY_ASSERT (name.is_literal_operand ());
literal_t lit = lit_get_literal_by_cp (name.get_literal ());
jsp_operand_t tmp;
if (lit->get_type () == LIT_STR_T
|| lit->get_type () == LIT_MAGIC_STR_T
|| lit->get_type () == LIT_MAGIC_STR_EX_T)
{
tmp = dump_string_assignment_res (name.get_literal ());
}
else
{
JERRY_ASSERT (lit->get_type () == LIT_NUMBER_T);
tmp = dump_number_assignment_res (name.get_literal ());
}
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_VARG_PROP_DATA),
tmp,
value);
}
void
dump_prop_getter_decl (jsp_operand_t name, jsp_operand_t func)
{
JERRY_ASSERT (name.is_literal_operand ());
JERRY_ASSERT (func.is_register_operand ());
literal_t lit = lit_get_literal_by_cp (name.get_literal ());
jsp_operand_t tmp;
if (lit->get_type () == LIT_STR_T
|| lit->get_type () == LIT_MAGIC_STR_T
|| lit->get_type () == LIT_MAGIC_STR_EX_T)
{
tmp = dump_string_assignment_res (name.get_literal ());
}
else
{
JERRY_ASSERT (lit->get_type () == LIT_NUMBER_T);
tmp = dump_number_assignment_res (name.get_literal ());
}
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_VARG_PROP_GETTER),
tmp,
func);
}
void
dump_prop_setter_decl (jsp_operand_t name, jsp_operand_t func)
{
JERRY_ASSERT (name.is_literal_operand ());
JERRY_ASSERT (func.is_register_operand ());
literal_t lit = lit_get_literal_by_cp (name.get_literal ());
jsp_operand_t tmp;
if (lit->get_type () == LIT_STR_T
|| lit->get_type () == LIT_MAGIC_STR_T
|| lit->get_type () == LIT_MAGIC_STR_EX_T)
{
tmp = dump_string_assignment_res (name.get_literal ());
}
else
{
JERRY_ASSERT (lit->get_type () == LIT_NUMBER_T);
tmp = dump_number_assignment_res (name.get_literal ());
}
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_VARG_PROP_SETTER),
tmp,
func);
}
void
dump_prop_getter (jsp_operand_t res, jsp_operand_t obj, jsp_operand_t prop)
{
dump_triple_address (VM_OP_PROP_GETTER, res, obj, prop);
}
jsp_operand_t
dump_prop_getter_res (jsp_operand_t obj, jsp_operand_t prop)
{
const jsp_operand_t res = tmp_operand ();
dump_prop_getter (res, obj, prop);
return res;
}
void
dump_prop_setter (jsp_operand_t res, jsp_operand_t obj, jsp_operand_t prop)
{
dump_triple_address (VM_OP_PROP_SETTER, res, obj, prop);
}
void
dump_function_end_for_rewrite (void)
{
STACK_PUSH (function_ends, serializer_get_current_instr_counter ());
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_FUNCTION_END),
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
}
void
rewrite_function_end ()
{
vm_instr_counter_t oc;
{
oc = (vm_instr_counter_t) (get_diff_from (STACK_TOP (function_ends))
+ serializer_count_instrs_in_subscopes ());
}
vm_idx_t id1, id2;
split_instr_counter (oc, &id1, &id2);
op_meta function_end_op_meta = serializer_get_op_meta (STACK_TOP (function_ends));
JERRY_ASSERT (function_end_op_meta.op.op_idx == VM_OP_META);
JERRY_ASSERT (function_end_op_meta.op.data.meta.type == OPCODE_META_TYPE_FUNCTION_END);
JERRY_ASSERT (function_end_op_meta.op.data.meta.data_1 == VM_IDX_REWRITE_GENERAL_CASE);
JERRY_ASSERT (function_end_op_meta.op.data.meta.data_2 == VM_IDX_REWRITE_GENERAL_CASE);
function_end_op_meta.op.data.meta.data_1 = id1;
function_end_op_meta.op.data.meta.data_2 = id2;
serializer_rewrite_op_meta (STACK_TOP (function_ends), function_end_op_meta);
STACK_DROP (function_ends, 1);
}
void
dump_this (jsp_operand_t op)
{
dump_single_address (VM_OP_THIS_BINDING, op);
}
jsp_operand_t
dump_this_res (void)
{
const jsp_operand_t res = tmp_operand ();
dump_this (res);
return res;
}
void
dump_post_increment (jsp_operand_t res, jsp_operand_t obj)
{
dump_double_address (VM_OP_POST_INCR, res, obj);
}
jsp_operand_t
dump_post_increment_res (jsp_operand_t op)
{
const jsp_operand_t res = tmp_operand ();
dump_post_increment (res, op);
return res;
}
void
dump_post_decrement (jsp_operand_t res, jsp_operand_t obj)
{
dump_double_address (VM_OP_POST_DECR, res, obj);
}
jsp_operand_t
dump_post_decrement_res (jsp_operand_t op)
{
const jsp_operand_t res = tmp_operand ();
dump_post_decrement (res, op);
return res;
}
/**
* Check if operand of prefix operation is correct
*/
static void
check_operand_in_prefix_operation (jsp_operand_t obj) /**< operand, which type should be Reference */
{
const op_meta last = last_dumped_op_meta ();
if (last.op.op_idx != VM_OP_PROP_GETTER)
{
if (obj.is_empty_operand ())
{
/*
* FIXME:
* Implement correct handling of references through parser operands
*/
PARSE_ERROR (JSP_EARLY_ERROR_REFERENCE,
"Invalid left-hand-side expression in prefix operation",
LIT_ITERATOR_POS_ZERO);
}
}
} /* check_operand_in_prefix_operation */
void
dump_pre_increment (jsp_operand_t res, jsp_operand_t obj)
{
check_operand_in_prefix_operation (obj);
dump_double_address (VM_OP_PRE_INCR, res, obj);
}
jsp_operand_t
dump_pre_increment_res (jsp_operand_t op)
{
const jsp_operand_t res = tmp_operand ();
dump_pre_increment (res, op);
return res;
}
void
dump_pre_decrement (jsp_operand_t res, jsp_operand_t obj)
{
check_operand_in_prefix_operation (obj);
dump_double_address (VM_OP_PRE_DECR, res, obj);
}
jsp_operand_t
dump_pre_decrement_res (jsp_operand_t op)
{
const jsp_operand_t res = tmp_operand ();
dump_pre_decrement (res, op);
return res;
}
void
dump_unary_plus (jsp_operand_t res, jsp_operand_t obj)
{
dump_double_address (VM_OP_UNARY_PLUS, res, obj);
}
jsp_operand_t
dump_unary_plus_res (jsp_operand_t op)
{
const jsp_operand_t res = tmp_operand ();
dump_unary_plus (res, op);
return res;
}
void
dump_unary_minus (jsp_operand_t res, jsp_operand_t obj)
{
dump_double_address (VM_OP_UNARY_MINUS, res, obj);
}
jsp_operand_t
dump_unary_minus_res (jsp_operand_t op)
{
const jsp_operand_t res = tmp_operand ();
dump_unary_minus (res, op);
return res;
}
void
dump_bitwise_not (jsp_operand_t res, jsp_operand_t obj)
{
dump_double_address (VM_OP_B_NOT, res, obj);
}
jsp_operand_t
dump_bitwise_not_res (jsp_operand_t op)
{
const jsp_operand_t res = tmp_operand ();
dump_bitwise_not (res, op);
return res;
}
void
dump_logical_not (jsp_operand_t res, jsp_operand_t obj)
{
dump_double_address (VM_OP_LOGICAL_NOT, res, obj);
}
jsp_operand_t
dump_logical_not_res (jsp_operand_t op)
{
const jsp_operand_t res = tmp_operand ();
dump_logical_not (res, op);
return res;
}
void
dump_delete (jsp_operand_t res, jsp_operand_t op, bool is_strict, locus loc)
{
if (op.is_literal_operand ())
{
literal_t lit = lit_get_literal_by_cp (op.get_literal ());
if (lit->get_type () == LIT_STR_T
|| lit->get_type () == LIT_MAGIC_STR_T
|| lit->get_type () == LIT_MAGIC_STR_EX_T)
{
jsp_early_error_check_delete (is_strict, loc);
dump_double_address (VM_OP_DELETE_VAR, res, op);
}
else if (lit->get_type () == LIT_NUMBER_T)
{
dump_boolean_assignment (res, true);
}
}
else
{
JERRY_ASSERT (op.is_register_operand ());
const op_meta last_op_meta = last_dumped_op_meta ();
switch (last_op_meta.op.op_idx)
{
case VM_OP_PROP_GETTER:
{
const vm_instr_counter_t oc = (vm_instr_counter_t) (serializer_get_current_instr_counter () - 1);
serializer_set_writing_position (oc);
dump_triple_address (VM_OP_DELETE_PROP,
res,
create_operand_from_tmp_and_lit (last_op_meta.op.data.prop_getter.obj,
last_op_meta.lit_id[1]),
create_operand_from_tmp_and_lit (last_op_meta.op.data.prop_getter.prop,
last_op_meta.lit_id[2]));
break;
}
default:
{
dump_boolean_assignment (res, true);
}
}
}
}
jsp_operand_t
dump_delete_res (jsp_operand_t op, bool is_strict, locus loc)
{
const jsp_operand_t res = tmp_operand ();
dump_delete (res, op, is_strict, loc);
return res;
}
void
dump_typeof (jsp_operand_t res, jsp_operand_t op)
{
dump_double_address (VM_OP_TYPEOF, res, op);
}
jsp_operand_t
dump_typeof_res (jsp_operand_t op)
{
const jsp_operand_t res = tmp_operand ();
dump_typeof (res, op);
return res;
}
void
dump_multiplication (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_MULTIPLICATION, res, lhs, rhs);
}
jsp_operand_t
dump_multiplication_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_multiplication (res, lhs, rhs);
return res;
}
void
dump_division (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_DIVISION, res, lhs, rhs);
}
jsp_operand_t
dump_division_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_division (res, lhs, rhs);
return res;
}
void
dump_remainder (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_REMAINDER, res, lhs, rhs);
}
jsp_operand_t
dump_remainder_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_remainder (res, lhs, rhs);
return res;
}
void
dump_addition (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_ADDITION, res, lhs, rhs);
}
jsp_operand_t
dump_addition_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_addition (res, lhs, rhs);
return res;
}
void
dump_substraction (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_SUBSTRACTION, res, lhs, rhs);
}
jsp_operand_t
dump_substraction_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_substraction (res, lhs, rhs);
return res;
}
void
dump_left_shift (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_B_SHIFT_LEFT, res, lhs, rhs);
}
jsp_operand_t
dump_left_shift_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_left_shift (res, lhs, rhs);
return res;
}
void
dump_right_shift (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_B_SHIFT_RIGHT, res, lhs, rhs);
}
jsp_operand_t
dump_right_shift_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_right_shift (res, lhs, rhs);
return res;
}
void
dump_right_shift_ex (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_B_SHIFT_URIGHT, res, lhs, rhs);
}
jsp_operand_t
dump_right_shift_ex_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_right_shift_ex (res, lhs, rhs);
return res;
}
void
dump_less_than (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_LESS_THAN, res, lhs, rhs);
}
jsp_operand_t
dump_less_than_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_less_than (res, lhs, rhs);
return res;
}
void
dump_greater_than (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_GREATER_THAN, res, lhs, rhs);
}
jsp_operand_t
dump_greater_than_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_greater_than (res, lhs, rhs);
return res;
}
void
dump_less_or_equal_than (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_LESS_OR_EQUAL_THAN, res, lhs, rhs);
}
jsp_operand_t
dump_less_or_equal_than_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_less_or_equal_than (res, lhs, rhs);
return res;
}
void
dump_greater_or_equal_than (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_GREATER_OR_EQUAL_THAN, res, lhs, rhs);
}
jsp_operand_t
dump_greater_or_equal_than_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_greater_or_equal_than (res, lhs, rhs);
return res;
}
void
dump_instanceof (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_INSTANCEOF, res, lhs, rhs);
}
jsp_operand_t
dump_instanceof_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_instanceof (res, lhs, rhs);
return res;
}
void
dump_in (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_IN, res, lhs, rhs);
}
jsp_operand_t
dump_in_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_in (res, lhs, rhs);
return res;
}
void
dump_equal_value (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_EQUAL_VALUE, res, lhs, rhs);
}
jsp_operand_t
dump_equal_value_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_equal_value (res, lhs, rhs);
return res;
}
void
dump_not_equal_value (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_NOT_EQUAL_VALUE, res, lhs, rhs);
}
jsp_operand_t
dump_not_equal_value_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_not_equal_value (res, lhs, rhs);
return res;
}
void
dump_equal_value_type (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_EQUAL_VALUE_TYPE, res, lhs, rhs);
}
jsp_operand_t
dump_equal_value_type_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_equal_value_type (res, lhs, rhs);
return res;
}
void
dump_not_equal_value_type (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_NOT_EQUAL_VALUE_TYPE, res, lhs, rhs);
}
jsp_operand_t
dump_not_equal_value_type_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_not_equal_value_type (res, lhs, rhs);
return res;
}
void
dump_bitwise_and (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_B_AND, res, lhs, rhs);
}
jsp_operand_t
dump_bitwise_and_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_bitwise_and (res, lhs, rhs);
return res;
}
void
dump_bitwise_xor (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_B_XOR, res, lhs, rhs);
}
jsp_operand_t
dump_bitwise_xor_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_bitwise_xor (res, lhs, rhs);
return res;
}
void
dump_bitwise_or (jsp_operand_t res, jsp_operand_t lhs, jsp_operand_t rhs)
{
dump_triple_address (VM_OP_B_OR, res, lhs, rhs);
}
jsp_operand_t
dump_bitwise_or_res (jsp_operand_t lhs, jsp_operand_t rhs)
{
const jsp_operand_t res = tmp_operand ();
dump_bitwise_or (res, lhs, rhs);
return res;
}
void
start_dumping_logical_and_checks (void)
{
STACK_PUSH (U8, (uint8_t) STACK_SIZE (logical_and_checks));
}
void
dump_logical_and_check_for_rewrite (jsp_operand_t op)
{
STACK_PUSH (logical_and_checks, serializer_get_current_instr_counter ());
dump_triple_address (VM_OP_IS_FALSE_JMP_DOWN,
op,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
}
void
rewrite_logical_and_checks (void)
{
for (uint8_t i = STACK_TOP (U8); i < STACK_SIZE (logical_and_checks); i++)
{
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (STACK_ELEMENT (logical_and_checks, i)), &id1, &id2);
op_meta jmp_op_meta = serializer_get_op_meta (STACK_ELEMENT (logical_and_checks, i));
JERRY_ASSERT (jmp_op_meta.op.op_idx == VM_OP_IS_FALSE_JMP_DOWN);
jmp_op_meta.op.data.is_false_jmp_down.oc_idx_1 = id1;
jmp_op_meta.op.data.is_false_jmp_down.oc_idx_2 = id2;
serializer_rewrite_op_meta (STACK_ELEMENT (logical_and_checks, i), jmp_op_meta);
}
STACK_DROP (logical_and_checks, STACK_SIZE (logical_and_checks) - STACK_TOP (U8));
STACK_DROP (U8, 1);
}
void
start_dumping_logical_or_checks (void)
{
STACK_PUSH (U8, (uint8_t) STACK_SIZE (logical_or_checks));
}
void
dump_logical_or_check_for_rewrite (jsp_operand_t op)
{
STACK_PUSH (logical_or_checks, serializer_get_current_instr_counter ());
dump_triple_address (VM_OP_IS_TRUE_JMP_DOWN,
op,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
}
void
rewrite_logical_or_checks (void)
{
for (uint8_t i = STACK_TOP (U8); i < STACK_SIZE (logical_or_checks); i++)
{
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (STACK_ELEMENT (logical_or_checks, i)), &id1, &id2);
op_meta jmp_op_meta = serializer_get_op_meta (STACK_ELEMENT (logical_or_checks, i));
JERRY_ASSERT (jmp_op_meta.op.op_idx == VM_OP_IS_TRUE_JMP_DOWN);
jmp_op_meta.op.data.is_true_jmp_down.oc_idx_1 = id1;
jmp_op_meta.op.data.is_true_jmp_down.oc_idx_2 = id2;
serializer_rewrite_op_meta (STACK_ELEMENT (logical_or_checks, i), jmp_op_meta);
}
STACK_DROP (logical_or_checks, STACK_SIZE (logical_or_checks) - STACK_TOP (U8));
STACK_DROP (U8, 1);
}
void
dump_conditional_check_for_rewrite (jsp_operand_t op)
{
STACK_PUSH (conditional_checks, serializer_get_current_instr_counter ());
dump_triple_address (VM_OP_IS_FALSE_JMP_DOWN,
op,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
}
void
rewrite_conditional_check (void)
{
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (STACK_TOP (conditional_checks)), &id1, &id2);
op_meta jmp_op_meta = serializer_get_op_meta (STACK_TOP (conditional_checks));
JERRY_ASSERT (jmp_op_meta.op.op_idx == VM_OP_IS_FALSE_JMP_DOWN);
jmp_op_meta.op.data.is_false_jmp_down.oc_idx_1 = id1;
jmp_op_meta.op.data.is_false_jmp_down.oc_idx_2 = id2;
serializer_rewrite_op_meta (STACK_TOP (conditional_checks), jmp_op_meta);
STACK_DROP (conditional_checks, 1);
}
void
dump_jump_to_end_for_rewrite (void)
{
STACK_PUSH (jumps_to_end, serializer_get_current_instr_counter ());
dump_double_address (VM_OP_JMP_DOWN,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
}
void
rewrite_jump_to_end (void)
{
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (STACK_TOP (jumps_to_end)), &id1, &id2);
op_meta jmp_op_meta = serializer_get_op_meta (STACK_TOP (jumps_to_end));
JERRY_ASSERT (jmp_op_meta.op.op_idx == VM_OP_JMP_DOWN);
jmp_op_meta.op.data.jmp_down.oc_idx_1 = id1;
jmp_op_meta.op.data.jmp_down.oc_idx_2 = id2;
serializer_rewrite_op_meta (STACK_TOP (jumps_to_end), jmp_op_meta);
STACK_DROP (jumps_to_end, 1);
}
void
start_dumping_assignment_expression (void)
{
const op_meta last = last_dumped_op_meta ();
if (last.op.op_idx == VM_OP_PROP_GETTER)
{
serializer_set_writing_position ((vm_instr_counter_t) (serializer_get_current_instr_counter () - 1));
}
STACK_PUSH (prop_getters, last);
}
jsp_operand_t
dump_prop_setter_or_variable_assignment_res (jsp_operand_t res, jsp_operand_t op)
{
const op_meta last = STACK_TOP (prop_getters);
if (last.op.op_idx == VM_OP_PROP_GETTER)
{
dump_prop_setter_op_meta (last, op);
}
else
{
if (res.is_register_operand ())
{
/*
* FIXME:
* Implement correct handling of references through parser operands
*/
PARSE_ERROR (JSP_EARLY_ERROR_REFERENCE, "Invalid left-hand-side expression", LIT_ITERATOR_POS_ZERO);
}
dump_variable_assignment (res, op);
}
STACK_DROP (prop_getters, 1);
return op;
}
jsp_operand_t
dump_prop_setter_or_addition_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_ADDITION, res, op);
}
jsp_operand_t
dump_prop_setter_or_multiplication_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_MULTIPLICATION, res, op);
}
jsp_operand_t
dump_prop_setter_or_division_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_DIVISION, res, op);
}
jsp_operand_t
dump_prop_setter_or_remainder_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_REMAINDER, res, op);
}
jsp_operand_t
dump_prop_setter_or_substraction_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_SUBSTRACTION, res, op);
}
jsp_operand_t
dump_prop_setter_or_left_shift_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_B_SHIFT_LEFT, res, op);
}
jsp_operand_t
dump_prop_setter_or_right_shift_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_B_SHIFT_RIGHT, res, op);
}
jsp_operand_t
dump_prop_setter_or_right_shift_ex_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_B_SHIFT_URIGHT, res, op);
}
jsp_operand_t
dump_prop_setter_or_bitwise_and_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_B_AND, res, op);
}
jsp_operand_t
dump_prop_setter_or_bitwise_xor_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_B_XOR, res, op);
}
jsp_operand_t
dump_prop_setter_or_bitwise_or_res (jsp_operand_t res, jsp_operand_t op)
{
return dump_prop_setter_or_triple_address_res (VM_OP_B_OR, res, op);
}
void
dumper_set_next_interation_target (void)
{
STACK_PUSH (next_iterations, serializer_get_current_instr_counter ());
}
void
dump_continue_iterations_check (jsp_operand_t op)
{
const vm_instr_counter_t next_iteration_target_diff = (vm_instr_counter_t) (serializer_get_current_instr_counter ()
- STACK_TOP (next_iterations));
vm_idx_t id1, id2;
split_instr_counter (next_iteration_target_diff, &id1, &id2);
if (operand_is_empty (op))
{
dump_double_address (VM_OP_JMP_UP,
jsp_operand_t::make_idx_const_operand (id1),
jsp_operand_t::make_idx_const_operand (id2));
}
else
{
dump_triple_address (VM_OP_IS_TRUE_JMP_UP,
op,
jsp_operand_t::make_idx_const_operand (id1),
jsp_operand_t::make_idx_const_operand (id2));
}
STACK_DROP (next_iterations, 1);
}
/**
* Dump template of 'jmp_break_continue' or 'jmp_down' instruction (depending on is_simple_jump argument).
*
* Note:
* the instruction's flags field is written later (see also: rewrite_simple_or_nested_jump_get_next).
*
* @return position of dumped instruction
*/
vm_instr_counter_t
dump_simple_or_nested_jump_for_rewrite (bool is_simple_jump, /**< flag indicating, whether simple jump
* or 'jmp_break_continue' template should be dumped */
vm_instr_counter_t next_jump_for_tgt_oc) /**< instr counter of next
* template targetted to
* the same target - if any,
* or MAX_OPCODES - otherwise */
{
vm_idx_t id1, id2;
split_instr_counter (next_jump_for_tgt_oc, &id1, &id2);
vm_instr_counter_t ret = serializer_get_current_instr_counter ();
if (is_simple_jump)
{
dump_double_address (VM_OP_JMP_DOWN,
jsp_operand_t::make_idx_const_operand (id1),
jsp_operand_t::make_idx_const_operand (id2));
}
else
{
dump_double_address (VM_OP_JMP_BREAK_CONTINUE,
jsp_operand_t::make_idx_const_operand (id1),
jsp_operand_t::make_idx_const_operand (id2));
}
return ret;
} /* dump_simple_or_nested_jump_for_rewrite */
/**
* Write jump target position into previously dumped template of jump (simple or nested) instruction
*
* @return instr counter value that was encoded in the jump before rewrite
*/
vm_instr_counter_t
rewrite_simple_or_nested_jump_and_get_next (vm_instr_counter_t jump_oc, /**< position of jump to rewrite */
vm_instr_counter_t target_oc) /**< the jump's target */
{
op_meta jump_op_meta = serializer_get_op_meta (jump_oc);
bool is_simple_jump = (jump_op_meta.op.op_idx == VM_OP_JMP_DOWN);
JERRY_ASSERT (is_simple_jump
|| (jump_op_meta.op.op_idx == VM_OP_JMP_BREAK_CONTINUE));
vm_idx_t id1, id2, id1_prev, id2_prev;
split_instr_counter ((vm_instr_counter_t) (target_oc - jump_oc), &id1, &id2);
if (is_simple_jump)
{
id1_prev = jump_op_meta.op.data.jmp_down.oc_idx_1;
id2_prev = jump_op_meta.op.data.jmp_down.oc_idx_2;
jump_op_meta.op.data.jmp_down.oc_idx_1 = id1;
jump_op_meta.op.data.jmp_down.oc_idx_2 = id2;
}
else
{
JERRY_ASSERT (jump_op_meta.op.op_idx == VM_OP_JMP_BREAK_CONTINUE);
id1_prev = jump_op_meta.op.data.jmp_break_continue.oc_idx_1;
id2_prev = jump_op_meta.op.data.jmp_break_continue.oc_idx_2;
jump_op_meta.op.data.jmp_break_continue.oc_idx_1 = id1;
jump_op_meta.op.data.jmp_break_continue.oc_idx_2 = id2;
}
serializer_rewrite_op_meta (jump_oc, jump_op_meta);
return vm_calc_instr_counter_from_idx_idx (id1_prev, id2_prev);
} /* rewrite_simple_or_nested_jump_get_next */
void
start_dumping_case_clauses (void)
{
STACK_PUSH (U8, (uint8_t) STACK_SIZE (case_clauses));
STACK_PUSH (U8, (uint8_t) STACK_SIZE (case_clauses));
}
void
dump_case_clause_check_for_rewrite (jsp_operand_t switch_expr, jsp_operand_t case_expr)
{
const jsp_operand_t res = tmp_operand ();
dump_triple_address (VM_OP_EQUAL_VALUE_TYPE, res, switch_expr, case_expr);
STACK_PUSH (case_clauses, serializer_get_current_instr_counter ());
dump_triple_address (VM_OP_IS_TRUE_JMP_DOWN,
res,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
}
void
dump_default_clause_check_for_rewrite (void)
{
STACK_PUSH (case_clauses, serializer_get_current_instr_counter ());
dump_double_address (VM_OP_JMP_DOWN,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
}
void
rewrite_case_clause (void)
{
const vm_instr_counter_t jmp_oc = STACK_ELEMENT (case_clauses, STACK_HEAD (U8, 2));
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (jmp_oc), &id1, &id2);
op_meta jmp_op_meta = serializer_get_op_meta (jmp_oc);
JERRY_ASSERT (jmp_op_meta.op.op_idx == VM_OP_IS_TRUE_JMP_DOWN);
jmp_op_meta.op.data.is_true_jmp_down.oc_idx_1 = id1;
jmp_op_meta.op.data.is_true_jmp_down.oc_idx_2 = id2;
serializer_rewrite_op_meta (jmp_oc, jmp_op_meta);
STACK_INCR_HEAD (U8, 2);
}
void
rewrite_default_clause (void)
{
const vm_instr_counter_t jmp_oc = STACK_TOP (case_clauses);
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (jmp_oc), &id1, &id2);
op_meta jmp_op_meta = serializer_get_op_meta (jmp_oc);
JERRY_ASSERT (jmp_op_meta.op.op_idx == VM_OP_JMP_DOWN);
jmp_op_meta.op.data.jmp_down.oc_idx_1 = id1;
jmp_op_meta.op.data.jmp_down.oc_idx_2 = id2;
serializer_rewrite_op_meta (jmp_oc, jmp_op_meta);
}
void
finish_dumping_case_clauses (void)
{
STACK_DROP (case_clauses, STACK_SIZE (case_clauses) - STACK_TOP (U8));
STACK_DROP (U8, 1);
STACK_DROP (U8, 1);
}
/**
* Dump template of 'with' instruction.
*
* Note:
* the instruction's flags field is written later (see also: rewrite_with).
*
* @return position of dumped instruction
*/
vm_instr_counter_t
dump_with_for_rewrite (jsp_operand_t op) /**< jsp_operand_t - result of evaluating Expression
* in WithStatement */
{
vm_instr_counter_t oc = serializer_get_current_instr_counter ();
dump_triple_address (VM_OP_WITH,
op,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
return oc;
} /* dump_with_for_rewrite */
/**
* Write position of 'with' block's end to specified 'with' instruction template,
* dumped earlier (see also: dump_with_for_rewrite).
*/
void
rewrite_with (vm_instr_counter_t oc) /**< instr counter of the instruction template */
{
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (oc), &id1, &id2);
op_meta with_op_meta = serializer_get_op_meta (oc);
with_op_meta.op.data.with.oc_idx_1 = id1;
with_op_meta.op.data.with.oc_idx_2 = id2;
serializer_rewrite_op_meta (oc, with_op_meta);
} /* rewrite_with */
/**
* Dump 'meta' instruction of 'end with' type
*/
void
dump_with_end (void)
{
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_END_WITH),
jsp_operand_t::make_empty_operand (),
jsp_operand_t::make_empty_operand ());
} /* dump_with_end */
/**
* Dump template of 'for_in' instruction.
*
* Note:
* the instruction's flags field is written later (see also: rewrite_for_in).
*
* @return position of dumped instruction
*/
vm_instr_counter_t
dump_for_in_for_rewrite (jsp_operand_t op) /**< jsp_operand_t - result of evaluating Expression
* in for-in statement */
{
vm_instr_counter_t oc = serializer_get_current_instr_counter ();
dump_triple_address (VM_OP_FOR_IN,
op,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
return oc;
} /* dump_for_in_for_rewrite */
/**
* Write position of 'for_in' block's end to specified 'for_in' instruction template,
* dumped earlier (see also: dump_for_in_for_rewrite).
*/
void
rewrite_for_in (vm_instr_counter_t oc) /**< instr counter of the instruction template */
{
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (oc), &id1, &id2);
op_meta for_in_op_meta = serializer_get_op_meta (oc);
for_in_op_meta.op.data.for_in.oc_idx_1 = id1;
for_in_op_meta.op.data.for_in.oc_idx_2 = id2;
serializer_rewrite_op_meta (oc, for_in_op_meta);
} /* rewrite_for_in */
/**
* Dump 'meta' instruction of 'end for_in' type
*/
void
dump_for_in_end (void)
{
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_END_FOR_IN),
jsp_operand_t::make_empty_operand (),
jsp_operand_t::make_empty_operand ());
} /* dump_for_in_end */
void
dump_try_for_rewrite (void)
{
STACK_PUSH (tries, serializer_get_current_instr_counter ());
dump_double_address (VM_OP_TRY_BLOCK,
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
}
void
rewrite_try (void)
{
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (STACK_TOP (tries)), &id1, &id2);
op_meta try_op_meta = serializer_get_op_meta (STACK_TOP (tries));
JERRY_ASSERT (try_op_meta.op.op_idx == VM_OP_TRY_BLOCK);
try_op_meta.op.data.try_block.oc_idx_1 = id1;
try_op_meta.op.data.try_block.oc_idx_2 = id2;
serializer_rewrite_op_meta (STACK_TOP (tries), try_op_meta);
STACK_DROP (tries, 1);
}
void
dump_catch_for_rewrite (jsp_operand_t op)
{
JERRY_ASSERT (op.is_literal_operand ());
STACK_PUSH (catches, serializer_get_current_instr_counter ());
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_CATCH),
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER),
op,
jsp_operand_t::make_empty_operand ());
}
void
rewrite_catch (void)
{
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (STACK_TOP (catches)), &id1, &id2);
op_meta catch_op_meta = serializer_get_op_meta (STACK_TOP (catches));
JERRY_ASSERT (catch_op_meta.op.op_idx == VM_OP_META
&& catch_op_meta.op.data.meta.type == OPCODE_META_TYPE_CATCH);
catch_op_meta.op.data.meta.data_1 = id1;
catch_op_meta.op.data.meta.data_2 = id2;
serializer_rewrite_op_meta (STACK_TOP (catches), catch_op_meta);
STACK_DROP (catches, 1);
}
void
dump_finally_for_rewrite (void)
{
STACK_PUSH (finallies, serializer_get_current_instr_counter ());
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_FINALLY),
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
}
void
rewrite_finally (void)
{
vm_idx_t id1, id2;
split_instr_counter (get_diff_from (STACK_TOP (finallies)), &id1, &id2);
op_meta finally_op_meta = serializer_get_op_meta (STACK_TOP (finallies));
JERRY_ASSERT (finally_op_meta.op.op_idx == VM_OP_META
&& finally_op_meta.op.data.meta.type == OPCODE_META_TYPE_FINALLY);
finally_op_meta.op.data.meta.data_1 = id1;
finally_op_meta.op.data.meta.data_2 = id2;
serializer_rewrite_op_meta (STACK_TOP (finallies), finally_op_meta);
STACK_DROP (finallies, 1);
}
void
dump_end_try_catch_finally (void)
{
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_END_TRY_CATCH_FINALLY),
jsp_operand_t::make_empty_operand (),
jsp_operand_t::make_empty_operand ());
}
void
dump_throw (jsp_operand_t op)
{
dump_single_address (VM_OP_THROW_VALUE, op);
}
/**
* Checks if variable is already declared
*
* @return true if variable declaration already exists
* false otherwise
*/
bool
dumper_variable_declaration_exists (lit_cpointer_t lit_id) /**< literal which holds variable's name */
{
vm_instr_counter_t var_decls_count = (vm_instr_counter_t) serializer_get_current_var_decls_counter ();
for (vm_instr_counter_t oc = (vm_instr_counter_t) (0); oc < var_decls_count; oc++)
{
const op_meta var_decl_op_meta = serializer_get_var_decl (oc);
if (var_decl_op_meta.lit_id[0].packed_value == lit_id.packed_value)
{
return true;
}
}
return false;
} /* dumper_variable_declaration_exists */
/**
* Dump instruction designating variable declaration
*/
void
dump_variable_declaration (lit_cpointer_t lit_id) /**< literal which holds variable's name */
{
jsp_operand_t op_var_name = jsp_operand_t::make_lit_operand (lit_id);
serializer_dump_var_decl (jsp_dmp_create_op_meta (VM_OP_VAR_DECL, &op_var_name, 1));
} /* dump_variable_declaration */
/**
* Dump template of 'meta' instruction for scope's code flags.
*
* Note:
* the instruction's flags field is written later (see also: rewrite_scope_code_flags).
*
* @return position of dumped instruction
*/
vm_instr_counter_t
dump_scope_code_flags_for_rewrite (void)
{
vm_instr_counter_t oc = serializer_get_current_instr_counter ();
dump_triple_address (VM_OP_META,
jsp_operand_t::make_idx_const_operand (OPCODE_META_TYPE_SCOPE_CODE_FLAGS),
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_empty_operand ());
return oc;
} /* dump_scope_code_flags_for_rewrite */
/**
* Write scope's code flags to specified 'meta' instruction template,
* dumped earlier (see also: dump_scope_code_flags_for_rewrite).
*/
void
rewrite_scope_code_flags (vm_instr_counter_t scope_code_flags_oc, /**< position of instruction to rewrite */
opcode_scope_code_flags_t scope_flags) /**< scope's code properties flags set */
{
JERRY_ASSERT ((vm_idx_t) scope_flags == scope_flags);
op_meta opm = serializer_get_op_meta (scope_code_flags_oc);
JERRY_ASSERT (opm.op.op_idx == VM_OP_META);
JERRY_ASSERT (opm.op.data.meta.type == OPCODE_META_TYPE_SCOPE_CODE_FLAGS);
JERRY_ASSERT (opm.op.data.meta.data_1 == VM_IDX_REWRITE_GENERAL_CASE);
JERRY_ASSERT (opm.op.data.meta.data_2 == VM_IDX_EMPTY);
opm.op.data.meta.data_1 = (vm_idx_t) scope_flags;
serializer_rewrite_op_meta (scope_code_flags_oc, opm);
} /* rewrite_scope_code_flags */
void
dump_ret (void)
{
serializer_dump_op_meta (jsp_dmp_create_op_meta_0 (VM_OP_RET));
}
void
dump_reg_var_decl_for_rewrite (void)
{
STACK_PUSH (reg_var_decls, serializer_get_current_instr_counter ());
dump_triple_address (VM_OP_REG_VAR_DECL,
jsp_operand_t::make_idx_const_operand (VM_REG_FIRST),
jsp_operand_t::make_unknown_operand (),
jsp_operand_t::make_unknown_operand ());
}
void
rewrite_reg_var_decl (void)
{
vm_instr_counter_t reg_var_decl_oc = STACK_TOP (reg_var_decls);
op_meta opm = serializer_get_op_meta (reg_var_decl_oc);
JERRY_ASSERT (opm.op.op_idx == VM_OP_REG_VAR_DECL);
if (jsp_reg_max_for_local_var != VM_IDX_EMPTY)
{
JERRY_ASSERT (jsp_reg_max_for_local_var >= jsp_reg_max_for_temps);
opm.op.data.reg_var_decl.local_var_regs_num = (vm_idx_t) (jsp_reg_max_for_local_var - jsp_reg_max_for_temps);
opm.op.data.reg_var_decl.max = jsp_reg_max_for_local_var;
jsp_reg_max_for_local_var = VM_IDX_EMPTY;
}
else
{
opm.op.data.reg_var_decl.max = jsp_reg_max_for_temps;
opm.op.data.reg_var_decl.local_var_regs_num = 0;
}
serializer_rewrite_op_meta (reg_var_decl_oc, opm);
STACK_DROP (reg_var_decls, 1);
}
void
dump_retval (jsp_operand_t op)
{
dump_single_address (VM_OP_RETVAL, op);
}
void
dumper_init (void)
{
jsp_reg_next = VM_REG_GENERAL_FIRST;
jsp_reg_max_for_temps = VM_REG_GENERAL_FIRST;
jsp_reg_max_for_local_var = VM_IDX_EMPTY;
STACK_INIT (U8);
STACK_INIT (varg_headers);
STACK_INIT (function_ends);
STACK_INIT (logical_and_checks);
STACK_INIT (logical_or_checks);
STACK_INIT (conditional_checks);
STACK_INIT (jumps_to_end);
STACK_INIT (prop_getters);
STACK_INIT (next_iterations);
STACK_INIT (case_clauses);
STACK_INIT (catches);
STACK_INIT (finallies);
STACK_INIT (tries);
STACK_INIT (jsp_reg_id_stack);
STACK_INIT (reg_var_decls);
}
void
dumper_free (void)
{
STACK_FREE (U8);
STACK_FREE (varg_headers);
STACK_FREE (function_ends);
STACK_FREE (logical_and_checks);
STACK_FREE (logical_or_checks);
STACK_FREE (conditional_checks);
STACK_FREE (jumps_to_end);
STACK_FREE (prop_getters);
STACK_FREE (next_iterations);
STACK_FREE (case_clauses);
STACK_FREE (catches);
STACK_FREE (finallies);
STACK_FREE (tries);
STACK_FREE (jsp_reg_id_stack);
STACK_FREE (reg_var_decls);
}