/* * Copyright (C) 2020 Weber Yann * * This file is part of pyrpn. * * pyrpn is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * pyrpn is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with pyrpn. If not, see . */ #ifndef __rpn_jit__h__ #define __rpn_jit__h__ #include "config.h" #include #include #include #include #include #include #include "rpn_lib.h" #include "rpn_parse.h" /**@defgroup rpn RPN evaluation lib * @brief High speed RPN expression evaluation librarie */ /**@defgroup rpn_compile RPN expression compilation * @brief How is an RPN expression transformed into a callable function * * Compilation is done in two steps : * - @ref rpn_tokenize * - @ref rpn_exec * @ingroup rpn */ /**@defgroup rpn_cmap Executable code map creation * @brief A code map containing compiled code to evaluate the expression * * In order to provide a callable memory adress, the compilation process starts * by creating a new memory map. Then @ref rpn_lib precompiled symbols are * copyied in it, suffixed by @ref rpn_exec_ret symbol. Finally, the map is set executable using mprotect. * @ingroup rpn_compile */ /**@file rpn_jit.h * @brief Contains structure & functions for rpn_expr_t manipulation & evaluation * @ingroup rpn */ /**@brief Mremap chunk size */ #define RPN_MAP_CHUNK 512 /**@brief @ref rpn_expr_t error state */ #define RPN_ERROR -1 /**@brief @ref rpn_expr_t initialization state */ #define RPN_SOURCE 0 /**@brief @ref rpn_expr_t ready to eval state */ #define RPN_READY 1 /**@brief Code part copy macro * @param expr rpn_expr_t* A pointer on @ref rpn_expr_t * @param NAME code part name * @see _rpn_code_part_cpy * @ingroup rpn_cmap */ #define CODE_PART_CPY(expr, NAME) _rpn_code_part_cpy(expr, &NAME, CODE_SZ(NAME), NULL) /**@brief Copy a value push in rpn code ptr * @param expr rpn_expr_t* A pointer on @ref rpn_expr_t * @param value unsigned long that will be push * @see _rpn_code_part_cpy * @ingroup rpn_cmap */ #define CODE_VALUE_CPY(expr, value) _rpn_code_part_cpy(expr, &rpn_value, CODE_SZ(rpn_value), &(value)); /**@brief Add an instruction to push an argument on RPN stack * @param expr rpn_expr_t* A pointer on @ref rpn_expr_t * @param value unsigned long The argument number * @see _rpn_code_part_cpy * @ingroup rpn_cmap */ #define CODE_ARG_CPY(expr, value) _rpn_code_part_cpy(expr, &rpn_arg, CODE_SZ(rpn_arg), &(value)); /**@brief RPN evaluation function type * @ingroup rpn_cmap */ typedef unsigned long (*rpn_run_f)(unsigned long, unsigned long*, void*); /**@brief RPN expression type * @ingroup rpn */ typedef struct rpn_expr_s rpn_expr_t; /**@brief Stores RPN expression informations * @ingroup rpn */ struct rpn_expr_s { /**@brief pointer on RPN expression */ char *expr; /**@brief Tokenized version of expression (set by @ref rpn_expr_compile)*/ rpn_tokenized_t toks; /**@brief pointer on jit code memory map */ void *code_map; /**@brief Pointer on next copy addr in code map */ void *code_map_ptr; /**@brief Code map size */ size_t code_map_sz; /**@brief rpn expression arguments count */ size_t args_count; /**@brief Stack values memory */ rpn_value_t *stack; /**@brief rpn jit function stack size * @note item size (size in bytes is sizeof(long) * stack_sz */ unsigned char stack_sz; /**@brief Expression status. Takes value in @ref RPN_ERROR, * @ref RPN_SOURCE, @ref RPN_READY */ short state; /**@brief Error reason */ char err_reason[128]; }; /**@brief Initialize a new @ref rpn_expr_s * @param expr Pointer on the expression * @param stack_sz Expression stack size * @param args_count Expression argument counter * @return 0 if no error else -1 * @note Once rpn_expr_init has been called, you have to call * @ref rpn_expr_close in order to free handled ressources * @ingroup rpn */ int rpn_expr_init(rpn_expr_t* expr, const unsigned char stack_sz, const size_t args_count); /**@brief Reinit an existing @ref rpn_expr_s avoiding mmap and malloc * for executable memory map and for stack * @param expr */ int rpn_expr_reinit(rpn_expr_t* expr); /**@brief Starts a new initialized expression from an expression string * @param expr Pointer on an intialized expression ( see @ref rpn_expr_init ) * @param code '\0' terminated string representing the RPN expr * @return 0 if no error else -1 and @ref rpn_expr_s::err_reason is set * @note The expression is copied, given buffer can be deallocated after call * @ingroup rpn */ int rpn_expr_compile(rpn_expr_t *expr, const char *code); /**@brief Starts a new initialized expression from a tokenized form * @param expr Pointer on an intialized expression ( see @ref rpn_expr_init ) * @param tokens Tokenized form * @param long_op If true long operation are used, else 1 chr op are used * @return 0 if no error else -1 and @ref rpn_expr_s::err_reason is set * @note The @ref rpn_tokenized_s::tokens attribute is "captured" by the * @ref rpn_expr_s structure and will be deallocated when @ref rpn_expr_close * is called. It is not encouraged to keep a reference on this attribute after * @ref rpn_expr_start_untokenize call (but pointed @ref rpn_tokenized_t * can be reused) * @ingroup rpn */ int rpn_expr_untokenize(rpn_expr_t *expr, rpn_tokenized_t *tokens, char long_op); /**@brief Generate a new random rpn_expression * @param op_sz Number of token in generated expression * @param args_count Number of arguments for generated expression * @return A pointer on allocated memory storing a valid random RPN expression. * NULL if error with errno set (produce a message on stderr) * @ingroup rpn */ char* rpn_random(size_t op_sz, size_t args_count); /**@brief Compile an new RPN expression from string expression * @param expr Pointer on @ref rpn_expr_s * @return 0 if no error else -1 and set @ref rpn_expr_s err_reason * @ingroup rpn_compile */ int _rpn_expr_compile_expr(rpn_expr_t* expr); /**@brief Compile an new RPN expression from string expression * @param expr Pointer on @ref rpn_expr_s * @return 0 if no error else -1 and set @ref rpn_expr_s err_reason * @ingroup rpn_compile */ int _rpn_expr_compile_tokens(rpn_expr_t* expr); /**@brief Evaluate an RPN expression * @param expr Pointer on @ref rpn_expr_s * @param args List of arguments * @return Head of stack after evaluation * @note If expression not compiled yet compile it before eval * @ingroup rpn */ unsigned long rpn_expr_eval(rpn_expr_t *expr, unsigned long *args); /**@brief Free ressources handled by given @ref rpn_expr_s * @param expr Pointer on rpn_expr_t * @param expr Pointer on @ref rpn_expr_s * @ingroup rpn */ void rpn_expr_close(rpn_expr_t* expr); /**@brief bzero memory allocated for stack * @param expr Pointer on rpn_expr_t * @ingroup rpn */ void rpn_expr_reset_stack(rpn_expr_t *expr); /**@brief Copy precompiled code from @ref rpn_lib.h in expression code map * @param expr The expression being compiled * @param token Pointer on token informations * @return 0 if no error else -1, set error and errno * @ingroup rpn_cmap */ int _rpn_expr_token_copy(rpn_expr_t *expr, rpn_token_t *token); /**@brief Copy a part of code to the code map * @warning designed to be use with @ref CODE_PART_CPY and CODE_VALUE_CPY macros * @param expr Pointer on rpn_expr_t * @param code_part copy src address * @param code_part_sz the code part size * @param value if not NULL set the first code part * instruction argument to this value * @return 0 if no error else -1 and set errno * @ingroup rpn_cmap */ int _rpn_code_part_cpy(rpn_expr_t* expr, const void* code_part, unsigned long code_part_sz, const unsigned long *value); /**@brief Allocate a memory map for given rpn_expt_t and copy the function * header * @param expr Pointer on rpn_expr_t * @return 0 if no error, else -1 and set errno * @ingroup rpn_cmap */ int _rpn_expr_init_map(rpn_expr_t* expr); /**@brief Copy the function suffix and change memory map protection * @param expr Pointer on rpn_expr_t * @return 0 if no error, else -1 and set errno * @ingroup rpn_cmap */ int _rpn_expr_end_map(rpn_expr_t *expr); #endif