diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md
index a01f5da2ef..835e960b74 100644
--- a/docs/02.API-REFERENCE.md
+++ b/docs/02.API-REFERENCE.md
@@ -175,6 +175,8 @@ Possible compile time enabled feature types:
- JERRY_FEATURE_GLOBAL_THIS - GlobalThisValue support
- JERRY_FEATURE_PROMISE_CALLBACK - Promise callback support
- JERRY_FEATURE_MODULE - Module support
+ - JERRY_FEATURE_WEAKREF - WeakRef support
+ - JERRY_FEATURE_FUNCTION_TO_STRING - function toString support
*New in version 2.0*.
@@ -183,7 +185,8 @@ Possible compile time enabled feature types:
*Changed in version 2.4*: Added `JERRY_FEATURE_BIGINT`, `JERRY_FEATURE_REALM` values.
*Changed in version [[NEXT_RELEASE]]*: Added `JERRY_FEATURE_VM_THROW`, `JERRY_FEATURE_GLOBAL_THIS`,
- `JERRY_FEATURE_PROMISE_CALLBACK`, and `JERRY_FEATURE_MODULE` values.
+ `JERRY_FEATURE_PROMISE_CALLBACK`, and `JERRY_FEATURE_MODULE`,
+ `JERRY_FEATURE_WEAKREF`, and `JERRY_FEATURE_FUNCTION_TO_STRING` values.
## jerry_container_type_t
diff --git a/jerry-core/CMakeLists.txt b/jerry-core/CMakeLists.txt
index cb3c228536..f4e08de8bf 100644
--- a/jerry-core/CMakeLists.txt
+++ b/jerry-core/CMakeLists.txt
@@ -24,6 +24,7 @@ set(JERRY_DEBUGGER OFF CACHE BOOL "Enable JerryScrip
set(JERRY_ERROR_MESSAGES OFF CACHE BOOL "Enable error messages?")
set(JERRY_EXTERNAL_CONTEXT OFF CACHE BOOL "Enable external context?")
set(JERRY_PARSER ON CACHE BOOL "Enable javascript-parser?")
+set(JERRY_FUNCTION_TO_STRING OFF CACHE BOOL "Enable function toString operation?")
set(JERRY_LINE_INFO OFF CACHE BOOL "Enable line info?")
set(JERRY_LOGGING OFF CACHE BOOL "Enable logging?")
set(JERRY_MEM_STATS OFF CACHE BOOL "Enable memory statistics?")
@@ -83,6 +84,7 @@ message(STATUS "JERRY_DEBUGGER " ${JERRY_DEBUGGER})
message(STATUS "JERRY_ERROR_MESSAGES " ${JERRY_ERROR_MESSAGES})
message(STATUS "JERRY_EXTERNAL_CONTEXT " ${JERRY_EXTERNAL_CONTEXT})
message(STATUS "JERRY_PARSER " ${JERRY_PARSER})
+message(STATUS "JERRY_FUNCTION_TO_STRING " ${JERRY_FUNCTION_TO_STRING})
message(STATUS "JERRY_LINE_INFO " ${JERRY_LINE_INFO})
message(STATUS "JERRY_LOGGING " ${JERRY_LOGGING} ${JERRY_LOGGING_MESSAGE})
message(STATUS "JERRY_MEM_STATS " ${JERRY_MEM_STATS})
@@ -135,6 +137,7 @@ set(SOURCE_CORE_FILES
ecma/base/ecma-alloc.c
ecma/base/ecma-gc.c
ecma/base/ecma-errors.c
+ ecma/base/ecma-extended-info.c
ecma/base/ecma-helpers-collection.c
ecma/base/ecma-helpers-conversion.c
ecma/base/ecma-helpers-errol.c
@@ -559,6 +562,9 @@ jerry_add_define01(JERRY_EXTERNAL_CONTEXT)
# JS-Parser
jerry_add_define01(JERRY_PARSER)
+# JS function toString
+jerry_add_define01(JERRY_FUNCTION_TO_STRING)
+
# JS line info
jerry_add_define01(JERRY_LINE_INFO)
diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c
index 4af6ca3032..5af9192f1d 100644
--- a/jerry-core/api/jerry-snapshot.c
+++ b/jerry-core/api/jerry-snapshot.c
@@ -979,8 +979,13 @@ jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
user_value = option_values_p->user_value;
}
- uint32_t script_size = (user_value != ECMA_VALUE_EMPTY ? sizeof (cbc_script_user_t)
- : sizeof (cbc_script_t));
+ size_t script_size = sizeof (cbc_script_t);
+
+ if (user_value != ECMA_VALUE_EMPTY)
+ {
+ script_size += sizeof (ecma_value_t);
+ }
+
cbc_script_t *script_p = jmem_heap_alloc_block (script_size);
CBC_SCRIPT_SET_TYPE (script_p, user_value, CBC_SCRIPT_REF_ONE);
@@ -1003,6 +1008,10 @@ jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
script_p->resource_name = resource_name;
#endif /* JERRY_RESOURCE_NAME */
+#if JERRY_FUNCTION_TO_STRING
+ script_p->source_code = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
+#endif /* JERRY_FUNCTION_TO_STRING */
+
const uint8_t *literal_base_p = snapshot_data_p + header_p->lit_table_offset;
bytecode_p = snapshot_load_compiled_code ((const uint8_t *) bytecode_p,
@@ -1021,7 +1030,7 @@ jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
if (user_value != ECMA_VALUE_EMPTY)
{
- ((cbc_script_user_t *) script_p)->user_value = ecma_copy_value_if_not_object (user_value);
+ CBC_SCRIPT_GET_USER_VALUE (script_p) = ecma_copy_value_if_not_object (user_value);
}
}
diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c
index cb0079da76..b20b0b8f55 100644
--- a/jerry-core/api/jerry.c
+++ b/jerry-core/api/jerry.c
@@ -1841,6 +1841,9 @@ jerry_is_feature_enabled (const jerry_feature_t feature) /**< feature to check *
#if JERRY_MODULE_SYSTEM
|| feature == JERRY_FEATURE_MODULE
#endif /* JERRY_MODULE_SYSTEM */
+#if JERRY_FUNCTION_TO_STRING
+ || feature == JERRY_FEATURE_FUNCTION_TO_STRING
+#endif /* JERRY_FUNCTION_TO_STRING */
);
} /* jerry_is_feature_enabled */
@@ -2801,7 +2804,7 @@ jerry_create_regexp_sz (const jerry_char_t *pattern_p, /**< zero-terminated UTF-
jerry_assert_api_available ();
#if JERRY_BUILTIN_REGEXP
- if (!lit_is_valid_utf8_string (pattern_p, pattern_size))
+ if (!lit_is_valid_utf8_string (pattern_p, pattern_size, true))
{
return jerry_throw (ecma_raise_common_error (ECMA_ERR_MSG ("Input must be a valid utf8 string")));
}
@@ -5130,7 +5133,8 @@ jerry_is_valid_utf8_string (const jerry_char_t *utf8_buf_p, /**< UTF-8 string */
jerry_size_t buf_size) /**< string size */
{
return lit_is_valid_utf8_string ((lit_utf8_byte_t *) utf8_buf_p,
- (lit_utf8_size_t) buf_size);
+ (lit_utf8_size_t) buf_size,
+ true);
} /* jerry_is_valid_utf8_string */
/**
@@ -5490,7 +5494,7 @@ jerry_get_user_value (const jerry_value_t value) /**< jerry api value */
return ECMA_VALUE_UNDEFINED;
}
- return ecma_copy_value (((cbc_script_user_t *) script_p)->user_value);
+ return ecma_copy_value (CBC_SCRIPT_GET_USER_VALUE (script_p));
} /* jerry_get_user_value */
/**
diff --git a/jerry-core/config.h b/jerry-core/config.h
index 67c3de9d43..7c5d0305f3 100644
--- a/jerry-core/config.h
+++ b/jerry-core/config.h
@@ -231,6 +231,19 @@
# define JERRY_LCACHE 1
#endif /* !defined (JERRY_LCACHE) */
+/**
+ * Enable/Disable function toString operation.
+ *
+ * Allowed values:
+ * 0: Disable function toString operation.
+ * 1: Enable function toString operation.
+ *
+ * Default value: 0
+ */
+#ifndef JERRY_FUNCTION_TO_STRING
+# define JERRY_FUNCTION_TO_STRING 0
+#endif /* !defined (JERRY_FUNCTION_TO_STRING) */
+
/**
* Enable/Disable line-info management inside the engine.
*
@@ -634,6 +647,10 @@
|| ((JERRY_LCACHE != 0) && (JERRY_LCACHE != 1))
# error "Invalid value for 'JERRY_LCACHE' macro."
#endif
+#if !defined (JERRY_FUNCTION_TO_STRING) \
+|| ((JERRY_FUNCTION_TO_STRING != 0) && (JERRY_FUNCTION_TO_STRING != 1))
+# error "Invalid value for 'JERRY_FUNCTION_TO_STRING' macro."
+#endif
#if !defined (JERRY_LINE_INFO) \
|| ((JERRY_LINE_INFO != 0) && (JERRY_LINE_INFO != 1))
# error "Invalid value for 'JERRY_LINE_INFO' macro."
diff --git a/jerry-core/ecma/base/ecma-extended-info.c b/jerry-core/ecma/base/ecma-extended-info.c
new file mode 100644
index 0000000000..b5fabf5801
--- /dev/null
+++ b/jerry-core/ecma/base/ecma-extended-info.c
@@ -0,0 +1,152 @@
+/* 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 "byte-code.h"
+#include "ecma-helpers.h"
+#include "ecma-extended-info.h"
+
+#if JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmaextendedinfo Extended info
+ * @{
+ */
+
+/**
+ * Decodes an uint32_t number, and updates the buffer position.
+ *
+ * @return the decoded value
+ */
+uint32_t
+ecma_extended_info_decode_vlq (uint8_t **buffer_p) /**< [in/out] target buffer */
+{
+ uint8_t *source_p = *buffer_p;
+ uint32_t value = 0;
+
+ do
+ {
+ source_p--;
+ value = (value << ECMA_EXTENDED_INFO_VLQ_SHIFT) | (*source_p & ECMA_EXTENDED_INFO_VLQ_MASK);
+ }
+ while (*source_p & ECMA_EXTENDED_INFO_VLQ_CONTINUE);
+
+ *buffer_p = source_p;
+ return value;
+} /* ecma_extended_info_decode_vlq */
+
+/**
+ * Encodes an uint32_t number into a buffer.
+ */
+void
+ecma_extended_info_encode_vlq (uint8_t **buffer_p, /**< target buffer */
+ uint32_t value) /**< encoded value */
+{
+ uint8_t *destination_p = *buffer_p - 1;
+
+ if (value <= ECMA_EXTENDED_INFO_VLQ_MASK)
+ {
+ *destination_p = (uint8_t) value;
+ *buffer_p = destination_p;
+ return;
+ }
+
+ uint32_t length = 0;
+ uint32_t current_value = value >> ECMA_EXTENDED_INFO_VLQ_SHIFT;
+
+ do
+ {
+ current_value >>= ECMA_EXTENDED_INFO_VLQ_SHIFT;
+ length++;
+ }
+ while (current_value > 0);
+
+ destination_p -= length;
+ *buffer_p = destination_p;
+
+ do
+ {
+ *destination_p++ = (uint8_t) (value | ECMA_EXTENDED_INFO_VLQ_CONTINUE);
+ value >>= ECMA_EXTENDED_INFO_VLQ_SHIFT;
+ }
+ while (value > 0);
+
+ **buffer_p &= ECMA_EXTENDED_INFO_VLQ_MASK;
+} /* ecma_extended_info_encode_vlq */
+
+/**
+ * Gets the encoded length of a number.
+ *
+ * @return encoded length
+ */
+uint32_t
+ecma_extended_info_get_encoded_length (uint32_t value) /**< encoded value */
+{
+ uint32_t length = 0;
+
+ do
+ {
+ value >>= ECMA_EXTENDED_INFO_VLQ_SHIFT;
+ length++;
+ }
+ while (value > 0);
+
+ return length;
+} /* ecma_extended_info_get_encoded_length */
+
+/**
+ * Get the extended info from a byte code
+ *
+ * @return pointer to the extended info
+ */
+uint8_t *
+ecma_compiled_code_resolve_extended_info (const ecma_compiled_code_t *bytecode_header_p) /**< compiled code */
+{
+ JERRY_ASSERT (bytecode_header_p != NULL);
+ JERRY_ASSERT (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO);
+
+ ecma_value_t *base_p = ecma_compiled_code_resolve_arguments_start (bytecode_header_p);
+
+#if JERRY_ESNEXT
+ if (CBC_FUNCTION_GET_TYPE (bytecode_header_p->status_flags) != CBC_FUNCTION_CONSTRUCTOR)
+ {
+ base_p--;
+ }
+
+ if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_TAGGED_LITERALS)
+ {
+ base_p--;
+ }
+#endif /* JERRY_ESNEXT */
+
+#if JERRY_LINE_INFO
+ if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_LINE_INFO)
+ {
+ base_p--;
+ }
+#endif /* JERRY_LINE_INFO */
+
+ JERRY_ASSERT (((uint8_t *) base_p)[-1] != 0);
+
+ return ((uint8_t *) base_p) - 1;
+} /* ecma_compiled_code_resolve_extended_info */
+
+#endif /* JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING */
+
+/**
+ * @}
+ * @}
+ */
diff --git a/jerry-core/ecma/base/ecma-extended-info.h b/jerry-core/ecma/base/ecma-extended-info.h
new file mode 100644
index 0000000000..c9fc1c90ed
--- /dev/null
+++ b/jerry-core/ecma/base/ecma-extended-info.h
@@ -0,0 +1,58 @@
+/* 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.
+ */
+
+#ifndef ECMA_EXTENDED_INFO_H
+#define ECMA_EXTENDED_INFO_H
+
+/** \addtogroup ecma ECMA
+ * @{
+ *
+ * \addtogroup ecmaextendedinfo Extended info
+ * @{
+ */
+
+#if JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING
+
+#include "ecma-globals.h"
+
+/**
+ * Vlq encoding: flag which is set for all bytes except the last one.
+ */
+#define ECMA_EXTENDED_INFO_VLQ_CONTINUE 0x80
+
+/**
+ * Vlq encoding: mask to decode the number fragment.
+ */
+#define ECMA_EXTENDED_INFO_VLQ_MASK 0x7f
+
+/**
+ * Vlq encoding: number of bits stored in a byte.
+ */
+#define ECMA_EXTENDED_INFO_VLQ_SHIFT 7
+
+uint32_t ecma_extended_info_decode_vlq (uint8_t **buffer_p);
+void ecma_extended_info_encode_vlq (uint8_t **buffer_p, uint32_t value);
+uint32_t ecma_extended_info_get_encoded_length (uint32_t value);
+
+uint8_t *ecma_compiled_code_resolve_extended_info (const ecma_compiled_code_t *bytecode_header_p);
+
+#endif /* JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING */
+
+/**
+ * @}
+ * @}
+ */
+
+#endif /* !ECMA_EXTENDED_INFO_H */
diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c
index 4ca9692b3e..ab6a603a9e 100644
--- a/jerry-core/ecma/base/ecma-gc.c
+++ b/jerry-core/ecma/base/ecma-gc.c
@@ -430,10 +430,10 @@ ecma_gc_mark_compiled_code (const ecma_compiled_code_t *compiled_code_p) /**< co
if (CBC_SCRIPT_GET_TYPE (script_p) == CBC_SCRIPT_USER_OBJECT)
{
- cbc_script_user_t *script_user_p = (cbc_script_user_t *) script_p;
+ ecma_value_t user_value = CBC_SCRIPT_GET_USER_VALUE (script_p);
- JERRY_ASSERT (ecma_is_value_object (script_user_p->user_value));
- ecma_gc_set_object_visited (ecma_get_object_from_value (script_user_p->user_value));
+ JERRY_ASSERT (ecma_is_value_object (user_value));
+ ecma_gc_set_object_visited (ecma_get_object_from_value (user_value));
}
#if JERRY_BUILTIN_REALMS
diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h
index 1ecfba9f66..72247db105 100644
--- a/jerry-core/ecma/base/ecma-globals.h
+++ b/jerry-core/ecma/base/ecma-globals.h
@@ -130,6 +130,9 @@ typedef enum
#if JERRY_ESNEXT
ECMA_PARSE_INTERNAL_PRE_SCANNING = (1u << 16), /**< the parser is in pre-scanning mode */
#endif /* JERRY_ESNEXT */
+#if JERRY_FUNCTION_TO_STRING
+ ECMA_PARSE_INTERNAL_HAS_4_BYTE_MARKER = (1u << 17), /**< source has 4 byte marker */
+#endif /* JERRY_FUNCTION_TO_STRING */
#ifndef JERRY_NDEBUG
/**
* This flag represents an error in for in/of statements, which cannot be set
diff --git a/jerry-core/ecma/base/ecma-helpers-string.c b/jerry-core/ecma/base/ecma-helpers-string.c
index 0fefdc1e7d..aa9dfa4fa0 100644
--- a/jerry-core/ecma/base/ecma-helpers-string.c
+++ b/jerry-core/ecma/base/ecma-helpers-string.c
@@ -443,7 +443,7 @@ ecma_new_ecma_string_from_utf8_converted_to_cesu8 (const lit_utf8_byte_t *string
converted_string_size += string_size;
- JERRY_ASSERT (lit_is_valid_utf8_string (string_p, string_size));
+ JERRY_ASSERT (lit_is_valid_utf8_string (string_p, string_size, false));
lit_utf8_byte_t *data_p;
ecma_string_t *string_desc_p = ecma_new_ecma_string_from_utf8_buffer (converted_string_length,
diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c
index 9d3a3db8ed..70c759f242 100644
--- a/jerry-core/ecma/base/ecma-helpers.c
+++ b/jerry-core/ecma/base/ecma-helpers.c
@@ -1527,14 +1527,14 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */
if (type != CBC_SCRIPT_GENERIC)
{
- script_size = sizeof (cbc_script_user_t);
+ script_size += sizeof (ecma_value_t);
if (type == CBC_SCRIPT_USER_VALUE)
{
- cbc_script_user_t *script_user_p = (cbc_script_user_t *) script_p;
+ ecma_value_t user_value = CBC_SCRIPT_GET_USER_VALUE (script_p);
- JERRY_ASSERT (!ecma_is_value_object (script_user_p->user_value));
- ecma_free_value (script_user_p->user_value);
+ JERRY_ASSERT (!ecma_is_value_object (user_value));
+ ecma_free_value (user_value);
}
}
@@ -1542,6 +1542,16 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */
ecma_deref_ecma_string (ecma_get_string_from_value (script_p->resource_name));
#endif /* JERRY_RESOURCE_NAME */
+#if JERRY_FUNCTION_TO_STRING
+ ecma_deref_ecma_string (ecma_get_string_from_value (script_p->source_code));
+
+ if (script_p->refs_and_type & CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS)
+ {
+ ecma_deref_ecma_string (ecma_get_string_from_value (CBC_SCRIPT_GET_FUNCTION_ARGUMENTS (script_p, type)));
+ script_size += sizeof (ecma_value_t);
+ }
+#endif /* JERRY_FUNCTION_TO_STRING */
+
jmem_heap_free_block (script_p, script_size);
}
@@ -1728,21 +1738,6 @@ ecma_compiled_code_resolve_function_name (const ecma_compiled_code_t *bytecode_h
return base_p;
} /* ecma_compiled_code_resolve_function_name */
-/**
- * Get the extended info from a byte code
- *
- * @return extended info value
- */
-uint32_t
-ecma_compiled_code_resolve_extended_info (const ecma_compiled_code_t *bytecode_header_p) /**< compiled code */
-{
- JERRY_ASSERT (bytecode_header_p != NULL);
- JERRY_ASSERT (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO);
-
- ecma_value_t *base_p = ecma_compiled_code_resolve_function_name (bytecode_header_p);
- return base_p[-1];
-} /* ecma_compiled_code_resolve_extended_info */
-
/**
* Get the tagged template collection of the compiled code
*
@@ -1755,9 +1750,7 @@ ecma_compiled_code_get_tagged_template_collection (const ecma_compiled_code_t *b
JERRY_ASSERT (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_TAGGED_LITERALS);
ecma_value_t *base_p = ecma_compiled_code_resolve_function_name (bytecode_header_p);
- int offset = (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO) ? -2 : -1;
-
- return ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, base_p[offset]);
+ return ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, base_p[-1]);
} /* ecma_compiled_code_get_tagged_template_collection */
#endif /* JERRY_ESNEXT */
@@ -1783,11 +1776,6 @@ ecma_compiled_code_get_line_info (const ecma_compiled_code_t *bytecode_header_p)
base_p--;
}
- if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO)
- {
- base_p--;
- }
-
if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_TAGGED_LITERALS)
{
base_p--;
diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h
index a4349536be..e8f64ad6ba 100644
--- a/jerry-core/ecma/base/ecma-helpers.h
+++ b/jerry-core/ecma/base/ecma-helpers.h
@@ -539,7 +539,6 @@ const ecma_compiled_code_t *ecma_bytecode_get_from_value (ecma_value_t value);
ecma_value_t *ecma_compiled_code_resolve_arguments_start (const ecma_compiled_code_t *bytecode_header_p);
#if JERRY_ESNEXT
ecma_value_t *ecma_compiled_code_resolve_function_name (const ecma_compiled_code_t *bytecode_header_p);
-uint32_t ecma_compiled_code_resolve_extended_info (const ecma_compiled_code_t *bytecode_header_p);
ecma_collection_t *ecma_compiled_code_get_tagged_template_collection (const ecma_compiled_code_t *bytecode_header_p);
#endif /* JERRY_ESNEXT */
#if JERRY_LINE_INFO
diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c
index 8837938594..c3ddd8cf47 100644
--- a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c
+++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c
@@ -18,6 +18,7 @@
#include "ecma-builtins.h"
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
+#include "ecma-extended-info.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
@@ -79,9 +80,116 @@ enum
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
-ecma_builtin_function_prototype_object_to_string (void)
+ecma_builtin_function_prototype_object_to_string (ecma_object_t *func_obj_p) /**< this argument object */
{
- return ecma_make_magic_string_value (LIT_MAGIC_STRING__FUNCTION_TO_STRING);
+ if (ecma_get_object_type (func_obj_p) != ECMA_OBJECT_TYPE_FUNCTION)
+ {
+ return ecma_make_magic_string_value (LIT_MAGIC_STRING_FUNCTION_TO_STRING_NATIVE);
+ }
+
+#if JERRY_FUNCTION_TO_STRING
+ const ecma_compiled_code_t *bytecode_p;
+ bytecode_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) func_obj_p);
+
+ ecma_value_t script_value = ((cbc_uint8_arguments_t *) bytecode_p)->script_value;
+ cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
+
+ if (bytecode_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO)
+ {
+ uint8_t *extended_info_p = ecma_compiled_code_resolve_extended_info (bytecode_p);
+ uint8_t extended_info = *extended_info_p;
+
+ if (extended_info & CBC_EXTENDED_CODE_FLAGS_HAS_SOURCE_CODE_RANGE)
+ {
+#if JERRY_ESNEXT
+ if (extended_info & CBC_EXTENDED_CODE_FLAGS_HAS_ARGUMENT_LENGTH)
+ {
+ ecma_extended_info_decode_vlq (&extended_info_p);
+ }
+#endif /* JERRY_ESNEXT */
+
+ uint32_t range_start = ecma_extended_info_decode_vlq (&extended_info_p);
+ uint32_t range_size = ecma_extended_info_decode_vlq (&extended_info_p);
+ ecma_value_t source_code;
+
+ if (!(extended_info & CBC_EXTENDED_CODE_FLAGS_SOURCE_CODE_IN_ARGUMENTS))
+ {
+ source_code = script_p->source_code;
+#if JERRY_SNAPSHOT_EXEC
+ if (ecma_is_value_magic_string (source_code, LIT_MAGIC_STRING__EMPTY))
+ {
+ return ecma_make_magic_string_value (LIT_MAGIC_STRING_FUNCTION_TO_STRING_ECMA);
+ }
+#endif /* JERRY_SNAPSHOT_EXEC */
+ }
+ else
+ {
+#if JERRY_SNAPSHOT_EXEC
+ if (!(script_p->refs_and_type & CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS))
+ {
+ return ecma_make_magic_string_value (LIT_MAGIC_STRING_FUNCTION_TO_STRING_ECMA);
+ }
+#else /* !JERRY_SNAPSHOT_EXEC */
+ JERRY_ASSERT (script_p->refs_and_type & CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS);
+#endif /* JERRY_SNAPSHOT_EXEC */
+
+ source_code = CBC_SCRIPT_GET_FUNCTION_ARGUMENTS (script_p, CBC_SCRIPT_GET_TYPE (script_p));
+ }
+
+ ecma_string_t *result_string_p;
+
+ ECMA_STRING_TO_UTF8_STRING (ecma_get_string_from_value (source_code), source_p, source_size);
+ result_string_p = ecma_new_ecma_string_from_utf8 (source_p + range_start, range_size);
+ ECMA_FINALIZE_UTF8_STRING (source_p, source_size);
+
+ return ecma_make_string_value (result_string_p);
+ }
+ }
+
+#if JERRY_SNAPSHOT_EXEC
+ if (!(script_p->refs_and_type & CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS))
+ {
+ return ecma_make_magic_string_value (LIT_MAGIC_STRING_FUNCTION_TO_STRING_ECMA);
+ }
+#else /* !JERRY_SNAPSHOT_EXEC */
+ JERRY_ASSERT (script_p->refs_and_type & CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS);
+#endif /* JERRY_SNAPSHOT_EXEC */
+
+ lit_magic_string_id_t header_id = LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON;
+
+#if JERRY_ESNEXT
+ switch (CBC_FUNCTION_GET_TYPE (bytecode_p->status_flags))
+ {
+ case CBC_FUNCTION_GENERATOR:
+ {
+ header_id = LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_GENERATOR;
+ break;
+ }
+ case CBC_FUNCTION_ASYNC_GENERATOR:
+ {
+ header_id = LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_ASYNC_GENERATOR;
+ break;
+ }
+ case CBC_FUNCTION_ASYNC:
+ {
+ header_id = LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_ASYNC;
+ break;
+ }
+ }
+#endif /* JERRY_ESNEXT */
+
+ ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (ecma_get_magic_string (header_id));
+ ecma_value_t function_arguments = CBC_SCRIPT_GET_FUNCTION_ARGUMENTS (script_p, CBC_SCRIPT_GET_TYPE (script_p));
+
+ ecma_stringbuilder_append (&builder, ecma_get_string_from_value (function_arguments));
+ ecma_stringbuilder_append_raw (&builder, (const lit_utf8_byte_t *) "\n) {\n", 5);
+ ecma_stringbuilder_append (&builder, ecma_get_string_from_value (script_p->source_code));
+ ecma_stringbuilder_append_raw (&builder, (const lit_utf8_byte_t *) "\n}", 2);
+
+ return ecma_make_string_value (ecma_stringbuilder_finalize (&builder));
+#else /* !JERRY_FUNCTION_TO_STRING */
+ return ecma_make_magic_string_value (LIT_MAGIC_STRING_FUNCTION_TO_STRING_ECMA);
+#endif /* JERRY_FUNCTION_TO_STRING */
} /* ecma_builtin_function_prototype_object_to_string */
/**
@@ -440,7 +548,7 @@ ecma_builtin_function_prototype_dispatch_routine (uint8_t builtin_routine_id, /*
{
case ECMA_FUNCTION_PROTOTYPE_TO_STRING:
{
- return ecma_builtin_function_prototype_object_to_string ();
+ return ecma_builtin_function_prototype_object_to_string (func_obj_p);
}
case ECMA_FUNCTION_PROTOTYPE_APPLY:
{
diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.c b/jerry-core/ecma/builtin-objects/ecma-builtin-global.c
index 187dd2eea9..34570ecb0f 100644
--- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.c
+++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.c
@@ -284,7 +284,7 @@ ecma_builtin_global_object_decode_uri_helper (lit_utf8_byte_t *input_start_p, /*
}
if (!is_valid
- || !lit_is_valid_utf8_string (octets, bytes_count))
+ || !lit_is_valid_utf8_string (octets, bytes_count, true))
{
ecma_stringbuilder_destroy (&builder);
return ecma_raise_uri_error (ECMA_ERR_MSG ("Invalid UTF8 string"));
diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c
index cfe96aba10..f15a225d3b 100644
--- a/jerry-core/ecma/operations/ecma-function-object.c
+++ b/jerry-core/ecma/operations/ecma-function-object.c
@@ -17,6 +17,7 @@
#include "ecma-builtin-helpers.h"
#include "ecma-builtin-handlers.h"
#include "ecma-exceptions.h"
+#include "ecma-extended-info.h"
#include "ecma-function-object.h"
#include "ecma-gc.h"
#include "ecma-helpers.h"
@@ -1739,11 +1740,7 @@ ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**<
const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p);
uint32_t len;
- if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO)
- {
- len = CBC_EXTENDED_INFO_GET_LENGTH (ecma_compiled_code_resolve_extended_info (bytecode_data_p));
- }
- else if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
+ if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_data_p;
len = args_p->argument_end;
@@ -1754,6 +1751,16 @@ ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**<
len = args_p->argument_end;
}
+ if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO)
+ {
+ uint8_t *extended_info_p = ecma_compiled_code_resolve_extended_info (bytecode_data_p);
+
+ if (*extended_info_p & CBC_EXTENDED_CODE_FLAGS_HAS_ARGUMENT_LENGTH)
+ {
+ len = ecma_extended_info_decode_vlq (&extended_info_p);
+ }
+ }
+
/* Set tag bit to represent initialized 'length' property */
ECMA_SET_FIRST_BIT_TO_POINTER_TAG (ext_func_p->u.function.scope_cp);
ecma_property_t *value_prop_p;
diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h
index 27db4c6613..0ac226d6d9 100644
--- a/jerry-core/include/jerryscript-snapshot.h
+++ b/jerry-core/include/jerryscript-snapshot.h
@@ -30,7 +30,7 @@ extern "C"
/**
* Jerry snapshot format version.
*/
-#define JERRY_SNAPSHOT_VERSION (67u)
+#define JERRY_SNAPSHOT_VERSION (68u)
/**
* Flags for jerry_generate_snapshot and jerry_generate_function_snapshot.
diff --git a/jerry-core/include/jerryscript-types.h b/jerry-core/include/jerryscript-types.h
index 505a098e76..50966d13ce 100644
--- a/jerry-core/include/jerryscript-types.h
+++ b/jerry-core/include/jerryscript-types.h
@@ -112,6 +112,7 @@ typedef enum
JERRY_FEATURE_PROMISE_CALLBACK, /**< Promise callback support */
JERRY_FEATURE_MODULE, /**< Module support */
JERRY_FEATURE_WEAKREF, /**< WeakRef support */
+ JERRY_FEATURE_FUNCTION_TO_STRING, /**< function toString support */
JERRY_FEATURE__COUNT /**< number of features. NOTE: must be at the end of the list */
} jerry_feature_t;
diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h
index 7744bf370f..b663a50863 100644
--- a/jerry-core/lit/lit-magic-strings.inc.h
+++ b/jerry-core/lit/lit-magic-strings.inc.h
@@ -1003,7 +1003,13 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UTC_MILLISECONDS_UL, "setUTCMilliseco
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_LOCALE_DATE_STRING_UL, "toLocaleDateString")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_LOCALE_TIME_STRING_UL, "toLocaleTimeString")
#endif
+#if JERRY_FUNCTION_TO_STRING
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON, "function anonymous(")
+#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_OWN_PROPERTY_NAMES_UL, "getOwnPropertyNames")
+#if JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_GENERATOR, "function* anonymous(")
+#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PROPERTY_IS_ENUMERABLE_UL, "propertyIsEnumerable")
#if JERRY_ESNEXT
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_OWN_PROPERTY_SYMBOLS_UL, "getOwnPropertySymbols")
@@ -1011,10 +1017,20 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASYNC_GENERATOR_FUNCTION_UL, "AsyncGenera
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REGEXP_STRING_ITERATOR_UL, "RegExp String Iterator")
#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTOR_UL, "getOwnPropertyDescriptor")
+#if JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_ASYNC, "async function anonymous(")
+#endif
#if JERRY_ESNEXT
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTORS_UL, "getOwnPropertyDescriptors")
#endif
-LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING__FUNCTION_TO_STRING, "function(){/* ecmascript */}")
+#if JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_ASYNC_GENERATOR, "async function* anonymous(")
+#endif
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FUNCTION_TO_STRING_NATIVE, "function () { [native code] }")
+#if JERRY_FUNCTION_TO_STRING && JERRY_SNAPSHOT_EXEC \
+|| !(JERRY_FUNCTION_TO_STRING)
+LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FUNCTION_TO_STRING_ECMA, "function () { /* ecmascript */ }")
+#endif
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (0, LIT_MAGIC_STRING__EMPTY)
#if JERRY_ESNEXT
@@ -1213,8 +1229,16 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (17, LIT_MAGIC_STRING_GET_TIMEZONE_OFFSE
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (17, LIT_MAGIC_STRING_PREVENT_EXTENSIONS_UL)
#endif
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (18, LIT_MAGIC_STRING_DECODE_URI_COMPONENT)
+#if JERRY_FUNCTION_TO_STRING
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (19, LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON)
+#else
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (19, LIT_MAGIC_STRING_GET_OWN_PROPERTY_NAMES_UL)
+#endif
+#if JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (20, LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_GENERATOR)
+#else
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (20, LIT_MAGIC_STRING_PROPERTY_IS_ENUMERABLE_UL)
+#endif
#if JERRY_ESNEXT
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (21, LIT_MAGIC_STRING_GET_OWN_PROPERTY_SYMBOLS_UL)
#else
@@ -1227,11 +1251,32 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (22, LIT_MAGIC_STRING_GET_OWN_PROPERTY_D
#endif
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (23, LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTOR_UL)
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (24, LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTOR_UL)
-#if JERRY_ESNEXT
+#if JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (25, LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_ASYNC)
+#elif JERRY_ESNEXT
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (25, LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTORS_UL)
+#elif JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (25, LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_ASYNC_GENERATOR)
+#else
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (25, LIT_MAGIC_STRING_FUNCTION_TO_STRING_NATIVE)
+#endif
+#if JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (26, LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_ASYNC_GENERATOR)
#else
-LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (25, LIT_MAGIC_STRING__FUNCTION_TO_STRING)
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (26, LIT_MAGIC_STRING_FUNCTION_TO_STRING_NATIVE)
+#endif
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (27, LIT_MAGIC_STRING_FUNCTION_TO_STRING_NATIVE)
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (28, LIT_MAGIC_STRING_FUNCTION_TO_STRING_NATIVE)
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (29, LIT_MAGIC_STRING_FUNCTION_TO_STRING_NATIVE)
+#if JERRY_FUNCTION_TO_STRING && JERRY_SNAPSHOT_EXEC \
+|| !(JERRY_FUNCTION_TO_STRING)
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (30, LIT_MAGIC_STRING_FUNCTION_TO_STRING_ECMA)
+#endif
+#if JERRY_FUNCTION_TO_STRING && JERRY_SNAPSHOT_EXEC \
+|| !(JERRY_FUNCTION_TO_STRING)
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (31, LIT_MAGIC_STRING_FUNCTION_TO_STRING_ECMA)
+#endif
+#if JERRY_FUNCTION_TO_STRING && JERRY_SNAPSHOT_EXEC \
+|| !(JERRY_FUNCTION_TO_STRING)
+LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (32, LIT_MAGIC_STRING_FUNCTION_TO_STRING_ECMA)
#endif
-LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (26, LIT_MAGIC_STRING__FUNCTION_TO_STRING)
-LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (27, LIT_MAGIC_STRING__FUNCTION_TO_STRING)
-LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (28, LIT_MAGIC_STRING__FUNCTION_TO_STRING)
diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini
index a52e429ffc..8f311d1040 100644
--- a/jerry-core/lit/lit-magic-strings.ini
+++ b/jerry-core/lit/lit-magic-strings.ini
@@ -406,10 +406,15 @@ LIT_MAGIC_STRING_SET_UTC_MILLISECONDS_UL = "setUTCMilliseconds"
LIT_MAGIC_STRING_TO_LOCALE_DATE_STRING_UL = "toLocaleDateString"
LIT_MAGIC_STRING_TO_LOCALE_TIME_STRING_UL = "toLocaleTimeString"
LIT_MAGIC_STRING_GET_OWN_PROPERTY_NAMES_UL = "getOwnPropertyNames"
+LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON = "function anonymous("
+LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_GENERATOR = "function* anonymous("
LIT_MAGIC_STRING_PROPERTY_IS_ENUMERABLE_UL = "propertyIsEnumerable"
LIT_MAGIC_STRING_GET_OWN_PROPERTY_SYMBOLS_UL = "getOwnPropertySymbols"
LIT_MAGIC_STRING_REGEXP_STRING_ITERATOR_UL = "RegExp String Iterator"
LIT_MAGIC_STRING_ASYNC_GENERATOR_FUNCTION_UL = "AsyncGeneratorFunction"
LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTOR_UL = "getOwnPropertyDescriptor"
+LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_ASYNC = "async function anonymous("
LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTORS_UL = "getOwnPropertyDescriptors"
-LIT_MAGIC_STRING__FUNCTION_TO_STRING = "function(){/* ecmascript */}"
+LIT_MAGIC_STRING_FUNCTION_TO_STRING_ANON_ASYNC_GENERATOR = "async function* anonymous("
+LIT_MAGIC_STRING_FUNCTION_TO_STRING_NATIVE = "function () { [native code] }"
+LIT_MAGIC_STRING_FUNCTION_TO_STRING_ECMA = "function () { /* ecmascript */ }"
diff --git a/jerry-core/lit/lit-strings.c b/jerry-core/lit/lit-strings.c
index c2e6d929da..81d4ac0720 100644
--- a/jerry-core/lit/lit-strings.c
+++ b/jerry-core/lit/lit-strings.c
@@ -22,14 +22,14 @@
*
* NOTE:
* Isolated surrogates are allowed.
- * Correct pair of surrogates is not allowed, it should be represented as 4-byte utf-8 character.
*
* @return true if utf-8 string is well-formed
* false otherwise
*/
bool
lit_is_valid_utf8_string (const lit_utf8_byte_t *utf8_buf_p, /**< utf-8 string */
- lit_utf8_size_t buf_size) /**< string size */
+ lit_utf8_size_t buf_size, /**< string size */
+ bool is_strict) /**< true if surrogate pairs are not allowed */
{
lit_utf8_size_t idx = 0;
@@ -95,21 +95,22 @@ lit_is_valid_utf8_string (const lit_utf8_byte_t *utf8_buf_p, /**< utf-8 string *
return false;
}
- if (code_point >= LIT_UTF16_HIGH_SURROGATE_MIN
- && code_point <= LIT_UTF16_HIGH_SURROGATE_MAX)
- {
- is_prev_code_point_high_surrogate = true;
- }
- else if (code_point >= LIT_UTF16_LOW_SURROGATE_MIN
- && code_point <= LIT_UTF16_LOW_SURROGATE_MAX
- && is_prev_code_point_high_surrogate)
- {
- /* sequence of high and low surrogate is not allowed */
- return false;
- }
- else
+ if (is_strict)
{
is_prev_code_point_high_surrogate = false;
+
+ if (code_point >= LIT_UTF16_HIGH_SURROGATE_MIN
+ && code_point <= LIT_UTF16_HIGH_SURROGATE_MAX)
+ {
+ is_prev_code_point_high_surrogate = true;
+ }
+ else if (code_point >= LIT_UTF16_LOW_SURROGATE_MIN
+ && code_point <= LIT_UTF16_LOW_SURROGATE_MAX
+ && is_prev_code_point_high_surrogate)
+ {
+ /* sequence of high and low surrogate is not allowed */
+ return false;
+ }
}
idx += extra_bytes_count;
diff --git a/jerry-core/lit/lit-strings.h b/jerry-core/lit/lit-strings.h
index 7ba61a2c06..0c18da4cb3 100644
--- a/jerry-core/lit/lit-strings.h
+++ b/jerry-core/lit/lit-strings.h
@@ -84,7 +84,7 @@
#define LIT_UTF8_FIRST_BYTE_MAX (0xF8)
/* validation */
-bool lit_is_valid_utf8_string (const lit_utf8_byte_t *utf8_buf_p, lit_utf8_size_t buf_size);
+bool lit_is_valid_utf8_string (const lit_utf8_byte_t *utf8_buf_p, lit_utf8_size_t buf_size, bool strict);
bool lit_is_valid_cesu8_string (const lit_utf8_byte_t *cesu8_buf_p, lit_utf8_size_t buf_size);
/* checks */
diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h
index 7f3e7ffdc5..1f9f0321a4 100644
--- a/jerry-core/parser/js/byte-code.h
+++ b/jerry-core/parser/js/byte-code.h
@@ -895,6 +895,27 @@ typedef enum
check a range of types without decoding the actual type. */
} cbc_code_flags_t;
+/**
+ * Optional byte code fields. These fields are stored in a reversed
+ * order from the end of the byte code data.
+ *
+ * Value fields:
+ * - when CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED is set:
+ * argument_end number of argument names encoded as strings
+ * - when function type is not CBC_FUNCTION_CONSTRUCTOR:
+ * function name encoded as string
+ * - when CBC_CODE_FLAGS_HAS_TAGGED_LITERALS is set:
+ * pointer to the tagged template collection encoded as value
+ *
+ * Byte fields when CBC_CODE_FLAGS_HAS_EXTENDED_INFO is set:
+ * - always available:
+ * a byte which contains a combination of CBC_EXTENDED_CODE_FLAGS bits
+ * - when CBC_EXTENDED_CODE_FLAGS_HAS_ARGUMENT_LENGTH is set:
+ * a vlq encoded default value for function length
+ * - when CBC_EXTENDED_CODE_FLAGS_HAS_SOURCE_CODE_RANGE is set:
+ * a pair of vlq encoded values, representing the start and size of the range
+ */
+
/**
* Compact byte code function types.
*/
@@ -962,9 +983,15 @@ typedef enum
((flags) >= (CBC_FUNCTION_ARROW << CBC_FUNCTION_TYPE_SHIFT))
/**
- * Get length property from extended info
+ * Compact byte code extended status flags.
*/
-#define CBC_EXTENDED_INFO_GET_LENGTH(extended_info) (extended_info)
+typedef enum
+{
+ CBC_EXTENDED_CODE_FLAGS_HAS_ARGUMENT_LENGTH = (1u << 0), /**< has argument length */
+ CBC_EXTENDED_CODE_FLAGS_HAS_SOURCE_CODE_RANGE = (1u << 1), /**< has source code range (start, end) */
+ CBC_EXTENDED_CODE_FLAGS_SOURCE_CODE_IN_ARGUMENTS = (1u << 2), /**< source code range is inside
+ * the function arguments */
+} cbc_extended_code_flags_t;
/**
* Shared script data.
@@ -977,20 +1004,25 @@ typedef enum
} cbc_script_type;
/**
- * Value for increasing or decreasing the script reference counter.
+ * Script is a function with arguments source code.
*/
-#define CBC_SCRIPT_REF_ONE 0x4
+#define CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS 0x4
/**
- * Get the type of a script.
+ * Value for increasing or decreasing the script reference counter.
*/
-#define CBC_SCRIPT_GET_TYPE(script_p) ((script_p)->refs_and_type & (CBC_SCRIPT_REF_ONE - 1))
+#define CBC_SCRIPT_REF_ONE 0x8
/**
* Maximum value of script reference counter.
*/
#define CBC_SCRIPT_REF_MAX (UINT32_MAX - CBC_SCRIPT_REF_ONE + 1)
+/**
+ * Get the type of a script.
+ */
+#define CBC_SCRIPT_GET_TYPE(script_p) ((script_p)->refs_and_type & 0x3)
+
/**
* Sets the type of a script using the user_value.
*/
@@ -1018,16 +1050,30 @@ typedef struct
#if JERRY_RESOURCE_NAME
ecma_value_t resource_name; /**< resource name */
#endif /* JERRY_RESOURCE_NAME */
+#if JERRY_FUNCTION_TO_STRING
+ ecma_value_t source_code; /**< source code */
+#endif /* JERRY_FUNCTION_TO_STRING */
} cbc_script_t;
/**
- * Script data with user value.
+ * Get the array of optional values assigned to a script.
+ *
+ * First value: user value
+ * Second value: function arguments value
*/
-typedef struct
-{
- cbc_script_t header; /**< script header */
- ecma_value_t user_value; /**< user value */
-} cbc_script_user_t;
+#define CBC_SCRIPT_GET_OPTIONAL_VALUES(script_p) ((ecma_value_t *) ((script_p) + 1))
+
+/**
+ * Get user value.
+ */
+#define CBC_SCRIPT_GET_USER_VALUE(script_p) \
+ (CBC_SCRIPT_GET_OPTIONAL_VALUES (script_p)[0])
+
+/**
+ * Get function arguments.
+ */
+#define CBC_SCRIPT_GET_FUNCTION_ARGUMENTS(script_p, type) \
+ (CBC_SCRIPT_GET_OPTIONAL_VALUES (script_p)[(type) != CBC_SCRIPT_GENERIC ? 1 : 0])
#define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1,
diff --git a/jerry-core/parser/js/common.c b/jerry-core/parser/js/common.c
index 6985d77241..cf241a12f0 100644
--- a/jerry-core/parser/js/common.c
+++ b/jerry-core/parser/js/common.c
@@ -15,6 +15,7 @@
#include "common.h"
#include "ecma-helpers.h"
+#include "ecma-extended-info.h"
#include "ecma-big-uint.h"
#include "ecma-bigint.h"
#include "js-parser-internal.h"
@@ -396,16 +397,31 @@ util_print_cbc (ecma_compiled_code_t *compiled_code_p) /**< compiled code */
JERRY_DEBUG_MSG (" Const literal range end: %d\n", (int) const_literal_end);
JERRY_DEBUG_MSG (" Literal range end: %d\n\n", (int) literal_end);
-#if JERRY_ESNEXT
+#if JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING
if (compiled_code_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO)
{
- uint32_t extended_info = ecma_compiled_code_resolve_extended_info (compiled_code_p);
+ uint8_t *extended_info_p = ecma_compiled_code_resolve_extended_info (compiled_code_p);
+ uint8_t *extended_info_start_p = extended_info_p + sizeof (uint8_t);
+ uint8_t extended_info = *extended_info_p;
- JERRY_DEBUG_MSG (" [Extended] Argument length: %d\n\n", (int) CBC_EXTENDED_INFO_GET_LENGTH (extended_info));
+ if (extended_info & CBC_EXTENDED_CODE_FLAGS_HAS_ARGUMENT_LENGTH)
+ {
+ uint32_t argument_length = ecma_extended_info_decode_vlq (&extended_info_p);
+ JERRY_DEBUG_MSG (" [Extended] Argument length: %d\n", (int) argument_length);
+ }
- size -= sizeof (ecma_value_t);
+ if (extended_info & CBC_EXTENDED_CODE_FLAGS_HAS_SOURCE_CODE_RANGE)
+ {
+ uint32_t range_start = ecma_extended_info_decode_vlq (&extended_info_p);
+ uint32_t range_end = ecma_extended_info_decode_vlq (&extended_info_p) + range_start;
+ JERRY_DEBUG_MSG (" [Extended] Source code range: %d - %d\n", (int) range_start, (int) range_end);
+ }
+
+ JERRY_DEBUG_MSG ("\n");
+
+ size -= (size_t) (extended_info_start_p - extended_info_p);
}
-#endif /* JERRY_ESNEXT */
+#endif /* JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING */
byte_code_start_p = (uint8_t *) compiled_code_p;
diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c
index fe8d5a747d..98dec512e1 100644
--- a/jerry-core/parser/js/js-lexer.c
+++ b/jerry-core/parser/js/js-lexer.c
@@ -741,6 +741,9 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
{
decoded_length = 2 * 3;
status_flags = LEXER_LIT_LOCATION_HAS_ESCAPE;
+#if JERRY_FUNCTION_TO_STRING
+ context_p->global_status_flags |= ECMA_PARSE_INTERNAL_HAS_4_BYTE_MARKER;
+#endif /* JERRY_FUNCTION_TO_STRING */
}
#else /* !JERRY_ESNEXT */
if (code_point < LIT_UTF8_4_BYTE_MARKER)
@@ -1171,6 +1174,9 @@ lexer_parse_string (parser_context_t *context_p, /**< context */
raw_length_adjust += 2;
#endif /* JERRY_ESNEXT */
column++;
+#if JERRY_FUNCTION_TO_STRING
+ context_p->global_status_flags |= ECMA_PARSE_INTERNAL_HAS_4_BYTE_MARKER;
+#endif /* JERRY_FUNCTION_TO_STRING */
continue;
}
else if (*source_p == LIT_CHAR_TAB)
@@ -1605,6 +1611,11 @@ lexer_next_token (parser_context_t *context_p) /**< context */
{
size_t length;
+#if JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING
+ /* Needed by arrow functions with expression body */
+ context_p->function_end_p = context_p->source_p;
+#endif /* JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING */
+
lexer_skip_spaces (context_p);
context_p->token.keyword_type = LEXER_EOS;
@@ -3069,7 +3080,7 @@ lexer_construct_regexp_object (parser_context_t *context_p, /**< context */
}
else
{
- JERRY_ASSERT (lit_is_valid_utf8_string (regex_start_p, length));
+ JERRY_ASSERT (lit_is_valid_utf8_string (regex_start_p, length, false));
pattern_str_p = ecma_new_ecma_string_from_utf8_converted_to_cesu8 (regex_start_p, length);
}
@@ -3189,6 +3200,13 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
JERRY_ASSERT ((ident_opts & LEXER_OBJ_IDENT_CLASS_IDENTIFIER)
|| !(ident_opts & LEXER_OBJ_IDENT_CLASS_NO_STATIC));
+#if JERRY_FUNCTION_TO_STRING
+ if (ident_opts & LEXER_OBJ_IDENT_SET_FUNCTION_START)
+ {
+ context_p->function_start_p = context_p->source_p;
+ }
+#endif /* JERRY_FUNCTION_TO_STRING */
+
if (lexer_parse_identifier (context_p, LEXER_PARSE_NO_OPTS))
{
if (!(ident_opts & (LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJECT_PATTERN)))
@@ -3253,6 +3271,10 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
#if JERRY_ESNEXT
case LIT_CHAR_LEFT_SQUARE:
{
+#if JERRY_FUNCTION_TO_STRING
+ const uint8_t *function_start_p = context_p->function_start_p;
+#endif /* JERRY_FUNCTION_TO_STRING */
+
lexer_consume_next_character (context_p);
lexer_next_token (context_p);
@@ -3262,6 +3284,10 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_SQUARE_EXPECTED);
}
+
+#if JERRY_FUNCTION_TO_STRING
+ context_p->function_start_p = function_start_p;
+#endif /* JERRY_FUNCTION_TO_STRING */
return;
}
case LIT_CHAR_ASTERISK:
@@ -3277,7 +3303,7 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
}
case LIT_CHAR_DOT:
{
- if ((ident_opts & ((uint32_t) ~LEXER_OBJ_IDENT_OBJECT_PATTERN))
+ if ((ident_opts & ((uint32_t) ~(LEXER_OBJ_IDENT_OBJECT_PATTERN | LEXER_OBJ_IDENT_SET_FUNCTION_START)))
|| context_p->source_p + 2 >= context_p->source_end_p
|| context_p->source_p[1] != LIT_CHAR_DOT
|| context_p->source_p[2] != LIT_CHAR_DOT)
diff --git a/jerry-core/parser/js/js-lexer.h b/jerry-core/parser/js/js-lexer.h
index e9f948cb5a..71b7c0394c 100644
--- a/jerry-core/parser/js/js-lexer.h
+++ b/jerry-core/parser/js/js-lexer.h
@@ -275,11 +275,16 @@ typedef enum
*/
typedef enum
{
- LEXER_OBJ_IDENT_NO_OPTS = 0, /**< no options */
- LEXER_OBJ_IDENT_ONLY_IDENTIFIERS = (1u << 0), /**< only identifiers are accepted */
- LEXER_OBJ_IDENT_CLASS_IDENTIFIER = (1u << 1), /**< expect identifier inside a class body */
- LEXER_OBJ_IDENT_CLASS_NO_STATIC = (1u << 2), /**< static keyword was not present before the identifier */
- LEXER_OBJ_IDENT_OBJECT_PATTERN = (1u << 3), /**< parse "get"/"set" as string literal in object pattern */
+ LEXER_OBJ_IDENT_NO_OPTS = 0, /**< no options */
+ LEXER_OBJ_IDENT_ONLY_IDENTIFIERS = (1u << 0), /**< only identifiers are accepted */
+ LEXER_OBJ_IDENT_CLASS_IDENTIFIER = (1u << 1), /**< expect identifier inside a class body */
+ LEXER_OBJ_IDENT_CLASS_NO_STATIC = (1u << 2), /**< static keyword was not present before the identifier */
+ LEXER_OBJ_IDENT_OBJECT_PATTERN = (1u << 3), /**< parse "get"/"set" as string literal in object pattern */
+#if JERRY_FUNCTION_TO_STRING
+ LEXER_OBJ_IDENT_SET_FUNCTION_START = (1u << 4), /**< set function start */
+#else /* !JERRY_FUNCTION_TO_STRING */
+ LEXER_OBJ_IDENT_SET_FUNCTION_START = 0, /**< set function start (disabled) */
+#endif /* JERRY_FUNCTION_TO_STRING */
} lexer_obj_ident_opts_t;
/**
diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c
index 0088b20fef..6e347a8e8e 100644
--- a/jerry-core/parser/js/js-parser-expr.c
+++ b/jerry-core/parser/js/js-parser-expr.c
@@ -562,6 +562,7 @@ parser_parse_class_body (parser_context_t *context_p, /**< context */
}
lexer_expect_object_literal_id (context_p, (LEXER_OBJ_IDENT_CLASS_IDENTIFIER
+ | LEXER_OBJ_IDENT_SET_FUNCTION_START
| (is_static ? 0 : LEXER_OBJ_IDENT_CLASS_NO_STATIC)));
if (context_p->token.type == LEXER_RIGHT_BRACE)
@@ -1167,7 +1168,7 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */
while (true)
{
- lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_NO_OPTS);
+ lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_SET_FUNCTION_START);
switch (context_p->token.type)
{
@@ -2011,6 +2012,10 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
+#if JERRY_FUNCTION_TO_STRING
+ context_p->function_start_p = context_p->token.lit_location.char_p;
+#endif /* JERRY_FUNCTION_TO_STRING */
+
uint32_t arrow_status_flags = (PARSER_IS_FUNCTION
| PARSER_IS_ARROW_FUNCTION
| (context_p->status_flags & PARSER_INSIDE_CLASS_FIELD));
@@ -2124,6 +2129,9 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
}
case LEXER_KEYW_FUNCTION:
{
+#if JERRY_FUNCTION_TO_STRING
+ context_p->function_start_p = context_p->token.lit_location.char_p;
+#endif /* JERRY_FUNCTION_TO_STRING */
parser_parse_function_expression (context_p, PARSER_FUNCTION_CLOSURE | PARSER_IS_FUNC_EXPRESSION);
break;
}
@@ -2270,6 +2278,10 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
parser_check_assignment_expr (context_p);
+#if JERRY_FUNCTION_TO_STRING
+ context_p->function_start_p = context_p->source_p - 1;
+#endif /* JERRY_FUNCTION_TO_STRING */
+
uint32_t arrow_status_flags = (PARSER_IS_FUNCTION
| PARSER_IS_ARROW_FUNCTION
| (context_p->status_flags & PARSER_INSIDE_CLASS_FIELD));
diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h
index 237051d825..3d0e77b782 100644
--- a/jerry-core/parser/js/js-parser-internal.h
+++ b/jerry-core/parser/js/js-parser-internal.h
@@ -539,6 +539,10 @@ typedef struct parser_saved_context_t
#if JERRY_LINE_INFO
parser_line_info_data_t *line_info_p; /**< line info data */
#endif /* JERRY_LINE_INFO */
+
+#if JERRY_FUNCTION_TO_STRING
+ const uint8_t *function_start_p; /**< start position of the current function */
+#endif /* JERRY_FUNCTION_TO_STRING */
} parser_saved_context_t;
/**
@@ -571,6 +575,7 @@ typedef struct
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 argument_list; /**< current argument list as value */
ecma_value_t user_value; /**< current user value */
#if JERRY_MODULE_SYSTEM
@@ -639,6 +644,11 @@ typedef struct
#if JERRY_LINE_INFO
parser_line_info_data_t *line_info_p; /**< line info data */
#endif /* JERRY_LINE_INFO */
+
+#if JERRY_FUNCTION_TO_STRING
+ const uint8_t *function_start_p; /**< start position of the function which will be parsed */
+ const uint8_t *function_end_p; /**< end position of the current function */
+#endif /* JERRY_FUNCTION_TO_STRING */
} parser_context_t;
/**
diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c
index bd69b6966e..6ce13c5229 100644
--- a/jerry-core/parser/js/js-parser-statm.c
+++ b/jerry-core/parser/js/js-parser-statm.c
@@ -656,6 +656,17 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
}
#endif /* JERRY_ESNEXT */
+#if JERRY_FUNCTION_TO_STRING
+#if JERRY_ESNEXT
+ if (!(context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC))
+ {
+ context_p->function_start_p = context_p->token.lit_location.char_p;
+ }
+#else /* !JERRY_ESNEXT */
+ context_p->function_start_p = context_p->token.lit_location.char_p;
+#endif /* JERRY_ESNEXT */
+#endif /* JERRY_FUNCTION_TO_STRING */
+
#if JERRY_DEBUGGER
parser_line_counter_t debugger_line = context_p->token.line;
parser_line_counter_t debugger_column = context_p->token.column;
@@ -2560,6 +2571,9 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */
&& context_p->next_scanner_info_p->source_p == context_p->source_p
&& context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION)
{
+#if JERRY_FUNCTION_TO_STRING
+ context_p->function_start_p = context_p->token.lit_location.char_p;
+#endif /* JERRY_FUNCTION_TO_STRING */
lexer_next_token (context_p);
}
@@ -3246,6 +3260,9 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
parser_raise_error (context_p, PARSER_ERR_LEXICAL_SINGLE_STATEMENT);
}
+#if JERRY_FUNCTION_TO_STRING
+ context_p->function_start_p = context_p->token.lit_location.char_p;
+#endif /* JERRY_FUNCTION_TO_STRING */
lexer_next_token (context_p);
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FUNCTION);
continue;
@@ -3343,6 +3360,10 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
}
#endif /* JERRY_LINE_INFO */
+#if JERRY_FUNCTION_TO_STRING
+ context_p->function_end_p = context_p->source_p;
+#endif /* JERRY_FUNCTION_TO_STRING */
+
parser_stack_pop_uint8 (context_p);
context_p->last_statement.current_p = NULL;
/* There is no lexer_next_token here, since the
diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c
index 5fa0448000..25f43e7b2c 100644
--- a/jerry-core/parser/js/js-parser.c
+++ b/jerry-core/parser/js/js-parser.c
@@ -15,6 +15,7 @@
#include "debugger.h"
#include "ecma-exceptions.h"
+#include "ecma-extended-info.h"
#include "ecma-helpers.h"
#include "ecma-literal-storage.h"
#include "ecma-module.h"
@@ -910,11 +911,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */
total_size += sizeof (ecma_value_t);
}
- if (context_p->argument_length != UINT16_MAX)
- {
- total_size += sizeof (ecma_value_t);
- }
-
if (context_p->tagged_template_literal_cp != JMEM_CP_NULL)
{
total_size += sizeof (ecma_value_t);
@@ -925,6 +921,48 @@ parser_post_processing (parser_context_t *context_p) /**< context */
total_size += sizeof (ecma_value_t);
#endif /* JERRY_LINE_INFO */
+#if JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING
+ uint8_t extended_info = 0;
+#endif /* JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING */
+
+#if JERRY_ESNEXT
+ if (context_p->argument_length != UINT16_MAX)
+ {
+ extended_info |= CBC_EXTENDED_CODE_FLAGS_HAS_ARGUMENT_LENGTH;
+ total_size += ecma_extended_info_get_encoded_length (context_p->argument_length);
+ }
+#endif /* JERRY_ESNEXT */
+
+#if JERRY_FUNCTION_TO_STRING
+ if (context_p->last_context_p != NULL)
+ {
+ extended_info |= CBC_EXTENDED_CODE_FLAGS_HAS_SOURCE_CODE_RANGE;
+
+ const uint8_t *start_p = context_p->source_start_p;
+ const uint8_t *function_start_p = context_p->last_context_p->function_start_p;
+
+ if (function_start_p < start_p || function_start_p >= start_p + context_p->source_size)
+ {
+ JERRY_ASSERT (context_p->arguments_start_p != NULL
+ && function_start_p >= context_p->arguments_start_p
+ && function_start_p < context_p->arguments_start_p + context_p->arguments_size);
+
+ start_p = context_p->arguments_start_p;
+ extended_info |= CBC_EXTENDED_CODE_FLAGS_SOURCE_CODE_IN_ARGUMENTS;
+ }
+
+ total_size += ecma_extended_info_get_encoded_length ((uint32_t) (function_start_p - start_p));
+ total_size += ecma_extended_info_get_encoded_length ((uint32_t) (context_p->function_end_p - function_start_p));
+ }
+#endif /* JERRY_FUNCTION_TO_STRING */
+
+#if JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING
+ if (extended_info != 0)
+ {
+ total_size += sizeof (uint8_t);
+ }
+#endif /* JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING */
+
total_size = JERRY_ALIGNUP (total_size, JMEM_ALIGNMENT);
compiled_code_p = (ecma_compiled_code_t *) parser_malloc (context_p, total_size);
@@ -1327,19 +1365,10 @@ parser_post_processing (parser_context_t *context_p) /**< context */
*(--base_p) = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
}
- if (context_p->argument_length != UINT16_MAX)
- {
- compiled_code_p->status_flags |= CBC_CODE_FLAGS_HAS_EXTENDED_INFO;
- *(--base_p) = context_p->argument_length;
- }
-
if (context_p->tagged_template_literal_cp != JMEM_CP_NULL)
{
compiled_code_p->status_flags |= CBC_CODE_FLAGS_HAS_TAGGED_LITERALS;
- base_p[-1] = (ecma_value_t) context_p->tagged_template_literal_cp;
-#if JERRY_LINE_INFO
- --base_p;
-#endif /* JERRY_LINE_INFO */
+ *(--base_p) = (ecma_value_t) context_p->tagged_template_literal_cp;
}
#endif /* JERRY_ESNEXT */
@@ -1347,6 +1376,44 @@ parser_post_processing (parser_context_t *context_p) /**< context */
ECMA_SET_INTERNAL_VALUE_POINTER (base_p[-1], line_info_p);
#endif /* JERRY_LINE_INFO */
+#if JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING
+ if (extended_info != 0)
+ {
+#if JERRY_LINE_INFO
+ base_p--;
+#endif /* JERRY_LINE_INFO */
+
+ uint8_t *extended_info_p = ((uint8_t *) base_p) - 1;
+
+ compiled_code_p->status_flags |= CBC_CODE_FLAGS_HAS_EXTENDED_INFO;
+ *extended_info_p = extended_info;
+
+#if JERRY_ESNEXT
+ if (context_p->argument_length != UINT16_MAX)
+ {
+ ecma_extended_info_encode_vlq (&extended_info_p, context_p->argument_length);
+ }
+#endif /* JERRY_ESNEXT */
+
+#if JERRY_FUNCTION_TO_STRING
+ if (context_p->last_context_p != NULL)
+ {
+ const uint8_t *start_p = context_p->source_start_p;
+
+ if (extended_info & CBC_EXTENDED_CODE_FLAGS_SOURCE_CODE_IN_ARGUMENTS)
+ {
+ start_p = context_p->arguments_start_p;
+ }
+
+ const uint8_t *function_start_p = context_p->last_context_p->function_start_p;
+
+ ecma_extended_info_encode_vlq (&extended_info_p, (uint32_t) (function_start_p - start_p));
+ ecma_extended_info_encode_vlq (&extended_info_p, (uint32_t) (context_p->function_end_p - function_start_p));
+ }
+#endif /* JERRY_FUNCTION_TO_STRING */
+ }
+#endif /* JERRY_ESNEXT || JERRY_FUNCTION_TO_STRING */
+
#if JERRY_PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
@@ -1793,22 +1860,22 @@ parser_parse_source (void *source_p, /**< source code */
context.module_names_p = NULL;
#endif /* JERRY_MODULE_SYSTEM */
- ecma_value_t argument_list = ECMA_VALUE_EMPTY;
+ context.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;
+ context.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];
+ context.argument_list = ((ecma_value_t *) source_p)[1];
}
- if (argument_list != ECMA_VALUE_EMPTY)
+ if (context.argument_list != ECMA_VALUE_EMPTY)
{
- JERRY_ASSERT (ecma_is_value_string (argument_list));
+ JERRY_ASSERT (ecma_is_value_string (context.argument_list));
context.status_flags |= PARSER_IS_FUNCTION;
#if JERRY_ESNEXT
@@ -1822,7 +1889,7 @@ parser_parse_source (void *source_p, /**< source code */
}
#endif /* JERRY_ESNEXT */
- ecma_string_t *string_p = ecma_get_string_from_value (argument_list);
+ ecma_string_t *string_p = ecma_get_string_from_value (context.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);
@@ -1881,7 +1948,7 @@ parser_parse_source (void *source_p, /**< source code */
if (CBC_SCRIPT_GET_TYPE (parent_script_p) != CBC_SCRIPT_GENERIC)
{
- context.user_value = ((cbc_script_user_t *) parent_script_p)->user_value;
+ context.user_value = CBC_SCRIPT_GET_USER_VALUE (parent_script_p);
}
#if JERRY_SNAPSHOT_EXEC
}
@@ -1893,8 +1960,20 @@ parser_parse_source (void *source_p, /**< source code */
context.user_value = context.options_p->user_value;
}
- uint32_t script_size = (context.user_value != ECMA_VALUE_EMPTY ? sizeof (cbc_script_user_t)
- : sizeof (cbc_script_t));
+ size_t script_size = sizeof (cbc_script_t);
+
+ if (context.user_value != ECMA_VALUE_EMPTY)
+ {
+ script_size += sizeof (ecma_value_t);
+ }
+
+#if JERRY_FUNCTION_TO_STRING
+ if (context.argument_list != ECMA_VALUE_EMPTY)
+ {
+ script_size += sizeof (ecma_value_t);
+ }
+#endif /* JERRY_FUNCTION_TO_STRING */
+
context.script_p = jmem_heap_alloc_block_null_on_error (script_size);
if (JERRY_UNLIKELY (context.script_p == NULL))
@@ -1977,6 +2056,11 @@ parser_parse_source (void *source_p, /**< source code */
context.line_info_p = NULL;
#endif /* JERRY_LINE_INFO */
+#if JERRY_FUNCTION_TO_STRING
+ context.function_start_p = NULL;
+ context.function_end_p = NULL;
+#endif /* JERRY_FUNCTION_TO_STRING */
+
#if JERRY_PARSER_DUMP_BYTE_CODE
context.is_show_opcodes = (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_SHOW_OPCODES);
context.total_byte_code_size = 0;
@@ -2116,9 +2200,44 @@ parser_parse_source (void *source_p, /**< source code */
if (context.user_value != ECMA_VALUE_EMPTY)
{
- ((cbc_script_user_t *) context.script_p)->user_value = ecma_copy_value_if_not_object (context.user_value);
+ CBC_SCRIPT_GET_USER_VALUE (context.script_p) = ecma_copy_value_if_not_object (context.user_value);
}
+#if JERRY_FUNCTION_TO_STRING
+ if (!(context.global_status_flags & ECMA_PARSE_HAS_SOURCE_VALUE))
+ {
+ ecma_string_t *string_p;
+
+ if (context.global_status_flags & ECMA_PARSE_INTERNAL_HAS_4_BYTE_MARKER)
+ {
+ string_p = ecma_new_ecma_string_from_utf8_converted_to_cesu8 (context.source_start_p, context.source_size);
+ }
+ else
+ {
+ string_p = ecma_new_ecma_string_from_utf8 (context.source_start_p, context.source_size);
+ }
+
+ context.script_p->source_code = ecma_make_string_value (string_p);
+ }
+ else
+ {
+ ecma_value_t source = ((ecma_value_t *) source_p)[0];
+
+ ecma_ref_ecma_string (ecma_get_string_from_value (source));
+ context.script_p->source_code = source;
+ }
+
+ if (context.argument_list != ECMA_VALUE_EMPTY)
+ {
+ int idx = (context.user_value != ECMA_VALUE_EMPTY) ? 1 : 0;
+
+ CBC_SCRIPT_GET_OPTIONAL_VALUES (context.script_p)[idx] = context.argument_list;
+
+ ecma_ref_ecma_string (ecma_get_string_from_value (context.argument_list));
+ context.script_p->refs_and_type |= CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS;
+ }
+#endif /* JERRY_FUNCTION_TO_STRING */
+
#if JERRY_PARSER_DUMP_BYTE_CODE
if (context.is_show_opcodes)
{
@@ -2315,6 +2434,10 @@ parser_save_context (parser_context_t *context_p, /**< context */
saved_context_p->line_info_p = context_p->line_info_p;
#endif /* JERRY_LINE_INFO */
+#if JERRY_FUNCTION_TO_STRING
+ saved_context_p->function_start_p = context_p->function_start_p;
+#endif /* JERRY_FUNCTION_TO_STRING */
+
/* Reset private part of the context. */
context_p->status_flags &= PARSER_IS_STRICT;
diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c
index bfa251a811..e428f60dce 100644
--- a/jerry-core/vm/vm.c
+++ b/jerry-core/vm/vm.c
@@ -4573,7 +4573,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
if (CBC_SCRIPT_GET_TYPE (script_p) != CBC_SCRIPT_GENERIC)
{
- user_value = ((cbc_script_user_t *) script_p)->user_value;
+ user_value = CBC_SCRIPT_GET_USER_VALUE (script_p);
}
#if JERRY_SNAPSHOT_EXEC
}
diff --git a/tests/jerry/es.next/function-prototype-tostring.js b/tests/jerry/es.next/function-prototype-tostring.js
new file mode 100644
index 0000000000..72abaefe81
--- /dev/null
+++ b/tests/jerry/es.next/function-prototype-tostring.js
@@ -0,0 +1,188 @@
+// 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.
+
+function check() {}
+
+if (check.toString() !== "function () { /* ecmascript */ }")
+{
+ var a, b, o, c, f;
+
+ /* Function statements. */
+
+ a = 6; function f1(a,b=1,c) { return a /* comment */ + b + c } b = 7
+ assert(f1.toString() === "function f1(a,b=1,c) { return a /* comment */ + b + c }")
+
+ a = 6; function * f2(a,b,c=1) {
+ function x() {}
+ } b = 7
+ assert(f2.toString() === "function * f2(a,b,c=1) {\n function x() {}\n }")
+
+ a = 6;async function f3 ( a , b , c ) { } b = 7
+ assert(f3.toString() === "async function f3 ( a , b , c ) { }")
+
+ a = 6;async/**/function*f4(a,b,c){} b = 7
+ assert(f4.toString() === "async/**/function*f4(a,b,c){}")
+
+ /* Object initializers. */
+
+ o = {f(a) { return a }}
+ assert(o.f.toString() === "f(a) { return a }")
+
+ o = {f:function(a){/**/}}
+ assert(o.f.toString() === "function(a){/**/}")
+
+ o = { [function(){ return 'f' }()] (a = function() {}) {} }
+ assert(o.f.toString() === "[function(){ return 'f' }()] (a = function() {}) {}")
+
+ o = {* f(a) {}}
+ assert(o.f.toString() === "* f(a) {}")
+
+ o = {*[function(){ return 'f' }()](a) {}}
+ assert(o.f.toString() === "*[function(){ return 'f' }()](a) {}")
+
+ o = {async/**/f(a) {}}
+ assert(o.f.toString() === "async/**/f(a) {}")
+
+ o = {/**/async [function(){ return 'f' }()](a) {}/**/}
+ assert(o.f.toString() === "async [function(){ return 'f' }()](a) {}")
+
+ o = {a:1,async/**/*/**/f(a) {},b:1}
+ assert(o.f.toString() === "async/**/*/**/f(a) {}")
+
+ o = {async *//
+ [function(){ return 'f' }()](a) {}/**/}
+ assert(o.f.toString() === "async *//\n [function(){ return 'f' }()](a) {}")
+
+ o = { get a() {return/**/6} }
+ assert(Object.getOwnPropertyDescriptor(o, "a").get.toString() === "get a() {return/**/6}")
+
+ o = { get[function(){ return 'a' }()](){} }
+ assert(Object.getOwnPropertyDescriptor(o, "a").get.toString() === "get[function(){ return 'a' }()](){}")
+
+ o = { set a(v) {/**/} }
+ assert(Object.getOwnPropertyDescriptor(o, "a").set.toString() === "set a(v) {/**/}")
+
+ o = {/**/set/**/[function(){ return 'a' }()]/**/(v) {/**/}/**/}
+ assert(Object.getOwnPropertyDescriptor(o, "a").set.toString() === "set/**/[function(){ return 'a' }()]/**/(v) {/**/}")
+
+ /* Class static functions. */
+
+ c = class { static/**/f() {}/**/ }
+ assert(c.f.toString() === "f() {}")
+
+ c = class { static[function(){ return 'f' }()]() {} }
+ assert(c.f.toString() === "[function(){ return 'f' }()]() {}")
+
+ c = class { static *f() {} }
+ assert(c.f.toString() === "*f() {}")
+
+ c = class {/**/static * [function(){ return 'f' }()](a=6){}/**/}
+ assert(c.f.toString() === "* [function(){ return 'f' }()](a=6){}")
+
+ c = class { static/**/async f() {} }
+ assert(c.f.toString() === "async f() {}")
+
+ c = class {static async[function(){ return 'f' }()]() {/**/}}
+ assert(c.f.toString() === "async[function(){ return 'f' }()]() {/**/}")
+
+ c = class { static async*f() {}}
+ assert(c.f.toString() === "async*f() {}")
+
+ c = class { static async*/**/[function(){ return 'f' }()](){} }
+ assert(c.f.toString() === "async*/**/[function(){ return 'f' }()](){}")
+
+ c = class { static/**/get/**/a() {}}
+ assert(Object.getOwnPropertyDescriptor(c, "a").get.toString() === "get/**/a() {}")
+
+ c = class {static set a(v){}}
+ assert(Object.getOwnPropertyDescriptor(c, "a").set.toString() === "set a(v){}")
+
+ c = class { static get[function(){ return 'a' }()](){} }
+ assert(Object.getOwnPropertyDescriptor(c, "a").get.toString() === "get[function(){ return 'a' }()](){}")
+
+ c = class { static set[function(){ return 'a' }()](v){}//
+ }
+ assert(Object.getOwnPropertyDescriptor(c, "a").set.toString() === "set[function(){ return 'a' }()](v){}")
+
+ /* Class functions. */
+
+ o = Object.getPrototypeOf(new class {/**/f() {}/**/})
+ assert(o.f.toString() === "f() {}")
+
+ o = Object.getPrototypeOf(new class {[function(){ return 'f' }()](){}})
+ assert(o.f.toString() === "[function(){ return 'f' }()](){}")
+
+ o = Object.getPrototypeOf(new class { * /**/ f() {} })
+ assert(o.f.toString() === "* /**/ f() {}")
+
+ o = Object.getPrototypeOf(new class { * [function(){ return 'f' }()]/**/(){} })
+ assert(o.f.toString() === "* [function(){ return 'f' }()]/**/(){}")
+
+ o = Object.getPrototypeOf(new class {async f() {}})
+ assert(o.f.toString() === "async f() {}")
+
+ o = Object.getPrototypeOf(new class {async[function(){ return 'f' }()](){}})
+ assert(o.f.toString() === "async[function(){ return 'f' }()](){}")
+
+ o = Object.getPrototypeOf(new class {/**/get/**/a() {}/**/})
+ assert(Object.getOwnPropertyDescriptor(o, "a").get.toString() === "get/**/a() {}")
+
+ o = Object.getPrototypeOf(new class { set a(v){} })
+ assert(Object.getOwnPropertyDescriptor(o, "a").set.toString() === "set a(v){}")
+
+ o = Object.getPrototypeOf(new class {/**/get/**/[function(){ return 'a' }()]() {}/**/})
+ assert(Object.getOwnPropertyDescriptor(o, "a").get.toString() === "get/**/[function(){ return 'a' }()]() {}")
+
+ o = Object.getPrototypeOf(new class { set/**/[function(){ return 'a' }()]( v ){} })
+ assert(Object.getOwnPropertyDescriptor(o, "a").set.toString() === "set/**/[function(){ return 'a' }()]( v ){}")
+
+ /* Function creators. */
+ f = Function("a,b", "return a + b")
+ assert(f.toString() === "function anonymous(a,b\n) {\nreturn a + b\n}")
+
+ f = Function("", "")
+ assert(f.toString() === "function anonymous(\n) {\n\n}")
+
+ f = function*(){}.constructor("a,b", "c", "yield a; return b + c")
+ assert(f.toString() === "function* anonymous(a,b,c\n) {\nyield a; return b + c\n}")
+
+ f = async function(){}.constructor("a", "return a + 'x'")
+ assert(f.toString() === "async function anonymous(a\n) {\nreturn a + 'x'\n}")
+
+ f = async function*(){}.constructor("a=3", "return a")
+ assert(f.toString() === "async function* anonymous(a=3\n) {\nreturn a\n}")
+
+ f = Function("a = function(x) { return x + 3 }", "return a")
+ assert(f().toString() === "function(x) { return x + 3 }")
+
+ f = Function("return function(x) { return x + 3 }")
+ assert(f().toString() === "function(x) { return x + 3 }")
+
+ /* Arrow functions. */
+ f = x => x + 1/**/
+ assert(f.toString() === "x => x + 1")
+
+ f =x => { return x + 1 }/**/
+ assert(f.toString() === "x => { return x + 1 }")
+
+ f = (/**/) => 'x' //
+ + y
+ assert(f.toString() === "(/**/) => 'x' //\n + y")
+
+ f = async x => x + 1
+ assert(f.toString() === "async x => x + 1")
+
+ f =/**/async (x,/**/y)=>/**/null
+ assert(f.toString() === "async (x,/**/y)=>/**/null")
+}
diff --git a/tests/jerry/es.next/new-target.js b/tests/jerry/es.next/new-target.js
index cc6e87675e..a17ae95818 100644
--- a/tests/jerry/es.next/new-target.js
+++ b/tests/jerry/es.next/new-target.js
@@ -149,7 +149,9 @@ new delete_test ();
function binary_test_1 () {
/*/ new.target is converted to string */
- assert ((new.target + 1) === "function(){/* ecmascript */}1");
+ var str = (new.target + 1);
+ assert (str.substring(0, 8) === "function"
+ && str.substring(str.length - 2, str.length) === "}1");
}
function binary_test_2 () { assert (isNaN (new.target - 3)); }
function binary_test_3 () { assert (isNaN (new.target * 2)); }
diff --git a/tests/jerry/es.next/regression-test-issue-4468.js b/tests/jerry/es.next/regression-test-issue-4468.js
index 2c8247e31a..0c5694af43 100644
--- a/tests/jerry/es.next/regression-test-issue-4468.js
+++ b/tests/jerry/es.next/regression-test-issue-4468.js
@@ -14,4 +14,6 @@
var str = 'for (let i=0; i<(eval("1; function x() { }; 2;")); x - i++) { x += delete x;}'
-assert(eval(str) === 'function(){/* ecmascript */}true');
+var e = eval(str)
+assert(e === 'function x() { }true'
+ || e === 'function () { /* ecmascript */ }true');
diff --git a/tests/jerry/function-prototype-tostring.js b/tests/jerry/function-prototype-tostring.js
index 9b1438e629..fedd23f667 100644
--- a/tests/jerry/function-prototype-tostring.js
+++ b/tests/jerry/function-prototype-tostring.js
@@ -12,16 +12,27 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-assert (Math.cos.toString() === "function(){/* ecmascript */}");
+assert (Math.cos.toString() === "function () { [native code] }");
+
+var has_toString = none.toString() != "function () { /* ecmascript */ }"
+
+function check(f, expected)
+{
+ assert (f.toString() === (has_toString ? expected : "function () { /* ecmascript */ }"))
+}
function none() { return 1; }
-assert (none.toString() === "function(){/* ecmascript */}");
+check (none, "function none() { return 1; }")
+assert (none.bind({}).toString() === "function () { [native code] }")
function single(b) { return 1; }
-assert (single.toString() === "function(){/* ecmascript */}");
+check (single, "function single(b) { return 1; }")
+assert (single.bind({}).toString() === "function () { [native code] }")
function multiple(a,b) { return 1; }
-assert (multiple.toString() === "function(){/* ecmascript */}");
+check (multiple, "function multiple(a,b) { return 1; }")
+assert (multiple.bind({}).toString() === "function () { [native code] }")
function lots(a,b,c,d,e,f,g,h,i,j,k) { return 1; }
-assert (lots.toString() === "function(){/* ecmascript */}");
+check (lots, "function lots(a,b,c,d,e,f,g,h,i,j,k) { return 1; }")
+assert (lots.bind({}).toString() === "function () { [native code] }")
diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml
index 7b2f7cf4bf..7c426359a8 100644
--- a/tests/test262-esnext-excludelist.xml
+++ b/tests/test262-esnext-excludelist.xml
@@ -28,60 +28,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -6678,16 +6627,6 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/build.py b/tools/build.py
index 5a38476c38..17f79247ba 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -120,6 +120,8 @@ def devhelp(helpstring):
help='enable the jerry debugger (%(choices)s)')
coregrp.add_argument('--js-parser', metavar='X', choices=['ON', 'OFF'], type=str.upper,
help='enable js-parser (%(choices)s)')
+ coregrp.add_argument('--function-to-string', metavar='X', choices=['ON', 'OFF'], type=str.upper,
+ help='enable function toString (%(choices)s)')
coregrp.add_argument('--line-info', metavar='X', choices=['ON', 'OFF'], type=str.upper,
help='provide line info (%(choices)s)')
coregrp.add_argument('--logging', metavar='X', choices=['ON', 'OFF'], type=str.upper,
@@ -208,6 +210,7 @@ def build_options_append(cmakeopt, cliarg):
build_options_append('JERRY_EXTERNAL_CONTEXT', arguments.external_context)
build_options_append('JERRY_DEBUGGER', arguments.jerry_debugger)
build_options_append('JERRY_PARSER', arguments.js_parser)
+ build_options_append('JERRY_FUNCTION_TO_STRING', arguments.function_to_string)
build_options_append('JERRY_LINE_INFO', arguments.line_info)
build_options_append('JERRY_LOGGING', arguments.logging)
build_options_append('JERRY_GLOBAL_HEAP_SIZE', arguments.mem_heap)
diff --git a/tools/run-tests.py b/tools/run-tests.py
index b7d2e934bc..f449206e5d 100755
--- a/tools/run-tests.py
+++ b/tools/run-tests.py
@@ -42,7 +42,7 @@ def skip_if(condition, desc):
OPTIONS_COMMON = ['--lto=off']
OPTIONS_PROFILE_MIN = ['--profile=minimal']
OPTIONS_PROFILE_ES51 = ['--profile=es5.1']
-OPTIONS_PROFILE_ESNEXT = ['--profile=es.next']
+OPTIONS_PROFILE_ESNEXT = ['--profile=es.next', '--function-to-string=on']
OPTIONS_STACK_LIMIT = ['--stack-limit=96']
OPTIONS_GC_MARK_LIMIT = ['--gc-mark-limit=16']
OPTIONS_MEM_STRESS = ['--mem-stress-test=on']