/*
* 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