From f3846424096e64b29dddf9a1166a73f95e6ca379 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Mon, 19 Oct 2020 10:55:26 +0200 Subject: [PATCH] Implement proper function length support (#4290) Comma after last destructuring argument has been fixed as well JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/ecma/base/ecma-helpers.c | 83 ++++++++-------- jerry-core/ecma/base/ecma-helpers.h | 4 +- .../ecma/operations/ecma-function-object.c | 9 +- jerry-core/include/jerryscript-snapshot.h | 2 +- jerry-core/parser/js/byte-code.h | 14 ++- jerry-core/parser/js/js-parser-internal.h | 6 ++ jerry-core/parser/js/js-parser.c | 99 ++++++++++++++----- tests/jerry/es.next/function-decl.js | 21 ++-- tests/test262-es6-excludelist.xml | 1 - tests/test262-esnext-excludelist.xml | 48 --------- 10 files changed, 157 insertions(+), 130 deletions(-) diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index f21fde176..5436db5ff 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -1498,27 +1498,6 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG); } /* ecma_bytecode_deref */ -/** - * Get the number of formal parameters of the compiled code - * - * @return number of formal parameters - */ -uint32_t -ecma_compiled_code_get_formal_params (const ecma_compiled_code_t *bytecode_header_p) /**< compiled code */ -{ - if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)) - { - return 0; - } - - if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) - { - return ((cbc_uint16_arguments_t *) bytecode_header_p)->argument_end; - } - - return ((cbc_uint8_arguments_t *) bytecode_header_p)->argument_end; -} /* ecma_compiled_code_get_formal_params */ - /** * Resolve the position of the arguments list start of the compiled code * @@ -1532,25 +1511,20 @@ ecma_compiled_code_resolve_arguments_start (const ecma_compiled_code_t *bytecode uint8_t *byte_p = (uint8_t *) bytecode_header_p; byte_p += ((size_t) bytecode_header_p->size) << JMEM_ALIGNMENT_LOG; - return ((ecma_value_t *) byte_p) - ecma_compiled_code_get_formal_params (bytecode_header_p); + if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)) + { + return ((ecma_value_t *) byte_p); + } + + if (JERRY_LIKELY (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS))) + { + return ((ecma_value_t *) byte_p) - ((cbc_uint8_arguments_t *) bytecode_header_p)->argument_end; + } + + return ((ecma_value_t *) byte_p) - ((cbc_uint16_arguments_t *) bytecode_header_p)->argument_end; } /* ecma_compiled_code_resolve_arguments_start */ #if ENABLED (JERRY_ESNEXT) -/** - * Get the tagged template collection of the compiled code - * - * @return pointer to the tagged template collection - */ -ecma_collection_t * -ecma_compiled_code_get_tagged_template_collection (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_TAGGED_LITERALS); - - ecma_value_t *base_p = ecma_compiled_code_resolve_function_name (bytecode_header_p); - - return ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, base_p[-1]); -} /* ecma_compiled_code_get_tagged_template_collection */ /** * Resolve the position of the function name of the compiled code @@ -1563,15 +1537,46 @@ ecma_compiled_code_resolve_function_name (const ecma_compiled_code_t *bytecode_h JERRY_ASSERT (bytecode_header_p != NULL); ecma_value_t *base_p = ecma_compiled_code_resolve_arguments_start (bytecode_header_p); -#if ENABLED (JERRY_ESNEXT) if (CBC_FUNCTION_GET_TYPE (bytecode_header_p->status_flags) != CBC_FUNCTION_CONSTRUCTOR) { base_p--; } -#endif /* ENABLED (JERRY_ESNEXT) */ 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 + * + * @return pointer to the tagged template collection + */ +ecma_collection_t * +ecma_compiled_code_get_tagged_template_collection (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_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]); +} /* ecma_compiled_code_get_tagged_template_collection */ + #endif /* ENABLED (JERRY_ESNEXT) */ /** diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index e5cde489a..06a89b193 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -514,11 +514,11 @@ void ecma_raise_error_from_error_reference (ecma_value_t value); void ecma_bytecode_ref (ecma_compiled_code_t *bytecode_p); void ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p); -uint32_t ecma_compiled_code_get_formal_params (const ecma_compiled_code_t *bytecode_p); ecma_value_t *ecma_compiled_code_resolve_arguments_start (const ecma_compiled_code_t *bytecode_header_p); #if ENABLED (JERRY_ESNEXT) -ecma_collection_t *ecma_compiled_code_get_tagged_template_collection (const ecma_compiled_code_t *bytecode_header_p); 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 /* ENABLED (JERRY_ESNEXT) */ ecma_value_t ecma_get_resource_name (const ecma_compiled_code_t *bytecode_p); #if (JERRY_STACK_LIMIT != 0) diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index eedcc8483..ed004a9e6 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -1524,12 +1524,18 @@ ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_LENGTH)) { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + if (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp)) { /* Initialize 'length' property */ 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_UINT16_ARGUMENTS) + + 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) { cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_data_p; len = args_p->argument_end; @@ -1629,7 +1635,6 @@ ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< return caller_prop_p; } #endif /* ENABLED (JERRY_ESNEXT) */ - } return NULL; diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index 2e04112ca..c87c210b9 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 (60u) +#define JERRY_SNAPSHOT_VERSION (61u) /** * Flags for jerry_generate_snapshot and jerry_generate_function_snapshot. diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 79410f772..2aa743598 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -869,10 +869,11 @@ typedef enum CBC_CODE_FLAGS_STRICT_MODE = (1u << 2), /**< strict mode is enabled */ CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED = (1u << 3), /**< mapped arguments object must be constructed */ CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 4), /**< no need to create a lexical environment */ - CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 5), /**< this function is a static snapshot function */ - CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 6), /**< this function should be ignored by debugger */ - CBC_CODE_FLAGS_HAS_TAGGED_LITERALS = (1u << 7), /**< this function has tagged template literal list */ - CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED = (1u << 8), /**< compiled code needs a lexical block */ + 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 */ /* 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 @@ -944,6 +945,11 @@ typedef enum #define CBC_FUNCTION_IS_ARROW(flags) \ ((flags) >= (CBC_FUNCTION_ARROW << CBC_FUNCTION_TYPE_SHIFT)) +/** + * Get length property from extended info + */ +#define CBC_EXTENDED_INFO_GET_LENGTH(extended_info) (extended_info) + #define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1, /** diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 9e9202378..632473f33 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -504,6 +504,9 @@ typedef struct parser_saved_context_t /* Literal types */ uint16_t argument_count; /**< number of function arguments */ +#if ENABLED (JERRY_ESNEXT) + uint16_t argument_length; /**< length property of arguments */ +#endif /* ENABLED (JERRY_ESNEXT) */ uint16_t register_count; /**< number of registers */ uint16_t literal_count; /**< number of literals */ @@ -574,6 +577,9 @@ typedef struct /* Literal types */ uint16_t argument_count; /**< number of function arguments */ +#if ENABLED (JERRY_ESNEXT) + uint16_t argument_length; /**< length property of arguments */ +#endif /* ENABLED (JERRY_ESNEXT) */ uint16_t register_count; /**< number of registers */ uint16_t literal_count; /**< number of literals */ diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index ebe56fb3a..d33b37b14 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -727,6 +727,15 @@ parse_print_final_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 ENABLED (JERRY_ESNEXT) + 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); + + JERRY_DEBUG_MSG (" [Extended] Argument length: %d\n\n", (int) CBC_EXTENDED_INFO_GET_LENGTH (extended_info)); + } +#endif /* ENABLED (JERRY_ESNEXT) */ + byte_code_start_p = (uint8_t *) compiled_code_p; if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) @@ -1273,6 +1282,11 @@ 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); @@ -1416,11 +1430,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */ function_type = CBC_FUNCTION_TO_TYPE_BITS (CBC_FUNCTION_NORMAL); } - if (context_p->tagged_template_literal_cp != JMEM_CP_NULL) - { - compiled_code_p->status_flags |= CBC_CODE_FLAGS_HAS_TAGGED_LITERALS; - } - if (context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED) { JERRY_ASSERT (!(context_p->status_flags & PARSER_IS_FUNCTION)); @@ -1638,27 +1647,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ parser_cbc_stream_free (&context_p->byte_code); -#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) - if (context_p->is_show_opcodes) - { - parser_list_iterator_t literal_iterator; - lexer_literal_t *literal_p; - - parse_print_final_cbc (compiled_code_p, &context_p->literal_pool, length); - JERRY_DEBUG_MSG ("\nByte code size: %d bytes\n", (int) length); - context_p->total_byte_code_size += (uint32_t) length; - - parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); - while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator))) - { - if ((literal_p->type == LEXER_IDENT_LITERAL || literal_p->type == LEXER_STRING_LITERAL) - && !(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR)) - { - jmem_heap_free_block ((void *) literal_p->u.char_p, literal_p->prop.length); - } - } - } -#else /* !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ +#if !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) if (context_p->status_flags & PARSER_HAS_LATE_LIT_INIT) { parser_list_iterator_t literal_iterator; @@ -1679,7 +1668,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } } } -#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ +#endif /* !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ ecma_value_t *base_p = (ecma_value_t *) (((uint8_t *) compiled_code_p) + total_size); @@ -1726,12 +1715,41 @@ parser_post_processing (parser_context_t *context_p) /**< context */ *(--base_p) = ECMA_VALUE_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; } #endif /* ENABLED (JERRY_ESNEXT) */ +#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) + if (context_p->is_show_opcodes) + { + parser_list_iterator_t literal_iterator; + lexer_literal_t *literal_p; + + parse_print_final_cbc (compiled_code_p, &context_p->literal_pool, length); + JERRY_DEBUG_MSG ("\nByte code size: %d bytes\n", (int) length); + context_p->total_byte_code_size += (uint32_t) length; + + parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); + while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator))) + { + if ((literal_p->type == LEXER_IDENT_LITERAL || literal_p->type == LEXER_STRING_LITERAL) + && !(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR)) + { + jmem_heap_free_block ((void *) literal_p->u.char_p, literal_p->prop.length); + } + } + } +#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + #if ENABLED (JERRY_DEBUGGER) if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) { @@ -1876,6 +1894,11 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER); } + if (context_p->argument_length == UINT16_MAX) + { + context_p->argument_length = context_p->argument_count; + } + flags |= PARSER_PATTERN_TARGET_DEFAULT; } @@ -1900,6 +1923,11 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ } lexer_next_token (context_p); + + if (context_p->token.type == end_type) + { + break; + } continue; } #endif /* ENABLED (JERRY_ESNEXT) */ @@ -1951,6 +1979,11 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER); } + if (context_p->argument_length == UINT16_MAX) + { + context_p->argument_length = context_p->argument_count; + } + parser_branch_t skip_init; if (has_duplicated_arg_names) @@ -2176,6 +2209,9 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.last_cbc_opcode = PARSER_CBC_UNAVAILABLE; context.argument_count = 0; +#if ENABLED (JERRY_ESNEXT) + context.argument_length = UINT16_MAX; +#endif /* ENABLED (JERRY_ESNEXT) */ context.register_count = 0; context.literal_count = 0; @@ -2438,6 +2474,9 @@ parser_save_context (parser_context_t *context_p, /**< context */ saved_context_p->last_statement = context_p->last_statement; saved_context_p->argument_count = context_p->argument_count; +#if ENABLED (JERRY_ESNEXT) + saved_context_p->argument_length = context_p->argument_length; +#endif /* ENABLED (JERRY_ESNEXT) */ saved_context_p->register_count = context_p->register_count; saved_context_p->literal_count = context_p->literal_count; @@ -2466,6 +2505,9 @@ parser_save_context (parser_context_t *context_p, /**< context */ context_p->last_statement.current_p = NULL; context_p->argument_count = 0; +#if ENABLED (JERRY_ESNEXT) + context_p->argument_length = UINT16_MAX; +#endif /* ENABLED (JERRY_ESNEXT) */ context_p->register_count = 0; context_p->literal_count = 0; @@ -2511,6 +2553,9 @@ parser_restore_context (parser_context_t *context_p, /**< context */ context_p->last_statement = saved_context_p->last_statement; context_p->argument_count = saved_context_p->argument_count; +#if ENABLED (JERRY_ESNEXT) + context_p->argument_length = saved_context_p->argument_length; +#endif /* ENABLED (JERRY_ESNEXT) */ context_p->register_count = saved_context_p->register_count; context_p->literal_count = saved_context_p->literal_count; diff --git a/tests/jerry/es.next/function-decl.js b/tests/jerry/es.next/function-decl.js index c54ad373e..ed7b6eaf9 100644 --- a/tests/jerry/es.next/function-decl.js +++ b/tests/jerry/es.next/function-decl.js @@ -32,17 +32,26 @@ function f1(a,) {} assert(f1.length === 1) function f2(a = 1,) {} -assert(f2.length === 1) +assert(f2.length === 0) function f3(a = 1, b = 1 + 1, c,) {} -assert(f3.length === 3) +assert(f3.length === 0) var f4 = async(a,) => {} assert(f4.length === 1) -var f5 = async(a = 1,) => {} -assert(f5.length === 1) +var f5 = async(a = 1,b,) => {} +assert(f5.length === 0) -assert(((a = 1, b = 1 + 1, c,) => {}).length === 3) +assert(((a, b = 1 + 1, c,) => {}).length === 1) -assert(((a = 1, b, c = 1 + 1,) => {}).length === 3) +assert(((a = 1, b, c = 1 + 1,) => {}).length === 0) + +function f6([a=1, b], [c, [d = 5] = []], e, [{f} = {}, g],) {} +assert(f6.length === 4) + +function f7([a, {b = 1, 4 : c = 2} = {}], {'cc' : d = 5, e}, f, {g, h} = a = {},) {} +assert(f7.length === 3) + +function f8(a, [b] = [], ...e) {} +assert(f8.length === 1) diff --git a/tests/test262-es6-excludelist.xml b/tests/test262-es6-excludelist.xml index 8b5458913..a47f06133 100644 --- a/tests/test262-es6-excludelist.xml +++ b/tests/test262-es6-excludelist.xml @@ -243,7 +243,6 @@ No longer a SyntaxError in ES11 - diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index e81a1bb80..2d27282c6 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -515,11 +515,9 @@ - - @@ -575,19 +573,14 @@ - - - - - @@ -604,15 +597,7 @@ - - - - - - - - @@ -624,17 +609,13 @@ - - - - @@ -645,17 +626,11 @@ - - - - - - @@ -857,12 +832,9 @@ - - - @@ -880,14 +852,6 @@ - - - - - - - - @@ -976,16 +940,12 @@ - - - - @@ -8446,7 +8406,6 @@ - @@ -8489,7 +8448,6 @@ - @@ -8522,7 +8480,6 @@ - @@ -8535,7 +8492,6 @@ - @@ -9097,7 +9053,6 @@ - @@ -9124,7 +9079,6 @@ - @@ -9163,7 +9117,6 @@ - @@ -9176,7 +9129,6 @@ -