From 3ed93cfb519f9749d8ba772fa080e2279d88cca5 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Wed, 11 Aug 2021 17:37:12 +0200 Subject: [PATCH] Support parsing of scripts / functions stored in string values (#4728) Function arguments must be passed as string values. Snapshots are generated from compiled code rather than source code. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- docs/02.API-REFERENCE.md | 402 +++++++----------- jerry-core/api/jerry-snapshot.c | 157 ++----- jerry-core/api/jerry.c | 176 ++++---- jerry-core/debugger/debugger.c | 6 +- jerry-core/ecma/base/ecma-globals.h | 14 +- jerry-core/ecma/base/ecma-literal-storage.c | 2 +- jerry-core/ecma/base/ecma-literal-storage.h | 2 +- .../builtin-objects/ecma-builtin-global.c | 2 +- jerry-core/ecma/operations/ecma-eval.c | 34 +- jerry-core/ecma/operations/ecma-eval.h | 4 +- .../ecma/operations/ecma-function-object.c | 16 +- jerry-core/include/jerryscript-core.h | 4 +- jerry-core/include/jerryscript-snapshot.h | 8 +- jerry-core/include/jerryscript-types.h | 11 +- jerry-core/parser/js/js-parser-internal.h | 7 +- jerry-core/parser/js/js-parser.c | 162 ++++--- jerry-core/parser/js/js-parser.h | 13 +- jerry-core/parser/js/js-scanner.c | 27 +- jerry-main/main-jerry-snapshot.c | 32 +- tests/unit-core/test-api.c | 35 +- tests/unit-core/test-regexp-dotall-unicode.c | 13 +- tests/unit-core/test-regexp.c | 13 +- tests/unit-core/test-script-user-value.c | 13 +- tests/unit-core/test-snapshot.c | 144 ++++--- 24 files changed, 601 insertions(+), 696 deletions(-) diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 211206ffb..d01fad135 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -243,6 +243,7 @@ Option bits for [jerry_parse_options_t](#jerry_parse_options_t). - JERRY_PARSE_NO_OPTS - No options passed - JERRY_PARSE_STRICT_MODE - Enable strict mode - JERRY_PARSE_MODULE - Parse source as an ECMAScript module + - JERRY_PARSE_HAS_ARGUMENT_LIST - `argument_list` field is valid - JERRY_PARSE_HAS_RESOURCE - `resource_name` field is valid - JERRY_PARSE_HAS_START - `start_line` and `start_column` fields are valid - JERRY_PARSE_HAS_USER_VALUE - `user_value` field is valid @@ -278,8 +279,7 @@ List of backtrace frame types returned by ## jerry_generate_snapshot_opts_t -Flags for [jerry_generate_snapshot](#jerry_generate_snapshot) and -[jerry_generate_function_snapshot](#jerry_generate_function_snapshot) functions: +Flags for [jerry_generate_snapshot](#jerry_generate_snapshot): - JERRY_SNAPSHOT_SAVE_STATIC - generate static snapshot (see below) @@ -540,8 +540,7 @@ Enum that contains the flags of property descriptors. **Summary** -Various configuration options for parsing functions such as [jerry_parse](#jerry_parse) -or [jerry_parse_function](#jerry_parse_function) +Various configuration options for parsing functions such as [jerry_parse](#jerry_parse). **Prototype** @@ -549,9 +548,11 @@ or [jerry_parse_function](#jerry_parse_function) typedef struct { uint32_t options; /**< combination of jerry_parse_option_enable_feature_t values */ + jerry_value_t argument_list; /**< function argument list if JERRY_PARSE_HAS_ARGUMENT_LIST is set in options + * Note: must be string value */ jerry_value_t resource_name; /**< resource name string (usually a file name) * if JERRY_PARSE_HAS_RESOURCE is set in options - * Note: non-string values are ignored */ + * Note: must be string value */ uint32_t start_line; /**< start line of the source code if JERRY_PARSE_HAS_START is set in options */ uint32_t start_column; /**< start column of the source code if JERRY_PARSE_HAS_START is set in options */ jerry_value_t user_value; /**< user value assigned to all functions created by this script including eval @@ -564,9 +565,7 @@ typedef struct **See also** - [jerry_parse](#jerry_parse) -- [jerry_parse_function](#jerry_parse_function) - [jerry_generate_snapshot](#jerry_generate_snapshot) -- [jerry_generate_function_snapshot](#jerry_generate_function_snapshot) - [jerry_exec_snapshot](#jerry_exec_snapshot) - [jerry_parse_option_enable_feature_t](#jerry_parse_option_enable_feature_t) @@ -1696,9 +1695,7 @@ main (void) **Summary** -Parse script and construct an EcmaScript function. The lexical environment is -set to the global lexical environment. The resource name can be used by -debugging systems to provide line / backtrace info. +Parse a script, module, or function and create a compiled code using a character string. *Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) when it is no longer needed. @@ -1734,6 +1731,7 @@ main (void) { jerry_init (JERRY_INIT_EMPTY); + /* Parsing a script. */ const jerry_char_t script[] = "print ('Hello, World!');"; jerry_parse_options_t parse_options; @@ -1745,6 +1743,89 @@ main (void) jerry_value_t parsed_code = jerry_parse (script, sizeof (script) - 1, &parse_options); jerry_release_value (parse_options.resource_name); + + jerry_release_value (jerry_run (parsed_code)); + jerry_release_value (parsed_code); + + /* Parsing a function. */ + parse_options.options = JERRY_PARSE_HAS_ARGUMENT_LIST; + parse_options.argument_list = jerry_create_string ((const jerry_char_t *) "a, b"); + + const jerry_char_t function_code[] = "return a + b;"; + jerry_value_t parsed_function = jerry_parse (function_code, sizeof (function_code) - 1, &parse_options); + jerry_release_value (parse_options.argument_list); + + jerry_value_t args[] = { + jerry_create_number (3), + jerry_create_number (4), + }; + jerry_size_t argc = sizeof (args) / sizeof (args[0]); + jerry_release_value (jerry_call_function (parsed_function, + jerry_create_undefined(), + args, + argc)); + jerry_release_value (parsed_function); + + jerry_cleanup (); + return 0; +} +``` + +**See also** + +- [jerry_parse_value](#jerry_parse_value) +- [jerry_run](#jerry_run) +- [jerry_parse_options_t](#jerry_parse_options_t) + +## jerry_parse_value + +**Summary** + +Parse a script, module, or function and create a compiled code using a string value. + +*Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) when it +is no longer needed. + +**Prototype** + +```c +jerry_value_t +jerry_parse_value (const jerry_value_t source_value, + const jerry_parse_options_t *options_p); +``` + +- `source_value` - string value, containing source code to parse (only string values are accepted). +- `options_p` - additional parsing options, can be NULL if not used +- return value + - function object value, if script was parsed successfully, + - thrown error, otherwise + +*New in version [[NEXT_RELEASE]]*. + +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t script_value = jerry_create_string ((const jerry_char_t *) "print ('Hello, World!');"); + + jerry_parse_options_t parse_options; + parse_options.options = JERRY_PARSE_STRICT_MODE | JERRY_PARSE_HAS_RESOURCE | JERRY_PARSE_HAS_START; + parse_options.resource_name = jerry_create_string ((const jerry_char_t *) "hello.js"); + /* This example script is extracted from the middle of a file. */ + parse_options.start_line = 10; + parse_options.start_column = 1; + + jerry_value_t parsed_code = jerry_parse_value (script_value, &parse_options); + jerry_release_value (parse_options.resource_name); + jerry_release_value (script_value); jerry_release_value (parsed_code); jerry_cleanup (); @@ -1754,120 +1835,10 @@ main (void) **See also** +- [jerry_parse](#jerry_parse) - [jerry_run](#jerry_run) -- [jerry_parse_function](#jerry_parse_function) - [jerry_parse_options_t](#jerry_parse_options_t) -## jerry_parse_function - -**Summary** - -Parse function source code and construct an ECMAScript -function. The function arguments and function body are -passed as separated arguments. The lexical environment -is set to the global lexical environment. The resource -name (usually a file name) is also passed to this function -which is used by the debugger to find the source code. - -*Note*: The returned value must be freed with [jerry_release_value](#jerry_release_value) when it -is no longer needed. - -**Prototype** - -```c -jerry_value_t -jerry_parse_function (const jerry_char_t *arg_list_p, - size_t arg_list_size, - const jerry_char_t *source_p, - size_t source_size, - const jerry_parse_options_t *options_p); -``` - -- `arg_list_p` - argument list of the function (must be a valid UTF8 string). -- `arg_list_size` - size of the argument list, in bytes. -- `source_p` - string, containing source code to parse (must be a valid UTF8 string). -- `source_size` - size of the string, in bytes. -- `options_p` - additional parsing options, can be NULL if not used -- return value - - function object value, if script was parsed successfully, - - thrown error, otherwise - -*New in version 2.0*. -*Changed in version [[NEXT_RELEASE]]*: The `resource_name_p`, `resource_name_length`, and `parse_opts` arguments are replaced by `options_p`. - -**Example** - -[doctest]: # (name="02.API-REFERENCE-parse-func.c") - -```c -#include -#include -#include "jerryscript.h" - -int -main (void) -{ - int return_value = 1; - - /* Initialize engine */ - jerry_init (JERRY_INIT_EMPTY); - - /* Parse the 'function (a,b) { return a + b; }' function */ - const char function_args[] = "a, b"; - const char function_source[] = "return a + b"; - - jerry_value_t parsed_function = jerry_parse_function ((const jerry_char_t *) function_args, - strlen (function_args), - (const jerry_char_t *) function_source, - strlen (function_source), - NULL); - - if (!jerry_value_is_error (parsed_function)) - { - /* Run the parsed function */ - jerry_value_t args[] = { - jerry_create_number (3), - jerry_create_number (55), - }; - jerry_size_t argc = sizeof (args) / sizeof (args[0]); - jerry_value_t ret_value = jerry_call_function (parsed_function, - jerry_create_undefined(), - args, - argc); - - /* Process result value */ - if (jerry_value_is_number (ret_value)) { - double value = jerry_get_number_value (ret_value); - printf ("Function result: %lf\n", value); - - return_value = !(value == (3 + 55)); - } - - /* Release the function arguments */ - for (jerry_size_t idx = 0; idx < argc; idx++) { - jerry_release_value (args[idx]); - } - - /* Returned value must be freed */ - jerry_release_value (ret_value); - } - - /* Parsed function must be freed */ - jerry_release_value (parsed_function); - - /* Cleanup engine */ - jerry_cleanup (); - - return return_value; -} -``` - -**See also** - -- [jerry_call_function](#jerry_call_function) -- [jerry_parse_options_t](#jerry_parse_options_t) - - ## jerry_run **Summary** @@ -10429,17 +10400,13 @@ Generate snapshot from the specified source code. ```c jerry_value_t -jerry_generate_snapshot (const jerry_char_t *source_p, - size_t source_size, - const jerry_parse_options_t *options_p, +jerry_generate_snapshot (jerry_value_t compiled_code, uint32_t generate_snapshot_opts, uint32_t *buffer_p, size_t buffer_size); ``` -- `source_p` - script source, it must be a valid utf8 string. -- `source_size` - script source size, in bytes. -- `options_p` - additional parsing options, can be NULL if not used +- `compiled_code` - compiled script or function (see: [jerry_parse](#jerry_parse)). - `generate_snapshot_opts` - any combination of [jerry_generate_snapshot_opts_t](#jerry_generate_snapshot_opts_t) flags. - `buffer_p` - output buffer (aligned to 4 bytes) to save snapshot to. - `buffer_size` - the output buffer's size in bytes. @@ -10450,7 +10417,10 @@ jerry_generate_snapshot (const jerry_char_t *source_p, - thrown error, otherwise. *New in version 2.0*. -*Changed in version [[NEXT_RELEASE]]*: The `resource_name_p`, and `resource_name_length` arguments are replaced by `options_p`. + +*Changed in version [[NEXT_RELEASE]]*: The `source_p`, `source_size`, `resource_name_p`, + and `resource_name_length` arguments are replaced by `compiled_code` + which should contain a compiled ECMAScript script / function. **Example** @@ -10467,13 +10437,16 @@ main (void) static uint32_t global_mode_snapshot_buffer[256]; const jerry_char_t script_to_snapshot[] = "(function () { return 'string from snapshot'; }) ();"; - jerry_value_t generate_result; - generate_result = jerry_generate_snapshot (script_to_snapshot, - sizeof (script_to_snapshot) - 1, - NULL, - 0, - global_mode_snapshot_buffer, - sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t)); + jerry_value_t parse_result = jerry_parse (script_to_snapshot, + sizeof (script_to_snapshot) - 1, + NULL); + + size_t buffer_size = sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t); + jerry_value_t generate_result = jerry_generate_snapshot (parse_result, + 0, + global_mode_snapshot_buffer, + buffer_size); + jerry_release_value (parse_result); if (!jerry_value_is_error (generate_result)) { @@ -10489,107 +10462,12 @@ main (void) **See also** -- [jerry_init](#jerry_init) -- [jerry_cleanup](#jerry_cleanup) -- [jerry_generate_function_snapshot](#jerry_generate_function_snapshot) +- [jerry_parse](#jerry_parse) +- [jerry_parse_value](#jerry_parse_value) - [jerry_exec_snapshot](#jerry_exec_snapshot) - [jerry_parse_options_t](#jerry_parse_options_t) -## jerry_generate_function_snapshot - -**Summary** - -Generate function snapshot from the specified source code -with the given arguments. - -The function arguments and function body are -passed as separated arguments. - -*Notes*: -- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it - is no longer needed. -- This API depends on a build option (`JERRY_SNAPSHOT_SAVE`) and can be checked in runtime with - the `JERRY_FEATURE_SNAPSHOT_SAVE` feature enum value, see [jerry_is_feature_enabled](#jerry_is_feature_enabled). - If the feature is not enabled the function will return an error. - -**Prototype** - -```c -jerry_value_t -jerry_generate_function_snapshot (const jerry_char_t *source_p, - size_t source_size, - const jerry_char_t *args_p, - size_t args_size, - const jerry_parse_options_t *options_p, - uint32_t generate_snapshot_opts, - uint32_t *buffer_p, - size_t buffer_size) -``` - -- `source_p` - script source, it must be a valid utf8 string. -- `source_size` - script source size, in bytes. -- `args_p` - function arguments, it must be a valid utf8 string. -- `args_size` - function argument size, in bytes. -- `options_p` - additional parsing options, can be NULL if not used -- `generate_snapshot_opts` - any combination of [jerry_generate_snapshot_opts_t](#jerry_generate_snapshot_opts_t) flags. -- `buffer_p` - buffer (aligned to 4 bytes) to save snapshot to. -- `buffer_size` - the buffer's size in bytes. -- return value - - the size of the generated snapshot in bytes as number value, if it was generated succesfully (i.e. there - are no syntax errors in source code, buffer size is sufficient, and snapshot support is enabled in - current configuration through JERRY_SNAPSHOT_SAVE) - - thrown error, otherwise. - -*New in version 2.0*. -*Changed in version [[NEXT_RELEASE]]*: The `resource_name_p`, and `resource_name_length` arguments are replaced by `options_p`. - -**Example** - -[doctest]: # () - -```c -#include "jerryscript.h" - -int -main (void) -{ - jerry_init (JERRY_INIT_EMPTY); - - static uint32_t func_snapshot_buffer[256]; - const jerry_char_t args[] = "a, b"; - const jerry_char_t src[] = "return a + b;"; - - jerry_value_t generate_result; - generate_result = jerry_generate_function_snapshot (src, - sizeof (src) - 1, - args, - sizeof (args) - 1, - NULL, - 0, - func_snapshot_buffer, - sizeof (func_snapshot_buffer) / sizeof (uint32_t)); - - if (!jerry_value_is_error (generate_result)) - { - size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); - } - - jerry_release_value (generate_result); - - jerry_cleanup (); - return 0; -} -``` - -**See also** - -- [jerry_init](#jerry_init) -- [jerry_cleanup](#jerry_cleanup) -- [jerry_generate_snapshot](#jerry_generate_snapshot) -- [jerry_parse_options_t](#jerry_parse_options_t) - - ## jerry_exec_snapshot **Summary** @@ -10645,13 +10523,17 @@ main (void) const jerry_char_t script_to_snapshot[] = "(function () { return 'string from snapshot'; }) ();"; - jerry_value_t generate_result; - generate_result = jerry_generate_snapshot (script_to_snapshot, - sizeof (script_to_snapshot) - 1, - NULL, - 0, - snapshot_buffer, - sizeof (snapshot_buffer) / sizeof (uint32_t)); + jerry_value_t parse_result = jerry_parse (script_to_snapshot, + sizeof (script_to_snapshot) - 1, + NULL); + + size_t buffer_size = sizeof (snapshot_buffer) / sizeof (uint32_t); + jerry_value_t generate_result = jerry_generate_snapshot (parse_result, + 0, + snapshot_buffer, + buffer_size); + jerry_release_value (parse_result); + /* 'generate_result' variable should be checked whether it contains an error. */ size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); @@ -10689,18 +10571,24 @@ main (void) /* 2nd example: function snapshot. */ jerry_init (JERRY_INIT_EMPTY); - const jerry_char_t function_to_snapshot_args[] = "a, b"; const jerry_char_t function_to_snapshot[] = "return a + b;"; - jerry_value_t generate_result; - generate_result = jerry_generate_function_snapshot (function_to_snapshot, - sizeof (function_to_snapshot) - 1, - function_to_snapshot_args, - sizeof (function_to_snapshot_args) - 1, - NULL, - 0, - snapshot_buffer, - sizeof (snapshot_buffer) / sizeof (uint32_t)); + jerry_parse_options_t parse_options; + parse_options.options = JERRY_PARSE_HAS_ARGUMENT_LIST; + parse_options.argument_list = jerry_create_string ((const jerry_char_t *) "a, b"); + + jerry_value_t parse_result = jerry_parse (function_to_snapshot, + sizeof (function_to_snapshot) - 1, + &parse_options); + + size_t buffer_size = sizeof (snapshot_buffer) / sizeof (uint32_t); + jerry_value_t generate_result = jerry_generate_snapshot (parse_result, + 0, + snapshot_buffer, + buffer_size); + jerry_release_value (parse_result); + jerry_release_value (parse_options.argument_list); + /* 'generate_result' variable should be checked whether it contains an error. */ size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); @@ -10740,7 +10628,6 @@ main (void) - [jerry_init](#jerry_init) - [jerry_cleanup](#jerry_cleanup) - [jerry_generate_snapshot](#jerry_generate_snapshot) -- [jerry_generate_function_snapshot](#jerry_generate_function_snapshot) ## jerry_get_literals_from_snapshot @@ -10795,12 +10682,17 @@ main (void) static uint32_t snapshot_buffer[256]; const jerry_char_t script_for_literal_save[] = "var obj = { a:'aa', bb:'Bb' }"; - jerry_value_t generate_result = jerry_generate_snapshot (script_for_literal_save, - sizeof (script_for_literal_save) - 1, - NULL, + jerry_value_t parse_result = jerry_parse (script_for_literal_save, + sizeof (script_for_literal_save) - 1, + NULL); + + size_t buffer_size = sizeof (snapshot_buffer) / sizeof (uint32_t); + jerry_value_t generate_result = jerry_generate_snapshot (parse_result, 0, snapshot_buffer, - 256); + buffer_size); + jerry_release_value (parse_result); + size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); jerry_release_value (generate_result); @@ -11667,9 +11559,7 @@ main (void) **See also** - [jerry_parse](#jerry_parse) -- [jerry_parse_function](#jerry_parse_function) - [jerry_generate_snapshot](#jerry_generate_snapshot) -- [jerry_generate_function_snapshot](#jerry_generate_function_snapshot) - [jerry_exec_snapshot](#jerry_exec_snapshot) diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index 878ac7c62..4af6ca303 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -134,7 +134,7 @@ snapshot_write_to_buffer_by_offset (uint8_t *buffer_p, /**< buffer */ * @return start offset */ static uint32_t -snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */ +snapshot_add_compiled_code (const ecma_compiled_code_t *compiled_code_p, /**< compiled code */ uint8_t *snapshot_buffer_p, /**< snapshot buffer */ size_t snapshot_buffer_size, /**< snapshot buffer size */ snapshot_globals_t *globals_p) /**< snapshot globals */ @@ -328,7 +328,7 @@ static_snapshot_error_unsupported_literal (snapshot_globals_t *globals_p, /**< s * @return start offset */ static uint32_t -static_snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */ +static_snapshot_add_compiled_code (const ecma_compiled_code_t *compiled_code_p, /**< compiled code */ uint8_t *snapshot_buffer_p, /**< snapshot buffer */ size_t snapshot_buffer_size, /**< snapshot buffer size */ snapshot_globals_t *globals_p) /**< snapshot globals */ @@ -750,8 +750,6 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th #endif /* JERRY_SNAPSHOT_EXEC */ -#if JERRY_SNAPSHOT_SAVE - /** * Generate snapshot from specified source and arguments * @@ -760,28 +758,54 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th * and snapshot support is enabled in current configuration through JERRY_SNAPSHOT_SAVE), * error object otherwise */ -static jerry_value_t -jerry_generate_snapshot_with_args (const jerry_char_t *source_p, /**< script source */ - size_t source_size, /**< script source size */ - const jerry_char_t *args_p, /**< arguments string */ - size_t args_size, /**< arguments string size */ - const jerry_parse_options_t *options_p, /**< parsing options, - * can be NULL if not used */ - uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */ - uint32_t *buffer_p, /**< buffer to save snapshot to */ - size_t buffer_size) /**< the buffer's size */ +jerry_value_t +jerry_generate_snapshot (jerry_value_t compiled_code, /**< parsed script or function */ + uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */ + uint32_t *buffer_p, /**< buffer to save snapshot to */ + size_t buffer_size) /**< the buffer's size */ { +#if JERRY_SNAPSHOT_SAVE uint32_t allowed_options = JERRY_SNAPSHOT_SAVE_STATIC; - uint32_t allowed_parse_options = (JERRY_PARSE_STRICT_MODE - | JERRY_PARSE_HAS_RESOURCE - | JERRY_PARSE_HAS_START); - if ((generate_snapshot_opts & ~allowed_options) != 0 - || (options_p != NULL && (options_p->options & ~allowed_parse_options) != 0)) + if ((generate_snapshot_opts & ~allowed_options) != 0) { return jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) ecma_error_snapshot_flag_not_supported); } + const ecma_compiled_code_t *bytecode_data_p = NULL; + + if (ecma_is_value_object (compiled_code)) + { + ecma_object_t *object_p = ecma_get_object_from_value (compiled_code); + + if (ecma_object_class_is (object_p, ECMA_OBJECT_CLASS_SCRIPT)) + { + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + + bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ext_object_p->u.cls.u3.value); + } + else if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) + { + JERRY_ASSERT (!ecma_get_object_is_builtin (object_p)); + + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); + + uint16_t type = CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags); + + if (type != CBC_FUNCTION_NORMAL) + { + bytecode_data_p = NULL; + } + } + } + + if (JERRY_UNLIKELY (bytecode_data_p == NULL)) + { + return jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) ECMA_ERR_MSG ("Unsupported compiled code")); + } + snapshot_globals_t globals; const uint32_t aligned_header_size = JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t), JMEM_ALIGNMENT); @@ -791,21 +815,6 @@ jerry_generate_snapshot_with_args (const jerry_char_t *source_p, /**< script sou globals.regex_found = false; globals.class_found = false; - uint32_t status_flags = ECMA_PARSE_NO_OPTS; - - if (options_p != NULL) - { - status_flags |= (options_p->options & ECMA_PARSE_STRICT_MODE); - } - - ecma_compiled_code_t *bytecode_data_p; - bytecode_data_p = parser_parse_script (args_p, args_size, source_p, source_size, status_flags, options_p); - - if (JERRY_UNLIKELY (bytecode_data_p == NULL)) - { - return ecma_create_error_reference_from_context (); - } - if (generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STATIC) { static_snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals); @@ -817,7 +826,6 @@ jerry_generate_snapshot_with_args (const jerry_char_t *source_p, /**< script sou if (!ecma_is_value_empty (globals.snapshot_error)) { - ecma_bytecode_deref (bytecode_data_p); return globals.snapshot_error; } @@ -846,7 +854,6 @@ jerry_generate_snapshot_with_args (const jerry_char_t *source_p, /**< script sou &literals_num)) { JERRY_ASSERT (lit_map_p == NULL); - ecma_bytecode_deref (bytecode_data_p); return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) ecma_error_cannot_allocate_memory_literals); } @@ -868,43 +875,9 @@ jerry_generate_snapshot_with_args (const jerry_char_t *source_p, /**< script sou jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t)); } - ecma_bytecode_deref (bytecode_data_p); - return ecma_make_number_value ((ecma_number_t) globals.snapshot_buffer_write_offset); -} /* jerry_generate_snapshot_with_args */ - -#endif /* JERRY_SNAPSHOT_SAVE */ - -/** - * Generate snapshot from specified source and arguments - * - * @return size of snapshot (a number value), if it was generated succesfully - * (i.e. there are no syntax errors in source code, buffer size is sufficient, - * and snapshot support is enabled in current configuration through JERRY_SNAPSHOT_SAVE), - * error object otherwise - */ -jerry_value_t -jerry_generate_snapshot (const jerry_char_t *source_p, /**< script source */ - size_t source_size, /**< script source size */ - const jerry_parse_options_t *options_p, /**< parsing options, - * can be NULL if not used */ - uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */ - uint32_t *buffer_p, /**< buffer to save snapshot to */ - size_t buffer_size) /**< the buffer's size */ -{ -#if JERRY_SNAPSHOT_SAVE - return jerry_generate_snapshot_with_args (source_p, - source_size, - NULL, - 0, - options_p, - generate_snapshot_opts, - buffer_p, - buffer_size); #else /* !JERRY_SNAPSHOT_SAVE */ - JERRY_UNUSED (source_p); - JERRY_UNUSED (source_size); - JERRY_UNUSED (options_p); + JERRY_UNUSED (compiled_code); JERRY_UNUSED (generate_snapshot_opts); JERRY_UNUSED (buffer_p); JERRY_UNUSED (buffer_size); @@ -1815,45 +1788,3 @@ jerry_get_literals_from_snapshot (const uint32_t *snapshot_p, /**< input snapsho return 0; #endif /* JERRY_SNAPSHOT_SAVE */ } /* jerry_get_literals_from_snapshot */ - -/** - * Generate snapshot function from specified source and arguments - * - * @return size of snapshot (a number value), if it was generated succesfully - * (i.e. there are no syntax errors in source code, buffer size is sufficient, - * and snapshot support is enabled in current configuration through JERRY_SNAPSHOT_SAVE), - * error object otherwise - */ -jerry_value_t -jerry_generate_function_snapshot (const jerry_char_t *source_p, /**< script source */ - size_t source_size, /**< script source size */ - const jerry_char_t *args_p, /**< arguments string */ - size_t args_size, /**< arguments string size */ - const jerry_parse_options_t *options_p, /**< parsing options, - * can be NULL if not used */ - uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */ - uint32_t *buffer_p, /**< buffer to save snapshot to */ - size_t buffer_size) /**< the buffer's size */ -{ -#if JERRY_SNAPSHOT_SAVE - return jerry_generate_snapshot_with_args (source_p, - source_size, - args_p, - args_size, - options_p, - generate_snapshot_opts, - buffer_p, - buffer_size); -#else /* !JERRY_SNAPSHOT_SAVE */ - JERRY_UNUSED (source_p); - JERRY_UNUSED (source_size); - JERRY_UNUSED (args_p); - JERRY_UNUSED (args_size); - JERRY_UNUSED (options_p); - JERRY_UNUSED (generate_snapshot_opts); - JERRY_UNUSED (buffer_p); - JERRY_UNUSED (buffer_size); - - return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) "Snapshot save is not supported"); -#endif /* JERRY_SNAPSHOT_SAVE */ -} /* jerry_generate_function_snapshot */ diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index a0f059714..aeec8ea12 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -376,34 +376,43 @@ jerry_run_simple (const jerry_char_t *script_source_p, /**< script source */ return result; } /* jerry_run_simple */ +#if JERRY_PARSER + /** - * Parse script and construct an EcmaScript function. The lexical - * environment is set to the global lexical environment. + * Common code for parsing a script, module, or function. * * @return function object value - if script was parsed successfully, * thrown error - otherwise */ -jerry_value_t -jerry_parse (const jerry_char_t *source_p, /**< script source */ - size_t source_size, /**< script source size */ - const jerry_parse_options_t *options_p) /**< parsing options, can be NULL if not used */ +static jerry_value_t +jerry_parse_common (void *source_p, /**< script source */ + const jerry_parse_options_t *options_p, /**< parsing options, can be NULL if not used */ + uint32_t parse_opts) /**< internal parsing options */ { -#if JERRY_PARSER jerry_assert_api_available (); - uint32_t allowed_parse_options = (JERRY_PARSE_STRICT_MODE - | JERRY_PARSE_MODULE - | JERRY_PARSE_HAS_RESOURCE - | JERRY_PARSE_HAS_START - | JERRY_PARSE_HAS_USER_VALUE); - - if (options_p != NULL && (options_p->options & ~allowed_parse_options) != 0) + if (options_p != NULL) { - return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p))); - } -#endif /* JERRY_PARSER */ + const uint32_t allowed_options = (JERRY_PARSE_STRICT_MODE + | JERRY_PARSE_MODULE + | JERRY_PARSE_HAS_ARGUMENT_LIST + | JERRY_PARSE_HAS_RESOURCE + | JERRY_PARSE_HAS_START + | JERRY_PARSE_HAS_USER_VALUE); + uint32_t options = options_p->options; -#if JERRY_DEBUGGER && JERRY_PARSER + if ((options & ~allowed_options) != 0 + || ((options_p->options & JERRY_PARSE_HAS_ARGUMENT_LIST) + && ((options_p->options & JERRY_PARSE_MODULE) + || !ecma_is_value_string (options_p->argument_list))) + || ((options_p->options & JERRY_PARSE_HAS_RESOURCE) + && !ecma_is_value_string (options_p->resource_name))) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p))); + } + } + +#if JERRY_DEBUGGER if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && options_p != NULL && (options_p->options & JERRY_PARSE_HAS_RESOURCE) @@ -418,10 +427,7 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */ resource_name_size); ECMA_FINALIZE_UTF8_STRING (resource_name_start_p, resource_name_size); } -#endif /* JERRY_DEBUGGER && JERRY_PARSER */ - -#if JERRY_PARSER - uint32_t parse_opts = 0; +#endif /* JERRY_DEBUGGER */ if (options_p != NULL) { @@ -438,7 +444,7 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */ } ecma_compiled_code_t *bytecode_data_p; - bytecode_data_p = parser_parse_script (NULL, 0, source_p, source_size, parse_opts, options_p); + bytecode_data_p = parser_parse_script (source_p, parse_opts, options_p); if (JERRY_UNLIKELY (bytecode_data_p == NULL)) { @@ -464,6 +470,22 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */ } #endif /* JERRY_MODULE_SYSTEM */ + if (JERRY_UNLIKELY (options_p != NULL + && (options_p->options & JERRY_PARSE_HAS_ARGUMENT_LIST))) + { + ecma_object_t *global_object_p = ecma_builtin_get_global (); + +#if JERRY_BUILTIN_REALMS + JERRY_ASSERT (global_object_p == (ecma_object_t *) ecma_op_function_get_realm (bytecode_data_p)); +#endif /* JERRY_BUILTIN_REALMS */ + + ecma_object_t *lex_env_p = ecma_get_global_environment (global_object_p); + ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_data_p); + ecma_bytecode_deref (bytecode_data_p); + + return ecma_make_object_value (func_obj_p); + } + ecma_object_t *object_p = ecma_create_object (NULL, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; @@ -471,6 +493,27 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */ ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.cls.u3.value, bytecode_data_p); return ecma_make_object_value (object_p); +} /* jerry_parse_common */ + +#endif /* JERRY_PARSER */ + +/** + * Parse a script, module, or function and create a compiled code using a character string + * + * @return function object value - if script was parsed successfully, + * thrown error - otherwise + */ +jerry_value_t +jerry_parse (const jerry_char_t *source_p, /**< script source */ + size_t source_size, /**< script source size */ + const jerry_parse_options_t *options_p) /**< parsing options, can be NULL if not used */ +{ +#if JERRY_PARSER + parser_source_char_t source_char; + source_char.source_p = source_p; + source_char.source_size = source_size; + + return jerry_parse_common ((void *) &source_char, options_p, JERRY_PARSE_NO_OPTS); #else /* !JERRY_PARSER */ JERRY_UNUSED (source_p); JERRY_UNUSED (source_size); @@ -481,93 +524,32 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */ } /* jerry_parse */ /** - * Parse function and construct an EcmaScript function. The lexical - * environment is set to the global lexical environment. + * Parse a script, module, or function and create a compiled code using a string value * * @return function object value - if script was parsed successfully, * thrown error - otherwise */ jerry_value_t -jerry_parse_function (const jerry_char_t *arg_list_p, /**< script source */ - size_t arg_list_size, /**< script source size */ - const jerry_char_t *source_p, /**< script source */ - size_t source_size, /**< script source size */ - const jerry_parse_options_t *options_p) /**< parsing options, can be NULL if not used */ +jerry_parse_value (const jerry_value_t source_value, /**< script source */ + const jerry_parse_options_t *options_p) /**< parsing options, can be NULL if not used */ { #if JERRY_PARSER - jerry_assert_api_available (); - - uint32_t allowed_parse_options = (JERRY_PARSE_STRICT_MODE - | JERRY_PARSE_HAS_RESOURCE - | JERRY_PARSE_HAS_START - | JERRY_PARSE_HAS_USER_VALUE); - - if (options_p != NULL && (options_p->options & ~allowed_parse_options) != 0) + if (!ecma_is_value_string (source_value)) { return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p))); } -#endif /* JERRY_PARSER */ -#if JERRY_DEBUGGER && JERRY_PARSER - if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) - && options_p != NULL - && (options_p->options & JERRY_PARSE_HAS_RESOURCE) - && ecma_is_value_string (options_p->resource_name)) - { - ECMA_STRING_TO_UTF8_STRING (ecma_get_string_from_value (options_p->resource_name), - resource_name_start_p, - resource_name_size); - jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE_NAME, - JERRY_DEBUGGER_NO_SUBTYPE, - resource_name_start_p, - resource_name_size); - ECMA_FINALIZE_UTF8_STRING (resource_name_start_p, resource_name_size); - } -#endif /* JERRY_DEBUGGER && JERRY_PARSER */ + ecma_value_t source[1]; + source[0] = source_value; -#if JERRY_PARSER - uint32_t parse_opts = 0; - - if (options_p != NULL) - { - parse_opts |= options_p->options & JERRY_PARSE_STRICT_MODE; - } - - if (arg_list_p == NULL) - { - /* Must not be a NULL value. */ - arg_list_p = (const jerry_char_t *) ""; - } - - ecma_compiled_code_t *bytecode_p; - bytecode_p = parser_parse_script (arg_list_p, arg_list_size, source_p, source_size, parse_opts, options_p); - - if (JERRY_UNLIKELY (bytecode_p == NULL)) - { - return ecma_create_error_reference_from_context (); - } - - ecma_object_t *global_object_p = ecma_builtin_get_global (); - -#if JERRY_BUILTIN_REALMS - JERRY_ASSERT (global_object_p == (ecma_object_t *) ecma_op_function_get_realm (bytecode_p)); -#endif /* JERRY_BUILTIN_REALMS */ - - ecma_object_t *lex_env_p = ecma_get_global_environment (global_object_p); - ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_p); - ecma_bytecode_deref (bytecode_p); - - return ecma_make_object_value (func_obj_p); + return jerry_parse_common ((void *) source, options_p, ECMA_PARSE_HAS_SOURCE_VALUE); #else /* !JERRY_PARSER */ - JERRY_UNUSED (arg_list_p); - JERRY_UNUSED (arg_list_size); - JERRY_UNUSED (source_p); - JERRY_UNUSED (source_size); + JERRY_UNUSED (source_value); JERRY_UNUSED (options_p); return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG (ecma_error_parser_not_supported_p))); #endif /* JERRY_PARSER */ -} /* jerry_parse_function */ +} /* jerry_parse_value */ /** * Run a Script or Module created by jerry_parse. @@ -632,9 +614,11 @@ jerry_eval (const jerry_char_t *source_p, /**< source code */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p))); } - return jerry_return (ecma_op_eval_chars_buffer ((const lit_utf8_byte_t *) source_p, - source_size, - parse_opts)); + parser_source_char_t source_char; + source_char.source_p = source_p; + source_char.source_size = source_size; + + return jerry_return (ecma_op_eval_chars_buffer ((void *) &source_char, parse_opts)); } /* jerry_eval */ /** diff --git a/jerry-core/debugger/debugger.c b/jerry-core/debugger/debugger.c index 8e868c142..093ab24a7 100644 --- a/jerry-core/debugger/debugger.c +++ b/jerry-core/debugger/debugger.c @@ -548,7 +548,11 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s memcpy (&chain_index, eval_string_p, sizeof (uint32_t)); uint32_t parse_opts = ECMA_PARSE_DIRECT_EVAL | (chain_index << ECMA_PARSE_CHAIN_INDEX_SHIFT); - ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p + 5, eval_string_size - 5, parse_opts); + parser_source_char_t source_char; + source_char.source_p = eval_string_p + 5; + source_char.source_size = eval_string_size - 5; + + ecma_value_t result = ecma_op_eval_chars_buffer ((void *) &source_char, parse_opts); JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE); if (!ECMA_IS_VALUE_ERROR (result)) diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 813566421..aa142ed4e 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -115,12 +115,20 @@ typedef enum ECMA_PARSE_ALLOW_NEW_TARGET = (1u << 8), /**< allow new.target access */ ECMA_PARSE_FUNCTION_CONTEXT = (1u << 9), /**< function context is present (ECMA_PARSE_DIRECT_EVAL must be set) */ - ECMA_PARSE_GENERATOR_FUNCTION = (1u << 10), /**< generator function is parsed */ - ECMA_PARSE_ASYNC_FUNCTION = (1u << 11), /**< async function is parsed */ + ECMA_PARSE_HAS_SOURCE_VALUE = (1u << 10), /**< source_p points to a value list + * and the first value is the source code */ + ECMA_PARSE_HAS_ARGUMENT_LIST_VALUE = (1u << 11), /**< source_p points to a value list + * and the second value is the argument list */ +#if JERRY_ESNEXT + ECMA_PARSE_GENERATOR_FUNCTION = (1u << 12), /**< generator function is parsed */ + ECMA_PARSE_ASYNC_FUNCTION = (1u << 13), /**< async function is parsed */ +#endif /* JERRY_ESNEXT */ /* These flags are internally used by the parser. */ + ECMA_PARSE_INTERNAL_FREE_SOURCE = (1u << 14), /**< free source_p data */ + ECMA_PARSE_INTERNAL_FREE_ARG_LIST = (1u << 15), /**< free arg_list_p data */ #if JERRY_ESNEXT - ECMA_PARSE_INTERNAL_PRE_SCANNING = (1u << 12), + ECMA_PARSE_INTERNAL_PRE_SCANNING = (1u << 16), /**< the parser is in pre-scanning mode */ #endif /* JERRY_ESNEXT */ #ifndef JERRY_NDEBUG /** diff --git a/jerry-core/ecma/base/ecma-literal-storage.c b/jerry-core/ecma/base/ecma-literal-storage.c index 9ef723e0a..934a35de5 100644 --- a/jerry-core/ecma/base/ecma-literal-storage.c +++ b/jerry-core/ecma/base/ecma-literal-storage.c @@ -714,7 +714,7 @@ ecma_snapshot_get_literal (const uint8_t *literal_base_p, /**< literal start */ * @return pointer to the beginning of the serializable ecma-values */ ecma_value_t * -ecma_snapshot_resolve_serializable_values (ecma_compiled_code_t *compiled_code_p, /**< compiled code */ +ecma_snapshot_resolve_serializable_values (const ecma_compiled_code_t *compiled_code_p, /**< compiled code */ uint8_t *bytecode_end_p) /**< end of the bytecode */ { ecma_value_t *base_p = (ecma_value_t *) bytecode_end_p; diff --git a/jerry-core/ecma/base/ecma-literal-storage.h b/jerry-core/ecma/base/ecma-literal-storage.h index 118231ea8..4080e51f2 100644 --- a/jerry-core/ecma/base/ecma-literal-storage.h +++ b/jerry-core/ecma/base/ecma-literal-storage.h @@ -59,7 +59,7 @@ bool ecma_save_literals_for_snapshot (ecma_collection_t *lit_pool_p, uint32_t *b ecma_value_t ecma_snapshot_get_literal (const uint8_t *literal_base_p, ecma_value_t literal_value); ecma_value_t * -ecma_snapshot_resolve_serializable_values (ecma_compiled_code_t *compiled_code_p, uint8_t *byte_code_end_p); +ecma_snapshot_resolve_serializable_values (const ecma_compiled_code_t *compiled_code_p, uint8_t *byte_code_end_p); #endif /* JERRY_SNAPSHOT_EXEC || JERRY_SNAPSHOT_SAVE */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.c b/jerry-core/ecma/builtin-objects/ecma-builtin-global.c index 8e4b05da7..e3cc0d435 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.c @@ -107,7 +107,7 @@ ecma_builtin_global_object_eval (ecma_value_t x) /**< routine's first argument * #endif /* JERRY_ESNEXT */ /* steps 2 to 8 */ - return ecma_op_eval (ecma_get_string_from_value (x), parse_opts); + return ecma_op_eval (x, parse_opts); } /* ecma_builtin_global_object_eval */ /** diff --git a/jerry-core/ecma/operations/ecma-eval.c b/jerry-core/ecma/operations/ecma-eval.c index f58023c54..c64ccb4b3 100644 --- a/jerry-core/ecma/operations/ecma-eval.c +++ b/jerry-core/ecma/operations/ecma-eval.c @@ -41,28 +41,18 @@ * @return ecma value */ ecma_value_t -ecma_op_eval (ecma_string_t *code_p, /**< code string */ +ecma_op_eval (ecma_value_t source_code, /**< source code */ uint32_t parse_opts) /**< ecma_parse_opts_t option bits */ { - ecma_value_t ret_value; + JERRY_ASSERT (ecma_is_value_string (source_code)); - lit_utf8_size_t chars_num = ecma_string_get_size (code_p); - if (chars_num == 0) + if (ecma_is_value_magic_string (source_code, LIT_MAGIC_STRING__EMPTY)) { - ret_value = ECMA_VALUE_UNDEFINED; - } - else - { - ECMA_STRING_TO_UTF8_STRING (code_p, code_utf8_buffer_p, code_utf8_buffer_size); - - ret_value = ecma_op_eval_chars_buffer (code_utf8_buffer_p, - chars_num, - parse_opts); - - ECMA_FINALIZE_UTF8_STRING (code_utf8_buffer_p, code_utf8_buffer_size); + return ECMA_VALUE_UNDEFINED; } - return ret_value; + return ecma_op_eval_chars_buffer ((void *) &source_code, + parse_opts | ECMA_PARSE_HAS_SOURCE_VALUE); } /* ecma_op_eval */ /** @@ -75,12 +65,11 @@ ecma_op_eval (ecma_string_t *code_p, /**< code string */ * @return ecma value */ ecma_value_t -ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters buffer */ - size_t code_buffer_size, /**< size of the buffer */ +ecma_op_eval_chars_buffer (void *source_p, /**< source code */ uint32_t parse_opts) /**< ecma_parse_opts_t option bits */ { #if JERRY_PARSER - JERRY_ASSERT (code_p != NULL); + JERRY_ASSERT (source_p != NULL); uint32_t is_strict_call = ECMA_PARSE_STRICT_MODE | ECMA_PARSE_DIRECT_EVAL; @@ -95,12 +84,7 @@ ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters b ECMA_CLEAR_LOCAL_PARSE_OPTS (); #endif /* JERRY_ESNEXT */ - ecma_compiled_code_t *bytecode_p = parser_parse_script (NULL, - 0, - code_p, - code_buffer_size, - parse_opts, - NULL); + ecma_compiled_code_t *bytecode_p = parser_parse_script (source_p, parse_opts, NULL); if (JERRY_UNLIKELY (bytecode_p == NULL)) { diff --git a/jerry-core/ecma/operations/ecma-eval.h b/jerry-core/ecma/operations/ecma-eval.h index 057c4d2fa..fad3b02d2 100644 --- a/jerry-core/ecma/operations/ecma-eval.h +++ b/jerry-core/ecma/operations/ecma-eval.h @@ -26,10 +26,10 @@ */ ecma_value_t -ecma_op_eval (ecma_string_t *code_p, uint32_t parse_opts); +ecma_op_eval (ecma_value_t source_code, uint32_t parse_opts); ecma_value_t -ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, size_t code_buffer_size, uint32_t parse_opts); +ecma_op_eval_chars_buffer (void *source_p, uint32_t parse_opts); /** * @} diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 1890605a3..cfe96aba1 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -454,18 +454,14 @@ ecma_op_create_dynamic_function (const ecma_value_t *arguments_list_p, /**< argu function_body_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); } - ECMA_STRING_TO_UTF8_STRING (arguments_str_p, arguments_buffer_p, arguments_buffer_size); - ECMA_STRING_TO_UTF8_STRING (function_body_str_p, function_body_buffer_p, function_body_buffer_size); + ecma_value_t source[2]; + source[0] = ecma_make_string_value (function_body_str_p); + source[1] = ecma_make_string_value (arguments_str_p); - ecma_compiled_code_t *bytecode_p = parser_parse_script (arguments_buffer_p, - arguments_buffer_size, - function_body_buffer_p, - function_body_buffer_size, - parse_opts, - NULL); + parse_opts |= ECMA_PARSE_HAS_SOURCE_VALUE | ECMA_PARSE_HAS_ARGUMENT_LIST_VALUE; + + ecma_compiled_code_t *bytecode_p = parser_parse_script ((void *) source, parse_opts, NULL); - ECMA_FINALIZE_UTF8_STRING (function_body_buffer_p, function_body_buffer_size); - ECMA_FINALIZE_UTF8_STRING (arguments_buffer_p, arguments_buffer_size); ecma_deref_ecma_string (arguments_str_p); ecma_deref_ecma_string (function_body_str_p); diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 0e5e9f494..96161a79b 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -46,9 +46,7 @@ bool jerry_get_memory_stats (jerry_heap_stats_t *out_stats_p); bool jerry_run_simple (const jerry_char_t *script_source_p, size_t script_source_size, jerry_init_flag_t flags); jerry_value_t jerry_parse (const jerry_char_t *source_p, size_t source_size, const jerry_parse_options_t *options_p); -jerry_value_t jerry_parse_function (const jerry_char_t *arg_list_p, size_t arg_list_size, - const jerry_char_t *source_p, size_t source_size, - const jerry_parse_options_t *options_p); +jerry_value_t jerry_parse_value (const jerry_value_t source_value, const jerry_parse_options_t *options_p); jerry_value_t jerry_run (const jerry_value_t func_val); jerry_value_t jerry_eval (const jerry_char_t *source_p, size_t source_size, uint32_t parse_opts); diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index 48e39b9ff..27db4c661 100644 --- a/jerry-core/include/jerryscript-snapshot.h +++ b/jerry-core/include/jerryscript-snapshot.h @@ -70,14 +70,8 @@ typedef struct /** * Snapshot functions. */ -jerry_value_t jerry_generate_snapshot (const jerry_char_t *source_p, size_t source_size, - const jerry_parse_options_t *options_p, uint32_t generate_snapshot_opts, +jerry_value_t jerry_generate_snapshot (jerry_value_t compiled_code, uint32_t generate_snapshot_opts, uint32_t *buffer_p, size_t buffer_size); -jerry_value_t jerry_generate_function_snapshot (const jerry_char_t *source_p, size_t source_size, - const jerry_char_t *args_p, size_t args_size, - const jerry_parse_options_t *options_p, - uint32_t generate_snapshot_opts, - uint32_t *buffer_p, size_t buffer_size); jerry_value_t jerry_exec_snapshot (const uint32_t *snapshot_p, size_t snapshot_size, size_t func_index, uint32_t exec_snapshot_opts, diff --git a/jerry-core/include/jerryscript-types.h b/jerry-core/include/jerryscript-types.h index 7635597d8..707ccdc09 100644 --- a/jerry-core/include/jerryscript-types.h +++ b/jerry-core/include/jerryscript-types.h @@ -167,9 +167,10 @@ typedef enum JERRY_PARSE_NO_OPTS = 0, /**< no options passed */ JERRY_PARSE_STRICT_MODE = (1 << 0), /**< enable strict mode */ JERRY_PARSE_MODULE = (1 << 1), /**< parse source as an ECMAScript module */ - JERRY_PARSE_HAS_RESOURCE = (1 << 2), /**< resource_name field is valid */ - JERRY_PARSE_HAS_START = (1 << 3), /**< start_line and start_column fields are valid */ - JERRY_PARSE_HAS_USER_VALUE = (1 << 4), /**< user_value field is valid */ + JERRY_PARSE_HAS_ARGUMENT_LIST = (1 << 2), /**< argument_list field is valid */ + JERRY_PARSE_HAS_RESOURCE = (1 << 3), /**< resource_name field is valid */ + JERRY_PARSE_HAS_START = (1 << 4), /**< start_line and start_column fields are valid */ + JERRY_PARSE_HAS_USER_VALUE = (1 << 5), /**< user_value field is valid */ } jerry_parse_option_enable_feature_t; /** @@ -178,9 +179,11 @@ typedef enum typedef struct { uint32_t options; /**< combination of jerry_parse_option_enable_feature_t values */ + jerry_value_t argument_list; /**< function argument list if JERRY_PARSE_HAS_ARGUMENT_LIST is set in options + * Note: must be string value */ jerry_value_t resource_name; /**< resource name string (usually a file name) * if JERRY_PARSE_HAS_RESOURCE is set in options - * Note: non-string values are ignored */ + * Note: must be string value */ uint32_t start_line; /**< start line of the source code if JERRY_PARSE_HAS_START is set in options */ uint32_t start_column; /**< start column of the source code if JERRY_PARSE_HAS_START is set in options */ jerry_value_t user_value; /**< user value assigned to all functions created by this script including eval diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index d34f81f39..5f40ad3df 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -567,6 +567,10 @@ typedef struct parser_saved_context_t *last_context_p; /**< last saved context */ parser_stack_iterator_t last_statement; /**< last statement position */ cbc_script_t *script_p; /**< current script */ + const uint8_t *source_start_p; /**< source start */ + lit_utf8_size_t source_size; /**< source size */ + const uint8_t *arguments_start_p; /**< function argument list start */ + lit_utf8_size_t arguments_size; /**< function argument list size */ ecma_value_t script_value; /**< current script as value */ ecma_value_t user_value; /**< current user value */ @@ -853,8 +857,7 @@ bool scanner_literal_is_created (parser_context_t *context_p, uint16_t literal_i bool scanner_literal_exists (parser_context_t *context_p, uint16_t literal_index); #endif /* JERRY_ESNEXT */ -void scanner_scan_all (parser_context_t *context_p, const uint8_t *arg_list_p, const uint8_t *arg_list_end_p, - const uint8_t *source_p, const uint8_t *source_end_p); +void scanner_scan_all (parser_context_t *context_p); /** * @} diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index e1dac4f97..1aa476696 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1761,10 +1761,7 @@ JERRY_STATIC_ASSERT (PARSER_SCANNING_SUCCESSFUL == PARSER_HAS_LATE_LIT_INIT, * @return compiled code */ static ecma_compiled_code_t * -parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ - size_t arg_list_size, /**< size of function argument list */ - const uint8_t *source_p, /**< valid UTF-8 source code */ - size_t source_size, /**< size of the source code */ +parser_parse_source (void *source_p, /**< source code */ uint32_t parse_opts, /**< ecma_parse_opts_t option bits */ const jerry_parse_options_t *options_p) /**< additional configuration options */ { @@ -1775,6 +1772,16 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.status_flags = parse_opts & PARSER_STRICT_MODE_MASK; context.global_status_flags = parse_opts; +#if JERRY_ESNEXT + context.status_flags |= PARSER_RESTORE_STATUS_FLAGS (parse_opts); + context.tagged_template_literal_cp = JMEM_CP_NULL; +#endif /* JERRY_ESNEXT */ + + context.stack_depth = 0; + context.stack_limit = 0; + context.options_p = options_p; + context.arguments_start_p = NULL; + context.arguments_size = 0; #if JERRY_MODULE_SYSTEM if (context.global_status_flags & ECMA_PARSE_MODULE) { @@ -1784,8 +1791,23 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.module_names_p = NULL; #endif /* JERRY_MODULE_SYSTEM */ - if (arg_list_p != NULL) + ecma_value_t argument_list = ECMA_VALUE_EMPTY; + + if (context.options_p != NULL + && (context.options_p->options & JERRY_PARSE_HAS_ARGUMENT_LIST)) { + argument_list = context.options_p->argument_list; + } + else if (context.global_status_flags & ECMA_PARSE_HAS_ARGUMENT_LIST_VALUE) + { + JERRY_ASSERT (context.global_status_flags & ECMA_PARSE_HAS_SOURCE_VALUE); + argument_list = ((ecma_value_t *) source_p)[1]; + } + + if (argument_list != ECMA_VALUE_EMPTY) + { + JERRY_ASSERT (ecma_is_value_string (argument_list)); + context.status_flags |= PARSER_IS_FUNCTION; #if JERRY_ESNEXT if (parse_opts & ECMA_PARSE_GENERATOR_FUNCTION) @@ -1797,20 +1819,49 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.status_flags |= PARSER_IS_ASYNC_FUNCTION; } #endif /* JERRY_ESNEXT */ + + ecma_string_t *string_p = ecma_get_string_from_value (argument_list); + uint8_t flags = ECMA_STRING_FLAG_EMPTY; + + context.arguments_start_p = ecma_string_get_chars (string_p, &context.arguments_size, NULL, NULL, &flags); + + if (flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + context.global_status_flags |= ECMA_PARSE_INTERNAL_FREE_ARG_LIST; + } } -#if JERRY_ESNEXT - context.status_flags |= PARSER_RESTORE_STATUS_FLAGS (parse_opts); - context.tagged_template_literal_cp = JMEM_CP_NULL; -#endif /* JERRY_ESNEXT */ + if (!(context.global_status_flags & ECMA_PARSE_HAS_SOURCE_VALUE)) + { + context.source_start_p = ((parser_source_char_t *) source_p)->source_p; + context.source_size = (lit_utf8_size_t) ((parser_source_char_t *) source_p)->source_size; + } + else + { + ecma_value_t source = ((ecma_value_t *) source_p)[0]; - context.stack_depth = 0; - context.stack_limit = 0; - context.options_p = options_p; - context.last_context_p = NULL; - context.last_statement.current_p = NULL; - context.token.flags = 0; - lexer_init_line_info (&context); + JERRY_ASSERT (ecma_is_value_string (source)); + + ecma_string_t *string_p = ecma_get_string_from_value (source); + uint8_t flags = ECMA_STRING_FLAG_EMPTY; + + context.source_start_p = ecma_string_get_chars (string_p, &context.source_size, NULL, NULL, &flags); + + if (flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + context.global_status_flags |= ECMA_PARSE_INTERNAL_FREE_SOURCE; + } + } + +#if JERRY_DEBUGGER + if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) + { + jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE, + JERRY_DEBUGGER_NO_SUBTYPE, + context.source_start_p, + context.source_size); + } +#endif /* JERRY_DEBUGGER */ context.user_value = ECMA_VALUE_EMPTY; @@ -1862,9 +1913,10 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ ecma_value_t resource_name = ecma_make_magic_string_value (LIT_MAGIC_STRING_RESOURCE_ANON); if (context.options_p != NULL - && (context.options_p->options & JERRY_PARSE_HAS_RESOURCE) - && ecma_is_value_string (context.options_p->resource_name)) + && (context.options_p->options & JERRY_PARSE_HAS_RESOURCE)) { + JERRY_ASSERT (ecma_is_value_string (context.options_p->resource_name)); + ecma_ref_ecma_string (ecma_get_string_from_value (context.options_p->resource_name)); resource_name = context.options_p->resource_name; } @@ -1878,6 +1930,11 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ ECMA_SET_INTERNAL_VALUE_POINTER (context.script_value, context.script_p); + context.last_context_p = NULL; + context.last_statement.current_p = NULL; + context.token.flags = 0; + lexer_init_line_info (&context); + scanner_info_t scanner_info_end; scanner_info_end.next_p = NULL; scanner_info_end.source_p = NULL; @@ -1929,16 +1986,12 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ if (context.is_show_opcodes) { JERRY_DEBUG_MSG ("\n--- %s parsing start ---\n\n", - (arg_list_p == NULL) ? "Script" - : "Function"); + (context.arguments_start_p == NULL) ? "Script" + : "Function"); } #endif /* JERRY_PARSER_DUMP_BYTE_CODE */ - scanner_scan_all (&context, - arg_list_p, - arg_list_p + arg_list_size, - source_p, - source_p + source_size); + scanner_scan_all (&context); if (JERRY_UNLIKELY (context.error != PARSER_ERR_NO_ERROR)) { @@ -1950,15 +2003,15 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ return NULL; } - if (arg_list_p == NULL) + if (context.arguments_start_p == NULL) { - context.source_p = source_p; - context.source_end_p = source_p + source_size; + context.source_p = context.source_start_p; + context.source_end_p = context.source_start_p + context.source_size; } else { - context.source_p = arg_list_p; - context.source_end_p = arg_list_p + arg_list_size; + context.source_p = context.arguments_start_p; + context.source_end_p = context.arguments_start_p + context.arguments_size; } context.u.allocated_buffer_p = NULL; @@ -1989,15 +2042,15 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ * lexer_next_token() must be immediately called. */ lexer_next_token (&context); - if (arg_list_p != NULL) + if (context.arguments_start_p != NULL) { parser_parse_function_arguments (&context, LEXER_EOS); JERRY_ASSERT (context.next_scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS); scanner_release_next (&context, sizeof (scanner_info_t)); - context.source_p = source_p; - context.source_end_p = source_p + source_size; + context.source_p = context.source_start_p; + context.source_end_p = context.source_start_p + context.source_size; lexer_init_line_info (&context); lexer_next_token (&context); @@ -2016,7 +2069,7 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ #endif /* JERRY_MODULE_SYSTEM */ else { - JERRY_ASSERT (context.next_scanner_info_p->source_p == source_p + JERRY_ASSERT (context.next_scanner_info_p->source_p == context.source_start_p && context.next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); #if JERRY_ESNEXT @@ -2059,7 +2112,7 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ && context.stack.first_p->next_p == NULL && context.stack.last_p == NULL); - JERRY_ASSERT (arg_list_p != NULL || !(context.status_flags & PARSER_ARGUMENTS_NEEDED)); + JERRY_ASSERT (context.arguments_start_p != NULL || !(context.status_flags & PARSER_ARGUMENTS_NEEDED)); context.script_p->refs_and_type -= CBC_SCRIPT_REF_ONE; @@ -2072,8 +2125,8 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ if (context.is_show_opcodes) { JERRY_DEBUG_MSG ("\n%s parsing successfully completed. Total byte code size: %d bytes\n", - (arg_list_p == NULL) ? "Script" - : "Function", + (context.arguments_start_p == NULL) ? "Script" + : "Function", (int) context.total_byte_code_size); } #endif /* JERRY_PARSER_DUMP_BYTE_CODE */ @@ -2122,13 +2175,23 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ if (context.is_show_opcodes) { JERRY_DEBUG_MSG ("\n--- %s parsing end ---\n\n", - (arg_list_p == NULL) ? "Script" - : "Function"); + (context.arguments_start_p == NULL) ? "Script" + : "Function"); } #endif /* JERRY_PARSER_DUMP_BYTE_CODE */ parser_stack_free (&context); + if (context.global_status_flags & ECMA_PARSE_INTERNAL_FREE_SOURCE) + { + jmem_heap_free_block ((void *) context.source_start_p, context.source_size); + } + + if (context.global_status_flags & ECMA_PARSE_INTERNAL_FREE_ARG_LIST) + { + jmem_heap_free_block ((void *) context.arguments_start_p, context.arguments_size); + } + if (compiled_code_p != NULL) { return compiled_code_p; @@ -2930,29 +2993,12 @@ parser_raise_error (parser_context_t *context_p, /**< context */ * NULL - otherwise */ ecma_compiled_code_t * -parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */ - size_t arg_list_size, /**< size of function argument list */ - const uint8_t *source_p, /**< source code */ - size_t source_size, /**< size of the source code */ +parser_parse_script (void *source_p, /**< source code */ uint32_t parse_opts, /**< ecma_parse_opts_t option bits */ const jerry_parse_options_t *options_p) /**< additional configuration options */ { #if JERRY_PARSER - -#if JERRY_DEBUGGER - if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) - { - jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE, - JERRY_DEBUGGER_NO_SUBTYPE, - source_p, - source_size); - } -#endif /* JERRY_DEBUGGER */ - - ecma_compiled_code_t *bytecode_p = parser_parse_source (arg_list_p, - arg_list_size, - source_p, - source_size, + ecma_compiled_code_t *bytecode_p = parser_parse_source (source_p, parse_opts, options_p); diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h index 96a030c7a..0496b5670 100644 --- a/jerry-core/parser/js/js-parser.h +++ b/jerry-core/parser/js/js-parser.h @@ -192,11 +192,18 @@ typedef enum */ typedef uint32_t parser_line_counter_t; +/** + * Source code as character data. + */ +typedef struct +{ + const uint8_t *source_p; /**< valid UTF-8 source code */ + size_t source_size; /**< size of the source code */ +} parser_source_char_t; + /* Note: source must be a valid UTF-8 string */ ecma_compiled_code_t * -parser_parse_script (const uint8_t *arg_list_p, size_t arg_list_size, - const uint8_t *source_p, size_t source_size, - uint32_t parse_opts, const jerry_parse_options_t *options_p); +parser_parse_script (void *source_p, uint32_t parse_opts, const jerry_parse_options_t *options_p); #if JERRY_ERROR_MESSAGES const char *parser_error_to_string (parser_error_t); diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index a7b39912c..c04761f2d 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -2463,11 +2463,7 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ * Scan the whole source code. */ void JERRY_ATTR_NOINLINE -scanner_scan_all (parser_context_t *context_p, /**< context */ - const uint8_t *arg_list_p, /**< function argument list */ - const uint8_t *arg_list_end_p, /**< end of argument list */ - const uint8_t *source_p, /**< valid UTF-8 source code */ - const uint8_t *source_end_p) /**< end of source code */ +scanner_scan_all (parser_context_t *context_p) /**< context */ { scanner_context_t scanner_context; @@ -2507,10 +2503,10 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ PARSER_TRY (context_p->try_buffer) { - if (arg_list_p == NULL) + if (context_p->arguments_start_p == NULL) { - context_p->source_p = source_p; - context_p->source_end_p = source_end_p; + context_p->source_p = context_p->source_start_p; + context_p->source_end_p = context_p->source_start_p + context_p->source_size; uint16_t status_flags = (SCANNER_LITERAL_POOL_FUNCTION | SCANNER_LITERAL_POOL_NO_ARGUMENTS @@ -2522,7 +2518,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } scanner_literal_pool_t *literal_pool_p = scanner_push_literal_pool (context_p, &scanner_context, status_flags); - literal_pool_p->source_p = source_p; + literal_pool_p->source_p = context_p->source_start_p; parser_stack_push_uint8 (context_p, SCAN_STACK_SCRIPT); @@ -2531,8 +2527,8 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } else { - context_p->source_p = arg_list_p; - context_p->source_end_p = arg_list_end_p; + context_p->source_p = context_p->arguments_start_p; + context_p->source_end_p = context_p->arguments_start_p + context_p->arguments_size; uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION; @@ -3115,8 +3111,8 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ scanner_context.end_arguments_p = scanner_info_p; context_p->next_scanner_info_p = scanner_info_p; - context_p->source_p = source_p; - context_p->source_end_p = source_end_p; + context_p->source_p = context_p->source_start_p; + context_p->source_end_p = context_p->source_start_p + context_p->source_size; lexer_init_line_info (context_p); #if JERRY_ESNEXT @@ -3525,7 +3521,8 @@ scan_completed: if (context_p->is_show_opcodes) { scanner_info_t *info_p = context_p->next_scanner_info_p; - const uint8_t *source_start_p = (arg_list_p == NULL) ? source_p : arg_list_p; + const uint8_t *source_start_p = (context_p->arguments_start_p == NULL ? context_p->source_start_p + : context_p->arguments_start_p); while (info_p->type != SCANNER_TYPE_END) { @@ -3537,7 +3534,7 @@ scan_completed: case SCANNER_TYPE_END_ARGUMENTS: { JERRY_DEBUG_MSG (" END_ARGUMENTS\n"); - source_start_p = source_p; + source_start_p = context_p->source_start_p; break; } case SCANNER_TYPE_FUNCTION: diff --git a/jerry-main/main-jerry-snapshot.c b/jerry-main/main-jerry-snapshot.c index c44d8454b..5e9e230d5 100644 --- a/jerry-main/main-jerry-snapshot.c +++ b/jerry-main/main-jerry-snapshot.c @@ -374,32 +374,36 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ } } - jerry_value_t snapshot_result; - jerry_parse_options_t parse_options; parse_options.options = JERRY_PARSE_HAS_RESOURCE; + /* To avoid cppcheck warning. */ + parse_options.argument_list = 0; parse_options.resource_name = jerry_create_string_sz ((const jerry_char_t *) file_name_p, (jerry_size_t) strlen (file_name_p)); if (function_args_p != NULL) { - snapshot_result = jerry_generate_function_snapshot ((jerry_char_t *) source_p, - source_length, - (const jerry_char_t *) function_args_p, - strlen (function_args_p), - &parse_options, - snapshot_flags, - output_buffer, - sizeof (output_buffer) / sizeof (uint32_t)); + parse_options.options |= JERRY_PARSE_HAS_ARGUMENT_LIST; + parse_options.argument_list = jerry_create_string_from_utf8 ((const jerry_char_t *) function_args_p); } - else - { - snapshot_result = jerry_generate_snapshot ((jerry_char_t *) source_p, + + jerry_value_t snapshot_result = jerry_parse ((jerry_char_t *) source_p, source_length, - &parse_options, + &parse_options); + + if (!jerry_value_is_error (snapshot_result)) + { + jerry_value_t parse_result = snapshot_result; + snapshot_result = jerry_generate_snapshot (parse_result, snapshot_flags, output_buffer, sizeof (output_buffer) / sizeof (uint32_t)); + jerry_release_value (parse_result); + } + + if (parse_options.options & JERRY_PARSE_HAS_ARGUMENT_LIST) + { + jerry_release_value (parse_options.argument_list); } jerry_release_value (parse_options.resource_name); diff --git a/tests/unit-core/test-api.c b/tests/unit-core/test-api.c index 5249e8466..ca26cdfee 100644 --- a/tests/unit-core/test-api.c +++ b/tests/unit-core/test-api.c @@ -844,17 +844,19 @@ main (void) jerry_release_value (val_t); /* Test: create function */ - const jerry_char_t func_arg_list[] = "a , b,c"; - const jerry_char_t func_src[] = " return 5 + a+\nb+c"; + jerry_value_t script_source = jerry_create_string ((const jerry_char_t *) " return 5 + a+\nb+c"); - jerry_value_t func_val = jerry_parse_function (func_arg_list, - sizeof (func_arg_list) - 1, - func_src, - sizeof (func_src) - 1, - NULL); + jerry_parse_options_t parse_options; + parse_options.options = JERRY_PARSE_HAS_ARGUMENT_LIST; + parse_options.argument_list = jerry_create_string ((const jerry_char_t *) "a , b,c"); + + jerry_value_t func_val = jerry_parse_value (script_source, &parse_options); TEST_ASSERT (!jerry_value_is_error (func_val)); + jerry_release_value (parse_options.argument_list); + jerry_release_value (script_source); + jerry_value_t func_args[3] = { jerry_create_number (4), @@ -869,6 +871,24 @@ main (void) jerry_release_value (val_t); jerry_release_value (func_val); + parse_options.options = JERRY_PARSE_HAS_ARGUMENT_LIST; + parse_options.argument_list = jerry_create_null (); + + func_val = jerry_parse ((const jerry_char_t *) "", 0, &parse_options); + jerry_release_value (parse_options.argument_list); + + TEST_ASSERT (jerry_value_is_error (func_val) + && jerry_get_error_type (func_val) == JERRY_ERROR_TYPE); + jerry_release_value (func_val); + + script_source = jerry_create_number (4.5); + func_val = jerry_parse_value (script_source, NULL); + jerry_release_value (script_source); + + TEST_ASSERT (jerry_value_is_error (func_val) + && jerry_get_error_type (func_val) == JERRY_ERROR_TYPE); + jerry_release_value (func_val); + jerry_cleanup (); TEST_ASSERT (test_api_is_free_callback_was_called); @@ -1048,7 +1068,6 @@ main (void) "SyntaxError: Primary expression expected [:2:10]", false); - jerry_parse_options_t parse_options; parse_options.options = JERRY_PARSE_HAS_RESOURCE; parse_options.resource_name = jerry_create_string ((const jerry_char_t *) "filename.js"); diff --git a/tests/unit-core/test-regexp-dotall-unicode.c b/tests/unit-core/test-regexp-dotall-unicode.c index 21e765502..d203ac637 100644 --- a/tests/unit-core/test-regexp-dotall-unicode.c +++ b/tests/unit-core/test-regexp-dotall-unicode.c @@ -36,13 +36,14 @@ main (void) jerry_value_t regex_obj = jerry_create_regexp (pattern2, flags); TEST_ASSERT (jerry_value_is_object (regex_obj)); - const jerry_char_t func_arg_list[] = "regex"; const jerry_char_t func_src2[] = "return [regex.exec('a\\nb'), regex.dotAll, regex.sticky, regex.unicode ];"; - jerry_value_t func_val = jerry_parse_function (func_arg_list, - sizeof (func_arg_list) - 1, - func_src2, - sizeof (func_src2) - 1, - NULL); + + jerry_parse_options_t parse_options; + parse_options.options = JERRY_PARSE_HAS_ARGUMENT_LIST; + parse_options.argument_list = jerry_create_string ((const jerry_char_t *) "regex"); + + jerry_value_t func_val = jerry_parse (func_src2, sizeof (func_src2) - 1, &parse_options); + jerry_release_value (parse_options.argument_list); jerry_value_t res = jerry_call_function (func_val, undefined_this_arg, ®ex_obj, 1); jerry_value_t regex_res = jerry_get_property_by_index (res, 0); diff --git a/tests/unit-core/test-regexp.c b/tests/unit-core/test-regexp.c index c061a064d..70cf8e177 100644 --- a/tests/unit-core/test-regexp.c +++ b/tests/unit-core/test-regexp.c @@ -30,13 +30,14 @@ main (void) jerry_value_t regex_obj = jerry_create_regexp (pattern, flags); TEST_ASSERT (jerry_value_is_object (regex_obj)); - const jerry_char_t func_arg_list[] = "regex"; const jerry_char_t func_src[] = "return [regex.exec('something.domain.com'), regex.multiline, regex.global];"; - jerry_value_t func_val = jerry_parse_function (func_arg_list, - sizeof (func_arg_list) - 1, - func_src, - sizeof (func_src) - 1, - NULL); + + jerry_parse_options_t parse_options; + parse_options.options = JERRY_PARSE_HAS_ARGUMENT_LIST; + parse_options.argument_list = jerry_create_string ((const jerry_char_t *) "regex"); + + jerry_value_t func_val = jerry_parse (func_src, sizeof (func_src) - 1, &parse_options); + jerry_release_value (parse_options.argument_list); jerry_value_t res = jerry_call_function (func_val, global_obj_val, ®ex_obj, 1); jerry_value_t regex_res = jerry_get_property_by_index (res, 0); diff --git a/tests/unit-core/test-script-user-value.c b/tests/unit-core/test-script-user-value.c index 172f8b415..2d04d858c 100644 --- a/tests/unit-core/test-script-user-value.c +++ b/tests/unit-core/test-script-user-value.c @@ -62,15 +62,16 @@ test_parse_function (const char *source_p, /**< source code */ jerry_parse_options_t *options_p, /**< options passed to jerry_parse */ bool run_code) /**< run the code after parsing */ { + options_p->options |= JERRY_PARSE_HAS_ARGUMENT_LIST; + options_p->argument_list = jerry_create_string ((const jerry_char_t *) ""); + for (size_t i = 0; i < USER_VALUES_SIZE; i++) { options_p->user_value = user_values[i]; - jerry_value_t result = jerry_parse_function ((const jerry_char_t *) "", - 0, - (const jerry_char_t *) source_p, - strlen (source_p), - options_p); + jerry_value_t result = jerry_parse ((const jerry_char_t *) source_p, + strlen (source_p), + options_p); TEST_ASSERT (!jerry_value_is_error (result)); if (run_code) @@ -94,6 +95,8 @@ test_parse_function (const char *source_p, /**< source code */ jerry_release_value (user_value); jerry_release_value (result); } + + jerry_release_value (options_p->argument_list); } /* test_parse_function */ int diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index bcfe25b0b..1a3a6fdda 100644 --- a/tests/unit-core/test-snapshot.c +++ b/tests/unit-core/test-snapshot.c @@ -63,19 +63,26 @@ static void test_function_snapshot (void) const jerry_init_flag_t flags = JERRY_INIT_EMPTY; static uint32_t function_snapshot_buffer[SNAPSHOT_BUFFER_SIZE]; - const jerry_char_t func_args[] = "a, b"; const jerry_char_t code_to_snapshot[] = "return a + b"; jerry_init (flags); - jerry_value_t generate_result; - generate_result = jerry_generate_function_snapshot (code_to_snapshot, - sizeof (code_to_snapshot) - 1, - func_args, - sizeof (func_args) - 1, - NULL, - 0, - function_snapshot_buffer, - SNAPSHOT_BUFFER_SIZE); + + jerry_parse_options_t parse_options; + parse_options.options = JERRY_PARSE_HAS_ARGUMENT_LIST; + parse_options.argument_list = jerry_create_string ((const jerry_char_t *) "a, b"); + + jerry_value_t parse_result = jerry_parse (code_to_snapshot, + sizeof (code_to_snapshot) - 1, + &parse_options); + TEST_ASSERT (!jerry_value_is_error (parse_result)); + + jerry_value_t generate_result = jerry_generate_snapshot (parse_result, + 0, + function_snapshot_buffer, + SNAPSHOT_BUFFER_SIZE); + jerry_release_value (parse_result); + jerry_release_value (parse_options.argument_list); + TEST_ASSERT (!jerry_value_is_error (generate_result) && jerry_value_is_number (generate_result)); @@ -146,13 +153,16 @@ static void test_function_arguments_snapshot (void) ); jerry_init (JERRY_INIT_EMPTY); - jerry_value_t generate_result; - generate_result = jerry_generate_snapshot (code_to_snapshot, - sizeof (code_to_snapshot) - 1, - NULL, - 0, - arguments_snapshot_buffer, - SNAPSHOT_BUFFER_SIZE); + jerry_value_t parse_result = jerry_parse (code_to_snapshot, + sizeof (code_to_snapshot) - 1, + NULL); + TEST_ASSERT (!jerry_value_is_error (parse_result)); + + jerry_value_t generate_result= jerry_generate_snapshot (parse_result, + 0, + arguments_snapshot_buffer, + SNAPSHOT_BUFFER_SIZE); + jerry_release_value (parse_result); TEST_ASSERT (!jerry_value_is_error (generate_result) && jerry_value_is_number (generate_result)); @@ -204,18 +214,22 @@ static void test_snapshot_with_user (void) ); jerry_init (JERRY_INIT_EMPTY); - jerry_value_t result = jerry_generate_snapshot (code_to_snapshot, - sizeof (code_to_snapshot) - 1, - NULL, - 0, - snapshot_buffer, - SNAPSHOT_BUFFER_SIZE); + jerry_value_t parse_result = jerry_parse (code_to_snapshot, + sizeof (code_to_snapshot) - 1, + NULL); + TEST_ASSERT (!jerry_value_is_error (parse_result)); - TEST_ASSERT (!jerry_value_is_error (result) - && jerry_value_is_number (result)); + jerry_value_t generate_result = jerry_generate_snapshot (parse_result, + 0, + snapshot_buffer, + SNAPSHOT_BUFFER_SIZE); + jerry_release_value (parse_result); - size_t snapshot_size = (size_t) jerry_get_number_value (result); - jerry_release_value (result); + 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); for (int i = 0; i < 3; i++) { @@ -234,11 +248,11 @@ static void test_snapshot_with_user (void) snapshot_exec_options.user_value = jerry_create_string ((const jerry_char_t *) "AnyString..."); } - result = jerry_exec_snapshot (snapshot_buffer, - snapshot_size, - 0, - JERRY_SNAPSHOT_EXEC_HAS_USER_VALUE, - &snapshot_exec_options); + jerry_value_t result = jerry_exec_snapshot (snapshot_buffer, + snapshot_size, + 0, + JERRY_SNAPSHOT_EXEC_HAS_USER_VALUE, + &snapshot_exec_options); TEST_ASSERT (!jerry_value_is_error (result) && jerry_value_is_function (result)); @@ -284,13 +298,17 @@ main (void) sizeof (magic_string_lengths) / sizeof (jerry_length_t), magic_string_lengths); - jerry_value_t generate_result; - generate_result = jerry_generate_snapshot (code_to_snapshot, - sizeof (code_to_snapshot) - 1, - NULL, - JERRY_SNAPSHOT_SAVE_STATIC, - snapshot_buffer, - SNAPSHOT_BUFFER_SIZE); + jerry_value_t parse_result = jerry_parse (code_to_snapshot, + sizeof (code_to_snapshot) - 1, + NULL); + TEST_ASSERT (!jerry_value_is_error (parse_result)); + + jerry_value_t generate_result = jerry_generate_snapshot (parse_result, + JERRY_SNAPSHOT_SAVE_STATIC, + snapshot_buffer, + SNAPSHOT_BUFFER_SIZE); + jerry_release_value (parse_result); + TEST_ASSERT (!jerry_value_is_error (generate_result) && jerry_value_is_number (generate_result)); @@ -319,13 +337,18 @@ main (void) const jerry_char_t code_to_snapshot1[] = "var a = 'hello'; 123"; jerry_init (JERRY_INIT_EMPTY); - jerry_value_t generate_result; - generate_result = jerry_generate_snapshot (code_to_snapshot1, - sizeof (code_to_snapshot1) - 1, - NULL, - 0, - snapshot_buffer_0, - SNAPSHOT_BUFFER_SIZE); + + jerry_value_t parse_result = jerry_parse (code_to_snapshot1, + sizeof (code_to_snapshot1) - 1, + NULL); + TEST_ASSERT (!jerry_value_is_error (parse_result)); + + jerry_value_t generate_result = jerry_generate_snapshot (parse_result, + 0, + snapshot_buffer_0, + SNAPSHOT_BUFFER_SIZE); + jerry_release_value (parse_result); + TEST_ASSERT (!jerry_value_is_error (generate_result) && jerry_value_is_number (generate_result)); @@ -337,12 +360,18 @@ main (void) const jerry_char_t code_to_snapshot2[] = "var b = 'hello'; 456"; jerry_init (JERRY_INIT_EMPTY); - generate_result = jerry_generate_snapshot (code_to_snapshot2, - sizeof (code_to_snapshot2) - 1, - NULL, + + parse_result = jerry_parse (code_to_snapshot2, + sizeof (code_to_snapshot2) - 1, + NULL); + TEST_ASSERT (!jerry_value_is_error (parse_result)); + + generate_result = jerry_generate_snapshot (parse_result, 0, snapshot_buffer_1, SNAPSHOT_BUFFER_SIZE); + jerry_release_value (parse_result); + TEST_ASSERT (!jerry_value_is_error (generate_result) && jerry_value_is_number (generate_result)); @@ -402,13 +431,16 @@ main (void) static uint32_t literal_snapshot_buffer[SNAPSHOT_BUFFER_SIZE]; static const jerry_char_t code_for_c_format[] = "var object = { aa:'fo\" o\\n \\\\', Bb:'max', aaa:'xzy0' };"; - jerry_value_t generate_result; - generate_result = jerry_generate_snapshot (code_for_c_format, - sizeof (code_for_c_format) - 1, - NULL, - 0, - literal_snapshot_buffer, - SNAPSHOT_BUFFER_SIZE); + jerry_value_t parse_result = jerry_parse (code_for_c_format, + sizeof (code_for_c_format) - 1, + NULL); + TEST_ASSERT (!jerry_value_is_error (parse_result)); + + jerry_value_t generate_result = jerry_generate_snapshot (parse_result, + 0, + literal_snapshot_buffer, + SNAPSHOT_BUFFER_SIZE); + jerry_release_value (parse_result); TEST_ASSERT (!jerry_value_is_error (generate_result)); TEST_ASSERT (jerry_value_is_number (generate_result));