forked from xuos/xiuos
860 lines
25 KiB
C
860 lines
25 KiB
C
/* Copyright JS Foundation and other contributors, http://js.foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "jerryscript.h"
|
|
#include "jerryscript-port.h"
|
|
#include "jerryscript-port-default.h"
|
|
|
|
#include "cli.h"
|
|
|
|
/**
|
|
* Maximum size for loaded snapshots
|
|
*/
|
|
#define JERRY_BUFFER_SIZE (1048576)
|
|
|
|
/**
|
|
* Maximum number of loaded literals
|
|
*/
|
|
#define JERRY_LITERAL_LENGTH (4096)
|
|
|
|
/**
|
|
* Standalone Jerry exit codes
|
|
*/
|
|
#define JERRY_STANDALONE_EXIT_CODE_OK (0)
|
|
#define JERRY_STANDALONE_EXIT_CODE_FAIL (1)
|
|
|
|
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];
|
|
|
|
#if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1)
|
|
/**
|
|
* The alloc function passed to jerry_create_context
|
|
*/
|
|
static void *
|
|
context_alloc (size_t size,
|
|
void *cb_data_p)
|
|
{
|
|
(void) cb_data_p; /* unused */
|
|
return malloc (size);
|
|
} /* context_alloc */
|
|
|
|
/**
|
|
* Create and set the default external context.
|
|
*/
|
|
static void
|
|
context_init (void)
|
|
{
|
|
jerry_context_t *context_p = jerry_create_context (JERRY_GLOBAL_HEAP_SIZE * 1024, context_alloc, NULL);
|
|
jerry_port_default_set_current_context (context_p);
|
|
} /* context_init */
|
|
|
|
#endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* @return size of file - if loading is successful
|
|
* 0 - otherwise
|
|
*/
|
|
static size_t
|
|
read_file (uint8_t *input_pos_p, /**< next position in the input buffer */
|
|
const char *file_name) /**< file name */
|
|
{
|
|
FILE *file = fopen (file_name, "rb");
|
|
|
|
if (file == NULL)
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to open file: %s\n", file_name);
|
|
return 0;
|
|
}
|
|
|
|
size_t max_size = (size_t) (input_buffer + JERRY_BUFFER_SIZE - input_pos_p);
|
|
|
|
size_t bytes_read = fread (input_pos_p, 1u, max_size, file);
|
|
fclose (file);
|
|
|
|
if (bytes_read == 0)
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to read file: %s\n", file_name);
|
|
return 0;
|
|
}
|
|
|
|
if (bytes_read == max_size)
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: file too large: %s\n", file_name);
|
|
return 0;
|
|
}
|
|
|
|
printf ("Input file '%s' (%zu bytes) loaded.\n", file_name, bytes_read);
|
|
return bytes_read;
|
|
} /* read_file */
|
|
|
|
/**
|
|
* Print error value
|
|
*/
|
|
static void
|
|
print_unhandled_exception (jerry_value_t error_value) /**< error value */
|
|
{
|
|
assert (!jerry_value_is_error (error_value));
|
|
|
|
jerry_value_t err_str_val = jerry_value_to_string (error_value);
|
|
|
|
if (jerry_value_is_error (err_str_val))
|
|
{
|
|
/* Avoid recursive error throws. */
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Snapshot error: [value cannot be converted to string]\n");
|
|
jerry_release_value (err_str_val);
|
|
return;
|
|
}
|
|
|
|
jerry_size_t err_str_size = jerry_get_utf8_string_size (err_str_val);
|
|
|
|
if (err_str_size >= 256)
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Snapshot error: [value cannot be converted to string]\n");
|
|
jerry_release_value (err_str_val);
|
|
return;
|
|
}
|
|
|
|
jerry_char_t err_str_buf[256];
|
|
jerry_size_t string_end = jerry_string_to_utf8_char_buffer (err_str_val, err_str_buf, err_str_size);
|
|
assert (string_end == err_str_size);
|
|
err_str_buf[string_end] = 0;
|
|
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Snapshot error: %s\n", (char *) err_str_buf);
|
|
jerry_release_value (err_str_val);
|
|
} /* print_unhandled_exception */
|
|
|
|
/**
|
|
* Generate command line option IDs
|
|
*/
|
|
typedef enum
|
|
{
|
|
OPT_GENERATE_HELP,
|
|
OPT_GENERATE_STATIC,
|
|
OPT_GENERATE_SHOW_OP,
|
|
OPT_GENERATE_FUNCTION,
|
|
OPT_GENERATE_OUT,
|
|
OPT_IMPORT_LITERAL_LIST
|
|
} 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_STATIC, .opt = "s", .longopt = "static",
|
|
.help = "generate static snapshot"),
|
|
CLI_OPT_DEF (.id = OPT_GENERATE_FUNCTION, .opt = "f", .longopt = "generate-function-snapshot",
|
|
.meta = "ARGUMENTS",
|
|
.help = "generate function snapshot with given arguments"),
|
|
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_SHOW_OP, .longopt = "show-opcodes",
|
|
.help = "print generated opcodes"),
|
|
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 source 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;
|
|
|
|
uint32_t snapshot_flags = 0;
|
|
jerry_init_flag_t flags = JERRY_INIT_EMPTY;
|
|
|
|
const char *file_name_p = NULL;
|
|
uint8_t *source_p = input_buffer;
|
|
size_t source_length = 0;
|
|
const char *literals_file_name_p = NULL;
|
|
const char *function_args_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_STATIC:
|
|
{
|
|
snapshot_flags |= JERRY_SNAPSHOT_SAVE_STATIC;
|
|
break;
|
|
}
|
|
case OPT_GENERATE_FUNCTION:
|
|
{
|
|
function_args_p = cli_consume_string (cli_state_p);
|
|
break;
|
|
}
|
|
case OPT_IMPORT_LITERAL_LIST:
|
|
{
|
|
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_OUT:
|
|
{
|
|
output_file_name_p = cli_consume_string (cli_state_p);
|
|
break;
|
|
}
|
|
case CLI_OPT_DEFAULT:
|
|
{
|
|
if (file_name_p != NULL)
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Exactly one input file must be specified\n");
|
|
return JERRY_STANDALONE_EXIT_CODE_FAIL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
cli_state_p->error = "Internal error";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (check_cli_error (cli_state_p))
|
|
{
|
|
return JERRY_STANDALONE_EXIT_CODE_FAIL;
|
|
}
|
|
|
|
if (file_name_p == NULL)
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Exactly one input file must be specified\n");
|
|
return JERRY_STANDALONE_EXIT_CODE_FAIL;
|
|
}
|
|
|
|
#if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1)
|
|
context_init ();
|
|
#endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */
|
|
|
|
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");
|
|
jerry_cleanup ();
|
|
return JERRY_STANDALONE_EXIT_CODE_FAIL;
|
|
}
|
|
|
|
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);
|
|
|
|
if (sp_buffer_size > 0)
|
|
{
|
|
const char *sp_buffer_p = (const char *) sp_buffer_start_p;
|
|
uint32_t num_of_lit = 0;
|
|
|
|
do
|
|
{
|
|
char *sp_buffer_end_p = NULL;
|
|
jerry_length_t mstr_size = (jerry_length_t) strtol (sp_buffer_p, &sp_buffer_end_p, 10);
|
|
if (mstr_size > 0)
|
|
{
|
|
magic_string_items[num_of_lit] = (jerry_char_t *) (sp_buffer_end_p + 1);
|
|
magic_string_lengths[num_of_lit] = mstr_size;
|
|
num_of_lit++;
|
|
}
|
|
sp_buffer_p = sp_buffer_end_p + mstr_size + 1;
|
|
}
|
|
while ((size_t) (sp_buffer_p - (char *) sp_buffer_start_p) < sp_buffer_size);
|
|
|
|
if (num_of_lit > 0)
|
|
{
|
|
jerry_register_magic_strings (magic_string_items, num_of_lit,
|
|
magic_string_lengths);
|
|
}
|
|
}
|
|
}
|
|
|
|
jerry_value_t snapshot_result;
|
|
|
|
if (function_args_p != NULL)
|
|
{
|
|
snapshot_result = jerry_generate_function_snapshot ((jerry_char_t *) file_name_p,
|
|
(size_t) strlen (file_name_p),
|
|
(jerry_char_t *) source_p,
|
|
source_length,
|
|
(const jerry_char_t *) function_args_p,
|
|
strlen (function_args_p),
|
|
snapshot_flags,
|
|
output_buffer,
|
|
sizeof (output_buffer) / sizeof (uint32_t));
|
|
}
|
|
else
|
|
{
|
|
snapshot_result = jerry_generate_snapshot ((jerry_char_t *) file_name_p,
|
|
(size_t) strlen (file_name_p),
|
|
(jerry_char_t *) source_p,
|
|
source_length,
|
|
snapshot_flags,
|
|
output_buffer,
|
|
sizeof (output_buffer) / sizeof (uint32_t));
|
|
}
|
|
|
|
if (jerry_value_is_error (snapshot_result))
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Generating snapshot failed!\n");
|
|
|
|
snapshot_result = jerry_get_value_from_error (snapshot_result, true);
|
|
|
|
print_unhandled_exception (snapshot_result);
|
|
|
|
jerry_release_value (snapshot_result);
|
|
jerry_cleanup ();
|
|
return JERRY_STANDALONE_EXIT_CODE_FAIL;
|
|
}
|
|
|
|
size_t snapshot_size = (size_t) jerry_get_number_value (snapshot_result);
|
|
jerry_release_value (snapshot_result);
|
|
|
|
FILE *snapshot_file_p = fopen (output_file_name_p, "wb");
|
|
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;
|
|
}
|
|
|
|
fwrite (output_buffer, sizeof (uint8_t), snapshot_size, snapshot_file_p);
|
|
fclose (snapshot_file_p);
|
|
|
|
printf ("Created snapshot file: '%s' (%zu bytes)\n", output_file_name_p, snapshot_size);
|
|
|
|
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))
|
|
{
|
|
switch (id)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1)
|
|
context_init ();
|
|
#endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */
|
|
|
|
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 (%zu 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' (%zu 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
|
|
*/
|
|
typedef enum
|
|
{
|
|
OPT_MERGE_HELP,
|
|
OPT_MERGE_OUT,
|
|
} merge_opt_id_t;
|
|
|
|
/**
|
|
* Merge command line options
|
|
*/
|
|
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: js.snapshot)"),
|
|
CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE",
|
|
.help = "input snapshot files, minimum two")
|
|
};
|
|
|
|
/**
|
|
* Process 'merge' command.
|
|
*
|
|
* @return error code (0 - no error)
|
|
*/
|
|
static int
|
|
process_merge (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, merge_opts);
|
|
|
|
JERRY_VLA (const uint32_t *, merge_buffers, argc);
|
|
JERRY_VLA (size_t, merge_buffer_sizes, argc);
|
|
uint32_t number_of_files = 0;
|
|
|
|
for (int id = cli_consume_option (cli_state_p); id != CLI_OPT_END; id = cli_consume_option (cli_state_p))
|
|
{
|
|
switch (id)
|
|
{
|
|
case OPT_MERGE_HELP:
|
|
{
|
|
cli_help (prog_name_p, "merge", merge_opts);
|
|
return JERRY_STANDALONE_EXIT_CODE_OK;
|
|
}
|
|
case OPT_MERGE_OUT:
|
|
{
|
|
output_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;
|
|
}
|
|
|
|
merge_buffers[number_of_files] = (const uint32_t *) input_pos_p;
|
|
merge_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;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (check_cli_error (cli_state_p))
|
|
{
|
|
return JERRY_STANDALONE_EXIT_CODE_FAIL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1)
|
|
context_init ();
|
|
#endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */
|
|
|
|
jerry_init (JERRY_INIT_EMPTY);
|
|
|
|
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)
|
|
{
|
|
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' (%zu bytes).\n",
|
|
output_file_name_p,
|
|
merged_snapshot_size);
|
|
|
|
jerry_cleanup ();
|
|
return JERRY_STANDALONE_EXIT_CODE_OK;
|
|
} /* process_merge */
|
|
|
|
/**
|
|
* Command line option IDs
|
|
*/
|
|
typedef enum
|
|
{
|
|
OPT_HELP,
|
|
} main_opt_id_t;
|
|
|
|
/**
|
|
* Command line options
|
|
*/
|
|
static const cli_opt_t main_opts[] =
|
|
{
|
|
CLI_OPT_DEF (.id = OPT_HELP, .opt = "h", .longopt = "help",
|
|
.help = "print this help and exit"),
|
|
CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "COMMAND",
|
|
.help = "specify the command")
|
|
};
|
|
|
|
/**
|
|
* Print available commands.
|
|
*/
|
|
static void
|
|
print_commands (char *prog_name_p) /**< program name */
|
|
{
|
|
cli_help (prog_name_p, NULL, main_opts);
|
|
|
|
printf ("\nAvailable commands:\n"
|
|
" generate\n"
|
|
" litdump\n"
|
|
" merge\n"
|
|
"\nPassing -h or --help after a command displays its help.\n");
|
|
} /* print_commands */
|
|
|
|
/**
|
|
* Main function.
|
|
*
|
|
* @return error code (0 - no error)
|
|
*/
|
|
int
|
|
main (int argc, /**< number of arguments */
|
|
char **argv) /**< argument list */
|
|
{
|
|
cli_state_t cli_state = cli_init (main_opts, argc, argv);
|
|
|
|
for (int id = cli_consume_option (&cli_state); id != CLI_OPT_END; id = cli_consume_option (&cli_state))
|
|
{
|
|
switch (id)
|
|
{
|
|
case OPT_MERGE_HELP:
|
|
{
|
|
/* Help is always printed if no command is provided. */
|
|
break;
|
|
}
|
|
case CLI_OPT_DEFAULT:
|
|
{
|
|
const char *command_p = cli_consume_string (&cli_state);
|
|
|
|
if (cli_state.error != NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!strcmp ("merge", command_p))
|
|
{
|
|
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]);
|
|
}
|
|
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: unknown command: %s\n\n", command_p);
|
|
print_commands (argv[0]);
|
|
|
|
return JERRY_STANDALONE_EXIT_CODE_FAIL;
|
|
}
|
|
default:
|
|
{
|
|
cli_state.error = "Internal error";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (check_cli_error (&cli_state))
|
|
{
|
|
return JERRY_STANDALONE_EXIT_CODE_FAIL;
|
|
}
|
|
|
|
print_commands (argv[0]);
|
|
return JERRY_STANDALONE_EXIT_CODE_OK;
|
|
} /* main */
|