Move snapshot generation function to the snapshot tool (#2057)

Now there is a snapshot tool which can merge snapshots
but was unable to generate snapshots by itself.

This change moves the snapshot generation utilities
to the snapshot tool.

JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com
This commit is contained in:
Péter Gál
2017-11-05 18:37:27 +01:00
committed by Akos Kiss
parent ee24965bcf
commit 8ae659227e
4 changed files with 302 additions and 145 deletions
+276 -22
View File
@@ -17,6 +17,7 @@
#include "jerryscript.h"
#include "jerryscript-port.h"
#include "jerryscript-port-default.h"
#include "cli.h"
@@ -33,6 +34,52 @@
static uint8_t input_buffer[ JERRY_BUFFER_SIZE ];
static uint32_t output_buffer[ JERRY_BUFFER_SIZE / 4 ];
static const char *output_file_name_p = "js.snapshot";
/**
* Check whether JerryScript has a requested feature enabled or not. If not,
* print a warning message.
*
* @return the status of the feature.
*/
static bool
check_feature (jerry_feature_t feature, /**< feature to check */
const char *option) /**< command line option that triggered this check */
{
if (!jerry_is_feature_enabled (feature))
{
jerry_port_default_set_log_level (JERRY_LOG_LEVEL_WARNING);
jerry_port_log (JERRY_LOG_LEVEL_WARNING, "Ignoring '%s' option because this feature is disabled!\n", option);
return false;
}
return true;
} /* check_feature */
/**
* Utility method to check and print error in the given cli state.
*
* @return true - if any error is detected
* false - if there is no error in the cli state
*/
static bool
check_cli_error (const cli_state_t *const cli_state_p)
{
if (cli_state_p->error != NULL)
{
if (cli_state_p->arg != NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s %s\n", cli_state_p->error, cli_state_p->arg);
}
else
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", cli_state_p->error);
}
return true;
}
return false;
} /* check_cli_error */
/**
* Loading a single file into the memory.
@@ -73,6 +120,227 @@ read_file (uint8_t *input_pos_p, /**< next position in the input buffer */
return bytes_read;
} /* read_file */
/**
* Generate command line option IDs
*/
typedef enum
{
OPT_GENERATE_HELP,
OPT_GENERATE_CONTEXT,
OPT_GENERATE_SHOW_OP,
OPT_GENERATE_LITERAL_LIST,
OPT_GENERATE_LITERAL_C,
OPT_GENERATE_OUT,
} generate_opt_id_t;
/**
* Generate command line options
*/
static const cli_opt_t generate_opts[] =
{
CLI_OPT_DEF (.id = OPT_GENERATE_HELP, .opt = "h", .longopt = "help",
.help = "print this help and exit"),
CLI_OPT_DEF (.id = OPT_GENERATE_SHOW_OP, .longopt = "show-opcodes",
.help = "print generated opcodes"),
CLI_OPT_DEF (.id = OPT_GENERATE_CONTEXT, .opt = "c", .longopt = "context",
.meta = "MODE",
.help = "specify the execution context of the snapshot: "
"global or eval (default: global)."),
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_OUT, .opt = "o", .meta="FILE",
.help = "specify output file name (default: js.snapshot)"),
CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE",
.help = "input snapshot file")
};
/**
* Process 'generate' command.
*
* @return error code (0 - no error)
*/
static int
process_generate (cli_state_t *cli_state_p, /**< cli state */
int argc, /**< number of arguments */
char *prog_name_p) /**< program name */
{
(void) argc;
bool is_save_literals_mode_in_c_format = false;
bool is_snapshot_mode_for_global = true;
jerry_init_flag_t flags = JERRY_INIT_EMPTY;
uint32_t number_of_files = 0;
uint8_t *source_p = input_buffer;
size_t source_length = 0;
const char *save_literals_file_name_p = NULL;
cli_change_opts (cli_state_p, generate_opts);
for (int id = cli_consume_option (cli_state_p); id != CLI_OPT_END; id = cli_consume_option (cli_state_p))
{
switch (id)
{
case OPT_GENERATE_HELP:
{
cli_help (prog_name_p, "generate", generate_opts);
return JERRY_STANDALONE_EXIT_CODE_OK;
}
case OPT_GENERATE_OUT:
{
output_file_name_p = cli_consume_string (cli_state_p);
break;
}
case OPT_GENERATE_LITERAL_LIST:
case OPT_GENERATE_LITERAL_C:
{
if (save_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_save_literals_mode_in_c_format = (id == OPT_GENERATE_LITERAL_C);
save_literals_file_name_p = cli_consume_string (cli_state_p);
break;
}
case OPT_GENERATE_SHOW_OP:
{
if (check_feature (JERRY_FEATURE_PARSER_DUMP, cli_state_p->arg))
{
jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG);
flags |= JERRY_INIT_SHOW_OPCODES;
}
break;
}
case OPT_GENERATE_CONTEXT:
{
const char *mode_str_p = cli_consume_string (cli_state_p);
if (cli_state_p->error != NULL)
{
break;
}
if (!strcmp ("global", mode_str_p))
{
is_snapshot_mode_for_global = true;
}
else if (!strcmp ("eval", mode_str_p))
{
is_snapshot_mode_for_global = false;
}
else
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Incorrect argument for context mode: %s\n", mode_str_p);
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
break;
}
case CLI_OPT_DEFAULT:
{
const char *file_name_p = cli_consume_string (cli_state_p);
if (cli_state_p->error == NULL)
{
source_length = read_file (source_p, file_name_p);
if (source_length == 0)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Input file is empty\n");
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
number_of_files++;
}
break;
}
default:
{
cli_state_p->error = "Internal error";
break;
}
}
}
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: No input file specified!\n");
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
jerry_init (flags);
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");
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
size_t snapshot_size = jerry_parse_and_save_snapshot ((jerry_char_t *) source_p,
source_length,
is_snapshot_mode_for_global,
false,
output_buffer,
sizeof (output_buffer) / sizeof (uint32_t));
if (snapshot_size == 0)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Generating snapshot failed!\n");
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
FILE *snapshot_file_p = fopen (output_file_name_p, "w");
if (snapshot_file_p == NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Unable to write snapshot file: '%s'\n", output_file_name_p);
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
fwrite (output_buffer, sizeof (uint8_t), snapshot_size, snapshot_file_p);
fclose (snapshot_file_p);
printf ("Created snapshot file: '%s' (%lu bytes)\n", output_file_name_p, (unsigned long) snapshot_size);
if (save_literals_file_name_p != NULL)
{
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)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Literal saving failed!\n");
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
FILE *literal_file_p = fopen (save_literals_file_name_p, "w");
if (literal_file_p == NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Unable to write literal file: '%s'\n", save_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", save_literals_file_name_p, (unsigned long) literal_buffer_size);
}
return 0;
} /* process_generate */
/**
* Merge command line option IDs
*/
@@ -90,7 +358,7 @@ static const cli_opt_t merge_opts[] =
CLI_OPT_DEF (.id = OPT_MERGE_HELP, .opt = "h", .longopt = "help",
.help = "print this help and exit"),
CLI_OPT_DEF (.id = OPT_MERGE_OUT, .opt = "o",
.help = "specify output file name (default: merged.snapshot)"),
.help = "specify output file name (default: js.snapshot)"),
CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE",
.help = "input snapshot files, minimum two")
};
@@ -111,7 +379,6 @@ process_merge (cli_state_t *cli_state_p, /**< cli state */
cli_change_opts (cli_state_p, merge_opts);
const char *output_file_name_p = "merged.snapshot";
const uint32_t *merge_buffers[argc];
size_t merge_buffer_sizes[argc];
uint32_t number_of_files = 0;
@@ -160,17 +427,8 @@ process_merge (cli_state_t *cli_state_p, /**< cli state */
}
}
if (cli_state_p->error != NULL)
if (check_cli_error (cli_state_p))
{
if (cli_state_p->arg != NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s %s\n", cli_state_p->error, cli_state_p->arg);
}
else
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", cli_state_p->error);
}
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
@@ -238,6 +496,7 @@ print_commands (char *prog_name_p) /**< program name */
cli_help (prog_name_p, NULL, main_opts);
printf ("\nAvailable commands:\n"
" generate\n"
" merge\n"
"\nPassing -h or --help after a command displays its help.\n");
} /* print_commands */
@@ -275,6 +534,10 @@ main (int argc, /**< number of arguments */
{
return process_merge (&cli_state, argc, argv[0]);
}
else if (!strcmp ("generate", command_p))
{
return process_generate (&cli_state, argc, argv[0]);
}
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: unknown command: %s\n\n", command_p);
print_commands (argv[0]);
@@ -289,17 +552,8 @@ main (int argc, /**< number of arguments */
}
}
if (cli_state.error != NULL)
if (check_cli_error (&cli_state))
{
if (cli_state.arg != NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s %s\n", cli_state.error, cli_state.arg);
}
else
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", cli_state.error);
}
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
+10 -114
View File
@@ -314,10 +314,6 @@ typedef enum
OPT_DEBUG_SERVER,
OPT_DEBUG_PORT,
OPT_DEBUGGER_WAIT_SOURCE,
OPT_SAVE_SNAP_GLOBAL,
OPT_SAVE_SNAP_EVAL,
OPT_SAVE_LIT_LIST,
OPT_SAVE_LIT_C,
OPT_EXEC_SNAP,
OPT_EXEC_SNAP_FUNC,
OPT_LOG_LEVEL,
@@ -348,14 +344,6 @@ static const cli_opt_t main_opts[] =
.help = "debug server port (default: 5001)"),
CLI_OPT_DEF (.id = OPT_DEBUGGER_WAIT_SOURCE, .longopt = "debugger-wait-source",
.help = "wait for an executable source from the client"),
CLI_OPT_DEF (.id = OPT_SAVE_SNAP_GLOBAL, .longopt = "save-snapshot-for-global", .meta = "FILE",
.help = "save binary snapshot of parsed JS input (for execution in global context)"),
CLI_OPT_DEF (.id = OPT_SAVE_SNAP_EVAL, .longopt = "save-snapshot-for-eval", .meta = "FILE",
.help = "save binary snapshot of parsed JS input (for execution in local context by eval)"),
CLI_OPT_DEF (.id = OPT_SAVE_LIT_LIST, .longopt = "save-literals-list-format", .meta = "FILE",
.help = "export literals found in parsed JS input (in list format)"),
CLI_OPT_DEF (.id = OPT_SAVE_LIT_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_EXEC_SNAP, .longopt = "exec-snapshot", .meta = "FILE",
.help = "execute input snapshot file(s)"),
CLI_OPT_DEF (.id = OPT_EXEC_SNAP_FUNC, .longopt = "exec-snapshot-func", .meta = "FILE NUM",
@@ -435,13 +423,6 @@ main (int argc,
int exec_snapshots_count = 0;
bool is_parse_only = false;
bool is_save_snapshot_mode = false;
bool is_save_snapshot_mode_for_global_or_eval = false;
const char *save_snapshot_file_name_p = NULL;
bool is_save_literals_mode = false;
bool is_save_literals_mode_in_c_format_or_list = false;
const char *save_literals_file_name_p = NULL;
bool start_debug_server = false;
uint16_t debug_port = 5001;
@@ -521,30 +502,6 @@ main (int argc,
}
break;
}
case OPT_SAVE_SNAP_GLOBAL:
case OPT_SAVE_SNAP_EVAL:
{
check_usage (save_snapshot_file_name_p == NULL, argv[0], "Error: snapshot file name already specified", NULL);
if (check_feature (JERRY_FEATURE_SNAPSHOT_SAVE, cli_state.arg))
{
is_save_snapshot_mode = true;
is_save_snapshot_mode_for_global_or_eval = (id == OPT_SAVE_SNAP_GLOBAL);
}
save_snapshot_file_name_p = cli_consume_string (&cli_state);
break;
}
case OPT_SAVE_LIT_LIST:
case OPT_SAVE_LIT_C:
{
check_usage (save_literals_file_name_p == NULL, argv[0], "Error: literal file name already specified", NULL);
if (check_feature (JERRY_FEATURE_SNAPSHOT_SAVE, cli_state.arg))
{
is_save_literals_mode = true;
is_save_literals_mode_in_c_format_or_list = (id == OPT_SAVE_LIT_C);
}
save_literals_file_name_p = cli_consume_string (&cli_state);
break;
}
case OPT_EXEC_SNAP:
{
if (check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg))
@@ -617,20 +574,6 @@ main (int argc,
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
if (is_save_snapshot_mode)
{
check_usage (files_counter == 1,
argv[0], "Error: --save-snapshot-* options work with exactly one script", NULL);
check_usage (exec_snapshots_count == 0,
argv[0], "Error: --save-snapshot-* and --exec-snapshot options can't be passed simultaneously", NULL);
}
if (is_save_literals_mode)
{
check_usage (files_counter == 1,
argv[0], "Error: --save-literals-* options work with exactly one script", NULL);
}
if (files_counter == 0
&& exec_snapshots_count == 0)
{
@@ -701,64 +644,17 @@ main (int argc,
break;
}
if (is_save_snapshot_mode || is_save_literals_mode)
ret_value = jerry_parse_named_resource ((jerry_char_t *) file_names[i],
strlen (file_names[i]),
source_p,
source_size,
false);
if (!jerry_value_has_error_flag (ret_value) && !is_parse_only)
{
static uint32_t snapshot_save_buffer[ JERRY_SNAPSHOT_BUFFER_SIZE ];
if (is_save_snapshot_mode)
{
size_t snapshot_size = jerry_parse_and_save_snapshot ((jerry_char_t *) source_p,
source_size,
is_save_snapshot_mode_for_global_or_eval,
false,
snapshot_save_buffer,
JERRY_SNAPSHOT_BUFFER_SIZE);
if (snapshot_size == 0)
{
ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "Snapshot saving failed!");
}
else
{
FILE *snapshot_file_p = fopen (save_snapshot_file_name_p, "w");
fwrite (snapshot_save_buffer, sizeof (uint8_t), snapshot_size, snapshot_file_p);
fclose (snapshot_file_p);
}
}
if (!jerry_value_has_error_flag (ret_value) && is_save_literals_mode)
{
const size_t literal_buffer_size = jerry_parse_and_save_literals ((jerry_char_t *) source_p,
source_size,
false,
snapshot_save_buffer,
JERRY_SNAPSHOT_BUFFER_SIZE,
is_save_literals_mode_in_c_format_or_list);
if (literal_buffer_size == 0)
{
ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "Literal saving failed!");
}
else
{
FILE *literal_file_p = fopen (save_literals_file_name_p, "w");
fwrite (snapshot_save_buffer, sizeof (uint8_t), literal_buffer_size, literal_file_p);
fclose (literal_file_p);
}
}
}
else
{
ret_value = jerry_parse_named_resource ((jerry_char_t *) file_names[i],
strlen (file_names[i]),
source_p,
source_size,
false);
if (!jerry_value_has_error_flag (ret_value) && !is_parse_only)
{
jerry_value_t func_val = ret_value;
ret_value = jerry_run (func_val);
jerry_release_value (func_val);
}
jerry_value_t func_val = ret_value;
ret_value = jerry_run (func_val);
jerry_release_value (func_val);
}
if (jerry_value_has_error_flag (ret_value))
+6 -6
View File
@@ -59,10 +59,10 @@ JERRY_TESTS_OPTIONS = [
Options('jerry_tests-debug-cpointer_32bit',
['--debug', '--cpointer-32bit=on', '--mem-heap=1024']),
Options('jerry_tests-snapshot',
['--snapshot-save=on', '--snapshot-exec=on'],
['--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
['--snapshot']),
Options('jerry_tests-debug-snapshot',
['--debug', '--snapshot-save=on', '--snapshot-exec=on'],
['--debug', '--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
['--snapshot']),
Options('jerry_tests-es2015-subset-debug',
['--debug', '--profile=es2015-subset']),
@@ -76,20 +76,20 @@ JERRY_TEST_SUITE_OPTIONS.extend([
Options('jerry_test_suite-minimal',
['--profile=minimal']),
Options('jerry_test_suite-minimal-snapshot',
['--profile=minimal', '--snapshot-save=on', '--snapshot-exec=on'],
['--profile=minimal', '--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
['--snapshot']),
Options('jerry_test_suite-minimal-debug',
['--debug', '--profile=minimal']),
Options('jerry_test_suite-minimal-debug-snapshot',
['--debug', '--profile=minimal', '--snapshot-save=on', '--snapshot-exec=on'],
['--debug', '--profile=minimal', '--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
['--snapshot']),
Options('jerry_test_suite-es2015-subset',
['--profile=es2015-subset']),
Options('jerry_test_suite-es2015-subset-snapshot',
['--profile=es2015-subset', '--snapshot-save=on', '--snapshot-exec=on'],
['--profile=es2015-subset', '--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
['--snapshot']),
Options('jerry_test_suite-es2015-subset-debug-snapshot',
['--debug', '--profile=es2015-subset', '--snapshot-save=on', '--snapshot-exec=on'],
['--debug', '--profile=es2015-subset', '--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'],
['--snapshot'])
])
+10 -3
View File
@@ -49,7 +49,14 @@ then
TEST_FILES="$TEST_FILES.snapshot"
TEST_FAILED="$TEST_FAILED.snapshot"
TEST_PASSED="$TEST_PASSED.snapshot"
IS_SNAPSHOT=true;
IS_SNAPSHOT=true
SNAPSHOT_TOOL=${ENGINE}-snapshot
if [ ! -x $SNAPSHOT_TOOL ]
then
echo "$0: $SNAPSHOT_TOOL: not an executable"
exit 1
fi
shift
fi
@@ -134,8 +141,8 @@ do
# Testing snapshot
SNAPSHOT_TEMP=`mktemp $(basename -s .js $test).snapshot.XXXXXXXXXX`
cmd_line="${ENGINE#$ROOT_DIR} $ENGINE_ARGS --save-snapshot-for-global $SNAPSHOT_TEMP ${full_test#$ROOT_DIR}"
$TIMEOUT_CMD $TIMEOUT $ENGINE $ENGINE_ARGS --save-snapshot-for-global $SNAPSHOT_TEMP $full_test &> $ENGINE_TEMP
cmd_line="${SNAPSHOT_TOOL#$ROOT_DIR} generate --context global -o $SNAPSHOT_TEMP ${full_test#$ROOT_DIR}"
$TIMEOUT_CMD $TIMEOUT $SNAPSHOT_TOOL generate --context global -o $SNAPSHOT_TEMP $full_test &> $ENGINE_TEMP
status_code=$?
if [ $status_code -eq 0 ]