Files
jerryscript/src/libcoreint/opcodes.h
T
Ilmir Usmanov dc8ab27900 Split parser into parser itself, opcodes dumper and syntax errors checker.
Add internal hash map of literal indexes:
  In this hash map key is pair of block number and literal's unique identifier in the block, and the value is a literal index that unique in the whole program.
  Block is a continues array of opcodes. So, bytecode is splitted into blocks.
  Each block has its own uid counter. To get literal index the interpreter looks up it in the hash map.
  Thus, now JS program is able to have more than 255 identifiers/string literals.
  The first 128 (0-127) uids are reserved for block's uid counter, the other 128 (128-255) are reserved for tmp variables.
2014-12-10 18:31:59 +03:00

282 lines
12 KiB
C

/* Copyright 2014 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OPCODES_H
#define OPCODES_H
#include "ecma-globals.h"
#include "globals.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)
typedef uint16_t opcode_counter_t; /** opcode counters */
typedef uint8_t idx_t; /** index values */
/**
* 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 variable name */
} opcode_arg_type_operand;
/**
* Types of data in 'meta' opcode.
*/
typedef enum
{
OPCODE_META_TYPE_UNDEFINED, /**< undefined meta (should be rewritten) */
OPCODE_META_TYPE_THIS_ARG, /**< value (var_idx) of this used during call */
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_STRICT_CODE /**< mark of beginning of strict code */
} opcode_meta_type;
typedef struct
{
opcode_counter_t pos; /**< current opcode to execute */
ecma_value_t this_binding; /**< this binding for current context */
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 */
idx_t min_reg_num; /**< minimum idx used for register identification */
idx_t max_reg_num; /**< maximum idx used for register identification */
ecma_value_t *regs_p; /**< register variables */
ecma_number_t* tmp_num_p; /**< an allocated number (to reduce temporary allocations) */
#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 */
} int_data_t;
opcode_counter_t calc_opcode_counter_from_idx_idx (const idx_t oc_idx_1, const idx_t oc_idx_2);
opcode_counter_t read_meta_opcode_counter (opcode_meta_type expected_type, int_data_t *int_data);
#define OP_CALLS_AND_ARGS(p, a) \
p##_3 (a, call_n, lhs, name_lit_idx, arg_list) \
p##_3 (a, native_call, lhs, name, arg_list) \
p##_3 (a, construct_n, lhs, name_lit_idx, arg_list) \
p##_2 (a, func_decl_n, name_lit_idx, arg_list) \
p##_3 (a, func_expr_n, lhs, name_lit_idx, arg_list) \
p##_1 (a, exitval, status_code) \
p##_1 (a, retval, ret_value) \
p##_0 (a, ret)
#define OP_INITS(p, a) \
p##_2 (a, array_decl, lhs, list) \
p##_3 (a, prop_getter, lhs, obj, prop) \
p##_3 (a, prop_setter, obj, prop, rhs) \
p##_2 (a, obj_decl, lhs, list) \
p##_1 (a, this, lhs) \
p##_2 (a, delete_var, lhs, name) \
p##_3 (a, delete_prop, lhs, base, name) \
p##_2 (a, typeof, lhs, obj) \
p##_1 (a, with, expr) \
p##_2 (a, try, oc_idx_1, oc_idx_2) \
p##_1 (a, throw, var)
#define OP_ASSIGNMENTS(p, a) \
p##_3 (a, assignment, var_left, type_value_right, value_right)
#define OP_B_SHIFTS(p, a) \
p##_3 (a, b_shift_left, dst, var_left, var_right) \
p##_3 (a, b_shift_right, dst, var_left, var_right) \
p##_3 (a, b_shift_uright, dst, var_left, var_right)
#define OP_B_BITWISE(p, a) \
p##_3 (a, b_and, dst, var_left, var_right) \
p##_3 (a, b_or, dst, var_left, var_right) \
p##_3 (a, b_xor, dst, var_left, var_right) \
p##_2 (a, b_not, dst, var_right)
#define OP_B_LOGICAL(p, a) \
p##_2 (a, logical_not, dst, var_right)
#define OP_EQUALITY(p, a) \
p##_3 (a, equal_value, dst, var_left, var_right) \
p##_3 (a, not_equal_value, dst, var_left, var_right) \
p##_3 (a, equal_value_type, dst, var_left, var_right) \
p##_3 (a, not_equal_value_type, dst, var_left, var_right)
#define OP_RELATIONAL(p, a) \
p##_3 (a, less_than, dst, var_left, var_right) \
p##_3 (a, greater_than, dst, var_left, var_right) \
p##_3 (a, less_or_equal_than, dst, var_left, var_right) \
p##_3 (a, greater_or_equal_than, dst, var_left, var_right) \
p##_3 (a, instanceof, dst, var_left, var_right) \
p##_3 (a, in, dst, var_left, var_right)
#define OP_ARITHMETIC(p, a) \
p##_2 (a, post_incr, dst, var_right) \
p##_2 (a, post_decr, dst, var_right) \
p##_2 (a, pre_incr, dst, var_right) \
p##_2 (a, pre_decr, dst, var_right) \
p##_3 (a, addition, dst, var_left, var_right) \
p##_3 (a, substraction, dst, var_left, var_right) \
p##_3 (a, division, dst, var_left, var_right) \
p##_3 (a, multiplication, dst, var_left, var_right) \
p##_3 (a, remainder, dst, var_left, var_right) \
p##_2 (a, unary_minus, dst, var) \
p##_2 (a, unary_plus, dst, var)
#define OP_JUMPS(p, a) \
p##_2 (a, jmp_up, opcode_1, opcode_2) \
p##_2 (a, jmp_down, opcode_1, opcode_2) \
p##_0 (a, nop) \
p##_3 (a, is_true_jmp_up, value, opcode_1, opcode_2) \
p##_3 (a, is_true_jmp_down, value, opcode_1, opcode_2) \
p##_3 (a, is_false_jmp_up, value, opcode_1, opcode_2) \
p##_3 (a, is_false_jmp_down, value, opcode_1, opcode_2)
#define OP_LIST_FULL(p, a) \
OP_CALLS_AND_ARGS (p, a) \
OP_INITS (p, a) \
OP_ASSIGNMENTS (p, a) \
OP_B_LOGICAL (p, a) \
OP_B_BITWISE (p, a) \
OP_B_SHIFTS (p, a) \
OP_EQUALITY (p, a) \
OP_RELATIONAL (p, a) \
OP_ARITHMETIC (p, a) \
OP_JUMPS (p, a) \
p##_1 (a, var_decl, variable_name) \
p##_2 (a, reg_var_decl, min, max) \
p##_3 (a, meta, type, data_1, data_2)
#define OP_LIST(a) OP_LIST_FULL (OP, a)
#define OP_ARGS_LIST(a) OP_LIST_FULL (a, void)
#define OP_DATA_0(action, name) \
typedef struct \
{ \
idx_t __do_not_use; \
} __op_##name;
#define OP_DATA_1(action, name, arg1) \
typedef struct \
{ \
idx_t arg1; \
} __op_##name;
#define OP_DATA_2(action, name, arg1, arg2) \
typedef struct \
{ \
idx_t arg1; \
idx_t arg2; \
} __op_##name;
#define OP_DATA_3(action, name, arg1, arg2, arg3) \
typedef struct \
{ \
idx_t arg1; \
idx_t arg2; \
idx_t arg3; \
} __op_##name;
OP_ARGS_LIST (OP_DATA)
#define __OP_STRUCT_FIELD(name, arg1, arg2, arg3) __op_##name name;
typedef struct
{
idx_t op_idx;
union
{
OP_LIST (OP_STRUCT_FIELD)
} data;
} opcode_t;
#undef __OP_STRUCT_FIELD
#define __OP_ENUM_FIELD(name, arg1, arg2, arg3) __op__idx_##name ,
enum __opcode_idx
{
OP_LIST (OP_ENUM_FIELD)
LAST_OP
};
#undef __OP_ENUM_FIELD
#define __OP_FUNC_DECL(name, arg1, arg2, arg3) ecma_completion_value_t opfunc_##name (opcode_t, int_data_t*);
OP_LIST (OP_FUNC_DECL)
#undef __OP_FUNC_DECL
typedef ecma_completion_value_t (*opfunc) (opcode_t, int_data_t *);
#define GETOP_DECL_0(a, name) \
opcode_t getop_##name (void);
#define GETOP_DECL_1(a, name, arg1) \
opcode_t getop_##name (idx_t);
#define GETOP_DECL_2(a, name, arg1, arg2) \
opcode_t getop_##name (idx_t, idx_t);
#define GETOP_DECL_3(a, name, arg1, arg2, arg3) \
opcode_t getop_##name (idx_t, idx_t, idx_t);
#define GETOP_DEF_0(a, name) \
opcode_t getop_##name (void) \
{ \
opcode_t opdata; \
opdata.op_idx = __op__idx_##name; \
return opdata; \
}
OP_ARGS_LIST (GETOP_DECL)
#undef GETOP_DECL_0
#undef GETOP_DECL_1
#undef GETOP_DECL_2
#undef GETOP_DECL_3
typedef struct
{
uint8_t uids[4];
}
raw_opcode;
#endif /* OPCODES_H */