Convert certain push number opcodes to literals (#2328)

Binary operations are much faster with literal arguments.
The byte immediates are still kept for other cases, e.g. array declarations.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2018-05-18 10:22:53 +02:00 committed by yichoi
parent 64b16bf190
commit 5560c76b41
10 changed files with 232 additions and 81 deletions

View File

@ -41,7 +41,7 @@ typedef struct
/**
* Jerry snapshot format version.
*/
#define JERRY_SNAPSHOT_VERSION (12u)
#define JERRY_SNAPSHOT_VERSION (13u)
/**
* Snapshot configuration flags.

View File

@ -272,11 +272,11 @@
CBC_OPCODE (CBC_PUSH_THIS_LITERAL, CBC_HAS_LITERAL_ARG, 2, \
VM_OC_PUSH_TWO | VM_OC_GET_THIS_LITERAL) \
CBC_OPCODE (CBC_PUSH_NUMBER_0, CBC_NO_FLAG, 1, \
VM_OC_PUSH_NUMBER_0 | VM_OC_PUT_STACK) \
VM_OC_PUSH_0 | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_NUMBER_POS_BYTE, CBC_HAS_BYTE_ARG, 1, \
VM_OC_PUSH_NUMBER_POS_BYTE | VM_OC_PUT_STACK) \
VM_OC_PUSH_POS_BYTE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_NUMBER_NEG_BYTE, CBC_HAS_BYTE_ARG, 1, \
VM_OC_PUSH_NUMBER_NEG_BYTE | VM_OC_PUT_STACK) \
VM_OC_PUSH_NEG_BYTE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP, CBC_NO_FLAG, -1, \
VM_OC_PROP_GET | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
@ -539,6 +539,12 @@
/* Basic opcodes. */ \
CBC_OPCODE (CBC_EXT_DEBUGGER, CBC_NO_FLAG, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0, CBC_HAS_LITERAL_ARG, 2, \
VM_OC_PUSH_LIT_0 | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE, CBC_HAS_LITERAL_ARG | CBC_HAS_BYTE_ARG, 2, \
VM_OC_PUSH_LIT_POS_BYTE | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE, CBC_HAS_LITERAL_ARG | CBC_HAS_BYTE_ARG, 2, \
VM_OC_PUSH_LIT_NEG_BYTE | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_EXT_RESOURCE_NAME, CBC_NO_FLAG, 0, \
VM_OC_RESOURCE_NAME) \
CBC_OPCODE (CBC_EXT_LINE, CBC_NO_FLAG, 0, \

View File

@ -1745,7 +1745,7 @@ lexer_construct_literal_object (parser_context_t *context_p, /**< context */
*/
bool
lexer_construct_number_object (parser_context_t *context_p, /**< context */
bool push_number_allowed, /**< push number support is allowed */
bool is_expr, /**< expression is parsed */
bool is_negative_number) /**< sign is negative */
{
parser_list_iterator_t literal_iterator;
@ -1773,7 +1773,7 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */
while (src_p < src_end_p);
}
if (push_number_allowed)
if (is_expr)
{
int32_t int_num = (int32_t) num;
@ -1818,22 +1818,99 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */
}
literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
literal_p->prop.length = context_p->token.lit_location.length;
literal_p->type = LEXER_UNUSED_LITERAL;
literal_p->status_flags = 0;
context_p->literal_count++;
literal_p->u.value = lit_value;
literal_p->prop.length = 0; /* Unused. */
literal_p->type = LEXER_NUMBER_LITERAL;
literal_p->status_flags = 0;
context_p->lit_object.literal_p = literal_p;
context_p->lit_object.index = (uint16_t) literal_index;
context_p->lit_object.type = LEXER_LITERAL_OBJECT_ANY;
context_p->literal_count++;
return false;
} /* lexer_construct_number_object */
/**
* Convert a push number opcode to push literal opcode
*/
void
lexer_convert_push_number_to_push_literal (parser_context_t *context_p) /**< context */
{
ecma_integer_value_t value;
bool two_literals = !PARSER_IS_BASIC_OPCODE (context_p->last_cbc_opcode);
if (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_0
|| context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0))
{
value = 0;
}
else if (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_POS_BYTE
|| context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE))
{
value = ((ecma_integer_value_t) context_p->last_cbc.value) + 1;
}
else
{
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_NEG_BYTE
|| context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE));
value = -((ecma_integer_value_t) context_p->last_cbc.value) - 1;
}
ecma_value_t lit_value = ecma_make_integer_value (value);
parser_list_iterator_t literal_iterator;
parser_list_iterator_init (&context_p->literal_pool, &literal_iterator);
context_p->last_cbc_opcode = two_literals ? CBC_PUSH_TWO_LITERALS : CBC_PUSH_LITERAL;
uint32_t literal_index = 0;
lexer_literal_t *literal_p;
while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
{
if (literal_p->type == LEXER_NUMBER_LITERAL
&& literal_p->u.value == lit_value)
{
if (two_literals)
{
context_p->last_cbc.value = (uint16_t) literal_index;
}
else
{
context_p->last_cbc.literal_index = (uint16_t) literal_index;
}
return;
}
literal_index++;
}
JERRY_ASSERT (literal_index == context_p->literal_count);
if (literal_index >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
}
literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
literal_p->u.value = lit_value;
literal_p->prop.length = 0; /* Unused. */
literal_p->type = LEXER_NUMBER_LITERAL;
literal_p->status_flags = 0;
context_p->literal_count++;
if (two_literals)
{
context_p->last_cbc.value = (uint16_t) literal_index;
}
else
{
context_p->last_cbc.literal_index = (uint16_t) literal_index;
}
} /* lexer_convert_push_number_to_push_literal */
/**
* Construct a function literal object.
*

View File

@ -808,12 +808,6 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
{
JERRY_ASSERT (context_p->lit_object.index <= CBC_PUSH_NUMBER_BYTE_RANGE_END);
if (context_p->lit_object.index == 0)
{
parser_emit_cbc (context_p, CBC_PUSH_NUMBER_0);
break;
}
parser_emit_cbc_push_number (context_p, is_negative_number);
break;
}
@ -1563,6 +1557,11 @@ parser_process_binary_opcodes (parser_context_t *context_p, /**< context */
{
opcode = LEXER_BINARY_OP_TOKEN_TO_OPCODE (token);
if (PARSER_IS_PUSH_NUMBER (context_p->last_cbc_opcode))
{
lexer_convert_push_number_to_push_literal (context_p);
}
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, opcode + CBC_BINARY_WITH_LITERAL));

View File

@ -117,6 +117,13 @@ typedef struct
((opcode) == CBC_PUSH_LITERAL \
|| (opcode) == CBC_PUSH_TWO_LITERALS \
|| (opcode) == CBC_PUSH_THREE_LITERALS)
#define PARSER_IS_PUSH_NUMBER(opcode) \
((opcode) == CBC_PUSH_NUMBER_0 \
|| (opcode) == CBC_PUSH_NUMBER_POS_BYTE \
|| (opcode) == CBC_PUSH_NUMBER_NEG_BYTE \
|| (opcode) == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0) \
|| (opcode) == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE) \
|| (opcode) == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE))
#define PARSER_GET_LITERAL(literal_index) \
((lexer_literal_t *) parser_list_get (&context_p->literal_pool, (literal_index)))
@ -429,7 +436,8 @@ ecma_char_t lexer_hex_to_character (parser_context_t *context_p, const uint8_t *
void lexer_expect_object_literal_id (parser_context_t *context_p, bool must_be_identifier);
void lexer_construct_literal_object (parser_context_t *context_p, lexer_lit_location_t *literal_p,
uint8_t literal_type);
bool lexer_construct_number_object (parser_context_t *context_p, bool push_number_allowed, bool is_negative_number);
bool lexer_construct_number_object (parser_context_t *context_p, bool is_expr, bool is_negative_number);
void lexer_convert_push_number_to_push_literal (parser_context_t *context_p);
uint16_t lexer_construct_function_object (parser_context_t *context_p, uint32_t extra_status_flags);
void lexer_construct_regexp_object (parser_context_t *context_p, bool parse_only);
bool lexer_compare_identifier_to_current (parser_context_t *context_p, const lexer_lit_location_t *right);

View File

@ -206,7 +206,20 @@ parser_flush_cbc (parser_context_t *context_p) /**< context */
if (flags & CBC_HAS_BYTE_ARG)
{
JERRY_DEBUG_MSG (" byte_arg:%d", (int) context_p->last_cbc.value);
if ((last_opcode == CBC_PUSH_NUMBER_POS_BYTE)
|| (last_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE)))
{
JERRY_DEBUG_MSG (" number:%d", (int) context_p->last_cbc.value + 1);
}
else if ((last_opcode == CBC_PUSH_NUMBER_NEG_BYTE)
|| (last_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE)))
{
JERRY_DEBUG_MSG (" number:%d", -((int) context_p->last_cbc.value + 1));
}
else
{
JERRY_DEBUG_MSG (" byte_arg:%d", (int) context_p->last_cbc.value);
}
}
JERRY_DEBUG_MSG ("\n");
@ -311,41 +324,66 @@ parser_emit_cbc_push_number (parser_context_t *context_p, /**< context */
bool is_negative_number) /**< sign is negative */
{
uint16_t value = context_p->lit_object.index;
uint16_t lit_value = UINT16_MAX;
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
cbc_opcode_t opcode = is_negative_number ? CBC_PUSH_NUMBER_NEG_BYTE : CBC_PUSH_NUMBER_POS_BYTE;
JERRY_ASSERT (value > 0 && value <= CBC_PUSH_NUMBER_BYTE_RANGE_END);
JERRY_ASSERT (CBC_STACK_ADJUST_VALUE (cbc_flags[opcode]) == 1);
context_p->stack_depth++;
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
JERRY_DEBUG_MSG (" [%3d] %s number:%d\n",
(int) context_p->stack_depth,
cbc_names[opcode],
is_negative_number ? -(int) value : (int) value);
}
#endif /* PARSER_DUMP_BYTE_CODE */
parser_emit_two_bytes (context_p, opcode, (uint8_t) (value - 1));
context_p->byte_code_size += 2;
if (context_p->stack_depth > context_p->stack_limit)
{
context_p->stack_limit = context_p->stack_depth;
if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
lit_value = context_p->last_cbc.literal_index;
}
else
{
if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
{
context_p->last_cbc_opcode = CBC_PUSH_LITERAL;
lit_value = context_p->last_cbc.value;
}
else if (context_p->last_cbc_opcode == CBC_PUSH_THREE_LITERALS)
{
context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS;
lit_value = context_p->last_cbc.third_literal_index;
}
parser_flush_cbc (context_p);
}
}
if (value == 0)
{
if (lit_value == UINT16_MAX)
{
context_p->last_cbc_opcode = CBC_PUSH_NUMBER_0;
return;
}
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0);
context_p->last_cbc.literal_index = lit_value;
return;
}
uint16_t opcode;
if (lit_value == UINT16_MAX)
{
opcode = (is_negative_number ? CBC_PUSH_NUMBER_NEG_BYTE
: CBC_PUSH_NUMBER_POS_BYTE);
JERRY_ASSERT (CBC_STACK_ADJUST_VALUE (PARSER_GET_FLAGS (opcode)) == 1);
}
else
{
opcode = PARSER_TO_EXT_OPCODE (is_negative_number ? CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE
: CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE);
JERRY_ASSERT (CBC_STACK_ADJUST_VALUE (PARSER_GET_FLAGS (opcode)) == 2);
context_p->last_cbc.literal_index = lit_value;
}
JERRY_ASSERT (value > 0 && value <= CBC_PUSH_NUMBER_BYTE_RANGE_END);
context_p->last_cbc_opcode = opcode;
context_p->last_cbc.value = (uint16_t) (value - 1);
} /* parser_emit_cbc_push_number */
#ifdef JERRY_ENABLE_LINE_INFO

View File

@ -356,11 +356,6 @@ parser_compute_indicies (parser_context_t *context_p, /**< context */
{
uint16_t init_index;
if (literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT)
{
continue;
}
if (literal_p->type != LEXER_IDENT_LITERAL)
{
if (literal_p->type == LEXER_STRING_LITERAL
@ -392,6 +387,11 @@ parser_compute_indicies (parser_context_t *context_p, /**< context */
continue;
}
if (literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT)
{
continue;
}
if (!(literal_p->status_flags & LEXER_FLAG_VAR))
{
literal_p->prop.index = ident_index;
@ -560,8 +560,6 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */
uint16_t next_index = uninitialized_var_end;
#endif /* !JERRY_NDEBUG */
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED;
*dst_p++ = CBC_INITIALIZE_VARS;
dst_p = parser_encode_literal (dst_p,
(uint16_t) uninitialized_var_end,
@ -1267,20 +1265,6 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code
literal_pool_p);
continue;
}
if (opcode == CBC_PUSH_NUMBER_POS_BYTE)
{
JERRY_DEBUG_MSG (" number:%d\n", *byte_code_p + 1);
byte_code_p++;
continue;
}
if (opcode == CBC_PUSH_NUMBER_NEG_BYTE)
{
JERRY_DEBUG_MSG (" number:%d\n", -(*byte_code_p + 1));
byte_code_p++;
continue;
}
}
else
{
@ -1332,7 +1316,20 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code
if (flags & CBC_HAS_BYTE_ARG)
{
JERRY_DEBUG_MSG (" byte_arg:%d", *byte_code_p);
if (opcode == CBC_PUSH_NUMBER_POS_BYTE
|| ext_opcode == CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE)
{
JERRY_DEBUG_MSG (" number:%d", (int) *byte_code_p + 1);
}
else if (opcode == CBC_PUSH_NUMBER_NEG_BYTE
|| ext_opcode == CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE)
{
JERRY_DEBUG_MSG (" number:%d", -((int) *byte_code_p + 1));
}
else
{
JERRY_DEBUG_MSG (" byte_arg:%d", *byte_code_p);
}
byte_code_p++;
}

View File

@ -999,23 +999,46 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
*stack_top_p++ = ecma_copy_value (frame_ctx_p->this_binding);
continue;
}
case VM_OC_PUSH_NUMBER_0:
case VM_OC_PUSH_0:
{
*stack_top_p++ = ecma_make_integer_value (0);
continue;
}
case VM_OC_PUSH_NUMBER_POS_BYTE:
case VM_OC_PUSH_POS_BYTE:
{
ecma_integer_value_t number = *byte_code_p++;
*stack_top_p++ = ecma_make_integer_value (number + 1);
continue;
}
case VM_OC_PUSH_NUMBER_NEG_BYTE:
case VM_OC_PUSH_NEG_BYTE:
{
ecma_integer_value_t number = *byte_code_p++;
*stack_top_p++ = ecma_make_integer_value (-(number + 1));
continue;
}
case VM_OC_PUSH_LIT_0:
{
stack_top_p[0] = left_value;
stack_top_p[1] = ecma_make_integer_value (0);
stack_top_p += 2;
continue;
}
case VM_OC_PUSH_LIT_POS_BYTE:
{
ecma_integer_value_t number = *byte_code_p++;
stack_top_p[0] = left_value;
stack_top_p[1] = ecma_make_integer_value (number + 1);
stack_top_p += 2;
continue;
}
case VM_OC_PUSH_LIT_NEG_BYTE:
{
ecma_integer_value_t number = *byte_code_p++;
stack_top_p[0] = left_value;
stack_top_p[1] = ecma_make_integer_value (-(number + 1));
stack_top_p += 2;
continue;
}
case VM_OC_PUSH_OBJECT:
{
ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);

View File

@ -105,17 +105,20 @@ typedef enum
VM_OC_NONE, /**< do nothing */
VM_OC_POP, /**< pop from stack */
VM_OC_POP_BLOCK, /**< pop block */
VM_OC_PUSH, /**< push one element */
VM_OC_PUSH_TWO, /**< push two elements onto the stack */
VM_OC_PUSH_THREE, /**< push three elements onto the stack */
VM_OC_PUSH, /**< push one literal */
VM_OC_PUSH_TWO, /**< push two literals */
VM_OC_PUSH_THREE, /**< push three literals */
VM_OC_PUSH_UNDEFINED, /**< push undefined value */
VM_OC_PUSH_TRUE, /**< push true value */
VM_OC_PUSH_FALSE, /**< push false value */
VM_OC_PUSH_NULL, /**< push null value */
VM_OC_PUSH_THIS, /**< push this */
VM_OC_PUSH_NUMBER_0, /**< push number zero */
VM_OC_PUSH_NUMBER_POS_BYTE, /**< push number between 1 and 256 */
VM_OC_PUSH_NUMBER_NEG_BYTE, /**< push number between -1 and -256 */
VM_OC_PUSH_0, /**< push number zero */
VM_OC_PUSH_POS_BYTE, /**< push number between 1 and 256 */
VM_OC_PUSH_NEG_BYTE, /**< push number between -1 and -256 */
VM_OC_PUSH_LIT_0, /**< push literal and number zero */
VM_OC_PUSH_LIT_POS_BYTE, /**< push literal and number between 1 and 256 */
VM_OC_PUSH_LIT_NEG_BYTE, /**< push literal and number between -1 and -256 */
VM_OC_PUSH_OBJECT, /**< push object */
VM_OC_SET_PROPERTY, /**< set property */
VM_OC_SET_GETTER, /**< set getter */

View File

@ -216,7 +216,7 @@ main (void)
/* Check the snapshot data. Unused bytes should be filled with zeroes */
const uint8_t expected_data[] =
{
0x4A, 0x52, 0x52, 0x59, 0x0C, 0x00, 0x00, 0x00,
0x4A, 0x52, 0x52, 0x59, 0x0D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,