Improve API of literal save and the snapshot (command line) tool (#2507)

Removed 'jerry_parse_and_save_literals' and introduced
'jerry_get_literals_from_snapshot' instead which works
on snapshot buffers rather than source code. Added literal
saving feature to snapshot merge in the snapshot command
line tool. Also added missing 'jerry_cleanup()' calls to the
snapshot tool. Improved the console messages of the snapshot
tool.

Based on previous work of Tamas Zakor <ztamas@inf.u-szeged.hu>

JerryScript-DCO-1.0-Signed-off-by: László Langó llango.u-szeged@partner.samsung.com
This commit is contained in:
László Langó
2018-09-06 13:45:15 +02:00
committed by Akos Kiss
parent 054717fd29
commit 99c9a22b78
5 changed files with 360 additions and 186 deletions
+220 -64
View File
@@ -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]);