diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 14c35593b..a1e9beccd 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -678,7 +678,7 @@ main (void) - [jerry_init](#jerry_init) - [jerry_cleanup](#jerry_cleanup) -- [jerry_parse_and_save_literals](#jerry_parse_and_save_literals) +- [jerry_get_literals_from_snapshot](#jerry_get_literals_from_snapshot) ## jerry_get_memory_stats @@ -5349,30 +5349,28 @@ main (void) - [jerry_parse_and_save_function_snapshot](#jerry_parse_and_save_function_snapshot) -## jerry_parse_and_save_literals +## jerry_get_literals_from_snapshot **Summary** -Collect the used literals from the given source code and save them into a specific file in a list or C format. -These literals are generated by the parser, they are valid identifiers and none of them are magic string. +Collect the used literals from the given snapshot and save them into a buffer in list or C format. +None of these literals are magic strings. In C format only valid identifiers are collected. **Prototype** ```c size_t -jerry_parse_and_save_literals (const jerry_char_t *source_p, - size_t source_size, - bool is_strict, - uint32_t *buffer_p, - size_t buffer_size, - bool is_c_format); +jerry_get_literals_from_snapshot (const uint32_t *snapshot_p, + size_t snapshot_size, + jerry_char_t *lit_buf_p, + size_t lit_buf_size, + bool is_c_format); ``` -- `source_p` - script source, it must be a valid utf8 string. -- `source_size` - script source size, in bytes. -- `is_strict` - strict mode. -- `buffer_p` - buffer to save literals to. -- `buffer_size` - the buffer's size. +- `snapshot_p` - input snapshot buffer. +- `snapshot_size` - snapshot size, in bytes. +- `lit_buf_p` - buffer to save literals to. +- `lit_buf_size` - the buffer's size. - `is_c_format` - the output format would be C-style (true) or a simple list (false). - return value - the size of the literal-list, if it was generated succesfully (i.e. the list of literals isn't empty, @@ -5393,20 +5391,31 @@ main (void) { jerry_init (JERRY_INIT_EMPTY); - static uint32_t save_literal_buffer[256]; + static jerry_char_t literal_buffer[256]; + static uint32_t snapshot_buffer[256]; const jerry_char_t *code_for_literal_save_p = (const jerry_char_t *) "var obj = { a:'aa', bb:'Bb' }"; + size_t code_for_literal_save_size = strlen ((const char *) code_for_literal_save_p); - size_t literal_sizes = jerry_parse_and_save_literals (code_for_literal_save_p, - strlen ((const char *) code_for_literal_save_p), - false, - save_literal_buffer, - sizeof (save_literal_buffer) / sizeof (uint32_t), - true); + jerry_value_t generate_result = jerry_generate_snapshot (NULL, + 0, + code_for_literal_save_p, + code_for_literal_save_size, + 0, + snapshot_buffer, + 256); + size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); + jerry_release_value (generate_result); - if (literal_sizes != 0) + const size_t literal_size = jerry_get_literals_from_snapshot (snapshot_buffer, + snapshot_size, + literal_buffer, + 256, + true); + + if (literal_size != 0) { - FILE *literal_file_p = fopen ("literals.txt", "w"); - fwrite (save_literal_buffer, sizeof (uint8_t), literal_sizes, literal_file_p); + FILE *literal_file_p = fopen ("literals.h", "wb"); + fwrite (literal_buffer, sizeof (uint8_t), literal_size, literal_file_p); fclose (literal_file_p); } diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index 47241bf88..94924b3f2 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -1259,7 +1259,7 @@ jerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers t functions_size += header_p->lit_table_offset - start_offset; scan_snapshot_functions (data_p + start_offset, - data_p + header_p->lit_table_offset, + literal_base_p, lit_pool_p, literal_base_p); } @@ -1582,48 +1582,44 @@ ecma_string_is_valid_identifier (const ecma_string_t *string_p) #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ /** - * Copy certain string literals into the given buffer in a specified format, - * which are valid identifiers and none of them are magic string. + * Get the literals from a snapshot. Copies certain string literals into the given + * buffer in a specified format. + * + * Note: + * Only valid identifiers are saved in C format. * * @return size of the literal-list in bytes, at most equal to the buffer size, - * if the source parsed successfully and the list of the literals isn't empty, + * if the list of the literals isn't empty, * 0 - otherwise. */ size_t -jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source */ - size_t source_size, /**< script source size */ - bool is_strict, /**< strict mode */ - uint32_t *buffer_p, /**< [out] buffer to save literals to */ - size_t buffer_size, /**< the buffer's size */ - bool is_c_format) /**< format-flag */ +jerry_get_literals_from_snapshot (const uint32_t *snapshot_p, /**< input snapshot buffer */ + size_t snapshot_size, /**< size of the input snapshot buffer */ + jerry_char_t *lit_buf_p, /**< [out] buffer to save literals to */ + size_t lit_buf_size, /**< the buffer's size */ + bool is_c_format) /**< format-flag */ { #ifdef JERRY_ENABLE_SNAPSHOT_SAVE - ecma_value_t parse_status; - ecma_compiled_code_t *bytecode_data_p; + const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p; + const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) snapshot_data_p; -#ifdef JERRY_ENABLE_LINE_INFO - JERRY_CONTEXT (resource_name) = ECMA_VALUE_UNDEFINED; -#endif /* JERRY_ENABLE_LINE_INFO */ - - parse_status = parser_parse_script (NULL, - 0, - source_p, - source_size, - is_strict, - &bytecode_data_p); - - if (ECMA_IS_VALUE_ERROR (parse_status)) + if (snapshot_size <= sizeof (jerry_snapshot_header_t) + || header_p->magic != JERRY_SNAPSHOT_MAGIC + || header_p->version != JERRY_SNAPSHOT_VERSION + || !snapshot_check_global_flags (header_p->global_flags)) { - ecma_free_value (JERRY_CONTEXT (error_value)); + /* Invalid snapshot format */ return 0; } - ecma_free_value (parse_status); + JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0); + const uint8_t *literal_base_p = snapshot_data_p + header_p->lit_table_offset; ecma_collection_header_t *lit_pool_p = ecma_new_values_collection (); - ecma_save_literals_add_compiled_code (bytecode_data_p, lit_pool_p); - - ecma_bytecode_deref (bytecode_data_p); + scan_snapshot_functions (snapshot_data_p + header_p->func_offsets[0], + literal_base_p, + lit_pool_p, + literal_base_p); lit_utf8_size_t literal_count = 0; ecma_value_t *iterator_p = ecma_collection_iterator_init (lit_pool_p); @@ -1657,10 +1653,8 @@ jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source return 0; } - uint8_t *destination_p = (uint8_t *) buffer_p; - - uint8_t *const buffer_start_p = destination_p; - uint8_t *const buffer_end_p = destination_p + buffer_size; + jerry_char_t *const buffer_start_p = lit_buf_p; + jerry_char_t *const buffer_end_p = lit_buf_p + lit_buf_size; JMEM_DEFINE_LOCAL_ARRAY (literal_array, literal_count, ecma_string_t *); lit_utf8_size_t literal_idx = 0; @@ -1697,43 +1691,43 @@ jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source if (is_c_format) { /* Save literal count. */ - destination_p = jerry_append_chars_to_buffer (destination_p, - buffer_end_p, - "jerry_length_t literal_count = ", - 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, + buffer_end_p, + "jerry_length_t literal_count = ", + 0); - destination_p = jerry_append_number_to_buffer (destination_p, buffer_end_p, literal_count); + lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count); /* Save the array of literals. */ - destination_p = jerry_append_chars_to_buffer (destination_p, - buffer_end_p, - ";\n\njerry_char_t *literals[", - 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, + buffer_end_p, + ";\n\njerry_char_t *literals[", + 0); - destination_p = jerry_append_number_to_buffer (destination_p, buffer_end_p, literal_count); - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "] =\n{\n", 0); + lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "] =\n{\n", 0); for (lit_utf8_size_t i = 0; i < literal_count; i++) { - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, " \"", 0); - destination_p = jerry_append_ecma_string_to_buffer (destination_p, buffer_end_p, literal_array[i]); - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "\"", 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " \"", 0); + lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\"", 0); if (i < literal_count - 1) { - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, ",", 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, ",", 0); } - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "\n", 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\n", 0); } - destination_p = jerry_append_chars_to_buffer (destination_p, - buffer_end_p, - "};\n\njerry_length_t literal_sizes[", - 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, + buffer_end_p, + "};\n\njerry_length_t literal_sizes[", + 0); - destination_p = jerry_append_number_to_buffer (destination_p, buffer_end_p, literal_count); - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "] =\n{\n", 0); + lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "] =\n{\n", 0); } /* Save the literal sizes respectively. */ @@ -1743,51 +1737,51 @@ jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source if (is_c_format) { - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, " ", 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " ", 0); } - destination_p = jerry_append_number_to_buffer (destination_p, buffer_end_p, str_size); - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, " ", 0); + lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, str_size); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " ", 0); if (is_c_format) { /* Show the given string as a comment. */ - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "/* ", 0); - destination_p = jerry_append_ecma_string_to_buffer (destination_p, buffer_end_p, literal_array[i]); - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, " */", 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "/* ", 0); + lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " */", 0); if (i < literal_count - 1) { - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, ",", 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, ",", 0); } } else { - destination_p = jerry_append_ecma_string_to_buffer (destination_p, buffer_end_p, literal_array[i]); + lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]); } - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "\n", 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\n", 0); } if (is_c_format) { - destination_p = jerry_append_chars_to_buffer (destination_p, buffer_end_p, "};\n", 0); + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "};\n", 0); } JMEM_FINALIZE_LOCAL_ARRAY (literal_array); - return destination_p <= buffer_end_p ? (size_t) (destination_p - buffer_start_p) : 0; + return lit_buf_p <= buffer_end_p ? (size_t) (lit_buf_p - buffer_start_p) : 0; #else /* !JERRY_ENABLE_SNAPSHOT_SAVE */ - JERRY_UNUSED (source_p); - JERRY_UNUSED (source_size); - JERRY_UNUSED (is_strict); - JERRY_UNUSED (buffer_p); - JERRY_UNUSED (buffer_size); + JERRY_UNUSED (snapshot_p); + JERRY_UNUSED (snapshot_size); + JERRY_UNUSED (lit_buf_p); + JERRY_UNUSED (lit_buf_size); JERRY_UNUSED (is_c_format); return 0; #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ -} /* jerry_parse_and_save_literals */ +} /* jerry_get_literals_from_snapshot */ + /** * Generate snapshot function from specified source and arguments diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index 8da3f4898..64dd16cf0 100644 --- a/jerry-core/include/jerryscript-snapshot.h +++ b/jerry-core/include/jerryscript-snapshot.h @@ -65,8 +65,8 @@ jerry_value_t jerry_load_function_snapshot (const uint32_t *function_snapshot_p, size_t jerry_merge_snapshots (const uint32_t **inp_buffers_p, size_t *inp_buffer_sizes_p, size_t number_of_snapshots, uint32_t *out_buffer_p, size_t out_buffer_size, const char **error_p); -size_t jerry_parse_and_save_literals (const jerry_char_t *source_p, size_t source_size, bool is_strict, - uint32_t *buffer_p, size_t buffer_size, bool is_c_format); +size_t jerry_get_literals_from_snapshot (const uint32_t *snapshot_p, size_t snapshot_size, + jerry_char_t *lit_buf_p, size_t lit_buf_size, bool is_c_format); /** * @} */ diff --git a/jerry-main/main-unix-snapshot.c b/jerry-main/main-unix-snapshot.c index 1f01158f1..62a5fa31b 100644 --- a/jerry-main/main-unix-snapshot.c +++ b/jerry-main/main-unix-snapshot.c @@ -41,6 +41,7 @@ static uint8_t input_buffer[JERRY_BUFFER_SIZE]; static uint32_t output_buffer[JERRY_BUFFER_SIZE / 4]; +static jerry_char_t literal_buffer[JERRY_BUFFER_SIZE]; static const char *output_file_name_p = "js.snapshot"; static jerry_length_t magic_string_lengths[JERRY_LITERAL_LENGTH]; static const jerry_char_t *magic_string_items[JERRY_LITERAL_LENGTH]; @@ -125,7 +126,7 @@ read_file (uint8_t *input_pos_p, /**< next position in the input buffer */ return 0; } - printf ("Input file '%s' (%d bytes) loaded.\n", file_name, (int) bytes_read); + printf ("Input file '%s' (%lu bytes) loaded.\n", file_name, bytes_read); return bytes_read; } /* read_file */ @@ -172,8 +173,6 @@ typedef enum { OPT_GENERATE_HELP, OPT_GENERATE_STATIC, - OPT_GENERATE_LITERAL_LIST, - OPT_GENERATE_LITERAL_C, OPT_GENERATE_SHOW_OP, OPT_GENERATE_OUT, OPT_IMPORT_LITERAL_LIST @@ -191,12 +190,6 @@ static const cli_opt_t generate_opts[] = CLI_OPT_DEF (.id = OPT_IMPORT_LITERAL_LIST, .longopt = "load-literals-list-format", .meta = "FILE", .help = "import literals from list format (for static snapshots)"), - CLI_OPT_DEF (.id = OPT_GENERATE_LITERAL_LIST, .longopt = "save-literals-list-format", - .meta = "FILE", - .help = "export literals found in parsed JS input (in list format)"), - CLI_OPT_DEF (.id = OPT_GENERATE_LITERAL_C, .longopt = "save-literals-c-format", - .meta = "FILE", - .help = "export literals found in parsed JS input (in C source format)"), CLI_OPT_DEF (.id = OPT_GENERATE_SHOW_OP, .longopt = "show-opcodes", .help = "print generated opcodes"), CLI_OPT_DEF (.id = OPT_GENERATE_OUT, .opt = "o", .meta="FILE", @@ -217,8 +210,6 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ { (void) argc; - bool is_save_literals_mode_in_c_format = false; - bool is_import_literals = false; uint32_t snapshot_flags = 0; jerry_init_flag_t flags = JERRY_INIT_EMPTY; @@ -243,18 +234,8 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ snapshot_flags |= JERRY_SNAPSHOT_SAVE_STATIC; break; } - case OPT_GENERATE_LITERAL_C: - case OPT_GENERATE_LITERAL_LIST: case OPT_IMPORT_LITERAL_LIST: { - if (literals_file_name_p != NULL) - { - jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: literal file name already specified"); - return JERRY_STANDALONE_EXIT_CODE_FAIL; - } - - is_import_literals = (id == OPT_IMPORT_LITERAL_LIST); - is_save_literals_mode_in_c_format = (id == OPT_GENERATE_LITERAL_C); literals_file_name_p = cli_consume_string (cli_state_p); break; } @@ -318,11 +299,13 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ if (!jerry_is_valid_utf8_string (source_p, (jerry_size_t) source_length)) { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Input must be a valid UTF-8 string.\n"); + jerry_cleanup (); return JERRY_STANDALONE_EXIT_CODE_FAIL; } - if (is_import_literals) + if (literals_file_name_p != NULL) { + /* Import literal list */ uint8_t *sp_buffer_start_p = source_p + source_length + 1; size_t sp_buffer_size = read_file (sp_buffer_start_p, literals_file_name_p); @@ -371,6 +354,7 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ print_unhandled_exception (snapshot_result); jerry_release_value (snapshot_result); + jerry_cleanup (); return JERRY_STANDALONE_EXIT_CODE_FAIL; } @@ -381,6 +365,7 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ if (snapshot_file_p == NULL) { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Unable to write snapshot file: '%s'\n", output_file_name_p); + jerry_cleanup (); return JERRY_STANDALONE_EXIT_CODE_FAIL; } @@ -389,36 +374,197 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ printf ("Created snapshot file: '%s' (%lu bytes)\n", output_file_name_p, (unsigned long) snapshot_size); - if (literals_file_name_p != NULL && !is_import_literals) + jerry_cleanup (); + return JERRY_STANDALONE_EXIT_CODE_OK; +} /* process_generate */ + +/** + * Literal dump command line option IDs + */ +typedef enum +{ + OPT_LITERAL_DUMP_HELP, + OPT_LITERAL_DUMP_FORMAT, + OPT_LITERAL_DUMP_OUT, +} literal_dump_opt_id_t; + +/** + * Literal dump command line options + */ +static const cli_opt_t literal_dump_opts[] = +{ + CLI_OPT_DEF (.id = OPT_LITERAL_DUMP_HELP, .opt = "h", .longopt = "help", + .help = "print this help and exit"), + CLI_OPT_DEF (.id = OPT_LITERAL_DUMP_FORMAT, .longopt = "format", + .meta = "[c|list]", + .help = "specify output format (default: list)"), + CLI_OPT_DEF (.id = OPT_LITERAL_DUMP_OUT, .opt = "o", + .help = "specify output file name (default: literals.[h|list])"), + CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE(S)", + .help = "input snapshot files") +}; + +/** + * Process 'litdump' command. + * + * @return error code (0 - no error) + */ +static int +process_literal_dump (cli_state_t *cli_state_p, /**< cli state */ + int argc, /**< number of arguments */ + char *prog_name_p) /**< program name */ +{ + uint8_t *input_pos_p = input_buffer; + + cli_change_opts (cli_state_p, literal_dump_opts); + + JERRY_VLA (const uint32_t *, snapshot_buffers, argc); + JERRY_VLA (size_t, snapshot_buffer_sizes, argc); + uint32_t number_of_files = 0; + const char *literals_file_name_p = NULL; + bool is_c_format = false; + + for (int id = cli_consume_option (cli_state_p); id != CLI_OPT_END; id = cli_consume_option (cli_state_p)) { - const size_t literal_buffer_size = jerry_parse_and_save_literals ((jerry_char_t *) source_p, - source_length, - false, - output_buffer, - sizeof (output_buffer) / sizeof (uint32_t), - is_save_literals_mode_in_c_format); - if (literal_buffer_size == 0) + switch (id) { - jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Literal saving failed!\n"); - return JERRY_STANDALONE_EXIT_CODE_FAIL; + case OPT_LITERAL_DUMP_HELP: + { + cli_help (prog_name_p, "litdump", literal_dump_opts); + return JERRY_STANDALONE_EXIT_CODE_OK; + } + case OPT_LITERAL_DUMP_FORMAT: + { + const char *fromat_str_p = cli_consume_string (cli_state_p); + if (!strcmp ("c", fromat_str_p)) + { + is_c_format = true; + } + else if (!strcmp ("list", fromat_str_p)) + { + is_c_format = false; + } + else + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Unsupported literal dump format."); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + break; + } + case OPT_LITERAL_DUMP_OUT: + { + literals_file_name_p = cli_consume_string (cli_state_p); + break; + } + case CLI_OPT_DEFAULT: + { + const char *file_name_p = cli_consume_string (cli_state_p); + + if (cli_state_p->error == NULL) + { + size_t size = read_file (input_pos_p, file_name_p); + + if (size == 0) + { + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + snapshot_buffers[number_of_files] = (const uint32_t *) input_pos_p; + snapshot_buffer_sizes[number_of_files] = size; + + number_of_files++; + const uintptr_t mask = sizeof (uint32_t) - 1; + input_pos_p = (uint8_t *) ((((uintptr_t) input_pos_p) + size + mask) & ~mask); + } + break; + } + default: + { + cli_state_p->error = "Internal error"; + break; + } } - - FILE *literal_file_p = fopen (literals_file_name_p, "wb"); - - if (literal_file_p == NULL) - { - jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Unable to write literal file: '%s'\n", literals_file_name_p); - return JERRY_STANDALONE_EXIT_CODE_FAIL; - } - - fwrite (output_buffer, sizeof (uint8_t), literal_buffer_size, literal_file_p); - fclose (literal_file_p); - - printf ("Created literal file: '%s' (%lu bytes)\n", literals_file_name_p, (unsigned long) literal_buffer_size); } - return 0; -} /* process_generate */ + if (check_cli_error (cli_state_p)) + { + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + if (number_of_files < 1) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: at least one input file must be specified.\n"); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + jerry_init (JERRY_INIT_EMPTY); + + size_t lit_buf_sz = 0; + if (number_of_files == 1) + { + lit_buf_sz = jerry_get_literals_from_snapshot (snapshot_buffers[0], + snapshot_buffer_sizes[0], + literal_buffer, + JERRY_BUFFER_SIZE, + is_c_format); + } + else + { + /* The input contains more than one input snapshot file, so we must merge them first. */ + const char *error_p = NULL; + size_t merged_snapshot_size = jerry_merge_snapshots (snapshot_buffers, + snapshot_buffer_sizes, + number_of_files, + output_buffer, + JERRY_BUFFER_SIZE, + &error_p); + + if (merged_snapshot_size == 0) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", error_p); + jerry_cleanup (); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + printf ("Successfully merged the input snapshots (%lu bytes).\n", merged_snapshot_size); + + lit_buf_sz = jerry_get_literals_from_snapshot (output_buffer, + merged_snapshot_size, + literal_buffer, + JERRY_BUFFER_SIZE, + is_c_format); + } + + if (lit_buf_sz == 0) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, + "Error: Literal saving failed! No literals were found in the input snapshot(s).\n"); + jerry_cleanup (); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + if (literals_file_name_p == NULL) + { + literals_file_name_p = is_c_format ? "literals.h" : "literals.list"; + } + + FILE *file_p = fopen (literals_file_name_p, "wb"); + + if (file_p == NULL) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: cannot open file: '%s'\n", literals_file_name_p); + jerry_cleanup (); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + fwrite (literal_buffer, sizeof (uint8_t), lit_buf_sz, file_p); + fclose (file_p); + + printf ("Literals are saved into '%s' (%lu bytes).\n", literals_file_name_p, lit_buf_sz); + + jerry_cleanup (); + return JERRY_STANDALONE_EXIT_CODE_OK; +} /* process_literal_dump */ /** * Merge command line option IDs @@ -452,8 +598,6 @@ process_merge (cli_state_t *cli_state_p, /**< cli state */ int argc, /**< number of arguments */ char *prog_name_p) /**< program name */ { - jerry_init (JERRY_INIT_EMPTY); - uint8_t *input_pos_p = input_buffer; cli_change_opts (cli_state_p, merge_opts); @@ -514,36 +658,43 @@ process_merge (cli_state_t *cli_state_p, /**< cli state */ if (number_of_files < 2) { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: at least two input files must be passed.\n"); - return JERRY_STANDALONE_EXIT_CODE_FAIL; } - const char *error_p; - size_t size = jerry_merge_snapshots (merge_buffers, - merge_buffer_sizes, - number_of_files, - output_buffer, - JERRY_BUFFER_SIZE, - &error_p); + jerry_init (JERRY_INIT_EMPTY); - if (size == 0) + const char *error_p = NULL; + size_t merged_snapshot_size = jerry_merge_snapshots (merge_buffers, + merge_buffer_sizes, + number_of_files, + output_buffer, + JERRY_BUFFER_SIZE, + &error_p); + + if (merged_snapshot_size == 0) { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", error_p); + jerry_cleanup (); return JERRY_STANDALONE_EXIT_CODE_FAIL; } FILE *file_p = fopen (output_file_name_p, "wb"); - if (file_p != NULL) - { - fwrite (output_buffer, 1u, size, file_p); - fclose (file_p); - } - else + if (file_p == NULL) { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: cannot open file: '%s'\n", output_file_name_p); + jerry_cleanup (); + return JERRY_STANDALONE_EXIT_CODE_FAIL; } + fwrite (output_buffer, 1u, merged_snapshot_size, file_p); + fclose (file_p); + + printf ("Merge is completed. Merged snapshot is saved into '%s' (%lu bytes).\n", + output_file_name_p, + merged_snapshot_size); + + jerry_cleanup (); return JERRY_STANDALONE_EXIT_CODE_OK; } /* process_merge */ @@ -576,6 +727,7 @@ print_commands (char *prog_name_p) /**< program name */ printf ("\nAvailable commands:\n" " generate\n" + " litdump\n" " merge\n" "\nPassing -h or --help after a command displays its help.\n"); } /* print_commands */ @@ -613,6 +765,10 @@ main (int argc, /**< number of arguments */ { return process_merge (&cli_state, argc, argv[0]); } + else if (!strcmp ("litdump", command_p)) + { + return process_literal_dump (&cli_state, argc, argv[0]); + } else if (!strcmp ("generate", command_p)) { return process_generate (&cli_state, argc, argv[0]); diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index 6d11bfb13..f91ae85de 100644 --- a/tests/unit-core/test-snapshot.c +++ b/tests/unit-core/test-snapshot.c @@ -23,6 +23,11 @@ */ #define SNAPSHOT_BUFFER_SIZE (256) +/** + * Maximum size of literal buffer + */ +#define LITERAL_BUFFER_SIZE (256) + /** * Magic strings */ @@ -370,16 +375,32 @@ main (void) /* C format generation */ jerry_init (JERRY_INIT_EMPTY); - static uint32_t literal_buffer_c[SNAPSHOT_BUFFER_SIZE]; + static jerry_char_t literal_buffer_c[LITERAL_BUFFER_SIZE]; + static uint32_t literal_snapshot_buffer[SNAPSHOT_BUFFER_SIZE]; static const char *code_for_c_format_p = "var object = { aa:'fo o', Bb:'max', aaa:'xzy0' };"; - size_t literal_sizes_c_format = jerry_parse_and_save_literals ((jerry_char_t *) code_for_c_format_p, - strlen (code_for_c_format_p), - false, - literal_buffer_c, - SNAPSHOT_BUFFER_SIZE, - true); - TEST_ASSERT (literal_sizes_c_format == 200); + jerry_value_t generate_result; + generate_result = jerry_generate_snapshot (NULL, + 0, + (const jerry_char_t *) code_for_c_format_p, + strlen (code_for_c_format_p), + 0, + literal_snapshot_buffer, + SNAPSHOT_BUFFER_SIZE); + + TEST_ASSERT (!jerry_value_is_error (generate_result) + && jerry_value_is_number (generate_result)); + + size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); + jerry_release_value (generate_result); + TEST_ASSERT (snapshot_size == 120); + + const size_t lit_c_buf_sz = jerry_get_literals_from_snapshot (literal_snapshot_buffer, + snapshot_size, + literal_buffer_c, + LITERAL_BUFFER_SIZE, + true); + TEST_ASSERT (lit_c_buf_sz == 200); static const char *expected_c_format = ( "jerry_length_t literal_count = 4;\n\n" @@ -399,24 +420,18 @@ main (void) "};\n" ); - TEST_ASSERT (!strncmp ((char *) literal_buffer_c, expected_c_format, literal_sizes_c_format)); - jerry_cleanup (); + TEST_ASSERT (!strncmp ((char *) literal_buffer_c, expected_c_format, lit_c_buf_sz)); /* List format generation */ - jerry_init (JERRY_INIT_EMPTY); + static jerry_char_t literal_buffer_list[LITERAL_BUFFER_SIZE]; + const size_t lit_list_buf_sz = jerry_get_literals_from_snapshot (literal_snapshot_buffer, + snapshot_size, + literal_buffer_list, + LITERAL_BUFFER_SIZE, + false); - static uint32_t literal_buffer_list[SNAPSHOT_BUFFER_SIZE]; - static const char *code_for_list_format_p = "var obj = { a:'aa', bb:'Bb' };"; - - size_t literal_sizes_list_format = jerry_parse_and_save_literals ((jerry_char_t *) code_for_list_format_p, - strlen (code_for_list_format_p), - false, - literal_buffer_list, - SNAPSHOT_BUFFER_SIZE, - false); - - TEST_ASSERT (literal_sizes_list_format == 25); - TEST_ASSERT (!strncmp ((char *) literal_buffer_list, "1 a\n2 Bb\n2 aa\n2 bb\n3 obj\n", literal_sizes_list_format)); + TEST_ASSERT (lit_list_buf_sz == 30); + TEST_ASSERT (!strncmp ((char *) literal_buffer_list, "2 Bb\n2 aa\n3 aaa\n4 fo o\n4 xzy0\n", lit_list_buf_sz)); jerry_cleanup (); }