mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Replacing 'this_arg' meta opcode with more general 'call site additional information' meta opcode with flags describing the call site features, and, optionally, 'this' argument.
Introducing opcode_call_flags_t for argument of the new meta opcode, currently with two flags: 'have this argument' and '"direct call to eval" form'. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
This commit is contained in:
parent
6fadcd3f84
commit
446e8bf989
@ -764,6 +764,27 @@ dump_intrinsic (operand obj, operand arg)
|
||||
return dump_undefined_assignment_res ();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ECMA_MAGIC_STRING_EVAL string,
|
||||
* false - otherwise.
|
||||
*/
|
||||
bool
|
||||
dumper_is_eval_literal (operand obj) /**< byte-code operand */
|
||||
{
|
||||
/*
|
||||
* FIXME: Switch to corresponding magic string
|
||||
*/
|
||||
const ecma_char_t *eval_string_p = (const ecma_char_t *) "eval";
|
||||
bool is_eval_lit = (obj.type == OPERAND_LITERAL
|
||||
&& lit_literal_equal_type_zt (lit_get_literal_by_cp (obj.data.lit_id),
|
||||
eval_string_p));
|
||||
|
||||
return is_eval_lit;
|
||||
} /* dumper_is_eval_literal */
|
||||
|
||||
void
|
||||
dump_boolean_assignment (operand op, bool is_true)
|
||||
{
|
||||
@ -1077,14 +1098,30 @@ rewrite_varg_header_set_args_count (uint8_t args_count)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump 'meta' instruction of 'call additional information' type,
|
||||
* containing call flags and, optionally, 'this' argument
|
||||
*/
|
||||
void
|
||||
dump_this_arg (operand this_arg)
|
||||
dump_call_additional_info (opcode_call_flags_t flags, /**< call flags */
|
||||
operand this_arg) /**< 'this' argument - if flags include OPCODE_CALL_FLAGS_HAVE_THIS_ARG,
|
||||
* or empty operand - otherwise */
|
||||
{
|
||||
JERRY_ASSERT (this_arg.type == OPERAND_TMP);
|
||||
const opcode_t opcode = getop_meta (OPCODE_META_TYPE_THIS_ARG, this_arg.data.uid, INVALID_VALUE);
|
||||
if (flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
|
||||
{
|
||||
JERRY_ASSERT (this_arg.type == OPERAND_TMP);
|
||||
JERRY_ASSERT (!operand_is_empty (this_arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (operand_is_empty (this_arg));
|
||||
}
|
||||
|
||||
const opcode_t opcode = getop_meta (OPCODE_META_TYPE_CALL_SITE_INFO,
|
||||
flags,
|
||||
(flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG) ? this_arg.data.uid : INVALID_VALUE);
|
||||
serializer_dump_op_meta (create_op_meta_000 (opcode));
|
||||
return;
|
||||
}
|
||||
} /* dump_call_additional_info */
|
||||
|
||||
void
|
||||
dump_varg (operand op)
|
||||
|
||||
@ -61,6 +61,8 @@ void dumper_finish_scope (void);
|
||||
bool dumper_is_intrinsic (operand);
|
||||
operand dump_intrinsic (operand, operand);
|
||||
|
||||
extern bool dumper_is_eval_literal (operand);
|
||||
|
||||
void dump_boolean_assignment (operand, bool);
|
||||
operand dump_boolean_assignment_res (bool);
|
||||
void dump_string_assignment (operand, lit_cpointer_t);
|
||||
@ -78,7 +80,7 @@ operand dump_variable_assignment_res (operand);
|
||||
|
||||
void dump_varg_header_for_rewrite (varg_list_type, operand);
|
||||
operand rewrite_varg_header_set_args_count (uint8_t);
|
||||
void dump_this_arg (operand);
|
||||
void dump_call_additional_info (opcode_call_flags_t, operand);
|
||||
void dump_varg (operand);
|
||||
|
||||
void dump_prop_name_and_value (operand, operand);
|
||||
|
||||
@ -316,11 +316,13 @@ parse_property_assignment (void)
|
||||
For each ALT dumps appropriate bytecode. Uses OBJ during dump if neccesary.
|
||||
Result tmp. */
|
||||
static operand
|
||||
parse_argument_list (varg_list_type vlt, operand obj, uint8_t *args_count, operand *this_arg)
|
||||
parse_argument_list (varg_list_type vlt, operand obj, uint8_t *args_count, operand *this_arg_p)
|
||||
{
|
||||
token_type close_tt = TOK_CLOSE_PAREN;
|
||||
uint8_t args_num = 0;
|
||||
|
||||
JERRY_ASSERT (!(vlt != VARG_CALL_EXPR && this_arg_p != NULL));
|
||||
|
||||
switch (vlt)
|
||||
{
|
||||
case VARG_FUNC_DECL:
|
||||
@ -342,11 +344,58 @@ parse_argument_list (varg_list_type vlt, operand obj, uint8_t *args_count, opera
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (this_arg != NULL && this_arg->type == OPERAND_LITERAL)
|
||||
|
||||
opcode_call_flags_t call_flags = OPCODE_CALL_FLAGS__EMPTY;
|
||||
|
||||
operand this_arg = empty_operand ();
|
||||
if (this_arg_p != NULL
|
||||
&& !operand_is_empty (*this_arg_p))
|
||||
{
|
||||
*this_arg = dump_variable_assignment_res (*this_arg);
|
||||
call_flags = (opcode_call_flags_t) (call_flags | OPCODE_CALL_FLAGS_HAVE_THIS_ARG);
|
||||
|
||||
if (this_arg_p->type == OPERAND_LITERAL)
|
||||
{
|
||||
/*
|
||||
* FIXME:
|
||||
* Base of CallExpression should be evaluated only once during evaluation of CallExpression
|
||||
*
|
||||
* See also:
|
||||
* Evaluation of MemberExpression (ECMA-262 v5, 11.2.1)
|
||||
*/
|
||||
this_arg = dump_variable_assignment_res (*this_arg_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
this_arg = *this_arg_p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Presence of explicit 'this' argument implies that it is not Direct call to Eval
|
||||
*
|
||||
* See also:
|
||||
* ECMA-262 v5, 15.2.2.1
|
||||
*/
|
||||
}
|
||||
else if (dumper_is_eval_literal (obj))
|
||||
{
|
||||
call_flags = (opcode_call_flags_t) (call_flags | OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM);
|
||||
}
|
||||
|
||||
dump_varg_header_for_rewrite (vlt, obj);
|
||||
|
||||
if (call_flags != OPCODE_CALL_FLAGS__EMPTY)
|
||||
{
|
||||
if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
|
||||
{
|
||||
JERRY_ASSERT (!operand_is_empty (this_arg));
|
||||
dump_call_additional_info (call_flags, this_arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
dump_call_additional_info (call_flags, empty_operand ());
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case VARG_ARRAY_DECL:
|
||||
@ -365,11 +414,6 @@ parse_argument_list (varg_list_type vlt, operand obj, uint8_t *args_count, opera
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (vlt == VARG_CALL_EXPR && this_arg != NULL && !operand_is_empty (*this_arg))
|
||||
{
|
||||
dump_this_arg (*this_arg);
|
||||
args_num++;
|
||||
}
|
||||
|
||||
skip_newlines ();
|
||||
while (!token_is (close_tt))
|
||||
|
||||
@ -338,7 +338,6 @@ generate_opcode (scopes_tree tree, opcode_counter_t opc_index, lit_id_hash_table
|
||||
change_uid (om, lit_ids, 0x011);
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_THIS_ARG:
|
||||
case OPCODE_META_TYPE_VARG:
|
||||
case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER:
|
||||
{
|
||||
@ -351,6 +350,7 @@ generate_opcode (scopes_tree tree, opcode_counter_t opc_index, lit_id_hash_table
|
||||
case OPCODE_META_TYPE_CATCH:
|
||||
case OPCODE_META_TYPE_FINALLY:
|
||||
case OPCODE_META_TYPE_END_TRY_CATCH_FINALLY:
|
||||
case OPCODE_META_TYPE_CALL_SITE_INFO:
|
||||
case OPCODE_META_TYPE_SCOPE_CODE_FLAGS:
|
||||
{
|
||||
change_uid (om, lit_ids, 0x000);
|
||||
@ -477,7 +477,6 @@ count_new_literals_in_opcode (scopes_tree tree, opcode_counter_t opc_index)
|
||||
insert_uids_to_lit_id_map (om, 0x011);
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_THIS_ARG:
|
||||
case OPCODE_META_TYPE_VARG:
|
||||
case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER:
|
||||
{
|
||||
@ -490,6 +489,7 @@ count_new_literals_in_opcode (scopes_tree tree, opcode_counter_t opc_index)
|
||||
case OPCODE_META_TYPE_CATCH:
|
||||
case OPCODE_META_TYPE_FINALLY:
|
||||
case OPCODE_META_TYPE_END_TRY_CATCH_FINALLY:
|
||||
case OPCODE_META_TYPE_CALL_SITE_INFO:
|
||||
case OPCODE_META_TYPE_SCOPE_CODE_FLAGS:
|
||||
{
|
||||
insert_uids_to_lit_id_map (om, 0x000);
|
||||
|
||||
@ -653,44 +653,40 @@ opfunc_call_n (opcode_t opdata, /**< operation data */
|
||||
|
||||
int_data->pos++;
|
||||
|
||||
bool this_arg_var_idx_set = false;
|
||||
idx_t this_arg_var_idx = INVALID_VALUE;
|
||||
idx_t args_number;
|
||||
|
||||
opcode_call_flags_t call_flags = OPCODE_CALL_FLAGS__EMPTY;
|
||||
|
||||
opcode_t next_opcode = vm_get_opcode (int_data->opcodes_p, int_data->pos);
|
||||
if (next_opcode.op_idx == __op__idx_meta
|
||||
&& next_opcode.data.meta.type == OPCODE_META_TYPE_THIS_ARG)
|
||||
&& next_opcode.data.meta.type == OPCODE_META_TYPE_CALL_SITE_INFO)
|
||||
{
|
||||
this_arg_var_idx = next_opcode.data.meta.data_1;
|
||||
JERRY_ASSERT (is_reg_variable (int_data, this_arg_var_idx));
|
||||
call_flags = (opcode_call_flags_t) next_opcode.data.meta.data_1;
|
||||
|
||||
this_arg_var_idx_set = true;
|
||||
|
||||
JERRY_ASSERT (args_number_idx > 0);
|
||||
args_number = (idx_t) (args_number_idx - 1);
|
||||
if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
|
||||
{
|
||||
this_arg_var_idx = next_opcode.data.meta.data_2;
|
||||
JERRY_ASSERT (is_reg_variable (int_data, this_arg_var_idx));
|
||||
}
|
||||
|
||||
int_data->pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
args_number = args_number_idx;
|
||||
}
|
||||
|
||||
MEM_DEFINE_LOCAL_ARRAY (arg_values, args_number, ecma_value_t);
|
||||
MEM_DEFINE_LOCAL_ARRAY (arg_values, args_number_idx, ecma_value_t);
|
||||
|
||||
ecma_length_t args_read;
|
||||
ecma_completion_value_t get_arg_completion = fill_varg_list (int_data,
|
||||
args_number,
|
||||
args_number_idx,
|
||||
arg_values,
|
||||
&args_read);
|
||||
|
||||
if (ecma_is_completion_value_empty (get_arg_completion))
|
||||
{
|
||||
JERRY_ASSERT (args_read == args_number);
|
||||
JERRY_ASSERT (args_read == args_number_idx);
|
||||
|
||||
ecma_completion_value_t get_this_completion_value;
|
||||
|
||||
if (this_arg_var_idx_set)
|
||||
if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
|
||||
{
|
||||
get_this_completion_value = get_variable_value (int_data, this_arg_var_idx, false);
|
||||
}
|
||||
@ -714,7 +710,7 @@ opfunc_call_n (opcode_t opdata, /**< operation data */
|
||||
ecma_op_function_call (func_obj_p,
|
||||
this_value,
|
||||
arg_values,
|
||||
args_number),
|
||||
args_number_idx),
|
||||
ret_value);
|
||||
|
||||
ret_value = set_variable_value (int_data, lit_oc,
|
||||
@ -1680,7 +1676,7 @@ opfunc_meta (opcode_t opdata, /**< operation data */
|
||||
|
||||
case OPCODE_META_TYPE_SCOPE_CODE_FLAGS:
|
||||
case OPCODE_META_TYPE_UNDEFINED:
|
||||
case OPCODE_META_TYPE_THIS_ARG:
|
||||
case OPCODE_META_TYPE_CALL_SITE_INFO:
|
||||
case OPCODE_META_TYPE_FUNCTION_END:
|
||||
case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER:
|
||||
{
|
||||
|
||||
@ -59,7 +59,8 @@ typedef enum
|
||||
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_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 */
|
||||
@ -74,6 +75,17 @@ typedef enum
|
||||
* (See also: opcode_scope_code_flags_t) */
|
||||
} opcode_meta_type;
|
||||
|
||||
typedef enum : 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 */
|
||||
} opcode_call_flags_t;
|
||||
|
||||
/**
|
||||
* Flags indicating various properties of a scope's code
|
||||
*/
|
||||
|
||||
@ -266,15 +266,9 @@ pp_op_meta (opcode_counter_t oc, op_meta opm, bool rewrite)
|
||||
}
|
||||
case NAME_TO_ID (call_n):
|
||||
{
|
||||
if (opm.op.data.call_n.arg_list == 0)
|
||||
{
|
||||
pp_printf ("%s = %s ();", opm.op, opm.lit_id, oc, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
vargs_num = opm.op.data.call_n.arg_list;
|
||||
seen_vargs = 0;
|
||||
}
|
||||
vargs_num = opm.op.data.call_n.arg_list;
|
||||
seen_vargs = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
case NAME_TO_ID (native_call):
|
||||
@ -381,13 +375,17 @@ pp_op_meta (opcode_counter_t oc, op_meta opm, bool rewrite)
|
||||
printf ("unknown meta;");
|
||||
break;
|
||||
}
|
||||
case OPCODE_META_TYPE_THIS_ARG:
|
||||
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:
|
||||
{
|
||||
seen_vargs++;
|
||||
if (opm.op.data.meta.type != OPCODE_META_TYPE_CALL_SITE_INFO)
|
||||
{
|
||||
seen_vargs++;
|
||||
}
|
||||
|
||||
if (seen_vargs == vargs_num)
|
||||
{
|
||||
bool found = false;
|
||||
@ -473,15 +471,26 @@ pp_op_meta (opcode_counter_t oc, op_meta opm, bool rewrite)
|
||||
for (opcode_counter_t counter = start; counter <= oc; counter++)
|
||||
{
|
||||
opcode_t meta_op = serializer_get_opcode (counter);
|
||||
|
||||
switch (meta_op.op_idx)
|
||||
{
|
||||
case NAME_TO_ID (meta):
|
||||
{
|
||||
switch (meta_op.data.meta.type)
|
||||
{
|
||||
case OPCODE_META_TYPE_THIS_ARG:
|
||||
case OPCODE_META_TYPE_CALL_SITE_INFO:
|
||||
{
|
||||
pp_printf ("this_arg = %s", meta_op, NULL, counter, 2);
|
||||
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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user