From 235a5b1329bea6dddd09b60298d8e5cf7097c5c0 Mon Sep 17 00:00:00 2001 From: Akos Kiss Date: Sat, 20 Feb 2016 15:39:37 +0100 Subject: [PATCH] Refactor ECMA builtin template Avoid sorting the array of property magic string IDs and make it const, thus ensuring that it gets placed in .rodata. Replace the binary search in the array (which would not work anymore because of unsortendness) with function that returns the index of the looked-after magic string ID using a switch-based logic (we rely on compiler optimization to generate optimal code from that switch). Extras: * Getting rid of the superfluous macro argument from routine names. * Fixing the list of undef'd macros * Fixing related comments JerryScript-DCO-1.0-Signed-off-by: Akos Kiss akiss@inf.u-szeged.hu --- ...a-builtin-internal-routines-template.inc.h | 184 +++++++++++------- .../builtin-objects/ecma-builtins-internal.h | 9 +- .../ecma/builtin-objects/ecma-builtins.c | 55 ------ .../ecma/builtin-objects/ecma-builtins.inc.h | 4 +- 4 files changed, 113 insertions(+), 139 deletions(-) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h index 9fc1f8a21..0a8d003e5 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h @@ -1,4 +1,5 @@ -/* Copyright 2014-2015 Samsung Electronics Co., Ltd. +/* Copyright 2014-2016 Samsung Electronics Co., Ltd. + * Copyright 2016 University of Szeged * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,14 +28,14 @@ #define PASTE_(x, y) PASTE__ (x, y) #define PASTE(x, y) PASTE_ (x, y) -#define SORT_PROPERTY_NAMES_ROUTINE_NAME(builtin_underscored_id) \ - PASTE (PASTE (ecma_builtin_, builtin_underscored_id), _sort_property_names) -#define TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME(builtin_underscored_id) \ - PASTE (PASTE (ecma_builtin_, builtin_underscored_id), _try_to_instantiate_property) -#define LIST_LAZY_PROPERTY_NAMES_ROUTINE_NAME(builtin_underscored_id) \ - PASTE (PASTE (ecma_builtin_, builtin_underscored_id), _list_lazy_property_names) -#define DISPATCH_ROUTINE_ROUTINE_NAME(builtin_underscored_id) \ - PASTE (PASTE (ecma_builtin_, builtin_underscored_id), _dispatch_routine) +#define FIND_PROPERTY_INDEX_ROUTINE_NAME \ + PASTE (PASTE (ecma_builtin_, BUILTIN_UNDERSCORED_ID), _find_property_index) +#define TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME \ + PASTE (PASTE (ecma_builtin_, BUILTIN_UNDERSCORED_ID), _try_to_instantiate_property) +#define LIST_LAZY_PROPERTY_NAMES_ROUTINE_NAME \ + PASTE (PASTE (ecma_builtin_, BUILTIN_UNDERSCORED_ID), _list_lazy_property_names) +#define DISPATCH_ROUTINE_ROUTINE_NAME \ + PASTE (PASTE (ecma_builtin_, BUILTIN_UNDERSCORED_ID), _dispatch_routine) #define ROUTINE_ARG(n) , ecma_value_t arg ## n #define ROUTINE_ARG_LIST_0 ecma_value_t this_arg @@ -56,7 +57,7 @@ #define ECMA_BUILTIN_PROPERTY_NAMES \ PASTE (PASTE (ecma_builtin_property_names, _), BUILTIN_UNDERSCORED_ID) -static lit_magic_string_id_t ECMA_BUILTIN_PROPERTY_NAMES[] = +static const lit_magic_string_id_t ECMA_BUILTIN_PROPERTY_NAMES[] = { #define SIMPLE_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) name, #define NUMBER_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) name, @@ -67,34 +68,79 @@ static lit_magic_string_id_t ECMA_BUILTIN_PROPERTY_NAMES[] = #include BUILTIN_INC_HEADER_NAME }; -/** - * Sort builtin's property names array - */ -void -SORT_PROPERTY_NAMES_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (void) +#define ECMA_BUILTIN_PROPERTY_NAME_INDEX(name) \ + PASTE (PASTE (PASTE (PASTE (ecma_builtin_property_names, _), BUILTIN_UNDERSCORED_ID), _), name) + +enum { - bool swapped; +#define SIMPLE_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) \ + ECMA_BUILTIN_PROPERTY_NAME_INDEX(name), +#define NUMBER_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) \ + ECMA_BUILTIN_PROPERTY_NAME_INDEX(name), +#define STRING_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) \ + ECMA_BUILTIN_PROPERTY_NAME_INDEX(name), +#define CP_UNIMPLEMENTED_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) \ + ECMA_BUILTIN_PROPERTY_NAME_INDEX(name), +#define OBJECT_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) \ + ECMA_BUILTIN_PROPERTY_NAME_INDEX(name), +#define ROUTINE(name, c_function_name, args_number, length_prop_value) \ + ECMA_BUILTIN_PROPERTY_NAME_INDEX(name), +#include BUILTIN_INC_HEADER_NAME +}; - do +/** + * Return the index of a magic string ID in the ECMA_BUILTIN_PROPERTY_NAMES + * array, or -1 if not found. + * + * Note: we trust the compiler to find the optimal (most performance and/or + * memory effective) way of implementing the switch construct of this function + * in binary code (e.g., jump tables for large consecutive cases, binary search + * for non-consecutive cases, some simple conditional branches for low number of + * cases, etc. -- the worst case is a linear sequence of comparisons, but even + * that's not that bad, since we cannot have more than 64 IDs in the array). + */ +static int32_t +FIND_PROPERTY_INDEX_ROUTINE_NAME (lit_magic_string_id_t id) /**< magic string id */ +{ + switch (id) { - swapped = false; - - for (ecma_length_t i = 1; - i < (sizeof (ECMA_BUILTIN_PROPERTY_NAMES) / sizeof (ECMA_BUILTIN_PROPERTY_NAMES[0])); - i++) +#define SIMPLE_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) \ + case name: \ + { \ + return ECMA_BUILTIN_PROPERTY_NAME_INDEX(name); \ + } +#define NUMBER_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) \ + case name: \ + { \ + return ECMA_BUILTIN_PROPERTY_NAME_INDEX(name); \ + } +#define STRING_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) \ + case name: \ + { \ + return ECMA_BUILTIN_PROPERTY_NAME_INDEX(name); \ + } +#define CP_UNIMPLEMENTED_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) \ + case name: \ + { \ + return ECMA_BUILTIN_PROPERTY_NAME_INDEX(name); \ + } +#define OBJECT_VALUE(name, obj_getter, prop_writable, prop_enumerable, prop_configurable) \ + case name: \ + { \ + return ECMA_BUILTIN_PROPERTY_NAME_INDEX(name); \ + } +#define ROUTINE(name, c_function_name, args_number, length_prop_value) \ + case name: \ + { \ + return ECMA_BUILTIN_PROPERTY_NAME_INDEX(name); \ + } +#include BUILTIN_INC_HEADER_NAME + default: { - if (ECMA_BUILTIN_PROPERTY_NAMES[i] < ECMA_BUILTIN_PROPERTY_NAMES[i - 1]) - { - lit_magic_string_id_t id_temp = ECMA_BUILTIN_PROPERTY_NAMES[i - 1]; - ECMA_BUILTIN_PROPERTY_NAMES[i - 1] = ECMA_BUILTIN_PROPERTY_NAMES[i]; - ECMA_BUILTIN_PROPERTY_NAMES[i] = id_temp; - - swapped = true; - } + return -1; } } - while (swapped); -} /* SORT_PROPERTY_NAMES_ROUTINE_NAME */ +} /* FIND_PROPERTY_INDEX_ROUTINE_NAME */ /** * If the property's name is one of built-in properties of the built-in object @@ -105,8 +151,8 @@ SORT_PROPERTY_NAMES_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (void) * NULL - otherwise. */ ecma_property_t * -TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (ecma_object_t *obj_p, /**< object */ - ecma_string_t *prop_name_p) /**< property's name */ +TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME (ecma_object_t *obj_p, /**< object */ + ecma_string_t *prop_name_p) /**< property's name */ { #define OBJECT_ID(builtin_id) const ecma_builtin_id_t builtin_object_id = builtin_id; #include BUILTIN_INC_HEADER_NAME @@ -121,12 +167,7 @@ TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (ecma_object_t return NULL; } - const ecma_length_t property_numbers = (ecma_length_t) (sizeof (ECMA_BUILTIN_PROPERTY_NAMES) / - sizeof (ECMA_BUILTIN_PROPERTY_NAMES[0])); - int32_t index; - index = ecma_builtin_bin_search_for_magic_string_id_in_array (ECMA_BUILTIN_PROPERTY_NAMES, - property_numbers, - id); + int32_t index = FIND_PROPERTY_INDEX_ROUTINE_NAME (id); if (index == -1) { @@ -284,21 +325,18 @@ TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (ecma_object_t * @return string values collection */ void -LIST_LAZY_PROPERTY_NAMES_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (ecma_object_t *object_p, /**< a built-in object */ - /** true - list enumerable properties - * into main collection, - * and non-enumerable to - * collection of 'skipped - * non-enumerable' - * properties, - * false - list all properties into - * main collection. - */ - bool separate_enumerable, - /** 'main' collection */ - ecma_collection_header_t *main_collection_p, - /** skipped 'non-enumerable' collection */ - ecma_collection_header_t *non_enum_collection_p) +LIST_LAZY_PROPERTY_NAMES_ROUTINE_NAME (ecma_object_t *object_p, /**< a built-in object */ + bool separate_enumerable, /**< true - list enumerable properties + into main collection, + and non-enumerable to + collection of 'skipped + non-enumerable' + properties, + false - list all properties into + main collection. */ + ecma_collection_header_t *main_collection_p, /**< 'main' collection */ + ecma_collection_header_t *non_enum_collection_p) /**< skipped 'non-enumerable' + collection */ { ecma_collection_header_t *for_enumerable_p = main_collection_p; (void) for_enumerable_p; @@ -313,16 +351,11 @@ LIST_LAZY_PROPERTY_NAMES_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (ecma_object_t *o const ecma_length_t properties_number = (ecma_length_t) (sizeof (ECMA_BUILTIN_PROPERTY_NAMES) / sizeof (ECMA_BUILTIN_PROPERTY_NAMES[0])); - for (ecma_length_t i = 0; - i < properties_number; - i++) + for (ecma_length_t index = 0; + index < properties_number; + index++) { - lit_magic_string_id_t name = ECMA_BUILTIN_PROPERTY_NAMES[i]; - - int32_t index; - index = ecma_builtin_bin_search_for_magic_string_id_in_array (ECMA_BUILTIN_PROPERTY_NAMES, - properties_number, - name); + lit_magic_string_id_t name = ECMA_BUILTIN_PROPERTY_NAMES[index]; uint32_t bit; ecma_internal_property_id_t mask_prop_id; @@ -398,14 +431,14 @@ LIST_LAZY_PROPERTY_NAMES_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (ecma_object_t *o * Returned value must be freed with ecma_free_value. */ ecma_value_t -DISPATCH_ROUTINE_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (uint16_t builtin_routine_id, /**< built-in wide routine - identifier */ - ecma_value_t this_arg_value, /**< 'this' argument - value */ - const ecma_value_t arguments_list[], /**< list of arguments - passed to routine */ - ecma_length_t arguments_number) /**< length of - arguments' list */ +DISPATCH_ROUTINE_ROUTINE_NAME (uint16_t builtin_routine_id, /**< built-in wide routine + identifier */ + ecma_value_t this_arg_value, /**< 'this' argument + value */ + const ecma_value_t arguments_list[], /**< list of arguments + passed to routine */ + ecma_length_t arguments_number) /**< length of + arguments' list */ { /* the arguments may be unused for some built-ins */ (void) this_arg_value; @@ -444,10 +477,11 @@ DISPATCH_ROUTINE_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (uint16_t builtin_routine #undef PASTE__ #undef PASTE_ #undef PASTE -#undef SORT_PROPERTY_NAMES_ROUTINE_NAME -#undef DISPATCH_ROUTINE_ROUTINE_NAME +#undef FIND_PROPERTY_INDEX_ROUTINE_NAME #undef TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME +#undef LIST_LAZY_PROPERTY_NAMES_ROUTINE_NAME +#undef DISPATCH_ROUTINE_ROUTINE_NAME #undef BUILTIN_UNDERSCORED_ID #undef BUILTIN_INC_HEADER_NAME #undef ECMA_BUILTIN_PROPERTY_NAMES - +#undef ECMA_BUILTIN_PROPERTY_NAME_INDEX diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h b/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h index 11b4d60df..2ba9bb022 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h @@ -1,4 +1,4 @@ -/* Copyright 2014-2015 Samsung Electronics Co., Ltd. +/* Copyright 2014-2016 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,9 +60,6 @@ /* ecma-builtins.c */ extern ecma_object_t * ecma_builtin_make_function_object_for_routine (ecma_builtin_id_t, uint16_t, uint8_t); -extern int32_t -ecma_builtin_bin_search_for_magic_string_id_in_array (const lit_magic_string_id_t[], - ecma_length_t, lit_magic_string_id_t); #define BUILTIN(builtin_id, \ object_type, \ @@ -88,9 +85,7 @@ extern void \ ecma_builtin_ ## lowercase_name ## _list_lazy_property_names (ecma_object_t *, \ bool, \ ecma_collection_header_t *, \ - ecma_collection_header_t *); \ -extern void \ -ecma_builtin_ ## lowercase_name ## _sort_property_names (void); + ecma_collection_header_t *); #include "ecma-builtins.inc.h" #endif /* !ECMA_BUILTINS_INTERNAL_H */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.c b/jerry-core/ecma/builtin-objects/ecma-builtins.c index 01a3bad5c..08d2c7e06 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.c @@ -219,10 +219,6 @@ ecma_instantiate_builtin (ecma_builtin_id_t id) /**< built-in id */ case builtin_id: \ { \ JERRY_ASSERT (ecma_builtin_objects[builtin_id] == NULL); \ - if (is_static) \ - { \ - ecma_builtin_ ## lowercase_name ## _sort_property_names (); \ - } \ \ ecma_object_t *prototype_obj_p; \ if (object_prototype_builtin_id == ECMA_BUILTIN_ID__COUNT) \ @@ -701,57 +697,6 @@ ecma_builtin_dispatch_routine (ecma_builtin_id_t builtin_object_id, /**< built-i JERRY_UNREACHABLE (); } /* ecma_builtin_dispatch_routine */ -/** - * Binary search for magic string identifier in array. - * - * Warning: - * array should be sorted in ascending order - * - * @return index of identifier, if it is contained in array, - * -1 - otherwise. - */ -int32_t -ecma_builtin_bin_search_for_magic_string_id_in_array (const lit_magic_string_id_t ids[], /**< array to search in */ - ecma_length_t array_length, /**< number of elements - in the array */ - lit_magic_string_id_t key) /**< value to search for */ -{ -#ifndef JERRY_NDEBUG - /* For binary search the values should be sorted */ - for (ecma_length_t id_index = 1; - id_index < array_length; - id_index++) - { - JERRY_ASSERT (ids[id_index - 1] < ids[id_index]); - } -#endif /* !JERRY_NDEBUG */ - - int32_t min = 0; - int32_t max = (int32_t) array_length - 1; - - while (min <= max) - { - int32_t mid = (min + max) / 2; - - if (ids[mid] == key) - { - return (int32_t) mid; - } - else if (ids[mid] > key) - { - max = mid - 1; - } - else - { - JERRY_ASSERT (ids[mid] < key); - - min = mid + 1; - } - } - - return -1; -} /* ecma_builtin_bin_search_for_magic_string_id_in_array */ - /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h index 475db0461..1a52e9e86 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -1,4 +1,4 @@ -/* Copyright 2014-2015 Samsung Electronics Co., Ltd. +/* Copyright 2014-2016 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ */ /* Description of built-in objects - in format (ECMA_BUILTIN_ID_id, object_type, class_magic_string_id, prototype_id, is_extensible, underscored_id) */ + in format (ECMA_BUILTIN_ID_id, object_type, prototype_id, is_extensible, is_static, underscored_id) */ /* The Object.prototype object (15.2.4) */ BUILTIN (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE,