258 lines
8.4 KiB
C
258 lines
8.4 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifndef __rpn_jit__h__
|
|
#define __rpn_jit__h__
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/random.h>
|
|
|
|
|
|
#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
|