From 998e49a969d0ff38e9ccebc6dfb7937d2a006afc Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Thu, 15 Jul 2021 13:45:10 +0200 Subject: [PATCH] Rework storing the line/column/bytecode info (#4707) This information is stored in a separate memory block instead of being part of the byte code. Snapshot does not supported. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/CMakeLists.txt | 3 + jerry-core/api/jerry-snapshot.c | 5 + jerry-core/api/jerry.c | 20 +- jerry-core/ecma/base/ecma-helpers.c | 45 ++ jerry-core/ecma/base/ecma-helpers.h | 3 + jerry-core/ecma/base/ecma-line-info.c | 283 +++++++++ jerry-core/ecma/base/ecma-line-info.h | 121 ++++ jerry-core/include/jerryscript-snapshot.h | 2 +- jerry-core/parser/js/byte-code.c | 2 +- jerry-core/parser/js/byte-code.h | 9 +- jerry-core/parser/js/common.c | 23 +- jerry-core/parser/js/js-parser-expr.c | 16 +- jerry-core/parser/js/js-parser-internal.h | 38 +- .../parser/js/js-parser-line-info-create.c | 577 ++++++++++++++++++ jerry-core/parser/js/js-parser-statm.c | 20 +- jerry-core/parser/js/js-parser-util.c | 54 -- jerry-core/parser/js/js-parser.c | 103 ++-- jerry-core/vm/vm-defines.h | 3 - jerry-core/vm/vm-utils.c | 28 +- jerry-core/vm/vm.c | 20 - jerry-core/vm/vm.h | 6 - tests/unit-core/test-backtrace.c | 38 +- 22 files changed, 1218 insertions(+), 201 deletions(-) create mode 100644 jerry-core/ecma/base/ecma-line-info.c create mode 100644 jerry-core/ecma/base/ecma-line-info.h create mode 100644 jerry-core/parser/js/js-parser-line-info-create.c diff --git a/jerry-core/CMakeLists.txt b/jerry-core/CMakeLists.txt index bd701189a..a818c0571 100644 --- a/jerry-core/CMakeLists.txt +++ b/jerry-core/CMakeLists.txt @@ -143,6 +143,7 @@ set(SOURCE_CORE_FILES ecma/base/ecma-helpers.c ecma/base/ecma-init-finalize.c ecma/base/ecma-lcache.c + ecma/base/ecma-line-info.c ecma/base/ecma-literal-storage.c ecma/base/ecma-module.c ecma/base/ecma-property-hashmap.c @@ -295,6 +296,7 @@ set(SOURCE_CORE_FILES parser/js/common.c parser/js/js-lexer.c parser/js/js-parser-expr.c + parser/js/js-parser-line-info-create.c parser/js/js-parser-mem.c parser/js/js-parser-module.c parser/js/js-parser-statm.c @@ -334,6 +336,7 @@ if(ENABLE_AMALGAM) ecma/base/ecma-helpers.h ecma/base/ecma-init-finalize.h ecma/base/ecma-lcache.h + ecma/base/ecma-line-info.h ecma/base/ecma-literal-storage.h ecma/base/ecma-module.h ecma/base/ecma-property-hashmap.h diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index 55a57ac32..214c7dd2e 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -256,6 +256,11 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled uint32_t const_literal_end; uint32_t literal_end; +#if JERRY_LINE_INFO + /* TODO: support snapshots. */ + ((ecma_compiled_code_t *) buffer_p)->status_flags &= (uint16_t) ~CBC_CODE_FLAGS_HAS_LINE_INFO; +#endif /* JERRY_LINE_INFO */ + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t)); diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 89231be82..a81712df2 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -34,7 +34,7 @@ #include "ecma-init-finalize.h" #include "ecma-iterator-object.h" #include "ecma-lex-env.h" -#include "lit-char-helpers.h" +#include "ecma-line-info.h" #include "ecma-literal-storage.h" #include "ecma-objects.h" #include "ecma-objects-general.h" @@ -43,12 +43,13 @@ #include "ecma-proxy-object.h" #include "ecma-symbol-object.h" #include "ecma-typedarray-object.h" -#include "opcodes.h" #include "jcontext.h" #include "jerryscript.h" #include "jerryscript-debugger-transport.h" #include "jmem.h" #include "js-parser.h" +#include "lit-char-helpers.h" +#include "opcodes.h" #include "re-compiler.h" JERRY_STATIC_ASSERT (sizeof (jerry_value_t) == sizeof (ecma_value_t), @@ -5262,10 +5263,19 @@ jerry_backtrace_get_location (jerry_backtrace_frame_t *frame_p) /**< frame point if (frame_p->frame_type == JERRY_BACKTRACE_FRAME_JS) { vm_frame_ctx_t *context_p = frame_p->context_p; + const ecma_compiled_code_t *bytecode_header_p = context_p->shared_p->bytecode_header_p; + + if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_LINE_INFO)) + { + return NULL; + } + + frame_p->location.resource_name = ecma_get_resource_name (bytecode_header_p); + + ecma_line_info_get (ecma_compiled_code_get_line_info (bytecode_header_p), + (uint32_t) (context_p->byte_code_p - context_p->byte_code_start_p), + &frame_p->location); - frame_p->location.resource_name = ecma_get_resource_name (context_p->shared_p->bytecode_header_p); - frame_p->location.line = context_p->current_line; - frame_p->location.column = 1; return &frame_p->location; } #endif /* JERRY_LINE_INFO */ diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index f69dea6ec..cc838fd91 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -19,6 +19,7 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-lcache.h" +#include "ecma-line-info.h" #include "ecma-property-hashmap.h" #include "jcontext.h" #include "jrt-bit-fields.h" @@ -1525,6 +1526,13 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ } #endif /* JERRY_ESNEXT */ +#if JERRY_LINE_INFO + if (bytecode_p->status_flags & CBC_CODE_FLAGS_HAS_LINE_INFO) + { + ecma_line_info_free (ecma_compiled_code_get_line_info (bytecode_p)); + } +#endif /* JERRY_LINE_INFO */ + #if JERRY_DEBUGGER if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && !(bytecode_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE) @@ -1657,6 +1665,43 @@ ecma_compiled_code_get_tagged_template_collection (const ecma_compiled_code_t *b #endif /* JERRY_ESNEXT */ +#if JERRY_LINE_INFO + +/** + * Get the line info data from the byte code + * + * @return pointer to the line info data + */ +uint8_t * +ecma_compiled_code_get_line_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_LINE_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_EXTENDED_INFO) + { + base_p--; + } + + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_TAGGED_LITERALS) + { + base_p--; + } +#endif /* JERRY_ESNEXT */ + + return ECMA_GET_INTERNAL_VALUE_POINTER (uint8_t, base_p[-1]); +} /* ecma_compiled_code_get_line_info */ + +#endif /* JERRY_LINE_INFO */ + /** * Get the resource name of a compiled code. * diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index e3276fea3..1ac804426 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -538,6 +538,9 @@ ecma_value_t *ecma_compiled_code_resolve_function_name (const ecma_compiled_code 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 +uint8_t *ecma_compiled_code_get_line_info (const ecma_compiled_code_t *bytecode_header_p); +#endif /* JERRY_LINE_INFO */ ecma_value_t ecma_get_resource_name (const ecma_compiled_code_t *bytecode_p); #if (JERRY_STACK_LIMIT != 0) uintptr_t ecma_get_current_stack_usage (void); diff --git a/jerry-core/ecma/base/ecma-line-info.c b/jerry-core/ecma/base/ecma-line-info.c new file mode 100644 index 000000000..c9686423a --- /dev/null +++ b/jerry-core/ecma/base/ecma-line-info.c @@ -0,0 +1,283 @@ +/* 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 "ecma-helpers.h" +#include "ecma-line-info.h" + +#if JERRY_LINE_INFO + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmalineinfo Line info + * @{ + */ + +/* The layout of the structure is defined in js-parser-line-info-create.c */ + +JERRY_STATIC_ASSERT ((ECMA_LINE_INFO_COLUMN_DEFAULT - 1) == ((ECMA_LINE_INFO_ENCODE_TWO_BYTE >> 1) - 1), + ecma_line_info_column_1_must_be_accessible_with_the_highest_one_byte_negative_value); + +/** + * Decodes an uint32_t number, and updates the buffer position. + * Numbers expected to be larger values. + * + * @return the decoded value + */ +uint32_t +ecma_line_info_decode_vlq (uint8_t **buffer_p) /**< [in/out] target buffer */ +{ + uint8_t *source_p = *buffer_p; + uint32_t value = 0; + + do + { + value = (value << ECMA_LINE_INFO_VLQ_SHIFT) | (*source_p & ECMA_LINE_INFO_VLQ_MASK); + } + while (*source_p++ & ECMA_LINE_INFO_VLQ_CONTINUE); + + *buffer_p = source_p; + return value; +} /* ecma_line_info_decode_vlq */ + +/** + * Decodes an uint32_t number, and updates the buffer position. + * Numbers expected to be smaller values. + * + * @return the decoded value + */ +static uint32_t +ecma_line_info_decode_small (uint8_t **buffer_p) /**< [in/out] target buffer */ +{ + uint8_t *source_p = *buffer_p; + + uint32_t type = source_p[0]; + + if (type < ECMA_LINE_INFO_ENCODE_TWO_BYTE_MIN) + { + *buffer_p = source_p + 1; + return type; + } + + uint32_t value = source_p[1]; + + if (type == ECMA_LINE_INFO_ENCODE_TWO_BYTE) + { + *buffer_p = source_p + 2; + return (uint32_t) (value + ECMA_LINE_INFO_ENCODE_TWO_BYTE_MIN); + } + + value |= ((uint32_t) source_p[2]) << 8; + + if (type == ECMA_LINE_INFO_ENCODE_THREE_BYTE) + { + *buffer_p = source_p + 3; + return (uint32_t) (value + ECMA_LINE_INFO_ENCODE_THREE_BYTE_MIN); + } + + JERRY_ASSERT (type == ECMA_LINE_INFO_ENCODE_FIVE_BYTE); + + *buffer_p = source_p + 5; + return value | (((uint32_t) source_p[3]) << 8) | (((uint32_t) source_p[4]) << 8); +} /* ecma_line_info_decode_small */ + +/** + * Updates a value using an encoded difference. + * + * @return updated value + */ +extern inline uint32_t JERRY_ATTR_ALWAYS_INLINE +ecma_line_info_difference_update (uint32_t current_value, /**< current value */ + uint32_t difference_value) /**< encoded difference */ +{ + if ((difference_value & 0x1) == ECMA_LINE_INFO_INCREASE) + { + return current_value + (difference_value >> 1) + 1; + } + + return current_value - (difference_value >> 1); +} /* ecma_line_info_difference_update */ + +/** + * Release line info data. + */ +void +ecma_line_info_free (uint8_t *line_info_p) /**< line info buffer */ +{ + uint8_t *source_p = line_info_p; + uint32_t total_length = ecma_line_info_decode_vlq (&source_p); + + jmem_heap_free_block (line_info_p, total_length + (uint32_t) (source_p - line_info_p)); +} /* ecma_line_info_free */ + +/** + * Returns the line/column information for a given byte code offset. + */ +void +ecma_line_info_get (uint8_t *line_info_p, /**< line info buffer */ + uint32_t offset, /**< byte code offset */ + jerry_backtrace_location_t *location_p) /**< [out] location */ +{ + uint32_t line = 1; + uint32_t column = ECMA_LINE_INFO_COLUMN_DEFAULT; + uint32_t end_offset = 0; + uint32_t end_offset_increase; + uint32_t value; + + /* Skip total_length. */ + ecma_line_info_decode_vlq (&line_info_p); + + while (true) + { + value = ecma_line_info_decode_vlq (&line_info_p); + line = ecma_line_info_difference_update (line, value); + + if (*line_info_p == 0) + { + break; + } + + uint8_t *size_p = line_info_p + *line_info_p + (ECMA_LINE_INFO_STREAM_SIZE_MIN + 1); + + end_offset += ecma_line_info_decode_vlq (&size_p); + + if (offset < end_offset) + { + break; + } + + line_info_p = size_p; + } + + line_info_p++; + + do + { + end_offset_increase = ecma_line_info_decode_small (&line_info_p); + + if (end_offset_increase & ECMA_LINE_INFO_HAS_LINE) + { + value = ecma_line_info_decode_small (&line_info_p); + line = ecma_line_info_difference_update (line, value); + column = ECMA_LINE_INFO_COLUMN_DEFAULT; + } + + end_offset_increase >>= 1; + + value = ecma_line_info_decode_small (&line_info_p); + column = ecma_line_info_difference_update (column, value); + + end_offset += end_offset_increase; + } + while (end_offset_increase != 0 && end_offset <= offset); + + location_p->line = line; + location_p->column = column; +} /* ecma_line_info_get */ + +#if JERRY_PARSER_DUMP_BYTE_CODE + +/** + * Dumps line info data. + */ +void +ecma_line_info_dump (uint8_t *line_info_p) /**< dumps line info data */ +{ + bool block_last = false; + uint32_t block_line = 1; + uint32_t block_byte_code_offset = 0; + uint32_t value; + + value = ecma_line_info_decode_vlq (&line_info_p); + JERRY_DEBUG_MSG ("\nLine info size: %d bytes\n", (int) value); + + while (true) + { + value = ecma_line_info_decode_vlq (&line_info_p); + block_line = ecma_line_info_difference_update (block_line, value); + + JERRY_DEBUG_MSG ("\nNew block: line: %d", (int) block_line); + + if (*line_info_p == 0) + { + JERRY_DEBUG_MSG (" StreamLength: [last]\n"); + block_last = true; + } + else + { + uint8_t *size_p = line_info_p + *line_info_p + (ECMA_LINE_INFO_STREAM_SIZE_MIN + 1); + + value = ecma_line_info_decode_vlq (&size_p); + + JERRY_DEBUG_MSG (" StreamLength: %d ByteCodeSize: %d\n", + (int) (*line_info_p + ECMA_LINE_INFO_STREAM_SIZE_MIN), + (int) value); + } + + line_info_p++; + + uint32_t stream_line = block_line; + uint32_t stream_column = ECMA_LINE_INFO_COLUMN_DEFAULT; + uint32_t stream_end_offset = block_byte_code_offset; + + while (true) + { + uint32_t stream_end_offset_increase = ecma_line_info_decode_small (&line_info_p); + + if (stream_end_offset_increase & ECMA_LINE_INFO_HAS_LINE) + { + value = ecma_line_info_decode_small (&line_info_p); + stream_line = ecma_line_info_difference_update (stream_line, value); + stream_column = ECMA_LINE_INFO_COLUMN_DEFAULT; + } + + stream_end_offset_increase >>= 1; + + value = ecma_line_info_decode_small (&line_info_p); + stream_column = ecma_line_info_difference_update (stream_column, value); + + if (stream_end_offset_increase == 0) + { + JERRY_DEBUG_MSG (" ByteCodeEndOffset: [unterminated] Line: %d Column: %d\n", + (int) stream_line, + (int) stream_column); + break; + } + + stream_end_offset += stream_end_offset_increase; + + JERRY_DEBUG_MSG (" ByteCodeEndOffset: %d Line: %d Column: %d\n", + (int) stream_end_offset, + (int) stream_line, + (int) stream_column); + } + + if (block_last) + { + break; + } + + block_byte_code_offset += ecma_line_info_decode_vlq (&line_info_p); + } +} /* ecma_line_info_dump */ + +#endif /* JERRY_PARSER_DUMP_BYTE_CODE */ + +#endif /* JERRY_LINE_INFO */ + +/** + * @} + * @} + */ diff --git a/jerry-core/ecma/base/ecma-line-info.h b/jerry-core/ecma/base/ecma-line-info.h new file mode 100644 index 000000000..93573cdd1 --- /dev/null +++ b/jerry-core/ecma/base/ecma-line-info.h @@ -0,0 +1,121 @@ +/* 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_LINE_INFO_H +#define ECMA_LINE_INFO_H + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmalineinfo Line info + * @{ + */ + +#if JERRY_LINE_INFO + +#include "ecma-globals.h" + +/** + * Increase the current value of line or column. + */ +#define ECMA_LINE_INFO_INCREASE 0x0 + +/** + * Decrease the current value of line or column. + */ +#define ECMA_LINE_INFO_DECREASE 0x1 + +/** + * Line update is present. + */ +#define ECMA_LINE_INFO_HAS_LINE 0x1 + +/** + * A default value for columns after a line update. + */ +#define ECMA_LINE_INFO_COLUMN_DEFAULT 126 + +/** + * Vlq encoding: flag which is set for all bytes except the last one. + */ +#define ECMA_LINE_INFO_VLQ_CONTINUE 0x80 + +/** + * Vlq encoding: mask to decode the number fragment. + */ +#define ECMA_LINE_INFO_VLQ_MASK 0x7f + +/** + * Vlq encoding: number of bits stored in a byte. + */ +#define ECMA_LINE_INFO_VLQ_SHIFT 7 + +/** + * Small encoding: a value which represents a two byte long number. + */ +#define ECMA_LINE_INFO_ENCODE_TWO_BYTE (UINT8_MAX - 2) + +/** + * Small encoding: minimum value of an encoded two byte long number. + */ +#define ECMA_LINE_INFO_ENCODE_TWO_BYTE_MIN (UINT8_MAX - 2) + +/** + * Small encoding: a value which represents a three byte long number. + */ +#define ECMA_LINE_INFO_ENCODE_THREE_BYTE (UINT8_MAX - 1) + +/** + * Small encoding: minimum value of an encoded three byte long number. + */ +#define ECMA_LINE_INFO_ENCODE_THREE_BYTE_MIN (ECMA_LINE_INFO_ENCODE_TWO_BYTE_MIN + UINT8_MAX + 1) + +/** + * Small encoding: a value which represents a five byte long number. + */ +#define ECMA_LINE_INFO_ENCODE_FIVE_BYTE UINT8_MAX + +/** + * Maximum number of line/column entries stored in a stream. + */ +#define ECMA_LINE_INFO_STREAM_VALUE_COUNT_MAX 48 + +/** + * Minimum size of a stream (except the last one). + */ +#define ECMA_LINE_INFO_STREAM_SIZE_MIN \ + ((2 * ECMA_LINE_INFO_STREAM_VALUE_COUNT_MAX) - 1) + +/* Helper functions for parser/js/js-parser-line-info-create.c. */ +uint32_t ecma_line_info_decode_vlq (uint8_t **buffer_p); +uint32_t ecma_line_info_difference_update (uint32_t current_value, uint32_t difference_value); + +/* General functions. */ +void ecma_line_info_free (uint8_t *line_info_p); +void ecma_line_info_get (uint8_t *line_info_p, uint32_t offset, + jerry_backtrace_location_t *location_p); + +#if JERRY_PARSER_DUMP_BYTE_CODE +void ecma_line_info_dump (uint8_t *line_info_p); +#endif /* JERRY_PARSER_DUMP_BYTE_CODE */ + +#endif /* ECMA_LINE_INFO_H */ + +/** + * @} + * @} + */ + +#endif /* !ECMA_LINE_INFO_H */ diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index 5f3cf4ecc..c3796eaa7 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 (65u) +#define JERRY_SNAPSHOT_VERSION (66u) /** * Flags for jerry_generate_snapshot and jerry_generate_function_snapshot. diff --git a/jerry-core/parser/js/byte-code.c b/jerry-core/parser/js/byte-code.c index 6ed30959c..3cff2e624 100644 --- a/jerry-core/parser/js/byte-code.c +++ b/jerry-core/parser/js/byte-code.c @@ -27,7 +27,7 @@ JERRY_STATIC_ASSERT ((sizeof (cbc_uint16_arguments_t) % sizeof (jmem_cpointer_t) */ JERRY_STATIC_ASSERT (CBC_END == 238, number_of_cbc_opcodes_changed); -JERRY_STATIC_ASSERT (CBC_EXT_END == 147, +JERRY_STATIC_ASSERT (CBC_EXT_END == 146, number_of_cbc_ext_opcodes_changed); #if JERRY_PARSER || JERRY_PARSER_DUMP_BYTE_CODE diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 918242dec..d7a64c23f 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -606,8 +606,6 @@ VM_OC_STRING_CONCAT | VM_OC_GET_LITERAL_LITERAL | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_EXT_GET_TAGGED_TEMPLATE_LITERAL, CBC_HAS_BYTE_ARG, 1, \ VM_OC_GET_TEMPLATE_OBJECT | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_LINE, CBC_NO_FLAG, 0, \ - VM_OC_LINE) \ CBC_OPCODE (CBC_EXT_THROW_REFERENCE_ERROR, CBC_NO_FLAG, 1, \ VM_OC_THROW_REFERENCE_ERROR) \ CBC_OPCODE (CBC_EXT_THROW_ASSIGN_CONST_ERROR, CBC_NO_FLAG, 0, \ @@ -889,9 +887,10 @@ typedef enum CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 4), /**< no need to create a lexical environment */ CBC_CODE_FLAGS_HAS_EXTENDED_INFO = (1u << 5), /**< this function has extended info block */ CBC_CODE_FLAGS_HAS_TAGGED_LITERALS = (1u << 6), /**< this function has tagged template literal list */ - CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 7), /**< this function is a static snapshot function */ - CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 8), /**< this function should be ignored by debugger */ - CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED = (1u << 9), /**< compiled code needs a lexical block */ + CBC_CODE_FLAGS_HAS_LINE_INFO = (1u << 7), /**< this function has line info block */ + CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 8), /**< this function is a static snapshot function */ + CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 9), /**< this function should be ignored by debugger */ + CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED = (1u << 10), /**< compiled code needs a lexical block */ /* Bits from bit 12 is reserved for function types (see CBC_FUNCTION_TYPE_SHIFT). * Note: the last bits are used for type flags because < and >= operators can be used to diff --git a/jerry-core/parser/js/common.c b/jerry-core/parser/js/common.c index 9a20f92aa..6985d7724 100644 --- a/jerry-core/parser/js/common.c +++ b/jerry-core/parser/js/common.c @@ -430,6 +430,11 @@ util_print_cbc (ecma_compiled_code_t *compiled_code_p) /**< compiled code */ size -= sizeof (ecma_value_t); } + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_HAS_LINE_INFO) + { + size -= sizeof (ecma_value_t); + } + byte_code_end_p = ((uint8_t *) compiled_code_p) + size; byte_code_p = byte_code_start_p; @@ -462,24 +467,6 @@ util_print_cbc (ecma_compiled_code_t *compiled_code_p) /**< compiled code */ flags = cbc_ext_flags[ext_opcode]; JERRY_DEBUG_MSG (" %3d : %s", (int) cbc_offset, cbc_ext_names[ext_opcode]); byte_code_p += 2; - -#if JERRY_LINE_INFO - if (ext_opcode == CBC_EXT_LINE) - { - uint32_t value = 0; - uint8_t byte; - - do - { - byte = *byte_code_p++; - value = (value << 7) | (byte & CBC_LOWER_SEVEN_BIT_MASK); - } - while (byte & CBC_HIGHEST_BIT_MASK); - - JERRY_DEBUG_MSG (" %d\n", (int) value); - continue; - } -#endif /* JERRY_LINE_INFO */ } if (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)) diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 65887074c..81e53a8a9 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -3388,13 +3388,6 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */ context_p->last_breakpoint_line = ident_line_counter; } #endif /* JERRY_DEBUGGER */ - -#if JERRY_LINE_INFO - if (ident_line_counter != context_p->last_line_info_line) - { - parser_emit_line_info (context_p, ident_line_counter, false); - } -#endif /* JERRY_LINE_INFO */ } /* parser_pattern_form_assignment */ /** @@ -3483,6 +3476,9 @@ parser_pattern_process_assignment (parser_context_t *context_p, /**< context */ } parser_line_counter_t ident_line_counter = context_p->token.line; +#if JERRY_LINE_INFO + parser_line_counter_t ident_column_counter = context_p->token.column; +#endif /* JERRY_LINE_INFO */ if (flags & PARSER_PATTERN_BINDING) { @@ -3538,6 +3534,9 @@ parser_pattern_process_assignment (parser_context_t *context_p, /**< context */ } parser_pattern_form_assignment (context_p, flags, rhs_opcode, literal_index, ident_line_counter); +#if JERRY_LINE_INFO + parser_line_info_append (context_p, ident_line_counter, ident_column_counter); +#endif /* JERRY_LINE_INFO */ return false; } /* parser_pattern_process_assignment */ @@ -3720,6 +3719,9 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */ || context_p->token.type == LEXER_COMMA); parser_pattern_form_assignment (context_p, flags, push_prop_opcode, prop_index, start_line); +#if JERRY_LINE_INFO + parser_line_info_append (context_p, start_line, start_column); +#endif /* JERRY_LINE_INFO */ } if (context_p->token.type == LEXER_RIGHT_BRACE) diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 5cf7bac45..d581a3179 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -486,6 +486,19 @@ typedef struct #endif /* JERRY_DEBUGGER */ +#if JERRY_LINE_INFO + +typedef struct +{ + parser_mem_page_t *first_page_p; /**< first page of line info data */ + parser_mem_page_t *last_page_p; /**< last page of line info data */ + uint32_t byte_code_position; /**< last byte code position */ + parser_line_counter_t line; /**< last line */ + parser_line_counter_t column; /**< last column */ +} parser_line_info_data_t; + +#endif /* JERRY_LINE_INFO */ + /** * Those members of a context which needs * to be saved when a sub-function is parsed. @@ -523,6 +536,10 @@ typedef struct parser_saved_context_t #ifndef JERRY_NDEBUG uint16_t context_stack_depth; /**< current context stack depth */ #endif /* !JERRY_NDEBUG */ + +#if JERRY_LINE_INFO + parser_line_info_data_t line_info; /**< line info data */ +#endif /* JERRY_LINE_INFO */ } parser_saved_context_t; /** @@ -618,6 +635,7 @@ typedef struct #endif /* JERRY_RESOURCE_NAME */ #if JERRY_LINE_INFO + parser_line_info_data_t line_info; /**< line info data */ parser_line_counter_t last_line_info_line; /**< last line where line info has been inserted */ #endif /* JERRY_LINE_INFO */ } parser_context_t; @@ -875,6 +893,20 @@ void parser_module_add_names_to_node (parser_context_t *context_p, #endif /* JERRY_MODULE_SYSTEM */ +/* + * @} + * + * \addtogroup jsparser_line_info_create Create line info data + * @{ + */ + +#if JERRY_LINE_INFO +void parser_line_info_free (parser_line_info_data_t *line_info_p); +void parser_line_info_append (parser_context_t *context_p, + parser_line_counter_t line, parser_line_counter_t column); +uint8_t *parser_line_info_generate (parser_context_t *context_p); +#endif /* JERRY_LINE_INFO */ + /** * @} * @@ -905,12 +937,6 @@ void parser_append_breakpoint_info (parser_context_t *context_p, jerry_debugger_ #endif /* JERRY_DEBUGGER */ -#if JERRY_LINE_INFO - -void parser_emit_line_info (parser_context_t *context_p, uint32_t line, bool flush_cbc); - -#endif /* JERRY_LINE_INFO */ - #if JERRY_PARSER_DUMP_BYTE_CODE void util_print_cbc (ecma_compiled_code_t *compiled_code_p); #endif /* JERRY_PARSER_DUMP_BYTE_CODE */ diff --git a/jerry-core/parser/js/js-parser-line-info-create.c b/jerry-core/parser/js/js-parser-line-info-create.c new file mode 100644 index 000000000..010a177d0 --- /dev/null +++ b/jerry-core/parser/js/js-parser-line-info-create.c @@ -0,0 +1,577 @@ +/* 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 "ecma-line-info.h" +#include "js-parser-internal.h" + +#if JERRY_PARSER + +#if JERRY_LINE_INFO + +/* \addtogroup parser Parser + * @{ + * + * \addtogroup jsparser JavaScript + * @{ + * + * \addtogroup jsparser_line_info_create Create line info data + * @{ + */ + +/* + * The line-info data structure uses two number encodings: + * + * Vlq (variable length quantity): + * Each byte has 7 bit data and the highest bit is set for continuation. + * The format is big endian. + * + * Small: + * First byte can encode signed values between 127 and -125 in 1 byte. + * Large values requires more bytes than vlq. + * + * The line-info data structure is a sequence of chunks: + * + * +------+--------------+------------+----------------+ + * | Line | StreamLength | StreamData | [ByteCodeSize] | + * +------+--------------+------------+----------------+ + * + * Line [Vlq encoding]: + * Specifies the start line of this chunk, relative to its previous value. + * The starting column is always ECMA_LINE_INFO_COLUMN_DEFAULT + * + * StreamLength [uint8_t]: + * Length of the StreamData in bytes minus ECMA_LINE_INFO_STREAM_SIZE_MIN. + * The 0 value represents the last chunk, which size is not specified + * (Can be less than ECMA_LINE_INFO_STREAM_SIZE_MIN). + * + * StreamData [sequence of bytes]: + * Sequence of the following items: + * + * +-----------+--------+--------+ + * | EndOffset | [Line] | Column | + * +-----------+--------+--------+ + * + * EndOffset [Small encoding]: + * Specifies the EndOffset in the byte code, relative to the previous EndOffset. + * The range of byte codes corresponding to the line/column position of this item + * is between the EndOffset of the previous item (inclusive) and the EndOffset + * of this item (exclusive). The last end offset of a stream is always 0, which + * represents an unterminated range. + * + * Line [Small encoding] [Optional]: + * If bit 1 of end offset is set, this specifies the line position of this item, + * relative to the previous line position, and the column position is set to + * ECMA_LINE_INFO_COLUMN_DEFAULT. + * + * Column [Small encoding]: + * Specifies the current column position relative to the previous column position. + * + * ByteCodeSize [Vlq encoding] [Optional]: + * If StreamLength is not 0, this specifies the byte code size of the whole range. + * This value can be used to skip the byte codes which line info is stored + * in this chunk. This information is not available for the last chunk. + */ + +/** + * Maximum number of bytes requires to encode a number. + */ +#define PARSER_LINE_INFO_BUFFER_MAX_SIZE 5 + +/** + * Stream generation ends after this size is reached, + * since there might be not enough place for the next item. + */ +#define PARSER_LINE_INFO_STREAM_SIZE_LIMIT \ + (ECMA_LINE_INFO_STREAM_SIZE_MIN + UINT8_MAX - ((2 * PARSER_LINE_INFO_BUFFER_MAX_SIZE) + 1)) + +/** + * Free line info temporary data collected during parsing. + */ +void +parser_line_info_free (parser_line_info_data_t *line_info_p) +{ + parser_mem_page_t *current_page_p = line_info_p->first_page_p; + + while (current_page_p != NULL) + { + parser_mem_page_t *next_p = current_page_p->next_p; + + parser_free (current_page_p, sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE); + current_page_p = next_p; + } +} /* parser_line_info_free */ + +/** + * Encodes an uint32_t number into a buffer. Numbers expected to be larger values. + * + * @return the number of bytes written to the buffer + */ +static uint32_t +parser_line_info_encode_vlq (uint8_t *buffer_p, /**< target buffer */ + uint32_t value) /**< encoded value */ +{ + if (value <= ECMA_LINE_INFO_VLQ_MASK) + { + *buffer_p = (uint8_t) value; + return 1; + } + + uint32_t length = 0; + uint32_t current_value = value; + + do + { + current_value >>= ECMA_LINE_INFO_VLQ_SHIFT; + length++; + } + while (current_value > 0); + + buffer_p += length; + + do + { + *(--buffer_p) = (uint8_t) (value | ECMA_LINE_INFO_VLQ_CONTINUE); + value >>= ECMA_LINE_INFO_VLQ_SHIFT; + } + while (value > 0); + + buffer_p[length - 1] &= ECMA_LINE_INFO_VLQ_MASK; + return length; +} /* parser_line_info_encode_vlq */ + +/** + * Encodes an uint32_t number into a buffer. Numbers expected to be smaller values. + * + * @return the number of bytes written to the buffer + */ +static uint32_t +parser_line_info_encode_small (uint8_t *buffer_p, /**< target buffer */ + uint32_t value) /**< encoded value */ +{ + if (value < ECMA_LINE_INFO_ENCODE_TWO_BYTE_MIN) + { + buffer_p[0] = (uint8_t) value; + return 1; + } + + uint32_t length; + + if (JERRY_LIKELY (value < ECMA_LINE_INFO_ENCODE_THREE_BYTE_MIN)) + { + value -= ECMA_LINE_INFO_ENCODE_TWO_BYTE_MIN; + buffer_p[0] = ECMA_LINE_INFO_ENCODE_TWO_BYTE; + length = 2; + } + else + { + if (value <= (ECMA_LINE_INFO_ENCODE_THREE_BYTE_MIN + UINT16_MAX)) + { + value -= ECMA_LINE_INFO_ENCODE_THREE_BYTE_MIN; + buffer_p[0] = ECMA_LINE_INFO_ENCODE_THREE_BYTE; + length = 3; + } + else + { + buffer_p[0] = ECMA_LINE_INFO_ENCODE_FIVE_BYTE; + buffer_p[3] = (uint8_t) (value >> 16); + buffer_p[4] = (uint8_t) (value >> 24); + length = 5; + } + + buffer_p[2] = (uint8_t) (value >> 8); + } + + buffer_p[1] = (uint8_t) value; + return length; +} /* parser_line_info_encode_small */ + +/** + * Encodes the difference between two values. + * + * @return encoded difference + */ +static inline uint32_t JERRY_ATTR_ALWAYS_INLINE +parser_line_info_difference_get (uint32_t current_value, /**< current value */ + uint32_t prev_value) /**< previous value */ +{ + uint32_t result = current_value - prev_value - 1; + + if (result <= (UINT32_MAX >> 1)) + { + return (result << 1) | ECMA_LINE_INFO_INCREASE; + } + + return ((UINT32_MAX - result) << 1) | ECMA_LINE_INFO_DECREASE; +} /* parser_line_info_difference_get */ + +/** + * Appends a value at the end of the line info stream. + */ +static void +parser_line_info_append_number (parser_context_t *context_p, /**< context */ + uint32_t value) /**< value to be encoded */ +{ + uint8_t buffer[PARSER_LINE_INFO_BUFFER_MAX_SIZE]; + + uint32_t length = parser_line_info_encode_vlq (buffer, value); + + if (context_p->line_info.last_page_p != NULL + && context_p->line_info.last_page_p->bytes[0] + length <= PARSER_STACK_PAGE_SIZE) + { + memcpy (context_p->line_info.last_page_p->bytes + context_p->line_info.last_page_p->bytes[0], + buffer, + length); + + length += context_p->line_info.last_page_p->bytes[0]; + context_p->line_info.last_page_p->bytes[0] = (uint8_t) length; + return; + } + + size_t size = sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE; + parser_mem_page_t *new_page_p = (parser_mem_page_t *) parser_malloc (context_p, size); + + new_page_p->next_p = NULL; + + if (context_p->line_info.first_page_p == NULL) + { + context_p->line_info.first_page_p = new_page_p; + context_p->line_info.last_page_p = new_page_p; + } + else + { + context_p->line_info.last_page_p->next_p = new_page_p; + context_p->line_info.last_page_p = new_page_p; + } + + context_p->line_info.last_page_p->bytes[0] = (uint8_t) (length + 1); + memcpy (new_page_p->bytes + 1, buffer, length); +} /* parser_line_info_append_number */ + +/** + * Updates the current line information data. + */ +void +parser_line_info_append (parser_context_t *context_p, /**< context */ + parser_line_counter_t line, /**< line */ + parser_line_counter_t column) /**< column */ +{ + if (context_p->line_info.first_page_p != NULL + && (context_p->byte_code_size == context_p->line_info.byte_code_position + || (context_p->line_info.line == line + && context_p->line_info.column == column))) + { + return; + } + + /* Sets ECMA_LINE_INFO_HAS_LINE bit. */ + uint32_t value = (((context_p->byte_code_size - context_p->line_info.byte_code_position) << 1) + | (uint32_t) (context_p->line_info.line != line)); + + parser_line_info_append_number (context_p, value); + context_p->line_info.byte_code_position = context_p->byte_code_size; + + if (value & ECMA_LINE_INFO_HAS_LINE) + { + value = parser_line_info_difference_get (line, context_p->line_info.line); + parser_line_info_append_number (context_p, value); + context_p->line_info.line = line; + } + + value = parser_line_info_difference_get (column, context_p->line_info.column); + parser_line_info_append_number (context_p, value); + context_p->line_info.column = column; +} /* parser_line_info_append */ + +/** + * Line info iterator structure + */ +typedef struct +{ + parser_mem_page_t *current_page_p; /**< current page */ + uint32_t offset; /**< current offset */ +} parser_line_info_iterator_t; + +/** + * Decodes the next value from the iterator stream + */ +static uint32_t +parser_line_info_iterator_get (parser_line_info_iterator_t *iterator_p) /**< iterator */ +{ + uint8_t *source_p = iterator_p->current_page_p->bytes + iterator_p->offset; + uint32_t result = ecma_line_info_decode_vlq (&source_p); + + iterator_p->offset = (uint32_t) (source_p - iterator_p->current_page_p->bytes); + + JERRY_ASSERT (iterator_p->offset <= iterator_p->current_page_p->bytes[0]); + + if (iterator_p->offset < iterator_p->current_page_p->bytes[0]) + { + return result; + } + + iterator_p->current_page_p = iterator_p->current_page_p->next_p; + iterator_p->offset = 1; + return result; +} /* parser_line_info_iterator_get */ + +/** + * Generate line info data + * + * @return generated line info data + */ +uint8_t * +parser_line_info_generate (parser_context_t *context_p) /**< context */ +{ + parser_line_info_iterator_t iterator; + uint8_t *line_info_p = NULL; + uint8_t *dst_p = NULL; + uint32_t total_length = 0; + uint32_t total_length_size = 0; + + while (true) + { + /* The following code runs twice: first the size of the data, + * is computed and the data is generated during the second run. + * Note: line_info_p is NULL during the first run. */ + parser_mem_page_t *iterator_byte_code_page_p = context_p->byte_code.first_p; + uint32_t iterator_byte_code_page_offset = 0; + uint32_t iterator_byte_code_base = 0; + uint32_t iterator_last_byte_code_offset = UINT32_MAX; + uint32_t iterator_prev_line = 0; + uint32_t iterator_prev_column = 0; + uint32_t iterator_line = 1; + uint32_t iterator_column = 1; + uint8_t block_buffer[PARSER_LINE_INFO_BUFFER_MAX_SIZE]; + uint8_t line_column_buffer[PARSER_LINE_INFO_BUFFER_MAX_SIZE * 2]; + uint8_t *block_size_p = NULL; + uint32_t block_byte_code_offset = 0; + uint32_t block_prev_line = 1; + uint32_t stream_byte_code_offset = 0; + uint32_t stream_current_line = 1; + uint32_t stream_current_column = ECMA_LINE_INFO_COLUMN_DEFAULT; + uint32_t stream_prev_line = 1; + uint32_t stream_prev_column = ECMA_LINE_INFO_COLUMN_DEFAULT; + uint32_t stream_size = 0; + uint32_t stream_value_count = 0; + uint32_t value; + + iterator.current_page_p = context_p->line_info.first_page_p; + iterator.offset = 1; + + do + { + /* Decode line information generated during parsing. */ + value = parser_line_info_iterator_get (&iterator); + iterator_byte_code_page_offset += (value >> 1); + + if (value & 0x1) + { + value = parser_line_info_iterator_get (&iterator); + JERRY_ASSERT (value != ((0 << 1) | ECMA_LINE_INFO_DECREASE)); + iterator_line = ecma_line_info_difference_update (iterator_line, value); + } + + value = parser_line_info_iterator_get (&iterator); + iterator_column = ecma_line_info_difference_update (iterator_column, value); + + while (iterator_byte_code_page_offset >= PARSER_CBC_STREAM_PAGE_SIZE) + { + iterator_byte_code_base += iterator_byte_code_page_p->bytes[PARSER_CBC_STREAM_PAGE_SIZE - 1]; + iterator_byte_code_page_offset -= PARSER_CBC_STREAM_PAGE_SIZE; + iterator_byte_code_page_p = iterator_byte_code_page_p->next_p; + } + + uint32_t iterator_byte_code_offset = iterator_byte_code_base; + + if (iterator_byte_code_page_offset > 0) + { + uint8_t relative_offset = iterator_byte_code_page_p->bytes[iterator_byte_code_page_offset - 1]; + iterator_byte_code_offset += relative_offset & CBC_LOWER_SEVEN_BIT_MASK; + } + + /* Skip those line/column pairs which byte code was discarded during post processing + * or does not change line/column (this is possible when multiple skips occures). */ + if (iterator_byte_code_offset == iterator_last_byte_code_offset + || (iterator_line == iterator_prev_line && iterator_column == iterator_prev_column)) + { + continue; + } + + iterator_prev_line = iterator_line; + iterator_prev_column = iterator_column; + iterator_last_byte_code_offset = iterator_byte_code_offset; + + if (block_size_p != NULL) + { + /* Sets ECMA_LINE_INFO_HAS_LINE bit. */ + value = (((iterator_byte_code_offset - stream_byte_code_offset) << 1) + | (uint32_t) (stream_prev_line != stream_current_line)); + + uint32_t line_column_size = 0; + uint32_t offset_size = parser_line_info_encode_small (block_buffer, value); + stream_byte_code_offset = iterator_byte_code_offset; + + if (value & ECMA_LINE_INFO_HAS_LINE) + { + value = parser_line_info_difference_get (stream_current_line, stream_prev_line); + line_column_size = parser_line_info_encode_small (line_column_buffer, value); + stream_prev_line = stream_current_line; + stream_prev_column = ECMA_LINE_INFO_COLUMN_DEFAULT; + } + + value = parser_line_info_difference_get (stream_current_column, stream_prev_column); + line_column_size += parser_line_info_encode_small (line_column_buffer + line_column_size, value); + + stream_prev_column = stream_current_column; + stream_current_line = iterator_line; + stream_current_column = iterator_column; + + stream_value_count++; + + if (stream_value_count < ECMA_LINE_INFO_STREAM_VALUE_COUNT_MAX + && (stream_size + offset_size + line_column_size <= PARSER_LINE_INFO_STREAM_SIZE_LIMIT)) + { + stream_size += offset_size + line_column_size; + + if (line_info_p != NULL) + { + memcpy (dst_p, block_buffer, offset_size); + dst_p += offset_size; + memcpy (dst_p, line_column_buffer, line_column_size); + dst_p += line_column_size; + } + continue; + } + + /* Finalize the current chunk. The size of EndOffset is always 1. */ + stream_size += 1 + line_column_size; + + JERRY_ASSERT (stream_size > ECMA_LINE_INFO_STREAM_SIZE_MIN + && (stream_size - ECMA_LINE_INFO_STREAM_SIZE_MIN) <= UINT8_MAX); + + if (line_info_p != NULL) + { + *block_size_p = (uint8_t) (stream_size - ECMA_LINE_INFO_STREAM_SIZE_MIN); + /* Set EndOffset to 0 and copy the has_line bit. */ + *dst_p++ = (uint8_t) (block_buffer[0] & ECMA_LINE_INFO_HAS_LINE); + memcpy (dst_p, line_column_buffer, line_column_size); + dst_p += line_column_size; + } + else + { + total_length += stream_size; + dst_p = block_buffer; + } + + uint32_t byte_code_diff = iterator_last_byte_code_offset - block_byte_code_offset; + dst_p += parser_line_info_encode_vlq (dst_p, byte_code_diff); + block_byte_code_offset = iterator_last_byte_code_offset; + + if (line_info_p == NULL) + { + total_length += (uint32_t) (dst_p - block_buffer); + } + } + + /* Start a new chunk. */ + if (line_info_p == NULL) + { + dst_p = block_buffer; + } + + value = parser_line_info_difference_get (iterator_line, block_prev_line); + + dst_p += parser_line_info_encode_vlq (dst_p, value); + block_size_p = dst_p; + dst_p++; + + if (line_info_p == NULL) + { + total_length += (uint32_t) (dst_p - block_buffer); + } + + block_prev_line = iterator_line; + stream_current_line = iterator_line; + stream_current_column = iterator_column; + stream_prev_line = iterator_line; + stream_prev_column = ECMA_LINE_INFO_COLUMN_DEFAULT; + stream_size = 0; + stream_value_count = 0; + } + while (iterator.current_page_p != NULL); + + value = (stream_prev_line != stream_current_line); + + /* Finalize the last stream */ + if (line_info_p == NULL) + { + dst_p = line_column_buffer; + total_length += stream_size + 1; + } + else + { + *block_size_p = 0; + /* Small encoded value of has_line bit. */ + *dst_p++ = (uint8_t) value; + } + + if (value) + { + value = parser_line_info_difference_get (stream_current_line, stream_prev_line); + dst_p += parser_line_info_encode_small (dst_p, value); + stream_prev_column = ECMA_LINE_INFO_COLUMN_DEFAULT; + } + + value = parser_line_info_difference_get (stream_current_column, stream_prev_column); + dst_p += parser_line_info_encode_small (dst_p, value); + + if (line_info_p == NULL) + { + total_length += (uint32_t) (dst_p - line_column_buffer); + } + + if (line_info_p != NULL) + { + break; + } + + total_length_size = parser_line_info_encode_vlq (block_buffer, total_length); + + /* TODO: Support allocation fail. */ + line_info_p = (uint8_t *) jmem_heap_alloc_block (total_length + total_length_size); + dst_p = line_info_p + parser_line_info_encode_vlq (line_info_p, total_length); + } + + JERRY_ASSERT (line_info_p + total_length_size + total_length == dst_p); + +#if JERRY_PARSER_DUMP_BYTE_CODE + if (context_p->is_show_opcodes) + { + ecma_line_info_dump (line_info_p); + } +#endif /* JERRY_PARSER_DUMP_BYTE_CODE */ + + return line_info_p; +} /* parser_line_info_generate */ + +#endif /* JERRY_LINE_INFO */ + +#endif /* JERRY_PARSER */ + +/** + * @} + * @} + * @} + */ diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 06c049adf..217fdc1d2 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -485,6 +485,9 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ #if JERRY_DEBUGGER || JERRY_LINE_INFO parser_line_counter_t ident_line_counter = context_p->token.line; #endif /* JERRY_DEBUGGER || JERRY_LINE_INFO */ +#if JERRY_LINE_INFO + parser_line_counter_t ident_column_counter = context_p->token.column; +#endif /* JERRY_LINE_INFO */ #if JERRY_MODULE_SYSTEM parser_module_append_export_name (context_p); @@ -522,10 +525,7 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ #endif /* JERRY_DEBUGGER */ #if JERRY_LINE_INFO - if (ident_line_counter != context_p->last_line_info_line) - { - parser_emit_line_info (context_p, ident_line_counter, false); - } + parser_line_info_append (context_p, ident_line_counter, ident_column_counter); #endif /* JERRY_LINE_INFO */ uint16_t index = context_p->lit_object.index; @@ -1866,10 +1866,7 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * switch_case_was_found = true; #if JERRY_LINE_INFO - if (context_p->token.line != context_p->last_line_info_line) - { - parser_emit_line_info (context_p, context_p->token.line, true); - } + parser_line_info_append (context_p, context_p->token.line, context_p->token.column); #endif /* JERRY_LINE_INFO */ parser_parse_expression (context_p, PARSE_EXPR); @@ -2834,7 +2831,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ } #endif /* JERRY_DEBUGGER */ #if JERRY_LINE_INFO - parser_emit_line_info (context_p, context_p->token.line, false); + parser_line_info_append (context_p, context_p->token.line, context_p->token.column); #endif /* JERRY_LINE_INFO */ lexer_construct_literal_object (context_p, &lit_location, LEXER_STRING_LITERAL); @@ -2919,8 +2916,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ #endif /* JERRY_DEBUGGER */ #if JERRY_LINE_INFO - if (context_p->token.line != context_p->last_line_info_line - && context_p->token.type != LEXER_SEMICOLON + if (context_p->token.type != LEXER_SEMICOLON && context_p->token.type != LEXER_LEFT_BRACE && context_p->token.type != LEXER_RIGHT_BRACE && context_p->token.type != LEXER_KEYW_VAR @@ -2930,7 +2926,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ && context_p->token.type != LEXER_KEYW_CASE && context_p->token.type != LEXER_KEYW_DEFAULT) { - parser_emit_line_info (context_p, context_p->token.line, true); + parser_line_info_append (context_p, context_p->token.line, context_p->token.column); } #endif /* JERRY_LINE_INFO */ diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index a9d2125eb..0a353599f 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -453,60 +453,6 @@ parser_emit_cbc_push_number (parser_context_t *context_p, /**< context */ context_p->last_cbc.value = (uint16_t) (value - 1); } /* parser_emit_cbc_push_number */ -#if JERRY_LINE_INFO - -/** - * Append a line info data - */ -void -parser_emit_line_info (parser_context_t *context_p, /**< context */ - uint32_t line, /**< current line */ - bool flush_cbc) /**< flush last byte code */ -{ - if (flush_cbc && context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE) - { - parser_flush_cbc (context_p); - } - -#if JERRY_PARSER_DUMP_BYTE_CODE - if (context_p->is_show_opcodes) - { - JERRY_DEBUG_MSG (" [%3d] CBC_EXT_LINE %d\n", (int) context_p->stack_depth, line); - } -#endif /* JERRY_PARSER_DUMP_BYTE_CODE */ - - parser_emit_two_bytes (context_p, CBC_EXT_OPCODE, CBC_EXT_LINE); - context_p->byte_code_size += 2; - - context_p->last_line_info_line = line; - - const uint32_t max_shift_plus_7 = 7 * 5; - uint32_t shift = 7; - - while (shift < max_shift_plus_7 && (line >> shift) > 0) - { - shift += 7; - } - - do - { - shift -= 7; - - uint8_t byte = (uint8_t) ((line >> shift) & CBC_LOWER_SEVEN_BIT_MASK); - - if (shift > 0) - { - byte = (uint8_t) (byte | CBC_HIGHEST_BIT_MASK); - } - - PARSER_APPEND_TO_BYTE_CODE (context_p, byte); - context_p->byte_code_size++; - } - while (shift > 0); -} /* parser_emit_line_info */ - -#endif /* JERRY_LINE_INFO */ - /** * Append a byte code with a branch argument */ diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index f05ff7331..a0953fa53 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -649,6 +649,13 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } #endif /* JERRY_ESNEXT */ +#if JERRY_LINE_INFO + if (context_p->line_info.first_page_p == NULL) + { + parser_line_info_append (context_p, context_p->token.line, context_p->token.column); + } +#endif /* JERRY_LINE_INFO */ + JERRY_ASSERT (context_p->stack_depth == 0); #ifndef JERRY_NDEBUG JERRY_ASSERT (context_p->context_stack_depth == 0); @@ -730,23 +737,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */ flags = cbc_ext_flags[ext_opcode]; PARSER_NEXT_BYTE (page_p, offset); length++; - -#if JERRY_LINE_INFO - if (ext_opcode == CBC_EXT_LINE) - { - uint8_t last_byte = 0; - - do - { - last_byte = page_p->bytes[offset]; - PARSER_NEXT_BYTE (page_p, offset); - length++; - } - while (last_byte & CBC_HIGHEST_BIT_MASK); - - continue; - } -#endif /* JERRY_LINE_INFO */ break; } case CBC_POST_DECR: @@ -941,6 +931,10 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } #endif /* JERRY_ESNEXT */ +#if JERRY_LINE_INFO + total_size += sizeof (ecma_value_t); +#endif /* JERRY_LINE_INFO */ + total_size = JERRY_ALIGNUP (total_size, JMEM_ALIGNMENT); compiled_code_p = (ecma_compiled_code_t *) parser_malloc (context_p, total_size); @@ -1087,6 +1081,10 @@ parser_post_processing (parser_context_t *context_p) /**< context */ compiled_code_p->status_flags |= function_type; +#if JERRY_LINE_INFO + compiled_code_p->status_flags |= CBC_CODE_FLAGS_HAS_LINE_INFO; +#endif /* JERRY_LINE_INFO */ + literal_pool_p = ((ecma_value_t *) byte_code_p) - context_p->register_count; byte_code_p += literal_length; dst_p = byte_code_p; @@ -1157,25 +1155,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */ opcode_p++; real_offset++; PARSER_NEXT_BYTE_UPDATE (page_p, offset, real_offset); - -#if JERRY_LINE_INFO - if (ext_opcode == CBC_EXT_LINE) - { - uint8_t last_byte = 0; - - do - { - last_byte = page_p->bytes[offset]; - *dst_p++ = last_byte; - - real_offset++; - PARSER_NEXT_BYTE_UPDATE (page_p, offset, real_offset); - } - while (last_byte & CBC_HIGHEST_BIT_MASK); - - continue; - } -#endif /* JERRY_LINE_INFO */ } /* Only literal and call arguments can be combined. */ @@ -1291,6 +1270,10 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } JERRY_ASSERT (dst_p == byte_code_p + length); +#if JERRY_LINE_INFO + uint8_t *line_info_p = parser_line_info_generate (context_p); +#endif /* JERRY_LINE_INFO */ + parse_update_branches (context_p, byte_code_p); parser_cbc_stream_free (&context_p->byte_code); @@ -1371,9 +1354,16 @@ parser_post_processing (parser_context_t *context_p) /**< context */ { 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 */ } #endif /* JERRY_ESNEXT */ +#if JERRY_LINE_INFO + ECMA_SET_INTERNAL_VALUE_POINTER (base_p[-1], line_info_p); +#endif /* JERRY_LINE_INFO */ + #if JERRY_PARSER_DUMP_BYTE_CODE if (context_p->is_show_opcodes) { @@ -1896,6 +1886,14 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.context_stack_depth = 0; #endif /* !JERRY_NDEBUG */ +#if JERRY_LINE_INFO + context.line_info.first_page_p = NULL; + context.line_info.last_page_p = NULL; + context.line_info.byte_code_position = 0; + context.line_info.line = 1; + context.line_info.column = 1; +#endif /* JERRY_LINE_INFO */ + #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; @@ -2074,6 +2072,10 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ parser_free (context.scope_stack_p, context.scope_stack_size * sizeof (parser_scope_stack_t)); } +#if JERRY_LINE_INFO + parser_line_info_free (&context.line_info); +#endif /* JERRY_LINE_INFO */ + #if JERRY_PARSER_DUMP_BYTE_CODE if (context.is_show_opcodes) { @@ -2206,6 +2208,10 @@ parser_save_context (parser_context_t *context_p, /**< context */ saved_context_p->context_stack_depth = context_p->context_stack_depth; #endif /* !JERRY_NDEBUG */ +#if JERRY_LINE_INFO + saved_context_p->line_info = context_p->line_info; +#endif /* JERRY_LINE_INFO */ + /* Reset private part of the context. */ context_p->status_flags &= PARSER_IS_STRICT; @@ -2236,6 +2242,14 @@ parser_save_context (parser_context_t *context_p, /**< context */ #ifndef JERRY_NDEBUG context_p->context_stack_depth = 0; #endif /* !JERRY_NDEBUG */ + +#if JERRY_LINE_INFO + context_p->line_info.first_page_p = NULL; + context_p->line_info.last_page_p = NULL; + context_p->line_info.byte_code_position = 0; + context_p->line_info.line = 1; + context_p->line_info.column = 1; +#endif /* JERRY_LINE_INFO */ } /* parser_save_context */ /** @@ -2252,6 +2266,10 @@ parser_restore_context (parser_context_t *context_p, /**< context */ parser_free (context_p->scope_stack_p, context_p->scope_stack_size * sizeof (parser_scope_stack_t)); } +#if JERRY_LINE_INFO + parser_line_info_free (&context_p->line_info); +#endif /* JERRY_LINE_INFO */ + /* Restore private part of the context. */ JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE); @@ -2284,6 +2302,10 @@ parser_restore_context (parser_context_t *context_p, /**< context */ #ifndef JERRY_NDEBUG context_p->context_stack_depth = saved_context_p->context_stack_depth; #endif /* !JERRY_NDEBUG */ + +#if JERRY_LINE_INFO + context_p->line_info = saved_context_p->line_info; +#endif /* JERRY_LINE_INFO */ } /* parser_restore_context */ /** @@ -2579,10 +2601,7 @@ parser_parse_class_fields (parser_context_t *context_p) /**< context */ } #if JERRY_LINE_INFO - if (context_p->token.line != context_p->last_line_info_line) - { - parser_emit_line_info (context_p, context_p->token.line, true); - } + parser_line_info_append (context_p, context_p->token.line, context_p->token.column); #endif /* JERRY_LINE_INFO */ context_p->source_end_p = range.source_end_p; @@ -2822,6 +2841,10 @@ parser_raise_error (parser_context_t *context_p, /**< context */ } #endif /* JERRY_ESNEXT */ +#if JERRY_LINE_INFO + parser_line_info_free (&saved_context_p->line_info); +#endif /* JERRY_LINE_INFO */ + saved_context_p = saved_context_p->prev_context_p; } diff --git a/jerry-core/vm/vm-defines.h b/jerry-core/vm/vm-defines.h index 047f25559..42c773cb9 100644 --- a/jerry-core/vm/vm-defines.h +++ b/jerry-core/vm/vm-defines.h @@ -113,9 +113,6 @@ typedef struct vm_frame_ctx_t struct vm_frame_ctx_t *prev_context_p; /**< previous context */ ecma_value_t this_binding; /**< this binding */ ecma_value_t block_result; /**< block result */ -#if JERRY_LINE_INFO - uint32_t current_line; /**< currently executed line */ -#endif /* JERRY_LINE_INFO */ uint16_t context_depth; /**< current context depth */ uint8_t status_flags; /**< combination of vm_frame_ctx_flags_t bits */ uint8_t call_operation; /**< perform a call or construct operation */ diff --git a/jerry-core/vm/vm-utils.c b/jerry-core/vm/vm-utils.c index 753b0adec..dc402288c 100644 --- a/jerry-core/vm/vm-utils.c +++ b/jerry-core/vm/vm-utils.c @@ -15,6 +15,7 @@ #include "ecma-array-object.h" #include "ecma-helpers.h" +#include "ecma-line-info.h" #include "jcontext.h" #include "lit-char-helpers.h" #include "vm.h" @@ -75,7 +76,8 @@ vm_get_backtrace (uint32_t max_depth) /**< maximum backtrace depth, 0 = unlimite while (context_p != NULL) { - ecma_value_t resource_name = ecma_get_resource_name (context_p->shared_p->bytecode_header_p); + const ecma_compiled_code_t *bytecode_header_p = context_p->shared_p->bytecode_header_p; + ecma_value_t resource_name = ecma_get_resource_name (bytecode_header_p); ecma_string_t *str_p = ecma_get_string_from_value (resource_name); ecma_stringbuilder_t builder = ecma_stringbuilder_create (); @@ -89,9 +91,27 @@ vm_get_backtrace (uint32_t max_depth) /**< maximum backtrace depth, 0 = unlimite ecma_stringbuilder_append_byte (&builder, LIT_CHAR_COLON); } - ecma_string_t *line_str_p = ecma_new_ecma_string_from_uint32 (context_p->current_line); - ecma_stringbuilder_append (&builder, line_str_p); - ecma_deref_ecma_string (line_str_p); + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_LINE_INFO) + { + jerry_backtrace_location_t location; + ecma_line_info_get (ecma_compiled_code_get_line_info (bytecode_header_p), + (uint32_t) (context_p->byte_code_p - context_p->byte_code_start_p), + &location); + + ecma_string_t *line_str_p = ecma_new_ecma_string_from_uint32 (location.line); + ecma_stringbuilder_append (&builder, line_str_p); + ecma_deref_ecma_string (line_str_p); + + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_COLON); + + line_str_p = ecma_new_ecma_string_from_uint32 (location.column); + ecma_stringbuilder_append (&builder, line_str_p); + ecma_deref_ecma_string (line_str_p); + } + else + { + ecma_stringbuilder_append_raw (&builder, (const lit_utf8_byte_t *)"1:1", 3); + } ecma_string_t *builder_str_p = ecma_stringbuilder_finalize (&builder); ecma_fast_array_set_property (array_p, index, ecma_make_string_value (builder_str_p)); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 76be1d26b..fe0735685 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -4629,23 +4629,6 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ continue; } #endif /* JERRY_DEBUGGER */ -#if JERRY_LINE_INFO - case VM_OC_LINE: - { - uint32_t value = 0; - uint8_t byte; - - do - { - byte = *byte_code_p++; - value = (value << 7) | (byte & CBC_LOWER_SEVEN_BIT_MASK); - } - while (byte & CBC_HIGHEST_BIT_MASK); - - frame_ctx_p->current_line = value; - continue; - } -#endif /* JERRY_LINE_INFO */ case VM_OC_NONE: default: { @@ -5112,9 +5095,6 @@ vm_init_exec (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ frame_ctx_p->prev_context_p = JERRY_CONTEXT (vm_top_context_p); frame_ctx_p->block_result = ECMA_VALUE_UNDEFINED; -#if JERRY_LINE_INFO - frame_ctx_p->current_line = 0; -#endif /* JERRY_LINE_INFO */ frame_ctx_p->context_depth = 0; frame_ctx_p->status_flags = (uint8_t) ((shared_p->status_flags & VM_FRAME_CTX_DIRECT_EVAL) | (bytecode_header_p->status_flags & VM_FRAME_CTX_IS_STRICT)); diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index d03543c54..72dd7480e 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -234,9 +234,6 @@ typedef enum VM_OC_BREAKPOINT_ENABLED, /**< enabled breakpoint for debugger */ VM_OC_BREAKPOINT_DISABLED, /**< disabled breakpoint for debugger */ #endif /* JERRY_DEBUGGER */ -#if JERRY_LINE_INFO - VM_OC_LINE, /**< line number of the next statement */ -#endif /* JERRY_LINE_INFO */ #if JERRY_ESNEXT VM_OC_CHECK_VAR, /**< check redeclared vars in the global scope */ VM_OC_CHECK_LET, /**< check redeclared lets in the global scope */ @@ -319,9 +316,6 @@ typedef enum VM_OC_BREAKPOINT_ENABLED = VM_OC_NONE, /**< enabled breakpoint for debugger is unused */ VM_OC_BREAKPOINT_DISABLED = VM_OC_NONE, /**< disabled breakpoint for debugger is unused */ #endif /* !JERRY_DEBUGGER */ -#if !JERRY_LINE_INFO - VM_OC_LINE = VM_OC_NONE, /**< line number of the next statement is unused */ -#endif /* !JERRY_LINE_INFO */ #if !JERRY_ESNEXT VM_OC_EXT_VAR_EVAL = VM_OC_NONE, /**< variable and function evaluation for * functions with separate argument context */ diff --git a/tests/unit-core/test-backtrace.c b/tests/unit-core/test-backtrace.c index b32ac580a..aef9bdbe7 100644 --- a/tests/unit-core/test-backtrace.c +++ b/tests/unit-core/test-backtrace.c @@ -75,7 +75,7 @@ backtrace_callback (jerry_backtrace_frame_t *frame_p, /* frame information */ { TEST_ASSERT (!jerry_backtrace_is_strict (frame_p)); TEST_ASSERT (location_p->line == 2); - TEST_ASSERT (location_p->column == 1); + TEST_ASSERT (location_p->column == 3); TEST_ASSERT (handler_args_p[0] == *function_p); TEST_ASSERT (handler_args_p[1] == *this_p); return true; @@ -85,7 +85,7 @@ backtrace_callback (jerry_backtrace_frame_t *frame_p, /* frame information */ { TEST_ASSERT (jerry_backtrace_is_strict (frame_p)); TEST_ASSERT (location_p->line == 7); - TEST_ASSERT (location_p->column == 1); + TEST_ASSERT (location_p->column == 6); TEST_ASSERT (handler_args_p[2] == *function_p); TEST_ASSERT (jerry_value_is_undefined (*this_p)); return true; @@ -96,7 +96,7 @@ backtrace_callback (jerry_backtrace_frame_t *frame_p, /* frame information */ TEST_ASSERT (frame_index == 3); TEST_ASSERT (!jerry_backtrace_is_strict (frame_p)); TEST_ASSERT (location_p->line == 11); - TEST_ASSERT (location_p->column == 1); + TEST_ASSERT (location_p->column == 3); TEST_ASSERT (handler_args_p[3] == *function_p); TEST_ASSERT (global == *this_p); @@ -125,7 +125,7 @@ async_backtrace_callback (jerry_backtrace_frame_t *frame_p, /* frame information { TEST_ASSERT (jerry_backtrace_is_strict (frame_p)); TEST_ASSERT (location_p->line == 3); - TEST_ASSERT (location_p->column == 1); + TEST_ASSERT (location_p->column == 3); TEST_ASSERT (handler_args_p[0] == *function_p); return true; } @@ -133,7 +133,7 @@ async_backtrace_callback (jerry_backtrace_frame_t *frame_p, /* frame information TEST_ASSERT (frame_index == 2); TEST_ASSERT (!jerry_backtrace_is_strict (frame_p)); TEST_ASSERT (location_p->line == 8); - TEST_ASSERT (location_p->column == 1); + TEST_ASSERT (location_p->column == 3); TEST_ASSERT (handler_args_p[1] == *function_p); return true; } /* async_backtrace_callback */ @@ -159,14 +159,14 @@ class_backtrace_callback (jerry_backtrace_frame_t *frame_p, /* frame information { TEST_ASSERT (jerry_backtrace_is_strict (frame_p)); TEST_ASSERT (location_p->line == 3); - TEST_ASSERT (location_p->column == 1); + TEST_ASSERT (location_p->column == 12); return false; } TEST_ASSERT (frame_index == 2); TEST_ASSERT (jerry_backtrace_is_strict (frame_p)); TEST_ASSERT (location_p->line == 2); - TEST_ASSERT (location_p->column == 1); + TEST_ASSERT (location_p->column == 5); return false; } /* class_backtrace_callback */ @@ -294,17 +294,17 @@ test_get_backtrace_api_call (void) TEST_ASSERT (jerry_get_array_length (backtrace) == 4); - compare (backtrace, 0, "something.js:2"); - compare (backtrace, 1, "something.js:6"); - compare (backtrace, 2, "something.js:10"); - compare (backtrace, 3, "something.js:13"); + compare (backtrace, 0, "something.js:2:3"); + compare (backtrace, 1, "something.js:6:3"); + compare (backtrace, 2, "something.js:10:3"); + compare (backtrace, 3, "something.js:13:1"); jerry_release_value (backtrace); /* Depth set to 2 this time. */ source_p = ("function f() {\n" - " return backtrace(2);\n" + " 1; return backtrace(2);\n" "}\n" "\n" "function g() {\n" @@ -324,8 +324,8 @@ test_get_backtrace_api_call (void) TEST_ASSERT (jerry_get_array_length (backtrace) == 2); - compare (backtrace, 0, "something_else.js:2"); - compare (backtrace, 1, "something_else.js:6"); + compare (backtrace, 0, "something_else.js:2:6"); + compare (backtrace, 1, "something_else.js:6:3"); jerry_release_value (backtrace); @@ -338,7 +338,7 @@ test_get_backtrace_api_call (void) "\n" "function g() {\n" " 'use strict';\n" - " return o.f();\n" + " 1; return o.f();\n" "}\n" "\n" "function h() {\n" @@ -458,9 +458,9 @@ test_exception_backtrace (void) TEST_ASSERT (jerry_get_array_length (backtrace) == 3); - compare (backtrace, 0, "bad.js:2"); - compare (backtrace, 1, "bad.js:6"); - compare (backtrace, 2, "bad.js:9"); + compare (backtrace, 0, "bad.js:2:3"); + compare (backtrace, 1, "bad.js:6:3"); + compare (backtrace, 2, "bad.js:9:1"); jerry_release_value (backtrace); @@ -505,7 +505,7 @@ test_large_line_count (void) TEST_ASSERT (jerry_get_array_length (backtrace) == 1); - compare (backtrace, 0, "bad.js:385"); + compare (backtrace, 0, "bad.js:385:1"); jerry_release_value (backtrace);