From 697442434ddaeadc72ec906d2b79c224e066b82e Mon Sep 17 00:00:00 2001 From: Akos Kiss Date: Thu, 4 Aug 2016 09:24:26 +0200 Subject: [PATCH] Cleanup jerry's assert-like routines and macros Until now, jerry had 3 different assert-like routines: `jerry_assert_fail`, `jerry_unreachable`, and `jerry_unimplemented`, and 3 corresponding macros (`JERRY_ASSERT`, `JERRY_UNREACHABLE`, and `JERRY_UNIMPLEMENTED`). They had some irregularities, namely: * All of them had a string parameter, although `jerry_unreachable` never got anything there but NULL. * Both `jerry_unreachable` and `jerry_unimplemented` checked its string parameter for NULL, although it was always NULL for the first one and never NULL for the second. * `jerry_unreachable` is just a regular assert with a fixed error message (i.e., control should not have got here), however, the expansion of its corresponding macro in debug and release modes differs from the behaviour of `JERRY_ASSERT`: `JERRY_ASSERT` is a no-op in release, however, `JERRY_UNREACHABLE` was triggering a crash even there. * Moreover, `JERRY_UNIMPLEMENTED` was almost never used anymore but in a few places (where often an `#ifdef` selected between `JERRY_UNIMPLEMENTED` and `JERRY_UNREACHABLE`). Because of the above, this patch makes the following changes: * Drops `JERRY_UNIMPLEMENTED` completely and whereever it was still used, replaces it with `JERRY_UNREACHABLE`. As a consequence, the `jerry_unimplemented` function and the `ERR_UNIMPLEMENTED_CASE` fatal error code are also removed. * Makes `JERRY_UNREACHABLE` expand to no-op in release builds. (Actually, to `__builtin_unreachable ()` to avoid warnings.) As a consequence, makes both `jerry_assert_fail` and `jerry_unreachable` be guarded by `#ifndef JERRY_NDEBUG`. Also, changes `jerry_unreachable` not to expect a string parameter. * Rewrites `TEST_ASSERT` not to rely on `jerry_assert_fail` as `TEST_ASSERT` has to work in release builds as well. This also allows changing the error message not to mention "ICE", which would misleadingly suggest an assert within the engine, but "TEST" instead. As a side-effect of the cleanup, some refactorings happened in jrt.h: * Removed the definition of the unnecessary `__extension__` macro. * Re-used `JERRY_UNUSED` and `unlikely` where possible. * Moved some parts of the file around. * Fixed some comments (`/**` should only be used for the docstring of a single entity, for groups header comments, the regular `/*` should be used). JerryScript-DCO-1.0-Signed-off-by: Akos Kiss akiss@inf.u-szeged.hu --- .../ecma/builtin-objects/ecma-builtins.c | 8 +- jerry-core/jerry-port.h | 1 - jerry-core/jerry.c | 4 +- jerry-core/jrt/jrt-fatals.c | 63 +------- jerry-core/jrt/jrt.h | 149 +++++++----------- jerry-core/vm/vm.c | 2 +- tests/unit/test-common.h | 17 +- 7 files changed, 81 insertions(+), 163 deletions(-) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.c b/jerry-core/ecma/builtin-objects/ecma-builtins.c index 2eef37ccc..44b2074cf 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.c @@ -253,7 +253,7 @@ ecma_instantiate_builtin (ecma_builtin_id_t id) /**< built-in id */ { JERRY_ASSERT (id < ECMA_BUILTIN_ID__COUNT); - JERRY_UNIMPLEMENTED ("The built-in is not implemented."); + JERRY_UNREACHABLE (); /* The built-in is not implemented. */ } } } /* ecma_instantiate_builtin */ @@ -683,7 +683,7 @@ ecma_builtin_dispatch_routine (ecma_builtin_id_t builtin_object_id, /**< built-i default: { - JERRY_UNIMPLEMENTED ("The built-in is not implemented."); + JERRY_UNREACHABLE (); /* The built-in is not implemented. */ } } @@ -744,7 +744,7 @@ ecma_builtin_dispatch_call (ecma_object_t *obj_p, /**< built-in object */ default: { - JERRY_UNIMPLEMENTED ("The built-in is not implemented."); + JERRY_UNREACHABLE (); /* The built-in is not implemented. */ } } } @@ -799,7 +799,7 @@ ecma_builtin_dispatch_construct (ecma_object_t *obj_p, /**< built-in object */ default: { - JERRY_UNIMPLEMENTED ("The built-in is not implemented."); + JERRY_UNREACHABLE (); /* The built-in is not implemented. */ } } diff --git a/jerry-core/jerry-port.h b/jerry-core/jerry-port.h index d5d1faa4e..19f956d6a 100644 --- a/jerry-core/jerry-port.h +++ b/jerry-core/jerry-port.h @@ -48,7 +48,6 @@ typedef enum ERR_OUT_OF_MEMORY = 10, ERR_SYSCALL = 11, ERR_REF_COUNT_LIMIT = 12, - ERR_UNIMPLEMENTED_CASE = 118, ERR_FAILED_INTERNAL_ASSERTION = 120 } jerry_fatal_code_t; diff --git a/jerry-core/jerry.c b/jerry-core/jerry.c index 3abcffd66..525fcc7c6 100644 --- a/jerry-core/jerry.c +++ b/jerry-core/jerry.c @@ -1821,7 +1821,7 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled copied_code_p->status_flags = compiled_code_p->status_flags; #else /* CONFIG_DISABLE_REGEXP_BUILTIN */ - JERRY_UNIMPLEMENTED ("RegExp is not supported in the selected profile."); + JERRY_UNREACHABLE (); /* RegExp is not supported in the selected profile. */ #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ return start_offset; } @@ -2117,7 +2117,7 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data return (ecma_compiled_code_t *) re_bytecode_p; #else /* CONFIG_DISABLE_REGEXP_BUILTIN */ - JERRY_UNIMPLEMENTED ("RegExp is not supported in the selected profile."); + JERRY_UNREACHABLE (); /* RegExp is not supported in the selected profile. */ #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ } diff --git a/jerry-core/jrt/jrt-fatals.c b/jerry-core/jrt/jrt-fatals.c index 9c829d18d..8335408c2 100644 --- a/jerry-core/jrt/jrt-fatals.c +++ b/jerry-core/jrt/jrt-fatals.c @@ -51,11 +51,6 @@ jerry_fatal (jerry_fatal_code_t code) /**< status code */ jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: ERR_REF_COUNT_LIMIT\n"); break; } - case ERR_UNIMPLEMENTED_CASE: - { - jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: ERR_UNIMPLEMENTED_CASE\n"); - break; - } case ERR_FAILED_INTERNAL_ASSERTION: { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: ERR_FAILED_INTERNAL_ASSERTION\n"); @@ -72,6 +67,7 @@ jerry_fatal (jerry_fatal_code_t code) /**< status code */ } } /* jerry_fatal */ +#ifndef JERRY_NDEBUG /** * Handle failed assertion */ @@ -81,19 +77,12 @@ jerry_assert_fail (const char *assertion, /**< assertion condition string */ const char *function, /**< function name */ const uint32_t line) /**< line */ { -#ifndef JERRY_NDEBUG jerry_port_log (JERRY_LOG_LEVEL_ERROR, "ICE: Assertion '%s' failed at %s(%s):%lu.\n", assertion, file, function, (unsigned long) line); -#else /* JERRY_NDEBUG */ - (void) assertion; - (void) file; - (void) function; - (void) line; -#endif /* !JERRY_NDEBUG */ jerry_fatal (ERR_FAILED_INTERNAL_ASSERTION); } /* jerry_assert_fail */ @@ -102,62 +91,16 @@ jerry_assert_fail (const char *assertion, /**< assertion condition string */ * Handle execution of control path that should be unreachable */ void __noreturn -jerry_unreachable (const char *comment, /**< comment to unreachable mark if exists, - NULL - otherwise */ - const char *file, /**< file name */ +jerry_unreachable (const char *file, /**< file name */ const char *function, /**< function name */ const uint32_t line) /**< line */ { -#ifndef JERRY_NDEBUG jerry_port_log (JERRY_LOG_LEVEL_ERROR, - "ICE: Unreachable control path at %s(%s):%lu was executed", + "ICE: Unreachable control path at %s(%s):%lu was executed.\n", file, function, (unsigned long) line); -#else /* JERRY_NDEBUG */ - (void) file; - (void) function; - (void) line; -#endif /* !JERRY_NDEBUG */ - - if (comment != NULL) - { - jerry_port_log (JERRY_LOG_LEVEL_ERROR, "(%s)", comment); - } - - jerry_port_log (JERRY_LOG_LEVEL_ERROR, ".\n"); jerry_fatal (ERR_FAILED_INTERNAL_ASSERTION); } /* jerry_unreachable */ - -/** - * Handle unimplemented case execution - */ -void __noreturn -jerry_unimplemented (const char *comment, /**< comment to unimplemented mark if exists, - NULL - otherwise */ - const char *file, /**< file name */ - const char *function, /**< function name */ - const uint32_t line) /**< line */ -{ -#ifndef JERRY_NDEBUG - jerry_port_log (JERRY_LOG_LEVEL_ERROR, - "SORRY: Unimplemented case at %s(%s):%lu was executed", - file, - function, - (unsigned long) line); -#else /* JERRY_NDEBUG */ - (void) file; - (void) function; - (void) line; #endif /* !JERRY_NDEBUG */ - - if (comment != NULL) - { - jerry_port_log (JERRY_LOG_LEVEL_ERROR, "(%s)", comment); - } - - jerry_port_log (JERRY_LOG_LEVEL_ERROR, ".\n"); - - jerry_fatal (ERR_UNIMPLEMENTED_CASE); -} /* jerry_unimplemented */ diff --git a/jerry-core/jrt/jrt.h b/jerry-core/jrt/jrt.h index 0ff09837f..2aa1883b9 100644 --- a/jerry-core/jrt/jrt.h +++ b/jerry-core/jrt/jrt.h @@ -24,7 +24,7 @@ #include "jerry-port.h" #include "jrt-types.h" -/** +/* * Attributes */ #define __noreturn __attribute__((noreturn)) @@ -40,7 +40,13 @@ # define __attr_pure___ __attribute__((pure)) #endif /* !__attr_pure___ */ -/** +/* + * Conditions' likeliness, unlikeliness. + */ +#define likely(x) __builtin_expect (!!(x), 1) +#define unlikely(x) __builtin_expect (!!(x) , 0) + +/* * Normally compilers store const(ant)s in ROM. Thus saving RAM. * But if your compiler does not support it then the directive below can force it. * @@ -51,16 +57,17 @@ # define JERRY_CONST_DATA #endif /* JERRY_CONST_DATA */ -#ifndef __GNUC__ -#define __extension__ -#endif /* !__GNUC__ */ - -/** +/* * Constants */ #define JERRY_BITSINBYTE 8 -/** +/* + * Make sure unused parameters, variables, or expressions trigger no compiler warning. + */ +#define JERRY_UNUSED(x) ((void) (x)) + +/* * Asserts * * Warning: @@ -73,30 +80,54 @@ #define JERRY_STATIC_ASSERT(x, msg) \ enum { JERRY_STATIC_ASSERT_GLUE (static_assertion_failed_, __LINE__, msg) = 1 / (!!(x)) } -/** - * Variable that must not be referenced. - * - * May be used for static assertion checks. - */ -extern uint32_t jerry_unreferenced_expression; - -extern void __noreturn jerry_assert_fail (const char *, const char *, const char *, const uint32_t); -extern void __noreturn jerry_unreachable (const char *, const char *, const char *, const uint32_t); -extern void __noreturn jerry_unimplemented (const char *, const char *, const char *, const uint32_t); - #ifndef JERRY_NDEBUG -#define JERRY_ASSERT(x) do { if (__builtin_expect (!(x), 0)) { \ - jerry_assert_fail (#x, __FILE__, __func__, __LINE__); } } while (0) +extern void __noreturn jerry_assert_fail (const char *, const char *, const char *, const uint32_t); +extern void __noreturn jerry_unreachable (const char *, const char *, const uint32_t); + +#define JERRY_ASSERT(x) \ + do \ + { \ + if (unlikely (!(x))) \ + { \ + jerry_assert_fail (#x, __FILE__, __func__, __LINE__); \ + } \ + } while (0) + +#define JERRY_UNREACHABLE() \ + do \ + { \ + jerry_unreachable (__FILE__, __func__, __LINE__); \ + } while (0) #else /* JERRY_NDEBUG */ -#define JERRY_ASSERT(x) do { if (false) { (void)(x); } } while (0) +#define JERRY_ASSERT(x) \ + do \ + { \ + if (false) \ + { \ + JERRY_UNUSED (x); \ + } \ + } while (0) + +#define JERRY_UNREACHABLE() __builtin_unreachable () #endif /* !JERRY_NDEBUG */ -#define JERRY_UNUSED(x) ((void) (x)) +/** + * Exit on fatal error + */ +extern void __noreturn jerry_fatal (jerry_fatal_code_t); +/* + * Logging + */ #ifdef JERRY_ENABLE_LOG #define JERRY_DLOG(...) jerry_port_log (JERRY_LOG_LEVEL_DEBUG, __VA_ARGS__) #define JERRY_DDLOG(...) jerry_port_log (JERRY_LOG_LEVEL_TRACE, __VA_ARGS__) #else /* !JERRY_ENABLE_LOG */ +/** + * Mark for unreachable points and unimplemented cases + */ +extern void jerry_ref_unused_variables (void *, ...); + #define JERRY_DLOG(...) \ do \ { \ @@ -112,76 +143,10 @@ extern void __noreturn jerry_unimplemented (const char *, const char *, const ch #define JERRY_WARNING_MSG(...) jerry_port_log (JERRY_LOG_LEVEL_WARNING, __VA_ARGS__) /** - * Mark for unreachable points and unimplemented cases - */ -extern void jerry_ref_unused_variables (void *, ...); - -#ifndef JERRY_NDEBUG -#define JERRY_UNREACHABLE() \ - do \ - { \ - jerry_unreachable (NULL, __FILE__, __func__, __LINE__); \ - } while (0) - -#define JERRY_UNIMPLEMENTED(comment) \ - do \ - { \ - jerry_unimplemented (comment, __FILE__, __func__, __LINE__); \ - } while (0) - -#define JERRY_UNIMPLEMENTED_REF_UNUSED_VARS(comment, ...) \ - do \ - { \ - if (false) \ - { \ - jerry_ref_unused_variables (0, __VA_ARGS__); \ - } \ - jerry_unimplemented (comment, __FILE__, __func__, __LINE__); \ - } while (0) -#else /* JERRY_NDEBUG */ -#define JERRY_UNREACHABLE() \ - do \ - { \ - jerry_unreachable (NULL, NULL, NULL, 0); \ - } while (0) - -#define JERRY_UNIMPLEMENTED(comment) \ - do \ - { \ - jerry_unimplemented (comment, NULL, NULL, 0); \ - } while (0) - -#define JERRY_UNIMPLEMENTED_REF_UNUSED_VARS(comment, ...) \ - do \ - { \ - if (false) \ - { \ - jerry_ref_unused_variables (0, __VA_ARGS__); \ - } \ - jerry_unimplemented (comment, NULL, NULL, 0); \ - } while (0) -#endif /* !JERRY_NDEBUG */ - -/** - * Conditions' likeliness, unlikeliness. - */ -#define likely(x) __builtin_expect (!!(x), 1) -#define unlikely(x) __builtin_expect (!!(x) , 0) - -/** - * Exit - */ -extern void __noreturn jerry_fatal (jerry_fatal_code_t); - -/** - * sizeof, offsetof, ... + * Size of struct member */ #define JERRY_SIZE_OF_STRUCT_MEMBER(struct_name, member_name) sizeof (((struct_name *) NULL)->member_name) -/** - * Alignment - */ - /** * Aligns @a value to @a alignment. @a must be the power of 2. * @@ -189,15 +154,13 @@ extern void __noreturn jerry_fatal (jerry_fatal_code_t); */ #define JERRY_ALIGNUP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment) - 1)) -/** +/* * min, max */ #define JERRY_MIN(v1, v2) (((v1) < (v2)) ? (v1) : (v2)) #define JERRY_MAX(v1, v2) (((v1) < (v2)) ? (v2) : (v1)) - extern bool jrt_read_from_buffer_by_offset (const uint8_t *, size_t, size_t *, void *, size_t); - extern bool jrt_write_to_buffer_by_offset (uint8_t *, size_t, size_t *, const void *, size_t); #endif /* !JRT_H */ diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 82c493aaa..7b9ae6629 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -301,7 +301,7 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ return ret_value; #else /* CONFIG_DISABLE_REGEXP_BUILTIN */ - JERRY_UNIMPLEMENTED ("Regular Expressions are not supported in the selected profile!"); + JERRY_UNREACHABLE (); /* Regular Expressions are not supported in the selected profile! */ #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ } } /* vm_construct_literal_object */ diff --git a/tests/unit/test-common.h b/tests/unit/test-common.h index eb210d6b6..cc7fc4a96 100644 --- a/tests/unit/test-common.h +++ b/tests/unit/test-common.h @@ -1,4 +1,5 @@ /* 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. @@ -25,8 +26,20 @@ #include #include -#define TEST_ASSERT(x) do { if (__builtin_expect (!(x), 0)) { \ - jerry_assert_fail (#x, __FILE__, __func__, __LINE__); } } while (0) +#define TEST_ASSERT(x) \ + do \ + { \ + if (unlikely (!(x))) \ + { \ + jerry_port_log (JERRY_LOG_LEVEL_ERROR, \ + "TEST: Assertion '%s' failed at %s(%s):%lu.\n", \ + #x, \ + __FILE__, \ + __func__, \ + (unsigned long) __LINE__); \ + jerry_fatal (ERR_FAILED_INTERNAL_ASSERTION); \ + } \ + } while (0) /** * Test initialization statement that should be included