diff --git a/jerry-core/api/jerry-snapshot.h b/jerry-core/api/jerry-snapshot.h index 919855769..b1f5dd325 100644 --- a/jerry-core/api/jerry-snapshot.h +++ b/jerry-core/api/jerry-snapshot.h @@ -41,7 +41,7 @@ typedef struct /** * Jerry snapshot format version. */ -#define JERRY_SNAPSHOT_VERSION (12u) +#define JERRY_SNAPSHOT_VERSION (13u) /** * Snapshot configuration flags. diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index a8db0884d..fff7ed687 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -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, \ diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index 5be95ec4a..fad86892f 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -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. * diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 5b1bbad92..0b5a3997d 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -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)); diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 0a5d6b195..6c9f2cdb1 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -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); diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index 48c1f20bd..b831802e1 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -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 diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index fb2c5d964..1f668730a 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -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++; } diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 857c824f7..6cb0d8a55 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -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); diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index 1aedee480..a91129efb 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -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 */ diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index 59b6d1f45..2853345fd 100644 --- a/tests/unit-core/test-snapshot.c +++ b/tests/unit-core/test-snapshot.c @@ -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,