Parser optimizations.

- parser is now non-recursive (i.e. parse function is not called recursively in any case);
 - byte-code is now more compact:
    - constants are now not immediately dumped upon occurence, but later - where necessary;
    - assignments are combined with unary / binary operations;
    - binary operations are encoded more compactly in many cases;
 - byte-code arrays are now allocated separately for each scope (so, GC of the scopes now becomes possible);
 - byte-code is dumped directly into corresponding byte-code arrays:
   - linked lists of op_meta are not now used for main code of a scope.

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
JerryScript-DCO-1.0-Signed-off-by: Andrey Shitov a.shitov@samsung.com
This commit is contained in:
Andrey Shitov
2015-11-03 19:14:19 +03:00
committed by Ruben Ayrapetyan
parent b1de93abd6
commit 50d124bfc3
51 changed files with 9044 additions and 7401 deletions
+188 -173
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include "bytecode-data.h"
#include "jrt.h"
#include "opcodes.h"
#include "opcodes-ecma-support.h"
@@ -77,9 +78,9 @@ opfunc_assignment (vm_instr_t instr, /**< instruction */
}
else if (type_value_right == OPCODE_ARG_TYPE_STRING)
{
lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (src_val_descr,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (src_val_descr,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
ecma_string_t *string_p = ecma_new_ecma_string_from_lit_cp (lit_cp);
ret_value = set_variable_value (frame_ctx_p,
@@ -108,9 +109,9 @@ opfunc_assignment (vm_instr_t instr, /**< instruction */
{
ecma_number_t *num_p = frame_ctx_p->tmp_num_p;
lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (src_val_descr,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (src_val_descr,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
literal_t lit = lit_get_literal_by_cp (lit_cp);
JERRY_ASSERT (lit->get_type () == LIT_NUMBER_T);
@@ -125,9 +126,9 @@ opfunc_assignment (vm_instr_t instr, /**< instruction */
{
ecma_number_t *num_p = frame_ctx_p->tmp_num_p;
lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (src_val_descr,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (src_val_descr,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
literal_t lit = lit_get_literal_by_cp (lit_cp);
JERRY_ASSERT (lit->get_type () == LIT_NUMBER_T);
@@ -152,7 +153,7 @@ opfunc_assignment (vm_instr_t instr, /**< instruction */
else if (type_value_right == OPCODE_ARG_TYPE_REGEXP)
{
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (src_val_descr,
lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (src_val_descr,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
ecma_string_t *string_p = ecma_new_ecma_string_from_lit_cp (lit_cp);
@@ -440,40 +441,10 @@ opfunc_reg_var_decl (vm_instr_t instr __attr_unused___, /**< instruction */
* However, ecma_free_completion_value may be called for it, but it is a no-op.
*/
ecma_completion_value_t
opfunc_var_decl (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_var_decl (vm_instr_t instr __attr_unused___, /**< instruction */
vm_frame_ctx_t *frame_ctx_p __attr_unused___) /**< interpreter context */
{
lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (instr.data.var_decl.variable_name,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL);
ecma_string_t *var_name_string_p = ecma_new_ecma_string_from_lit_cp (lit_cp);
if (!ecma_op_has_binding (frame_ctx_p->lex_env_p, var_name_string_p))
{
const bool is_configurable_bindings = frame_ctx_p->is_eval_code;
ecma_completion_value_t completion = ecma_op_create_mutable_binding (frame_ctx_p->lex_env_p,
var_name_string_p,
is_configurable_bindings);
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
/* Skipping SetMutableBinding as we have already checked that there were not
* any binding with specified name in current lexical environment
* and CreateMutableBinding sets the created binding's value to undefined */
JERRY_ASSERT (ecma_is_completion_value_normal_simple_value (ecma_op_get_binding_value (frame_ctx_p->lex_env_p,
var_name_string_p,
true),
ECMA_SIMPLE_VALUE_UNDEFINED));
}
ecma_deref_ecma_string (var_name_string_p);
frame_ctx_p->pos++;
return ecma_make_empty_completion_value ();
JERRY_UNREACHABLE ();
} /* opfunc_var_decl */
/**
@@ -482,74 +453,156 @@ opfunc_var_decl (vm_instr_t instr, /**< instruction */
* @return completion value
* returned value must be freed with ecma_free_completion_value.
*/
static ecma_completion_value_t
function_declaration (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
lit_cpointer_t function_name_lit_cp, /**< compressed pointer to literal with function name */
ecma_collection_header_t *formal_params_collection_p) /** formal parameters collection */
ecma_completion_value_t
vm_function_declaration (const bytecode_data_header_t *bytecode_header_p, /**< byte-code header */
bool is_strict, /**< is function declared in strict mode code? */
bool is_eval_code, /**< is function declared in eval code? */
ecma_object_t *lex_env_p) /**< lexical environment to use */
{
const bool is_configurable_bindings = frame_ctx_p->is_eval_code;
vm_instr_t *function_instrs_p = bytecode_header_p->instrs_p;
const vm_instr_counter_t function_code_end_oc = (vm_instr_counter_t) (
vm_read_instr_counter_from_meta (OPCODE_META_TYPE_FUNCTION_END, frame_ctx_p) + frame_ctx_p->pos);
frame_ctx_p->pos++;
vm_instr_counter_t instr_pos = 0;
ecma_string_t *function_name_string_p = ecma_new_ecma_string_from_lit_cp (function_name_lit_cp);
vm_instr_t func_header_instr = function_instrs_p[instr_pos];
ecma_completion_value_t ret_value = ecma_op_function_declaration (frame_ctx_p->lex_env_p,
function_name_string_p,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos,
formal_params_collection_p,
frame_ctx_p->is_strict,
is_configurable_bindings);
ecma_deref_ecma_string (function_name_string_p);
bool is_func_decl;
vm_idx_t function_name_idx;
ecma_length_t params_number;
frame_ctx_p->pos = function_code_end_oc;
if (func_header_instr.op_idx == VM_OP_FUNC_DECL_N)
{
is_func_decl = true;
function_name_idx = func_header_instr.data.func_decl_n.name_lit_idx;
params_number = func_header_instr.data.func_decl_n.arg_list;
}
else
{
is_func_decl = false;
function_name_idx = func_header_instr.data.func_expr_n.name_lit_idx;
params_number = func_header_instr.data.func_expr_n.arg_list;
}
lit_cpointer_t function_name_lit_cp = NOT_A_LITERAL;
if (function_name_idx != VM_IDX_EMPTY)
{
function_name_lit_cp = bc_get_literal_cp_by_uid (function_name_idx,
bytecode_header_p,
instr_pos);
}
else
{
JERRY_ASSERT (!is_func_decl);
}
instr_pos++;
ecma_completion_value_t ret_value;
ecma_collection_header_t *formal_params_collection_p = NULL;
if (bytecode_header_p->is_args_moved_to_regs)
{
instr_pos = (vm_instr_counter_t) (instr_pos + params_number);
}
else if (params_number != 0)
{
formal_params_collection_p = ecma_new_strings_collection (NULL, 0);
instr_pos = vm_fill_params_list (bytecode_header_p,
instr_pos,
params_number,
formal_params_collection_p);
}
if (is_func_decl)
{
const bool is_configurable_bindings = is_eval_code;
ecma_string_t *function_name_string_p = ecma_new_ecma_string_from_lit_cp (function_name_lit_cp);
ret_value = ecma_op_function_declaration (lex_env_p,
function_name_string_p,
bytecode_header_p,
instr_pos,
formal_params_collection_p,
is_strict,
is_configurable_bindings);
ecma_deref_ecma_string (function_name_string_p);
}
else
{
ecma_object_t *scope_p;
ecma_string_t *function_name_string_p = NULL;
bool is_named_func_expr = (function_name_idx != VM_IDX_EMPTY);
if (is_named_func_expr)
{
scope_p = ecma_create_decl_lex_env (lex_env_p);
JERRY_ASSERT (function_name_lit_cp.packed_value != MEM_CP_NULL);
function_name_string_p = ecma_new_ecma_string_from_lit_cp (function_name_lit_cp);
ecma_op_create_immutable_binding (scope_p, function_name_string_p);
}
else
{
scope_p = lex_env_p;
ecma_ref_object (scope_p);
}
ecma_object_t *func_obj_p = ecma_op_create_function_object (formal_params_collection_p,
scope_p,
is_strict,
bytecode_header_p,
instr_pos);
ret_value = ecma_make_normal_completion_value (ecma_make_object_value (func_obj_p));
if (is_named_func_expr)
{
ecma_op_initialize_immutable_binding (scope_p,
function_name_string_p,
ecma_make_object_value (func_obj_p));
ecma_deref_ecma_string (function_name_string_p);
}
ecma_deref_object (scope_p);
}
return ret_value;
} /* function_declaration */
} /* vm_function_declaration */
/**
* 'Function declaration' opcode handler.
* 'Function declaration header' opcode handler.
*
* @return completion value
* returned value must be freed with ecma_free_completion_value.
*/
ecma_completion_value_t
opfunc_func_decl_n (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_func_decl_n (vm_instr_t instr __attr_unused___, /**< instruction */
vm_frame_ctx_t *frame_ctx_p __attr_unused___) /**< interpreter context */
{
const vm_idx_t function_name_idx = instr.data.func_decl_n.name_lit_idx;
const ecma_length_t params_number = instr.data.func_decl_n.arg_list;
lit_cpointer_t function_name_lit_cp = serializer_get_literal_cp_by_uid (function_name_idx,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
frame_ctx_p->pos++;
ecma_completion_value_t ret_value;
ecma_collection_header_t *formal_params_collection_p;
if (params_number != 0)
{
formal_params_collection_p = ecma_new_strings_collection (NULL, 0);
vm_fill_params_list (frame_ctx_p, params_number, formal_params_collection_p);
}
else
{
formal_params_collection_p = NULL;
}
ret_value = function_declaration (frame_ctx_p,
function_name_lit_cp,
formal_params_collection_p);
return ret_value;
JERRY_UNREACHABLE ();
} /* opfunc_func_decl_n */
/**
* 'Function expression header' opcode handler.
*
* @return completion value
* returned value must be freed with ecma_free_completion_value.
*/
ecma_completion_value_t
opfunc_func_expr_n (vm_instr_t instr __attr_unused___, /**< instruction */
vm_frame_ctx_t *frame_ctx_p __attr_unused___) /**< interpreter context */
{
JERRY_UNREACHABLE ();
} /* opfunc_func_expr_n */
/**
* 'Function expression' opcode handler.
*
@@ -557,84 +610,46 @@ opfunc_func_decl_n (vm_instr_t instr, /**< instruction */
* returned value must be freed with ecma_free_completion_value.
*/
ecma_completion_value_t
opfunc_func_expr_n (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_func_expr_ref (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_instr_counter_t lit_oc = frame_ctx_p->pos;
frame_ctx_p->pos++;
const vm_idx_t dst_var_idx = instr.data.func_expr_n.lhs;
const vm_idx_t function_name_lit_idx = instr.data.func_expr_n.name_lit_idx;
const ecma_length_t params_number = instr.data.func_expr_n.arg_list;
const bool is_named_func_expr = (function_name_lit_idx != VM_IDX_EMPTY);
const vm_idx_t dst_var_idx = instr.data.func_expr_ref.lhs;
const vm_idx_t idx1 = instr.data.func_expr_ref.idx1;
const vm_idx_t idx2 = instr.data.func_expr_ref.idx2;
uint16_t index = (uint16_t) jrt_set_bit_field_value (jrt_set_bit_field_value (0, idx1, 0, JERRY_BITSINBYTE),
idx2, JERRY_BITSINBYTE, JERRY_BITSINBYTE);
const bytecode_data_header_t *header_p = frame_ctx_p->bytecode_header_p;
mem_cpointer_t *declarations_p = MEM_CP_GET_POINTER (mem_cpointer_t, header_p->declarations_cp);
JERRY_ASSERT (index < header_p->func_scopes_count);
const bytecode_data_header_t *func_expr_bc_header_p = MEM_CP_GET_NON_NULL_POINTER (const bytecode_data_header_t,
declarations_p[index]);
JERRY_ASSERT (func_expr_bc_header_p->instrs_p[0].op_idx == VM_OP_FUNC_EXPR_N);
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
vm_instr_counter_t function_code_end_oc;
ECMA_TRY_CATCH (func_obj_value,
vm_function_declaration (func_expr_bc_header_p,
frame_ctx_p->is_strict,
frame_ctx_p->is_eval_code,
frame_ctx_p->lex_env_p),
ret_value);
ecma_collection_header_t *formal_params_collection_p;
JERRY_ASSERT (ecma_is_constructor (func_obj_value));
if (params_number != 0)
{
formal_params_collection_p = ecma_new_strings_collection (NULL, 0);
ret_value = set_variable_value (frame_ctx_p, lit_oc, dst_var_idx, func_obj_value);
vm_fill_params_list (frame_ctx_p, params_number, formal_params_collection_p);
}
else
{
formal_params_collection_p = NULL;
}
function_code_end_oc = (vm_instr_counter_t) (vm_read_instr_counter_from_meta (OPCODE_META_TYPE_FUNCTION_END,
frame_ctx_p) + frame_ctx_p->pos);
frame_ctx_p->pos++;
ecma_object_t *scope_p;
ecma_string_t *function_name_string_p = NULL;
if (is_named_func_expr)
{
scope_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p);
lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (function_name_lit_idx,
frame_ctx_p->bytecode_header_p,
lit_oc);
JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL);
function_name_string_p = ecma_new_ecma_string_from_lit_cp (lit_cp);
ecma_op_create_immutable_binding (scope_p, function_name_string_p);
}
else
{
scope_p = frame_ctx_p->lex_env_p;
ecma_ref_object (scope_p);
}
ecma_object_t *func_obj_p = ecma_op_create_function_object (formal_params_collection_p,
scope_p,
frame_ctx_p->is_strict,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
ret_value = set_variable_value (frame_ctx_p, lit_oc,
dst_var_idx,
ecma_make_object_value (func_obj_p));
if (is_named_func_expr)
{
ecma_op_initialize_immutable_binding (scope_p,
function_name_string_p,
ecma_make_object_value (func_obj_p));
ecma_deref_ecma_string (function_name_string_p);
}
ecma_deref_object (func_obj_p);
ecma_deref_object (scope_p);
frame_ctx_p->pos = function_code_end_oc;
ECMA_FINALIZE (func_obj_value);
return ret_value;
} /* opfunc_func_expr_n */
} /* opfunc_func_expr_ref */
/**
* Get 'this' argument value and call flags mask for function call
@@ -718,9 +733,9 @@ vm_helper_call_get_call_flags_and_this_arg (vm_frame_ctx_t *int_data_p, /**< int
/* 6.b.i */
ecma_string_t var_name_string;
lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (var_idx,
int_data_p->bytecode_header_p,
var_idx_lit_oc);
lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (var_idx,
int_data_p->bytecode_header_p,
var_idx_lit_oc);
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 (int_data_p->lex_env_p,
@@ -1038,9 +1053,9 @@ opfunc_obj_decl (vm_instr_t instr, /**< instruction */
false),
ret_value);
lit_cpointer_t prop_name_lit_cp = serializer_get_literal_cp_by_uid (prop_name_idx,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
lit_cpointer_t prop_name_lit_cp = bc_get_literal_cp_by_uid (prop_name_idx,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
JERRY_ASSERT (prop_name_lit_cp.packed_value != MEM_CP_NULL);
ecma_string_t *prop_name_string_p = ecma_new_ecma_string_from_lit_cp (prop_name_lit_cp);
@@ -1453,9 +1468,9 @@ evaluate_arg_for_typeof (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context *
}
else
{
lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (var_idx,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
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_string_t *var_name_string_p = ecma_new_ecma_string_from_lit_cp (lit_cp);
@@ -1571,7 +1586,7 @@ opfunc_delete_var (vm_instr_t instr, /**< instruction */
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (name_lit_idx, frame_ctx_p->bytecode_header_p, lit_oc);
lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (name_lit_idx, frame_ctx_p->bytecode_header_p, lit_oc);
JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL);
ecma_string_t *name_string_p = ecma_new_ecma_string_from_lit_cp (lit_cp);
@@ -1718,7 +1733,6 @@ opfunc_meta (vm_instr_t instr, /**< instruction */
return ecma_make_meta_completion_value ();
}
case OPCODE_META_TYPE_SCOPE_CODE_FLAGS:
case OPCODE_META_TYPE_UNDEFINED:
case OPCODE_META_TYPE_CALL_SITE_INFO:
case OPCODE_META_TYPE_FUNCTION_END:
@@ -1750,14 +1764,15 @@ vm_calc_instr_counter_from_idx_idx (const vm_idx_t oc_idx_1, /**< first idx */
} /* vm_calc_instr_counter_from_idx_idx */
/**
* Read instruction counter from current instruction,
* Read instruction counter from specified instruction,
* that should be 'meta' instruction of specified type.
*/
vm_instr_counter_t
vm_read_instr_counter_from_meta (opcode_meta_type expected_type, /**< expected type of meta instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
const bytecode_data_header_t *bytecode_header_p, /**< byte-code header */
vm_instr_counter_t instr_pos) /**< position of the instruction */
{
vm_instr_t meta_opcode = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos);
vm_instr_t meta_opcode = vm_get_instr (bytecode_header_p->instrs_p, instr_pos);
JERRY_ASSERT (meta_opcode.data.meta.type == expected_type);
const vm_idx_t data_1 = meta_opcode.data.meta.data_1;