diff --git a/.gitignore b/.gitignore index 41193398..317d9c51 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,58 @@ -CMakeLists.txt -*.o -*.pyc -.dir +# Rust build artifacts +/target/ +**/*.rs.bk + +# Cargo files +Cargo.lock + +# IDE files +.vscode/ +*.swp +*.swo +*~ + +# OS files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Test artifacts +/build/ +*.tmp +*.temp + +# Logs +*.log + +# Local configuration +.env +.env.local + +# Backup files +*.bak +*.backup + +# Documentation build +/docs/build/ + +# Coverage reports +/coverage/ +*.gcov +*.gcda +*.gcno + +# Profiling data +*.prof +perf.data* + +# Binary executables mvm +mathvm + +# Temporary files +/tmp/ +*.tmp \ No newline at end of file diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 00000000..377a3e47 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,55 @@ +# Configuration for rustfmt +edition = "2021" +max_width = 100 +hard_tabs = false +tab_spaces = 4 +newline_style = "Unix" +use_small_heuristics = "Default" +indent_style = "Block" +wrap_comments = false +format_code_in_doc_comments = true +normalize_comments = true +normalize_doc_attributes = true +license_template_path = "" +format_strings = false +format_macro_matchers = true +format_macro_bodies = true +empty_item_single_line = true +struct_lit_single_line = true +fn_single_line = false +where_single_line = false +imports_indent = "Block" +imports_layout = "Mixed" +merge_imports = false +reorder_imports = true +reorder_modules = true +reorder_impl_items = false +type_punctuation_density = "Wide" +space_before_colon = false +space_after_colon = true +spaces_around_ranges = false +binop_separator = "Front" +remove_nested_parens = true +combine_control_expr = true +overflow_delimited_expr = false +struct_field_align_threshold = 0 +enum_discrim_align_threshold = 0 +match_block_trailing_comma = false +trailing_comma = "Vertical" +trailing_semicolon = true +use_field_init_shorthand = false +use_try_shorthand = false +condense_wildcard_suffixes = false +color = "Auto" +required_version = "1.4.38" +unstable_features = false +disable_all_formatting = false +skip_children = false +hide_parse_errors = false +error_on_line_overflow = false +error_on_unformatted = false +report_todo = "Never" +report_fixme = "Never" +ignore = [] +emit_mode = "Files" +make_backup = false \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..acb54d31 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "mathvm" +version = "0.1.0" +edition = "2021" +description = "A simple virtual machine for mathematical expressions - Course Assignment Stub" +authors = ["Student Name "] +license = "MIT" +readme = "README.md" + +[dependencies] +clap = { version = "4.0", features = ["derive"] } +thiserror = "1.0" +anyhow = "1.0" + +[dev-dependencies] +tempfile = "3.0" + +[[bin]] +name = "mvm" +path = "src/main.rs" + +[lib] +name = "mathvm" +path = "src/lib.rs" \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..cb388105 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Virtual Machines Course - MathVM Rust Implementation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index 77b384bc..00000000 --- a/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -ROOT = . -VM_ROOT = . -# This flag disables JIT dependencies. -NO_JIT = 1 - - -ifneq ($(NO_JIT), 1) -JIT_OBJ = $(OBJ)/jit$(OBJ_SUFF) -else -JIT_OBJ = -endif - -USER_OBJ = \ - $(JIT_OBJ) \ - $(OBJ)/main$(OBJ_SUFF) \ - $(OBJ)/translator$(OBJ_SUFF) - -include $(VM_ROOT)/common.mk - -MATHVM = $(BIN)/mvm - -all: $(MATHVM) - -$(MATHVM): $(OUT) $(MATHVM_OBJ) $(USER_OBJ) - $(CXX) -o $@ $(MATHVM_OBJ) $(USER_OBJ) $(LIBS) diff --git a/Makefile.student b/Makefile.student deleted file mode 100644 index 93907490..00000000 --- a/Makefile.student +++ /dev/null @@ -1,46 +0,0 @@ -ROOT = . -VM_ROOT = ../../.. - -# This flag enables -O2 optimization. Usage: make OPT=1 -#OPT = 1 - -# This flag disables JIT dependencies (should be 0 for task #4). -NO_JIT = 1 -# This flag enables SDL dependencies (should be 1 for task #4). -#WITH_SDL = 1 - -ifneq ($(NO_JIT), 1) -JIT_OBJ = $(OBJ)/jit$(OBJ_SUFF) -else -JIT_OBJ = -endif - -USER_OBJ = \ - $(JIT_OBJ) \ - $(OBJ)/main$(OBJ_SUFF) \ - $(OBJ)/translator_impl$(OBJ_SUFF) - -USER_CFLAGS = -std=c++14 - -include $(VM_ROOT)/common.mk - -MATHVM = $(BIN)/mvm - -all: $(MATHVM) - -ifeq ($(OPT), 1) -KIND = opt -else -KIND = debug -endif - -test: $(MATHVM) - $(VM_ROOT)/tests/task1.py -k $(KIND) -t $(VM_ROOT)/tests/mark3/ - $(VM_ROOT)/tests/task1.py -k $(KIND) -t $(VM_ROOT)/tests/mark4/ - $(VM_ROOT)/tests/task1.py -k $(KIND) -t $(VM_ROOT)/tests/mark5/ - #$(VM_ROOT)/tests/task3.py -k $(KIND) -t $(VM_ROOT)/tests/mark3/ - #$(VM_ROOT)/tests/task3.py -k $(KIND) -t $(VM_ROOT)/tests/mark4/ - #$(VM_ROOT)/tests/task3.py -k $(KIND) -t $(VM_ROOT)/tests/mark5/ - -$(MATHVM): $(OUT) $(MATHVM_OBJ) $(USER_OBJ) - $(CXX) -o $@ $(MATHVM_OBJ) $(USER_OBJ) $(LIBS) diff --git a/README.md b/README.md index d25df49d..91fabf95 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,183 @@ -# mathvm +# MathVM - Educational Virtual Machine in Rust + +A simple, educational Virtual Machine for Mathematical Expressions implemented in Rust. + +## Overview + +MathVM is an educational stack-based virtual machine designed for learning about language implementation, virtual machines, and compiler construction. It executes programs written in the MVM language and features both AST-based interpretation and bytecode compilation/execution. + +**This project is designed for educational purposes** to demonstrate: +- Language design and implementation +- Parsing and abstract syntax trees +- Virtual machine architecture +- Interpreter vs. compiler approaches +- Type systems and runtime environments + +## What You'll Learn + +By studying this codebase, you'll understand: +- How to build a lexer and recursive descent parser +- How to design and traverse abstract syntax trees +- How to implement tree-walking interpreters +- How to design bytecode instruction sets +- How to build stack-based virtual machines +- How scoping and variable resolution work +- How function calls and returns are implemented + +## MVM Language + +The MVM language is a C-style language with comprehensive support for: + +### Data Types +- `int`: 64-bit signed integer +- `double`: IEEE 754 double precision floating point +- `string`: Immutable UTF-8 strings + +### Language Features +- Variable declarations with initialization: `int x = 42;` +- Arithmetic operations: `+`, `-`, `*`, `/`, `%` with proper precedence +- Comparison operations: `==`, `!=`, `<`, `<=`, `>`, `>=` +- Logical operations: `&&`, `||`, `!` +- Bitwise operations: `&`, `|`, `^` +- Assignment operations: `=`, `+=`, `-=`, `*=`, `/=` +- Control flow: `if/else`, `while`, `for` loops with proper scoping +- Functions with parameters, return values, and closures +- Print statements with multiple arguments +- Automatic type conversions between compatible types + +### Example Programs + +```mvm +// Variables and arithmetic +int x = 10; +double y = 3.14; +print('Result: ', x + y * 2, '\n'); + +// Control flow +if (x > 5) { + print('x is greater than 5\n'); + for (i in 1..x) { + print('i = ', i, '\n'); + } +} -## Introduction +// Functions with recursion +function int factorial(int n) { + if (n <= 1) { + return 1; + } else { + return n * factorial(n - 1); + } +} -This folder contains partial source code for a simple VM, with few -intentionally missing pieces. This VM implements simple language (MVM -language) with basic computational functionality and flow control. +print('factorial(10) = ', factorial(10), '\n'); +``` -## MVM language +## Architecture -Language has simple C-style syntax and is intentionally rather basic. -Language has 3 types: - - 64-bit integer type, called `int` - - ANSI C compatible double type, called `double` - - immutable strings, called `string` (C equivalent: char*) +This educational VM demonstrates several key concepts in language implementation: -Every variable is scoped, scope is marked with curly braces (`{` -and `}`). Variable has to be declared before first use, otherwise -translation error will happen. +### Core Components -Values in variable could be modified with traditional C-style -expressions, like `x = 2 + y * 3`; with traditional C-style operators -precedence, i.e. aforementioned expression is evaluated as -`x = (2 + (y * 3))`; +1. **Lexer & Parser** (`src/parser.rs`) + - Recursive descent parser for the MVM language + - Basic error reporting with position information + - Demonstrates parsing techniques for expressions and statements -Variables in topmost scope could be bound to `Var` class instances, -to allow interoperability between MVM programs and C++. +2. **Abstract Syntax Tree** (`src/ast.rs`) + - AST representation with visitor pattern + - Shows how to structure language constructs in memory + - Includes a pretty printer for educational purposes -Literals can be: - - integer, such as 42 or 123456789012345 - - double, such as 42.0 or 1e-18 - - string, such as '42' or 'Hello \\'World\\'\n' +3. **Type System** (`src/types.rs`) + - Simple type system with int, double, string, and void + - Demonstrates type checking and conversions + - Function signatures and parameter handling -Flow control is as following: - - `for` loop, with semantics: -``` - for (i in -10..x) { - print('i=', i, '\n'); - } +4. **Execution Engines** + - **AST Interpreter** (`src/interpreter.rs`): Direct AST execution (tree-walking interpreter) + - **Bytecode System** (`src/bytecode.rs` + `src/translator.rs`): Demonstrates compilation to bytecode + - **Bytecode Interpreter**: Stack-based bytecode execution + +5. **Virtual Machine** (`src/vm.rs`) + - Unified interface for different execution modes + - Demonstrates how to build a simple VM API + +## Educational Value + +This project demonstrates several important concepts in programming language implementation: + +- **Lexical Analysis**: How to break source code into tokens +- **Parsing**: Converting tokens into an Abstract Syntax Tree +- **AST Design**: Representing language constructs in memory +- **Interpreters**: Tree-walking interpretation vs. bytecode execution +- **Type Systems**: Static typing with runtime type checking +- **Scoping**: Variable scope and environment management +- **Function Calls**: Parameter passing and return values +- **Error Handling**: Parse errors and runtime exceptions + +## Usage + +### Building and Running + +```bash +# Clone and build +git clone +cd mathvm +cargo build --release + +# Run a program +cargo run -- tests/mark3/add.mvm + +# Run in pretty-print mode +cargo run -- -p tests/mark3/function.mvm ``` - - `if` conditions, such as + +### Library Usage + +```rust +use mathvm::prelude::*; + +// Simple execution +let mut vm = VM::new(); +let result = vm.execute("print('Hello, ', 2 + 2);")?; ``` - if (x == 8 && y <= 2) { - print('c1\n'); - } else { - print('c2\n'); - } + +## Testing + +```bash +# Run all tests +cargo test + +# Run integration tests +cargo test integration_tests + +# Run with output visible +cargo test -- --nocapture ``` -## Implementation +## Development -We provide generic source -> AST (abstract syntax tree) translator, -so that implementors can focus on VM-specific issues. It means we -give scanner and top-down parser, generating tree of AST nodes, -representing program structure. It is up to implementors to provide -remaining pieces for fully functional VM. +### Building from Source -## Tests +```bash +# Debug build +cargo build -Directory `tests` contains set of tests on basic language features, -along with test scripts `taskN.py`. Generally, for every MVM program -we have an .expect file, which contains expected result of execution -for given MVM program. +# Optimized release build +cargo build --release -## Source tree layout +# Run linting +cargo clippy -Folder 'include' contains generic declarations of language constructs -(as AST nodes), set of bytecodes with description, and certain basic -interfaces. +# Format code +cargo fmt +``` -Folder `tests` contains MVM tests. Feel free to implement your own -tests. +## License -Folder `vm` contain source code for the VM. +MIT License - see [LICENSE](LICENSE) file for details. -## Building +--- -Build shall be pretty straightforward, just type `make` in command -line (known to work with MacOS and Linux). Use `make OPT=1` for an -optimized build. `NO_JIT` variables controls if JIT dependencies -shall be compiled in. -Create your own implementation in `students//` -folder, using `students//_example` template. +**MathVM** - An educational virtual machine implementation in Rust for learning language design and implementation. \ No newline at end of file diff --git a/common.mk b/common.mk deleted file mode 100644 index 905b554d..00000000 --- a/common.mk +++ /dev/null @@ -1,142 +0,0 @@ -OUT = $(ROOT)/build -ifeq ($(OPT),) - CFLAGS = -g3 - OBJ = $(OUT)/debug - BIN = $(OUT)/debug -else - OBJ = $(OUT)/opt - BIN = $(OUT)/opt - CFLAGS = -O2 -endif -OS := $(shell uname -s) - -MATHVM = $(BIN)/mvm -MATHVMTGZ = ../MathVM.tgz - -CXX ?= g++ -CFLAGS += -Wall -Werror -D_REENTRANT -fPIC $(USER_CFLAGS) -LIBS_ROOT = $(VM_ROOT)/libs -ASMJIT_CFLAGS = -Wno-error -INCLUDE = -I$(VM_ROOT)/include -I$(LIBS_ROOT) -VM_INCLUDE = -I$(VM_ROOT)/vm -ASMJIT_INCLUDE = -I$(LIBS_ROOT)/asmjit -USER_INCLUDE = -I$(ROOT) -DEFS = $(USER_DEFS) -D_POSIX_SOURCE -THREAD_LIB = -lpthread -OBJ_SUFF = .o -LIBS = $(USER_LIBS) $(THREAD_LIB) - - -ifneq (,$(findstring MINGW,$(OS))) - DEFS += -DMATHVM_WIN -else - DEFS += -DMATHVM_POSIX - LIBS += -ldl -endif - -ifneq (,$(findstring Darwin,$(OS))) - ifneq ($(WITH_SDL),) - DEFS += -I/opt/local/include - LIBS += -L/opt/local/lib -framework cocoa -lSDLmain - endif - DEFS += -D_DARWIN_C_SOURCE -endif - -ifneq (,$(findstring Linux,$(OS))) - LIBS += -rdynamic -endif - -ifneq ($(WITH_SDL),) - DEFS += -DMATHVM_WITH_SDL - LIBS += $(shell sdl-config --libs) - CFLAGS += $(shell sdl-config --cflags) -endif - -ASMJIT_OBJ_DIR = $(OBJ)/asmjit -ifneq ($(NO_JIT),1) -ASMJIT_OBJ = \ - $(ASMJIT_OBJ_DIR)/arch$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/assembler$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/codebuilder$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/codecompiler$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/codeemitter$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/codeholder$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/constpool$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/cpuinfo$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/func$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/globals$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/inst$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/logging$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/operand$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/osutils$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/regalloc$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/runtime$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/string$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/utils$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/vmem$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/zone$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/x86assembler$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/x86builder$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/x86compiler$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/x86inst$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/x86instimpl$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/x86internal$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/x86logging$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/x86operand$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/x86operand_regs$(OBJ_SUFF) \ - $(ASMJIT_OBJ_DIR)/x86regalloc$(OBJ_SUFF) -DEFS += -DASMJIT_BUILD_X86 -CFLAGS += -Wno-bool-compare -else -ASMJIT_OBJ = -endif - -MATHVM_OBJ = \ - $(ASMJIT_OBJ) \ - $(OBJ)/ast$(OBJ_SUFF) \ - $(OBJ)/mathvm$(OBJ_SUFF) \ - $(OBJ)/parser$(OBJ_SUFF) \ - $(OBJ)/scanner$(OBJ_SUFF) \ - $(OBJ)/utils$(OBJ_SUFF) \ - -default: $(OBJ)/.dir all - -tar: - rm -f $(MATHVMTGZ) - tar czf $(MATHVMTGZ) ../MathVM - - -$(OBJ)/%$(OBJ_SUFF): $(VM_ROOT)/vm/%.cpp \ - $(OBJ)/.dir \ - $(VM_ROOT)/include/ast.h $(VM_ROOT)/include/mathvm.h \ - $(VM_ROOT)/include/visitors.h \ - $(VM_ROOT)/vm/scanner.h $(VM_ROOT)/vm/parser.h \ - $(VM_ROOT)/common.mk - $(CXX) -c $(DEFS) $(CFLAGS) $(INCLUDE) $(VM_INCLUDE) $< -o $@ - -$(OBJ)/%$(OBJ_SUFF): $(ROOT)/%.cpp \ - $(OBJ)/.dir \ - $(VM_ROOT)/include/ast.h $(VM_ROOT)/include/mathvm.h \ - $(VM_ROOT)/include/visitors.h \ - $(VM_ROOT)/vm/scanner.h $(VM_ROOT)/vm/parser.h \ - $(VM_ROOT)/common.mk $(USER_DEPS) - $(CXX) -c $(DEFS) $(CFLAGS) $(INCLUDE) $(VM_INCLUDE) $< -o $@ - -$(ASMJIT_OBJ_DIR)/x86%$(OBJ_SUFF): $(LIBS_ROOT)/asmjit/x86/x86%.cpp $(OBJ)/.dir - $(CXX) -c $(DEFS) $(CFLAGS) $(ASMJIT_CFLAGS) $(INCLUDE) $(ASMJIT_INCLUDE) $< -o $@ - -$(ASMJIT_OBJ_DIR)/%$(OBJ_SUFF): $(LIBS_ROOT)/asmjit/base/%.cpp $(OBJ)/.dir - $(CXX) -c $(DEFS) $(CFLAGS) $(ASMJIT_CFLAGS) $(INCLUDE) $(ASMJIT_INCLUDE) $< -o $@ - -$(OBJ)/.dir: - mkdir -p $(OUT) - mkdir -p $(OBJ) - mkdir -p $(ASMJIT_OBJ_DIR) - mkdir -p $(BIN) - touch $@ - -clean: - rm -rf $(OUT) - -.PHONY : clean dirs all tar default - diff --git a/include/ast.h b/include/ast.h deleted file mode 100644 index 4211febb..00000000 --- a/include/ast.h +++ /dev/null @@ -1,743 +0,0 @@ -#ifndef _MATHVM_AST_H -#define _MATHVM_AST_H - -#include - -#include "mathvm.h" - -namespace mathvm { - -#define FOR_TOKENS(DO) \ - DO(tEOF, "", 0) \ - DO(tLPAREN, "(", 0) \ - DO(tRPAREN, ")", 0) \ - DO(tLBRACE, "{", 0) \ - DO(tRBRACE, "}", 0) \ - DO(tASSIGN, "=", 2) \ - DO(tOR, "||", 4) \ - DO(tAND, "&&", 5) \ - DO(tAOR, "|", 4) \ - DO(tAAND, "&", 5) \ - DO(tAXOR, "^", 5) \ - DO(tNOT, "!", 0) \ - DO(tEQ, "==", 9) \ - DO(tNEQ, "!=", 9) \ - DO(tGT, ">", 10) \ - DO(tGE, ">=", 10) \ - DO(tLT, "<", 10) \ - DO(tLE, "<=", 10) \ - DO(tRANGE, "..", 9) \ - DO(tADD, "+", 12) \ - DO(tSUB, "-", 12) \ - DO(tMUL, "*", 13) \ - DO(tDIV, "/", 13) \ - DO(tMOD, "%", 13) \ - DO(tINCRSET, "+=", 14) \ - DO(tDECRSET, "-=", 14) \ - DO(tDOUBLE, "", 0) \ - DO(tINT, "", 0) \ - DO(tSTRING, "", 0) \ - DO(tCOMMA, ",", 0) \ - DO(tSEMICOLON, ";", 0) \ - DO(tIDENT, "", 0) \ - DO(tERROR, "", 0) \ - DO(tUNDEF, "", 0) - -enum TokenKind { -#define ENUM_ELEM(t, s, p) t, - FOR_TOKENS(ENUM_ELEM) - tTokenCount -#undef ENUM_ELEM -}; - -#define FOR_KEYWORDS(DO) \ - DO("int") \ - DO("double") \ - DO("string") \ - DO("for") \ - DO("while") \ - DO("if") \ - DO("print") \ - DO("function") \ - DO("native") \ - DO("return") - -static inline bool isKeyword(const string& word) { -#define CHECK_WORD(w) if (word == w) return true; - FOR_KEYWORDS(CHECK_WORD); - return false; -} - -#define FOR_NODES(DO) \ - DO(BinaryOpNode, "binary") \ - DO(UnaryOpNode, "unary") \ - DO(StringLiteralNode, "string literal") \ - DO(DoubleLiteralNode, "double literal") \ - DO(IntLiteralNode, "int literal") \ - DO(LoadNode, "loadval") \ - DO(StoreNode, "storeval") \ - DO(ForNode, "for") \ - DO(WhileNode, "while") \ - DO(IfNode, "if") \ - DO(BlockNode, "block") \ - DO(FunctionNode, "function") \ - DO(ReturnNode, "return") \ - DO(CallNode, "call") \ - DO(NativeCallNode, "native call") \ - DO(PrintNode, "print") - -#define FORWARD_DECLARATION(type, name) class type; -FOR_NODES(FORWARD_DECLARATION) -#undef FORWARD_DECLARATION - -class Scope; - -class CustomDataHolder { - void* _info; - public: - void* info() const { return _info; } - void setInfo(void* info) { _info = info; } - protected: - CustomDataHolder() : _info(0) {} -}; - -/** - * This class represents variable in AST tree, without actual - * binding to particular storage. It's up to implementation - * to decide a logic for storing variables in memory. - * Generally, every variable must be guaranteed to be available - * for at least lifetime of its scope. - */ -class AstVar : public CustomDataHolder { - const string _name; - VarType _type; - Scope* _owner; - public: - AstVar(const string& name, VarType type, Scope* owner) : - _name(name), _type(type), _owner(owner) { - } - const string& name() const { return _name; } - VarType type() const { return _type; } - Scope* owner() const { return _owner; } -}; - -class FunctionNode; -class AstFunction : public CustomDataHolder { - FunctionNode* _function; - Scope* _owner; - public: - AstFunction(FunctionNode* function, Scope* owner) : - _function(function), _owner(owner) { - assert(_function != 0); - } - ~AstFunction(); - - const string& name() const; - VarType returnType() const; - VarType parameterType(uint32_t index) const; - const string& parameterName(uint32_t index) const; - uint32_t parametersNumber() const; - Scope* owner() const { return _owner; } - Scope* scope() const; - FunctionNode* node() const { return _function; } - static const string top_name; - static const string invalid; -}; - -class Scope { - typedef std::map VarMap; - typedef std::map FunctionMap; - - VarMap _vars; - FunctionMap _functions; - Scope* _parent; - vector _children; - - public: - Scope(Scope* parent): _parent(parent) {} - ~Scope(); - - uint32_t childScopeNumber() { return _children.size(); } - Scope* childScopeAt(uint32_t index) { return _children[index]; } - void addChildScope(Scope* scope) { _children.push_back(scope); } - - bool declareVariable(const string& name, VarType type); - bool declareFunction(FunctionNode* node); - - AstVar* lookupVariable(const string& name, bool useParent = true); - AstFunction* lookupFunction(const string& name, bool useParent = true); - - uint32_t variablesCount() const { return _vars.size(); } - uint32_t functionsCount() const { return _functions.size(); } - - Scope* parent() const { return _parent; } - - class VarIterator { - VarMap::iterator _it; - Scope* _scope; - bool _includeOuter; - public: - VarIterator(Scope* scope, bool includeOuter = false) : - _scope(scope), _includeOuter(includeOuter) { - _it = _scope->_vars.begin(); - } - - bool hasNext(); - AstVar* next(); - }; - - class FunctionIterator { - FunctionMap::iterator _it; - Scope* _scope; - bool _includeOuter; - public: - FunctionIterator(Scope* scope, bool includeOuter = false) : - _scope(scope), _includeOuter(includeOuter) { - _it = _scope->_functions.begin(); - } - - bool hasNext(); - AstFunction* next(); - }; - -}; - -class AstVisitor { - public: - AstVisitor() { - } - virtual ~AstVisitor() { - } - -#define VISITOR_FUNCTION(type, name) \ - virtual void visit##type(type* node) { static_cast(node); } - - FOR_NODES(VISITOR_FUNCTION) -#undef VISITOR_FUNCTION -}; - -#define COMMON_NODE_FUNCTIONS(type) \ - virtual void visit(AstVisitor* visitor); \ - virtual bool is##type() const { return true; } \ - virtual type* as##type() { return this; } - -class AstNode : public CustomDataHolder { - uint32_t _index; - public: - AstNode(uint32_t index) : - _index(index) { - } - virtual ~AstNode() { - } - - virtual void visit(AstVisitor* visitor) = 0; - virtual void visitChildren(AstVisitor* visitor) const = 0; - uint32_t position() const { - return _index; - } - -#define CHECK_FUNCTION(type, name) \ - virtual bool is##type() const { return false; } \ - virtual type* as##type() { return 0; } - - FOR_NODES(CHECK_FUNCTION) -#undef CHECK_FUNCTION - -}; - -class BinaryOpNode : public AstNode { - const TokenKind _kind; - AstNode* _left; - AstNode* _right; - public: - BinaryOpNode(uint32_t index, - TokenKind kind, - AstNode* left, - AstNode* right) : - AstNode(index), _kind(kind), _left(left), _right(right) { - assert(_left != 0); - assert(_right != 0); - } - - TokenKind kind() const { return _kind; } - AstNode* left() const { return _left; } - AstNode* right() const { return _right; } - - virtual void visitChildren(AstVisitor* visitor) const { - left()->visit(visitor); - right()->visit(visitor); - } - - COMMON_NODE_FUNCTIONS(BinaryOpNode); -}; - -class UnaryOpNode : public AstNode { - const TokenKind _kind; - AstNode* _operand; - public: - UnaryOpNode(uint32_t index, - TokenKind kind, - AstNode* operand) : - AstNode(index), _kind(kind), _operand(operand) { - assert(_operand != 0); - } - - TokenKind kind() const { return _kind; } - AstNode* operand() const { return _operand; } - - virtual void visitChildren(AstVisitor* visitor) const { - operand()->visit(visitor); - } - - COMMON_NODE_FUNCTIONS(UnaryOpNode); -}; - - -class StringLiteralNode : public AstNode { - const string _stringLiteral; - public: - StringLiteralNode(uint32_t index, const string& stringLiteral) : - AstNode(index), _stringLiteral(stringLiteral) { - } - - const string& literal() const { - return _stringLiteral; - } - - virtual void visitChildren(AstVisitor* visitor) const { - static_cast(visitor); - } - - COMMON_NODE_FUNCTIONS(StringLiteralNode); -}; - -class IntLiteralNode : public AstNode { - const int64_t _intLiteral; - public: - IntLiteralNode(uint32_t index, int64_t intLiteral) : - AstNode(index), _intLiteral(intLiteral) { - } - - int64_t literal() const { - return _intLiteral; - } - - virtual void visitChildren(AstVisitor* visitor) const { - static_cast(visitor); - } - - COMMON_NODE_FUNCTIONS(IntLiteralNode); -}; - -class DoubleLiteralNode : public AstNode { - const double _doubleLiteral; - public: - DoubleLiteralNode(uint32_t index, double doubleLiteral) : - AstNode(index), _doubleLiteral(doubleLiteral) { - } - - double literal() const { - return _doubleLiteral; - } - - virtual void visitChildren(AstVisitor* visitor) const { - static_cast(visitor); - } - - COMMON_NODE_FUNCTIONS(DoubleLiteralNode); -}; - -class LoadNode : public AstNode { - const AstVar* _var; - public: - LoadNode(uint32_t index, const AstVar* var) : - AstNode(index), _var(var) { - } - - const AstVar* var() const { - return _var; - } - - virtual void visitChildren(AstVisitor* visitor) const { - static_cast(visitor); - } - - COMMON_NODE_FUNCTIONS(LoadNode); -}; - -class StoreNode : public AstNode { - const AstVar* _var; - AstNode* _value; - TokenKind _op; - - public: - StoreNode(uint32_t index, - const AstVar* var, - AstNode* value, - TokenKind op) : - AstNode(index), _var(var), _value(value), _op(op) { - assert(_value != 0); - assert(_op == tASSIGN || _op == tINCRSET || _op == tDECRSET); - } - - const AstVar* var() const { - return _var; - } - - AstNode* value() const { - return _value; - } - - TokenKind op() const { - return _op; - } - - virtual void visitChildren(AstVisitor* visitor) const { - value()->visit(visitor); - } - - COMMON_NODE_FUNCTIONS(StoreNode); -}; - -class BlockNode : public AstNode { - vector _nodes; - Scope* _scope; - - public: - BlockNode(uint32_t index, - Scope* scope) : - AstNode(index), _scope(scope) { - } - - ~BlockNode() { - } - - Scope* scope() const { - return _scope; - } - - virtual uint32_t nodes() const { - return _nodes.size(); - } - - virtual AstNode* nodeAt(uint32_t index) const { - return _nodes[index]; - } - - virtual void add(AstNode* node) { - _nodes.push_back(node); - } - - virtual void visitChildren(AstVisitor* visitor) const { - for (uint32_t i = 0; i < nodes(); i++) { - nodeAt(i)->visit(visitor); - } - } - - COMMON_NODE_FUNCTIONS(BlockNode); -}; - -class NativeCallNode : public AstNode { - string _nativeName; - Signature _signature; - public: - NativeCallNode(uint32_t index, - const string& nativeName, - vector >& signature) : - AstNode(index), _nativeName(nativeName), _signature(signature) { - } - - ~NativeCallNode() { - } - - const string& nativeName() const { - return _nativeName; - } - - const Signature& nativeSignature() const { - return _signature; - } - - - virtual void visitChildren(AstVisitor* visitor) const { - static_cast(visitor); - } - - COMMON_NODE_FUNCTIONS(NativeCallNode); -}; - - -class ForNode : public AstNode { - const AstVar* _var; - AstNode* _inExpr; - BlockNode* _body; - - public: - ForNode(uint32_t index, - const AstVar* var, - AstNode* inExpr, - BlockNode* body) : - AstNode(index), _var(var), _inExpr(inExpr), _body(body) { - assert(_inExpr != 0); - assert(_body != 0); - } - - const AstVar* var() const { - return _var; - } - - AstNode* inExpr() const { - return _inExpr; - } - - BlockNode* body() const { - return _body; - } - - virtual void visitChildren(AstVisitor* visitor) const { - inExpr()->visit(visitor); - body()->visit(visitor); - } - - COMMON_NODE_FUNCTIONS(ForNode); -}; - -class WhileNode : public AstNode { - AstNode* _whileExpr; - BlockNode* _loopBlock; - - public: - WhileNode(uint32_t index, - AstNode* whileExpr, - BlockNode* loopBlock) : - AstNode(index), _whileExpr(whileExpr), - _loopBlock(loopBlock) { - assert(_whileExpr != 0); - assert(_loopBlock != 0); - } - - AstNode* whileExpr() const { - return _whileExpr; - } - - BlockNode* loopBlock() const { - return _loopBlock; - } - - virtual void visitChildren(AstVisitor* visitor) const { - whileExpr()->visit(visitor); - loopBlock()->visit(visitor); - } - - COMMON_NODE_FUNCTIONS(WhileNode); -}; - -class IfNode : public AstNode { - AstNode* _ifExpr; - BlockNode* _thenBlock; - BlockNode* _elseBlock; - - public: - IfNode(uint32_t index, - AstNode* ifExpr, - BlockNode* thenBlock, - BlockNode* elseBlock) : - AstNode(index), _ifExpr(ifExpr), - _thenBlock(thenBlock), _elseBlock(elseBlock) { - assert(_ifExpr != 0); - assert(_thenBlock != 0); - } - - AstNode* ifExpr() const { - return _ifExpr; - } - - BlockNode* thenBlock() const { - return _thenBlock; - } - - BlockNode* elseBlock() const { - return _elseBlock; - } - - virtual void visitChildren(AstVisitor* visitor) const { - ifExpr()->visit(visitor); - thenBlock()->visit(visitor); - if (elseBlock()) { - elseBlock()->visit(visitor); - } - } - - COMMON_NODE_FUNCTIONS(IfNode); -}; - -class ReturnNode : public AstNode { - AstNode* _returnExpr; - - public: - ReturnNode(uint32_t index, - AstNode* returnExpr) : - AstNode(index), _returnExpr(returnExpr) { - } - - AstNode* returnExpr() const { - return _returnExpr; - } - - virtual void visitChildren(AstVisitor* visitor) const { - if (returnExpr()) { - returnExpr()->visit(visitor); - } - } - - COMMON_NODE_FUNCTIONS(ReturnNode); -}; - -class FunctionNode : public AstNode { - const string _name; - Signature _signature; - BlockNode* _body; - - public: - FunctionNode(uint32_t index, - const string& name, - Signature& signature, - BlockNode* body) : - AstNode(index), _name(name), _signature(signature), _body(body) { - assert(_body != 0); - assert(signature.size() > 0); - } - - const string& name() const { - return _name; - } - - VarType returnType() const { - return _signature[0].first; - } - - uint32_t parametersNumber() const { - return _signature.size() - 1; - } - - VarType parameterType(uint32_t index) const { - return _signature[index + 1].first; - } - - const string& parameterName(uint32_t index) const { - return _signature[index + 1].second; - } - - const Signature& signature() const { - return _signature; - } - - BlockNode* body() const { - return _body; - } - - virtual void visitChildren(AstVisitor* visitor) const { - body()->visit(visitor); - } - - COMMON_NODE_FUNCTIONS(FunctionNode); -}; - -class CallNode : public AstNode { - const string _name; - vector _parameters; - -public: - CallNode(uint32_t index, - const string& name, - vector& parameters) : - AstNode(index), _name(name) { - for (uint32_t i = 0; i < parameters.size(); i++) { - _parameters.push_back(parameters[i]); - } - } - - const string& name() const { - return _name; - } - - uint32_t parametersNumber() const { - return _parameters.size(); - } - - AstNode* parameterAt(uint32_t index) const { - return _parameters[index]; - } - - virtual void visitChildren(AstVisitor* visitor) const { - for (uint32_t i = 0; i < parametersNumber(); i++) { - parameterAt(i)->visit(visitor); - } - } - - COMMON_NODE_FUNCTIONS(CallNode); -}; - -class PrintNode : public AstNode { - vector _operands; - - public: - PrintNode(uint32_t index) : - AstNode(index) { - } - - uint32_t operands() const { - return _operands.size(); - } - - AstNode* operandAt(uint32_t index) const { - return _operands[index]; - } - - void add(AstNode* node) { - _operands.push_back(node); - } - - virtual void visitChildren(AstVisitor* visitor) const { - for (uint32_t i = 0; i < operands(); i++) { - operandAt(i)->visit(visitor); - } - } - - COMMON_NODE_FUNCTIONS(PrintNode); -}; - -#undef COMMON_NODE_FUNCTIONS - -static inline const char* tokenStr(TokenKind token) { -#define R(t, s, p) case t: return #t; - switch (token) { - FOR_TOKENS(R) - default: - return ""; -#undef R - } -} - -static inline const char* tokenOp(TokenKind token) { -#define R(t, s, p) case t: return s; - switch (token) { - FOR_TOKENS(R) - default: - return "???"; -#undef R - } -} - -static inline int tokenPrecedence(TokenKind token) { -#define R(t, s, p) case t: return p; - switch (token) { - FOR_TOKENS(R) - default: - return 0; -#undef R - } -} - -} -#endif diff --git a/include/mathvm.h b/include/mathvm.h deleted file mode 100644 index 5140afe8..00000000 --- a/include/mathvm.h +++ /dev/null @@ -1,638 +0,0 @@ -#ifndef _MATHVM_H -#define _MATHVM_H - -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace mathvm { - -using namespace std; - -#define FOR_BYTECODES(DO) \ - DO(INVALID, "Invalid instruction.", 1) \ - DO(DLOAD, "Load double on TOS, inlined into insn stream.", 9) \ - DO(ILOAD, "Load int on TOS, inlined into insn stream.", 9) \ - DO(SLOAD, "Load string reference on TOS, next two bytes - constant id.", 3) \ - DO(DLOAD0, "Load double 0 on TOS.", 1) \ - DO(ILOAD0, "Load int 0 on TOS.", 1) \ - DO(SLOAD0, "Load empty string on TOS.", 1) \ - DO(DLOAD1, "Load double 1 on TOS.", 1) \ - DO(ILOAD1, "Load int 1 on TOS.", 1) \ - DO(DLOADM1, "Load double -1 on TOS.", 1) \ - DO(ILOADM1, "Load int -1 on TOS.", 1) \ - DO(DADD, "Add 2 doubles on TOS, push value back.", 1) \ - DO(IADD, "Add 2 ints on TOS, push value back.", 1) \ - DO(DSUB, "Subtract 2 doubles on TOS (lower from upper), push value back.", 1) \ - DO(ISUB, "Subtract 2 ints on TOS (lower from upper), push value back.", 1) \ - DO(DMUL, "Multiply 2 doubles on TOS, push value back.", 1) \ - DO(IMUL, "Multiply 2 ints on TOS, push value back.", 1) \ - DO(DDIV, "Divide 2 doubles on TOS (upper to lower), push value back.", 1) \ - DO(IDIV, "Divide 2 ints on TOS (upper to lower), push value back.", 1) \ - DO(IMOD, "Modulo operation on 2 ints on TOS (upper to lower), push value back.", 1) \ - DO(DNEG, "Negate double on TOS.", 1) \ - DO(INEG, "Negate int on TOS.", 1) \ - DO(IAOR, "Arithmetic OR of 2 ints on TOS, push value back.", 1) \ - DO(IAAND, "Arithmetic AND of 2 ints on TOS, push value back.", 1) \ - DO(IAXOR, "Arithmetic XOR of 2 ints on TOS, push value back.", 1) \ - DO(IPRINT, "Pop and print integer TOS.", 1) \ - DO(DPRINT, "Pop and print double TOS.", 1) \ - DO(SPRINT, "Pop and print string TOS.", 1) \ - DO(I2D, "Convert int on TOS to double.", 1) \ - DO(D2I, "Convert double on TOS to int.", 1) \ - DO(S2I, "Convert string on TOS to int.", 1) \ - DO(SWAP, "Swap 2 topmost values.", 1) \ - DO(POP, "Remove topmost value.", 1) \ - DO(LOADDVAR0, "Load double from variable 0, push on TOS.", 1) \ - DO(LOADDVAR1, "Load double from variable 1, push on TOS.", 1) \ - DO(LOADDVAR2, "Load double from variable 2, push on TOS.", 1) \ - DO(LOADDVAR3, "Load double from variable 3, push on TOS.", 1) \ - DO(LOADIVAR0, "Load int from variable 0, push on TOS.", 1) \ - DO(LOADIVAR1, "Load int from variable 1, push on TOS.", 1) \ - DO(LOADIVAR2, "Load int from variable 2, push on TOS.", 1) \ - DO(LOADIVAR3, "Load int from variable 3, push on TOS.", 1) \ - DO(LOADSVAR0, "Load string from variable 0, push on TOS.", 1) \ - DO(LOADSVAR1, "Load string from variable 1, push on TOS.", 1) \ - DO(LOADSVAR2, "Load string from variable 2, push on TOS.", 1) \ - DO(LOADSVAR3, "Load string from variable 3, push on TOS.", 1) \ - DO(STOREDVAR0, "Pop TOS and store to double variable 0.", 1) \ - DO(STOREDVAR1, "Pop TOS and store to double variable 1.", 1) \ - DO(STOREDVAR2, "Pop TOS and store to double variable 2.", 1) \ - DO(STOREDVAR3, "Pop TOS and store to double variable 3.", 1) \ - DO(STOREIVAR0, "Pop TOS and store to int variable 0.", 1) \ - DO(STOREIVAR1, "Pop TOS and store to int variable 1.", 1) \ - DO(STOREIVAR2, "Pop TOS and store to int variable 2.", 1) \ - DO(STOREIVAR3, "Pop TOS and store to int variable 3.", 1) \ - DO(STORESVAR0, "Pop TOS and store to string variable 0.", 1) \ - DO(STORESVAR1, "Pop TOS and store to string variable 1.", 1) \ - DO(STORESVAR2, "Pop TOS and store to string variable 2.", 1) \ - DO(STORESVAR3, "Pop TOS and store to string variable 3.", 1) \ - DO(LOADDVAR, "Load double from variable, whose 2-byte is id inlined to insn stream, push on TOS.", 3) \ - DO(LOADIVAR, "Load int from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3) \ - DO(LOADSVAR, "Load string from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3) \ - DO(STOREDVAR, "Pop TOS and store to double variable, whose 2-byte id is inlined to insn stream.", 3) \ - DO(STOREIVAR, "Pop TOS and store to int variable, whose 2-byte id is inlined to insn stream.", 3) \ - DO(STORESVAR, "Pop TOS and store to string variable, whose 2-byte id is inlined to insn stream.", 3) \ - DO(LOADCTXDVAR, "Load double from variable, whose 2-byte context and 2-byte id inlined to insn stream, push on TOS.", 5) \ - DO(LOADCTXIVAR, "Load int from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5) \ - DO(LOADCTXSVAR, "Load string from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5) \ - DO(STORECTXDVAR, "Pop TOS and store to double variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \ - DO(STORECTXIVAR, "Pop TOS and store to int variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \ - DO(STORECTXSVAR, "Pop TOS and store to string variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \ - DO(DCMP, "Compare 2 topmost doubles, pushing libc-stryle comparator value cmp(upper, lower) as integer.", 1) \ - DO(ICMP, "Compare 2 topmost ints, pushing libc-style comparator value cmp(upper, lower) as integer.", 1) \ - DO(JA, "Jump always, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPNE, "Compare two topmost integers and jump if upper != lower, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPE, "Compare two topmost integers and jump if upper == lower, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPG, "Compare two topmost integers and jump if upper > lower, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPGE, "Compare two topmost integers and jump if upper >= lower, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPL, "Compare two topmost integers and jump if upper < lower, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPLE, "Compare two topmost integers and jump if upper <= lower, next two bytes - signed offset of jump destination.", 3) \ - DO(DUMP, "Dump value on TOS, without removing it.", 1) \ - DO(STOP, "Stop execution.", 1) \ - DO(CALL, "Call function, next two bytes - unsigned function id.", 3) \ - DO(CALLNATIVE, "Call native function, next two bytes - id of the native function.", 3) \ - DO(RETURN, "Return to call location", 1) \ - DO(BREAK, "Breakpoint for the debugger.", 1) - -typedef enum { -#define ENUM_ELEM(b, d, l) BC_##b, - FOR_BYTECODES(ENUM_ELEM) -#undef ENUM_ELEM - BC_LAST -} Instruction; - -typedef enum { - VT_INVALID = 0, - VT_VOID, - VT_DOUBLE, - VT_INT, - VT_STRING -} VarType; - -// Element 0 is return type. -typedef pair SignatureElement; -typedef vector Signature; - -const uint16_t INVALID_ID = 0xffff; - -class Status { - bool _is_error; - string _msg; - uint32_t _position; - - explicit Status(const char* msg, uint32_t position, bool is_error) : - _is_error(is_error), _msg(msg), _position(position) {} - - public: - static Status* Error(const char* msg, uint32_t position = INVALID_POSITION) { - return new Status(msg, position, true); - } - - static Status* Warning(const char* msg, uint32_t position = INVALID_POSITION) { - return new Status(msg, position, false); - } - - static Status* Ok() { - return new Status("", INVALID_POSITION, false); - } - - bool isOk() const { - return !_is_error; - } - - bool isError() const { - return _is_error; - } - - const string& getError() const { - assert(isError()); - return _msg; - } - - const char* getErrorCstr() const { - assert(isError()); - return _msg.c_str(); - } - - const char* getMsg() const { - return _msg.c_str(); - } - - uint32_t getPosition() const { - return _position; - } - - static const uint32_t INVALID_POSITION = 0xffffffff; -}; - -class Var { - VarType _type; - string _name; - union { - double _doubleValue; - int64_t _intValue; - const char* _stringValue; - }; - - public: - Var(VarType type, const string& name); - - void setDoubleValue(double value) { - assert(_type == VT_DOUBLE); - _doubleValue = value; - } - - double getDoubleValue() const { - assert(_type == VT_DOUBLE); - return _doubleValue; - } - - void setIntValue(int64_t value) { - assert(_type == VT_INT); - _intValue = value; - } - - int64_t getIntValue() const { - assert(_type == VT_INT); - return _intValue; - } - - void setStringValue(const char* value) { - assert(_type == VT_STRING); - _stringValue = value; - } - - const char* getStringValue() const { - assert(_type == VT_STRING); - return _stringValue; - } - - const string& name() const { - return _name; - } - - VarType type() const { - return _type; - } - - void print(); -}; - -class Bytecode; -class Label { - Bytecode* _code; - uint32_t _bci; - vector _relocations; -public: - static const uint32_t INVALID_BCI = 0xffffffff; - - Label(Bytecode* code = 0, uint32_t bci = INVALID_BCI) : _code(code), _bci(bci) { - } - - ~Label() { - // Shall be like that, but we can hit this path - // if exception thrown before label bound. - // assert(_relocations.size() == 0); - } - - uint32_t bci() const { - assert(isBound()); - return _bci; - } - - int32_t offsetOf(uint32_t address) const { - return bci() - address; - } - - void bind(uint32_t address, Bytecode* code = 0); - - bool isBound() const { - return _bci != INVALID_BCI; - } - - void addRelocation(uint32_t bciOfRelocation); -}; - -class Bytecode { - protected: - vector _data; - public: - void put(uint32_t index, uint8_t b) { - if (index >= _data.size()) { - _data.resize(index+1); - } - _data[index] = b; - } - - void add(uint8_t b) { - _data.push_back(b); - } - - void addByte(uint8_t b) { - add(b); - } - - uint8_t get(uint32_t index) const { - return _data[index]; - } - - void set(uint32_t index, uint8_t v) { - _data[index] = v; - } - - uint8_t getByte(uint32_t index) const { - return get(index); - } - - Instruction getInsn(uint32_t index) const { - return (Instruction)get(index); - } - - void addInsn(Instruction insn) { - add((uint8_t)insn); - } - - uint32_t current() const { - return length(); - } - - void addBranch(Instruction insn, Label& target); - - void bind(Label& label) { - label.bind(current()); - } - - template T getTyped(uint32_t index) const { - union { - T val; - uint8_t bits[sizeof(T)]; - } u; - for (uint32_t i=0; i void addTyped(T d) { - union { - T val; - uint8_t bits[sizeof(T)]; - } u; - - u.val = d; - for (uint32_t i=0; i void setTyped(uint32_t index, T d) { - union { - T val; - uint8_t bits[sizeof(T)]; - } u; - - u.val = d; - for (uint32_t i=0; i(index); - } - - void addDouble(double d) { - addTyped(d); - } - - int16_t getInt16(uint32_t index) const { - return getTyped(index); - } - - void addInt16(int16_t value) { - addTyped(value); - } - - void setInt16(uint32_t index, int16_t value) { - setTyped(index, value); - } - - uint16_t getUInt16(uint32_t index) const { - return getTyped(index); - } - - void addUInt16(uint16_t value) { - addTyped(value); - } - - void setUInt16(uint32_t index, uint16_t value) { - setTyped(index, value); - } - - void addInt32(int32_t value) { - addTyped(value); - } - - int64_t getInt64(uint32_t index) const { - return getTyped(index); - } - - void addInt64(int64_t value) { - addTyped(value); - } - - uint32_t length() const { - return _data.size(); - } - - Label currentLabel() { - return Label(this, current()); - } - - void dump(ostream& out) const; -}; - -class AstFunction; -class TranslatedFunction { - uint16_t _id; - uint16_t _locals; - uint16_t _params; - uint16_t _scopeId; - const string _name; - Signature _signature; -public: - TranslatedFunction(AstFunction* function); - TranslatedFunction(const string& name, const Signature& signature); - virtual ~TranslatedFunction(); - - const string& name() const { return _name; } - VarType returnType() const { - return _signature[0].first; - } - VarType parameterType(uint32_t index) const { - return _signature[index + 1].first; - } - const string& parameterName(uint32_t index) const { - return _signature[index + 1].second; - } - uint16_t parametersNumber() const { return _params; } - const Signature& signature() const { return _signature; } - void setLocalsNumber(uint16_t locals) { - _locals = locals; - } - uint32_t localsNumber() const { return _locals; } - - void setScopeId(uint16_t scopeId) { - _scopeId = scopeId; - } - uint16_t scopeId() const { return _scopeId; } - - void assignId(uint16_t id) { - assert(_id == INVALID_ID); - _id = id; - } - uint16_t id() const { return _id; } - virtual void disassemble(ostream& out) const = 0; -}; - -class BytecodeFunction : public TranslatedFunction { - Bytecode _bytecode; - -public: - BytecodeFunction(AstFunction* function) : - TranslatedFunction(function) { - } - - Bytecode* bytecode() { - return &_bytecode; - } - - virtual void disassemble(ostream& out) const { - _bytecode.dump(out); - } - - virtual ~BytecodeFunction() {} -}; - -class FunctionFilter { - public: - virtual bool matches(TranslatedFunction* function) = 0; -}; - -class NativeFunctionDescriptor { - string _name; - Signature _signature; - const void* _code; - - public: - NativeFunctionDescriptor(const string& aName, - const Signature& aSignature, - const void* aCode) : - _name(aName), _signature(aSignature), _code(aCode) { - } - - const string& name() const { return _name; } - const Signature& signature() const { return _signature; } - const void* code() const { return _code; } -}; -class Code { - typedef map FunctionMap; - typedef map ConstantMap; - typedef map NativeMap; - - vector _functions; - vector _constants; - vector _natives; - FunctionMap _functionById; - ConstantMap _constantById; - NativeMap _nativeById; - static const string empty_string; -public: - Code(); - virtual ~Code(); - - uint16_t addFunction(TranslatedFunction* function); - TranslatedFunction* functionById(uint16_t index) const; - TranslatedFunction* functionByName(const string& name) const; - - uint16_t makeStringConstant(const string& str); - uint16_t makeNativeFunction(const string& name, - const Signature& signature, - const void* code); - const string& constantById(uint16_t id) const; - const void* nativeById(uint16_t id, - const Signature** signature, - const string** name) const; - - /** - * Execute this code with passed parameters, and update vars - * in array with new values from topmost scope, if code says so. - */ - virtual Status* execute(vector& vars) = 0; - - /** - * Disassemble all functions, or only matching filter, and dump disssembled - * output to the stream. - */ - virtual void disassemble(ostream& out = cout, FunctionFilter* filter = 0); - - class FunctionIterator { - Code* _code; - vector::iterator _it; - public: - FunctionIterator(Code* code) : _code(code) { - _it = _code->_functions.begin(); - } - - bool hasNext() { return _it != _code->_functions.end(); } - - TranslatedFunction* next() { - if (!hasNext()) { - return 0; - } - return *_it++; - } - }; - class NativeFunctionIterator { - Code* _code; - vector::iterator _it; - public: - NativeFunctionIterator(Code* code) : _code(code) { - _it = _code->_natives.begin(); - } - - bool hasNext() { return _it != _code->_natives.end(); } - - NativeFunctionDescriptor& next() { - if (!hasNext()) { - return *_it; - } - return *_it++; - } - }; - class ConstantIterator { - Code* _code; - vector::iterator _it; - public: - ConstantIterator(Code* code) : _code(code) { - _it = _code->_constants.begin() + 1; - } - - bool hasNext() { return _it != _code->_constants.end(); } - - const string& next() { - if (!hasNext()) { - assert(false); - return Code::empty_string; - } - return *_it++; - } - }; -}; - -class Translator { - public: - static Translator* create(const string& impl = ""); - - virtual ~Translator() {} - virtual Status* translate(const string& program, Code* *code) = 0; -}; - -class InterpreterCodeImpl; -class MachCodeImpl; -class BytecodeTranslatorImpl : public Translator { - Status* translateBytecode(const string& program, - InterpreterCodeImpl* *code); - - public: - BytecodeTranslatorImpl() { - } - - virtual ~BytecodeTranslatorImpl() { - } - - virtual Status* translate(const string& program, Code* *code); -}; - -class MachCodeTranslatorImpl : public Translator { - Status* translateMachCode(const string& program, - MachCodeImpl* *code); - - public: - MachCodeTranslatorImpl(); - virtual ~MachCodeTranslatorImpl(); - - virtual Status* translate(const string& program, Code* *code); -}; - -class ErrorInfoHolder { - protected: - char _msgBuffer[512]; - uint32_t _position; - ErrorInfoHolder() : _position(0) { - _msgBuffer[0] = '\0'; - } - public: - const char* getMessage() const { return _msgBuffer; } - uint32_t getPosition() const { return _position; } - void error(uint32_t position, const char* format, ...); - void verror(uint32_t position, const char* format, va_list args); -}; - -// Utility functions. -char* loadFile(const char* file); -void positionToLineOffset(const string& text, - uint32_t position, uint32_t& line, uint32_t& offset); -const char* typeToName(VarType type); -VarType nameToType(const string& typeName); -const char* bytecodeName(Instruction insn, size_t* length = 0); - -} -#endif // _MATHVM_H diff --git a/include/visitors.h b/include/visitors.h deleted file mode 100644 index f8356836..00000000 --- a/include/visitors.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _MATHVM_VISITORS_H -#define _MATHVM_VISITORS_H - -#include "mathvm.h" -#include "ast.h" - -namespace mathvm { - -class AstBaseVisitor : public AstVisitor { - public: - AstBaseVisitor() { - } - virtual ~AstBaseVisitor() { - } - -#define VISITOR_FUNCTION(type, name) \ - virtual void visit##type(type* node) { node->visitChildren(this); } - - FOR_NODES(VISITOR_FUNCTION) -#undef VISITOR_FUNCTION -}; - -class DeleteVisitor : public AstVisitor { -public: - DeleteVisitor() {} - - void performDelete(AstNode* root) { - if (root) { - root->visit(this); - } - } - -#define VISITOR_FUNCTION(type, name) \ - virtual void visit##type(type* node) { \ - assert(!node->isFunctionNode()); \ - node->visitChildren(this); \ - delete node; \ - } - FOR_NODES(VISITOR_FUNCTION) -#undef VISITOR_FUNCTION -}; - -class AstDumper : public AstVisitor { -public: - AstDumper() {} - - void dump(AstNode* root); - -#define VISITOR_FUNCTION(type, name) \ - virtual void visit##type(type* node); - - FOR_NODES(VISITOR_FUNCTION) -#undef VISITOR_FUNCTION -}; - -} - -#endif // _MATHVM_VISITORS_H diff --git a/libs/asmjit/arm.h b/libs/asmjit/arm.h deleted file mode 100644 index 0a916d9c..00000000 --- a/libs/asmjit/arm.h +++ /dev/null @@ -1,21 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_ARM_H -#define _ASMJIT_ARM_H - -// [Dependencies] -#include "./base.h" - -#include "./arm/armassembler.h" -#include "./arm/armbuilder.h" -#include "./arm/armcompiler.h" -#include "./arm/arminst.h" -#include "./arm/armoperand.h" - -// [Guard] -#endif // _ASMJIT_ARM_H diff --git a/libs/asmjit/asmjit.h b/libs/asmjit/asmjit.h deleted file mode 100644 index ead90f0c..00000000 --- a/libs/asmjit/asmjit.h +++ /dev/null @@ -1,47 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_ASMJIT_H -#define _ASMJIT_ASMJIT_H - -// ============================================================================ -// [asmjit_mainpage] -// ============================================================================ - -//! \mainpage -//! -//! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++. -//! -//! Introduction provided by the project page at https://github.com/asmjit/asmjit. - -//! \defgroup asmjit_base AsmJit Base API (architecture independent) -//! -//! \brief Backend Neutral API. - -//! \defgroup asmjit_x86 AsmJit X86/X64 API -//! -//! \brief X86/X64 Backend API. - -//! \defgroup asmjit_arm AsmJit ARM32/ARM64 API -//! -//! \brief ARM32/ARM64 Backend API. - -// [Dependencies] -#include "./base.h" - -// [X86/X64] -#if defined(ASMJIT_BUILD_X86) -#include "./x86.h" -#endif // ASMJIT_BUILD_X86 - -// [ARM32/ARM64] -#if defined(ASMJIT_BUILD_ARM) -#include "./arm.h" -#endif // ASMJIT_BUILD_ARM - -// [Guard] -#endif // _ASMJIT_ASMJIT_H diff --git a/libs/asmjit/asmjit_apibegin.h b/libs/asmjit/asmjit_apibegin.h deleted file mode 100644 index 58d16dba..00000000 --- a/libs/asmjit/asmjit_apibegin.h +++ /dev/null @@ -1,117 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Dependencies] -#if !defined(_ASMJIT_BUILD_H) -# include "./build.h" -#endif // !_ASMJIT_BUILD_H - -// [Guard] -#if !defined(ASMJIT_API_SCOPE) -# define ASMJIT_API_SCOPE -#else -# error "[asmjit] api-scope is already active, previous scope not closed by asmjit_apiend.h?" -#endif // ASMJIT_API_SCOPE - -// ============================================================================ -// [C++ Support] -// ============================================================================ - -// [NoExcept] -#if !ASMJIT_CC_HAS_NOEXCEPT && !defined(noexcept) -# define noexcept ASMJIT_NOEXCEPT -# define ASMJIT_UNDEF_NOEXCEPT -#endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept - -// [NullPtr] -#if !ASMJIT_CC_HAS_NULLPTR && !defined(nullptr) -# define nullptr NULL -# define ASMJIT_UNDEF_NULLPTR -#endif // !ASMJIT_CC_HAS_NULLPTR && !nullptr - -// [Override] -#if !ASMJIT_CC_HAS_OVERRIDE && !defined(override) -# define override -# define ASMJIT_UNDEF_OVERRIDE -#endif // !ASMJIT_CC_HAS_OVERRIDE && !override - -// ============================================================================ -// [Compiler Support] -// ============================================================================ - -// [Clang] -#if ASMJIT_CC_CLANG -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wc++11-extensions" -# pragma clang diagnostic ignored "-Wconstant-logical-operand" -# pragma clang diagnostic ignored "-Wunnamed-type-template-args" -#endif // ASMJIT_CC_CLANG - -// [GCC] -#if ASMJIT_CC_GCC -# pragma GCC diagnostic push -#endif // ASMJIT_CC_GCC - -// [MSC] -#if ASMJIT_CC_MSC -# pragma warning(push) -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4201) // nameless struct/union -# pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible loss of data -# pragma warning(disable: 4251) // struct needs to have dll-interface to be used by clients of struct ... -# pragma warning(disable: 4275) // non dll-interface struct ... used as base for dll-interface struct -# pragma warning(disable: 4355) // this used in base member initializer list -# pragma warning(disable: 4480) // specifying underlying type for enum -# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' -# if _MSC_VER < 1900 -# if !defined(vsnprintf) -# define ASMJIT_UNDEF_VSNPRINTF -# define vsnprintf _vsnprintf -# endif // !vsnprintf -# if !defined(snprintf) -# define ASMJIT_UNDEF_SNPRINTF -# define snprintf _snprintf -# endif // !snprintf -# endif -#endif // ASMJIT_CC_MSC - -// ============================================================================ -// [Custom Macros] -// ============================================================================ - -// [ASMJIT_NON...] -#if ASMJIT_CC_HAS_DELETE_FUNCTION -#define ASMJIT_NONCONSTRUCTIBLE(...) \ -private: \ - __VA_ARGS__() = delete; \ - __VA_ARGS__(const __VA_ARGS__& other) = delete; \ - __VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \ -public: -#define ASMJIT_NONCOPYABLE(...) \ -private: \ - __VA_ARGS__(const __VA_ARGS__& other) = delete; \ - __VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \ -public: -#else -#define ASMJIT_NONCONSTRUCTIBLE(...) \ -private: \ - inline __VA_ARGS__(); \ - inline __VA_ARGS__(const __VA_ARGS__& other); \ - inline __VA_ARGS__& operator=(const __VA_ARGS__& other); \ -public: -#define ASMJIT_NONCOPYABLE(...) \ -private: \ - inline __VA_ARGS__(const __VA_ARGS__& other); \ - inline __VA_ARGS__& operator=(const __VA_ARGS__& other); \ -public: -#endif // ASMJIT_CC_HAS_DELETE_FUNCTION - -// [ASMJIT_ENUM] -#if defined(_MSC_VER) && _MSC_VER >= 1400 -# define ASMJIT_ENUM(NAME) enum NAME : uint32_t -#else -# define ASMJIT_ENUM(NAME) enum NAME -#endif diff --git a/libs/asmjit/asmjit_apiend.h b/libs/asmjit/asmjit_apiend.h deleted file mode 100644 index a51630b5..00000000 --- a/libs/asmjit/asmjit_apiend.h +++ /dev/null @@ -1,74 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#if defined(ASMJIT_API_SCOPE) -# undef ASMJIT_API_SCOPE -#else -# error "[asmjit] api-scope not active, forgot to include asmjit_apibegin.h?" -#endif // ASMJIT_API_SCOPE - -// ============================================================================ -// [C++ Support] -// ============================================================================ - -// [NoExcept] -#if defined(ASMJIT_UNDEF_NOEXCEPT) -# undef noexcept -# undef ASMJIT_UNDEF_NOEXCEPT -#endif // ASMJIT_UNDEF_NOEXCEPT - -// [NullPtr] -#if defined(ASMJIT_UNDEF_NULLPTR) -# undef nullptr -# undef ASMJIT_UNDEF_NULLPTR -#endif // ASMJIT_UNDEF_NULLPTR - -// [Override] -#if defined(ASMJIT_UNDEF_OVERRIDE) -# undef override -# undef ASMJIT_UNDEF_OVERRIDE -#endif // ASMJIT_UNDEF_OVERRIDE - -// ============================================================================ -// [Compiler Support] -// ============================================================================ - -// [Clang] -#if ASMJIT_CC_CLANG -# pragma clang diagnostic pop -#endif // ASMJIT_CC_CLANG - -// [GCC] -#if ASMJIT_CC_GCC -# pragma GCC diagnostic pop -#endif // ASMJIT_CC_GCC - -// [MSC] -#if ASMJIT_CC_MSC -# pragma warning(pop) -# if _MSC_VER < 1900 -# if defined(ASMJIT_UNDEF_VSNPRINTF) -# undef vsnprintf -# undef ASMJIT_UNDEF_VSNPRINTF -# endif // ASMJIT_UNDEF_VSNPRINTF -# if defined(ASMJIT_UNDEF_SNPRINTF) -# undef snprintf -# undef ASMJIT_UNDEF_SNPRINTF -# endif // ASMJIT_UNDEF_SNPRINTF -# endif -#endif // ASMJIT_CC_MSC - -// ============================================================================ -// [Custom Macros] -// ============================================================================ - -// [ASMJIT_NON...] -#undef ASMJIT_NONCONSTRUCTIBLE -#undef ASMJIT_NONCOPYABLE - -// [ASMJIT_ENUM] -#undef ASMJIT_ENUM diff --git a/libs/asmjit/asmjit_build.h b/libs/asmjit/asmjit_build.h deleted file mode 100644 index 77b151ac..00000000 --- a/libs/asmjit/asmjit_build.h +++ /dev/null @@ -1,949 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BUILD_H -#define _ASMJIT_BUILD_H - -// ============================================================================ -// [asmjit::Build - Configuration] -// ============================================================================ - -// AsmJit is by default compiled only for a host processor for the purpose of -// JIT code generation. Both Assembler and CodeCompiler emitters are compiled -// by default. Preprocessor macros can be used to change the default behavior. - -// External Config File -// -------------------- -// -// Define in case your configuration is generated in an external file to be -// included. - -#if defined(ASMJIT_CONFIG_FILE) -# include ASMJIT_CONFIG_FILE -#endif // ASMJIT_CONFIG_FILE - -// AsmJit Static Builds and Embedding -// ---------------------------------- -// -// These definitions can be used to enable static library build. Embed is used -// when AsmJit's source code is embedded directly in another project, implies -// static build as well. -// -// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_STATIC). -// #define ASMJIT_STATIC // Define to enable static-library build. - -// AsmJit Build Modes -// ------------------ -// -// These definitions control the build mode and tracing support. The build mode -// should be auto-detected at compile time, but it's possible to override it in -// case that the auto-detection fails. -// -// Tracing is a feature that is never compiled by default and it's only used to -// debug AsmJit itself. -// -// #define ASMJIT_DEBUG // Define to enable debug-mode. -// #define ASMJIT_RELEASE // Define to enable release-mode. - -// AsmJit Build Backends -// --------------------- -// -// These definitions control which backends to compile. If none of these is -// defined AsmJit will use host architecture by default (for JIT code generation). -// -// #define ASMJIT_BUILD_X86 // Define to enable X86 and X64 code-generation. -// #define ASMJIT_BUILD_ARM // Define to enable ARM32 and ARM64 code-generation. -// #define ASMJIT_BUILD_HOST // Define to enable host instruction set. - -// AsmJit Build Features -// --------------------- -// -// Flags can be defined to disable standard features. These are handy especially -// when building AsmJit statically and some features are not needed or unwanted -// (like CodeCompiler). -// -// AsmJit features are enabled by default. -// #define ASMJIT_DISABLE_COMPILER // Disable CodeCompiler (completely). -// #define ASMJIT_DISABLE_LOGGING // Disable logging and formatting (completely). -// #define ASMJIT_DISABLE_TEXT // Disable everything that contains text -// // representation (instructions, errors, ...). -// #define ASMJIT_DISABLE_VALIDATION // Disable Validation (completely). - -// Prevent compile-time errors caused by misconfiguration. -#if defined(ASMJIT_DISABLE_TEXT) && !defined(ASMJIT_DISABLE_LOGGING) -# error "[asmjit] ASMJIT_DISABLE_TEXT requires ASMJIT_DISABLE_LOGGING to be defined." -#endif // ASMJIT_DISABLE_TEXT && !ASMJIT_DISABLE_LOGGING - -// Detect ASMJIT_DEBUG and ASMJIT_RELEASE if not forced from outside. -#if !defined(ASMJIT_DEBUG) && !defined(ASMJIT_RELEASE) -# if !defined(NDEBUG) -# define ASMJIT_DEBUG -# else -# define ASMJIT_RELEASE -# endif -#endif - -// ASMJIT_EMBED implies ASMJIT_STATIC. -#if defined(ASMJIT_EMBED) && !defined(ASMJIT_STATIC) -# define ASMJIT_STATIC -#endif - -// ============================================================================ -// [asmjit::Build - VERSION] -// ============================================================================ - -// [@VERSION{@] -#define ASMJIT_VERSION_MAJOR 1 -#define ASMJIT_VERSION_MINOR 0 -#define ASMJIT_VERSION_PATCH 0 -#define ASMJIT_VERSION_STRING "1.0.0" -// [@VERSION}@] - -// ============================================================================ -// [asmjit::Build - WIN32] -// ============================================================================ - -// [@WIN32_CRT_NO_DEPRECATE{@] -#if defined(_MSC_VER) && defined(ASMJIT_EXPORTS) -# if !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -# endif -# if !defined(_CRT_SECURE_NO_WARNINGS) -# define _CRT_SECURE_NO_WARNINGS -# endif -#endif -// [@WIN32_CRT_NO_DEPRECATE}@] - -// [@WIN32_LEAN_AND_MEAN{@] -#if (defined(_WIN32) || defined(_WINDOWS)) && !defined(_WINDOWS_) -# if !defined(WIN32_LEAN_AND_MEAN) -# define WIN32_LEAN_AND_MEAN -# define ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN -# endif -# if !defined(NOMINMAX) -# define NOMINMAX -# define ASMJIT_UNDEF_NOMINMAX -# endif -# include -# if defined(ASMJIT_UNDEF_NOMINMAX) -# undef NOMINMAX -# undef ASMJIT_UNDEF_NOMINMAX -# endif -# if defined(ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN) -# undef WIN32_LEAN_AND_MEAN -# undef ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN -# endif -#endif -// [@WIN32_LEAN_AND_MEAN}@] - -// ============================================================================ -// [asmjit::Build - OS] -// ============================================================================ - -// [@OS{@] -#if defined(_WIN32) || defined(_WINDOWS) -#define ASMJIT_OS_WINDOWS (1) -#else -#define ASMJIT_OS_WINDOWS (0) -#endif - -#if defined(__APPLE__) -# include -# define ASMJIT_OS_MAC (TARGET_OS_MAC) -# define ASMJIT_OS_IOS (TARGET_OS_IPHONE) -#else -# define ASMJIT_OS_MAC (0) -# define ASMJIT_OS_IOS (0) -#endif - -#if defined(__ANDROID__) -# define ASMJIT_OS_ANDROID (1) -#else -# define ASMJIT_OS_ANDROID (0) -#endif - -#if defined(__linux__) || defined(__ANDROID__) -# define ASMJIT_OS_LINUX (1) -#else -# define ASMJIT_OS_LINUX (0) -#endif - -#if defined(__DragonFly__) -# define ASMJIT_OS_DRAGONFLYBSD (1) -#else -# define ASMJIT_OS_DRAGONFLYBSD (0) -#endif - -#if defined(__FreeBSD__) -# define ASMJIT_OS_FREEBSD (1) -#else -# define ASMJIT_OS_FREEBSD (0) -#endif - -#if defined(__NetBSD__) -# define ASMJIT_OS_NETBSD (1) -#else -# define ASMJIT_OS_NETBSD (0) -#endif - -#if defined(__OpenBSD__) -# define ASMJIT_OS_OPENBSD (1) -#else -# define ASMJIT_OS_OPENBSD (0) -#endif - -#if defined(__QNXNTO__) -# define ASMJIT_OS_QNX (1) -#else -# define ASMJIT_OS_QNX (0) -#endif - -#if defined(__sun) -# define ASMJIT_OS_SOLARIS (1) -#else -# define ASMJIT_OS_SOLARIS (0) -#endif - -#if defined(__CYGWIN__) -# define ASMJIT_OS_CYGWIN (1) -#else -# define ASMJIT_OS_CYGWIN (0) -#endif - -#define ASMJIT_OS_BSD ( \ - ASMJIT_OS_FREEBSD || \ - ASMJIT_OS_DRAGONFLYBSD || \ - ASMJIT_OS_NETBSD || \ - ASMJIT_OS_OPENBSD || \ - ASMJIT_OS_MAC) -#define ASMJIT_OS_POSIX (!ASMJIT_OS_WINDOWS) -// [@OS}@] - -// ============================================================================ -// [asmjit::Build - ARCH] -// ============================================================================ - -// [@ARCH{@] -// \def ASMJIT_ARCH_ARM32 -// True if the target architecture is a 32-bit ARM. -// -// \def ASMJIT_ARCH_ARM64 -// True if the target architecture is a 64-bit ARM. -// -// \def ASMJIT_ARCH_X86 -// True if the target architecture is a 32-bit X86/IA32 -// -// \def ASMJIT_ARCH_X64 -// True if the target architecture is a 64-bit X64/AMD64 -// -// \def ASMJIT_ARCH_LE -// True if the target architecture is little endian. -// -// \def ASMJIT_ARCH_BE -// True if the target architecture is big endian. -// -// \def ASMJIT_ARCH_64BIT -// True if the target architecture is 64-bit. - -#if (defined(_M_X64 ) || defined(__x86_64) || defined(__x86_64__) || \ - defined(_M_AMD64) || defined(__amd64 ) || defined(__amd64__ )) -# define ASMJIT_ARCH_X64 1 -#else -# define ASMJIT_ARCH_X64 0 -#endif - -#if (defined(_M_IX86 ) || defined(__X86__ ) || defined(__i386 ) || \ - defined(__IA32__) || defined(__I86__ ) || defined(__i386__) || \ - defined(__i486__) || defined(__i586__) || defined(__i686__)) -# define ASMJIT_ARCH_X86 (!ASMJIT_ARCH_X64) -#else -# define ASMJIT_ARCH_X86 0 -#endif - -#if defined(__aarch64__) -# define ASMJIT_ARCH_ARM64 1 -#else -# define ASMJIT_ARCH_ARM64 0 -#endif - -#if (defined(_M_ARM ) || defined(__arm ) || defined(__thumb__ ) || \ - defined(_M_ARMT ) || defined(__arm__ ) || defined(__thumb2__)) -# define ASMJIT_ARCH_ARM32 (!ASMJIT_ARCH_ARM64) -#else -# define ASMJIT_ARCH_ARM32 0 -#endif - -#define ASMJIT_ARCH_LE ( \ - ASMJIT_ARCH_X86 || \ - ASMJIT_ARCH_X64 || \ - ASMJIT_ARCH_ARM32 || \ - ASMJIT_ARCH_ARM64 ) -#define ASMJIT_ARCH_BE (!(ASMJIT_ARCH_LE)) -#define ASMJIT_ARCH_64BIT (ASMJIT_ARCH_X64 || ASMJIT_ARCH_ARM64) -// [@ARCH}@] - -// [@ARCH_UNALIGNED_RW{@] -// \def ASMJIT_ARCH_UNALIGNED_16 -// True if the target architecture allows unaligned 16-bit reads and writes. -// -// \def ASMJIT_ARCH_UNALIGNED_32 -// True if the target architecture allows unaligned 32-bit reads and writes. -// -// \def ASMJIT_ARCH_UNALIGNED_64 -// True if the target architecture allows unaligned 64-bit reads and writes. - -#define ASMJIT_ARCH_UNALIGNED_16 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) -#define ASMJIT_ARCH_UNALIGNED_32 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) -#define ASMJIT_ARCH_UNALIGNED_64 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) -// [@ARCH_UNALIGNED_RW}@] - -// ============================================================================ -// [asmjit::Build - CC] -// ============================================================================ - -// [@CC{@] -// \def ASMJIT_CC_CLANG -// Non-zero if the detected C++ compiler is CLANG (contains normalized CLANG version). -// -// \def ASMJIT_CC_CODEGEAR -// Non-zero if the detected C++ compiler is CODEGEAR or BORLAND (version not normalized). -// -// \def ASMJIT_CC_INTEL -// Non-zero if the detected C++ compiler is INTEL (version not normalized). -// -// \def ASMJIT_CC_GCC -// Non-zero if the detected C++ compiler is GCC (contains normalized GCC version). -// -// \def ASMJIT_CC_MSC -// Non-zero if the detected C++ compiler is MSC (contains normalized MSC version). -// -// \def ASMJIT_CC_MINGW -// Non-zero if the detected C++ compiler is MINGW32 (set to 32) or MINGW64 (set to 64). - -#define ASMJIT_CC_CLANG 0 -#define ASMJIT_CC_CODEGEAR 0 -#define ASMJIT_CC_GCC 0 -#define ASMJIT_CC_INTEL 0 -#define ASMJIT_CC_MSC 0 - -// Intel masquerades as GCC, so check for it first. -#if defined(__INTEL_COMPILER) -# undef ASMJIT_CC_INTEL -# define ASMJIT_CC_INTEL __INTEL_COMPILER -#elif defined(__CODEGEARC__) -# undef ASMJIT_CC_CODEGEAR -# define ASMJIT_CC_CODEGEAR (__CODEGEARC__) -#elif defined(__BORLANDC__) -# undef ASMJIT_CC_CODEGEAR -# define ASMJIT_CC_CODEGEAR (__BORLANDC__) -#elif defined(__clang__) && defined(__clang_minor__) -# undef ASMJIT_CC_CLANG -# define ASMJIT_CC_CLANG (__clang_major__ * 10000000 + __clang_minor__ * 100000 + __clang_patchlevel__) -#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -# undef ASMJIT_CC_GCC -# define ASMJIT_CC_GCC (__GNUC__ * 10000000 + __GNUC_MINOR__ * 100000 + __GNUC_PATCHLEVEL__) -#elif defined(_MSC_VER) && defined(_MSC_FULL_VER) -# undef ASMJIT_CC_MSC -# if _MSC_VER == _MSC_FULL_VER / 10000 -# define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 10000)) -# else -# define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 100000)) -# endif -#else -# error "[asmjit] Unable to detect the C/C++ compiler." -#endif - -#if ASMJIT_CC_INTEL && (defined(__GNUC__) || defined(__clang__)) -# define ASMJIT_CC_INTEL_COMPAT_MODE 1 -# else -# define ASMJIT_CC_INTEL_COMPAT_MODE 0 -#endif - -#define ASMJIT_CC_CODEGEAR_EQ(x, y) (ASMJIT_CC_CODEGEAR == (((x) << 8) + (y))) -#define ASMJIT_CC_CODEGEAR_GE(x, y) (ASMJIT_CC_CODEGEAR >= (((x) << 8) + (y))) - -#define ASMJIT_CC_CLANG_EQ(x, y, z) (ASMJIT_CC_CLANG == ((x) * 10000000 + (y) * 100000 + (z))) -#define ASMJIT_CC_CLANG_GE(x, y, z) (ASMJIT_CC_CLANG >= ((x) * 10000000 + (y) * 100000 + (z))) - -#define ASMJIT_CC_GCC_EQ(x, y, z) (ASMJIT_CC_GCC == ((x) * 10000000 + (y) * 100000 + (z))) -#define ASMJIT_CC_GCC_GE(x, y, z) (ASMJIT_CC_GCC >= ((x) * 10000000 + (y) * 100000 + (z))) - -#define ASMJIT_CC_INTEL_EQ(x, y) (ASMJIT_CC_INTEL == (((x) * 100) + (y))) -#define ASMJIT_CC_INTEL_GE(x, y) (ASMJIT_CC_INTEL >= (((x) * 100) + (y))) - -#define ASMJIT_CC_MSC_EQ(x, y, z) (ASMJIT_CC_MSC == ((x) * 10000000 + (y) * 100000 + (z))) -#define ASMJIT_CC_MSC_GE(x, y, z) (ASMJIT_CC_MSC >= ((x) * 10000000 + (y) * 100000 + (z))) - -#if defined(__MINGW64__) -# define ASMJIT_CC_MINGW 64 -#elif defined(__MINGW32__) -# define ASMJIT_CC_MINGW 32 -#else -# define ASMJIT_CC_MINGW 0 -#endif - -#if defined(__cplusplus) -# if __cplusplus >= 201103L -# define ASMJIT_CC_CXX_VERSION __cplusplus -# elif defined(__GXX_EXPERIMENTAL_CXX0X__) || ASMJIT_CC_MSC_GE(18, 0, 0) || ASMJIT_CC_INTEL_GE(14, 0) -# define ASMJIT_CC_CXX_VERSION 201103L -# else -# define ASMJIT_CC_CXX_VERSION 199711L -# endif -#endif - -#if !defined(ASMJIT_CC_CXX_VERSION) -# define ASMJIT_CC_CXX_VERSION 0 -#endif -// [@CC}@] - -// [@CC_FEATURES{@] -#if ASMJIT_CC_CLANG -# define ASMJIT_CC_HAS_ATTRIBUTE (1) -# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (__has_attribute(__aligned__)) -# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(__always_inline__)) -# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (__has_attribute(__noinline__)) -# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (__has_attribute(__noreturn__)) -# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (__has_attribute(__optimize__)) -# define ASMJIT_CC_HAS_BUILTIN_ASSUME (__has_builtin(__builtin_assume)) -# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (__has_builtin(__builtin_assume_aligned)) -# define ASMJIT_CC_HAS_BUILTIN_EXPECT (__has_builtin(__builtin_expect)) -# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (__has_builtin(__builtin_unreachable)) -# define ASMJIT_CC_HAS_ALIGNAS (__has_extension(__cxx_alignas__)) -# define ASMJIT_CC_HAS_ALIGNOF (__has_extension(__cxx_alignof__)) -# define ASMJIT_CC_HAS_CONSTEXPR (__has_extension(__cxx_constexpr__)) -# define ASMJIT_CC_HAS_DECLTYPE (__has_extension(__cxx_decltype__)) -# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (__has_extension(__cxx_defaulted_functions__)) -# define ASMJIT_CC_HAS_DELETE_FUNCTION (__has_extension(__cxx_deleted_functions__)) -# define ASMJIT_CC_HAS_FINAL (__has_extension(__cxx_override_control__)) -# define ASMJIT_CC_HAS_INITIALIZER_LIST (__has_extension(__cxx_generalized_initializers__)) -# define ASMJIT_CC_HAS_LAMBDA (__has_extension(__cxx_lambdas__)) -# define ASMJIT_CC_HAS_NATIVE_CHAR (1) -# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1) -# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (__has_extension(__cxx_unicode_literals__)) -# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (__has_extension(__cxx_unicode_literals__)) -# define ASMJIT_CC_HAS_NOEXCEPT (__has_extension(__cxx_noexcept__)) -# define ASMJIT_CC_HAS_NULLPTR (__has_extension(__cxx_nullptr__)) -# define ASMJIT_CC_HAS_OVERRIDE (__has_extension(__cxx_override_control__)) -# define ASMJIT_CC_HAS_RVALUE (__has_extension(__cxx_rvalue_references__)) -# define ASMJIT_CC_HAS_STATIC_ASSERT (__has_extension(__cxx_static_assert__)) -# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (__has_extension(__cxx_variadic_templates__)) -#endif - -#if ASMJIT_CC_CODEGEAR -# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_CODEGEAR >= 0x0610) -# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0) -# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (0) -# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (ASMJIT_CC_CODEGEAR >= 0x0610) -# define ASMJIT_CC_HAS_ALIGNAS (0) -# define ASMJIT_CC_HAS_ALIGNOF (0) -# define ASMJIT_CC_HAS_CONSTEXPR (0) -# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_CODEGEAR >= 0x0610) -# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (0) -# define ASMJIT_CC_HAS_DELETE_FUNCTION (0) -# define ASMJIT_CC_HAS_FINAL (0) -# define ASMJIT_CC_HAS_INITIALIZER_LIST (0) -# define ASMJIT_CC_HAS_LAMBDA (0) -# define ASMJIT_CC_HAS_NATIVE_CHAR (1) -# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1) -# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (0) -# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (0) -# define ASMJIT_CC_HAS_NOEXCEPT (0) -# define ASMJIT_CC_HAS_NULLPTR (0) -# define ASMJIT_CC_HAS_OVERRIDE (0) -# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_CODEGEAR >= 0x0610) -# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_CODEGEAR >= 0x0610) -# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (0) -#endif - -#if ASMJIT_CC_GCC -# define ASMJIT_CC_HAS_ATTRIBUTE (1) -# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_GCC_GE(2, 7, 0)) -# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_GCC_GE(4, 4, 0) && !ASMJIT_CC_MINGW) -# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_GCC_GE(3, 4, 0) && !ASMJIT_CC_MINGW) -# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_GCC_GE(2, 5, 0)) -# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (ASMJIT_CC_GCC_GE(4, 4, 0)) -# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0) -# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (ASMJIT_CC_GCC_GE(4, 7, 0)) -# define ASMJIT_CC_HAS_BUILTIN_EXPECT (1) -# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_NATIVE_CHAR (1) -# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1) -# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L) -#endif - -#if ASMJIT_CC_INTEL -# define ASMJIT_CC_HAS_ATTRIBUTE (ASMJIT_CC_INTEL_COMPAT_MODE) -# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_INTEL_COMPAT_MODE) -# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_INTEL_COMPAT_MODE) -# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_INTEL_COMPAT_MODE) -# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_INTEL_COMPAT_MODE) -# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (ASMJIT_CC_INTEL_COMPAT_MODE) -# define ASMJIT_CC_HAS_BUILTIN_EXPECT (ASMJIT_CC_INTEL_COMPAT_MODE) -# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_INTEL_COMPAT_MODE == 0) -# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (ASMJIT_CC_INTEL_COMPAT_MODE == 0) -# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (ASMJIT_CC_INTEL_COMPAT_MODE == 0) -# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (ASMJIT_CC_INTEL_COMPAT_MODE == 0) -# define ASMJIT_CC_HAS_ASSUME (1) -# define ASMJIT_CC_HAS_ASSUME_ALIGNED (1) -# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_INTEL >= 1500) -# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_INTEL >= 1500) -# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_INTEL >= 1400) -# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_INTEL >= 1200) -# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_INTEL >= 1200) -# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_INTEL >= 1200) -# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_INTEL >= 1400) -# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_INTEL >= 1400) -# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_INTEL >= 1200) -# define ASMJIT_CC_HAS_NATIVE_CHAR (1) -# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1) -# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_INTEL >= 1400 || (ASMJIT_CC_INTEL_COMPAT_MODE > 0 && ASMJIT_CC_INTEL >= 1206)) -# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_INTEL >= 1400 || (ASMJIT_CC_INTEL_COMPAT_MODE > 0 && ASMJIT_CC_INTEL >= 1206)) -# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_INTEL >= 1400) -# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_INTEL >= 1206) -# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_INTEL >= 1400) -# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_INTEL >= 1110) -# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_INTEL >= 1110) -# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_INTEL >= 1206) -#endif - -#if ASMJIT_CC_MSC -# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (1) -# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (1) -# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (1) -# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (1) -# define ASMJIT_CC_HAS_ASSUME (1) -# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0) -# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_MSC_GE(19, 0, 0)) -# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_MSC_GE(19, 0, 0)) -# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_MSC_GE(19, 0, 0)) -# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_MSC_GE(16, 0, 0)) -# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_MSC_GE(18, 0, 0)) -# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_MSC_GE(18, 0, 0)) -# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_MSC_GE(14, 0, 0)) -# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_MSC_GE(18, 0, 0)) -# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_MSC_GE(16, 0, 0)) -# define ASMJIT_CC_HAS_NATIVE_CHAR (1) -# if defined(_NATIVE_WCHAR_T_DEFINED) -# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1) -# else -# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (0) -# endif -# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_MSC_GE(19, 0, 0)) -# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_MSC_GE(19, 0, 0)) -# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_MSC_GE(19, 0, 0)) -# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_MSC_GE(16, 0, 0)) -# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_MSC_GE(14, 0, 0)) -# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_MSC_GE(16, 0, 0)) -# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_MSC_GE(16, 0, 0)) -# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_MSC_GE(18, 0, 0)) -#endif - -// Fixup some vendor specific keywords. -#if !defined(ASMJIT_CC_HAS_ASSUME) -# define ASMJIT_CC_HAS_ASSUME (0) -#endif -#if !defined(ASMJIT_CC_HAS_ASSUME_ALIGNED) -# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0) -#endif - -// Fixup compilers that don't support '__attribute__'. -#if !defined(ASMJIT_CC_HAS_ATTRIBUTE) -# define ASMJIT_CC_HAS_ATTRIBUTE (0) -#endif -#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED) -# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (0) -#endif -#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE) -# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (0) -#endif -#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE) -# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (0) -#endif -#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_NORETURN) -# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (0) -#endif -#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE) -# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (0) -#endif - -// Fixup compilers that don't support '__builtin?'. -#if !defined(ASMJIT_CC_HAS_BUILTIN_ASSUME) -# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0) -#endif -#if !defined(ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED) -# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (0) -#endif -#if !defined(ASMJIT_CC_HAS_BUILTIN_EXPECT) -# define ASMJIT_CC_HAS_BUILTIN_EXPECT (0) -#endif -#if !defined(ASMJIT_CC_HAS_BUILTIN_UNREACHABLE) -# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (0) -#endif - -// Fixup compilers that don't support 'declspec'. -#if !defined(ASMJIT_CC_HAS_DECLSPEC_ALIGN) -# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (0) -#endif -#if !defined(ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE) -# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0) -#endif -#if !defined(ASMJIT_CC_HAS_DECLSPEC_NOINLINE) -# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (0) -#endif -#if !defined(ASMJIT_CC_HAS_DECLSPEC_NORETURN) -# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (0) -#endif -// [@CC_FEATURES}@] - -// [@CC_API{@] -// \def ASMJIT_API -// The decorated function is asmjit API and should be exported. -#if !defined(ASMJIT_API) -# if defined(ASMJIT_STATIC) -# define ASMJIT_API -# elif ASMJIT_OS_WINDOWS -# if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_CC_MINGW -# if defined(ASMJIT_EXPORTS) -# define ASMJIT_API __attribute__((__dllexport__)) -# else -# define ASMJIT_API __attribute__((__dllimport__)) -# endif -# else -# if defined(ASMJIT_EXPORTS) -# define ASMJIT_API __declspec(dllexport) -# else -# define ASMJIT_API __declspec(dllimport) -# endif -# endif -# else -# if ASMJIT_CC_CLANG || ASMJIT_CC_GCC_GE(4, 0, 0) || ASMJIT_CC_INTEL -# define ASMJIT_API __attribute__((__visibility__("default"))) -# endif -# endif -#endif -// [@CC_API}@] - -// [@CC_VARAPI{@] -// \def ASMJIT_VARAPI -// The decorated variable is part of asmjit API and is exported. -#if !defined(ASMJIT_VARAPI) -# define ASMJIT_VARAPI extern ASMJIT_API -#endif -// [@CC_VARAPI}@] - -// [@CC_VIRTAPI{@] -// \def ASMJIT_VIRTAPI -// The decorated class has a virtual table and is part of asmjit API. -// -// This is basically a workaround. When using MSVC and marking class as DLL -// export everything gets exported, which is unwanted in most projects. MSVC -// automatically exports typeinfo and vtable if at least one symbol of the -// class is exported. However, GCC has some strange behavior that even if -// one or more symbol is exported it doesn't export typeinfo unless the -// class itself is decorated with "visibility(default)" (i.e. asmjit_API). -#if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_OS_WINDOWS -# define ASMJIT_VIRTAPI ASMJIT_API -#else -# define ASMJIT_VIRTAPI -#endif -// [@CC_VIRTAPI}@] - -// [@CC_INLINE{@] -// \def ASMJIT_INLINE -// Always inline the decorated function. -#if ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE -# define ASMJIT_INLINE inline __attribute__((__always_inline__)) -#elif ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE -# define ASMJIT_INLINE __forceinline -#else -# define ASMJIT_INLINE inline -#endif -// [@CC_INLINE}@] - -// [@CC_NOINLINE{@] -// \def ASMJIT_NOINLINE -// Never inline the decorated function. -#if ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE -# define ASMJIT_NOINLINE __attribute__((__noinline__)) -#elif ASMJIT_CC_HAS_DECLSPEC_NOINLINE -# define ASMJIT_NOINLINE __declspec(noinline) -#else -# define ASMJIT_NOINLINE -#endif -// [@CC_NOINLINE}@] - -// [@CC_NORETURN{@] -// \def ASMJIT_NORETURN -// The decorated function never returns (exit, assertion failure, etc...). -#if ASMJIT_CC_HAS_ATTRIBUTE_NORETURN -# define ASMJIT_NORETURN __attribute__((__noreturn__)) -#elif ASMJIT_CC_HAS_DECLSPEC_NORETURN -# define ASMJIT_NORETURN __declspec(noreturn) -#else -# define ASMJIT_NORETURN -#endif -// [@CC_NORETURN}@] - -// [@CC_CDECL{@] -// \def ASMJIT_CDECL -// Standard C function calling convention decorator (__cdecl). -#if ASMJIT_ARCH_X86 -# if ASMJIT_CC_HAS_ATTRIBUTE -# define ASMJIT_CDECL __attribute__((__cdecl__)) -# else -# define ASMJIT_CDECL __cdecl -# endif -#else -# define ASMJIT_CDECL -#endif -// [@CC_CDECL}@] - -// [@CC_STDCALL{@] -// \def ASMJIT_STDCALL -// StdCall function calling convention decorator (__stdcall). -#if ASMJIT_ARCH_X86 -# if ASMJIT_CC_HAS_ATTRIBUTE -# define ASMJIT_STDCALL __attribute__((__stdcall__)) -# else -# define ASMJIT_STDCALL __stdcall -# endif -#else -# define ASMJIT_STDCALL -#endif -// [@CC_STDCALL}@] - -// [@CC_FASTCALL{@] -// \def ASMJIT_FASTCALL -// FastCall function calling convention decorator (__fastcall). -#if ASMJIT_ARCH_X86 -# if ASMJIT_CC_HAS_ATTRIBUTE -# define ASMJIT_FASTCALL __attribute__((__fastcall__)) -# else -# define ASMJIT_FASTCALL __fastcall -# endif -#else -# define ASMJIT_FASTCALL -#endif -// [@CC_FASTCALL}@] - -// [@CC_REGPARM{@] -// \def ASMJIT_REGPARM(n) -// A custom calling convention which passes n arguments in registers. -#if ASMJIT_ARCH_X86 && ASMJIT_CC_HAS_ATTRIBUTE -# define ASMJIT_REGPARM(n) __attribute__((__regparm__(n))) -#else -# define ASMJIT_REGPARM(n) -#endif -// [@CC_REGPARM}@] - -// [@CC_NOEXCEPT{@] -// \def ASMJIT_NOEXCEPT -// The decorated function never throws an exception (noexcept). -#if ASMJIT_CC_HAS_NOEXCEPT -# define ASMJIT_NOEXCEPT noexcept -#else -# define ASMJIT_NOEXCEPT -#endif -// [@CC_NOEXCEPT}@] - -// [@CC_NOP{@] -// \def ASMJIT_NOP -// No operation. -#if !defined(ASMJIT_NOP) -# define ASMJIT_NOP ((void)0) -#endif -// [@CC_NOP}@] - -// [@CC_ASSUME{@] -// \def ASMJIT_ASSUME(exp) -// Assume that the expression exp is always true. -#if ASMJIT_CC_HAS_ASSUME -# define ASMJIT_ASSUME(exp) __assume(exp) -#elif ASMJIT_CC_HAS_BUILTIN_ASSUME -# define ASMJIT_ASSUME(exp) __builtin_assume(exp) -#elif ASMJIT_CC_HAS_BUILTIN_UNREACHABLE -# define ASMJIT_ASSUME(exp) do { if (!(exp)) __builtin_unreachable(); } while (0) -#else -# define ASMJIT_ASSUME(exp) ((void)0) -#endif -// [@CC_ASSUME}@] - -// [@CC_ASSUME_ALIGNED{@] -// \def ASMJIT_ASSUME_ALIGNED(p, alignment) -// Assume that the pointer 'p' is aligned to at least 'alignment' bytes. -#if ASMJIT_CC_HAS_ASSUME_ALIGNED -# define ASMJIT_ASSUME_ALIGNED(p, alignment) __assume_aligned(p, alignment) -#elif ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED -# define ASMJIT_ASSUME_ALIGNED(p, alignment) p = __builtin_assume_aligned(p, alignment) -#else -# define ASMJIT_ASSUME_ALIGNED(p, alignment) ((void)0) -#endif -// [@CC_ASSUME_ALIGNED}@] - -// [@CC_EXPECT{@] -// \def ASMJIT_LIKELY(exp) -// Expression exp is likely to be true. -// -// \def ASMJIT_UNLIKELY(exp) -// Expression exp is likely to be false. -#if ASMJIT_CC_HAS_BUILTIN_EXPECT -# define ASMJIT_LIKELY(exp) __builtin_expect(!!(exp), 1) -# define ASMJIT_UNLIKELY(exp) __builtin_expect(!!(exp), 0) -#else -# define ASMJIT_LIKELY(exp) (exp) -# define ASMJIT_UNLIKELY(exp) (exp) -#endif -// [@CC_EXPECT}@] - -// [@CC_FALLTHROUGH{@] -// \def ASMJIT_FALLTHROUGH -// The code falls through annotation (switch / case). -#if ASMJIT_CC_CLANG && __cplusplus >= 201103L -# define ASMJIT_FALLTHROUGH [[clang::fallthrough]] -#else -# define ASMJIT_FALLTHROUGH (void)0 -#endif -// [@CC_FALLTHROUGH}@] - -// [@CC_UNUSED{@] -// \def ASMJIT_UNUSED(x) -// Mark a variable x as unused. -#define ASMJIT_UNUSED(x) (void)(x) -// [@CC_UNUSED}@] - -// [@CC_OFFSET_OF{@] -// \def ASMJIT_OFFSET_OF(x, y). -// Get the offset of a member y of a struct x at compile-time. -#define ASMJIT_OFFSET_OF(x, y) ((int)(intptr_t)((const char*)&((const x*)0x1)->y) - 1) -// [@CC_OFFSET_OF}@] - -// [@CC_ARRAY_SIZE{@] -// \def ASMJIT_ARRAY_SIZE(x) -// Get the array size of x at compile-time. -#define ASMJIT_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) -// [@CC_ARRAY_SIZE}@] - -// ============================================================================ -// [asmjit::Build - STDTYPES] -// ============================================================================ - -// [@STDTYPES{@] -#if defined(__MINGW32__) || defined(__MINGW64__) -# include -#endif -#if defined(_MSC_VER) && (_MSC_VER < 1600) -# include -# if !defined(ASMJIT_SUPPRESS_STD_TYPES) -# if (_MSC_VER < 1300) -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef signed __int64 int64_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned __int64 uint64_t; -# else -typedef __int8 int8_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -# endif -# endif -#else -# include -# include -#endif -// [@STDTYPES}@] - -// ============================================================================ -// [asmjit::Build - Dependencies] -// ============================================================================ - -#include -#include -#include -#include - -#include -#include - -#if ASMJIT_OS_POSIX -# include -#endif // ASMJIT_OS_POSIX - -// ============================================================================ -// [asmjit::Build - Additional] -// ============================================================================ - -// Build host architecture if no architecture is selected. -#if !defined(ASMJIT_BUILD_HOST) && \ - !defined(ASMJIT_BUILD_X86) && \ - !defined(ASMJIT_BUILD_ARM) -# define ASMJIT_BUILD_HOST -#endif - -// Detect host architecture if building only for host. -#if defined(ASMJIT_BUILD_HOST) -# if (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && !defined(ASMJIT_BUILD_X86) -# define ASMJIT_BUILD_X86 -# endif // ASMJIT_ARCH_X86 -#endif // ASMJIT_BUILD_HOST - -#if ASMJIT_CC_MSC -# define ASMJIT_UINT64_C(x) x##ui64 -#else -# define ASMJIT_UINT64_C(x) x##ull -#endif - -#if ASMJIT_ARCH_LE -# define ASMJIT_PACK32_4x8(A, B, C, D) ((A) + ((B) << 8) + ((C) << 16) + ((D) << 24)) -#else -# define ASMJIT_PACK32_4x8(A, B, C, D) ((D) + ((C) << 8) + ((B) << 16) + ((A) << 24)) -#endif - -// Internal macros that are only used when building AsmJit itself. -#if defined(ASMJIT_EXPORTS) -# if !defined(ASMJIT_DEBUG) && ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE -# define ASMJIT_FAVOR_SIZE __attribute__((__optimize__("Os"))) -# else -# define ASMJIT_FAVOR_SIZE -# endif -#endif // ASMJIT_EXPORTS - -// ============================================================================ -// [asmjit::Build - Test] -// ============================================================================ - -// Include a unit testing package if this is a `asmjit_test` build. -#if defined(ASMJIT_TEST) -# include "../../test/broken.h" -#endif // ASMJIT_TEST - -// [Guard] -#endif // _ASMJIT_BUILD_H diff --git a/libs/asmjit/base.h b/libs/asmjit/base.h deleted file mode 100644 index 70b7e82f..00000000 --- a/libs/asmjit/base.h +++ /dev/null @@ -1,34 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_H -#define _ASMJIT_BASE_H - -// [Dependencies] -#include "./base/arch.h" -#include "./base/assembler.h" -#include "./base/codebuilder.h" -#include "./base/codecompiler.h" -#include "./base/codeemitter.h" -#include "./base/codeholder.h" -#include "./base/constpool.h" -#include "./base/cpuinfo.h" -#include "./base/func.h" -#include "./base/globals.h" -#include "./base/inst.h" -#include "./base/logging.h" -#include "./base/operand.h" -#include "./base/osutils.h" -#include "./base/runtime.h" -#include "./base/simdtypes.h" -#include "./base/string.h" -#include "./base/utils.h" -#include "./base/vmem.h" -#include "./base/zone.h" - -// [Guard] -#endif // _ASMJIT_BASE_H diff --git a/libs/asmjit/base/arch.cpp b/libs/asmjit/base/arch.cpp deleted file mode 100644 index 2e849c67..00000000 --- a/libs/asmjit/base/arch.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/arch.h" - -#if defined(ASMJIT_BUILD_X86) -#include "../x86/x86operand.h" -#endif // ASMJIT_BUILD_X86 - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::ArchInfo] -// ============================================================================ - -static const uint32_t archInfoTable[] = { - // <-------------+---------------------+-----------------------+-------+ - // | Type | SubType | GPInfo| - // <-------------+---------------------+-----------------------+-------+ - ASMJIT_PACK32_4x8(ArchInfo::kTypeNone , ArchInfo::kSubTypeNone, 0, 0), - ASMJIT_PACK32_4x8(ArchInfo::kTypeX86 , ArchInfo::kSubTypeNone, 4, 8), - ASMJIT_PACK32_4x8(ArchInfo::kTypeX64 , ArchInfo::kSubTypeNone, 8, 16), - ASMJIT_PACK32_4x8(ArchInfo::kTypeX32 , ArchInfo::kSubTypeNone, 8, 16), - ASMJIT_PACK32_4x8(ArchInfo::kTypeA32 , ArchInfo::kSubTypeNone, 4, 16), - ASMJIT_PACK32_4x8(ArchInfo::kTypeA64 , ArchInfo::kSubTypeNone, 8, 32) -}; - -ASMJIT_FAVOR_SIZE void ArchInfo::init(uint32_t type, uint32_t subType) noexcept { - uint32_t index = type < ASMJIT_ARRAY_SIZE(archInfoTable) ? type : uint32_t(0); - - // Make sure the `archInfoTable` array is correctly indexed. - _signature = archInfoTable[index]; - ASMJIT_ASSERT(_type == index); - - // Even if the architecture is not known we setup its type and sub-type, - // however, such architecture is not really useful. - _type = type; - _subType = subType; -} - -// ============================================================================ -// [asmjit::ArchUtils] -// ============================================================================ - -ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t archType, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept { - uint32_t typeId = typeIdInOut; - - // Zero the signature so it's clear in case that typeId is not invalid. - regInfo._signature = 0; - -#if defined(ASMJIT_BUILD_X86) - if (ArchInfo::isX86Family(archType)) { - // Passed RegType instead of TypeId? - if (typeId <= Reg::kRegMax) - typeId = x86OpData.archRegs.regTypeToTypeId[typeId]; - - if (ASMJIT_UNLIKELY(!TypeId::isValid(typeId))) - return DebugUtils::errored(kErrorInvalidTypeId); - - // First normalize architecture dependent types. - if (TypeId::isAbstract(typeId)) { - if (typeId == TypeId::kIntPtr) - typeId = (archType == ArchInfo::kTypeX86) ? TypeId::kI32 : TypeId::kI64; - else - typeId = (archType == ArchInfo::kTypeX86) ? TypeId::kU32 : TypeId::kU64; - } - - // Type size helps to construct all kinds of registers. If the size is zero - // then the TypeId is invalid. - uint32_t size = TypeId::sizeOf(typeId); - if (ASMJIT_UNLIKELY(!size)) - return DebugUtils::errored(kErrorInvalidTypeId); - - if (ASMJIT_UNLIKELY(typeId == TypeId::kF80)) - return DebugUtils::errored(kErrorInvalidUseOfF80); - - uint32_t regType = 0; - - switch (typeId) { - case TypeId::kI8: - case TypeId::kU8: - regType = X86Reg::kRegGpbLo; - break; - - case TypeId::kI16: - case TypeId::kU16: - regType = X86Reg::kRegGpw; - break; - - case TypeId::kI32: - case TypeId::kU32: - regType = X86Reg::kRegGpd; - break; - - case TypeId::kI64: - case TypeId::kU64: - if (archType == ArchInfo::kTypeX86) - return DebugUtils::errored(kErrorInvalidUseOfGpq); - - regType = X86Reg::kRegGpq; - break; - - // F32 and F64 are always promoted to use vector registers. - case TypeId::kF32: - typeId = TypeId::kF32x1; - regType = X86Reg::kRegXmm; - break; - - case TypeId::kF64: - typeId = TypeId::kF64x1; - regType = X86Reg::kRegXmm; - break; - - // Mask registers {k}. - case TypeId::kMask8: - case TypeId::kMask16: - case TypeId::kMask32: - case TypeId::kMask64: - regType = X86Reg::kRegK; - break; - - // MMX registers. - case TypeId::kMmx32: - case TypeId::kMmx64: - regType = X86Reg::kRegMm; - break; - - // XMM|YMM|ZMM registers. - default: - if (size <= 16) - regType = X86Reg::kRegXmm; - else if (size == 32) - regType = X86Reg::kRegYmm; - else - regType = X86Reg::kRegZmm; - break; - } - - typeIdInOut = typeId; - regInfo._signature = x86OpData.archRegs.regInfo[regType].getSignature(); - return kErrorOk; - } -#endif // ASMJIT_BUILD_X86 - - return DebugUtils::errored(kErrorInvalidArch); -} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/arch.h b/libs/asmjit/base/arch.h deleted file mode 100644 index e03c6af4..00000000 --- a/libs/asmjit/base/arch.h +++ /dev/null @@ -1,199 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_ARCH_H -#define _ASMJIT_BASE_ARCH_H - -// [Dependencies] -#include "../base/globals.h" -#include "../base/operand.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::ArchInfo] -// ============================================================================ - -class ArchInfo { -public: - //! Architecture type. - ASMJIT_ENUM(Type) { - kTypeNone = 0, //!< No/Unknown architecture. - - // X86 architectures. - kTypeX86 = 1, //!< X86 architecture (32-bit). - kTypeX64 = 2, //!< X64 architecture (64-bit) (AMD64). - kTypeX32 = 3, //!< X32 architecture (DEAD-END). - - // ARM architectures. - kTypeA32 = 4, //!< ARM 32-bit architecture (AArch32/ARM/THUMB). - kTypeA64 = 5, //!< ARM 64-bit architecture (AArch64). - - //! Architecture detected at compile-time (architecture of the host). - kTypeHost = ASMJIT_ARCH_X86 ? kTypeX86 : - ASMJIT_ARCH_X64 ? kTypeX64 : - ASMJIT_ARCH_ARM32 ? kTypeA32 : - ASMJIT_ARCH_ARM64 ? kTypeA64 : kTypeNone - }; - - //! Architecture sub-type or execution mode. - ASMJIT_ENUM(SubType) { - kSubTypeNone = 0, //!< Default mode (or no specific mode). - - // X86 sub-types. - kSubTypeX86_AVX = 1, //!< Code generation uses AVX by default (VEC instructions). - kSubTypeX86_AVX2 = 2, //!< Code generation uses AVX2 by default (VEC instructions). - kSubTypeX86_AVX512 = 3, //!< Code generation uses AVX-512F by default (+32 vector regs). - kSubTypeX86_AVX512VL = 4, //!< Code generation uses AVX-512F-VL by default (+VL extensions). - - // ARM sub-types. - kSubTypeA32_Thumb = 8, //!< THUMB|THUMB2 sub-type (only ARM in 32-bit mode). - -#if (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX512VL__) - kSubTypeHost = kSubTypeX86_AVX512VL -#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX512F__) - kSubTypeHost = kSubTypeX86_AVX512 -#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX2__) - kSubTypeHost = kSubTypeX86_AVX2 -#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX__) - kSubTypeHost = kSubTypeX86_AVX -#elif (ASMJIT_ARCH_ARM32) && (defined(_M_ARMT) || defined(__thumb__) || defined(__thumb2__)) - kSubTypeHost = kSubTypeA32_Thumb -#else - kSubTypeHost = 0 -#endif - }; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE bool isX86Family(uint32_t archType) noexcept { return archType >= kTypeX86 && archType <= kTypeX32; } - static ASMJIT_INLINE bool isArmFamily(uint32_t archType) noexcept { return archType >= kTypeA32 && archType <= kTypeA64; } - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE ArchInfo() noexcept : _signature(0) {} - ASMJIT_INLINE ArchInfo(const ArchInfo& other) noexcept : _signature(other._signature) {} - explicit ASMJIT_INLINE ArchInfo(uint32_t type, uint32_t subType = kSubTypeNone) noexcept { init(type, subType); } - - ASMJIT_INLINE static ArchInfo host() noexcept { return ArchInfo(kTypeHost, kSubTypeHost); } - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool isInitialized() const noexcept { return _type != kTypeNone; } - - ASMJIT_API void init(uint32_t type, uint32_t subType = kSubTypeNone) noexcept; - ASMJIT_INLINE void reset() noexcept { _signature = 0; } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get if the architecture is 32-bit. - ASMJIT_INLINE bool is32Bit() const noexcept { return _gpSize == 4; } - //! Get if the architecture is 64-bit. - ASMJIT_INLINE bool is64Bit() const noexcept { return _gpSize == 8; } - - //! Get architecture type, see \ref Type. - ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } - - //! Get architecture sub-type, see \ref SubType. - //! - //! X86 & X64 - //! --------- - //! - //! Architecture subtype describe the highest instruction-set level that can - //! be used. - //! - //! ARM32 - //! ----- - //! - //! Architecture mode means the instruction encoding to be used when generating - //! machine code, thus mode can be used to force generation of THUMB and THUMB2 - //! encoding or regular ARM encoding. - //! - //! ARM64 - //! ----- - //! - //! No meaning yet. - ASMJIT_INLINE uint32_t getSubType() const noexcept { return _subType; } - - //! Get if the architecture is X86, X64, or X32. - ASMJIT_INLINE bool isX86Family() const noexcept { return isX86Family(_type); } - //! Get if the architecture is ARM32 or ARM64. - ASMJIT_INLINE bool isArmFamily() const noexcept { return isArmFamily(_type); } - - //! Get a size of a general-purpose register. - ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _gpSize; } - //! Get number of general-purpose registers. - ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _gpCount; } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE const ArchInfo& operator=(const ArchInfo& other) noexcept { _signature = other._signature; return *this; } - ASMJIT_INLINE bool operator==(const ArchInfo& other) const noexcept { return _signature == other._signature; } - ASMJIT_INLINE bool operator!=(const ArchInfo& other) const noexcept { return _signature != other._signature; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - union { - struct { - uint8_t _type; //!< Architecture type. - uint8_t _subType; //!< Architecture sub-type. - uint8_t _gpSize; //!< Default size of a general purpose register. - uint8_t _gpCount; //!< Count of all general purpose registers. - }; - uint32_t _signature; //!< Architecture signature (32-bit int). - }; -}; - -// ============================================================================ -// [asmjit::ArchRegs] -// ============================================================================ - -//! Information about all architecture registers. -struct ArchRegs { - //! Register information and signatures indexed by \ref Reg::Type. - RegInfo regInfo[Reg::kRegMax + 1]; - //! Count (maximum) of registers per \ref Reg::Type. - uint8_t regCount[Reg::kRegMax + 1]; - //! Converts RegType to TypeId, see \ref TypeId::Id. - uint8_t regTypeToTypeId[Reg::kRegMax + 1]; -}; - -// ============================================================================ -// [asmjit::ArchUtils] -// ============================================================================ - -struct ArchUtils { - ASMJIT_API static Error typeIdToRegInfo(uint32_t archType, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept; -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_ARCH_H diff --git a/libs/asmjit/base/assembler.cpp b/libs/asmjit/base/assembler.cpp deleted file mode 100644 index 79a26665..00000000 --- a/libs/asmjit/base/assembler.cpp +++ /dev/null @@ -1,447 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/assembler.h" -#include "../base/constpool.h" -#include "../base/utils.h" -#include "../base/vmem.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::Assembler - Construction / Destruction] -// ============================================================================ - -Assembler::Assembler() noexcept - : CodeEmitter(kTypeAssembler), - _section(nullptr), - _bufferData(nullptr), - _bufferEnd(nullptr), - _bufferPtr(nullptr), - _op4(), - _op5() {} - -Assembler::~Assembler() noexcept { - if (_code) sync(); -} - -// ============================================================================ -// [asmjit::Assembler - Events] -// ============================================================================ - -Error Assembler::onAttach(CodeHolder* code) noexcept { - // Attach to the end of the .text section. - _section = code->_sections[0]; - uint8_t* p = _section->_buffer._data; - - _bufferData = p; - _bufferEnd = p + _section->_buffer._capacity; - _bufferPtr = p + _section->_buffer._length; - - _op4.reset(); - _op5.reset(); - - return Base::onAttach(code); -} - -Error Assembler::onDetach(CodeHolder* code) noexcept { - _section = nullptr; - _bufferData = nullptr; - _bufferEnd = nullptr; - _bufferPtr = nullptr; - - _op4.reset(); - _op5.reset(); - - return Base::onDetach(code); -} - -// ============================================================================ -// [asmjit::Assembler - Code-Generation] -// ============================================================================ - -Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) { - _op4 = o4; - _op5 = o5; - _options |= kOptionOp4Op5Used; - return _emit(instId, o0, o1, o2, o3); -} - -Error Assembler::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) { - const Operand_* op = opArray; - switch (opCount) { - case 0: return _emit(instId, _none, _none, _none, _none); - case 1: return _emit(instId, op[0], _none, _none, _none); - case 2: return _emit(instId, op[0], op[1], _none, _none); - case 3: return _emit(instId, op[0], op[1], op[2], _none); - case 4: return _emit(instId, op[0], op[1], op[2], op[3]); - - case 5: - _op4 = op[4]; - _op5.reset(); - _options |= kOptionOp4Op5Used; - return _emit(instId, op[0], op[1], op[2], op[3]); - - case 6: - _op4 = op[4]; - _op5 = op[5]; - _options |= kOptionOp4Op5Used; - return _emit(instId, op[0], op[1], op[2], op[3]); - - default: - return DebugUtils::errored(kErrorInvalidArgument); - } -} - -// ============================================================================ -// [asmjit::Assembler - Sync] -// ============================================================================ - -void Assembler::sync() noexcept { - ASMJIT_ASSERT(_code != nullptr); // Only called by CodeHolder, so we must be attached. - ASMJIT_ASSERT(_section != nullptr); // One section must always be active, no matter what. - ASMJIT_ASSERT(_bufferData == _section->_buffer._data); // `_bufferStart` is a shortcut to `_section->buffer.data`. - - // Update only if the current offset is greater than the section length. - size_t offset = (size_t)(_bufferPtr - _bufferData); - if (_section->getBuffer().getLength() < offset) - _section->_buffer._length = offset; -} - -// ============================================================================ -// [asmjit::Assembler - Code-Buffer] -// ============================================================================ - -Error Assembler::setOffset(size_t offset) { - if (_lastError) return _lastError; - - size_t length = std::max(_section->getBuffer().getLength(), getOffset()); - if (ASMJIT_UNLIKELY(offset > length)) - return setLastError(DebugUtils::errored(kErrorInvalidArgument)); - - // If the `Assembler` generated any code the `_bufferPtr` may be higher than - // the section length stored in `CodeHolder` as it doesn't update it each - // time it generates machine code. This is the same as calling `sync()`. - if (_section->_buffer._length < length) - _section->_buffer._length = length; - - _bufferPtr = _bufferData + offset; - return kErrorOk; -} - -// ============================================================================ -// [asmjit::Assembler - Comment] -// ============================================================================ - -Error Assembler::comment(const char* s, size_t len) { - if (_lastError) return _lastError; - -#if !defined(ASMJIT_DISABLE_LOGGING) - if (_globalOptions & kOptionLoggingEnabled) { - Logger* logger = _code->getLogger(); - logger->log(s, len); - logger->log("\n", 1); - return kErrorOk; - } -#else - ASMJIT_UNUSED(s); - ASMJIT_UNUSED(len); -#endif - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::Assembler - Building Blocks] -// ============================================================================ - -Label Assembler::newLabel() { - uint32_t id = 0; - if (!_lastError) { - ASMJIT_ASSERT(_code != nullptr); - Error err = _code->newLabelId(id); - if (ASMJIT_UNLIKELY(err)) setLastError(err); - } - return Label(id); -} - -Label Assembler::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) { - uint32_t id = 0; - if (!_lastError) { - ASMJIT_ASSERT(_code != nullptr); - Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId); - if (ASMJIT_UNLIKELY(err)) setLastError(err); - } - return Label(id); -} - -Error Assembler::bind(const Label& label) { - if (_lastError) return _lastError; - ASMJIT_ASSERT(_code != nullptr); - - LabelEntry* le = _code->getLabelEntry(label); - if (ASMJIT_UNLIKELY(!le)) - return setLastError(DebugUtils::errored(kErrorInvalidLabel)); - - // Label can be bound only once. - if (ASMJIT_UNLIKELY(le->isBound())) - return setLastError(DebugUtils::errored(kErrorLabelAlreadyBound)); - -#if !defined(ASMJIT_DISABLE_LOGGING) - if (_globalOptions & kOptionLoggingEnabled) { - StringBuilderTmp<256> sb; - if (le->hasName()) - sb.setFormat("%s:", le->getName()); - else - sb.setFormat("L%u:", Operand::unpackId(label.getId())); - - size_t binSize = 0; - if (!_code->_logger->hasOption(Logger::kOptionBinaryForm)) - binSize = Globals::kInvalidIndex; - - Logging::formatLine(sb, nullptr, binSize, 0, 0, getInlineComment()); - _code->_logger->log(sb.getData(), sb.getLength()); - } -#endif // !ASMJIT_DISABLE_LOGGING - - Error err = kErrorOk; - size_t pos = getOffset(); - - LabelLink* link = le->_links; - LabelLink* prev = nullptr; - - while (link) { - intptr_t offset = link->offset; - uint32_t relocId = link->relocId; - - if (relocId != RelocEntry::kInvalidId) { - // Adjust relocation data. - RelocEntry* re = _code->_relocations[relocId]; - re->_data += static_cast(pos); - } - else { - // Not using relocId, this means that we are overwriting a real - // displacement in the CodeBuffer. - int32_t patchedValue = static_cast( - static_cast(pos) - offset + link->rel); - - // Size of the value we are going to patch. Only BYTE/DWORD is allowed. - uint32_t size = _bufferData[offset]; - if (size == 4) - Utils::writeI32u(_bufferData + offset, static_cast(patchedValue)); - else if (size == 1 && Utils::isInt8(patchedValue)) - _bufferData[offset] = static_cast(patchedValue & 0xFF); - else - err = DebugUtils::errored(kErrorInvalidDisplacement); - } - - prev = link->prev; - _code->_unresolvedLabelsCount--; - _code->_baseHeap.release(link, sizeof(LabelLink)); - - link = prev; - } - - // Set as bound. - le->_sectionId = _section->getId(); - le->_offset = pos; - le->_links = nullptr; - resetInlineComment(); - - if (err != kErrorOk) - return setLastError(err); - - return kErrorOk; -} - -Error Assembler::embed(const void* data, uint32_t size) { - if (_lastError) return _lastError; - - if (getRemainingSpace() < size) { - Error err = _code->growBuffer(&_section->_buffer, size); - if (ASMJIT_UNLIKELY(err != kErrorOk)) return setLastError(err); - } - - ::memcpy(_bufferPtr, data, size); - _bufferPtr += size; - -#if !defined(ASMJIT_DISABLE_LOGGING) - if (_globalOptions & kOptionLoggingEnabled) - _code->_logger->logBinary(data, size); -#endif // !ASMJIT_DISABLE_LOGGING - - return kErrorOk; -} - -Error Assembler::embedLabel(const Label& label) { - if (_lastError) return _lastError; - ASMJIT_ASSERT(_code != nullptr); - - RelocEntry* re; - LabelEntry* le = _code->getLabelEntry(label); - - if (ASMJIT_UNLIKELY(!le)) - return setLastError(DebugUtils::errored(kErrorInvalidLabel)); - - Error err; - uint32_t gpSize = getGpSize(); - - if (getRemainingSpace() < gpSize) { - err = _code->growBuffer(&_section->_buffer, gpSize); - if (ASMJIT_UNLIKELY(err)) return setLastError(err); - } - -#if !defined(ASMJIT_DISABLE_LOGGING) - if (_globalOptions & kOptionLoggingEnabled) - _code->_logger->logf(gpSize == 4 ? ".dd L%u\n" : ".dq L%u\n", Operand::unpackId(label.getId())); -#endif // !ASMJIT_DISABLE_LOGGING - - err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, gpSize); - if (ASMJIT_UNLIKELY(err)) return setLastError(err); - - re->_sourceSectionId = _section->getId(); - re->_sourceOffset = static_cast(getOffset()); - - if (le->isBound()) { - re->_targetSectionId = le->getSectionId(); - re->_data = static_cast(static_cast(le->getOffset())); - } - else { - LabelLink* link = _code->newLabelLink(le, _section->getId(), getOffset(), 0); - if (ASMJIT_UNLIKELY(!link)) - return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - link->relocId = re->getId(); - } - - // Emit dummy DWORD/QWORD depending on the address size. - ::memset(_bufferPtr, 0, gpSize); - _bufferPtr += gpSize; - - return kErrorOk; -} - -Error Assembler::embedConstPool(const Label& label, const ConstPool& pool) { - if (_lastError) return _lastError; - - if (!isLabelValid(label)) - return DebugUtils::errored(kErrorInvalidLabel); - - ASMJIT_PROPAGATE(align(kAlignData, static_cast(pool.getAlignment()))); - ASMJIT_PROPAGATE(bind(label)); - - size_t size = pool.getSize(); - if (getRemainingSpace() < size) { - Error err = _code->growBuffer(&_section->_buffer, size); - if (ASMJIT_UNLIKELY(err)) return setLastError(err); - } - - uint8_t* p = _bufferPtr; - pool.fill(p); - -#if !defined(ASMJIT_DISABLE_LOGGING) - if (_globalOptions & kOptionLoggingEnabled) - _code->_logger->logBinary(p, size); -#endif // !ASMJIT_DISABLE_LOGGING - - _bufferPtr += size; - return kErrorOk; -} - -// ============================================================================ -// [asmjit::Assembler - Emit-Helpers] -// ============================================================================ - -#if !defined(ASMJIT_DISABLE_LOGGING) -void Assembler::_emitLog( - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, - uint32_t relSize, uint32_t imLen, uint8_t* afterCursor) { - - Logger* logger = _code->getLogger(); - ASMJIT_ASSERT(logger != nullptr); - ASMJIT_ASSERT(options & CodeEmitter::kOptionLoggingEnabled); - - StringBuilderTmp<256> sb; - uint32_t logOptions = logger->getOptions(); - - uint8_t* beforeCursor = _bufferPtr; - intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor); - - sb.appendString(logger->getIndentation()); - - Operand_ opArray[6]; - opArray[0].copyFrom(o0); - opArray[1].copyFrom(o1); - opArray[2].copyFrom(o2); - opArray[3].copyFrom(o3); - - if (options & kOptionOp4Op5Used) { - opArray[4].copyFrom(_op4); - opArray[5].copyFrom(_op5); - } - else { - opArray[4].reset(); - opArray[5].reset(); - } - - Logging::formatInstruction( - sb, logOptions, - this, getArchType(), - Inst::Detail(instId, options, _extraReg), opArray, 6); - - if ((logOptions & Logger::kOptionBinaryForm) != 0) - Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment()); - else - Logging::formatLine(sb, nullptr, Globals::kInvalidIndex, 0, 0, getInlineComment()); - - logger->log(sb.getData(), sb.getLength()); -} - -Error Assembler::_emitFailed( - Error err, - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { - - StringBuilderTmp<256> sb; - sb.appendString(DebugUtils::errorAsString(err)); - sb.appendString(": "); - - Operand_ opArray[6]; - opArray[0].copyFrom(o0); - opArray[1].copyFrom(o1); - opArray[2].copyFrom(o2); - opArray[3].copyFrom(o3); - - if (options & kOptionOp4Op5Used) { - opArray[4].copyFrom(_op4); - opArray[5].copyFrom(_op5); - } - else { - opArray[4].reset(); - opArray[5].reset(); - } - - Logging::formatInstruction( - sb, 0, - this, getArchType(), - Inst::Detail(instId, options, _extraReg), opArray, 6); - - resetOptions(); - resetExtraReg(); - resetInlineComment(); - return setLastError(err, sb.getData()); -} -#endif - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/assembler.h b/libs/asmjit/base/assembler.h deleted file mode 100644 index 55fbb142..00000000 --- a/libs/asmjit/base/assembler.h +++ /dev/null @@ -1,154 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_ASSEMBLER_H -#define _ASMJIT_BASE_ASSEMBLER_H - -// [Dependencies] -#include "../base/codeemitter.h" -#include "../base/codeholder.h" -#include "../base/operand.h" -#include "../base/simdtypes.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::Assembler] -// ============================================================================ - -//! Base assembler. -//! -//! This class implements a base interface that is used by architecture -//! specific assemblers. -//! -//! \sa CodeCompiler. -class ASMJIT_VIRTAPI Assembler : public CodeEmitter { -public: - ASMJIT_NONCOPYABLE(Assembler) - typedef CodeEmitter Base; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `Assembler` instance. - ASMJIT_API Assembler() noexcept; - //! Destroy the `Assembler` instance. - ASMJIT_API virtual ~Assembler() noexcept; - - // -------------------------------------------------------------------------- - // [Events] - // -------------------------------------------------------------------------- - - ASMJIT_API Error onAttach(CodeHolder* code) noexcept override; - ASMJIT_API Error onDetach(CodeHolder* code) noexcept override; - - // -------------------------------------------------------------------------- - // [Code-Generation] - // -------------------------------------------------------------------------- - - using CodeEmitter::_emit; - - ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override; - ASMJIT_API Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) override; - - // -------------------------------------------------------------------------- - // [Code-Buffer] - // -------------------------------------------------------------------------- - - //! Called by \ref CodeHolder::sync(). - ASMJIT_API virtual void sync() noexcept; - - //! Get the capacity of the current CodeBuffer. - ASMJIT_INLINE size_t getBufferCapacity() const noexcept { return (size_t)(_bufferEnd - _bufferData); } - //! Get the number of remaining bytes in the current CodeBuffer. - ASMJIT_INLINE size_t getRemainingSpace() const noexcept { return (size_t)(_bufferEnd - _bufferPtr); } - - //! Get the current position in the CodeBuffer. - ASMJIT_INLINE size_t getOffset() const noexcept { return (size_t)(_bufferPtr - _bufferData); } - //! Set the current position in the CodeBuffer to `offset`. - //! - //! NOTE: The `offset` cannot be outside of the buffer length (even if it's - //! within buffer's capacity). - ASMJIT_API Error setOffset(size_t offset); - - //! Get start of the CodeBuffer of the current section. - ASMJIT_INLINE uint8_t* getBufferData() const noexcept { return _bufferData; } - //! Get end (first invalid byte) of the current section. - ASMJIT_INLINE uint8_t* getBufferEnd() const noexcept { return _bufferEnd; } - //! Get pointer in the CodeBuffer of the current section. - ASMJIT_INLINE uint8_t* getBufferPtr() const noexcept { return _bufferPtr; } - - // -------------------------------------------------------------------------- - // [Code-Generation] - // -------------------------------------------------------------------------- - - ASMJIT_API Label newLabel() override; - ASMJIT_API Label newNamedLabel( - const char* name, - size_t nameLength = Globals::kInvalidIndex, - uint32_t type = Label::kTypeGlobal, - uint32_t parentId = 0) override; - ASMJIT_API Error bind(const Label& label) override; - ASMJIT_API Error embed(const void* data, uint32_t size) override; - ASMJIT_API Error embedLabel(const Label& label) override; - ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override; - ASMJIT_API Error comment(const char* s, size_t len = Globals::kInvalidIndex) override; - - // -------------------------------------------------------------------------- - // [Emit-Helpers] - // -------------------------------------------------------------------------- - -protected: -#if !defined(ASMJIT_DISABLE_LOGGING) - void _emitLog( - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, - uint32_t relSize, uint32_t imLen, uint8_t* afterCursor); - - Error _emitFailed( - Error err, - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3); -#else - ASMJIT_INLINE Error _emitFailed( - uint32_t err, - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { - - resetOptions(); - resetInlineComment(); - return setLastError(err); - } -#endif - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -public: - SectionEntry* _section; //!< Current section where the assembling happens. - uint8_t* _bufferData; //!< Start of the CodeBuffer of the current section. - uint8_t* _bufferEnd; //!< End (first invalid byte) of the current section. - uint8_t* _bufferPtr; //!< Pointer in the CodeBuffer of the current section. - - Operand_ _op4; //!< 5th operand data, used only temporarily. - Operand_ _op5; //!< 6th operand data, used only temporarily. -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_ASSEMBLER_H diff --git a/libs/asmjit/base/codebuilder.cpp b/libs/asmjit/base/codebuilder.cpp deleted file mode 100644 index 1f002483..00000000 --- a/libs/asmjit/base/codebuilder.cpp +++ /dev/null @@ -1,584 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Guard] -#include "../asmjit_build.h" -#if !defined(ASMJIT_DISABLE_BUILDER) - -// [Dependencies] -#include "../base/codebuilder.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::CodeBuilder - Construction / Destruction] -// ============================================================================ - -CodeBuilder::CodeBuilder() noexcept - : CodeEmitter(kTypeBuilder), - _cbBaseZone(32768 - Zone::kZoneOverhead), - _cbDataZone(16384 - Zone::kZoneOverhead), - _cbPassZone(32768 - Zone::kZoneOverhead), - _cbHeap(&_cbBaseZone), - _cbPasses(), - _cbLabels(), - _firstNode(nullptr), - _lastNode(nullptr), - _cursor(nullptr), - _position(0), - _nodeFlags(0) {} -CodeBuilder::~CodeBuilder() noexcept {} - -// ============================================================================ -// [asmjit::CodeBuilder - Events] -// ============================================================================ - -Error CodeBuilder::onAttach(CodeHolder* code) noexcept { - return Base::onAttach(code); -} - -Error CodeBuilder::onDetach(CodeHolder* code) noexcept { - _cbPasses.reset(); - _cbLabels.reset(); - _cbHeap.reset(&_cbBaseZone); - - _cbBaseZone.reset(false); - _cbDataZone.reset(false); - _cbPassZone.reset(false); - - _position = 0; - _nodeFlags = 0; - - _firstNode = nullptr; - _lastNode = nullptr; - _cursor = nullptr; - - return Base::onDetach(code); -} - -// ============================================================================ -// [asmjit::CodeBuilder - Node-Factory] -// ============================================================================ - -Error CodeBuilder::getCBLabel(CBLabel** pOut, uint32_t id) noexcept { - if (_lastError) return _lastError; - ASMJIT_ASSERT(_code != nullptr); - - size_t index = Operand::unpackId(id); - if (ASMJIT_UNLIKELY(index >= _code->getLabelsCount())) - return DebugUtils::errored(kErrorInvalidLabel); - - if (index >= _cbLabels.getLength()) - ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1)); - - CBLabel* node = _cbLabels[index]; - if (!node) { - node = newNodeT(id); - if (ASMJIT_UNLIKELY(!node)) - return DebugUtils::errored(kErrorNoHeapMemory); - _cbLabels[index] = node; - } - - *pOut = node; - return kErrorOk; -} - -Error CodeBuilder::registerLabelNode(CBLabel* node) noexcept { - if (_lastError) return _lastError; - ASMJIT_ASSERT(_code != nullptr); - - // Don't call setLastError() from here, we are noexcept and we are called - // by `newLabelNode()` and `newFuncNode()`, which are noexcept as well. - uint32_t id; - ASMJIT_PROPAGATE(_code->newLabelId(id)); - size_t index = Operand::unpackId(id); - - // We just added one label so it must be true. - ASMJIT_ASSERT(_cbLabels.getLength() < index + 1); - ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1)); - - _cbLabels[index] = node; - node->_id = id; - return kErrorOk; -} - -CBLabel* CodeBuilder::newLabelNode() noexcept { - CBLabel* node = newNodeT(); - if (!node || registerLabelNode(node) != kErrorOk) - return nullptr; - return node; -} - -CBAlign* CodeBuilder::newAlignNode(uint32_t mode, uint32_t alignment) noexcept { - return newNodeT(mode, alignment); -} - -CBData* CodeBuilder::newDataNode(const void* data, uint32_t size) noexcept { - if (size > CBData::kInlineBufferSize) { - void* cloned = _cbDataZone.alloc(size); - if (!cloned) return nullptr; - - if (data) ::memcpy(cloned, data, size); - data = cloned; - } - - return newNodeT(const_cast(data), size); -} - -CBConstPool* CodeBuilder::newConstPool() noexcept { - CBConstPool* node = newNodeT(); - if (!node || registerLabelNode(node) != kErrorOk) - return nullptr; - return node; -} - -CBComment* CodeBuilder::newCommentNode(const char* s, size_t len) noexcept { - if (s) { - if (len == Globals::kInvalidIndex) len = ::strlen(s); - if (len > 0) { - s = static_cast(_cbDataZone.dup(s, len, true)); - if (!s) return nullptr; - } - } - - return newNodeT(s); -} - -// ============================================================================ -// [asmjit::CodeBuilder - Code-Emitter] -// ============================================================================ - -Label CodeBuilder::newLabel() { - uint32_t id = kInvalidValue; - - if (!_lastError) { - CBLabel* node = newNodeT(id); - if (ASMJIT_UNLIKELY(!node)) { - setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - } - else { - Error err = registerLabelNode(node); - if (ASMJIT_UNLIKELY(err)) - setLastError(err); - else - id = node->getId(); - } - } - - return Label(id); -} - -Label CodeBuilder::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) { - uint32_t id = kInvalidValue; - - if (!_lastError) { - CBLabel* node = newNodeT(id); - if (ASMJIT_UNLIKELY(!node)) { - setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - } - else { - Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId); - if (ASMJIT_UNLIKELY(err)) - setLastError(err); - else - id = node->getId(); - } - } - - return Label(id); -} - -Error CodeBuilder::bind(const Label& label) { - if (_lastError) return _lastError; - - CBLabel* node; - Error err = getCBLabel(&node, label); - if (ASMJIT_UNLIKELY(err)) - return setLastError(err); - - addNode(node); - return kErrorOk; -} - -Error CodeBuilder::align(uint32_t mode, uint32_t alignment) { - if (_lastError) return _lastError; - - CBAlign* node = newAlignNode(mode, alignment); - if (ASMJIT_UNLIKELY(!node)) - return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - - addNode(node); - return kErrorOk; -} - -Error CodeBuilder::embed(const void* data, uint32_t size) { - if (_lastError) return _lastError; - - CBData* node = newDataNode(data, size); - if (ASMJIT_UNLIKELY(!node)) - return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - - addNode(node); - return kErrorOk; -} - -Error CodeBuilder::embedLabel(const Label& label) { - if (_lastError) return _lastError; - - CBLabelData* node = newNodeT(label.getId()); - if (ASMJIT_UNLIKELY(!node)) - return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - - addNode(node); - return kErrorOk; -} - -Error CodeBuilder::embedConstPool(const Label& label, const ConstPool& pool) { - if (_lastError) return _lastError; - - if (!isLabelValid(label)) - return setLastError(DebugUtils::errored(kErrorInvalidLabel)); - - ASMJIT_PROPAGATE(align(kAlignData, static_cast(pool.getAlignment()))); - ASMJIT_PROPAGATE(bind(label)); - - CBData* node = newDataNode(nullptr, static_cast(pool.getSize())); - if (ASMJIT_UNLIKELY(!node)) - return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - - pool.fill(node->getData()); - addNode(node); - return kErrorOk; -} - -Error CodeBuilder::comment(const char* s, size_t len) { - if (_lastError) return _lastError; - - CBComment* node = newCommentNode(s, len); - if (ASMJIT_UNLIKELY(!node)) - return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - - addNode(node); - return kErrorOk; -} - -// ============================================================================ -// [asmjit::CodeBuilder - Node-Management] -// ============================================================================ - -CBNode* CodeBuilder::addNode(CBNode* node) noexcept { - ASMJIT_ASSERT(node); - ASMJIT_ASSERT(node->_prev == nullptr); - ASMJIT_ASSERT(node->_next == nullptr); - - if (!_cursor) { - if (!_firstNode) { - _firstNode = node; - _lastNode = node; - } - else { - node->_next = _firstNode; - _firstNode->_prev = node; - _firstNode = node; - } - } - else { - CBNode* prev = _cursor; - CBNode* next = _cursor->_next; - - node->_prev = prev; - node->_next = next; - - prev->_next = node; - if (next) - next->_prev = node; - else - _lastNode = node; - } - - _cursor = node; - return node; -} - -CBNode* CodeBuilder::addAfter(CBNode* node, CBNode* ref) noexcept { - ASMJIT_ASSERT(node); - ASMJIT_ASSERT(ref); - - ASMJIT_ASSERT(node->_prev == nullptr); - ASMJIT_ASSERT(node->_next == nullptr); - - CBNode* prev = ref; - CBNode* next = ref->_next; - - node->_prev = prev; - node->_next = next; - - prev->_next = node; - if (next) - next->_prev = node; - else - _lastNode = node; - - return node; -} - -CBNode* CodeBuilder::addBefore(CBNode* node, CBNode* ref) noexcept { - ASMJIT_ASSERT(node != nullptr); - ASMJIT_ASSERT(node->_prev == nullptr); - ASMJIT_ASSERT(node->_next == nullptr); - ASMJIT_ASSERT(ref != nullptr); - - CBNode* prev = ref->_prev; - CBNode* next = ref; - - node->_prev = prev; - node->_next = next; - - next->_prev = node; - if (prev) - prev->_next = node; - else - _firstNode = node; - - return node; -} - -static ASMJIT_INLINE void CodeBuilder_nodeRemoved(CodeBuilder* self, CBNode* node_) noexcept { - if (node_->isJmpOrJcc()) { - CBJump* node = static_cast(node_); - CBLabel* label = node->getTarget(); - - if (label) { - // Disconnect. - CBJump** pPrev = &label->_from; - for (;;) { - ASMJIT_ASSERT(*pPrev != nullptr); - - CBJump* current = *pPrev; - if (!current) break; - - if (current == node) { - *pPrev = node->_jumpNext; - break; - } - - pPrev = ¤t->_jumpNext; - } - - label->subNumRefs(); - } - } -} - -CBNode* CodeBuilder::removeNode(CBNode* node) noexcept { - CBNode* prev = node->_prev; - CBNode* next = node->_next; - - if (_firstNode == node) - _firstNode = next; - else - prev->_next = next; - - if (_lastNode == node) - _lastNode = prev; - else - next->_prev = prev; - - node->_prev = nullptr; - node->_next = nullptr; - - if (_cursor == node) - _cursor = prev; - CodeBuilder_nodeRemoved(this, node); - - return node; -} - -void CodeBuilder::removeNodes(CBNode* first, CBNode* last) noexcept { - if (first == last) { - removeNode(first); - return; - } - - CBNode* prev = first->_prev; - CBNode* next = last->_next; - - if (_firstNode == first) - _firstNode = next; - else - prev->_next = next; - - if (_lastNode == last) - _lastNode = prev; - else - next->_prev = prev; - - CBNode* node = first; - for (;;) { - CBNode* next = node->getNext(); - ASMJIT_ASSERT(next != nullptr); - - node->_prev = nullptr; - node->_next = nullptr; - - if (_cursor == node) - _cursor = prev; - CodeBuilder_nodeRemoved(this, node); - - if (node == last) - break; - node = next; - } -} - -CBNode* CodeBuilder::setCursor(CBNode* node) noexcept { - CBNode* old = _cursor; - _cursor = node; - return old; -} - -// ============================================================================ -// [asmjit::CodeBuilder - Passes] -// ============================================================================ - -ASMJIT_FAVOR_SIZE CBPass* CodeBuilder::getPassByName(const char* name) const noexcept { - for (size_t i = 0, len = _cbPasses.getLength(); i < len; i++) { - CBPass* pass = _cbPasses[i]; - if (::strcmp(pass->getName(), name) == 0) - return pass; - } - - return nullptr; -} - -ASMJIT_FAVOR_SIZE Error CodeBuilder::addPass(CBPass* pass) noexcept { - if (ASMJIT_UNLIKELY(pass == nullptr)) { - // Since this is directly called by `addPassT()` we treat `null` argument - // as out-of-memory condition. Otherwise it would be API misuse. - return DebugUtils::errored(kErrorNoHeapMemory); - } - else if (ASMJIT_UNLIKELY(pass->_cb)) { - // Kind of weird, but okay... - if (pass->_cb == this) - return kErrorOk; - return DebugUtils::errored(kErrorInvalidState); - } - - ASMJIT_PROPAGATE(_cbPasses.append(&_cbHeap, pass)); - pass->_cb = this; - return kErrorOk; -} - -ASMJIT_FAVOR_SIZE Error CodeBuilder::deletePass(CBPass* pass) noexcept { - if (ASMJIT_UNLIKELY(pass == nullptr)) - return DebugUtils::errored(kErrorInvalidArgument); - - if (pass->_cb != nullptr) { - if (pass->_cb != this) - return DebugUtils::errored(kErrorInvalidState); - - size_t index = _cbPasses.indexOf(pass); - ASMJIT_ASSERT(index != Globals::kInvalidIndex); - - pass->_cb = nullptr; - _cbPasses.removeAt(index); - } - - pass->~CBPass(); - return kErrorOk; -} - -// ============================================================================ -// [asmjit::CodeBuilder - Serialization] -// ============================================================================ - -Error CodeBuilder::serialize(CodeEmitter* dst) { - Error err = kErrorOk; - CBNode* node_ = getFirstNode(); - - do { - dst->setInlineComment(node_->getInlineComment()); - - switch (node_->getType()) { - case CBNode::kNodeAlign: { - CBAlign* node = static_cast(node_); - err = dst->align(node->getMode(), node->getAlignment()); - break; - } - - case CBNode::kNodeData: { - CBData* node = static_cast(node_); - err = dst->embed(node->getData(), node->getSize()); - break; - } - - case CBNode::kNodeFunc: - case CBNode::kNodeLabel: { - CBLabel* node = static_cast(node_); - err = dst->bind(node->getLabel()); - break; - } - - case CBNode::kNodeLabelData: { - CBLabelData* node = static_cast(node_); - err = dst->embedLabel(node->getLabel()); - break; - } - - case CBNode::kNodeConstPool: { - CBConstPool* node = static_cast(node_); - err = dst->embedConstPool(node->getLabel(), node->getConstPool()); - break; - } - - case CBNode::kNodeInst: - case CBNode::kNodeFuncCall: { - CBInst* node = node_->as(); - dst->setOptions(node->getOptions()); - dst->setExtraReg(node->getExtraReg()); - err = dst->emitOpArray(node->getInstId(), node->getOpArray(), node->getOpCount()); - break; - } - - case CBNode::kNodeComment: { - CBComment* node = static_cast(node_); - err = dst->comment(node->getInlineComment()); - break; - } - - default: - break; - } - - if (err) break; - node_ = node_->getNext(); - } while (node_); - - return err; -} - -// ============================================================================ -// [asmjit::CBPass] -// ============================================================================ - -CBPass::CBPass(const char* name) noexcept - : _cb(nullptr), - _name(name) {} -CBPass::~CBPass() noexcept {} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // !ASMJIT_DISABLE_BUILDER diff --git a/libs/asmjit/base/codebuilder.h b/libs/asmjit/base/codebuilder.h deleted file mode 100644 index 231dd844..00000000 --- a/libs/asmjit/base/codebuilder.h +++ /dev/null @@ -1,915 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_CODEBUILDER_H -#define _ASMJIT_BASE_CODEBUILDER_H - -#include "../asmjit_build.h" -#if !defined(ASMJIT_DISABLE_BUILDER) - -// [Dependencies] -#include "../base/assembler.h" -#include "../base/codeholder.h" -#include "../base/constpool.h" -#include "../base/inst.h" -#include "../base/operand.h" -#include "../base/utils.h" -#include "../base/zone.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -class CBNode; -class CBPass; - -class CBAlign; -class CBComment; -class CBConstPool; -class CBData; -class CBInst; -class CBJump; -class CBLabel; -class CBLabelData; -class CBSentinel; - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::CodeBuilder] -// ============================================================================ - -class ASMJIT_VIRTAPI CodeBuilder : public CodeEmitter { -public: - ASMJIT_NONCOPYABLE(CodeBuilder) - typedef CodeEmitter Base; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CodeBuilder` instance. - ASMJIT_API CodeBuilder() noexcept; - //! Destroy the `CodeBuilder` instance. - ASMJIT_API virtual ~CodeBuilder() noexcept; - - // -------------------------------------------------------------------------- - // [Events] - // -------------------------------------------------------------------------- - - ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override; - ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get a vector of CBPass objects that will be executed by `process()`. - ASMJIT_INLINE const ZoneVector& getPasses() const noexcept { return _cbPasses; } - - //! Get a vector of CBLabel nodes. - //! - //! NOTE: If a label of some index is not associated with `CodeBuilder` it - //! would be null, so always check for nulls if you iterate over the vector. - ASMJIT_INLINE const ZoneVector& getLabels() const noexcept { return _cbLabels; } - - //! Get the first node. - ASMJIT_INLINE CBNode* getFirstNode() const noexcept { return _firstNode; } - //! Get the last node. - ASMJIT_INLINE CBNode* getLastNode() const noexcept { return _lastNode; } - - // -------------------------------------------------------------------------- - // [Node-Management] - // -------------------------------------------------------------------------- - - //! \internal - template - ASMJIT_INLINE T* newNodeT() noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this); } - - //! \internal - template - ASMJIT_INLINE T* newNodeT(P0 p0) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0); } - - //! \internal - template - ASMJIT_INLINE T* newNodeT(P0 p0, P1 p1) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0, p1); } - - //! \internal - template - ASMJIT_INLINE T* newNodeT(P0 p0, P1 p1, P2 p2) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0, p1, p2); } - - ASMJIT_API Error registerLabelNode(CBLabel* node) noexcept; - //! Get `CBLabel` by `id`. - ASMJIT_API Error getCBLabel(CBLabel** pOut, uint32_t id) noexcept; - //! Get `CBLabel` by `label`. - ASMJIT_INLINE Error getCBLabel(CBLabel** pOut, const Label& label) noexcept { return getCBLabel(pOut, label.getId()); } - - //! Create a new \ref CBLabel node. - ASMJIT_API CBLabel* newLabelNode() noexcept; - //! Create a new \ref CBAlign node. - ASMJIT_API CBAlign* newAlignNode(uint32_t mode, uint32_t alignment) noexcept; - //! Create a new \ref CBData node. - ASMJIT_API CBData* newDataNode(const void* data, uint32_t size) noexcept; - //! Create a new \ref CBConstPool node. - ASMJIT_API CBConstPool* newConstPool() noexcept; - //! Create a new \ref CBComment node. - ASMJIT_API CBComment* newCommentNode(const char* s, size_t len) noexcept; - - // -------------------------------------------------------------------------- - // [Code-Emitter] - // -------------------------------------------------------------------------- - - ASMJIT_API virtual Label newLabel() override; - ASMJIT_API virtual Label newNamedLabel(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t type = Label::kTypeGlobal, uint32_t parentId = kInvalidValue) override; - ASMJIT_API virtual Error bind(const Label& label) override; - ASMJIT_API virtual Error align(uint32_t mode, uint32_t alignment) override; - ASMJIT_API virtual Error embed(const void* data, uint32_t size) override; - ASMJIT_API virtual Error embedLabel(const Label& label) override; - ASMJIT_API virtual Error embedConstPool(const Label& label, const ConstPool& pool) override; - ASMJIT_API virtual Error comment(const char* s, size_t len = Globals::kInvalidIndex) override; - - // -------------------------------------------------------------------------- - // [Node-Management] - // -------------------------------------------------------------------------- - - //! Add `node` after the current and set current to `node`. - ASMJIT_API CBNode* addNode(CBNode* node) noexcept; - //! Insert `node` after `ref`. - ASMJIT_API CBNode* addAfter(CBNode* node, CBNode* ref) noexcept; - //! Insert `node` before `ref`. - ASMJIT_API CBNode* addBefore(CBNode* node, CBNode* ref) noexcept; - //! Remove `node`. - ASMJIT_API CBNode* removeNode(CBNode* node) noexcept; - //! Remove multiple nodes. - ASMJIT_API void removeNodes(CBNode* first, CBNode* last) noexcept; - - //! Get current node. - //! - //! \note If this method returns null it means that nothing has been - //! emitted yet. - ASMJIT_INLINE CBNode* getCursor() const noexcept { return _cursor; } - //! Set the current node without returning the previous node. - ASMJIT_INLINE void _setCursor(CBNode* node) noexcept { _cursor = node; } - //! Set the current node to `node` and return the previous one. - ASMJIT_API CBNode* setCursor(CBNode* node) noexcept; - - // -------------------------------------------------------------------------- - // [Passes] - // -------------------------------------------------------------------------- - - template - ASMJIT_INLINE T* newPassT() noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(); } - template - ASMJIT_INLINE T* newPassT(P0 p0) noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(p0); } - template - ASMJIT_INLINE T* newPassT(P0 p0, P1 p1) noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(p0, p1); } - - template - ASMJIT_INLINE Error addPassT() noexcept { return addPass(newPassT()); } - template - ASMJIT_INLINE Error addPassT(P0 p0) noexcept { return addPass(newPassT(p0)); } - template - ASMJIT_INLINE Error addPassT(P0 p0, P1 p1) noexcept { return addPass(newPassT(p0, p1)); } - - //! Get a `CBPass` by name. - ASMJIT_API CBPass* getPassByName(const char* name) const noexcept; - //! Add `pass` to the list of passes. - ASMJIT_API Error addPass(CBPass* pass) noexcept; - //! Remove `pass` from the list of passes and delete it. - ASMJIT_API Error deletePass(CBPass* pass) noexcept; - - // -------------------------------------------------------------------------- - // [Serialization] - // -------------------------------------------------------------------------- - - ASMJIT_API virtual Error serialize(CodeEmitter* dst); - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - Zone _cbBaseZone; //!< Base zone used to allocate nodes and `CBPass`. - Zone _cbDataZone; //!< Data zone used to allocate data and names. - Zone _cbPassZone; //!< Zone passed to `CBPass::process()`. - ZoneHeap _cbHeap; //!< ZoneHeap that uses `_cbBaseZone`. - - ZoneVector _cbPasses; //!< Array of `CBPass` objects. - ZoneVector _cbLabels; //!< Maps label indexes to `CBLabel` nodes. - - CBNode* _firstNode; //!< First node of the current section. - CBNode* _lastNode; //!< Last node of the current section. - CBNode* _cursor; //!< Current node (cursor). - - uint32_t _position; //!< Flow-id assigned to each new node. - uint32_t _nodeFlags; //!< Flags assigned to each new node. -}; - -// ============================================================================ -// [asmjit::CBPass] -// ============================================================================ - -//! `CodeBuilder` pass used to code transformations, analysis, and lowering. -class ASMJIT_VIRTAPI CBPass { -public: - ASMJIT_NONCOPYABLE(CBPass); - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_API CBPass(const char* name) noexcept; - ASMJIT_API virtual ~CBPass() noexcept; - - // -------------------------------------------------------------------------- - // [Interface] - // -------------------------------------------------------------------------- - - //! Process the code stored in CodeBuffer `cb`. - //! - //! This is the only function that is called by the `CodeBuilder` to process - //! the code. It passes the CodeBuilder itself (`cb`) and also a zone memory - //! allocator `zone`, which will be reset after the `process()` returns. The - //! allocator should be used for all allocations as it's fast and everything - //! it allocates will be released at once when `process()` returns. - virtual Error process(Zone* zone) noexcept = 0; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE const CodeBuilder* cb() const noexcept { return _cb; } - ASMJIT_INLINE const char* getName() const noexcept { return _name; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - CodeBuilder* _cb; //!< CodeBuilder this pass is assigned to. - const char* _name; //!< Name of the pass. -}; - -// ============================================================================ -// [asmjit::CBNode] -// ============================================================================ - -//! Node (CodeBuilder). -//! -//! Every node represents a building-block used by \ref CodeBuilder. It can be -//! instruction, data, label, comment, directive, or any other high-level -//! representation that can be transformed to the building blocks mentioned. -//! Every class that inherits \ref CodeBuilder can define its own nodes that it -//! can lower to basic nodes. -class CBNode { -public: - ASMJIT_NONCOPYABLE(CBNode) - - // -------------------------------------------------------------------------- - // [Type] - // -------------------------------------------------------------------------- - - //! Type of \ref CBNode. - ASMJIT_ENUM(NodeType) { - kNodeNone = 0, //!< Invalid node (internal, don't use). - - // [CodeBuilder] - kNodeInst = 1, //!< Node is \ref CBInst or \ref CBJump. - kNodeData = 2, //!< Node is \ref CBData. - kNodeAlign = 3, //!< Node is \ref CBAlign. - kNodeLabel = 4, //!< Node is \ref CBLabel. - kNodeLabelData = 5, //!< Node is \ref CBLabelData. - kNodeConstPool = 6, //!< Node is \ref CBConstPool. - kNodeComment = 7, //!< Node is \ref CBComment. - kNodeSentinel = 8, //!< Node is \ref CBSentinel. - - // [CodeCompiler] - kNodeFunc = 16, //!< Node is \ref CCFunc (considered as \ref CBLabel by \ref CodeBuilder). - kNodeFuncExit = 17, //!< Node is \ref CCFuncRet. - kNodeFuncCall = 18, //!< Node is \ref CCFuncCall. - kNodePushArg = 19, //!< Node is \ref CCPushArg. - kNodeHint = 20, //!< Node is \ref CCHint. - - // [UserDefined] - kNodeUser = 32 //!< First id of a user-defined node. - }; - - // -------------------------------------------------------------------------- - // [Flags] - // -------------------------------------------------------------------------- - - ASMJIT_ENUM(Flags) { - //! The node has been translated by the CodeCompiler. - kFlagIsTranslated = 0x0001, - //! If the node can be safely removed (has no effect). - kFlagIsRemovable = 0x0004, - //! If the node is informative only and can be safely removed. - kFlagIsInformative = 0x0008, - - //! If the `CBInst` is a jump. - kFlagIsJmp = 0x0010, - //! If the `CBInst` is a conditional jump. - kFlagIsJcc = 0x0020, - - //! If the `CBInst` is an unconditional jump or conditional jump that is - //! likely to be taken. - kFlagIsTaken = 0x0040, - - //! If the `CBNode` will return from a function. - //! - //! This flag is used by both `CBSentinel` and `CCFuncRet`. - kFlagIsRet = 0x0080, - - //! Whether the instruction is special. - kFlagIsSpecial = 0x0100, - - //! Whether the instruction is an FPU instruction. - kFlagIsFp = 0x0200 - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new \ref CBNode - always use \ref CodeBuilder to allocate nodes. - ASMJIT_INLINE CBNode(CodeBuilder* cb, uint32_t type) noexcept { - _prev = nullptr; - _next = nullptr; - _type = static_cast(type); - _opCount = 0; - _flags = static_cast(cb->_nodeFlags); - _position = cb->_position; - _inlineComment = nullptr; - _passData = nullptr; - } - //! Destroy the `CBNode` instance (NEVER CALLED). - ASMJIT_INLINE ~CBNode() noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - template - ASMJIT_INLINE T* as() noexcept { return static_cast(this); } - template - ASMJIT_INLINE const T* as() const noexcept { return static_cast(this); } - - //! Get previous node in the compiler stream. - ASMJIT_INLINE CBNode* getPrev() const noexcept { return _prev; } - //! Get next node in the compiler stream. - ASMJIT_INLINE CBNode* getNext() const noexcept { return _next; } - - //! Get the node type, see \ref Type. - ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } - //! Get the node flags. - ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } - - //! Get whether the instruction has flag `flag`. - ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (static_cast(_flags) & flag) != 0; } - //! Set node flags to `flags`. - ASMJIT_INLINE void setFlags(uint32_t flags) noexcept { _flags = static_cast(flags); } - //! Add instruction `flags`. - ASMJIT_INLINE void orFlags(uint32_t flags) noexcept { _flags |= static_cast(flags); } - //! And instruction `flags`. - ASMJIT_INLINE void andFlags(uint32_t flags) noexcept { _flags &= static_cast(flags); } - //! Clear instruction `flags`. - ASMJIT_INLINE void andNotFlags(uint32_t flags) noexcept { _flags &= ~static_cast(flags); } - - //! Get whether the node has been translated. - ASMJIT_INLINE bool isTranslated() const noexcept { return hasFlag(kFlagIsTranslated); } - - //! Get whether the node is removable if it's in unreachable code block. - ASMJIT_INLINE bool isRemovable() const noexcept { return hasFlag(kFlagIsRemovable); } - //! Get whether the node is informative only (comment, hint). - ASMJIT_INLINE bool isInformative() const noexcept { return hasFlag(kFlagIsInformative); } - - //! Whether the node is `CBLabel`. - ASMJIT_INLINE bool isLabel() const noexcept { return _type == kNodeLabel; } - //! Whether the `CBInst` node is an unconditional jump. - ASMJIT_INLINE bool isJmp() const noexcept { return hasFlag(kFlagIsJmp); } - //! Whether the `CBInst` node is a conditional jump. - ASMJIT_INLINE bool isJcc() const noexcept { return hasFlag(kFlagIsJcc); } - //! Whether the `CBInst` node is a conditional/unconditional jump. - ASMJIT_INLINE bool isJmpOrJcc() const noexcept { return hasFlag(kFlagIsJmp | kFlagIsJcc); } - //! Whether the `CBInst` node is a return. - ASMJIT_INLINE bool isRet() const noexcept { return hasFlag(kFlagIsRet); } - - //! Get whether the node is `CBInst` and the instruction is special. - ASMJIT_INLINE bool isSpecial() const noexcept { return hasFlag(kFlagIsSpecial); } - //! Get whether the node is `CBInst` and the instruction uses x87-FPU. - ASMJIT_INLINE bool isFp() const noexcept { return hasFlag(kFlagIsFp); } - - ASMJIT_INLINE bool hasPosition() const noexcept { return _position != 0; } - //! Get flow index. - ASMJIT_INLINE uint32_t getPosition() const noexcept { return _position; } - //! Set flow index. - ASMJIT_INLINE void setPosition(uint32_t position) noexcept { _position = position; } - - //! Get if the node has an inline comment. - ASMJIT_INLINE bool hasInlineComment() const noexcept { return _inlineComment != nullptr; } - //! Get an inline comment string. - ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; } - //! Set an inline comment string to `s`. - ASMJIT_INLINE void setInlineComment(const char* s) noexcept { _inlineComment = s; } - //! Set an inline comment string to null. - ASMJIT_INLINE void resetInlineComment() noexcept { _inlineComment = nullptr; } - - //! Get if the node has associated work-data. - ASMJIT_INLINE bool hasPassData() const noexcept { return _passData != nullptr; } - //! Get work-data - data used during processing & transformations. - template - ASMJIT_INLINE T* getPassData() const noexcept { return (T*)_passData; } - //! Set work-data to `data`. - template - ASMJIT_INLINE void setPassData(T* data) noexcept { _passData = (void*)data; } - //! Reset work-data to null. - ASMJIT_INLINE void resetPassData() noexcept { _passData = nullptr; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - CBNode* _prev; //!< Previous node. - CBNode* _next; //!< Next node. - - uint8_t _type; //!< Node type, see \ref NodeType. - uint8_t _opCount; //!< Count of operands or zero. - uint16_t _flags; //!< Flags, different meaning for every type of the node. - uint32_t _position; //!< Flow index. - - const char* _inlineComment; //!< Inline comment or null if not used. - void* _passData; //!< Data used exclusively by the current `CBPass`. -}; - -// ============================================================================ -// [asmjit::CBInst] -// ============================================================================ - -//! Instruction (CodeBuilder). -//! -//! Wraps an instruction with its options and operands. -class CBInst : public CBNode { -public: - ASMJIT_NONCOPYABLE(CBInst) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CBInst` instance. - ASMJIT_INLINE CBInst(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept - : CBNode(cb, kNodeInst) { - - orFlags(kFlagIsRemovable); - _instDetail.instId = static_cast(instId); - _instDetail.options = options; - - _opCount = static_cast(opCount); - _opArray = opArray; - - _updateMemOp(); - } - - //! Destroy the `CBInst` instance (NEVER CALLED). - ASMJIT_INLINE ~CBInst() noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE Inst::Detail& getInstDetail() noexcept { return _instDetail; } - ASMJIT_INLINE const Inst::Detail& getInstDetail() const noexcept { return _instDetail; } - - //! Get the instruction id, see \ref Inst::Id. - ASMJIT_INLINE uint32_t getInstId() const noexcept { return _instDetail.instId; } - //! Set the instruction id to `instId`, see \ref Inst::Id. - ASMJIT_INLINE void setInstId(uint32_t instId) noexcept { _instDetail.instId = instId; } - - //! Whether the instruction is either a jump or a conditional jump likely to be taken. - ASMJIT_INLINE bool isTaken() const noexcept { return hasFlag(kFlagIsTaken); } - - //! Get emit options. - ASMJIT_INLINE uint32_t getOptions() const noexcept { return _instDetail.options; } - //! Set emit options. - ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _instDetail.options = options; } - //! Add emit options. - ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _instDetail.options |= options; } - //! Mask emit options. - ASMJIT_INLINE void andOptions(uint32_t options) noexcept { _instDetail.options &= options; } - //! Clear emit options. - ASMJIT_INLINE void delOptions(uint32_t options) noexcept { _instDetail.options &= ~options; } - - //! Get if the node has an extra register operand. - ASMJIT_INLINE bool hasExtraReg() const noexcept { return _instDetail.hasExtraReg(); } - //! Get extra register operand. - ASMJIT_INLINE RegOnly& getExtraReg() noexcept { return _instDetail.extraReg; } - //! \overload - ASMJIT_INLINE const RegOnly& getExtraReg() const noexcept { return _instDetail.extraReg; } - //! Set extra register operand to `reg`. - ASMJIT_INLINE void setExtraReg(const Reg& reg) noexcept { _instDetail.extraReg.init(reg); } - //! Set extra register operand to `reg`. - ASMJIT_INLINE void setExtraReg(const RegOnly& reg) noexcept { _instDetail.extraReg.init(reg); } - //! Reset extra register operand. - ASMJIT_INLINE void resetExtraReg() noexcept { _instDetail.extraReg.reset(); } - - //! Get operands count. - ASMJIT_INLINE uint32_t getOpCount() const noexcept { return _opCount; } - //! Get operands list. - ASMJIT_INLINE Operand* getOpArray() noexcept { return _opArray; } - //! \overload - ASMJIT_INLINE const Operand* getOpArray() const noexcept { return _opArray; } - - //! Get whether the instruction contains a memory operand. - ASMJIT_INLINE bool hasMemOp() const noexcept { return _memOpIndex != 0xFF; } - //! Get memory operand. - //! - //! NOTE: Can only be called if the instruction has such operand, - //! see `hasMemOp()`. - ASMJIT_INLINE Mem* getMemOp() const noexcept { - ASMJIT_ASSERT(hasMemOp()); - return static_cast(&_opArray[_memOpIndex]); - } - //! \overload - template - ASMJIT_INLINE T* getMemOp() const noexcept { - ASMJIT_ASSERT(hasMemOp()); - return static_cast(&_opArray[_memOpIndex]); - } - - //! Set memory operand index, `0xFF` means no memory operand. - ASMJIT_INLINE void setMemOpIndex(uint32_t index) noexcept { _memOpIndex = static_cast(index); } - //! Reset memory operand index to `0xFF` (no operand). - ASMJIT_INLINE void resetMemOpIndex() noexcept { _memOpIndex = 0xFF; } - - // -------------------------------------------------------------------------- - // [Utils] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void _updateMemOp() noexcept { - Operand* opArray = getOpArray(); - uint32_t opCount = getOpCount(); - - uint32_t i; - for (i = 0; i < opCount; i++) - if (opArray[i].isMem()) - goto Update; - i = 0xFF; - -Update: - setMemOpIndex(i); - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - Inst::Detail _instDetail; //!< Instruction id, options, and extra register. - uint8_t _memOpIndex; //!< \internal - uint8_t _reserved[7]; //!< \internal - Operand* _opArray; //!< Instruction operands. -}; - -// ============================================================================ -// [asmjit::CBInstEx] -// ============================================================================ - -struct CBInstEx : public CBInst { - Operand _op4; - Operand _op5; -}; - -// ============================================================================ -// [asmjit::CBJump] -// ============================================================================ - -//! Asm jump (conditional or direct). -//! -//! Extension of `CBInst` node, which stores more information about the jump. -class CBJump : public CBInst { -public: - ASMJIT_NONCOPYABLE(CBJump) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE CBJump(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept - : CBInst(cb, instId, options, opArray, opCount), - _target(nullptr), - _jumpNext(nullptr) {} - ASMJIT_INLINE ~CBJump() noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE CBLabel* getTarget() const noexcept { return _target; } - ASMJIT_INLINE CBJump* getJumpNext() const noexcept { return _jumpNext; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - CBLabel* _target; //!< Target node. - CBJump* _jumpNext; //!< Next jump to the same target in a single linked-list. -}; - -// ============================================================================ -// [asmjit::CBData] -// ============================================================================ - -//! Asm data (CodeBuilder). -//! -//! Wraps `.data` directive. The node contains data that will be placed at the -//! node's position in the assembler stream. The data is considered to be RAW; -//! no analysis nor byte-order conversion is performed on RAW data. -class CBData : public CBNode { -public: - ASMJIT_NONCOPYABLE(CBData) - enum { kInlineBufferSize = static_cast(64 - sizeof(CBNode) - 4) }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CBData` instance. - ASMJIT_INLINE CBData(CodeBuilder* cb, void* data, uint32_t size) noexcept : CBNode(cb, kNodeData) { - if (size <= kInlineBufferSize) { - if (data) ::memcpy(_buf, data, size); - } - else { - _externalPtr = static_cast(data); - } - _size = size; - } - - //! Destroy the `CBData` instance (NEVER CALLED). - ASMJIT_INLINE ~CBData() noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get size of the data. - uint32_t getSize() const noexcept { return _size; } - //! Get pointer to the data. - uint8_t* getData() const noexcept { return _size <= kInlineBufferSize ? const_cast(_buf) : _externalPtr; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - union { - struct { - uint8_t _buf[kInlineBufferSize]; //!< Embedded data buffer. - uint32_t _size; //!< Size of the data. - }; - struct { - uint8_t* _externalPtr; //!< Pointer to external data. - }; - }; -}; - -// ============================================================================ -// [asmjit::CBAlign] -// ============================================================================ - -//! Align directive (CodeBuilder). -//! -//! Wraps `.align` directive. -class CBAlign : public CBNode { -public: - ASMJIT_NONCOPYABLE(CBAlign) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CBAlign` instance. - ASMJIT_INLINE CBAlign(CodeBuilder* cb, uint32_t mode, uint32_t alignment) noexcept - : CBNode(cb, kNodeAlign), - _mode(mode), - _alignment(alignment) {} - //! Destroy the `CBAlign` instance (NEVER CALLED). - ASMJIT_INLINE ~CBAlign() noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get align mode. - ASMJIT_INLINE uint32_t getMode() const noexcept { return _mode; } - //! Set align mode. - ASMJIT_INLINE void setMode(uint32_t mode) noexcept { _mode = mode; } - - //! Get align offset in bytes. - ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; } - //! Set align offset in bytes to `offset`. - ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint32_t _mode; //!< Align mode, see \ref AlignMode. - uint32_t _alignment; //!< Alignment (in bytes). -}; - -// ============================================================================ -// [asmjit::CBLabel] -// ============================================================================ - -//! Label (CodeBuilder). -class CBLabel : public CBNode { -public: - ASMJIT_NONCOPYABLE(CBLabel) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CBLabel` instance. - ASMJIT_INLINE CBLabel(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept - : CBNode(cb, kNodeLabel), - _id(id), - _numRefs(0), - _from(nullptr) {} - //! Destroy the `CBLabel` instance (NEVER CALLED). - ASMJIT_INLINE ~CBLabel() noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get the label id. - ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } - //! Get the label as `Label` operand. - ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); } - - //! Get first jmp instruction. - ASMJIT_INLINE CBJump* getFrom() const noexcept { return _from; } - - //! Get number of jumps to this target. - ASMJIT_INLINE uint32_t getNumRefs() const noexcept { return _numRefs; } - //! Set number of jumps to this target. - ASMJIT_INLINE void setNumRefs(uint32_t i) noexcept { _numRefs = i; } - - //! Add number of jumps to this target. - ASMJIT_INLINE void addNumRefs(uint32_t i = 1) noexcept { _numRefs += i; } - //! Subtract number of jumps to this target. - ASMJIT_INLINE void subNumRefs(uint32_t i = 1) noexcept { _numRefs -= i; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint32_t _id; //!< Label id. - uint32_t _numRefs; //!< Count of jumps here. - CBJump* _from; //!< Linked-list of nodes that can jump here. -}; - -// ============================================================================ -// [asmjit::CBLabelData] -// ============================================================================ - -class CBLabelData : public CBNode { -public: - ASMJIT_NONCOPYABLE(CBLabelData) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CBLabelData` instance. - ASMJIT_INLINE CBLabelData(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept - : CBNode(cb, kNodeLabelData), - _id(id) {} - - //! Destroy the `CBLabelData` instance (NEVER CALLED). - ASMJIT_INLINE ~CBLabelData() noexcept {} - - // -------------------------------------------------------------------------- - // [Interface] - // -------------------------------------------------------------------------- - - //! Get the label id. - ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } - //! Get the label as `Label` operand. - ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint32_t _id; -}; - -// ============================================================================ -// [asmjit::CBConstPool] -// ============================================================================ - -class CBConstPool : public CBLabel { -public: - ASMJIT_NONCOPYABLE(CBConstPool) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CBConstPool` instance. - ASMJIT_INLINE CBConstPool(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept - : CBLabel(cb, id), - _constPool(&cb->_cbBaseZone) { _type = kNodeConstPool; } - - //! Destroy the `CBConstPool` instance (NEVER CALLED). - ASMJIT_INLINE ~CBConstPool() noexcept {} - - // -------------------------------------------------------------------------- - // [Interface] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE ConstPool& getConstPool() noexcept { return _constPool; } - ASMJIT_INLINE const ConstPool& getConstPool() const noexcept { return _constPool; } - - //! Get whether the constant-pool is empty. - ASMJIT_INLINE bool isEmpty() const noexcept { return _constPool.isEmpty(); } - //! Get the size of the constant-pool in bytes. - ASMJIT_INLINE size_t getSize() const noexcept { return _constPool.getSize(); } - //! Get minimum alignment. - ASMJIT_INLINE size_t getAlignment() const noexcept { return _constPool.getAlignment(); } - - //! See \ref ConstPool::add(). - ASMJIT_INLINE Error add(const void* data, size_t size, size_t& dstOffset) noexcept { - return _constPool.add(data, size, dstOffset); - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - ConstPool _constPool; -}; - -// ============================================================================ -// [asmjit::CBComment] -// ============================================================================ - -//! Comment (CodeBuilder). -class CBComment : public CBNode { -public: - ASMJIT_NONCOPYABLE(CBComment) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CBComment` instance. - ASMJIT_INLINE CBComment(CodeBuilder* cb, const char* comment) noexcept : CBNode(cb, kNodeComment) { - orFlags(kFlagIsRemovable | kFlagIsInformative); - _inlineComment = comment; - } - - //! Destroy the `CBComment` instance (NEVER CALLED). - ASMJIT_INLINE ~CBComment() noexcept {} -}; - -// ============================================================================ -// [asmjit::CBSentinel] -// ============================================================================ - -//! Sentinel (CodeBuilder). -//! -//! Sentinel is a marker that is completely ignored by the code builder. It's -//! used to remember a position in a code as it never gets removed by any pass. -class CBSentinel : public CBNode { -public: - ASMJIT_NONCOPYABLE(CBSentinel) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CBSentinel` instance. - ASMJIT_INLINE CBSentinel(CodeBuilder* cb) noexcept : CBNode(cb, kNodeSentinel) {} - //! Destroy the `CBSentinel` instance (NEVER CALLED). - ASMJIT_INLINE ~CBSentinel() noexcept {} -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // !ASMJIT_DISABLE_BUILDER -#endif // _ASMJIT_BASE_CODEBUILDER_H diff --git a/libs/asmjit/base/codecompiler.cpp b/libs/asmjit/base/codecompiler.cpp deleted file mode 100644 index 582e94a9..00000000 --- a/libs/asmjit/base/codecompiler.cpp +++ /dev/null @@ -1,573 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Guard] -#include "../asmjit_build.h" -#if !defined(ASMJIT_DISABLE_COMPILER) - -// [Dependencies] -#include "../base/assembler.h" -#include "../base/codecompiler.h" -#include "../base/cpuinfo.h" -#include "../base/logging.h" -#include "../base/regalloc_p.h" -#include "../base/utils.h" -#include - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [Constants] -// ============================================================================ - -static const char noName[1] = { '\0' }; - -// ============================================================================ -// [asmjit::CCFuncCall - Arg / Ret] -// ============================================================================ - -bool CCFuncCall::_setArg(uint32_t i, const Operand_& op) noexcept { - if ((i & ~kFuncArgHi) >= _funcDetail.getArgCount()) - return false; - - _args[i] = op; - return true; -} - -bool CCFuncCall::_setRet(uint32_t i, const Operand_& op) noexcept { - if (i >= 2) - return false; - - _ret[i] = op; - return true; -} - -// ============================================================================ -// [asmjit::CodeCompiler - Construction / Destruction] -// ============================================================================ - -CodeCompiler::CodeCompiler() noexcept - : CodeBuilder(), - _func(nullptr), - _vRegZone(4096 - Zone::kZoneOverhead), - _vRegArray(), - _localConstPool(nullptr), - _globalConstPool(nullptr) { - - _type = kTypeCompiler; -} -CodeCompiler::~CodeCompiler() noexcept {} - -// ============================================================================ -// [asmjit::CodeCompiler - Events] -// ============================================================================ - -Error CodeCompiler::onAttach(CodeHolder* code) noexcept { - return Base::onAttach(code); -} - -Error CodeCompiler::onDetach(CodeHolder* code) noexcept { - _func = nullptr; - - _localConstPool = nullptr; - _globalConstPool = nullptr; - - _vRegArray.reset(); - _vRegZone.reset(false); - - return Base::onDetach(code); -} - -// ============================================================================ -// [asmjit::CodeCompiler - Node-Factory] -// ============================================================================ - -CCHint* CodeCompiler::newHintNode(Reg& r, uint32_t hint, uint32_t value) noexcept { - if (!r.isVirtReg()) return nullptr; - - VirtReg* vr = getVirtReg(r); - return newNodeT(vr, hint, value); -} - -// ============================================================================ -// [asmjit::CodeCompiler - Func] -// ============================================================================ - -CCFunc* CodeCompiler::newFunc(const FuncSignature& sign) noexcept { - Error err; - - CCFunc* func = newNodeT(); - if (!func) goto _NoMemory; - - err = registerLabelNode(func); - if (ASMJIT_UNLIKELY(err)) { - // TODO: Calls setLastError, maybe rethink noexcept? - setLastError(err); - return nullptr; - } - - // Create helper nodes. - func->_exitNode = newLabelNode(); - func->_end = newNodeT(); - - if (!func->_exitNode || !func->_end) - goto _NoMemory; - - // Function prototype. - err = func->getDetail().init(sign); - if (err != kErrorOk) { - setLastError(err); - return nullptr; - } - - // If the CodeInfo guarantees higher alignment honor it. - if (_codeInfo.getStackAlignment() > func->_funcDetail._callConv.getNaturalStackAlignment()) - func->_funcDetail._callConv.setNaturalStackAlignment(_codeInfo.getStackAlignment()); - - // Allocate space for function arguments. - func->_args = nullptr; - if (func->getArgCount() != 0) { - func->_args = _cbHeap.allocT(func->getArgCount() * sizeof(VirtReg*)); - if (!func->_args) goto _NoMemory; - - ::memset(func->_args, 0, func->getArgCount() * sizeof(VirtReg*)); - } - - return func; - -_NoMemory: - setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - return nullptr; -} - -CCFunc* CodeCompiler::addFunc(CCFunc* func) { - ASMJIT_ASSERT(_func == nullptr); - _func = func; - - addNode(func); // Function node. - CBNode* cursor = getCursor(); // {CURSOR}. - addNode(func->getExitNode()); // Function exit label. - addNode(func->getEnd()); // Function end marker. - - _setCursor(cursor); - return func; -} - -CCFunc* CodeCompiler::addFunc(const FuncSignature& sign) { - CCFunc* func = newFunc(sign); - - if (!func) { - setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - return nullptr; - } - - return addFunc(func); -} - -CBSentinel* CodeCompiler::endFunc() { - CCFunc* func = getFunc(); - if (!func) { - // TODO: - return nullptr; - } - - // Add the local constant pool at the end of the function (if exists). - if (_localConstPool) { - setCursor(func->getEnd()->getPrev()); - addNode(_localConstPool); - _localConstPool = nullptr; - } - - // Mark as finished. - func->_isFinished = true; - _func = nullptr; - - CBSentinel* end = func->getEnd(); - setCursor(end); - return end; -} - -// ============================================================================ -// [asmjit::CodeCompiler - Ret] -// ============================================================================ - -CCFuncRet* CodeCompiler::newRet(const Operand_& o0, const Operand_& o1) noexcept { - CCFuncRet* node = newNodeT(o0, o1); - if (!node) { - setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - return nullptr; - } - return node; -} - -CCFuncRet* CodeCompiler::addRet(const Operand_& o0, const Operand_& o1) noexcept { - CCFuncRet* node = newRet(o0, o1); - if (!node) return nullptr; - return static_cast(addNode(node)); -} - -// ============================================================================ -// [asmjit::CodeCompiler - Call] -// ============================================================================ - -CCFuncCall* CodeCompiler::newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept { - Error err; - uint32_t nArgs; - - CCFuncCall* node = _cbHeap.allocT(sizeof(CCFuncCall) + sizeof(Operand)); - Operand* opArray = reinterpret_cast(reinterpret_cast(node) + sizeof(CCFuncCall)); - - if (ASMJIT_UNLIKELY(!node)) - goto _NoMemory; - - opArray[0].copyFrom(o0); - new (node) CCFuncCall(this, instId, 0, opArray, 1); - - if ((err = node->getDetail().init(sign)) != kErrorOk) { - setLastError(err); - return nullptr; - } - - // If there are no arguments skip the allocation. - if ((nArgs = sign.getArgCount()) == 0) - return node; - - node->_args = static_cast(_cbHeap.alloc(nArgs * sizeof(Operand))); - if (!node->_args) goto _NoMemory; - - ::memset(node->_args, 0, nArgs * sizeof(Operand)); - return node; - -_NoMemory: - setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - return nullptr; -} - -CCFuncCall* CodeCompiler::addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept { - CCFuncCall* node = newCall(instId, o0, sign); - if (!node) return nullptr; - return static_cast(addNode(node)); -} - -// ============================================================================ -// [asmjit::CodeCompiler - Vars] -// ============================================================================ - -Error CodeCompiler::setArg(uint32_t argIndex, const Reg& r) { - CCFunc* func = getFunc(); - - if (!func) - return setLastError(DebugUtils::errored(kErrorInvalidState)); - - if (!isVirtRegValid(r)) - return setLastError(DebugUtils::errored(kErrorInvalidVirtId)); - - VirtReg* vr = getVirtReg(r); - func->setArg(argIndex, vr); - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::CodeCompiler - Hint] -// ============================================================================ - -Error CodeCompiler::_hint(Reg& r, uint32_t hint, uint32_t value) { - if (!r.isVirtReg()) return kErrorOk; - - CCHint* node = newHintNode(r, hint, value); - if (!node) return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - - addNode(node); - return kErrorOk; -} - -// ============================================================================ -// [asmjit::CodeCompiler - Vars] -// ============================================================================ - -VirtReg* CodeCompiler::newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept { - size_t index = _vRegArray.getLength(); - if (ASMJIT_UNLIKELY(index > Operand::kPackedIdCount)) - return nullptr; - - VirtReg* vreg; - if (_vRegArray.willGrow(&_cbHeap, 1) != kErrorOk || !(vreg = _vRegZone.allocZeroedT())) - return nullptr; - - vreg->_id = Operand::packId(static_cast(index)); - vreg->_regInfo._signature = signature; - vreg->_name = noName; - -#if !defined(ASMJIT_DISABLE_LOGGING) - if (name && name[0] != '\0') - vreg->_name = static_cast(_cbDataZone.dup(name, ::strlen(name), true)); -#endif // !ASMJIT_DISABLE_LOGGING - - vreg->_size = TypeId::sizeOf(typeId); - vreg->_typeId = typeId; - vreg->_alignment = static_cast(std::min(vreg->_size, 64)); - vreg->_priority = 10; - - // The following are only used by `RAPass`. - vreg->_raId = kInvalidValue; - vreg->_state = VirtReg::kStateNone; - vreg->_physId = Globals::kInvalidRegId; - - _vRegArray.appendUnsafe(vreg); - return vreg; -} - -Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* name) { - RegInfo regInfo; - - Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo); - if (ASMJIT_UNLIKELY(err)) return setLastError(err); - - VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name); - if (ASMJIT_UNLIKELY(!vReg)) { - out.reset(); - return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - } - - out._initReg(regInfo.getSignature(), vReg->getId()); - return kErrorOk; -} - -Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap) { - StringBuilderTmp<256> sb; - sb.appendFormatVA(nameFmt, ap); - return _newReg(out, typeId, sb.getData()); -} - -Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* name) { - RegInfo regInfo; - uint32_t typeId; - - if (isVirtRegValid(ref)) { - VirtReg* vRef = getVirtReg(ref); - typeId = vRef->getTypeId(); - - // NOTE: It's possible to cast one register type to another if it's the - // same register kind. However, VirtReg always contains the TypeId that - // was used to create the register. This means that in some cases we may - // end up having different size of `ref` and `vRef`. In such case we - // adjust the TypeId to match the `ref` register type instead of the - // original register type, which should be the expected behavior. - uint32_t typeSize = TypeId::sizeOf(typeId); - uint32_t refSize = ref.getSize(); - - if (typeSize != refSize) { - if (TypeId::isInt(typeId)) { - // GP register - change TypeId to match `ref`, but keep sign of `vRef`. - switch (refSize) { - case 1: typeId = TypeId::kI8 | (typeId & 1); break; - case 2: typeId = TypeId::kI16 | (typeId & 1); break; - case 4: typeId = TypeId::kI32 | (typeId & 1); break; - case 8: typeId = TypeId::kI64 | (typeId & 1); break; - default: typeId = TypeId::kVoid; break; - } - } - else if (TypeId::isMmx(typeId)) { - // MMX register - always use 64-bit. - typeId = TypeId::kMmx64; - } - else if (TypeId::isMask(typeId)) { - // Mask register - change TypeId to match `ref` size. - switch (refSize) { - case 1: typeId = TypeId::kMask8; break; - case 2: typeId = TypeId::kMask16; break; - case 4: typeId = TypeId::kMask32; break; - case 8: typeId = TypeId::kMask64; break; - default: typeId = TypeId::kVoid; break; - } - } - else { - // VEC register - change TypeId to match `ref` size, keep vector metadata. - uint32_t elementTypeId = TypeId::elementOf(typeId); - - switch (refSize) { - case 16: typeId = TypeId::_kVec128Start + (elementTypeId - TypeId::kI8); break; - case 32: typeId = TypeId::_kVec256Start + (elementTypeId - TypeId::kI8); break; - case 64: typeId = TypeId::_kVec512Start + (elementTypeId - TypeId::kI8); break; - default: typeId = TypeId::kVoid; break; - } - } - - if (typeId == TypeId::kVoid) - return setLastError(DebugUtils::errored(kErrorInvalidState)); - } - } - else { - typeId = ref.getType(); - } - - Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo); - if (ASMJIT_UNLIKELY(err)) return setLastError(err); - - VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name); - if (ASMJIT_UNLIKELY(!vReg)) { - out.reset(); - return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - } - - out._initReg(regInfo.getSignature(), vReg->getId()); - return kErrorOk; -} - -Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap) { - StringBuilderTmp<256> sb; - sb.appendFormatVA(nameFmt, ap); - return _newReg(out, ref, sb.getData()); -} - -Error CodeCompiler::_newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name) { - if (size == 0) - return setLastError(DebugUtils::errored(kErrorInvalidArgument)); - - if (alignment == 0) alignment = 1; - if (!Utils::isPowerOf2(alignment)) - return setLastError(DebugUtils::errored(kErrorInvalidArgument)); - - if (alignment > 64) alignment = 64; - - VirtReg* vReg = newVirtReg(0, 0, name); - if (ASMJIT_UNLIKELY(!vReg)) { - out.reset(); - return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - } - - vReg->_size = size; - vReg->_isStack = true; - vReg->_alignment = static_cast(alignment); - - // Set the memory operand to GPD/GPQ and its id to VirtReg. - out = Mem(Init, _nativeGpReg.getType(), vReg->getId(), Reg::kRegNone, kInvalidValue, 0, 0, Mem::kSignatureMemRegHomeFlag); - return kErrorOk; -} - -Error CodeCompiler::_newConst(Mem& out, uint32_t scope, const void* data, size_t size) { - CBConstPool** pPool; - if (scope == kConstScopeLocal) - pPool = &_localConstPool; - else if (scope == kConstScopeGlobal) - pPool = &_globalConstPool; - else - return setLastError(DebugUtils::errored(kErrorInvalidArgument)); - - if (!*pPool && !(*pPool = newConstPool())) - return setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - - CBConstPool* pool = *pPool; - size_t off; - - Error err = pool->add(data, size, off); - if (ASMJIT_UNLIKELY(err)) return setLastError(err); - - out = Mem(Init, - Label::kLabelTag, // Base type. - pool->getId(), // Base id. - 0, // Index type. - kInvalidValue, // Index id. - static_cast(off), // Offset. - static_cast(size), // Size. - 0); // Flags. - return kErrorOk; -} - -Error CodeCompiler::alloc(Reg& reg) { - if (!reg.isVirtReg()) return kErrorOk; - return _hint(reg, CCHint::kHintAlloc, kInvalidValue); -} - -Error CodeCompiler::alloc(Reg& reg, uint32_t physId) { - if (!reg.isVirtReg()) return kErrorOk; - return _hint(reg, CCHint::kHintAlloc, physId); -} - -Error CodeCompiler::alloc(Reg& reg, const Reg& physReg) { - if (!reg.isVirtReg()) return kErrorOk; - return _hint(reg, CCHint::kHintAlloc, physReg.getId()); -} - -Error CodeCompiler::save(Reg& reg) { - if (!reg.isVirtReg()) return kErrorOk; - return _hint(reg, CCHint::kHintSave, kInvalidValue); -} - -Error CodeCompiler::spill(Reg& reg) { - if (!reg.isVirtReg()) return kErrorOk; - return _hint(reg, CCHint::kHintSpill, kInvalidValue); -} - -Error CodeCompiler::unuse(Reg& reg) { - if (!reg.isVirtReg()) return kErrorOk; - return _hint(reg, CCHint::kHintUnuse, kInvalidValue); -} - -uint32_t CodeCompiler::getPriority(Reg& reg) const { - if (!reg.isVirtReg()) return 0; - return getVirtRegById(reg.getId())->getPriority(); -} - -void CodeCompiler::setPriority(Reg& reg, uint32_t priority) { - if (!reg.isVirtReg()) return; - if (priority > 255) priority = 255; - - VirtReg* vreg = getVirtRegById(reg.getId()); - if (vreg) vreg->_priority = static_cast(priority); -} - -bool CodeCompiler::getSaveOnUnuse(Reg& reg) const { - if (!reg.isVirtReg()) return false; - - VirtReg* vreg = getVirtRegById(reg.getId()); - return static_cast(vreg->_saveOnUnuse); -} - -void CodeCompiler::setSaveOnUnuse(Reg& reg, bool value) { - if (!reg.isVirtReg()) return; - - VirtReg* vreg = getVirtRegById(reg.getId()); - if (!vreg) return; - - vreg->_saveOnUnuse = value; -} - -void CodeCompiler::rename(Reg& reg, const char* fmt, ...) { - if (!reg.isVirtReg()) return; - - VirtReg* vreg = getVirtRegById(reg.getId()); - if (!vreg) return; - - vreg->_name = noName; - if (fmt && fmt[0] != '\0') { - char buf[64]; - - va_list ap; - va_start(ap, fmt); - - vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap); - buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0'; - - vreg->_name = static_cast(_cbDataZone.dup(buf, ::strlen(buf), true)); - va_end(ap); - } -} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // !ASMJIT_DISABLE_COMPILER diff --git a/libs/asmjit/base/codecompiler.h b/libs/asmjit/base/codecompiler.h deleted file mode 100644 index 44b9644b..00000000 --- a/libs/asmjit/base/codecompiler.h +++ /dev/null @@ -1,738 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_CODECOMPILER_H -#define _ASMJIT_BASE_CODECOMPILER_H - -#include "../asmjit_build.h" -#if !defined(ASMJIT_DISABLE_COMPILER) - -// [Dependencies] -#include "../base/assembler.h" -#include "../base/codebuilder.h" -#include "../base/constpool.h" -#include "../base/func.h" -#include "../base/operand.h" -#include "../base/utils.h" -#include "../base/zone.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -struct VirtReg; -struct TiedReg; -struct RAState; -struct RACell; - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::ConstScope] -// ============================================================================ - -//! Scope of the constant. -ASMJIT_ENUM(ConstScope) { - //! Local constant, always embedded right after the current function. - kConstScopeLocal = 0, - //! Global constant, embedded at the end of the currently compiled code. - kConstScopeGlobal = 1 -}; - -// ============================================================================ -// [asmjit::VirtReg] -// ============================================================================ - -//! Virtual register data (CodeCompiler). -struct VirtReg { - //! A state of a virtual register (used during register allocation). - ASMJIT_ENUM(State) { - kStateNone = 0, //!< Not allocated, not used. - kStateReg = 1, //!< Allocated in register. - kStateMem = 2 //!< Allocated in memory or spilled. - }; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get the virtual-register id. - ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } - //! Get virtual-register's name. - ASMJIT_INLINE const char* getName() const noexcept { return _name; } - - //! Get a physical register type. - ASMJIT_INLINE uint32_t getType() const noexcept { return _regInfo.getType(); } - //! Get a physical register kind. - ASMJIT_INLINE uint32_t getKind() const noexcept { return _regInfo.getKind(); } - //! Get a physical register size. - ASMJIT_INLINE uint32_t getRegSize() const noexcept { return _regInfo.getSize(); } - //! Get a register signature of this virtual register. - ASMJIT_INLINE uint32_t getSignature() const noexcept { return _regInfo.getSignature(); } - - //! Get a register's type-id, see \ref TypeId. - ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _typeId; } - - //! Get virtual-register's size. - ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; } - //! Get virtual-register's alignment. - ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; } - - //! Get the virtual-register priority, used by compiler to decide which variable to spill. - ASMJIT_INLINE uint32_t getPriority() const noexcept { return _priority; } - //! Set the virtual-register priority. - ASMJIT_INLINE void setPriority(uint32_t priority) noexcept { - ASMJIT_ASSERT(priority <= 0xFF); - _priority = static_cast(priority); - } - - //! Get variable state, only used by `RAPass`. - ASMJIT_INLINE uint32_t getState() const noexcept { return _state; } - //! Set variable state, only used by `RAPass`. - ASMJIT_INLINE void setState(uint32_t state) { - ASMJIT_ASSERT(state <= 0xFF); - _state = static_cast(state); - } - - //! Get register index. - ASMJIT_INLINE uint32_t getPhysId() const noexcept { return _physId; } - //! Set register index. - ASMJIT_INLINE void setPhysId(uint32_t physId) { - ASMJIT_ASSERT(physId <= Globals::kInvalidRegId); - _physId = static_cast(physId); - } - //! Reset register index. - ASMJIT_INLINE void resetPhysId() { - _physId = static_cast(Globals::kInvalidRegId); - } - - //! Get home registers mask. - ASMJIT_INLINE uint32_t getHomeMask() const { return _homeMask; } - //! Add a home register index to the home registers mask. - ASMJIT_INLINE void addHomeId(uint32_t physId) { _homeMask |= Utils::mask(physId); } - - ASMJIT_INLINE bool isFixed() const noexcept { return static_cast(_isFixed); } - - //! Get whether the VirtReg is only memory allocated on the stack. - ASMJIT_INLINE bool isStack() const noexcept { return static_cast(_isStack); } - - //! Get whether to save variable when it's unused (spill). - ASMJIT_INLINE bool saveOnUnuse() const noexcept { return static_cast(_saveOnUnuse); } - - //! Get whether the variable was changed. - ASMJIT_INLINE bool isModified() const noexcept { return static_cast(_modified); } - //! Set whether the variable was changed. - ASMJIT_INLINE void setModified(bool modified) noexcept { _modified = modified; } - - //! Get home memory offset. - ASMJIT_INLINE int32_t getMemOffset() const noexcept { return _memOffset; } - //! Set home memory offset. - ASMJIT_INLINE void setMemOffset(int32_t offset) noexcept { _memOffset = offset; } - - //! Get home memory cell. - ASMJIT_INLINE RACell* getMemCell() const noexcept { return _memCell; } - //! Set home memory cell. - ASMJIT_INLINE void setMemCell(RACell* cell) noexcept { _memCell = cell; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint32_t _id; //!< Virtual register id. - RegInfo _regInfo; //!< Physical register info & signature. - const char* _name; //!< Virtual name (user provided). - uint32_t _size; //!< Virtual size (can be smaller than `regInfo._size`). - uint8_t _typeId; //!< Type-id. - uint8_t _alignment; //!< Register's natural alignment (for spilling). - uint8_t _priority; //!< Allocation priority (hint for RAPass that can be ignored). - uint8_t _isFixed : 1; //!< True if this is a fixed register, never reallocated. - uint8_t _isStack : 1; //!< True if the virtual register is only used as a stack. - uint8_t _isMaterialized : 1; //!< Register is constant that is easily created by a single instruction. - uint8_t _saveOnUnuse : 1; //!< Save on unuse (at end of the variable scope). - - // ------------------------------------------------------------------------- - // The following members are used exclusively by RAPass. They are initialized - // when the VirtReg is created and then changed during RAPass. - // ------------------------------------------------------------------------- - - uint32_t _raId; //!< Register allocator work-id (used by RAPass). - int32_t _memOffset; //!< Home memory offset. - uint32_t _homeMask; //!< Mask of all registers variable has been allocated to. - - uint8_t _state; //!< Variable state (connected with actual `RAState)`. - uint8_t _physId; //!< Actual register index (only used by `RAPass)`, during translate. - uint8_t _modified; //!< Whether variable was changed (connected with actual `RAState)`. - - RACell* _memCell; //!< Home memory cell, used by `RAPass` (initially nullptr). - - //! Temporary link to TiedReg* used by the `RAPass` used in - //! various phases, but always set back to nullptr when finished. - //! - //! This temporary data is designed to be used by algorithms that need to - //! store some data into variables themselves during compilation. But it's - //! expected that after variable is compiled & translated the data is set - //! back to zero/null. Initial value is nullptr. - TiedReg* _tied; -}; - -// ============================================================================ -// [asmjit::CCHint] -// ============================================================================ - -//! Hint for register allocator (CodeCompiler). -class CCHint : public CBNode { -public: - ASMJIT_NONCOPYABLE(CCHint) - - //! Hint type. - ASMJIT_ENUM(Hint) { - //! Alloc to physical reg. - kHintAlloc = 0, - //! Spill to memory. - kHintSpill = 1, - //! Save if modified. - kHintSave = 2, - //! Save if modified and mark it as unused. - kHintSaveAndUnuse = 3, - //! Mark as unused. - kHintUnuse = 4 - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CCHint` instance. - ASMJIT_INLINE CCHint(CodeBuilder* cb, VirtReg* vreg, uint32_t hint, uint32_t value) noexcept : CBNode(cb, kNodeHint) { - orFlags(kFlagIsRemovable | kFlagIsInformative); - _vreg = vreg; - _hint = hint; - _value = value; - } - - //! Destroy the `CCHint` instance (NEVER CALLED). - ASMJIT_INLINE ~CCHint() noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get variable. - ASMJIT_INLINE VirtReg* getVReg() const noexcept { return _vreg; } - - //! Get hint it, see \ref Hint. - ASMJIT_INLINE uint32_t getHint() const noexcept { return _hint; } - //! Set hint it, see \ref Hint. - ASMJIT_INLINE void setHint(uint32_t hint) noexcept { _hint = hint; } - - //! Get hint value. - ASMJIT_INLINE uint32_t getValue() const noexcept { return _value; } - //! Set hint value. - ASMJIT_INLINE void setValue(uint32_t value) noexcept { _value = value; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Variable. - VirtReg* _vreg; - //! Hint id. - uint32_t _hint; - //! Value. - uint32_t _value; -}; - -// ============================================================================ -// [asmjit::CCFunc] -// ============================================================================ - -//! Function entry (CodeCompiler). -class CCFunc : public CBLabel { -public: - ASMJIT_NONCOPYABLE(CCFunc) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CCFunc` instance. - //! - //! Always use `CodeCompiler::addFunc()` to create \ref CCFunc. - ASMJIT_INLINE CCFunc(CodeBuilder* cb) noexcept - : CBLabel(cb), - _funcDetail(), - _frameInfo(), - _exitNode(nullptr), - _end(nullptr), - _args(nullptr), - _isFinished(false) { - - _type = kNodeFunc; - } - - //! Destroy the `CCFunc` instance (NEVER CALLED). - ASMJIT_INLINE ~CCFunc() noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get function exit `CBLabel`. - ASMJIT_INLINE CBLabel* getExitNode() const noexcept { return _exitNode; } - //! Get function exit label. - ASMJIT_INLINE Label getExitLabel() const noexcept { return _exitNode->getLabel(); } - - //! Get "End of Func" sentinel. - ASMJIT_INLINE CBSentinel* getEnd() const noexcept { return _end; } - - //! Get function declaration. - ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; } - //! Get function declaration. - ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; } - - //! Get function declaration. - ASMJIT_INLINE FuncFrameInfo& getFrameInfo() noexcept { return _frameInfo; } - //! Get function declaration. - ASMJIT_INLINE const FuncFrameInfo& getFrameInfo() const noexcept { return _frameInfo; } - - //! Get arguments count. - ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _funcDetail.getArgCount(); } - //! Get returns count. - ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _funcDetail.getRetCount(); } - - //! Get arguments list. - ASMJIT_INLINE VirtReg** getArgs() const noexcept { return _args; } - - //! Get argument at `i`. - ASMJIT_INLINE VirtReg* getArg(uint32_t i) const noexcept { - ASMJIT_ASSERT(i < getArgCount()); - return _args[i]; - } - - //! Set argument at `i`. - ASMJIT_INLINE void setArg(uint32_t i, VirtReg* vreg) noexcept { - ASMJIT_ASSERT(i < getArgCount()); - _args[i] = vreg; - } - - //! Reset argument at `i`. - ASMJIT_INLINE void resetArg(uint32_t i) noexcept { - ASMJIT_ASSERT(i < getArgCount()); - _args[i] = nullptr; - } - - ASMJIT_INLINE uint32_t getAttributes() const noexcept { return _frameInfo.getAttributes(); } - ASMJIT_INLINE void addAttributes(uint32_t attrs) noexcept { _frameInfo.addAttributes(attrs); } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - FuncDetail _funcDetail; //!< Function detail. - FuncFrameInfo _frameInfo; //!< Function frame information. - - CBLabel* _exitNode; //!< Function exit. - CBSentinel* _end; //!< Function end. - - VirtReg** _args; //!< Arguments array as `VirtReg`. - - //! Function was finished by `Compiler::endFunc()`. - uint8_t _isFinished; -}; - -// ============================================================================ -// [asmjit::CCFuncRet] -// ============================================================================ - -//! Function return (CodeCompiler). -class CCFuncRet : public CBNode { -public: - ASMJIT_NONCOPYABLE(CCFuncRet) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CCFuncRet` instance. - ASMJIT_INLINE CCFuncRet(CodeBuilder* cb, const Operand_& o0, const Operand_& o1) noexcept : CBNode(cb, kNodeFuncExit) { - orFlags(kFlagIsRet); - _ret[0].copyFrom(o0); - _ret[1].copyFrom(o1); - } - - //! Destroy the `CCFuncRet` instance (NEVER CALLED). - ASMJIT_INLINE ~CCFuncRet() noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get the first return operand. - ASMJIT_INLINE Operand& getFirst() noexcept { return static_cast(_ret[0]); } - //! \overload - ASMJIT_INLINE const Operand& getFirst() const noexcept { return static_cast(_ret[0]); } - - //! Get the second return operand. - ASMJIT_INLINE Operand& getSecond() noexcept { return static_cast(_ret[1]); } - //! \overload - ASMJIT_INLINE const Operand& getSecond() const noexcept { return static_cast(_ret[1]); } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Return operands. - Operand_ _ret[2]; -}; - -// ============================================================================ -// [asmjit::CCFuncCall] -// ============================================================================ - -//! Function call (CodeCompiler). -class CCFuncCall : public CBInst { -public: - ASMJIT_NONCOPYABLE(CCFuncCall) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CCFuncCall` instance. - ASMJIT_INLINE CCFuncCall(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept - : CBInst(cb, instId, options, opArray, opCount), - _funcDetail(), - _args(nullptr) { - - _type = kNodeFuncCall; - _ret[0].reset(); - _ret[1].reset(); - orFlags(kFlagIsRemovable); - } - - //! Destroy the `CCFuncCall` instance (NEVER CALLED). - ASMJIT_INLINE ~CCFuncCall() noexcept {} - - // -------------------------------------------------------------------------- - // [Signature] - // -------------------------------------------------------------------------- - - //! Set function signature. - ASMJIT_INLINE Error setSignature(const FuncSignature& sign) noexcept { - return _funcDetail.init(sign); - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get function declaration. - ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; } - //! Get function declaration. - ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; } - - //! Get target operand. - ASMJIT_INLINE Operand& getTarget() noexcept { return static_cast(_opArray[0]); } - //! \overload - ASMJIT_INLINE const Operand& getTarget() const noexcept { return static_cast(_opArray[0]); } - - //! Get return at `i`. - ASMJIT_INLINE Operand& getRet(uint32_t i = 0) noexcept { - ASMJIT_ASSERT(i < 2); - return static_cast(_ret[i]); - } - //! \overload - ASMJIT_INLINE const Operand& getRet(uint32_t i = 0) const noexcept { - ASMJIT_ASSERT(i < 2); - return static_cast(_ret[i]); - } - - //! Get argument at `i`. - ASMJIT_INLINE Operand& getArg(uint32_t i) noexcept { - ASMJIT_ASSERT(i < kFuncArgCountLoHi); - return static_cast(_args[i]); - } - //! \overload - ASMJIT_INLINE const Operand& getArg(uint32_t i) const noexcept { - ASMJIT_ASSERT(i < kFuncArgCountLoHi); - return static_cast(_args[i]); - } - - //! Set argument at `i` to `op`. - ASMJIT_API bool _setArg(uint32_t i, const Operand_& op) noexcept; - //! Set return at `i` to `op`. - ASMJIT_API bool _setRet(uint32_t i, const Operand_& op) noexcept; - - //! Set argument at `i` to `reg`. - ASMJIT_INLINE bool setArg(uint32_t i, const Reg& reg) noexcept { return _setArg(i, reg); } - //! Set argument at `i` to `imm`. - ASMJIT_INLINE bool setArg(uint32_t i, const Imm& imm) noexcept { return _setArg(i, imm); } - - //! Set return at `i` to `var`. - ASMJIT_INLINE bool setRet(uint32_t i, const Reg& reg) noexcept { return _setRet(i, reg); } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - FuncDetail _funcDetail; //!< Function detail. - Operand_ _ret[2]; //!< Return. - Operand_* _args; //!< Arguments. -}; - -// ============================================================================ -// [asmjit::CCPushArg] -// ============================================================================ - -//! Push argument before a function call (CodeCompiler). -class CCPushArg : public CBNode { -public: - ASMJIT_NONCOPYABLE(CCPushArg) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CCPushArg` instance. - ASMJIT_INLINE CCPushArg(CodeBuilder* cb, CCFuncCall* call, VirtReg* src, VirtReg* cvt) noexcept - : CBNode(cb, kNodePushArg), - _call(call), - _src(src), - _cvt(cvt), - _args(0) { - orFlags(kFlagIsRemovable); - } - - //! Destroy the `CCPushArg` instance. - ASMJIT_INLINE ~CCPushArg() noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get the associated function-call. - ASMJIT_INLINE CCFuncCall* getCall() const noexcept { return _call; } - //! Get source variable. - ASMJIT_INLINE VirtReg* getSrcReg() const noexcept { return _src; } - //! Get conversion variable. - ASMJIT_INLINE VirtReg* getCvtReg() const noexcept { return _cvt; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - CCFuncCall* _call; //!< Associated `CCFuncCall`. - VirtReg* _src; //!< Source variable. - VirtReg* _cvt; //!< Temporary variable used for conversion (or null). - uint32_t _args; //!< Affected arguments bit-array. -}; - -// ============================================================================ -// [asmjit::CodeCompiler] -// ============================================================================ - -//! Code emitter that uses virtual registers and performs register allocation. -//! -//! Compiler is a high-level code-generation tool that provides register -//! allocation and automatic handling of function calling conventions. It was -//! primarily designed for merging multiple parts of code into a function -//! without worrying about registers and function calling conventions. -//! -//! CodeCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit -//! code at the same time. -//! -//! CodeCompiler is based on CodeBuilder and contains all the features it -//! provides. It means that the code it stores can be modified (removed, added, -//! injected) and analyzed. When the code is finalized the compiler can emit -//! the code into an Assembler to translate the abstract representation into a -//! machine code. -class ASMJIT_VIRTAPI CodeCompiler : public CodeBuilder { -public: - ASMJIT_NONCOPYABLE(CodeCompiler) - typedef CodeBuilder Base; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `CodeCompiler` instance. - ASMJIT_API CodeCompiler() noexcept; - //! Destroy the `CodeCompiler` instance. - ASMJIT_API virtual ~CodeCompiler() noexcept; - - // -------------------------------------------------------------------------- - // [Events] - // -------------------------------------------------------------------------- - - ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override; - ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override; - - // -------------------------------------------------------------------------- - // [Node-Factory] - // -------------------------------------------------------------------------- - - //! \internal - //! - //! Create a new `CCHint`. - ASMJIT_API CCHint* newHintNode(Reg& reg, uint32_t hint, uint32_t value) noexcept; - - // -------------------------------------------------------------------------- - // [Func] - // -------------------------------------------------------------------------- - - //! Get the current function. - ASMJIT_INLINE CCFunc* getFunc() const noexcept { return _func; } - - //! Create a new `CCFunc`. - ASMJIT_API CCFunc* newFunc(const FuncSignature& sign) noexcept; - //! Add a function `node` to the stream. - ASMJIT_API CCFunc* addFunc(CCFunc* func); - //! Add a new function. - ASMJIT_API CCFunc* addFunc(const FuncSignature& sign); - //! Emit a sentinel that marks the end of the current function. - ASMJIT_API CBSentinel* endFunc(); - - // -------------------------------------------------------------------------- - // [Ret] - // -------------------------------------------------------------------------- - - //! Create a new `CCFuncRet`. - ASMJIT_API CCFuncRet* newRet(const Operand_& o0, const Operand_& o1) noexcept; - //! Add a new `CCFuncRet`. - ASMJIT_API CCFuncRet* addRet(const Operand_& o0, const Operand_& o1) noexcept; - - // -------------------------------------------------------------------------- - // [Call] - // -------------------------------------------------------------------------- - - //! Create a new `CCFuncCall`. - ASMJIT_API CCFuncCall* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept; - //! Add a new `CCFuncCall`. - ASMJIT_API CCFuncCall* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept; - - // -------------------------------------------------------------------------- - // [Args] - // -------------------------------------------------------------------------- - - //! Set a function argument at `argIndex` to `reg`. - ASMJIT_API Error setArg(uint32_t argIndex, const Reg& reg); - - // -------------------------------------------------------------------------- - // [Hint] - // -------------------------------------------------------------------------- - - //! Emit a new hint (purely informational node). - ASMJIT_API Error _hint(Reg& reg, uint32_t hint, uint32_t value); - - // -------------------------------------------------------------------------- - // [VirtReg / Stack] - // -------------------------------------------------------------------------- - - //! Create a new virtual register representing the given `vti` and `signature`. - //! - //! This function accepts either register type representing a machine-specific - //! register, like `X86Reg`, or RegTag representation, which represents - //! machine independent register, and from the machine-specific register - //! is deduced. - ASMJIT_API VirtReg* newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept; - - ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* name); - ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap); - - ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* name); - ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap); - - ASMJIT_API Error _newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name); - ASMJIT_API Error _newConst(Mem& out, uint32_t scope, const void* data, size_t size); - - // -------------------------------------------------------------------------- - // [VirtReg] - // -------------------------------------------------------------------------- - - //! Get whether the virtual register `r` is valid. - ASMJIT_INLINE bool isVirtRegValid(const Reg& reg) const noexcept { - return isVirtRegValid(reg.getId()); - } - //! \overload - ASMJIT_INLINE bool isVirtRegValid(uint32_t id) const noexcept { - size_t index = Operand::unpackId(id); - return index < _vRegArray.getLength(); - } - - //! Get \ref VirtReg associated with the given `r`. - ASMJIT_INLINE VirtReg* getVirtReg(const Reg& reg) const noexcept { - return getVirtRegById(reg.getId()); - } - //! Get \ref VirtReg associated with the given `id`. - ASMJIT_INLINE VirtReg* getVirtRegById(uint32_t id) const noexcept { - ASMJIT_ASSERT(id != kInvalidValue); - size_t index = Operand::unpackId(id); - - ASMJIT_ASSERT(index < _vRegArray.getLength()); - return _vRegArray[index]; - } - - //! Get an array of all virtual registers managed by CodeCompiler. - ASMJIT_INLINE const ZoneVector& getVirtRegArray() const noexcept { return _vRegArray; } - - //! Alloc a virtual register `reg`. - ASMJIT_API Error alloc(Reg& reg); - //! Alloc a virtual register `reg` using `physId` as a register id. - ASMJIT_API Error alloc(Reg& reg, uint32_t physId); - //! Alloc a virtual register `reg` using `ref` as a register operand. - ASMJIT_API Error alloc(Reg& reg, const Reg& ref); - //! Spill a virtual register `reg`. - ASMJIT_API Error spill(Reg& reg); - //! Save a virtual register `reg` if the status is `modified` at this point. - ASMJIT_API Error save(Reg& reg); - //! Unuse a virtual register `reg`. - ASMJIT_API Error unuse(Reg& reg); - - //! Get priority of a virtual register `reg`. - ASMJIT_API uint32_t getPriority(Reg& reg) const; - //! Set priority of variable `reg` to `priority`. - ASMJIT_API void setPriority(Reg& reg, uint32_t priority); - - //! Get save-on-unuse `reg` property. - ASMJIT_API bool getSaveOnUnuse(Reg& reg) const; - //! Set save-on-unuse `reg` property to `value`. - ASMJIT_API void setSaveOnUnuse(Reg& reg, bool value); - - //! Rename variable `reg` to `name`. - //! - //! NOTE: Only new name will appear in the logger. - ASMJIT_API void rename(Reg& reg, const char* fmt, ...); - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - CCFunc* _func; //!< Current function. - - Zone _vRegZone; //!< Allocates \ref VirtReg objects. - ZoneVector _vRegArray; //!< Stores array of \ref VirtReg pointers. - - CBConstPool* _localConstPool; //!< Local constant pool, flushed at the end of each function. - CBConstPool* _globalConstPool; //!< Global constant pool, flushed at the end of the compilation. -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // !ASMJIT_DISABLE_COMPILER -#endif // _ASMJIT_BASE_CODECOMPILER_H diff --git a/libs/asmjit/base/codeemitter.cpp b/libs/asmjit/base/codeemitter.cpp deleted file mode 100644 index 48a4c9a2..00000000 --- a/libs/asmjit/base/codeemitter.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/assembler.h" -#include "../base/utils.h" -#include "../base/vmem.h" - -#if defined(ASMJIT_BUILD_X86) -#include "../x86/x86inst.h" -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) -#include "../arm/arminst.h" -#endif // ASMJIT_BUILD_ARM - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::CodeEmitter - Construction / Destruction] -// ============================================================================ - -CodeEmitter::CodeEmitter(uint32_t type) noexcept - : _codeInfo(), - _code(nullptr), - _nextEmitter(nullptr), - _type(static_cast(type)), - _destroyed(false), - _finalized(false), - _reserved(false), - _lastError(kErrorNotInitialized), - _privateData(0), - _globalHints(0), - _globalOptions(kOptionMaybeFailureCase), - _options(0), - _extraReg(), - _inlineComment(nullptr), - _none(), - _nativeGpReg(), - _nativeGpArray(nullptr) {} - -CodeEmitter::~CodeEmitter() noexcept { - if (_code) { - _destroyed = true; - _code->detach(this); - } -} - -// ============================================================================ -// [asmjit::CodeEmitter - Events] -// ============================================================================ - -Error CodeEmitter::onAttach(CodeHolder* code) noexcept { - _codeInfo = code->getCodeInfo(); - _lastError = kErrorOk; - - _globalHints = code->getGlobalHints(); - _globalOptions = code->getGlobalOptions(); - - return kErrorOk; -} - -Error CodeEmitter::onDetach(CodeHolder* code) noexcept { - _codeInfo.reset(); - _finalized = false; - _lastError = kErrorNotInitialized; - - _privateData = 0; - _globalHints = 0; - _globalOptions = kOptionMaybeFailureCase; - - _options = 0; - _extraReg.reset(); - _inlineComment = nullptr; - - _nativeGpReg.reset(); - _nativeGpArray = nullptr; - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::CodeEmitter - Code-Generation] -// ============================================================================ - -Error CodeEmitter::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) { - const Operand_* op = opArray; - switch (opCount) { - case 0: return _emit(instId, _none, _none, _none, _none); - case 1: return _emit(instId, op[0], _none, _none, _none); - case 2: return _emit(instId, op[0], op[1], _none, _none); - case 3: return _emit(instId, op[0], op[1], op[2], _none); - case 4: return _emit(instId, op[0], op[1], op[2], op[3]); - case 5: return _emit(instId, op[0], op[1], op[2], op[3], op[4], _none); - case 6: return _emit(instId, op[0], op[1], op[2], op[3], op[4], op[5]); - - default: - return DebugUtils::errored(kErrorInvalidArgument); - } -} - -// ============================================================================ -// [asmjit::CodeEmitter - Finalize] -// ============================================================================ - -Label CodeEmitter::getLabelByName(const char* name, size_t nameLength, uint32_t parentId) noexcept { - return Label(_code ? _code->getLabelIdByName(name, nameLength, parentId) : static_cast(0)); -} - -// ============================================================================ -// [asmjit::CodeEmitter - Finalize] -// ============================================================================ - -Error CodeEmitter::finalize() { - // Finalization does nothing by default, overridden by `CodeBuilder`. - return kErrorOk; -} - -// ============================================================================ -// [asmjit::CodeEmitter - Error Handling] -// ============================================================================ - -Error CodeEmitter::setLastError(Error error, const char* message) { - // This is fatal, CodeEmitter can't set error without being attached to `CodeHolder`. - ASMJIT_ASSERT(_code != nullptr); - - // Special case used to reset the last error. - if (error == kErrorOk) { - _lastError = kErrorOk; - _globalOptions &= ~kOptionMaybeFailureCase; - return kErrorOk; - } - - if (!message) - message = DebugUtils::errorAsString(error); - - // Logging is skipped if the error is handled by `ErrorHandler`. - ErrorHandler* handler = _code->_errorHandler; - if (handler && handler->handleError(error, message, this)) - return error; - - // The handler->handleError() function may throw an exception or longjmp() - // to terminate the execution of `setLastError()`. This is the reason why - // we have delayed changing the `_error` member until now. - _lastError = error; - _globalOptions |= kOptionMaybeFailureCase; - - return error; -} - -// ============================================================================ -// [asmjit::CodeEmitter - Helpers] -// ============================================================================ - -bool CodeEmitter::isLabelValid(uint32_t id) const noexcept { - size_t index = Operand::unpackId(id); - return _code && index < _code->_labels.getLength(); -} - -Error CodeEmitter::commentf(const char* fmt, ...) { - Error err = _lastError; - if (err) return err; - -#if !defined(ASMJIT_DISABLE_LOGGING) - if (_globalOptions & kOptionLoggingEnabled) { - va_list ap; - va_start(ap, fmt); - err = _code->_logger->logv(fmt, ap); - va_end(ap); - } -#else - ASMJIT_UNUSED(fmt); -#endif - - return err; -} - -Error CodeEmitter::commentv(const char* fmt, va_list ap) { - Error err = _lastError; - if (err) return err; - -#if !defined(ASMJIT_DISABLE_LOGGING) - if (_globalOptions & kOptionLoggingEnabled) - err = _code->_logger->logv(fmt, ap); -#else - ASMJIT_UNUSED(fmt); - ASMJIT_UNUSED(ap); -#endif - - return err; -} - -// ============================================================================ -// [asmjit::CodeEmitter - Emit] -// ============================================================================ - -#define OP const Operand_& - -Error CodeEmitter::emit(uint32_t instId) { return _emit(instId, _none, _none, _none, _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0) { return _emit(instId, o0, _none, _none, _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1) { return _emit(instId, o0, o1, _none, _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2) { return _emit(instId, o0, o1, o2, _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3) { return _emit(instId, o0, o1, o2, o3); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4) { return _emit(instId, o0, o1, o2, o3, o4, _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, OP o5) { return _emit(instId, o0, o1, o2, o3, o4, o5); } - -Error CodeEmitter::emit(uint32_t instId, int o0) { return _emit(instId, Imm(o0), _none, _none, _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, int o1) { return _emit(instId, o0, Imm(o1), _none, _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int o2) { return _emit(instId, o0, o1, Imm(o2), _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int o3) { return _emit(instId, o0, o1, o2, Imm(o3)); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); } - -Error CodeEmitter::emit(uint32_t instId, int64_t o0) { return _emit(instId, Imm(o0), _none, _none, _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, int64_t o1) { return _emit(instId, o0, Imm(o1), _none, _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int64_t o2) { return _emit(instId, o0, o1, Imm(o2), _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int64_t o3) { return _emit(instId, o0, o1, o2, Imm(o3)); } - -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int64_t o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); } -Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int64_t o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); } - -#undef OP - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/codeemitter.h b/libs/asmjit/base/codeemitter.h deleted file mode 100644 index 93a2de36..00000000 --- a/libs/asmjit/base/codeemitter.h +++ /dev/null @@ -1,499 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_CODEEMITTER_H -#define _ASMJIT_BASE_CODEEMITTER_H - -// [Dependencies] -#include "../base/arch.h" -#include "../base/codeholder.h" -#include "../base/operand.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -class ConstPool; - -// ============================================================================ -// [asmjit::CodeEmitter] -// ============================================================================ - -//! Provides a base foundation to emit code - specialized by \ref Assembler and -//! \ref CodeBuilder. -class ASMJIT_VIRTAPI CodeEmitter { -public: - //! CodeEmitter type. - ASMJIT_ENUM(Type) { - kTypeNone = 0, - kTypeAssembler = 1, - kTypeBuilder = 2, - kTypeCompiler = 3, - kTypeCount = 4 - }; - - //! CodeEmitter hints - global settings that affect machine-code generation. - ASMJIT_ENUM(Hints) { - //! Emit optimized code-alignment sequences. - //! - //! Default `true`. - //! - //! X86/X64 Specific - //! ---------------- - //! - //! Default align sequence used by X86/X64 architecture is one-byte (0x90) - //! opcode that is often shown by disassemblers as nop. However there are - //! more optimized align sequences for 2-11 bytes that may execute faster. - //! If this feature is enabled AsmJit will generate specialized sequences - //! for alignment between 2 to 11 bytes. - kHintOptimizedAlign = 0x00000001U, - - //! Emit jump-prediction hints. - //! - //! Default `false`. - //! - //! X86/X64 Specific - //! ---------------- - //! - //! Jump prediction is usually based on the direction of the jump. If the - //! jump is backward it is usually predicted as taken; and if the jump is - //! forward it is usually predicted as not-taken. The reason is that loops - //! generally use backward jumps and conditions usually use forward jumps. - //! However this behavior can be overridden by using instruction prefixes. - //! If this option is enabled these hints will be emitted. - //! - //! This feature is disabled by default, because the only processor that - //! used to take into consideration prediction hints was P4. Newer processors - //! implement heuristics for branch prediction that ignores any static hints. - kHintPredictedJumps = 0x00000002U - }; - - //! CodeEmitter options that are merged with instruction options. - ASMJIT_ENUM(Options) { - //! Reserved, used to check for errors in `Assembler::_emit()`. In addition, - //! if an emitter is in error state it will have `kOptionMaybeFailureCase` - //! set - kOptionMaybeFailureCase = 0x00000001U, - - //! Perform a strict validation before the instruction is emitted. - kOptionStrictValidation = 0x00000002U, - - //! Logging is enabled and `CodeHolder::getLogger()` should return a valid - //! \ref Logger pointer. - kOptionLoggingEnabled = 0x00000004U, - - //! Mask of all internal options that are not used to represent instruction - //! options, but are used to instrument Assembler and CodeBuilder. These - //! options are internal and should not be used outside of AsmJit itself. - //! - //! NOTE: Reserved options should never appear in `CBInst` options. - kOptionReservedMask = 0x00000007U, - - //! Used only by Assembler to mark `_op4` and `_op5` are used. - kOptionOp4Op5Used = 0x00000008U, - - //! Prevents following a jump during compilation (CodeCompiler). - kOptionUnfollow = 0x00000010U, - - //! Overwrite the destination operand (CodeCompiler). - //! - //! Hint that is important for register liveness analysis. It tells the - //! compiler that the destination operand will be overwritten now or by - //! adjacent instructions. CodeCompiler knows when a register is completely - //! overwritten by a single instruction, for example you don't have to - //! mark "movaps" or "pxor x, x", however, if a pair of instructions is - //! used and the first of them doesn't completely overwrite the content - //! of the destination, CodeCompiler fails to mark that register as dead. - //! - //! X86/X64 Specific - //! ---------------- - //! - //! - All instructions that always overwrite at least the size of the - //! register the virtual-register uses , for example "mov", "movq", - //! "movaps" don't need the overwrite option to be used - conversion, - //! shuffle, and other miscellaneous instructions included. - //! - //! - All instructions that clear the destination register if all operands - //! are the same, for example "xor x, x", "pcmpeqb x x", etc... - //! - //! - Consecutive instructions that partially overwrite the variable until - //! there is no old content require the `overwrite()` to be used. Some - //! examples (not always the best use cases thought): - //! - //! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa - //! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa - //! - `mov al, ?` followed by `and ax, 0xFF` - //! - `mov al, ?` followed by `mov ah, al` - //! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1` - //! - //! - If allocated variable is used temporarily for scalar operations. For - //! example if you allocate a full vector like `X86Compiler::newXmm()` - //! and then use that vector for scalar operations you should use - //! `overwrite()` directive: - //! - //! - `sqrtss x, y` - only LO element of `x` is changed, if you don't use - //! HI elements, use `X86Compiler.overwrite().sqrtss(x, y)`. - kOptionOverwrite = 0x00000020U - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_API CodeEmitter(uint32_t type) noexcept; - ASMJIT_API virtual ~CodeEmitter() noexcept; - - // -------------------------------------------------------------------------- - // [Events] - // -------------------------------------------------------------------------- - - //! Called after the \ref CodeEmitter was attached to the \ref CodeHolder. - virtual Error onAttach(CodeHolder* code) noexcept = 0; - //! Called after the \ref CodeEmitter was detached from the \ref CodeHolder. - virtual Error onDetach(CodeHolder* code) noexcept = 0; - - // -------------------------------------------------------------------------- - // [Code-Generation] - // -------------------------------------------------------------------------- - - //! Emit instruction having max 4 operands. - virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) = 0; - //! Emit instruction having max 6 operands. - virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) = 0; - //! Emit instruction having operands stored in array. - virtual Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount); - - //! Create a new label. - virtual Label newLabel() = 0; - //! Create a new named label. - virtual Label newNamedLabel( - const char* name, - size_t nameLength = Globals::kInvalidIndex, - uint32_t type = Label::kTypeGlobal, - uint32_t parentId = 0) = 0; - - //! Get a label by name. - //! - //! Returns invalid Label in case that the name is invalid or label was not found. - //! - //! NOTE: This function doesn't trigger ErrorHandler in case the name is - //! invalid or no such label exist. You must always check the validity of the - //! \ref Label returned. - ASMJIT_API Label getLabelByName( - const char* name, - size_t nameLength = Globals::kInvalidIndex, - uint32_t parentId = 0) noexcept; - - //! Bind the `label` to the current position of the current section. - //! - //! NOTE: Attempt to bind the same label multiple times will return an error. - virtual Error bind(const Label& label) = 0; - - //! Align to the `alignment` specified. - //! - //! The sequence that is used to fill the gap between the aligned location - //! and the current location depends on the align `mode`, see \ref AlignMode. - virtual Error align(uint32_t mode, uint32_t alignment) = 0; - - //! Embed raw data into the code-buffer. - virtual Error embed(const void* data, uint32_t size) = 0; - - //! Embed absolute label address as data (4 or 8 bytes). - virtual Error embedLabel(const Label& label) = 0; - - //! Embed a constant pool into the code-buffer in the following steps: - //! 1. Align by using kAlignData to the minimum `pool` alignment. - //! 2. Bind `label` so it's bound to an aligned location. - //! 3. Emit constant pool data. - virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0; - - //! Emit a comment string `s` with an optional `len` parameter. - virtual Error comment(const char* s, size_t len = Globals::kInvalidIndex) = 0; - - // -------------------------------------------------------------------------- - // [Code-Generation Status] - // -------------------------------------------------------------------------- - - //! Get if the CodeEmitter is initialized (i.e. attached to a \ref CodeHolder). - ASMJIT_INLINE bool isInitialized() const noexcept { return _code != nullptr; } - - ASMJIT_API virtual Error finalize(); - - // -------------------------------------------------------------------------- - // [Code Information] - // -------------------------------------------------------------------------- - - //! Get information about the code, see \ref CodeInfo. - ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; } - //! Get \ref CodeHolder this CodeEmitter is attached to. - ASMJIT_INLINE CodeHolder* getCode() const noexcept { return _code; } - - //! Get information about the architecture, see \ref ArchInfo. - ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); } - - //! Get if the target architecture is 32-bit. - ASMJIT_INLINE bool is32Bit() const noexcept { return getArchInfo().is32Bit(); } - //! Get if the target architecture is 64-bit. - ASMJIT_INLINE bool is64Bit() const noexcept { return getArchInfo().is64Bit(); } - - //! Get the target architecture type. - ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); } - //! Get the target architecture sub-type. - ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); } - //! Get the target architecture's GP register size (4 or 8 bytes). - ASMJIT_INLINE uint32_t getGpSize() const noexcept { return getArchInfo().getGpSize(); } - //! Get the number of target GP registers. - ASMJIT_INLINE uint32_t getGpCount() const noexcept { return getArchInfo().getGpCount(); } - - // -------------------------------------------------------------------------- - // [Code-Emitter Type] - // -------------------------------------------------------------------------- - - //! Get the type of this CodeEmitter, see \ref Type. - ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } - - ASMJIT_INLINE bool isAssembler() const noexcept { return _type == kTypeAssembler; } - ASMJIT_INLINE bool isCodeBuilder() const noexcept { return _type == kTypeBuilder; } - ASMJIT_INLINE bool isCodeCompiler() const noexcept { return _type == kTypeCompiler; } - - // -------------------------------------------------------------------------- - // [Global Information] - // -------------------------------------------------------------------------- - - //! Get global hints. - ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; } - - //! Get global options. - //! - //! Global options are merged with instruction options before the instruction - //! is encoded. These options have some bits reserved that are used for error - //! checking, logging, and strict validation. Other options are globals that - //! affect each instruction, for example if VEX3 is set globally, it will all - //! instructions, even those that don't have such option set. - ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; } - - // -------------------------------------------------------------------------- - // [Error Handling] - // -------------------------------------------------------------------------- - - //! Get if the object is in error state. - //! - //! Error state means that it does not consume anything unless the error - //! state is reset by calling `resetLastError()`. Use `getLastError()` to - //! get the last error that put the object into the error state. - ASMJIT_INLINE bool isInErrorState() const noexcept { return _lastError != kErrorOk; } - - //! Get the last error code. - ASMJIT_INLINE Error getLastError() const noexcept { return _lastError; } - //! Set the last error code and propagate it through the error handler. - ASMJIT_API Error setLastError(Error error, const char* message = nullptr); - //! Clear the last error code and return `kErrorOk`. - ASMJIT_INLINE Error resetLastError() noexcept { return setLastError(kErrorOk); } - - // -------------------------------------------------------------------------- - // [Accessors That Affect the Next Instruction] - // -------------------------------------------------------------------------- - - //! Get options of the next instruction. - ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; } - //! Set options of the next instruction. - ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _options = options; } - //! Add options of the next instruction. - ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; } - //! Reset options of the next instruction. - ASMJIT_INLINE void resetOptions() noexcept { _options = 0; } - - //! Get if the extra register operand is valid. - ASMJIT_INLINE bool hasExtraReg() const noexcept { return _extraReg.isValid(); } - //! Get an extra operand that will be used by the next instruction (architecture specific). - ASMJIT_INLINE const RegOnly& getExtraReg() const noexcept { return _extraReg; } - //! Set an extra operand that will be used by the next instruction (architecture specific). - ASMJIT_INLINE void setExtraReg(const Reg& reg) noexcept { _extraReg.init(reg); } - //! Set an extra operand that will be used by the next instruction (architecture specific). - ASMJIT_INLINE void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); } - //! Reset an extra operand that will be used by the next instruction (architecture specific). - ASMJIT_INLINE void resetExtraReg() noexcept { _extraReg.reset(); } - - //! Get annotation of the next instruction. - ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; } - //! Set annotation of the next instruction. - //! - //! NOTE: This string is set back to null by `_emit()`, but until that it has - //! to remain valid as `CodeEmitter` is not required to make a copy of it (and - //! it would be slow to do that for each instruction). - ASMJIT_INLINE void setInlineComment(const char* s) noexcept { _inlineComment = s; } - //! Reset annotation of the next instruction to null. - ASMJIT_INLINE void resetInlineComment() noexcept { _inlineComment = nullptr; } - - // -------------------------------------------------------------------------- - // [Helpers] - // -------------------------------------------------------------------------- - - //! Get if the `label` is valid (i.e. registered). - ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept { - return isLabelValid(label.getId()); - } - - //! Get if the label `id` is valid (i.e. registered). - ASMJIT_API bool isLabelValid(uint32_t id) const noexcept; - - //! Emit a formatted string `fmt`. - ASMJIT_API Error commentf(const char* fmt, ...); - //! Emit a formatted string `fmt` (va_list version). - ASMJIT_API Error commentv(const char* fmt, va_list ap); - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - // NOTE: These `emit()` helpers are designed to address a code-bloat generated - // by C++ compilers to call a function having many arguments. Each parameter to - // `_emit()` requires code to pass it, which means that if we default to 4 - // operand parameters in `_emit()` and instId the C++ compiler would have to - // generate a virtual function call having 5 parameters, which is quite a lot. - // Since by default asm instructions have 2 to 3 operands it's better to - // introduce helpers that pass those and fill all the remaining with `_none`. - - //! Emit an instruction. - ASMJIT_API Error emit(uint32_t instId); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5); - - //! Emit an instruction that has a 32-bit signed immediate operand. - ASMJIT_API Error emit(uint32_t instId, int o0); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, int o1); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, int o2); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, int o3); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, int o4); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, int o5); - - //! Emit an instruction that has a 64-bit signed immediate operand. - ASMJIT_API Error emit(uint32_t instId, int64_t o0); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, int64_t o1); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, int64_t o2); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, int64_t o3); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, int64_t o4); - //! \overload - ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, int64_t o5); - - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, unsigned int o0) { - return emit(instId, static_cast(o0)); - } - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, unsigned int o1) { - return emit(instId, o0, static_cast(o1)); - } - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, unsigned int o2) { - return emit(instId, o0, o1, static_cast(o2)); - } - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, unsigned int o3) { - return emit(instId, o0, o1, o2, static_cast(o3)); - } - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, unsigned int o4) { - return emit(instId, o0, o1, o2, o3, static_cast(o4)); - } - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, unsigned int o5) { - return emit(instId, o0, o1, o2, o3, o4, static_cast(o5)); - } - - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, uint64_t o0) { - return emit(instId, static_cast(o0)); - } - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, uint64_t o1) { - return emit(instId, o0, static_cast(o1)); - } - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, uint64_t o2) { - return emit(instId, o0, o1, static_cast(o2)); - } - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, uint64_t o3) { - return emit(instId, o0, o1, o2, static_cast(o3)); - } - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, uint64_t o4) { - return emit(instId, o0, o1, o2, o3, static_cast(o4)); - } - //! \overload - ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, uint64_t o5) { - return emit(instId, o0, o1, o2, o3, o4, static_cast(o5)); - } - - ASMJIT_INLINE Error emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) { - return _emitOpArray(instId, opArray, opCount); - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - CodeInfo _codeInfo; //!< Basic information about the code (matches CodeHolder::_codeInfo). - CodeHolder* _code; //!< CodeHolder the CodeEmitter is attached to. - CodeEmitter* _nextEmitter; //!< Linked list of `CodeEmitter`s attached to the same \ref CodeHolder. - - uint8_t _type; //!< See CodeEmitter::Type. - uint8_t _destroyed; //!< Set by ~CodeEmitter() before calling `_code->detach()`. - uint8_t _finalized; //!< True if the CodeEmitter is finalized (CodeBuilder & CodeCompiler). - uint8_t _reserved; //!< \internal - Error _lastError; //!< Last error code. - - uint32_t _privateData; //!< Internal private data used freely by any CodeEmitter. - uint32_t _globalHints; //!< Global hints, always in sync with CodeHolder. - uint32_t _globalOptions; //!< Global options, combined with `_options` before used by each instruction. - - uint32_t _options; //!< Used to pass instruction options (affects the next instruction). - RegOnly _extraReg; //!< Extra register (op-mask {k} on AVX-512) (affects the next instruction). - const char* _inlineComment; //!< Inline comment of the next instruction (affects the next instruction). - - Operand_ _none; //!< Used to pass unused operands to `_emit()` instead of passing null. - Reg _nativeGpReg; //!< Native GP register with zero id. - const Reg* _nativeGpArray; //!< Array of native registers indexed from zero. -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_CODEEMITTER_H diff --git a/libs/asmjit/base/codeholder.cpp b/libs/asmjit/base/codeholder.cpp deleted file mode 100644 index 282f0128..00000000 --- a/libs/asmjit/base/codeholder.cpp +++ /dev/null @@ -1,696 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/assembler.h" -#include "../base/utils.h" -#include "../base/vmem.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::ErrorHandler] -// ============================================================================ - -ErrorHandler::ErrorHandler() noexcept {} -ErrorHandler::~ErrorHandler() noexcept {} - -// ============================================================================ -// [asmjit::CodeHolder - Utilities] -// ============================================================================ - -static void CodeHolder_setGlobalOption(CodeHolder* self, uint32_t clear, uint32_t add) noexcept { - // Modify global options of `CodeHolder` itself. - self->_globalOptions = (self->_globalOptions & ~clear) | add; - - // Modify all global options of all `CodeEmitter`s attached. - CodeEmitter* emitter = self->_emitters; - while (emitter) { - emitter->_globalOptions = (emitter->_globalOptions & ~clear) | add; - emitter = emitter->_nextEmitter; - } -} - -static void CodeHolder_resetInternal(CodeHolder* self, bool releaseMemory) noexcept { - // Detach all `CodeEmitter`s. - while (self->_emitters) - self->detach(self->_emitters); - - // Reset everything into its construction state. - self->_codeInfo.reset(); - self->_globalHints = 0; - self->_globalOptions = 0; - self->_logger = nullptr; - self->_errorHandler = nullptr; - - self->_unresolvedLabelsCount = 0; - self->_trampolinesSize = 0; - - // Reset all sections. - size_t numSections = self->_sections.getLength(); - for (size_t i = 0; i < numSections; i++) { - SectionEntry* section = self->_sections[i]; - if (section->_buffer.hasData() && !section->_buffer.isExternal()) - Internal::releaseMemory(section->_buffer._data); - section->_buffer._data = nullptr; - section->_buffer._capacity = 0; - } - - // Reset zone allocator and all containers using it. - ZoneHeap* heap = &self->_baseHeap; - - self->_namedLabels.reset(heap); - self->_relocations.reset(); - self->_labels.reset(); - self->_sections.reset(); - - heap->reset(&self->_baseZone); - self->_baseZone.reset(releaseMemory); -} - -// ============================================================================ -// [asmjit::CodeHolder - Construction / Destruction] -// ============================================================================ - -CodeHolder::CodeHolder() noexcept - : _codeInfo(), - _globalHints(0), - _globalOptions(0), - _emitters(nullptr), - _cgAsm(nullptr), - _logger(nullptr), - _errorHandler(nullptr), - _unresolvedLabelsCount(0), - _trampolinesSize(0), - _baseZone(16384 - Zone::kZoneOverhead), - _dataZone(16384 - Zone::kZoneOverhead), - _baseHeap(&_baseZone), - _namedLabels(&_baseHeap) {} - -CodeHolder::~CodeHolder() noexcept { - CodeHolder_resetInternal(this, true); -} - -// ============================================================================ -// [asmjit::CodeHolder - Init / Reset] -// ============================================================================ - -Error CodeHolder::init(const CodeInfo& info) noexcept { - // Cannot reinitialize if it's locked or there is one or more CodeEmitter - // attached. - if (isInitialized()) - return DebugUtils::errored(kErrorAlreadyInitialized); - - // If we are just initializing there should be no emitters attached). - ASMJIT_ASSERT(_emitters == nullptr); - - // Create the default section and insert it to the `_sections` array. - Error err = _sections.willGrow(&_baseHeap); - if (err == kErrorOk) { - SectionEntry* se = _baseZone.allocZeroedT(); - if (ASMJIT_LIKELY(se)) { - se->_flags = SectionEntry::kFlagExec | SectionEntry::kFlagConst; - se->_setDefaultName('.', 't', 'e', 'x', 't'); - _sections.appendUnsafe(se); - } - else { - err = DebugUtils::errored(kErrorNoHeapMemory); - } - } - - if (ASMJIT_UNLIKELY(err)) { - _baseZone.reset(false); - return err; - } - else { - _codeInfo = info; - return kErrorOk; - } -} - -void CodeHolder::reset(bool releaseMemory) noexcept { - CodeHolder_resetInternal(this, releaseMemory); -} - -// ============================================================================ -// [asmjit::CodeHolder - Attach / Detach] -// ============================================================================ - -Error CodeHolder::attach(CodeEmitter* emitter) noexcept { - // Catch a possible misuse of the API. - if (!emitter) - return DebugUtils::errored(kErrorInvalidArgument); - - uint32_t type = emitter->getType(); - if (type == CodeEmitter::kTypeNone || type >= CodeEmitter::kTypeCount) - return DebugUtils::errored(kErrorInvalidState); - - // This is suspicious, but don't fail if `emitter` matches. - if (emitter->_code != nullptr) { - if (emitter->_code == this) return kErrorOk; - return DebugUtils::errored(kErrorInvalidState); - } - - // Special case - attach `Assembler`. - CodeEmitter** pSlot = nullptr; - if (type == CodeEmitter::kTypeAssembler) { - if (_cgAsm) - return DebugUtils::errored(kErrorSlotOccupied); - pSlot = reinterpret_cast(&_cgAsm); - } - - Error err = emitter->onAttach(this); - if (err != kErrorOk) return err; - - // Add to a single-linked list of `CodeEmitter`s. - emitter->_nextEmitter = _emitters; - _emitters = emitter; - if (pSlot) *pSlot = emitter; - - // Establish the connection. - emitter->_code = this; - return kErrorOk; -} - -Error CodeHolder::detach(CodeEmitter* emitter) noexcept { - if (!emitter) - return DebugUtils::errored(kErrorInvalidArgument); - - if (emitter->_code != this) - return DebugUtils::errored(kErrorInvalidState); - - uint32_t type = emitter->getType(); - Error err = kErrorOk; - - // NOTE: We always detach if we were asked to, if error happens during - // `emitter->onDetach()` we just propagate it, but the CodeEmitter will - // be detached. - if (!emitter->_destroyed) { - if (type == CodeEmitter::kTypeAssembler) - static_cast(emitter)->sync(); - err = emitter->onDetach(this); - } - - // Special case - detach `Assembler`. - if (type == CodeEmitter::kTypeAssembler) - _cgAsm = nullptr; - - // Remove from a single-linked list of `CodeEmitter`s. - CodeEmitter** pPrev = &_emitters; - for (;;) { - ASMJIT_ASSERT(*pPrev != nullptr); - CodeEmitter* cur = *pPrev; - - if (cur == emitter) { - *pPrev = emitter->_nextEmitter; - break; - } - - pPrev = &cur->_nextEmitter; - } - - emitter->_code = nullptr; - emitter->_nextEmitter = nullptr; - - return err; -} - -// ============================================================================ -// [asmjit::CodeHolder - Sync] -// ============================================================================ - -void CodeHolder::sync() noexcept { - if (_cgAsm) _cgAsm->sync(); -} - -// ============================================================================ -// [asmjit::CodeHolder - Result Information] -// ============================================================================ - -size_t CodeHolder::getCodeSize() const noexcept { - // Reflect all changes first. - const_cast(this)->sync(); - - // TODO: Support sections. - return _sections[0]->_buffer._length + getTrampolinesSize(); -} - -// ============================================================================ -// [asmjit::CodeHolder - Logging & Error Handling] -// ============================================================================ - -#if !defined(ASMJIT_DISABLE_LOGGING) -void CodeHolder::setLogger(Logger* logger) noexcept { - uint32_t opt = 0; - if (logger) opt = CodeEmitter::kOptionLoggingEnabled; - - _logger = logger; - CodeHolder_setGlobalOption(this, CodeEmitter::kOptionLoggingEnabled, opt); -} -#endif // !ASMJIT_DISABLE_LOGGING - -Error CodeHolder::setErrorHandler(ErrorHandler* handler) noexcept { - _errorHandler = handler; - return kErrorOk; -} - -// ============================================================================ -// [asmjit::CodeHolder - Sections] -// ============================================================================ - -static Error CodeHolder_reserveInternal(CodeHolder* self, CodeBuffer* cb, size_t n) noexcept { - uint8_t* oldData = cb->_data; - uint8_t* newData; - - if (oldData && !cb->isExternal()) - newData = static_cast(Internal::reallocMemory(oldData, n)); - else - newData = static_cast(Internal::allocMemory(n)); - - if (ASMJIT_UNLIKELY(!newData)) - return DebugUtils::errored(kErrorNoHeapMemory); - - cb->_data = newData; - cb->_capacity = n; - - // Update the `Assembler` pointers if attached. Maybe we should introduce an - // event for this, but since only one Assembler can be attached at a time it - // should not matter how these pointers are updated. - Assembler* a = self->_cgAsm; - if (a && &a->_section->_buffer == cb) { - size_t offset = a->getOffset(); - - a->_bufferData = newData; - a->_bufferEnd = newData + n; - a->_bufferPtr = newData + offset; - } - - return kErrorOk; -} - -Error CodeHolder::growBuffer(CodeBuffer* cb, size_t n) noexcept { - // This is most likely called by `Assembler` so `sync()` shouldn't be needed, - // however, if this is called by the user and the currently attached Assembler - // did generate some code we could lose that, so sync now and make sure the - // section length is updated. - if (_cgAsm) _cgAsm->sync(); - - // Now the length of the section must be valid. - size_t length = cb->getLength(); - if (ASMJIT_UNLIKELY(n > IntTraits::maxValue() - length)) - return DebugUtils::errored(kErrorNoHeapMemory); - - // We can now check if growing the buffer is really necessary. It's unlikely - // that this function is called while there is still room for `n` bytes. - size_t capacity = cb->getCapacity(); - size_t required = cb->getLength() + n; - if (ASMJIT_UNLIKELY(required <= capacity)) return kErrorOk; - - if (cb->isFixedSize()) - return DebugUtils::errored(kErrorCodeTooLarge); - - if (capacity < 8096) - capacity = 8096; - else - capacity += Globals::kAllocOverhead; - - do { - size_t old = capacity; - if (capacity < Globals::kAllocThreshold) - capacity *= 2; - else - capacity += Globals::kAllocThreshold; - - if (capacity < Globals::kAllocThreshold) - capacity *= 2; - else - capacity += Globals::kAllocThreshold; - - // Overflow. - if (ASMJIT_UNLIKELY(old > capacity)) - return DebugUtils::errored(kErrorNoHeapMemory); - } while (capacity - Globals::kAllocOverhead < required); - - return CodeHolder_reserveInternal(this, cb, capacity - Globals::kAllocOverhead); -} - -Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept { - size_t capacity = cb->getCapacity(); - if (n <= capacity) return kErrorOk; - - if (cb->isFixedSize()) - return DebugUtils::errored(kErrorCodeTooLarge); - - // We must sync, as mentioned in `growBuffer()` as well. - if (_cgAsm) _cgAsm->sync(); - - return CodeHolder_reserveInternal(this, cb, n); -} - -// ============================================================================ -// [asmjit::CodeHolder - Labels & Symbols] -// ============================================================================ - -namespace { - -//! \internal -//! -//! Only used to lookup a label from `_namedLabels`. -class LabelByName { -public: - ASMJIT_INLINE LabelByName(const char* name, size_t nameLength, uint32_t hVal) noexcept - : name(name), - nameLength(static_cast(nameLength)) {} - - ASMJIT_INLINE bool matches(const LabelEntry* entry) const noexcept { - return static_cast(entry->getNameLength()) == nameLength && - ::memcmp(entry->getName(), name, nameLength) == 0; - } - - const char* name; - uint32_t nameLength; - uint32_t hVal; -}; - -// Returns a hash of `name` and fixes `nameLength` if it's `Globals::kInvalidIndex`. -static uint32_t CodeHolder_hashNameAndFixLen(const char* name, size_t& nameLength) noexcept { - uint32_t hVal = 0; - if (nameLength == Globals::kInvalidIndex) { - size_t i = 0; - for (;;) { - uint8_t c = static_cast(name[i]); - if (!c) break; - hVal = Utils::hashRound(hVal, c); - i++; - } - nameLength = i; - } - else { - for (size_t i = 0; i < nameLength; i++) { - uint8_t c = static_cast(name[i]); - if (ASMJIT_UNLIKELY(!c)) return DebugUtils::errored(kErrorInvalidLabelName); - hVal = Utils::hashRound(hVal, c); - } - } - return hVal; -} - -} // anonymous namespace - -LabelLink* CodeHolder::newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept { - LabelLink* link = _baseHeap.allocT(); - if (ASMJIT_UNLIKELY(!link)) return nullptr; - - link->prev = le->_links; - le->_links = link; - - link->sectionId = sectionId; - link->relocId = RelocEntry::kInvalidId; - link->offset = offset; - link->rel = rel; - - _unresolvedLabelsCount++; - return link; -} - -Error CodeHolder::newLabelId(uint32_t& idOut) noexcept { - idOut = 0; - - size_t index = _labels.getLength(); - if (ASMJIT_LIKELY(index >= Operand::kPackedIdCount)) - return DebugUtils::errored(kErrorLabelIndexOverflow); - - ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap)); - LabelEntry* le = _baseHeap.allocZeroedT(); - - if (ASMJIT_UNLIKELY(!le)) - return DebugUtils::errored(kErrorNoHeapMemory);; - - uint32_t id = Operand::packId(static_cast(index)); - le->_setId(id); - le->_parentId = 0; - le->_sectionId = SectionEntry::kInvalidId; - le->_offset = 0; - - _labels.appendUnsafe(le); - idOut = id; - return kErrorOk; -} - -Error CodeHolder::newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept { - idOut = 0; - uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength); - - if (ASMJIT_UNLIKELY(nameLength == 0)) - return DebugUtils::errored(kErrorInvalidLabelName); - - if (ASMJIT_UNLIKELY(nameLength > Globals::kMaxLabelLength)) - return DebugUtils::errored(kErrorLabelNameTooLong); - - switch (type) { - case Label::kTypeLocal: - if (ASMJIT_UNLIKELY(Operand::unpackId(parentId) >= _labels.getLength())) - return DebugUtils::errored(kErrorInvalidParentLabel); - - hVal ^= parentId; - break; - - case Label::kTypeGlobal: - if (ASMJIT_UNLIKELY(parentId != 0)) - return DebugUtils::errored(kErrorNonLocalLabelCantHaveParent); - - break; - - default: - return DebugUtils::errored(kErrorInvalidArgument); - } - - // Don't allow to insert duplicates. Local labels allow duplicates that have - // different id, this is already accomplished by having a different hashes - // between the same label names having different parent labels. - LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal)); - if (ASMJIT_UNLIKELY(le)) - return DebugUtils::errored(kErrorLabelAlreadyDefined); - - Error err = kErrorOk; - size_t index = _labels.getLength(); - - if (ASMJIT_UNLIKELY(index >= Operand::kPackedIdCount)) - return DebugUtils::errored(kErrorLabelIndexOverflow); - - ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap)); - le = _baseHeap.allocZeroedT(); - - if (ASMJIT_UNLIKELY(!le)) - return DebugUtils::errored(kErrorNoHeapMemory); - - uint32_t id = Operand::packId(static_cast(index)); - le->_hVal = hVal; - le->_setId(id); - le->_type = static_cast(type); - le->_parentId = 0; - le->_sectionId = SectionEntry::kInvalidId; - le->_offset = 0; - - if (le->_name.mustEmbed(nameLength)) { - le->_name.setEmbedded(name, nameLength); - } - else { - char* nameExternal = static_cast(_dataZone.dup(name, nameLength, true)); - if (ASMJIT_UNLIKELY(!nameExternal)) - return DebugUtils::errored(kErrorNoHeapMemory); - le->_name.setExternal(nameExternal, nameLength); - } - - _labels.appendUnsafe(le); - _namedLabels.put(le); - - idOut = id; - return err; -} - -uint32_t CodeHolder::getLabelIdByName(const char* name, size_t nameLength, uint32_t parentId) noexcept { - uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength); - if (ASMJIT_UNLIKELY(!nameLength)) return 0; - - LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal)); - return le ? le->getId() : static_cast(0); -} - -// ============================================================================ -// [asmjit::CodeEmitter - Relocations] -// ============================================================================ - -//! Encode MOD byte. -static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept { - return (m << 6) | (o << 3) | rm; -} - -Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept { - ASMJIT_PROPAGATE(_relocations.willGrow(&_baseHeap)); - - size_t index = _relocations.getLength(); - if (ASMJIT_UNLIKELY(index > size_t(0xFFFFFFFFU))) - return DebugUtils::errored(kErrorRelocIndexOverflow); - - RelocEntry* re = _baseHeap.allocZeroedT(); - if (ASMJIT_UNLIKELY(!re)) - return DebugUtils::errored(kErrorNoHeapMemory); - - re->_id = static_cast(index); - re->_type = static_cast(type); - re->_size = static_cast(size); - re->_sourceSectionId = SectionEntry::kInvalidId; - re->_targetSectionId = SectionEntry::kInvalidId; - _relocations.appendUnsafe(re); - - *dst = re; - return kErrorOk; -} - -// TODO: Support multiple sections, this only relocates the first. -// TODO: This should go to Runtime as it's responsible for relocating the -// code, CodeHolder should just hold it. -size_t CodeHolder::relocate(void* _dst, uint64_t baseAddress) const noexcept { - SectionEntry* section = _sections[0]; - ASMJIT_ASSERT(section != nullptr); - - uint8_t* dst = static_cast(_dst); - if (baseAddress == Globals::kNoBaseAddress) - baseAddress = static_cast((uintptr_t)dst); - -#if !defined(ASMJIT_DISABLE_LOGGING) - Logger* logger = getLogger(); -#endif // ASMJIT_DISABLE_LOGGING - - size_t minCodeSize = section->getBuffer().getLength(); // Minimum code size. - size_t maxCodeSize = getCodeSize(); // Includes all possible trampolines. - - // We will copy the exact size of the generated code. Extra code for trampolines - // is generated on-the-fly by the relocator (this code doesn't exist at the moment). - ::memcpy(dst, section->_buffer._data, minCodeSize); - - // Trampoline offset from the beginning of dst/baseAddress. - size_t trampOffset = minCodeSize; - - // Relocate all recorded locations. - size_t numRelocs = _relocations.getLength(); - const RelocEntry* const* reArray = _relocations.getData(); - - for (size_t i = 0; i < numRelocs; i++) { - const RelocEntry* re = reArray[i]; - - // Possibly deleted or optimized out relocation entry. - if (re->getType() == RelocEntry::kTypeNone) - continue; - - uint64_t ptr = re->getData(); - size_t codeOffset = static_cast(re->getSourceOffset()); - - // Make sure that the `RelocEntry` is correct, we don't want to write - // out of bounds in `dst`. - if (ASMJIT_UNLIKELY(codeOffset + re->getSize() > maxCodeSize)) - return DebugUtils::errored(kErrorInvalidRelocEntry); - - // Whether to use trampoline, can be only used if relocation type is `kRelocTrampoline`. - bool useTrampoline = false; - - switch (re->getType()) { - case RelocEntry::kTypeAbsToAbs: { - break; - } - - case RelocEntry::kTypeRelToAbs: { - ptr += baseAddress; - break; - } - - case RelocEntry::kTypeAbsToRel: { - ptr -= baseAddress + re->getSourceOffset() + re->getSize(); - break; - } - - case RelocEntry::kTypeTrampoline: { - if (re->getSize() != 4) - return DebugUtils::errored(kErrorInvalidRelocEntry); - - ptr -= baseAddress + re->getSourceOffset() + re->getSize(); - if (!Utils::isInt32(static_cast(ptr))) { - ptr = (uint64_t)trampOffset - re->getSourceOffset() - re->getSize(); - useTrampoline = true; - } - break; - } - - default: - return DebugUtils::errored(kErrorInvalidRelocEntry); - } - - switch (re->getSize()) { - case 1: - Utils::writeU8(dst + codeOffset, static_cast(ptr & 0xFFU)); - break; - - case 4: - Utils::writeU32u(dst + codeOffset, static_cast(ptr & 0xFFFFFFFFU)); - break; - - case 8: - Utils::writeU64u(dst + codeOffset, ptr); - break; - - default: - return DebugUtils::errored(kErrorInvalidRelocEntry); - } - - // Handle the trampoline case. - if (useTrampoline) { - // Bytes that replace [REX, OPCODE] bytes. - uint32_t byte0 = 0xFF; - uint32_t byte1 = dst[codeOffset - 1]; - - if (byte1 == 0xE8) { - // Patch CALL/MOD byte to FF/2 (-> 0x15). - byte1 = x86EncodeMod(0, 2, 5); - } - else if (byte1 == 0xE9) { - // Patch JMP/MOD byte to FF/4 (-> 0x25). - byte1 = x86EncodeMod(0, 4, 5); - } - else { - return DebugUtils::errored(kErrorInvalidRelocEntry); - } - - // Patch `jmp/call` instruction. - ASMJIT_ASSERT(codeOffset >= 2); - dst[codeOffset - 2] = static_cast(byte0); - dst[codeOffset - 1] = static_cast(byte1); - - // Store absolute address and advance the trampoline pointer. - Utils::writeU64u(dst + trampOffset, re->getData()); - trampOffset += 8; - -#if !defined(ASMJIT_DISABLE_LOGGING) - if (logger) - logger->logf("[reloc] dq 0x%016llX ; Trampoline\n", re->getData()); -#endif // !ASMJIT_DISABLE_LOGGING - } - } - - // If there are no trampolines this is the same as `minCodeSize`. - return trampOffset; -} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/codeholder.h b/libs/asmjit/base/codeholder.h deleted file mode 100644 index f753ecc3..00000000 --- a/libs/asmjit/base/codeholder.h +++ /dev/null @@ -1,748 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_CODEHOLDER_H -#define _ASMJIT_BASE_CODEHOLDER_H - -// [Dependencies] -#include "../base/arch.h" -#include "../base/func.h" -#include "../base/logging.h" -#include "../base/operand.h" -#include "../base/simdtypes.h" -#include "../base/utils.h" -#include "../base/zone.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -class Assembler; -class CodeEmitter; -class CodeHolder; - -// ============================================================================ -// [asmjit::AlignMode] -// ============================================================================ - -//! Align mode. -ASMJIT_ENUM(AlignMode) { - kAlignCode = 0, //!< Align executable code. - kAlignData = 1, //!< Align non-executable code. - kAlignZero = 2, //!< Align by a sequence of zeros. - kAlignCount //!< Count of alignment modes. -}; - -// ============================================================================ -// [asmjit::ErrorHandler] -// ============================================================================ - -//! Error handler can be used to override the default behavior of error handling -//! available to all classes that inherit \ref CodeEmitter. See \ref handleError(). -class ASMJIT_VIRTAPI ErrorHandler { -public: - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `ErrorHandler` instance. - ASMJIT_API ErrorHandler() noexcept; - //! Destroy the `ErrorHandler` instance. - ASMJIT_API virtual ~ErrorHandler() noexcept; - - // -------------------------------------------------------------------------- - // [Handle Error] - // -------------------------------------------------------------------------- - - //! Error handler (abstract). - //! - //! Error handler is called after an error happened and before it's propagated - //! to the caller. There are multiple ways how the error handler can be used: - //! - //! 1. Returning `true` or `false` from `handleError()`. If `true` is returned - //! it means that the error was reported and AsmJit can continue execution. - //! The reported error still be propagated to the caller, but won't put the - //! CodeEmitter into an error state (it won't set last-error). However, - //! returning `false` means that the error cannot be handled - in such case - //! it stores the error, which can be then retrieved by using `getLastError()`. - //! Returning `false` is the default behavior when no error handler is present. - //! To put the assembler into a non-error state again a `resetLastError()` must - //! be called. - //! - //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely - //! exception-safe, but you can throw exception from your error handler if - //! this way is the preferred way of handling errors in your project. Throwing - //! an exception acts virtually as returning `true` as AsmJit won't be able - //! to store the error because the exception changes execution path. - //! - //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts - //! `CodeEmitter` to a consistent state before calling the `handleError()` - //! so `longjmp()` can be used without any issues to cancel the code - //! generation if an error occurred. There is no difference between - //! exceptions and longjmp() from AsmJit's perspective. - virtual bool handleError(Error err, const char* message, CodeEmitter* origin) = 0; -}; - -// ============================================================================ -// [asmjit::CodeInfo] -// ============================================================================ - -//! Basic information about a code (or target). It describes its architecture, -//! code generation mode (or optimization level), and base address. -class CodeInfo { -public: - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE CodeInfo() noexcept - : _archInfo(), - _stackAlignment(0), - _cdeclCallConv(CallConv::kIdNone), - _stdCallConv(CallConv::kIdNone), - _fastCallConv(CallConv::kIdNone), - _baseAddress(Globals::kNoBaseAddress) {} - ASMJIT_INLINE CodeInfo(const CodeInfo& other) noexcept { init(other); } - - explicit ASMJIT_INLINE CodeInfo(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept - : _archInfo(archType, archMode), - _packedMiscInfo(0), - _baseAddress(baseAddress) {} - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool isInitialized() const noexcept { - return _archInfo._type != ArchInfo::kTypeNone; - } - - ASMJIT_INLINE void init(const CodeInfo& other) noexcept { - _archInfo = other._archInfo; - _packedMiscInfo = other._packedMiscInfo; - _baseAddress = other._baseAddress; - } - - ASMJIT_INLINE void init(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept { - _archInfo.init(archType, archMode); - _packedMiscInfo = 0; - _baseAddress = baseAddress; - } - - ASMJIT_INLINE void reset() noexcept { - _archInfo.reset(); - _stackAlignment = 0; - _cdeclCallConv = CallConv::kIdNone; - _stdCallConv = CallConv::kIdNone; - _fastCallConv = CallConv::kIdNone; - _baseAddress = Globals::kNoBaseAddress; - } - - // -------------------------------------------------------------------------- - // [Architecture Information] - // -------------------------------------------------------------------------- - - //! Get architecture information, see \ref ArchInfo. - ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _archInfo; } - - //! Get architecture type, see \ref ArchInfo::Type. - ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archInfo.getType(); } - //! Get architecture sub-type, see \ref ArchInfo::SubType. - ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _archInfo.getSubType(); } - //! Get a size of a GP register of the architecture the code is using. - ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _archInfo.getGpSize(); } - //! Get number of GP registers available of the architecture the code is using. - ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _archInfo.getGpCount(); } - - // -------------------------------------------------------------------------- - // [High-Level Information] - // -------------------------------------------------------------------------- - - //! Get a natural stack alignment that must be honored (or 0 if not known). - ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; } - //! Set a natural stack alignment that must be honored. - ASMJIT_INLINE void setStackAlignment(uint8_t sa) noexcept { _stackAlignment = static_cast(sa); } - - ASMJIT_INLINE uint32_t getCdeclCallConv() const noexcept { return _cdeclCallConv; } - ASMJIT_INLINE void setCdeclCallConv(uint32_t cc) noexcept { _cdeclCallConv = static_cast(cc); } - - ASMJIT_INLINE uint32_t getStdCallConv() const noexcept { return _stdCallConv; } - ASMJIT_INLINE void setStdCallConv(uint32_t cc) noexcept { _stdCallConv = static_cast(cc); } - - ASMJIT_INLINE uint32_t getFastCallConv() const noexcept { return _fastCallConv; } - ASMJIT_INLINE void setFastCallConv(uint32_t cc) noexcept { _fastCallConv = static_cast(cc); } - - // -------------------------------------------------------------------------- - // [Addressing Information] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; } - ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _baseAddress; } - ASMJIT_INLINE void setBaseAddress(uint64_t p) noexcept { _baseAddress = p; } - ASMJIT_INLINE void resetBaseAddress() noexcept { _baseAddress = Globals::kNoBaseAddress; } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE CodeInfo& operator=(const CodeInfo& other) noexcept { init(other); return *this; } - ASMJIT_INLINE bool operator==(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) == 0; } - ASMJIT_INLINE bool operator!=(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) != 0; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - ArchInfo _archInfo; //!< Architecture information. - - union { - struct { - uint8_t _stackAlignment; //!< Natural stack alignment (ARCH+OS). - uint8_t _cdeclCallConv; //!< Default CDECL calling convention. - uint8_t _stdCallConv; //!< Default STDCALL calling convention. - uint8_t _fastCallConv; //!< Default FASTCALL calling convention. - }; - uint32_t _packedMiscInfo; //!< \internal - }; - - uint64_t _baseAddress; //!< Base address. -}; - -// ============================================================================ -// [asmjit::CodeBuffer] -// ============================================================================ - -//! Code or data buffer. -struct CodeBuffer { - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool hasData() const noexcept { return _data != nullptr; } - ASMJIT_INLINE uint8_t* getData() noexcept { return _data; } - ASMJIT_INLINE const uint8_t* getData() const noexcept { return _data; } - - ASMJIT_INLINE size_t getLength() const noexcept { return _length; } - ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; } - - ASMJIT_INLINE bool isExternal() const noexcept { return _isExternal; } - ASMJIT_INLINE bool isFixedSize() const noexcept { return _isFixedSize; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint8_t* _data; //!< The content of the buffer (data). - size_t _length; //!< Number of bytes of `data` used. - size_t _capacity; //!< Buffer capacity (in bytes). - bool _isExternal; //!< True if this is external buffer. - bool _isFixedSize; //!< True if this buffer cannot grow. -}; - -// ============================================================================ -// [asmjit::SectionEntry] -// ============================================================================ - -//! Section entry. -class SectionEntry { -public: - ASMJIT_ENUM(Id) { - kInvalidId = 0xFFFFFFFFU //!< Invalid section id. - }; - - //! Section flags. - ASMJIT_ENUM(Flags) { - kFlagExec = 0x00000001U, //!< Executable (.text sections). - kFlagConst = 0x00000002U, //!< Read-only (.text and .data sections). - kFlagZero = 0x00000004U, //!< Zero initialized by the loader (BSS). - kFlagInfo = 0x00000008U, //!< Info / comment flag. - kFlagImplicit = 0x80000000U //!< Section created implicitly (can be deleted by the Runtime). - }; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } - ASMJIT_INLINE const char* getName() const noexcept { return _name; } - - ASMJIT_INLINE void _setDefaultName( - char c0 = 0, char c1 = 0, char c2 = 0, char c3 = 0, - char c4 = 0, char c5 = 0, char c6 = 0, char c7 = 0) noexcept { - _nameAsU32[0] = Utils::pack32_4x8(c0, c1, c2, c3); - _nameAsU32[1] = Utils::pack32_4x8(c4, c5, c6, c7); - } - - ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } - ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } - ASMJIT_INLINE void addFlags(uint32_t flags) noexcept { _flags |= flags; } - ASMJIT_INLINE void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } - - ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; } - ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; } - - ASMJIT_INLINE size_t getPhysicalSize() const noexcept { return _buffer.getLength(); } - - ASMJIT_INLINE size_t getVirtualSize() const noexcept { return _virtualSize; } - ASMJIT_INLINE void setVirtualSize(uint32_t size) noexcept { _virtualSize = size; } - - ASMJIT_INLINE CodeBuffer& getBuffer() noexcept { return _buffer; } - ASMJIT_INLINE const CodeBuffer& getBuffer() const noexcept { return _buffer; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint32_t _id; //!< Section id. - uint32_t _flags; //!< Section flags. - uint32_t _alignment; //!< Section alignment requirements (0 if no requirements). - uint32_t _virtualSize; //!< Virtual size of the section (zero initialized mostly). - union { - char _name[36]; //!< Section name (max 35 characters, PE allows max 8). - uint32_t _nameAsU32[36 / 4]; //!< Section name as `uint32_t[]` (only optimization). - }; - CodeBuffer _buffer; //!< Code or data buffer. -}; - -// ============================================================================ -// [asmjit::LabelLink] -// ============================================================================ - -//! Data structure used to link labels. -struct LabelLink { - LabelLink* prev; //!< Previous link (single-linked list). - uint32_t sectionId; //!< Section id. - uint32_t relocId; //!< Relocation id or RelocEntry::kInvalidId. - size_t offset; //!< Label offset relative to the start of the section. - intptr_t rel; //!< Inlined rel8/rel32. -}; - -// ============================================================================ -// [asmjit::LabelEntry] -// ============================================================================ - -//! Label entry. -//! -//! Contains the following properties: -//! * Label id - This is the only thing that is set to the `Label` operand. -//! * Label name - Optional, used mostly to create executables and libraries. -//! * Label type - Type of the label, default `Label::kTypeAnonymous`. -//! * Label parent id - Derived from many assemblers that allow to define a -//! local label that falls under a global label. This allows to define -//! many labels of the same name that have different parent (global) label. -//! * Offset - offset of the label bound by `Assembler`. -//! * Links - single-linked list that contains locations of code that has -//! to be patched when the label gets bound. Every use of unbound label -//! adds one link to `_links` list. -//! * HVal - Hash value of label's name and optionally parentId. -//! * HashNext - Hash-table implementation detail. -class LabelEntry : public ZoneHashNode { -public: - // NOTE: Label id is stored in `_customData`, which is provided by ZoneHashNode - // to fill a padding that a C++ compiler targeting 64-bit CPU will add to align - // the structure to 64-bits. - - //! Get label id. - ASMJIT_INLINE uint32_t getId() const noexcept { return _customData; } - //! Set label id (internal, used only by \ref CodeHolder). - ASMJIT_INLINE void _setId(uint32_t id) noexcept { _customData = id; } - - //! Get label type, see \ref Label::Type. - ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } - //! Get label flags, returns 0 at the moment. - ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } - - ASMJIT_INLINE bool hasParent() const noexcept { return _parentId != 0; } - //! Get label's parent id. - ASMJIT_INLINE uint32_t getParentId() const noexcept { return _parentId; } - - //! Get label's section id where it's bound to (or `SectionEntry::kInvalidId` if it's not bound yet). - ASMJIT_INLINE uint32_t getSectionId() const noexcept { return _sectionId; } - - //! Get if the label has name. - ASMJIT_INLINE bool hasName() const noexcept { return !_name.isEmpty(); } - - //! Get the label's name. - //! - //! NOTE: Local labels will return their local name without their parent - //! part, for example ".L1". - ASMJIT_INLINE const char* getName() const noexcept { return _name.getData(); } - - //! Get length of label's name. - //! - //! NOTE: Label name is always null terminated, so you can use `strlen()` to - //! get it, however, it's also cached in `LabelEntry`, so if you want to know - //! the length the easiest way is to use `LabelEntry::getNameLength()`. - ASMJIT_INLINE size_t getNameLength() const noexcept { return _name.getLength(); } - - //! Get if the label is bound. - ASMJIT_INLINE bool isBound() const noexcept { return _sectionId != SectionEntry::kInvalidId; } - //! Get the label offset (only useful if the label is bound). - ASMJIT_INLINE intptr_t getOffset() const noexcept { return _offset; } - - //! Get the hash-value of label's name and its parent label (if any). - //! - //! Label hash is calculated as `HASH(Name) ^ ParentId`. The hash function - //! is implemented in `Utils::hashString()` and `Utils::hashRound()`. - ASMJIT_INLINE uint32_t getHVal() const noexcept { return _hVal; } - - // ------------------------------------------------------------------------ - // [Members] - // ------------------------------------------------------------------------ - - // Let's round the size of `LabelEntry` to 64 bytes (as ZoneHeap has 32 - // bytes granularity anyway). This gives `_name` the remaining space, which - // is roughly 16 bytes on 64-bit and 28 bytes on 32-bit architectures. - enum { kNameBytes = 64 - (sizeof(ZoneHashNode) + 16 + sizeof(intptr_t) + sizeof(LabelLink*)) }; - - uint8_t _type; //!< Label type, see Label::Type. - uint8_t _flags; //!< Must be zero. - uint16_t _reserved16; //!< Reserved. - uint32_t _parentId; //!< Label parent id or zero. - uint32_t _sectionId; //!< Section id or `SectionEntry::kInvalidId`. - uint32_t _reserved32; //!< Reserved. - intptr_t _offset; //!< Label offset. - LabelLink* _links; //!< Label links. - SmallString _name; //!< Label name. -}; - -// ============================================================================ -// [asmjit::RelocEntry] -// ============================================================================ - -//! Relocation entry. -struct RelocEntry { - ASMJIT_ENUM(Id) { - kInvalidId = 0xFFFFFFFFU //!< Invalid relocation id. - }; - - //! Relocation type. - ASMJIT_ENUM(Type) { - kTypeNone = 0, //!< Deleted entry (no relocation). - kTypeAbsToAbs = 1, //!< Relocate absolute to absolute. - kTypeRelToAbs = 2, //!< Relocate relative to absolute. - kTypeAbsToRel = 3, //!< Relocate absolute to relative. - kTypeTrampoline = 4 //!< Relocate absolute to relative or use trampoline. - }; - - // ------------------------------------------------------------------------ - // [Accessors] - // ------------------------------------------------------------------------ - - ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } - - ASMJIT_INLINE uint32_t getType() const noexcept { return _type; } - ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; } - - ASMJIT_INLINE uint32_t getSourceSectionId() const noexcept { return _sourceSectionId; } - ASMJIT_INLINE uint32_t getTargetSectionId() const noexcept { return _targetSectionId; } - - ASMJIT_INLINE uint64_t getSourceOffset() const noexcept { return _sourceOffset; } - ASMJIT_INLINE uint64_t getData() const noexcept { return _data; } - - // ------------------------------------------------------------------------ - // [Members] - // ------------------------------------------------------------------------ - - uint32_t _id; //!< Relocation id. - uint8_t _type; //!< Type of the relocation. - uint8_t _size; //!< Size of the relocation (1, 2, 4 or 8 bytes). - uint8_t _reserved[2]; //!< Reserved. - uint32_t _sourceSectionId; //!< Source section id. - uint32_t _targetSectionId; //!< Destination section id. - uint64_t _sourceOffset; //!< Source offset (relative to start of the section). - uint64_t _data; //!< Relocation data (target offset, target address, etc). -}; - -// ============================================================================ -// [asmjit::CodeHolder] -// ============================================================================ - -//! Contains basic information about the target architecture plus its settings, -//! and holds code & data (including sections, labels, and relocation information). -//! CodeHolder can store both binary and intermediate representation of assembly, -//! which can be generated by \ref Assembler and/or \ref CodeBuilder. -//! -//! NOTE: CodeHolder has ability to attach an \ref ErrorHandler, however, this -//! error handler is not triggered by CodeHolder itself, it's only used by the -//! attached code generators. -class CodeHolder { -public: - ASMJIT_NONCOPYABLE(CodeHolder) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create an uninitialized CodeHolder (you must init() it before it can be used). - ASMJIT_API CodeHolder() noexcept; - //! Destroy the CodeHolder. - ASMJIT_API ~CodeHolder() noexcept; - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool isInitialized() const noexcept { return _codeInfo.isInitialized(); } - - //! Initialize to CodeHolder to hold code described by `codeInfo`. - ASMJIT_API Error init(const CodeInfo& info) noexcept; - //! Detach all code-generators attached and reset the \ref CodeHolder. - ASMJIT_API void reset(bool releaseMemory = false) noexcept; - - // -------------------------------------------------------------------------- - // [Attach / Detach] - // -------------------------------------------------------------------------- - - //! Attach a \ref CodeEmitter to this \ref CodeHolder. - ASMJIT_API Error attach(CodeEmitter* emitter) noexcept; - //! Detach a \ref CodeEmitter from this \ref CodeHolder. - ASMJIT_API Error detach(CodeEmitter* emitter) noexcept; - - // -------------------------------------------------------------------------- - // [Sync] - // -------------------------------------------------------------------------- - - //! Synchronize all states of all `CodeEmitter`s associated with the CodeHolder. - //! This is required as some code generators don't sync every time they do - //! something - for example \ref Assembler generally syncs when it needs to - //! reallocate the \ref CodeBuffer, but not each time it encodes instruction - //! or directive. - ASMJIT_API void sync() noexcept; - - // -------------------------------------------------------------------------- - // [Code-Information] - // -------------------------------------------------------------------------- - - //! Get code/target information, see \ref CodeInfo. - ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; } - //! Get architecture information, see \ref ArchInfo. - ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); } - - //! Get the target's architecture type. - ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); } - //! Get the target's architecture sub-type. - ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); } - - //! Get if a static base-address is set. - ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _codeInfo.hasBaseAddress(); } - //! Get a static base-address (uint64_t). - ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _codeInfo.getBaseAddress(); } - - // -------------------------------------------------------------------------- - // [Global Information] - // -------------------------------------------------------------------------- - - //! Get global hints, internally propagated to all `CodeEmitter`s attached. - ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; } - //! Get global options, internally propagated to all `CodeEmitter`s attached. - ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; } - - // -------------------------------------------------------------------------- - // [Result Information] - // -------------------------------------------------------------------------- - - //! Get the size code & data of all sections. - ASMJIT_API size_t getCodeSize() const noexcept; - - //! Get size of all possible trampolines. - //! - //! Trampolines are needed to successfully generate relative jumps to absolute - //! addresses. This value is only non-zero if jmp of call instructions were - //! used with immediate operand (this means jumping or calling an absolute - //! address directly). - ASMJIT_INLINE size_t getTrampolinesSize() const noexcept { return _trampolinesSize; } - - // -------------------------------------------------------------------------- - // [Logging & Error Handling] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_DISABLE_LOGGING) - //! Get if a logger attached. - ASMJIT_INLINE bool hasLogger() const noexcept { return _logger != nullptr; } - //! Get the attached logger. - ASMJIT_INLINE Logger* getLogger() const noexcept { return _logger; } - //! Attach a `logger` to CodeHolder and propagate it to all attached `CodeEmitter`s. - ASMJIT_API void setLogger(Logger* logger) noexcept; - //! Reset the logger (does nothing if not attached). - ASMJIT_INLINE void resetLogger() noexcept { setLogger(nullptr); } -#endif // !ASMJIT_DISABLE_LOGGING - - //! Get if error-handler is attached. - ASMJIT_INLINE bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; } - //! Get the error-handler. - ASMJIT_INLINE ErrorHandler* getErrorHandler() const noexcept { return _errorHandler; } - //! Set the error handler, will affect all attached `CodeEmitter`s. - ASMJIT_API Error setErrorHandler(ErrorHandler* handler) noexcept; - //! Reset the error handler (does nothing if not attached). - ASMJIT_INLINE void resetErrorHandler() noexcept { setErrorHandler(nullptr); } - - // -------------------------------------------------------------------------- - // [Sections] - // -------------------------------------------------------------------------- - - //! Get array of `SectionEntry*` records. - ASMJIT_INLINE const ZoneVector& getSections() const noexcept { return _sections; } - - //! Get a section entry of the given index. - ASMJIT_INLINE SectionEntry* getSectionEntry(size_t index) const noexcept { return _sections[index]; } - - ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept; - ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept; - - // -------------------------------------------------------------------------- - // [Labels & Symbols] - // -------------------------------------------------------------------------- - - //! Create a new anonymous label and return its id in `idOut`. - //! - //! Returns `Error`, does not report error to \ref ErrorHandler. - ASMJIT_API Error newLabelId(uint32_t& idOut) noexcept; - - //! Create a new named label label-type `type`. - //! - //! Returns `Error`, does not report error to \ref ErrorHandler. - ASMJIT_API Error newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept; - - //! Get a label id by name. - ASMJIT_API uint32_t getLabelIdByName(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t parentId = 0) noexcept; - - //! Create a new label-link used to store information about yet unbound labels. - //! - //! Returns `null` if the allocation failed. - ASMJIT_API LabelLink* newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept; - - //! Get array of `LabelEntry*` records. - ASMJIT_INLINE const ZoneVector& getLabelEntries() const noexcept { return _labels; } - - //! Get number of labels created. - ASMJIT_INLINE size_t getLabelsCount() const noexcept { return _labels.getLength(); } - - //! Get number of label references, which are unresolved at the moment. - ASMJIT_INLINE size_t getUnresolvedLabelsCount() const noexcept { return _unresolvedLabelsCount; } - - //! Get if the `label` is valid (i.e. created by `newLabelId()`). - ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept { - return isLabelValid(label.getId()); - } - //! Get if the label having `id` is valid (i.e. created by `newLabelId()`). - ASMJIT_INLINE bool isLabelValid(uint32_t labelId) const noexcept { - size_t index = Operand::unpackId(labelId); - return index < _labels.getLength(); - } - - //! Get if the `label` is already bound. - //! - //! Returns `false` if the `label` is not valid. - ASMJIT_INLINE bool isLabelBound(const Label& label) const noexcept { - return isLabelBound(label.getId()); - } - //! \overload - ASMJIT_INLINE bool isLabelBound(uint32_t id) const noexcept { - size_t index = Operand::unpackId(id); - return index < _labels.getLength() && _labels[index]->isBound(); - } - - //! Get a `label` offset or -1 if the label is not yet bound. - ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const noexcept { - return getLabelOffset(label.getId()); - } - //! \overload - ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const noexcept { - ASMJIT_ASSERT(isLabelValid(id)); - return _labels[Operand::unpackId(id)]->getOffset(); - } - - //! Get information about the given `label`. - ASMJIT_INLINE LabelEntry* getLabelEntry(const Label& label) const noexcept { - return getLabelEntry(label.getId()); - } - //! Get information about a label having the given `id`. - ASMJIT_INLINE LabelEntry* getLabelEntry(uint32_t id) const noexcept { - size_t index = static_cast(Operand::unpackId(id)); - return index < _labels.getLength() ? _labels[index] : static_cast(nullptr); - } - - // -------------------------------------------------------------------------- - // [Relocations] - // -------------------------------------------------------------------------- - - //! Create a new relocation entry of type `type` and size `size`. - //! - //! Additional fields can be set after the relocation entry was created. - ASMJIT_API Error newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept; - - //! Get if the code contains relocations. - ASMJIT_INLINE bool hasRelocations() const noexcept { return !_relocations.isEmpty(); } - //! Get array of `RelocEntry*` records. - ASMJIT_INLINE const ZoneVector& getRelocEntries() const noexcept { return _relocations; } - - ASMJIT_INLINE RelocEntry* getRelocEntry(uint32_t id) const noexcept { return _relocations[id]; } - - //! Relocate the code to `baseAddress` and copy it to `dst`. - //! - //! \param dst Contains the location where the relocated code should be - //! copied. The pointer can be address returned by virtual memory allocator - //! or any other address that has sufficient space. - //! - //! \param baseAddress Base address used for relocation. `JitRuntime` always - //! sets the `baseAddress` to be the same as `dst`. - //! - //! \return The number bytes actually used. If the code emitter reserved - //! space for possible trampolines, but didn't use it, the number of bytes - //! used can actually be less than the expected worst case. Virtual memory - //! allocator can shrink the memory it allocated initially. - //! - //! A given buffer will be overwritten, to get the number of bytes required, - //! use `getCodeSize()`. - ASMJIT_API size_t relocate(void* dst, uint64_t baseAddress = Globals::kNoBaseAddress) const noexcept; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - CodeInfo _codeInfo; //!< Basic information about the code (architecture and other info). - - uint32_t _globalHints; //!< Global hints, propagated to all `CodeEmitter`s. - uint32_t _globalOptions; //!< Global options, propagated to all `CodeEmitter`s. - - CodeEmitter* _emitters; //!< Linked-list of all attached `CodeEmitter`s. - Assembler* _cgAsm; //!< Attached \ref Assembler (only one at a time). - - Logger* _logger; //!< Attached \ref Logger, used by all consumers. - ErrorHandler* _errorHandler; //!< Attached \ref ErrorHandler. - - uint32_t _unresolvedLabelsCount; //!< Count of label references which were not resolved. - uint32_t _trampolinesSize; //!< Size of all possible trampolines. - - Zone _baseZone; //!< Base zone (used to allocate core structures). - Zone _dataZone; //!< Data zone (used to allocate extra data like label names). - ZoneHeap _baseHeap; //!< Zone allocator, used to manage internal containers. - - ZoneVector _sections; //!< Section entries. - ZoneVector _labels; //!< Label entries (each label is stored here). - ZoneVector _relocations; //!< Relocation entries. - ZoneHash _namedLabels; //!< Label name -> LabelEntry (only named labels). -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_CODEHOLDER_H diff --git a/libs/asmjit/base/constpool.cpp b/libs/asmjit/base/constpool.cpp deleted file mode 100644 index 799abd1c..00000000 --- a/libs/asmjit/base/constpool.cpp +++ /dev/null @@ -1,511 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/constpool.h" -#include "../base/utils.h" - -#include - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// Binary tree code is based on Julienne Walker's "Andersson Binary Trees" -// article and implementation. However, only three operations are implemented - -// get, insert and traverse. - -// ============================================================================ -// [asmjit::ConstPool::Tree - Ops] -// ============================================================================ - -//! \internal -//! -//! Remove left horizontal links. -static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_skewNode(ConstPool::Node* node) noexcept { - ConstPool::Node* link = node->_link[0]; - uint32_t level = node->_level; - - if (level != 0 && link && link->_level == level) { - node->_link[0] = link->_link[1]; - link->_link[1] = node; - - node = link; - } - - return node; -} - -//! \internal -//! -//! Remove consecutive horizontal links. -static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_splitNode(ConstPool::Node* node) noexcept { - ConstPool::Node* link = node->_link[1]; - uint32_t level = node->_level; - - if (level != 0 && link && link->_link[1] && link->_link[1]->_level == level) { - node->_link[1] = link->_link[0]; - link->_link[0] = node; - - node = link; - node->_level++; - } - - return node; -} - -ConstPool::Node* ConstPool::Tree::get(const void* data) noexcept { - ConstPool::Node* node = _root; - size_t dataSize = _dataSize; - - while (node) { - int c = ::memcmp(node->getData(), data, dataSize); - if (c == 0) - return node; - node = node->_link[c < 0]; - } - - return nullptr; -} - -void ConstPool::Tree::put(ConstPool::Node* newNode) noexcept { - size_t dataSize = _dataSize; - _length++; - - if (!_root) { - _root = newNode; - return; - } - - ConstPool::Node* node = _root; - ConstPool::Node* stack[kHeightLimit]; - - unsigned int top = 0; - unsigned int dir; - - // Find a spot and save the stack. - for (;;) { - stack[top++] = node; - dir = ::memcmp(node->getData(), newNode->getData(), dataSize) < 0; - - ConstPool::Node* link = node->_link[dir]; - if (!link) break; - - node = link; - } - - // Link and rebalance. - node->_link[dir] = newNode; - - while (top > 0) { - // Which child? - node = stack[--top]; - - if (top != 0) { - dir = stack[top - 1]->_link[1] == node; - } - - node = ConstPoolTree_skewNode(node); - node = ConstPoolTree_splitNode(node); - - // Fix the parent. - if (top != 0) - stack[top - 1]->_link[dir] = node; - else - _root = node; - } -} - -// ============================================================================ -// [asmjit::ConstPool - Construction / Destruction] -// ============================================================================ - -ConstPool::ConstPool(Zone* zone) noexcept { reset(zone); } -ConstPool::~ConstPool() noexcept {} - -// ============================================================================ -// [asmjit::ConstPool - Reset] -// ============================================================================ - -void ConstPool::reset(Zone* zone) noexcept { - _zone = zone; - - size_t dataSize = 1; - for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) { - _tree[i].reset(); - _tree[i].setDataSize(dataSize); - _gaps[i] = nullptr; - dataSize <<= 1; - } - - _gapPool = nullptr; - _size = 0; - _alignment = 0; -} - -// ============================================================================ -// [asmjit::ConstPool - Ops] -// ============================================================================ - -static ASMJIT_INLINE ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcept { - ConstPool::Gap* gap = self->_gapPool; - if (!gap) return self->_zone->allocT(); - - self->_gapPool = gap->_next; - return gap; -} - -static ASMJIT_INLINE void ConstPool_freeGap(ConstPool* self, ConstPool::Gap* gap) noexcept { - gap->_next = self->_gapPool; - self->_gapPool = gap; -} - -static void ConstPool_addGap(ConstPool* self, size_t offset, size_t length) noexcept { - ASMJIT_ASSERT(length > 0); - - while (length > 0) { - size_t gapIndex; - size_t gapLength; - - gapIndex = ConstPool::kIndex16; - if (length >= 16 && Utils::isAligned(offset, 16)) { - gapLength = 16; - } - else if (length >= 8 && Utils::isAligned(offset, 8)) { - gapIndex = ConstPool::kIndex8; - gapLength = 8; - } - else if (length >= 4 && Utils::isAligned(offset, 4)) { - gapIndex = ConstPool::kIndex4; - gapLength = 4; - } - else if (length >= 2 && Utils::isAligned(offset, 2)) { - gapIndex = ConstPool::kIndex2; - gapLength = 2; - } - else { - gapIndex = ConstPool::kIndex1; - gapLength = 1; - } - - // We don't have to check for errors here, if this failed nothing really - // happened (just the gap won't be visible) and it will fail again at - // place where checking will cause kErrorNoHeapMemory. - ConstPool::Gap* gap = ConstPool_allocGap(self); - if (!gap) return; - - gap->_next = self->_gaps[gapIndex]; - self->_gaps[gapIndex] = gap; - - gap->_offset = offset; - gap->_length = gapLength; - - offset += gapLength; - length -= gapLength; - } -} - -Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept { - size_t treeIndex; - - if (size == 32) - treeIndex = kIndex32; - else if (size == 16) - treeIndex = kIndex16; - else if (size == 8) - treeIndex = kIndex8; - else if (size == 4) - treeIndex = kIndex4; - else if (size == 2) - treeIndex = kIndex2; - else if (size == 1) - treeIndex = kIndex1; - else - return DebugUtils::errored(kErrorInvalidArgument); - - ConstPool::Node* node = _tree[treeIndex].get(data); - if (node) { - dstOffset = node->_offset; - return kErrorOk; - } - - // Before incrementing the current offset try if there is a gap that can - // be used for the requested data. - size_t offset = ~static_cast(0); - size_t gapIndex = treeIndex; - - while (gapIndex != kIndexCount - 1) { - ConstPool::Gap* gap = _gaps[treeIndex]; - - // Check if there is a gap. - if (gap) { - size_t gapOffset = gap->_offset; - size_t gapLength = gap->_length; - - // Destroy the gap for now. - _gaps[treeIndex] = gap->_next; - ConstPool_freeGap(this, gap); - - offset = gapOffset; - ASMJIT_ASSERT(Utils::isAligned(offset, size)); - - gapLength -= size; - if (gapLength > 0) - ConstPool_addGap(this, gapOffset, gapLength); - } - - gapIndex++; - } - - if (offset == ~static_cast(0)) { - // Get how many bytes have to be skipped so the address is aligned accordingly - // to the 'size'. - size_t diff = Utils::alignDiff(_size, size); - - if (diff != 0) { - ConstPool_addGap(this, _size, diff); - _size += diff; - } - - offset = _size; - _size += size; - } - - // Add the initial node to the right index. - node = ConstPool::Tree::_newNode(_zone, data, size, offset, false); - if (!node) return DebugUtils::errored(kErrorNoHeapMemory); - - _tree[treeIndex].put(node); - _alignment = std::max(_alignment, size); - - dstOffset = offset; - - // Now create a bunch of shared constants that are based on the data pattern. - // We stop at size 4, it probably doesn't make sense to split constants down - // to 1 byte. - size_t pCount = 1; - while (size > 4) { - size >>= 1; - pCount <<= 1; - - ASMJIT_ASSERT(treeIndex != 0); - treeIndex--; - - const uint8_t* pData = static_cast(data); - for (size_t i = 0; i < pCount; i++, pData += size) { - node = _tree[treeIndex].get(pData); - if (node) continue; - - node = ConstPool::Tree::_newNode(_zone, pData, size, offset + (i * size), true); - _tree[treeIndex].put(node); - } - } - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::ConstPool - Reset] -// ============================================================================ - -struct ConstPoolFill { - ASMJIT_INLINE ConstPoolFill(uint8_t* dst, size_t dataSize) noexcept : - _dst(dst), - _dataSize(dataSize) {} - - ASMJIT_INLINE void visit(const ConstPool::Node* node) noexcept { - if (!node->_shared) - ::memcpy(_dst + node->_offset, node->getData(), _dataSize); - } - - uint8_t* _dst; - size_t _dataSize; -}; - -void ConstPool::fill(void* dst) const noexcept { - // Clears possible gaps, asmjit should never emit garbage to the output. - ::memset(dst, 0, _size); - - ConstPoolFill filler(static_cast(dst), 1); - for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) { - _tree[i].iterate(filler); - filler._dataSize <<= 1; - } -} - -// ============================================================================ -// [asmjit::ConstPool - Test] -// ============================================================================ - -#if defined(ASMJIT_TEST) -UNIT(base_constpool) { - Zone zone(32384 - Zone::kZoneOverhead); - ConstPool pool(&zone); - - uint32_t i; - uint32_t kCount = 1000000; - - INFO("Adding %u constants to the pool.", kCount); - { - size_t prevOffset; - size_t curOffset; - uint64_t c = ASMJIT_UINT64_C(0x0101010101010101); - - EXPECT(pool.add(&c, 8, prevOffset) == kErrorOk, - "pool.add() - Returned error"); - EXPECT(prevOffset == 0, - "pool.add() - First constant should have zero offset"); - - for (i = 1; i < kCount; i++) { - c++; - EXPECT(pool.add(&c, 8, curOffset) == kErrorOk, - "pool.add() - Returned error"); - EXPECT(prevOffset + 8 == curOffset, - "pool.add() - Returned incorrect curOffset"); - EXPECT(pool.getSize() == (i + 1) * 8, - "pool.getSize() - Reported incorrect size"); - prevOffset = curOffset; - } - - EXPECT(pool.getAlignment() == 8, - "pool.getAlignment() - Expected 8-byte alignment"); - } - - INFO("Retrieving %u constants from the pool.", kCount); - { - uint64_t c = ASMJIT_UINT64_C(0x0101010101010101); - - for (i = 0; i < kCount; i++) { - size_t offset; - EXPECT(pool.add(&c, 8, offset) == kErrorOk, - "pool.add() - Returned error"); - EXPECT(offset == i * 8, - "pool.add() - Should have reused constant"); - c++; - } - } - - INFO("Checking if the constants were split into 4-byte patterns"); - { - uint32_t c = 0x01010101; - for (i = 0; i < kCount; i++) { - size_t offset; - EXPECT(pool.add(&c, 4, offset) == kErrorOk, - "pool.add() - Returned error"); - EXPECT(offset == i * 8, - "pool.add() - Should reuse existing constant"); - c++; - } - } - - INFO("Adding 2 byte constant to misalign the current offset"); - { - uint16_t c = 0xFFFF; - size_t offset; - - EXPECT(pool.add(&c, 2, offset) == kErrorOk, - "pool.add() - Returned error"); - EXPECT(offset == kCount * 8, - "pool.add() - Didn't return expected position"); - EXPECT(pool.getAlignment() == 8, - "pool.getAlignment() - Expected 8-byte alignment"); - } - - INFO("Adding 8 byte constant to check if pool gets aligned again"); - { - uint64_t c = ASMJIT_UINT64_C(0xFFFFFFFFFFFFFFFF); - size_t offset; - - EXPECT(pool.add(&c, 8, offset) == kErrorOk, - "pool.add() - Returned error"); - EXPECT(offset == kCount * 8 + 8, - "pool.add() - Didn't return aligned offset"); - } - - INFO("Adding 2 byte constant to verify the gap is filled"); - { - uint16_t c = 0xFFFE; - size_t offset; - - EXPECT(pool.add(&c, 2, offset) == kErrorOk, - "pool.add() - Returned error"); - EXPECT(offset == kCount * 8 + 2, - "pool.add() - Didn't fill the gap"); - EXPECT(pool.getAlignment() == 8, - "pool.getAlignment() - Expected 8-byte alignment"); - } - - INFO("Checking reset functionality"); - { - pool.reset(&zone); - zone.reset(); - - EXPECT(pool.getSize() == 0, - "pool.getSize() - Expected pool size to be zero"); - EXPECT(pool.getAlignment() == 0, - "pool.getSize() - Expected pool alignment to be zero"); - } - - INFO("Checking pool alignment when combined constants are added"); - { - uint8_t bytes[32] = { 0 }; - size_t offset; - - pool.add(bytes, 1, offset); - - EXPECT(pool.getSize() == 1, - "pool.getSize() - Expected pool size to be 1 byte"); - EXPECT(pool.getAlignment() == 1, - "pool.getSize() - Expected pool alignment to be 1 byte"); - EXPECT(offset == 0, - "pool.getSize() - Expected offset returned to be zero"); - - pool.add(bytes, 2, offset); - - EXPECT(pool.getSize() == 4, - "pool.getSize() - Expected pool size to be 4 bytes"); - EXPECT(pool.getAlignment() == 2, - "pool.getSize() - Expected pool alignment to be 2 bytes"); - EXPECT(offset == 2, - "pool.getSize() - Expected offset returned to be 2"); - - pool.add(bytes, 4, offset); - - EXPECT(pool.getSize() == 8, - "pool.getSize() - Expected pool size to be 8 bytes"); - EXPECT(pool.getAlignment() == 4, - "pool.getSize() - Expected pool alignment to be 4 bytes"); - EXPECT(offset == 4, - "pool.getSize() - Expected offset returned to be 4"); - - pool.add(bytes, 4, offset); - - EXPECT(pool.getSize() == 8, - "pool.getSize() - Expected pool size to be 8 bytes"); - EXPECT(pool.getAlignment() == 4, - "pool.getSize() - Expected pool alignment to be 4 bytes"); - EXPECT(offset == 4, - "pool.getSize() - Expected offset returned to be 8"); - - pool.add(bytes, 32, offset); - EXPECT(pool.getSize() == 64, - "pool.getSize() - Expected pool size to be 64 bytes"); - EXPECT(pool.getAlignment() == 32, - "pool.getSize() - Expected pool alignment to be 32 bytes"); - EXPECT(offset == 32, - "pool.getSize() - Expected offset returned to be 32"); - } -} -#endif // ASMJIT_TEST - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/constpool.h b/libs/asmjit/base/constpool.h deleted file mode 100644 index 945ea647..00000000 --- a/libs/asmjit/base/constpool.h +++ /dev/null @@ -1,257 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_CONSTPOOL_H -#define _ASMJIT_BASE_CONSTPOOL_H - -// [Dependencies] -#include "../base/zone.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::ConstPool] -// ============================================================================ - -//! Constant pool. -class ConstPool { -public: - ASMJIT_NONCOPYABLE(ConstPool) - - enum { - kIndex1 = 0, - kIndex2 = 1, - kIndex4 = 2, - kIndex8 = 3, - kIndex16 = 4, - kIndex32 = 5, - kIndexCount = 6 - }; - - // -------------------------------------------------------------------------- - // [Gap] - // -------------------------------------------------------------------------- - - //! \internal - //! - //! Zone-allocated const-pool gap. - struct Gap { - Gap* _next; //!< Pointer to the next gap - size_t _offset; //!< Offset of the gap. - size_t _length; //!< Remaining bytes of the gap (basically a gap size). - }; - - // -------------------------------------------------------------------------- - // [Node] - // -------------------------------------------------------------------------- - - //! \internal - //! - //! Zone-allocated const-pool node. - struct Node { - ASMJIT_INLINE void* getData() const noexcept { - return static_cast(const_cast(this) + 1); - } - - Node* _link[2]; //!< Left/Right nodes. - uint32_t _level : 31; //!< Horizontal level for balance. - uint32_t _shared : 1; //!< If this constant is shared with another. - uint32_t _offset; //!< Data offset from the beginning of the pool. - }; - - // -------------------------------------------------------------------------- - // [Tree] - // -------------------------------------------------------------------------- - - //! \internal - //! - //! Zone-allocated const-pool tree. - struct Tree { - enum { - //! Maximum tree height == log2(1 << 64). - kHeightLimit = 64 - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE Tree(size_t dataSize = 0) noexcept - : _root(nullptr), - _length(0), - _dataSize(dataSize) {} - ASMJIT_INLINE ~Tree() {} - - // -------------------------------------------------------------------------- - // [Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void reset() noexcept { - _root = nullptr; - _length = 0; - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; } - ASMJIT_INLINE size_t getLength() const noexcept { return _length; } - - ASMJIT_INLINE void setDataSize(size_t dataSize) noexcept { - ASMJIT_ASSERT(isEmpty()); - _dataSize = dataSize; - } - - // -------------------------------------------------------------------------- - // [Ops] - // -------------------------------------------------------------------------- - - ASMJIT_API Node* get(const void* data) noexcept; - ASMJIT_API void put(Node* node) noexcept; - - // -------------------------------------------------------------------------- - // [Iterate] - // -------------------------------------------------------------------------- - - template - ASMJIT_INLINE void iterate(Visitor& visitor) const noexcept { - Node* node = const_cast(_root); - if (!node) return; - - Node* stack[kHeightLimit]; - size_t top = 0; - - for (;;) { - Node* left = node->_link[0]; - if (left != nullptr) { - ASMJIT_ASSERT(top != kHeightLimit); - stack[top++] = node; - - node = left; - continue; - } - -Visit: - visitor.visit(node); - node = node->_link[1]; - if (node != nullptr) - continue; - - if (top == 0) - return; - - node = stack[--top]; - goto Visit; - } - } - - // -------------------------------------------------------------------------- - // [Helpers] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE Node* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) noexcept { - Node* node = zone->allocT(sizeof(Node) + size); - if (ASMJIT_UNLIKELY(!node)) return nullptr; - - node->_link[0] = nullptr; - node->_link[1] = nullptr; - node->_level = 1; - node->_shared = shared; - node->_offset = static_cast(offset); - - ::memcpy(node->getData(), data, size); - return node; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - Node* _root; //!< Root of the tree - size_t _length; //!< Length of the tree (count of nodes). - size_t _dataSize; //!< Size of the data. - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_API ConstPool(Zone* zone) noexcept; - ASMJIT_API ~ConstPool() noexcept; - - // -------------------------------------------------------------------------- - // [Reset] - // -------------------------------------------------------------------------- - - ASMJIT_API void reset(Zone* zone) noexcept; - - // -------------------------------------------------------------------------- - // [Ops] - // -------------------------------------------------------------------------- - - //! Get whether the constant-pool is empty. - ASMJIT_INLINE bool isEmpty() const noexcept { return _size == 0; } - //! Get the size of the constant-pool in bytes. - ASMJIT_INLINE size_t getSize() const noexcept { return _size; } - //! Get minimum alignment. - ASMJIT_INLINE size_t getAlignment() const noexcept { return _alignment; } - - //! Add a constant to the constant pool. - //! - //! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes. - //! The constant is added to the pool only if it doesn't not exist, otherwise - //! cached value is returned. - //! - //! AsmJit is able to subdivide added constants, so for example if you add - //! 8-byte constant 0x1122334455667788 it will create the following slots: - //! - //! 8-byte: 0x1122334455667788 - //! 4-byte: 0x11223344, 0x55667788 - //! - //! The reason is that when combining MMX/SSE/AVX code some patterns are used - //! frequently. However, AsmJit is not able to reallocate a constant that has - //! been already added. For example if you try to add 4-byte constant and then - //! 8-byte constant having the same 4-byte pattern as the previous one, two - //! independent slots will be generated by the pool. - ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset) noexcept; - - // -------------------------------------------------------------------------- - // [Fill] - // -------------------------------------------------------------------------- - - //! Fill the destination with the constants from the pool. - ASMJIT_API void fill(void* dst) const noexcept; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - Zone* _zone; //!< Zone allocator. - Tree _tree[kIndexCount]; //!< Tree per size. - Gap* _gaps[kIndexCount]; //!< Gaps per size. - Gap* _gapPool; //!< Gaps pool - - size_t _size; //!< Size of the pool (in bytes). - size_t _alignment; //!< Required pool alignment. -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_CONSTPOOL_H diff --git a/libs/asmjit/base/cpuinfo.cpp b/libs/asmjit/base/cpuinfo.cpp deleted file mode 100644 index c8421735..00000000 --- a/libs/asmjit/base/cpuinfo.cpp +++ /dev/null @@ -1,674 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/cpuinfo.h" -#include "../base/utils.h" - -#if ASMJIT_OS_POSIX -# include -# include -# include -#endif // ASMJIT_OS_POSIX - -#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 -# if ASMJIT_CC_MSC_GE(14, 0, 0) - # include // Required by `__cpuid()` and `_xgetbv()`. -# endif // _MSC_VER >= 1400 -#endif - -#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 -# if ASMJIT_OS_LINUX -# include // Required by `getauxval()`. -# endif -#endif - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::CpuInfo - Detect ARM] -// ============================================================================ - -// ARM information has to be retrieved by the OS (this is how ARM was designed). -#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 - -#if ASMJIT_ARCH_ARM32 -static ASMJIT_INLINE void armPopulateBaselineA32Features(CpuInfo* cpuInfo) noexcept { - cpuInfo->_archInfo.init(ArchInfo::kTypeA32); -} -#endif // ASMJIT_ARCH_ARM32 - -#if ASMJIT_ARCH_ARM64 -static ASMJIT_INLINE void armPopulateBaselineA64Features(CpuInfo* cpuInfo) noexcept { - cpuInfo->_archInfo.init(ArchInfo::kTypeA64); - - // Thumb (including all variations) is supported on A64 (but not accessible from A64). - cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB); - cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB2); - - // A64 is based on ARMv8 and newer. - cpuInfo->addFeature(CpuInfo::kArmFeatureV6); - cpuInfo->addFeature(CpuInfo::kArmFeatureV7); - cpuInfo->addFeature(CpuInfo::kArmFeatureV8); - - // A64 comes with these features by default. - cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2); - cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv3); - cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv4); - cpuInfo->addFeature(CpuInfo::kArmFeatureEDSP); - cpuInfo->addFeature(CpuInfo::kArmFeatureASIMD); - cpuInfo->addFeature(CpuInfo::kArmFeatureIDIVA); - cpuInfo->addFeature(CpuInfo::kArmFeatureIDIVT); -} -#endif // ASMJIT_ARCH_ARM64 - -#if ASMJIT_OS_WINDOWS -//! \internal -//! -//! Detect ARM CPU features on Windows. -//! -//! The detection is based on `IsProcessorFeaturePresent()` API call. -static ASMJIT_INLINE void armDetectCpuInfoOnWindows(CpuInfo* cpuInfo) noexcept { -#if ASMJIT_ARCH_ARM32 - armPopulateBaselineA32Features(cpuInfo); - - // Windows for ARM requires at least ARMv7 with DSP extensions. - cpuInfo->addFeature(CpuInfo::kArmFeatureV6); - cpuInfo->addFeature(CpuInfo::kArmFeatureV7); - cpuInfo->addFeature(CpuInfo::kArmFeatureEDSP); - - // Windows for ARM requires VFPv3. - cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2); - cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv3); - - // Windows for ARM requires and uses THUMB2. - cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB); - cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB2); -#else - armPopulateBaselineA64Features(cpuInfo); -#endif - - // Windows for ARM requires ASIMD. - cpuInfo->addFeature(CpuInfo::kArmFeatureASIMD); - - // Detect additional CPU features by calling `IsProcessorFeaturePresent()`. - struct WinPFPMapping { - uint32_t pfpId; - uint32_t featureId; - }; - - static const WinPFPMapping mapping[] = { - { PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE , CpuInfo::kArmFeatureVFPv4 }, - { PF_ARM_VFP_32_REGISTERS_AVAILABLE , CpuInfo::kArmFeatureVFP_D32 }, - { PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE, CpuInfo::kArmFeatureIDIVT }, - { PF_ARM_64BIT_LOADSTORE_ATOMIC , CpuInfo::kArmFeatureAtomics64 } - }; - - for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(mapping); i++) - if (::IsProcessorFeaturePresent(mapping[i].pfpId)) - cpuInfo->addFeature(mapping[i].featureId); -} -#endif // ASMJIT_OS_WINDOWS - -#if ASMJIT_OS_LINUX -struct LinuxHWCapMapping { - uint32_t hwcapMask; - uint32_t featureId; -}; - -static void armDetectHWCaps(CpuInfo* cpuInfo, unsigned long type, const LinuxHWCapMapping* mapping, size_t length) noexcept { - unsigned long mask = getauxval(type); - - for (size_t i = 0; i < length; i++) - if ((mask & mapping[i].hwcapMask) == mapping[i].hwcapMask) - cpuInfo->addFeature(mapping[i].featureId); -} - -//! \internal -//! -//! Detect ARM CPU features on Linux. -//! -//! The detection is based on `getauxval()`. -ASMJIT_FAVOR_SIZE static void armDetectCpuInfoOnLinux(CpuInfo* cpuInfo) noexcept { -#if ASMJIT_ARCH_ARM32 - armPopulateBaselineA32Features(cpuInfo); - - // `AT_HWCAP` provides ARMv7 (and less) related flags. - static const LinuxHWCapMapping hwCapMapping[] = { - { /* HWCAP_VFP */ (1 << 6), CpuInfo::kArmFeatureVFPv2 }, - { /* HWCAP_EDSP */ (1 << 7), CpuInfo::kArmFeatureEDSP }, - { /* HWCAP_NEON */ (1 << 12), CpuInfo::kArmFeatureASIMD }, - { /* HWCAP_VFPv3 */ (1 << 13), CpuInfo::kArmFeatureVFPv3 }, - { /* HWCAP_VFPv4 */ (1 << 16), CpuInfo::kArmFeatureVFPv4 }, - { /* HWCAP_IDIVA */ (1 << 17), CpuInfo::kArmFeatureIDIVA }, - { /* HWCAP_IDIVT */ (1 << 18), CpuInfo::kArmFeatureIDIVT }, - { /* HWCAP_VFPD32 */ (1 << 19), CpuInfo::kArmFeatureVFP_D32 } - }; - armDetectHWCaps(cpuInfo, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping)); - - // VFPv3 implies VFPv2. - if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv3)) { - cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2); - } - - // VFPv2 implies ARMv6. - if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv2)) { - cpuInfo->addFeature(CpuInfo::kArmFeatureV6); - } - - // VFPv3 or ASIMD implies ARMv7. - if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv3) || - cpuInfo->hasFeature(CpuInfo::kArmFeatureASIMD)) { - cpuInfo->addFeature(CpuInfo::kArmFeatureV7); - } - - // `AT_HWCAP2` provides ARMv8+ related flags. - static const LinuxHWCapMapping hwCap2Mapping[] = { - { /* HWCAP2_AES */ (1 << 0), CpuInfo::kArmFeatureAES }, - { /* HWCAP2_PMULL */ (1 << 1), CpuInfo::kArmFeaturePMULL }, - { /* HWCAP2_SHA1 */ (1 << 2), CpuInfo::kArmFeatureSHA1 }, - { /* HWCAP2_SHA2 */ (1 << 3), CpuInfo::kArmFeatureSHA256 }, - { /* HWCAP2_CRC32 */ (1 << 4), CpuInfo::kArmFeatureCRC32 } - }; - armDetectHWCaps(cpuInfo, AT_HWCAP2, hwCap2Mapping, ASMJIT_ARRAY_SIZE(hwCap2Mapping)); - - if (cpuInfo->hasFeature(CpuInfo::kArmFeatureAES ) || - cpuInfo->hasFeature(CpuInfo::kArmFeatureCRC32 ) || - cpuInfo->hasFeature(CpuInfo::kArmFeaturePMULL ) || - cpuInfo->hasFeature(CpuInfo::kArmFeatureSHA1 ) || - cpuInfo->hasFeature(CpuInfo::kArmFeatureSHA256)) { - cpuInfo->addFeature(CpuInfo::kArmFeatureV8); - } -#else - armPopulateBaselineA64Features(cpuInfo); - - // `AT_HWCAP` provides ARMv8+ related flags. - static const LinuxHWCapMapping hwCapMapping[] = { - { /* HWCAP_ASIMD */ (1 << 1), CpuInfo::kArmFeatureASIMD }, - { /* HWCAP_AES */ (1 << 3), CpuInfo::kArmFeatureAES }, - { /* HWCAP_CRC32 */ (1 << 7), CpuInfo::kArmFeatureCRC32 }, - { /* HWCAP_PMULL */ (1 << 4), CpuInfo::kArmFeaturePMULL }, - { /* HWCAP_SHA1 */ (1 << 5), CpuInfo::kArmFeatureSHA1 }, - { /* HWCAP_SHA2 */ (1 << 6), CpuInfo::kArmFeatureSHA256 }, - { /* HWCAP_ATOMICS */ (1 << 8), CpuInfo::kArmFeatureAtomics64 } - }; - armDetectHWCaps(cpuInfo, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping)); - - // `AT_HWCAP2` is not used at the moment. -#endif -} -#endif // ASMJIT_OS_LINUX - -ASMJIT_FAVOR_SIZE static void armDetectCpuInfo(CpuInfo* cpuInfo) noexcept { -#if ASMJIT_OS_WINDOWS - armDetectCpuInfoOnWindows(cpuInfo); -#elif ASMJIT_OS_LINUX - armDetectCpuInfoOnLinux(cpuInfo); -#else -# error "[asmjit] armDetectCpuInfo() - Unsupported OS." -#endif -} -#endif // ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 - -// ============================================================================ -// [asmjit::CpuInfo - Detect X86] -// ============================================================================ - -#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 - -//! \internal -//! -//! X86 CPUID result. -struct CpuIdResult { - uint32_t eax, ebx, ecx, edx; -}; - -//! \internal -//! -//! Content of XCR register, result of XGETBV instruction. -struct XGetBVResult { - uint32_t eax, edx; -}; - -#if ASMJIT_CC_MSC && !ASMJIT_CC_MSC_GE(15, 0, 30729) && ASMJIT_ARCH_X64 -//! \internal -//! -//! HACK: VS2008 or less, 64-bit mode - `__cpuidex` doesn't exist! However, -//! 64-bit calling convention specifies the first parameter to be passed by -//! ECX, so we may be lucky if compiler doesn't move the register, otherwise -//! the result would be wrong. -static void ASMJIT_NOINLINE void x86CallCpuIdWorkaround(uint32_t inEcx, uint32_t inEax, CpuIdResult* result) noexcept { - __cpuid(reinterpret_cast(result), inEax); -} -#endif - -//! \internal -//! -//! Wrapper to call `cpuid` instruction. -static void ASMJIT_INLINE x86CallCpuId(CpuIdResult* result, uint32_t inEax, uint32_t inEcx = 0) noexcept { -#if ASMJIT_CC_MSC && ASMJIT_CC_MSC_GE(15, 0, 30729) - __cpuidex(reinterpret_cast(result), inEax, inEcx); -#elif ASMJIT_CC_MSC && ASMJIT_ARCH_X64 - x86CallCpuIdWorkaround(inEcx, inEax, result); -#elif ASMJIT_CC_MSC && ASMJIT_ARCH_X86 - uint32_t paramEax = inEax; - uint32_t paramEcx = inEcx; - uint32_t* out = reinterpret_cast(result); - - __asm { - mov eax, paramEax - mov ecx, paramEcx - mov edi, out - cpuid - mov dword ptr[edi + 0], eax - mov dword ptr[edi + 4], ebx - mov dword ptr[edi + 8], ecx - mov dword ptr[edi + 12], edx - } -#elif (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && ASMJIT_ARCH_X86 - __asm__ __volatile__( - "mov %%ebx, %%edi\n" - "cpuid\n" - "xchg %%edi, %%ebx\n" - : "=a"(result->eax), - "=D"(result->ebx), - "=c"(result->ecx), - "=d"(result->edx) - : "a"(inEax), - "c"(inEcx)); -#elif (ASMJIT_CC_GCC || ASMJIT_CC_CLANG || ASMJIT_CC_INTEL) && ASMJIT_ARCH_X64 - __asm__ __volatile__( - "mov %%rbx, %%rdi\n" - "cpuid\n" - "xchg %%rdi, %%rbx\n" - : "=a"(result->eax), - "=D"(result->ebx), - "=c"(result->ecx), - "=d"(result->edx) - : "a"(inEax), - "c"(inEcx)); -#else -# error "[asmjit] x86CallCpuid() - Unsupported compiler." -#endif -} - -//! \internal -//! -//! Wrapper to call `xgetbv` instruction. -static ASMJIT_INLINE void x86CallXGetBV(XGetBVResult* result, uint32_t inEcx) noexcept { -#if ASMJIT_CC_MSC_GE(16, 0, 40219) // 2010SP1+ - uint64_t value = _xgetbv(inEcx); - result->eax = static_cast(value & 0xFFFFFFFFU); - result->edx = static_cast(value >> 32); -#elif ASMJIT_CC_GCC || ASMJIT_CC_CLANG - uint32_t outEax; - uint32_t outEdx; - - // Replaced, because the world is not perfect: - // __asm__ __volatile__("xgetbv" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx)); - __asm__ __volatile__(".byte 0x0F, 0x01, 0xd0" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx)); - - result->eax = outEax; - result->edx = outEdx; -#else - result->eax = 0; - result->edx = 0; -#endif -} - -//! \internal -//! -//! Map a 12-byte vendor string returned by `cpuid` into a `CpuInfo::Vendor` ID. -static ASMJIT_INLINE uint32_t x86GetCpuVendorID(const char* vendorString) noexcept { - struct VendorData { - uint32_t id; - char text[12]; - }; - - static const VendorData vendorList[] = { - { CpuInfo::kVendorIntel , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } }, - { CpuInfo::kVendorAMD , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } }, - { CpuInfo::kVendorVIA , { 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 } }, - { CpuInfo::kVendorVIA , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } } - }; - - uint32_t dw0 = reinterpret_cast(vendorString)[0]; - uint32_t dw1 = reinterpret_cast(vendorString)[1]; - uint32_t dw2 = reinterpret_cast(vendorString)[2]; - - for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(vendorList); i++) { - if (dw0 == reinterpret_cast(vendorList[i].text)[0] && - dw1 == reinterpret_cast(vendorList[i].text)[1] && - dw2 == reinterpret_cast(vendorList[i].text)[2]) - return vendorList[i].id; - } - - return CpuInfo::kVendorNone; -} - -static ASMJIT_INLINE void x86SimplifyBrandString(char* s) noexcept { - // Used to always clear the current character to ensure that the result - // doesn't contain garbage after the new zero terminator. - char* d = s; - - char prev = 0; - char curr = s[0]; - s[0] = '\0'; - - for (;;) { - if (curr == 0) - break; - - if (curr == ' ') { - if (prev == '@' || s[1] == ' ' || s[1] == '@') - goto L_Skip; - } - - d[0] = curr; - d++; - prev = curr; - -L_Skip: - curr = *++s; - s[0] = '\0'; - } - - d[0] = '\0'; -} - -ASMJIT_FAVOR_SIZE static void x86DetectCpuInfo(CpuInfo* cpuInfo) noexcept { - uint32_t i, maxId; - - CpuIdResult regs; - XGetBVResult xcr0 = { 0, 0 }; - - cpuInfo->_archInfo.init(ArchInfo::kTypeHost); - cpuInfo->addFeature(CpuInfo::kX86FeatureI486); - - // -------------------------------------------------------------------------- - // [CPUID EAX=0x0] - // -------------------------------------------------------------------------- - - // Get vendor string/id. - x86CallCpuId(®s, 0x0); - - maxId = regs.eax; - ::memcpy(cpuInfo->_vendorString + 0, ®s.ebx, 4); - ::memcpy(cpuInfo->_vendorString + 4, ®s.edx, 4); - ::memcpy(cpuInfo->_vendorString + 8, ®s.ecx, 4); - cpuInfo->_vendorId = x86GetCpuVendorID(cpuInfo->_vendorString); - - // -------------------------------------------------------------------------- - // [CPUID EAX=0x1] - // -------------------------------------------------------------------------- - - if (maxId >= 0x1) { - // Get feature flags in ECX/EDX and family/model in EAX. - x86CallCpuId(®s, 0x1); - - // Fill family and model fields. - cpuInfo->_family = (regs.eax >> 8) & 0x0F; - cpuInfo->_model = (regs.eax >> 4) & 0x0F; - cpuInfo->_stepping = (regs.eax ) & 0x0F; - - // Use extended family and model fields. - if (cpuInfo->_family == 0x0F) { - cpuInfo->_family += ((regs.eax >> 20) & 0xFF); - cpuInfo->_model += ((regs.eax >> 16) & 0x0F) << 4; - } - - cpuInfo->_x86Data._processorType = ((regs.eax >> 12) & 0x03); - cpuInfo->_x86Data._brandIndex = ((regs.ebx ) & 0xFF); - cpuInfo->_x86Data._flushCacheLineSize = ((regs.ebx >> 8) & 0xFF) * 8; - cpuInfo->_x86Data._maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF); - - if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE3); - if (regs.ecx & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeaturePCLMULQDQ); - if (regs.ecx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureMONITOR); - if (regs.ecx & 0x00000200U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSSE3); - if (regs.ecx & 0x00002000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMPXCHG16B); - if (regs.ecx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4_1); - if (regs.ecx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4_2); - if (regs.ecx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMOVBE); - if (regs.ecx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeaturePOPCNT); - if (regs.ecx & 0x02000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAESNI); - if (regs.ecx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVE); - if (regs.ecx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureOSXSAVE); - if (regs.ecx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDRAND); - if (regs.edx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDTSC); - if (regs.edx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureMSR); - if (regs.edx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMPXCHG8B); - if (regs.edx & 0x00008000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMOV); - if (regs.edx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLFLUSH); - if (regs.edx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMMX); - if (regs.edx & 0x01000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFXSR); - if (regs.edx & 0x02000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE) - .addFeature(CpuInfo::kX86FeatureMMX2); - if (regs.edx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE) - .addFeature(CpuInfo::kX86FeatureSSE2); - if (regs.edx & 0x10000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMT); - - // Get the content of XCR0 if supported by CPU and enabled by OS. - if ((regs.ecx & 0x0C000000U) == 0x0C000000U) { - x86CallXGetBV(&xcr0, 0); - } - - // Detect AVX+. - if (regs.ecx & 0x10000000U) { - // - XCR0[2:1] == 11b - // XMM & YMM states need to be enabled by OS. - if ((xcr0.eax & 0x00000006U) == 0x00000006U) { - cpuInfo->addFeature(CpuInfo::kX86FeatureAVX); - - if (regs.ecx & 0x00001000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFMA); - if (regs.ecx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureF16C); - } - } - } - - // -------------------------------------------------------------------------- - // [CPUID EAX=0x7] - // -------------------------------------------------------------------------- - - // Detect new features if the processor supports CPUID-07. - bool maybeMPX = false; - - if (maxId >= 0x7) { - x86CallCpuId(®s, 0x7); - - if (regs.ebx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureFSGSBASE); - if (regs.ebx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureBMI); - if (regs.ebx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureHLE); - if (regs.ebx & 0x00000080U) cpuInfo->addFeature(CpuInfo::kX86FeatureSMEP); - if (regs.ebx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeatureBMI2); - if (regs.ebx & 0x00000200U) cpuInfo->addFeature(CpuInfo::kX86FeatureERMS); - if (regs.ebx & 0x00000800U) cpuInfo->addFeature(CpuInfo::kX86FeatureRTM); - if (regs.ebx & 0x00004000U) maybeMPX = true; - if (regs.ebx & 0x00040000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDSEED); - if (regs.ebx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureADX); - if (regs.ebx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSMAP); - if (regs.ebx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeaturePCOMMIT); - if (regs.ebx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLFLUSHOPT); - if (regs.ebx & 0x01000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLWB); - if (regs.ebx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSHA); - if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHWT1); - - // TSX is supported if at least one of `HLE` and `RTM` is supported. - if (regs.ebx & 0x00000810U) cpuInfo->addFeature(CpuInfo::kX86FeatureTSX); - - // Detect AVX2. - if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) { - if (regs.ebx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX2); - } - - // Detect AVX-512+. - if (regs.ebx & 0x00010000U) { - // - XCR0[2:1] == 11b - // XMM/YMM states need to be enabled by OS. - // - XCR0[7:5] == 111b - // Upper 256-bit of ZMM0-XMM15 and ZMM16-ZMM31 need to be enabled by the OS. - if ((xcr0.eax & 0x000000E6U) == 0x000000E6U) { - cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_F); - - if (regs.ebx & 0x00020000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_DQ); - if (regs.ebx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_IFMA); - if (regs.ebx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_PFI); - if (regs.ebx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_ERI); - if (regs.ebx & 0x10000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_CDI); - if (regs.ebx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_BW); - if (regs.ebx & 0x80000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VL); - if (regs.ecx & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VBMI); - if (regs.ecx & 0x00004000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VPOPCNTDQ); - if (regs.edx & 0x00000004U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_4VNNIW); - if (regs.edx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_4FMAPS); - } - } - } - - // -------------------------------------------------------------------------- - // [CPUID EAX=0xD] - // -------------------------------------------------------------------------- - - if (maxId >= 0xD) { - x86CallCpuId(®s, 0xD, 0); - - // Both CPUID result and XCR0 has to be enabled to have support for MPX. - if (((regs.eax & xcr0.eax) & 0x00000018U) == 0x00000018U && maybeMPX) - cpuInfo->addFeature(CpuInfo::kX86FeatureMPX); - - x86CallCpuId(®s, 0xD, 1); - if (regs.eax & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVEOPT); - if (regs.eax & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVEC); - if (regs.eax & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVES); - } - - // -------------------------------------------------------------------------- - // [CPUID EAX=0x80000000...maxId] - // -------------------------------------------------------------------------- - - // The highest EAX that we understand. - uint32_t kHighestProcessedEAX = 0x80000008U; - - // Several CPUID calls are required to get the whole branc string. It's easy - // to copy one DWORD at a time instead of performing a byte copy. - uint32_t* brand = reinterpret_cast(cpuInfo->_brandString); - - i = maxId = 0x80000000U; - do { - x86CallCpuId(®s, i); - switch (i) { - case 0x80000000U: - maxId = std::min(regs.eax, kHighestProcessedEAX); - break; - - case 0x80000001U: - if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureLAHFSAHF); - if (regs.ecx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureLZCNT); - if (regs.ecx & 0x00000040U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4A); - if (regs.ecx & 0x00000080U) cpuInfo->addFeature(CpuInfo::kX86FeatureMSSE); - if (regs.ecx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHW); - if (regs.ecx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureTBM); - if (regs.edx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureNX); - if (regs.edx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFXSROPT); - if (regs.edx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMMX2); - if (regs.edx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDTSCP); - if (regs.edx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86Feature3DNOW2) - .addFeature(CpuInfo::kX86FeatureMMX2); - if (regs.edx & 0x80000000U) cpuInfo->addFeature(CpuInfo::kX86Feature3DNOW); - - if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) { - if (regs.ecx & 0x00000800U) cpuInfo->addFeature(CpuInfo::kX86FeatureXOP); - if (regs.ecx & 0x00010000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFMA4); - } - - // These seem to be only supported by AMD. - if (cpuInfo->getVendorId() == CpuInfo::kVendorAMD) { - if (regs.ecx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureALTMOVCR8); - } - break; - - case 0x80000002U: - case 0x80000003U: - case 0x80000004U: - *brand++ = regs.eax; - *brand++ = regs.ebx; - *brand++ = regs.ecx; - *brand++ = regs.edx; - - // Go directly to the last one. - if (i == 0x80000004U) i = 0x80000008U - 1; - break; - - case 0x80000008U: - if (regs.ebx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLZERO); - break; - } - } while (++i <= maxId); - - // Simplify CPU brand string by removing unnecessary spaces. - x86SimplifyBrandString(cpuInfo->_brandString); -} -#endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 - -// ============================================================================ -// [asmjit::CpuInfo - Detect - HWThreadsCount] -// ============================================================================ - -static ASMJIT_INLINE uint32_t cpuDetectHWThreadsCount() noexcept { -#if ASMJIT_OS_WINDOWS - SYSTEM_INFO info; - ::GetSystemInfo(&info); - return info.dwNumberOfProcessors; -#elif ASMJIT_OS_POSIX && defined(_SC_NPROCESSORS_ONLN) - long res = ::sysconf(_SC_NPROCESSORS_ONLN); - if (res <= 0) return 1; - return static_cast(res); -#else - return 1; -#endif -} - -// ============================================================================ -// [asmjit::CpuInfo - Detect] -// ============================================================================ - -ASMJIT_FAVOR_SIZE void CpuInfo::detect() noexcept { - reset(); - -#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 - armDetectCpuInfo(this); -#endif // ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 - -#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 - x86DetectCpuInfo(this); -#endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 - - _hwThreadsCount = cpuDetectHWThreadsCount(); -} - -// ============================================================================ -// [asmjit::CpuInfo - GetHost] -// ============================================================================ - -struct HostCpuInfo : public CpuInfo { - ASMJIT_INLINE HostCpuInfo() noexcept : CpuInfo() { detect(); } -}; - -const CpuInfo& CpuInfo::getHost() noexcept { - static HostCpuInfo host; - return host; -} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/cpuinfo.h b/libs/asmjit/base/cpuinfo.h deleted file mode 100644 index 268d37e8..00000000 --- a/libs/asmjit/base/cpuinfo.h +++ /dev/null @@ -1,373 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_CPUINFO_H -#define _ASMJIT_BASE_CPUINFO_H - -// [Dependencies] -#include "../base/arch.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::CpuFeatures] -// ============================================================================ - -class CpuFeatures { -public: - typedef uintptr_t BitWord; - - enum { - kMaxFeatures = 128, - kBitWordSize = static_cast(sizeof(BitWord)) * 8, - kNumBitWords = kMaxFeatures / kBitWordSize - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE CpuFeatures() noexcept { reset(); } - ASMJIT_INLINE CpuFeatures(const CpuFeatures& other) noexcept { init(other); } - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void init(const CpuFeatures& other) noexcept { ::memcpy(this, &other, sizeof(*this)); } - ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); } - - // -------------------------------------------------------------------------- - // [Ops] - // -------------------------------------------------------------------------- - - //! Get all features as `BitWord` array. - ASMJIT_INLINE BitWord* getBits() noexcept { return _bits; } - //! Get all features as `BitWord` array (const). - ASMJIT_INLINE const BitWord* getBits() const noexcept { return _bits; } - - //! Get if feature `feature` is present. - ASMJIT_INLINE bool has(uint32_t feature) const noexcept { - ASMJIT_ASSERT(feature < kMaxFeatures); - - uint32_t idx = feature / kBitWordSize; - uint32_t bit = feature % kBitWordSize; - - return static_cast((_bits[idx] >> bit) & 0x1); - } - - //! Get if all features as defined by `other` are present. - ASMJIT_INLINE bool hasAll(const CpuFeatures& other) const noexcept { - for (uint32_t i = 0; i < kNumBitWords; i++) - if ((_bits[i] & other._bits[i]) != other._bits[i]) - return false; - return true; - } - - //! Add a CPU `feature`. - ASMJIT_INLINE CpuFeatures& add(uint32_t feature) noexcept { - ASMJIT_ASSERT(feature < kMaxFeatures); - - uint32_t idx = feature / kBitWordSize; - uint32_t bit = feature % kBitWordSize; - - _bits[idx] |= static_cast(1) << bit; - return *this; - } - - //! Remove a CPU `feature`. - ASMJIT_INLINE CpuFeatures& remove(uint32_t feature) noexcept { - ASMJIT_ASSERT(feature < kMaxFeatures); - - uint32_t idx = feature / kBitWordSize; - uint32_t bit = feature % kBitWordSize; - - _bits[idx] &= ~(static_cast(1) << bit); - return *this; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - BitWord _bits[kNumBitWords]; -}; - -// ============================================================================ -// [asmjit::CpuInfo] -// ============================================================================ - -//! CPU information. -class CpuInfo { -public: - //! CPU vendor ID. - ASMJIT_ENUM(Vendor) { - kVendorNone = 0, //!< Generic or unknown. - kVendorIntel = 1, //!< Intel vendor. - kVendorAMD = 2, //!< AMD vendor. - kVendorVIA = 3 //!< VIA vendor. - }; - - //! ARM/ARM64 CPU features. - ASMJIT_ENUM(ArmFeatures) { - kArmFeatureV6 = 1, //!< ARMv6 instruction set. - kArmFeatureV7, //!< ARMv7 instruction set. - kArmFeatureV8, //!< ARMv8 instruction set. - kArmFeatureTHUMB, //!< CPU provides THUMB v1 instruction set (THUMB mode). - kArmFeatureTHUMB2, //!< CPU provides THUMB v2 instruction set (THUMB mode). - kArmFeatureVFPv2, //!< CPU provides VFPv2 instruction set. - kArmFeatureVFPv3, //!< CPU provides VFPv3 instruction set. - kArmFeatureVFPv4, //!< CPU provides VFPv4 instruction set. - kArmFeatureVFP_D32, //!< CPU provides 32 VFP-D (64-bit) registers. - kArmFeatureEDSP, //!< CPU provides EDSP extensions. - kArmFeatureASIMD, //!< CPU provides 'Advanced SIMD'. - kArmFeatureIDIVA, //!< CPU provides hardware SDIV and UDIV (ARM mode). - kArmFeatureIDIVT, //!< CPU provides hardware SDIV and UDIV (THUMB mode). - kArmFeatureAES, //!< CPU provides AES instructions (ARM64 only). - kArmFeatureCRC32, //!< CPU provides CRC32 instructions. - kArmFeaturePMULL, //!< CPU provides PMULL instructions (ARM64 only). - kArmFeatureSHA1, //!< CPU provides SHA1 instructions. - kArmFeatureSHA256, //!< CPU provides SHA256 instructions. - kArmFeatureAtomics64, //!< CPU provides 64-bit load/store atomics (ARM64 only). - - kArmFeaturesCount //!< Count of ARM/ARM64 CPU features. - }; - - //! X86/X64 CPU features. - ASMJIT_ENUM(X86Features) { - kX86FeatureI486 = 1, //!< CPU is at least I486. - kX86FeatureNX, //!< CPU has Not-Execute-Bit. - kX86FeatureMT, //!< CPU has multi-threading. - kX86FeatureALTMOVCR8, //!< CPU supports `LOCK MOV CR8` (AMD CPUs). - kX86FeatureCMOV, //!< CPU has CMOV. - kX86FeatureCMPXCHG8B, //!< CPU has CMPXCHG8B. - kX86FeatureCMPXCHG16B, //!< CPU has CMPXCHG16B (x64). - kX86FeatureMSR, //!< CPU has RDMSR/WRMSR. - kX86FeatureRDTSC, //!< CPU has RDTSC. - kX86FeatureRDTSCP, //!< CPU has RDTSCP. - kX86FeatureCLFLUSH, //!< CPU has CLFUSH. - kX86FeatureCLFLUSHOPT, //!< CPU has CLFUSHOPT. - kX86FeatureCLWB, //!< CPU has CLWB. - kX86FeatureCLZERO, //!< CPU has CLZERO. - kX86FeaturePCOMMIT, //!< CPU has PCOMMIT. - kX86FeaturePREFETCHW, //!< CPU has PREFETCHW. - kX86FeaturePREFETCHWT1, //!< CPU has PREFETCHWT1. - kX86FeatureLAHFSAHF, //!< CPU has LAHF/SAHF. - kX86FeatureFXSR, //!< CPU has FXSAVE/FXRSTOR. - kX86FeatureFXSROPT, //!< CPU has FXSAVE/FXRSTOR (optimized). - kX86FeatureMMX, //!< CPU has MMX. - kX86FeatureMMX2, //!< CPU has extended MMX. - kX86Feature3DNOW, //!< CPU has 3DNOW. - kX86Feature3DNOW2, //!< CPU has 3DNOW2 (enhanced). - kX86FeatureGEODE, //!< CPU has GEODE extensions (few additions to 3DNOW). - kX86FeatureSSE, //!< CPU has SSE. - kX86FeatureSSE2, //!< CPU has SSE2. - kX86FeatureSSE3, //!< CPU has SSE3. - kX86FeatureSSSE3, //!< CPU has SSSE3. - kX86FeatureSSE4A, //!< CPU has SSE4.A. - kX86FeatureSSE4_1, //!< CPU has SSE4.1. - kX86FeatureSSE4_2, //!< CPU has SSE4.2. - kX86FeatureMSSE, //!< CPU has Misaligned SSE (MSSE). - kX86FeatureMONITOR, //!< CPU has MONITOR and MWAIT. - kX86FeatureMOVBE, //!< CPU has MOVBE. - kX86FeaturePOPCNT, //!< CPU has POPCNT. - kX86FeatureLZCNT, //!< CPU has LZCNT. - kX86FeatureAESNI, //!< CPU has AESNI. - kX86FeaturePCLMULQDQ, //!< CPU has PCLMULQDQ. - kX86FeatureRDRAND, //!< CPU has RDRAND. - kX86FeatureRDSEED, //!< CPU has RDSEED. - kX86FeatureSMAP, //!< CPU has SMAP (supervisor-mode access prevention). - kX86FeatureSMEP, //!< CPU has SMEP (supervisor-mode execution prevention). - kX86FeatureSHA, //!< CPU has SHA-1 and SHA-256. - kX86FeatureXSAVE, //!< CPU has XSAVE support (XSAVE/XRSTOR, XSETBV/XGETBV, and XCR). - kX86FeatureXSAVEC, //!< CPU has XSAVEC support (XSAVEC). - kX86FeatureXSAVES, //!< CPU has XSAVES support (XSAVES/XRSTORS). - kX86FeatureXSAVEOPT, //!< CPU has XSAVEOPT support (XSAVEOPT/XSAVEOPT64). - kX86FeatureOSXSAVE, //!< CPU has XSAVE enabled by OS. - kX86FeatureAVX, //!< CPU has AVX. - kX86FeatureAVX2, //!< CPU has AVX2. - kX86FeatureF16C, //!< CPU has F16C. - kX86FeatureFMA, //!< CPU has FMA. - kX86FeatureFMA4, //!< CPU has FMA4. - kX86FeatureXOP, //!< CPU has XOP. - kX86FeatureBMI, //!< CPU has BMI (bit manipulation instructions #1). - kX86FeatureBMI2, //!< CPU has BMI2 (bit manipulation instructions #2). - kX86FeatureADX, //!< CPU has ADX (multi-precision add-carry instruction extensions). - kX86FeatureTBM, //!< CPU has TBM (trailing bit manipulation). - kX86FeatureMPX, //!< CPU has MPX (memory protection extensions). - kX86FeatureHLE, //!< CPU has HLE. - kX86FeatureRTM, //!< CPU has RTM. - kX86FeatureTSX, //!< CPU has TSX. - kX86FeatureERMS, //!< CPU has ERMS (enhanced REP MOVSB/STOSB). - kX86FeatureFSGSBASE, //!< CPU has FSGSBASE. - kX86FeatureAVX512_F, //!< CPU has AVX512-F (foundation). - kX86FeatureAVX512_CDI, //!< CPU has AVX512-CDI (conflict detection). - kX86FeatureAVX512_PFI, //!< CPU has AVX512-PFI (prefetch instructions). - kX86FeatureAVX512_ERI, //!< CPU has AVX512-ERI (exponential and reciprocal). - kX86FeatureAVX512_DQ, //!< CPU has AVX512-DQ (DWORD/QWORD). - kX86FeatureAVX512_BW, //!< CPU has AVX512-BW (BYTE/WORD). - kX86FeatureAVX512_VL, //!< CPU has AVX512-VL (vector length extensions). - kX86FeatureAVX512_IFMA, //!< CPU has AVX512-IFMA (integer fused-multiply-add using 52-bit precision). - kX86FeatureAVX512_VBMI, //!< CPU has AVX512-VBMI (vector byte manipulation). - kX86FeatureAVX512_VPOPCNTDQ, //!< CPU has AVX512-VPOPCNTDQ (VPOPCNT[D|Q] instructions). - kX86FeatureAVX512_4VNNIW, //!< CPU has AVX512-VNNIW (vector NN instructions word variable precision). - kX86FeatureAVX512_4FMAPS, //!< CPU has AVX512-FMAPS (FMA packed single). - - kX86FeaturesCount //!< Count of X86/X64 CPU features. - }; - - // -------------------------------------------------------------------------- - // [ArmInfo] - // -------------------------------------------------------------------------- - - struct ArmData { - }; - - // -------------------------------------------------------------------------- - // [X86Info] - // -------------------------------------------------------------------------- - - struct X86Data { - uint32_t _processorType; //!< Processor type. - uint32_t _brandIndex; //!< Brand index. - uint32_t _flushCacheLineSize; //!< Flush cache line size (in bytes). - uint32_t _maxLogicalProcessors; //!< Maximum number of addressable IDs for logical processors. - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE CpuInfo() noexcept { reset(); } - ASMJIT_INLINE CpuInfo(const CpuInfo& other) noexcept { init(other); } - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - //! Initialize CpuInfo to the given architecture, see \ArchInfo. - ASMJIT_INLINE void initArch(uint32_t archType, uint32_t archMode = 0) noexcept { - _archInfo.init(archType, archMode); - } - - ASMJIT_INLINE void init(const CpuInfo& other) noexcept { ::memcpy(this, &other, sizeof(*this)); } - ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); } - - // -------------------------------------------------------------------------- - // [Detect] - // -------------------------------------------------------------------------- - - ASMJIT_API void detect() noexcept; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get generic architecture information. - ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _archInfo; } - //! Get CPU architecture type, see \ArchInfo::Type. - ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archInfo.getType(); } - //! Get CPU architecture sub-type, see \ArchInfo::SubType. - ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _archInfo.getSubType(); } - - //! Get CPU vendor ID. - ASMJIT_INLINE uint32_t getVendorId() const noexcept { return _vendorId; } - //! Get CPU family ID. - ASMJIT_INLINE uint32_t getFamily() const noexcept { return _family; } - //! Get CPU model ID. - ASMJIT_INLINE uint32_t getModel() const noexcept { return _model; } - //! Get CPU stepping. - ASMJIT_INLINE uint32_t getStepping() const noexcept { return _stepping; } - - //! Get number of hardware threads available. - ASMJIT_INLINE uint32_t getHwThreadsCount() const noexcept { - return _hwThreadsCount; - } - - //! Get all CPU features. - ASMJIT_INLINE const CpuFeatures& getFeatures() const noexcept { return _features; } - //! Get whether CPU has a `feature`. - ASMJIT_INLINE bool hasFeature(uint32_t feature) const noexcept { return _features.has(feature); } - //! Add a CPU `feature`. - ASMJIT_INLINE CpuInfo& addFeature(uint32_t feature) noexcept { _features.add(feature); return *this; } - - //! Get CPU vendor string. - ASMJIT_INLINE const char* getVendorString() const noexcept { return _vendorString; } - //! Get CPU brand string. - ASMJIT_INLINE const char* getBrandString() const noexcept { return _brandString; } - - // -------------------------------------------------------------------------- - // [Accessors - ARM] - // -------------------------------------------------------------------------- - - // -------------------------------------------------------------------------- - // [Accessors - X86] - // -------------------------------------------------------------------------- - - //! Get processor type. - ASMJIT_INLINE uint32_t getX86ProcessorType() const noexcept { - return _x86Data._processorType; - } - - //! Get brand index. - ASMJIT_INLINE uint32_t getX86BrandIndex() const noexcept { - return _x86Data._brandIndex; - } - - //! Get flush cache line size. - ASMJIT_INLINE uint32_t getX86FlushCacheLineSize() const noexcept { - return _x86Data._flushCacheLineSize; - } - - //! Get maximum logical processors count. - ASMJIT_INLINE uint32_t getX86MaxLogicalProcessors() const noexcept { - return _x86Data._maxLogicalProcessors; - } - - // -------------------------------------------------------------------------- - // [Statics] - // -------------------------------------------------------------------------- - - //! Get the host CPU information. - ASMJIT_API static const CpuInfo& getHost() noexcept; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - ArchInfo _archInfo; //!< CPU architecture information. - uint32_t _vendorId; //!< CPU vendor id, see \ref Vendor. - uint32_t _family; //!< CPU family ID. - uint32_t _model; //!< CPU model ID. - uint32_t _stepping; //!< CPU stepping. - uint32_t _hwThreadsCount; //!< Number of hardware threads. - CpuFeatures _features; //!< CPU features. - char _vendorString[16]; //!< CPU vendor string. - char _brandString[64]; //!< CPU brand string. - - // Architecture specific data. - union { - ArmData _armData; - X86Data _x86Data; - }; -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_CPUINFO_H diff --git a/libs/asmjit/base/func.cpp b/libs/asmjit/base/func.cpp deleted file mode 100644 index 52107655..00000000 --- a/libs/asmjit/base/func.cpp +++ /dev/null @@ -1,186 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/arch.h" -#include "../base/func.h" - -#if defined(ASMJIT_BUILD_X86) -#include "../x86/x86internal_p.h" -#include "../x86/x86operand.h" -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) -#include "../arm/arminternal_p.h" -#include "../arm/armoperand.h" -#endif // ASMJIT_BUILD_ARM - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::CallConv - Init / Reset] -// ============================================================================ - -ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId) noexcept { - reset(); - -#if defined(ASMJIT_BUILD_X86) - if (CallConv::isX86Family(ccId)) - return X86Internal::initCallConv(*this, ccId); -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) - if (CallConv::isArmFamily(ccId)) - return ArmInternal::initCallConv(*this, ccId); -#endif // ASMJIT_BUILD_ARM - - return DebugUtils::errored(kErrorInvalidArgument); -} - -// ============================================================================ -// [asmjit::FuncDetail - Init / Reset] -// ============================================================================ - -ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& sign) { - uint32_t ccId = sign.getCallConv(); - CallConv& cc = _callConv; - - uint32_t argCount = sign.getArgCount(); - if (ASMJIT_UNLIKELY(argCount > kFuncArgCount)) - return DebugUtils::errored(kErrorInvalidArgument); - - ASMJIT_PROPAGATE(cc.init(ccId)); - - uint32_t gpSize = (cc.getArchType() == ArchInfo::kTypeX86) ? 4 : 8; - uint32_t deabstractDelta = TypeId::deabstractDeltaOfSize(gpSize); - - const uint8_t* args = sign.getArgs(); - for (uint32_t i = 0; i < argCount; i++) { - Value& arg = _args[i]; - arg.initTypeId(TypeId::deabstract(args[i], deabstractDelta)); - } - _argCount = static_cast(argCount); - - uint32_t ret = sign.getRet(); - if (ret != TypeId::kVoid) { - _rets[0].initTypeId(TypeId::deabstract(ret, deabstractDelta)); - _retCount = 1; - } - -#if defined(ASMJIT_BUILD_X86) - if (CallConv::isX86Family(ccId)) - return X86Internal::initFuncDetail(*this, sign, gpSize); -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) - if (CallConv::isArmFamily(ccId)) - return ArmInternal::initFuncDetail(*this, sign, gpSize); -#endif // ASMJIT_BUILD_ARM - - // We should never bubble here as if `cc.init()` succeeded then there has to - // be an implementation for the current architecture. However, stay safe. - return DebugUtils::errored(kErrorInvalidArgument); -} - -// ============================================================================ -// [asmjit::FuncFrameLayout - Init / Reset] -// ============================================================================ - -ASMJIT_FAVOR_SIZE Error FuncFrameLayout::init(const FuncDetail& func, const FuncFrameInfo& ffi) noexcept { - uint32_t ccId = func.getCallConv().getId(); - -#if defined(ASMJIT_BUILD_X86) - if (CallConv::isX86Family(ccId)) - return X86Internal::initFrameLayout(*this, func, ffi); -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) - if (CallConv::isArmFamily(ccId)) - return ArmInternal::initFrameLayout(*this, func, ffi); -#endif // ASMJIT_BUILD_ARM - - return DebugUtils::errored(kErrorInvalidArgument); -} - -// ============================================================================ -// [asmjit::FuncArgsMapper] -// ============================================================================ - -ASMJIT_FAVOR_SIZE Error FuncArgsMapper::updateFrameInfo(FuncFrameInfo& ffi) const noexcept { - const FuncDetail* func = getFuncDetail(); - if (!func) return DebugUtils::errored(kErrorInvalidState); - - uint32_t ccId = func->getCallConv().getId(); - -#if defined(ASMJIT_BUILD_X86) - if (CallConv::isX86Family(ccId)) - return X86Internal::argsToFrameInfo(*this, ffi); -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) - if (CallConv::isArmFamily(ccId)) - return ArmInternal::argsToFrameInfo(*this, ffi); -#endif // ASMJIT_BUILD_X86 - - return DebugUtils::errored(kErrorInvalidArch); -} - -// ============================================================================ -// [asmjit::FuncUtils] -// ============================================================================ - -ASMJIT_FAVOR_SIZE Error FuncUtils::emitProlog(CodeEmitter* emitter, const FuncFrameLayout& layout) { -#if defined(ASMJIT_BUILD_X86) - if (emitter->getArchInfo().isX86Family()) - return X86Internal::emitProlog(static_cast(emitter), layout); -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) - if (emitter->getArchInfo().isArmFamily()) - return ArmInternal::emitProlog(static_cast(emitter), layout); -#endif // ASMJIT_BUILD_ARM - - return DebugUtils::errored(kErrorInvalidArch); -} - -ASMJIT_FAVOR_SIZE Error FuncUtils::emitEpilog(CodeEmitter* emitter, const FuncFrameLayout& layout) { -#if defined(ASMJIT_BUILD_X86) - if (emitter->getArchInfo().isX86Family()) - return X86Internal::emitEpilog(static_cast(emitter), layout); -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) - if (emitter->getArchInfo().isArmFamily()) - return ArmInternal::emitEpilog(static_cast(emitter), layout); -#endif // ASMJIT_BUILD_ARM - - return DebugUtils::errored(kErrorInvalidArch); -} - -ASMJIT_FAVOR_SIZE Error FuncUtils::allocArgs(CodeEmitter* emitter, const FuncFrameLayout& layout, const FuncArgsMapper& args) { -#if defined(ASMJIT_BUILD_X86) - if (emitter->getArchInfo().isX86Family()) - return X86Internal::allocArgs(static_cast(emitter), layout, args); -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) - if (emitter->getArchInfo().isArmFamily()) - return ArmInternal::allocArgs(static_cast(emitter), layout, args); -#endif // ASMJIT_BUILD_ARM - - return DebugUtils::errored(kErrorInvalidArch); -} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/func.h b/libs/asmjit/base/func.h deleted file mode 100644 index c9ab0529..00000000 --- a/libs/asmjit/base/func.h +++ /dev/null @@ -1,1296 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_FUNC_H -#define _ASMJIT_BASE_FUNC_H - -#include "../asmjit_build.h" - -// [Dependencies] -#include "../base/arch.h" -#include "../base/operand.h" -#include "../base/utils.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -class CodeEmitter; - -// ============================================================================ -// [asmjit::CallConv] -// ============================================================================ - -//! Function calling convention. -//! -//! Function calling convention is a scheme that defines how function parameters -//! are passed and how function returns its result. AsmJit defines a variety of -//! architecture and OS specific calling conventions and also provides a compile -//! time detection to make JIT code-generation easier. -struct CallConv { - //! Calling convention id. - ASMJIT_ENUM(Id) { - //! None or invalid (can't be used). - kIdNone = 0, - - // ------------------------------------------------------------------------ - // [Universal] - // ------------------------------------------------------------------------ - - // TODO: To make this possible we need to know target ARCH and ABI. - - /* - - // Universal calling conventions are applicable to any target and are - // converted to target dependent conventions at runtime. The purpose of - // these conventions is to make using functions less target dependent. - - kIdCDecl = 1, - kIdStdCall = 2, - kIdFastCall = 3, - - //! AsmJit specific calling convention designed for calling functions - //! inside a multimedia code like that don't use many registers internally, - //! but are long enough to be called and not inlined. These functions are - //! usually used to calculate trigonometric functions, logarithms, etc... - kIdFastEval2 = 10, - kIdFastEval3 = 11, - kIdFastEval4 = 12, - */ - - // ------------------------------------------------------------------------ - // [X86] - // ------------------------------------------------------------------------ - - //! X86 `__cdecl` calling convention (used by C runtime and libraries). - kIdX86CDecl = 16, - //! X86 `__stdcall` calling convention (used mostly by WinAPI). - kIdX86StdCall = 17, - //! X86 `__thiscall` calling convention (MSVC/Intel). - kIdX86MsThisCall = 18, - //! X86 `__fastcall` convention (MSVC/Intel). - kIdX86MsFastCall = 19, - //! X86 `__fastcall` convention (GCC and Clang). - kIdX86GccFastCall = 20, - //! X86 `regparm(1)` convention (GCC and Clang). - kIdX86GccRegParm1 = 21, - //! X86 `regparm(2)` convention (GCC and Clang). - kIdX86GccRegParm2 = 22, - //! X86 `regparm(3)` convention (GCC and Clang). - kIdX86GccRegParm3 = 23, - - kIdX86FastEval2 = 29, - kIdX86FastEval3 = 30, - kIdX86FastEval4 = 31, - - //! X64 calling convention defined by WIN64-ABI. - //! - //! Links: - //! * . - kIdX86Win64 = 32, - //! X64 calling convention used by Unix platforms (SYSV/AMD64-ABI). - kIdX86SysV64 = 33, - - kIdX64FastEval2 = 45, - kIdX64FastEval3 = 46, - kIdX64FastEval4 = 47, - - // ------------------------------------------------------------------------ - // [ARM] - // ------------------------------------------------------------------------ - - //! Legacy calling convention, floating point arguments are passed via GP registers. - kIdArm32SoftFP = 48, - //! Modern calling convention, uses VFP registers to pass floating point arguments. - kIdArm32HardFP = 49, - - // ------------------------------------------------------------------------ - // [Internal] - // ------------------------------------------------------------------------ - - _kIdX86Start = 16, //!< \internal - _kIdX86End = 31, //!< \internal - - _kIdX64Start = 32, //!< \internal - _kIdX64End = 47, //!< \internal - - _kIdArmStart = 48, //!< \internal - _kIdArmEnd = 49, //!< \internal - - // ------------------------------------------------------------------------ - // [Host] - // ------------------------------------------------------------------------ - -#if defined(ASMJIT_DOCGEN) - //! Default calling convention based on the current C++ compiler's settings. - //! - //! NOTE: This should be always the same as `kIdHostCDecl`, but some - //! compilers allow to override the default calling convention. Overriding - //! is not detected at the moment. - kIdHost = DETECTED_AT_COMPILE_TIME, - - //! Default CDECL calling convention based on the current C++ compiler's settings. - kIdHostCDecl = DETECTED_AT_COMPILE_TIME, - - //! Default STDCALL calling convention based on the current C++ compiler's settings. - //! - //! NOTE: If not defined by the host then it's the same as `kIdHostCDecl`. - kIdHostStdCall = DETECTED_AT_COMPILE_TIME, - - //! Compatibility for `__fastcall` calling convention. - //! - //! NOTE: If not defined by the host then it's the same as `kIdHostCDecl`. - kIdHostFastCall = DETECTED_AT_COMPILE_TIME -#elif ASMJIT_ARCH_X86 - kIdHost = kIdX86CDecl, - kIdHostCDecl = kIdX86CDecl, - kIdHostStdCall = kIdX86StdCall, - kIdHostFastCall = ASMJIT_CC_MSC ? kIdX86MsFastCall : - ASMJIT_CC_GCC ? kIdX86GccFastCall : - ASMJIT_CC_CLANG ? kIdX86GccFastCall : kIdNone, - kIdHostFastEval2 = kIdX86FastEval2, - kIdHostFastEval3 = kIdX86FastEval3, - kIdHostFastEval4 = kIdX86FastEval4 -#elif ASMJIT_ARCH_X64 - kIdHost = ASMJIT_OS_WINDOWS ? kIdX86Win64 : kIdX86SysV64, - kIdHostCDecl = kIdHost, // Doesn't exist, redirected to host. - kIdHostStdCall = kIdHost, // Doesn't exist, redirected to host. - kIdHostFastCall = kIdHost, // Doesn't exist, redirected to host. - kIdHostFastEval2 = kIdX64FastEval2, - kIdHostFastEval3 = kIdX64FastEval3, - kIdHostFastEval4 = kIdX64FastEval4 -#elif ASMJIT_ARCH_ARM32 -# if defined(__SOFTFP__) - kIdHost = kIdArm32SoftFP, -# else - kIdHost = kIdArm32HardFP, -# endif - // These don't exist on ARM. - kIdHostCDecl = kIdHost, // Doesn't exist, redirected to host. - kIdHostStdCall = kIdHost, // Doesn't exist, redirected to host. - kIdHostFastCall = kIdHost // Doesn't exist, redirected to host. -#else -# error "[asmjit] Couldn't determine the target's calling convention." -#endif - }; - - //! Calling convention algorithm. - //! - //! This is AsmJit specific. It basically describes how should AsmJit convert - //! the function arguments defined by `FuncSignature` into register ids or - //! stack offsets. The default algorithm is a standard algorithm that assigns - //! registers first, and then assigns stack. The Win64 algorithm does register - //! shadowing as defined by `WIN64` calling convention - it applies to 64-bit - //! calling conventions only. - ASMJIT_ENUM(Algorithm) { - kAlgorithmDefault = 0, //!< Default algorithm (cross-platform). - kAlgorithmWin64 = 1 //!< WIN64 specific algorithm. - }; - - //! Calling convention flags. - ASMJIT_ENUM(Flags) { - kFlagCalleePopsStack = 0x01, //!< Callee is responsible for cleaning up the stack. - kFlagPassFloatsByVec = 0x02, //!< Pass F32 and F64 arguments by VEC128 register. - kFlagVectorCall = 0x04, //!< This is a '__vectorcall' calling convention. - kFlagIndirectVecArgs = 0x08 //!< Pass vector arguments indirectly (as a pointer). - }; - - //! Internal limits of AsmJit/CallConv. - ASMJIT_ENUM(Limits) { - kMaxVRegKinds = Globals::kMaxVRegKinds, - kNumRegArgsPerKind = 8 - }; - - //! Passed registers' order. - union RegOrder { - uint8_t id[kNumRegArgsPerKind]; //!< Passed registers, ordered. - uint32_t packed[(kNumRegArgsPerKind + 3) / 4]; - }; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE bool isX86Family(uint32_t ccId) noexcept { return ccId >= _kIdX86Start && ccId <= _kIdX64End; } - static ASMJIT_INLINE bool isArmFamily(uint32_t ccId) noexcept { return ccId >= _kIdArmStart && ccId <= _kIdArmEnd; } - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - ASMJIT_API Error init(uint32_t ccId) noexcept; - - ASMJIT_INLINE void reset() noexcept { - ::memset(this, 0, sizeof(*this)); - ::memset(_passedOrder, 0xFF, sizeof(_passedOrder)); - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get calling convention id, see \ref Id. - ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } - //! Set calling convention id, see \ref Id. - ASMJIT_INLINE void setId(uint32_t id) noexcept { _id = static_cast(id); } - - //! Get architecture type. - ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archType; } - //! Set architecture type. - ASMJIT_INLINE void setArchType(uint32_t archType) noexcept { _archType = static_cast(archType); } - - //! Get calling convention algorithm, see \ref Algorithm. - ASMJIT_INLINE uint32_t getAlgorithm() const noexcept { return _algorithm; } - //! Set calling convention algorithm, see \ref Algorithm. - ASMJIT_INLINE void setAlgorithm(uint32_t algorithm) noexcept { _algorithm = static_cast(algorithm); } - - //! Get if the calling convention has the given `flag` set. - ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } - //! Get calling convention flags, see \ref Flags. - ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } - //! Add calling convention flags, see \ref Flags. - ASMJIT_INLINE void setFlags(uint32_t flag) noexcept { _flags = flag; }; - //! Add calling convention flags, see \ref Flags. - ASMJIT_INLINE void addFlags(uint32_t flag) noexcept { _flags |= flag; }; - - //! Get a natural stack alignment. - ASMJIT_INLINE uint32_t getNaturalStackAlignment() const noexcept { return _naturalStackAlignment; } - - //! Set a natural stack alignment. - //! - //! This function can be used to override the default stack alignment in case - //! that you know that it's alignment is different. For example it allows to - //! implement custom calling conventions that guarantee higher stack alignment. - ASMJIT_INLINE void setNaturalStackAlignment(uint32_t value) noexcept { - ASMJIT_ASSERT(value < 256); - _naturalStackAlignment = static_cast(value); - } - - //! Get if this calling convention specifies 'SpillZone'. - ASMJIT_INLINE bool hasSpillZone() const noexcept { return _spillZoneSize != 0; } - //! Get size of 'SpillZone'. - ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _spillZoneSize; } - //! Set size of 'SpillZone'. - ASMJIT_INLINE void setSpillZoneSize(uint32_t size) noexcept { _spillZoneSize = static_cast(size); } - - //! Get if this calling convention specifies 'RedZone'. - ASMJIT_INLINE bool hasRedZone() const noexcept { return _redZoneSize != 0; } - //! Get size of 'RedZone'. - ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _redZoneSize; } - //! Set size of 'RedZone'. - ASMJIT_INLINE void setRedZoneSize(uint32_t size) noexcept { _redZoneSize = static_cast(size); } - - ASMJIT_INLINE const uint8_t* getPassedOrder(uint32_t kind) const noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - return _passedOrder[kind].id; - } - - ASMJIT_INLINE uint32_t getPassedRegs(uint32_t kind) const noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - return _passedRegs[kind]; - } - - ASMJIT_INLINE void _setPassedPacked(uint32_t kind, uint32_t p0, uint32_t p1) noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - - _passedOrder[kind].packed[0] = p0; - _passedOrder[kind].packed[1] = p1; - } - - ASMJIT_INLINE void setPassedToNone(uint32_t kind) noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - - _setPassedPacked(kind, ASMJIT_PACK32_4x8(0xFF, 0xFF, 0xFF, 0xFF), - ASMJIT_PACK32_4x8(0xFF, 0xFF, 0xFF, 0xFF)); - _passedRegs[kind] = 0; - } - - ASMJIT_INLINE void setPassedOrder(uint32_t kind, uint32_t a0, uint32_t a1 = 0xFF, uint32_t a2 = 0xFF, uint32_t a3 = 0xFF, uint32_t a4 = 0xFF, uint32_t a5 = 0xFF, uint32_t a6 = 0xFF, uint32_t a7 = 0xFF) noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - - _setPassedPacked(kind, ASMJIT_PACK32_4x8(a0, a1, a2, a3), - ASMJIT_PACK32_4x8(a4, a5, a6, a7)); - - // NOTE: This should always be called with all arguments known at compile - // time, so even if it looks scary it should be translated to a single - // instruction. - _passedRegs[kind] = (a0 != 0xFF ? 1U << a0 : 0U) | - (a1 != 0xFF ? 1U << a1 : 0U) | - (a2 != 0xFF ? 1U << a2 : 0U) | - (a3 != 0xFF ? 1U << a3 : 0U) | - (a4 != 0xFF ? 1U << a4 : 0U) | - (a5 != 0xFF ? 1U << a5 : 0U) | - (a6 != 0xFF ? 1U << a6 : 0U) | - (a7 != 0xFF ? 1U << a7 : 0U) ; - } - - ASMJIT_INLINE uint32_t getPreservedRegs(uint32_t kind) const noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - return _preservedRegs[kind]; - } - - - ASMJIT_INLINE void setPreservedRegs(uint32_t kind, uint32_t regs) noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - _preservedRegs[kind] = regs; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint8_t _id; //!< Calling convention id, see \ref Id. - uint8_t _archType; //!< Architecture type (see \ref ArchInfo::Type). - uint8_t _algorithm; //!< Calling convention algorithm. - uint8_t _flags; //!< Calling convention flags. - - uint8_t _naturalStackAlignment; //!< Natural stack alignment as defined by OS/ABI. - uint8_t _spillZoneSize; //!< Spill zone size (WIN64 == 32 bytes). - uint16_t _redZoneSize; //!< Red zone size (AMD64 == 128 bytes). - - RegOrder _passedOrder[kMaxVRegKinds]; //!< Passed registers' order, per kind. - uint32_t _passedRegs[kMaxVRegKinds]; //!< Mask of all passed registers, per kind. - uint32_t _preservedRegs[kMaxVRegKinds];//!< Mask of all preserved registers, per kind. -}; - -// ============================================================================ -// [asmjit::FuncArgIndex] -// ============================================================================ - -//! Function argument index (lo/hi). -ASMJIT_ENUM(FuncArgIndex) { - //! Maximum number of function arguments supported by AsmJit. - kFuncArgCount = 16, - //! Extended maximum number of arguments (used internally). - kFuncArgCountLoHi = kFuncArgCount * 2, - - //! Index to the LO part of function argument (default). - //! - //! This value is typically omitted and added only if there is HI argument - //! accessed. - kFuncArgLo = 0, - - //! Index to the HI part of function argument. - //! - //! HI part of function argument depends on target architecture. On x86 it's - //! typically used to transfer 64-bit integers (they form a pair of 32-bit - //! integers). - kFuncArgHi = kFuncArgCount -}; - -// ============================================================================ -// [asmjit::FuncSignature] -// ============================================================================ - -//! Function signature. -//! -//! Contains information about function return type, count of arguments and -//! their TypeIds. Function signature is a low level structure which doesn't -//! contain platform specific or calling convention specific information. -struct FuncSignature { - enum { - //! Doesn't have variable number of arguments (`...`). - kNoVarArgs = 0xFF - }; - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - //! Initialize the function signature. - ASMJIT_INLINE void init(uint32_t ccId, uint32_t ret, const uint8_t* args, uint32_t argCount) noexcept { - ASMJIT_ASSERT(ccId <= 0xFF); - ASMJIT_ASSERT(argCount <= 0xFF); - - _callConv = static_cast(ccId); - _argCount = static_cast(argCount); - _vaIndex = kNoVarArgs; - _ret = ret; - _args = args; - } - - ASMJIT_INLINE void reset() noexcept { - memset(this, 0, sizeof(*this)); - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get the function's calling convention. - ASMJIT_INLINE uint32_t getCallConv() const noexcept { return _callConv; } - - //! Get if the function has variable number of arguments (...). - ASMJIT_INLINE bool hasVarArgs() const noexcept { return _vaIndex != kNoVarArgs; } - //! Get the variable arguments (...) index, `kNoVarArgs` if none. - ASMJIT_INLINE uint32_t getVAIndex() const noexcept { return _vaIndex; } - - //! Get the number of function arguments. - ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _argCount; } - - ASMJIT_INLINE bool hasRet() const noexcept { return _ret != TypeId::kVoid; } - //! Get the return value type. - ASMJIT_INLINE uint32_t getRet() const noexcept { return _ret; } - - //! Get the type of the argument at index `i`. - ASMJIT_INLINE uint32_t getArg(uint32_t i) const noexcept { - ASMJIT_ASSERT(i < _argCount); - return _args[i]; - } - //! Get the array of function arguments' types. - ASMJIT_INLINE const uint8_t* getArgs() const noexcept { return _args; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint8_t _callConv; //!< Calling convention id. - uint8_t _argCount; //!< Count of arguments. - uint8_t _vaIndex; //!< Index to a first vararg or `kNoVarArgs`. - uint8_t _ret; //!< TypeId of a return value. - const uint8_t* _args; //!< TypeIds of function arguments. -}; - -// ============================================================================ -// [asmjit::FuncSignatureT] -// ============================================================================ - -//! \internal -#define T(TYPE) TypeIdOf::kTypeId - -//! Static function signature (no arguments). -template -class FuncSignature0 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature0(uint32_t ccId = CallConv::kIdHost) noexcept { - init(ccId, T(RET), nullptr, 0); - } -}; - -//! Static function signature (1 argument). -template -class FuncSignature1 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature1(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { T(A0) }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; - -//! Static function signature (2 arguments). -template -class FuncSignature2 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature2(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { T(A0), T(A1) }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; - -//! Static function signature (3 arguments). -template -class FuncSignature3 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature3(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { T(A0), T(A1), T(A2) }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; - -//! Static function signature (4 arguments). -template -class FuncSignature4 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature4(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3) }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; - -//! Static function signature (5 arguments). -template -class FuncSignature5 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature5(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4) }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; - -//! Static function signature (6 arguments). -template -class FuncSignature6 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature6(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5) }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; - -//! Static function signature (7 arguments). -template -class FuncSignature7 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature7(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6) }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; - -//! Static function signature (8 arguments). -template -class FuncSignature8 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature8(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6), T(A7) }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; - -//! Static function signature (9 arguments). -template -class FuncSignature9 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature9(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6), T(A7), T(A8) }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; - -//! Static function signature (10 arguments). -template -class FuncSignature10 : public FuncSignature { -public: - ASMJIT_INLINE FuncSignature10(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6), T(A7), T(A8), T(A9) }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; - -#if ASMJIT_CC_HAS_VARIADIC_TEMPLATES -//! Static function signature (variadic). -template -class FuncSignatureT : public FuncSignature { -public: - ASMJIT_INLINE FuncSignatureT(uint32_t ccId = CallConv::kIdHost) noexcept { - static const uint8_t args[] = { (T(ARGS))... }; - init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args)); - } -}; -#endif // ASMJIT_CC_HAS_VARIADIC_TEMPLATES - -#undef T - -// ============================================================================ -// [asmjit::FuncSignatureX] -// ============================================================================ - -//! Dynamic function signature. -class FuncSignatureX : public FuncSignature { -public: - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE FuncSignatureX(uint32_t ccId = CallConv::kIdHost) noexcept { - init(ccId, TypeId::kVoid, _builderArgList, 0); - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void setCallConv(uint32_t ccId) noexcept { - ASMJIT_ASSERT(ccId <= 0xFF); - _callConv = static_cast(ccId); - } - - //! Set the return type to `retType`. - ASMJIT_INLINE void setRet(uint32_t retType) noexcept { _ret = retType; } - //! Set the return type based on `T`. - template - ASMJIT_INLINE void setRetT() noexcept { setRet(TypeIdOf::kTypeId); } - - //! Set the argument at index `i` to the `type` - ASMJIT_INLINE void setArg(uint32_t i, uint32_t type) noexcept { - ASMJIT_ASSERT(i < _argCount); - _builderArgList[i] = type; - } - //! Set the argument at index `i` to the type based on `T`. - template - ASMJIT_INLINE void setArgT(uint32_t i) noexcept { setArg(i, TypeIdOf::kTypeId); } - - //! Append an argument of `type` to the function prototype. - ASMJIT_INLINE void addArg(uint32_t type) noexcept { - ASMJIT_ASSERT(_argCount < kFuncArgCount); - _builderArgList[_argCount++] = static_cast(type); - } - //! Append an argument of type based on `T` to the function prototype. - template - ASMJIT_INLINE void addArgT() noexcept { addArg(TypeIdOf::kTypeId); } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint8_t _builderArgList[kFuncArgCount]; -}; - -// ============================================================================ -// [asmjit::FuncDetail] -// ============================================================================ - -//! Function detail - CallConv and expanded FuncSignature. -//! -//! Function details is architecture and OS dependent representation of function. -//! It contains calling convention and expanded function signature so all -//! arguments have assigned either register type & id or stack address. -class FuncDetail { -public: - ASMJIT_ENUM(Limits) { - kMaxVRegKinds = Globals::kMaxVRegKinds - }; - - //! Argument or return value as defined by `FuncSignature`, but with register - //! or stack address (and other metadata) assigned. - struct Value { - ASMJIT_ENUM(Parts) { - kTypeIdShift = 24, - kTypeIdMask = 0xFF000000U, - - kRegTypeShift = 8, - kRegTypeMask = 0x0000FF00U, - - kRegIdShift = 0, - kRegIdMask = 0x000000FFU, - - kStackOffsetShift = 0, - kStackOffsetMask = 0x0000FFFFU, - - kIsByReg = 0x00010000U, - kIsByStack = 0x00020000U, - kIsIndirect = 0x00040000U - }; - - //! Get if this value is initialized (i.e. contains a valid data). - ASMJIT_INLINE bool isInitialized() const noexcept { return _value != 0; } - //! Initialize this in/out by a given `typeId`. - ASMJIT_INLINE void initTypeId(uint32_t typeId) noexcept { _value = typeId << kTypeIdShift; } - //! Initialize this in/out by a given `typeId`, `regType`, and `regId`. - ASMJIT_INLINE void initReg(uint32_t typeId, uint32_t regType, uint32_t regId) noexcept { - _value = (typeId << kTypeIdShift) | (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsByReg; - } - //! Initialize this in/out by a given `typeId` and `offset`. - ASMJIT_INLINE void initStack(uint32_t typeId, uint32_t stackOffset) noexcept { - _value = (typeId << kTypeIdShift) | (stackOffset << kStackOffsetShift) | kIsByStack; - } - //! Reset the value to its uninitialized and unassigned state. - ASMJIT_INLINE void reset() noexcept { _value = 0; } - - ASMJIT_INLINE void assignToReg(uint32_t regType, uint32_t regId) noexcept { - ASMJIT_ASSERT(!isAssigned()); - _value |= (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsByReg; - } - - ASMJIT_INLINE void assignToStack(int32_t offset) noexcept { - ASMJIT_ASSERT(!isAssigned()); - _value |= (offset << kStackOffsetShift) | kIsByStack; - } - - //! Get if this argument is passed by register. - ASMJIT_INLINE bool byReg() const noexcept { return (_value & kIsByReg) != 0; } - //! Get if this argument is passed by stack. - ASMJIT_INLINE bool byStack() const noexcept { return (_value & kIsByStack) != 0; } - //! Get if this argument is passed by register. - ASMJIT_INLINE bool isAssigned() const noexcept { return (_value & (kIsByReg | kIsByStack)) != 0; } - //! Get if this argument is passed through a pointer (used by WIN64 to pass XMM|YMM|ZMM). - ASMJIT_INLINE bool isIndirect() const noexcept { return (_value & kIsIndirect) != 0; } - - //! Get virtual type of this argument or return value. - ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _value >> kTypeIdShift; } - //! Get a register type of the register used to pass the argument or return the value. - ASMJIT_INLINE uint32_t getRegType() const noexcept { return (_value & kRegTypeMask) >> kRegTypeShift; } - //! Get a physical id of the register used to pass the argument or return the value. - ASMJIT_INLINE uint32_t getRegId() const noexcept { return (_value & kRegIdMask) >> kRegIdShift; } - //! Get a stack offset of this argument (always positive). - ASMJIT_INLINE int32_t getStackOffset() const noexcept { return (_value & kStackOffsetMask) >> kStackOffsetShift; } - - uint32_t _value; - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE FuncDetail() noexcept { reset(); } - ASMJIT_INLINE FuncDetail(const FuncDetail& other) noexcept { - ::memcpy(this, &other, sizeof(*this)); - } - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - //! Initialize this `FuncDetail` to the given signature. - ASMJIT_API Error init(const FuncSignature& sign); - ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); } - - // -------------------------------------------------------------------------- - // [Accessors - Calling Convention] - // -------------------------------------------------------------------------- - - //! Get the function's calling convention, see `CallConv`. - ASMJIT_INLINE const CallConv& getCallConv() const noexcept { return _callConv; } - - //! Get CallConv flags, see \ref CallConv::Flags. - ASMJIT_INLINE uint32_t getFlags() const noexcept { return _callConv.getFlags(); } - //! Check if a CallConv `flag` is set, see \ref CallConv::Flags. - ASMJIT_INLINE bool hasFlag(uint32_t ccFlag) const noexcept { return _callConv.hasFlag(ccFlag); } - - // -------------------------------------------------------------------------- - // [Accessors - Arguments and Return] - // -------------------------------------------------------------------------- - - //! Get count of function return values. - ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _retCount; } - //! Get the number of function arguments. - ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _argCount; } - - //! Get whether the function has a return value. - ASMJIT_INLINE bool hasRet() const noexcept { return _retCount != 0; } - //! Get function return value. - ASMJIT_INLINE Value& getRet(size_t index = 0) noexcept { - ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_rets)); - return _rets[index]; - } - //! Get function return value (const). - ASMJIT_INLINE const Value& getRet(size_t index = 0) const noexcept { - ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_rets)); - return _rets[index]; - } - - //! Get function arguments array. - ASMJIT_INLINE Value* getArgs() noexcept { return _args; } - //! Get function arguments array (const). - ASMJIT_INLINE const Value* getArgs() const noexcept { return _args; } - - ASMJIT_INLINE bool hasArg(size_t index) const noexcept { - ASMJIT_ASSERT(index < kFuncArgCountLoHi); - return _args[index].isInitialized(); - } - - //! Get function argument at index `index`. - ASMJIT_INLINE Value& getArg(size_t index) noexcept { - ASMJIT_ASSERT(index < kFuncArgCountLoHi); - return _args[index]; - } - - //! Get function argument at index `index`. - ASMJIT_INLINE const Value& getArg(size_t index) const noexcept { - ASMJIT_ASSERT(index < kFuncArgCountLoHi); - return _args[index]; - } - - ASMJIT_INLINE void resetArg(size_t index) noexcept { - ASMJIT_ASSERT(index < kFuncArgCountLoHi); - _args[index].reset(); - } - - //! Get if the function passes one or more argument by stack. - ASMJIT_INLINE bool hasStackArgs() const noexcept { return _argStackSize != 0; } - //! Get stack size needed for function arguments passed on the stack. - ASMJIT_INLINE uint32_t getArgStackSize() const noexcept { return _argStackSize; } - - ASMJIT_INLINE uint32_t getNaturalStackAlignment() const noexcept { return _callConv.getNaturalStackAlignment(); } - ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _callConv.getSpillZoneSize(); } - ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _callConv.getRedZoneSize(); } - - ASMJIT_INLINE uint32_t getPassedRegs(uint32_t kind) const noexcept { return _callConv.getPassedRegs(kind); } - ASMJIT_INLINE uint32_t getPreservedRegs(uint32_t kind) const noexcept { return _callConv.getPreservedRegs(kind); } - - ASMJIT_INLINE uint32_t getUsedRegs(uint32_t kind) const noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - return _usedRegs[kind]; - } - - ASMJIT_INLINE void addUsedRegs(uint32_t kind, uint32_t regs) noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - _usedRegs[kind] |= regs; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - CallConv _callConv; //!< Calling convention. - uint8_t _argCount; //!< Number of function arguments. - uint8_t _retCount; //!< Number of function return values. - uint32_t _usedRegs[kMaxVRegKinds]; //!< Registers that contains arguments (signature dependent). - uint32_t _argStackSize; //!< Size of arguments passed by stack. - Value _rets[2]; //!< Function return values. - Value _args[kFuncArgCountLoHi]; //!< Function arguments. -}; - -// ============================================================================ -// [asmjit::FuncFrameInfo] -// ============================================================================ - -//! Function-frame information. -//! -//! This structure can be used to create a function frame in a cross-platform -//! way. It contains information about the function's stack to be used and -//! registers to be saved and restored. Based on this information in can -//! calculate the optimal layout of a function as \ref FuncFrameLayout. -struct FuncFrameInfo { - ASMJIT_ENUM(Limits) { - kMaxVRegKinds = Globals::kMaxVRegKinds - }; - - //! Attributes. - //! - //! Attributes are designed in a way that all are initially false, and user - //! or function-frame finalizer sets them when necessary. Architecture-specific - //! attributes are prefixed with the architecture name. - ASMJIT_ENUM(Attributes) { - kAttrPreserveFP = 0x00000001U, //!< Preserve frame pointer (EBP|RBP). - kAttrCompactPE = 0x00000002U, //!< Use smaller, but possibly slower prolog/epilog. - kAttrHasCalls = 0x00000004U, //!< Function calls other functions (is not leaf). - - kX86AttrAlignedVecSR = 0x00010000U, //!< Use aligned save/restore of VEC regs. - kX86AttrMmxCleanup = 0x00020000U, //!< Emit EMMS instruction in epilog (X86). - kX86AttrAvxCleanup = 0x00040000U, //!< Emit VZEROUPPER instruction in epilog (X86). - kX86AttrAvxEnabled = 0x00080000U //!< Use AVX instead of SSE for all operations (X86). - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE FuncFrameInfo() noexcept { reset(); } - - ASMJIT_INLINE FuncFrameInfo(const FuncFrameInfo& other) noexcept { - ::memcpy(this, &other, sizeof(*this)); - } - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void reset() noexcept { - ::memset(this, 0, sizeof(*this)); - _stackArgsRegId = Globals::kInvalidRegId; - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get frame-info flags, see \ref Attributes. - ASMJIT_INLINE uint32_t getAttributes() const noexcept { return _attributes; } - //! Check if a frame-info `flag` is set, see \ref Attributes. - ASMJIT_INLINE bool hasAttribute(uint32_t attr) const noexcept { return (_attributes & attr) != 0; } - //! Add `flags` to the frame-info, see \ref Attributes. - ASMJIT_INLINE void addAttributes(uint32_t attrs) noexcept { _attributes |= attrs; } - //! Clear `flags` from the frame-info, see \ref Attributes. - ASMJIT_INLINE void clearAttributes(uint32_t attrs) noexcept { _attributes &= ~attrs; } - - //! Get if the function preserves frame pointer (EBP|ESP on X86). - ASMJIT_INLINE bool hasPreservedFP() const noexcept { return (_attributes & kAttrPreserveFP) != 0; } - //! Enable preserved frame pointer. - ASMJIT_INLINE void enablePreservedFP() noexcept { _attributes |= kAttrPreserveFP; } - //! Disable preserved frame pointer. - ASMJIT_INLINE void disablePreservedFP() noexcept { _attributes &= ~kAttrPreserveFP; } - - //! Get if the function prolog and epilog should be compacted (as small as possible). - ASMJIT_INLINE bool hasCompactPE() const noexcept { return (_attributes & kAttrCompactPE) != 0; } - //! Enable compact prolog/epilog. - ASMJIT_INLINE void enableCompactPE() noexcept { _attributes |= kAttrCompactPE; } - //! Disable compact prolog/epilog. - ASMJIT_INLINE void disableCompactPE() noexcept { _attributes &= ~kAttrCompactPE; } - - //! Get if the function calls other functions. - ASMJIT_INLINE bool hasCalls() const noexcept { return (_attributes & kAttrHasCalls) != 0; } - //! Set `kFlagHasCalls` to true. - ASMJIT_INLINE void enableCalls() noexcept { _attributes |= kAttrHasCalls; } - //! Set `kFlagHasCalls` to false. - ASMJIT_INLINE void disableCalls() noexcept { _attributes &= ~kAttrHasCalls; } - - //! Get if the function contains MMX cleanup - 'emms' instruction in epilog. - ASMJIT_INLINE bool hasMmxCleanup() const noexcept { return (_attributes & kX86AttrMmxCleanup) != 0; } - //! Enable MMX cleanup. - ASMJIT_INLINE void enableMmxCleanup() noexcept { _attributes |= kX86AttrMmxCleanup; } - //! Disable MMX cleanup. - ASMJIT_INLINE void disableMmxCleanup() noexcept { _attributes &= ~kX86AttrMmxCleanup; } - - //! Get if the function contains AVX cleanup - 'vzeroupper' instruction in epilog. - ASMJIT_INLINE bool hasAvxCleanup() const noexcept { return (_attributes & kX86AttrAvxCleanup) != 0; } - //! Enable AVX cleanup. - ASMJIT_INLINE void enableAvxCleanup() noexcept { _attributes |= kX86AttrAvxCleanup; } - //! Disable AVX cleanup. - ASMJIT_INLINE void disableAvxCleanup() noexcept { _attributes &= ~kX86AttrAvxCleanup; } - - //! Get if the function contains AVX cleanup - 'vzeroupper' instruction in epilog. - ASMJIT_INLINE bool isAvxEnabled() const noexcept { return (_attributes & kX86AttrAvxEnabled) != 0; } - //! Enable AVX cleanup. - ASMJIT_INLINE void enableAvx() noexcept { _attributes |= kX86AttrAvxEnabled; } - //! Disable AVX cleanup. - ASMJIT_INLINE void disableAvx() noexcept { _attributes &= ~kX86AttrAvxEnabled; } - - //! Get which registers (by `kind`) are saved/restored in prolog/epilog, respectively. - ASMJIT_INLINE uint32_t getDirtyRegs(uint32_t kind) const noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - return _dirtyRegs[kind]; - } - - //! Set which registers (by `kind`) are saved/restored in prolog/epilog, respectively. - ASMJIT_INLINE void setDirtyRegs(uint32_t kind, uint32_t regs) noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - _dirtyRegs[kind] = regs; - } - - //! Add registers (by `kind`) to saved/restored registers. - ASMJIT_INLINE void addDirtyRegs(uint32_t kind, uint32_t regs) noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - _dirtyRegs[kind] |= regs; - } - - ASMJIT_INLINE void setAllDirty() noexcept { - _dirtyRegs[0] = 0xFFFFFFFFU; - _dirtyRegs[1] = 0xFFFFFFFFU; - _dirtyRegs[2] = 0xFFFFFFFFU; - _dirtyRegs[3] = 0xFFFFFFFFU; - } - - ASMJIT_INLINE void setAllDirty(uint32_t kind) noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - _dirtyRegs[kind] = 0xFFFFFFFFU; - } - - //! Get stack-frame size used by the function. - ASMJIT_INLINE uint32_t getStackFrameSize() const noexcept { return _stackFrameSize; } - //! Get call-frame size used by the function. - ASMJIT_INLINE uint32_t getCallFrameSize() const noexcept { return _callFrameSize; } - - //! Get minimum stack-frame alignment required by the function. - ASMJIT_INLINE uint32_t getStackFrameAlignment() const noexcept { return _stackFrameAlignment; } - //! Get minimum call-frame alignment required by the function. - ASMJIT_INLINE uint32_t getCallFrameAlignment() const noexcept { return _callFrameAlignment; } - - ASMJIT_INLINE void setStackFrameSize(uint32_t size) noexcept { _stackFrameSize = size; } - ASMJIT_INLINE void setCallFrameSize(uint32_t size) noexcept { _callFrameSize = size; } - - ASMJIT_INLINE void setStackFrameAlignment(uint32_t value) noexcept { - ASMJIT_ASSERT(value < 256); - _stackFrameAlignment = static_cast(value); - } - - ASMJIT_INLINE void setCallFrameAlignment(uint32_t value) noexcept { - ASMJIT_ASSERT(value < 256); - _callFrameAlignment = static_cast(value); - } - - ASMJIT_INLINE void mergeStackFrameSize(uint32_t size) noexcept { _stackFrameSize = std::max(_stackFrameSize, size); } - ASMJIT_INLINE void mergeCallFrameSize(uint32_t size) noexcept { _callFrameSize = std::max(_callFrameSize, size); } - - ASMJIT_INLINE void mergeStackFrameAlignment(uint32_t value) noexcept { - ASMJIT_ASSERT(value < 256); - _stackFrameAlignment = static_cast(std::max(_stackFrameAlignment, value)); - } - - ASMJIT_INLINE void mergeCallFrameAlignment(uint32_t value) noexcept { - ASMJIT_ASSERT(value < 256); - _callFrameAlignment = static_cast(std::max(_callFrameAlignment, value)); - } - - ASMJIT_INLINE bool hasStackArgsRegId() const noexcept { - return _stackArgsRegId != Globals::kInvalidRegId; - } - ASMJIT_INLINE uint32_t getStackArgsRegId() const noexcept { return _stackArgsRegId; } - ASMJIT_INLINE void setStackArgsRegId(uint32_t regId) { _stackArgsRegId = regId; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint32_t _attributes; //!< Function attributes. - uint32_t _dirtyRegs[kMaxVRegKinds]; //!< Registers used by the function. - - uint8_t _stackFrameAlignment; //!< Minimum alignment of stack-frame. - uint8_t _callFrameAlignment; //!< Minimum alignment of call-frame. - uint8_t _stackArgsRegId; //!< Register that holds base-address to arguments passed by stack. - - uint32_t _stackFrameSize; //!< Size of a stack-frame used by the function. - uint32_t _callFrameSize; //!< Size of a call-frame (not part of _stackFrameSize). -}; - -// ============================================================================ -// [asmjit::FuncFrameLayout] -// ============================================================================ - -//! Function-frame layout. -//! -//! Function layout is used directly by prolog and epilog insertion helpers. It -//! contains only information necessary to insert proper prolog and epilog, and -//! should be always calculated from \ref FuncDetail and \ref FuncFrameInfo, where -//! \ref FuncDetail defines function's calling convention and signature, and \ref -//! FuncFrameInfo specifies how much stack is used, and which registers are dirty. -struct FuncFrameLayout { - ASMJIT_ENUM(Limits) { - kMaxVRegKinds = Globals::kMaxVRegKinds - }; - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - ASMJIT_API Error init(const FuncDetail& func, const FuncFrameInfo& ffi) noexcept; - ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool hasPreservedFP() const noexcept { return static_cast(_preservedFP); } - ASMJIT_INLINE bool hasDsaSlotUsed() const noexcept { return static_cast(_dsaSlotUsed); } - ASMJIT_INLINE bool hasAlignedVecSR() const noexcept { return static_cast(_alignedVecSR); } - ASMJIT_INLINE bool hasDynamicAlignment() const noexcept { return static_cast(_dynamicAlignment); } - - ASMJIT_INLINE bool hasMmxCleanup() const noexcept { return static_cast(_mmxCleanup); } - ASMJIT_INLINE bool hasAvxCleanup() const noexcept { return static_cast(_avxCleanup); } - ASMJIT_INLINE bool isAvxEnabled() const noexcept { return static_cast(_avxEnabled); } - - ASMJIT_INLINE uint32_t getSavedRegs(uint32_t kind) const noexcept { - ASMJIT_ASSERT(kind < kMaxVRegKinds); - return _savedRegs[kind]; - } - - //! Get stack size. - ASMJIT_INLINE uint32_t getStackSize() const noexcept { return _stackSize; } - //! Get stack alignment. - ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; } - //! Get the offset needed to access the function's stack (it skips call-stack). - ASMJIT_INLINE uint32_t getStackBaseOffset() const noexcept { return _stackBaseOffset; } - - //! Get stack size required to save GP registers. - ASMJIT_INLINE uint32_t getGpStackSize() const noexcept { return _gpStackSize; } - //! Get stack size required to save VEC registers. - ASMJIT_INLINE uint32_t getVecStackSize() const noexcept { return _vecStackSize; } - - ASMJIT_INLINE uint32_t getGpStackOffset() const noexcept { return _gpStackOffset; } - ASMJIT_INLINE uint32_t getVecStackOffset() const noexcept { return _vecStackOffset; } - - ASMJIT_INLINE uint32_t getStackArgsRegId() const noexcept { return _stackArgsRegId; } - ASMJIT_INLINE uint32_t getStackArgsOffset() const noexcept { return _stackArgsOffset; } - - ASMJIT_INLINE bool hasStackAdjustment() const noexcept { return _stackAdjustment != 0; } - ASMJIT_INLINE uint32_t getStackAdjustment() const noexcept { return _stackAdjustment; } - - ASMJIT_INLINE bool hasCalleeStackCleanup() const noexcept { return _calleeStackCleanup != 0; } - ASMJIT_INLINE uint32_t getCalleeStackCleanup() const noexcept { return _calleeStackCleanup; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint8_t _stackAlignment; //!< Final stack alignment of the functions. - uint8_t _stackBaseRegId; //!< GP register that holds address of base stack address. - uint8_t _stackArgsRegId; //!< GP register that holds address of the first argument passed by stack. - - uint32_t _savedRegs[kMaxVRegKinds]; //!< Registers that will be saved/restored in prolog/epilog. - - uint32_t _preservedFP : 1; //!< Function preserves frame-pointer. - uint32_t _dsaSlotUsed : 1; //!< True if `_dsaSlot` contains a valid memory slot/offset. - uint32_t _alignedVecSR : 1; //!< Use instructions that perform aligned ops to save/restore XMM regs. - uint32_t _dynamicAlignment : 1; //!< Function must dynamically align the stack. - - uint32_t _mmxCleanup : 1; //!< Emit 'emms' in epilog (X86). - uint32_t _avxCleanup : 1; //!< Emit 'vzeroupper' in epilog (X86). - uint32_t _avxEnabled : 1; //!< Use AVX instead of SSE for SIMD saves/restores (X86). - - uint32_t _stackSize; //!< Stack size (sum of function's stack and call stack). - uint32_t _stackBaseOffset; //!< Stack offset (non-zero if kFlagHasCalls is set). - uint32_t _stackAdjustment; //!< Stack adjustment in prolog/epilog. - uint32_t _stackArgsOffset; //!< Offset to the first argument passed by stack of _stackArgsRegId. - - uint32_t _dsaSlot; //!< Memory slot where the prolog inserter stores previous (unaligned) ESP. - uint16_t _calleeStackCleanup; //!< How many bytes the callee should add to the stack (X86 STDCALL). - uint16_t _gpStackSize; //!< Stack size required to save GP regs. - uint16_t _vecStackSize; //!< Stack size required to save VEC regs. - uint32_t _gpStackOffset; //!< Offset where saved GP regs are stored. - uint32_t _vecStackOffset; //!< Offset where saved GP regs are stored. -}; - -// ============================================================================ -// [asmjit::FuncArgsMapper] -// ============================================================================ - -//! Assign a physical register to each function argument. -//! -//! This is used to specify where each function argument should be shuffled -//! or allocated (in case it's passed by stack). -class FuncArgsMapper { -public: - struct Value { - // NOTE: The layout is compatible with FuncDetail::Value except stack. - ASMJIT_ENUM(Parts) { - kTypeIdShift = 24, - kTypeIdMask = 0xFF000000U, - - kRegTypeShift = 8, - kRegTypeMask = 0x0000FF00U, - - kRegIdShift = 0, - kRegIdMask = 0x000000FFU, - - kIsAssigned = 0x00010000U - }; - - //! Get if this value is initialized (i.e. contains a valid data). - ASMJIT_INLINE bool isAssigned() const noexcept { return _value != 0; } - //! Initialize this in/out by a given `typeId`, `regType`, and `regId`. - ASMJIT_INLINE void assign(uint32_t typeId, uint32_t regType, uint32_t regId) noexcept { - _value = (typeId << kTypeIdShift) | (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsAssigned; - } - //! Reset the value to its unassigned state. - ASMJIT_INLINE void reset() noexcept { _value = 0; } - - //! Get virtual type of this argument or return value. - ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _value >> kTypeIdShift; } - //! Get a register type of the register used to pass the argument or return the value. - ASMJIT_INLINE uint32_t getRegType() const noexcept { return (_value & kRegTypeMask) >> kRegTypeShift; } - //! Get a physical id of the register used to pass the argument or return the value. - ASMJIT_INLINE uint32_t getRegId() const noexcept { return (_value & kRegIdMask) >> kRegIdShift; } - - uint32_t _value; - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - explicit ASMJIT_INLINE FuncArgsMapper(const FuncDetail* fd) noexcept { reset(fd); } - ASMJIT_INLINE FuncArgsMapper(const FuncArgsMapper& other) noexcept { - ::memcpy(this, &other, sizeof(*this)); - } - - // -------------------------------------------------------------------------- - // [Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void reset(const FuncDetail* fd = nullptr) noexcept { - _funcDetail = fd; - ::memset(_args, 0, sizeof(_args)); - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE const FuncDetail* getFuncDetail() const noexcept { return _funcDetail; } - ASMJIT_INLINE void setFuncDetail(const FuncDetail* fd) noexcept { _funcDetail = fd; } - - ASMJIT_INLINE Value& getArg(size_t index) noexcept { - ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args)); - return _args[index]; - } - ASMJIT_INLINE const Value& getArg(size_t index) const noexcept { - ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args)); - return _args[index]; - } - - ASMJIT_INLINE bool isAssigned(size_t index) const noexcept { - ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args)); - return _args[index].isAssigned(); - } - - ASMJIT_INLINE void assign(size_t index, const Reg& reg, uint32_t typeId = TypeId::kVoid) noexcept { - // Not designed for virtual registers. - ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args)); - ASMJIT_ASSERT(reg.isPhysReg()); - - _args[index].assign(typeId, reg.getType(), reg.getId()); - } - - // NOTE: All `assignAll()` methods are shortcuts to assign all arguments at - // once, however, since registers are passed all at once these initializers - // don't provide any way to pass TypeId and/or to keep any argument between - // the arguments passed uninitialized. - ASMJIT_INLINE void assignAll(const Reg& a0) noexcept { - assign(0, a0); - } - ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1) noexcept { - assign(0, a0); assign(1, a1); - } - ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2) noexcept { - assign(0, a0); assign(1, a1); assign(2, a2); - } - ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3) noexcept { - assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3); - } - ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4) noexcept { - assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3); - assign(4, a4); - } - ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4, const Reg& a5) noexcept { - assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3); - assign(4, a4); assign(5, a5); - } - ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4, const Reg& a5, const Reg& a6) noexcept { - assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3); - assign(4, a4); assign(5, a5); assign(6, a6); - } - ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4, const Reg& a5, const Reg& a6, const Reg& a7) noexcept { - assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3); - assign(4, a4); assign(5, a5); assign(6, a6); assign(7, a7); - } - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - //! Update `FuncFrameInfo` accordingly to FuncArgsMapper. - //! - //! This method must be called if you use `FuncArgsMapper` and you plan to - //! use `FuncUtils::allocArgs()` to remap all arguments after the prolog is - //! inserted. - ASMJIT_API Error updateFrameInfo(FuncFrameInfo& ffi) const noexcept; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - const FuncDetail* _funcDetail; //!< Function detail. - Value _args[kFuncArgCountLoHi]; //!< Mapping of each function argument. -}; - -// ============================================================================ -// [asmjit::FuncUtils] -// ============================================================================ - -struct FuncUtils { - ASMJIT_API static Error emitProlog(CodeEmitter* emitter, const FuncFrameLayout& layout); - ASMJIT_API static Error emitEpilog(CodeEmitter* emitter, const FuncFrameLayout& layout); - ASMJIT_API static Error allocArgs(CodeEmitter* emitter, const FuncFrameLayout& layout, const FuncArgsMapper& args); -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_FUNC_H diff --git a/libs/asmjit/base/globals.cpp b/libs/asmjit/base/globals.cpp deleted file mode 100644 index b4612e5f..00000000 --- a/libs/asmjit/base/globals.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/globals.h" -#include "../base/utils.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::DebugUtils] -// ============================================================================ - -#if !defined(ASMJIT_DISABLE_TEXT) -static const char errorMessages[] = - "Ok\0" - "No heap memory\0" - "No virtual memory\0" - "Invalid argument\0" - "Invalid state\0" - "Invalid architecture\0" - "Not initialized\0" - "Already initialized\0" - "Feature not enabled\0" - "Slot occupied\0" - "No code generated\0" - "Code too large\0" - "Invalid label\0" - "Label index overflow\0" - "Label already bound\0" - "Label already defined\0" - "Label name too long\0" - "Invalid label name\0" - "Invalid parent label\0" - "Non-local label can't have parent\0" - "Relocation index overflow\0" - "Invalid relocation entry\0" - "Invalid instruction\0" - "Invalid register type\0" - "Invalid register kind\0" - "Invalid register's physical id\0" - "Invalid register's virtual id\0" - "Invalid prefix combination\0" - "Invalid lock prefix\0" - "Invalid xacquire prefix\0" - "Invalid xrelease prefix\0" - "Invalid rep prefix\0" - "Invalid rex prefix\0" - "Invalid mask, expected {k}\0" - "Invalid use of {k}\0" - "Invalid use of {k}{z}\0" - "Invalid broadcast {1tox}\0" - "Invalid {er} or {sae} option\0" - "Invalid address\0" - "Invalid address index\0" - "Invalid address scale\0" - "Invalid use of 64-bit address\0" - "Invalid displacement\0" - "Invalid segment\0" - "Invalid immediate value\0" - "Invalid operand size\0" - "Ambiguous operand size\0" - "Operand size mismatch\0" - "Invalid type-info\0" - "Invalid use of a low 8-bit GPB register\0" - "Invalid use of a 64-bit GPQ register in 32-bit mode\0" - "Invalid use of an 80-bit float\0" - "Not consecutive registers\0" - "No more physical registers\0" - "Overlapped registers\0" - "Overlapping register and arguments base-address register\0" - "Unknown error\0"; -#endif // ASMJIT_DISABLE_TEXT - -ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept { -#if !defined(ASMJIT_DISABLE_TEXT) - return Utils::findPackedString(errorMessages, std::min(err, kErrorCount)); -#else - static const char noMessage[] = ""; - return noMessage; -#endif -} - -ASMJIT_FAVOR_SIZE void DebugUtils::debugOutput(const char* str) noexcept { -#if ASMJIT_OS_WINDOWS - ::OutputDebugStringA(str); -#else - ::fputs(str, stderr); -#endif -} - -ASMJIT_FAVOR_SIZE void DebugUtils::assertionFailed(const char* file, int line, const char* msg) noexcept { - char str[1024]; - - snprintf(str, 1024, - "[asmjit] Assertion failed at %s (line %d):\n" - "[asmjit] %s\n", file, line, msg); - - // Support buggy `snprintf` implementations. - str[1023] = '\0'; - - debugOutput(str); - ::abort(); -} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/globals.h b/libs/asmjit/base/globals.h deleted file mode 100644 index 74c72515..00000000 --- a/libs/asmjit/base/globals.h +++ /dev/null @@ -1,341 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_GLOBALS_H -#define _ASMJIT_BASE_GLOBALS_H - -// [Dependencies] -#include "../asmjit_build.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::Globals] -// ============================================================================ - -enum { kInvalidValue = 0xFFFFFFFFU }; - -//! AsmJit globals. -namespace Globals { - -//! Invalid index -//! -//! Invalid index is the last possible index that is never used in practice. In -//! AsmJit it is used exclusively with strings to indicate the the length of the -//! string is not known and has to be determined. -static const size_t kInvalidIndex = ~static_cast(0); - -//! Invalid base address. -static const uint64_t kNoBaseAddress = ~static_cast(0); - -//! Global definitions. -ASMJIT_ENUM(Defs) { - //! Invalid register id. - kInvalidRegId = 0xFF, - - //! Host memory allocator overhead. - kAllocOverhead = static_cast(sizeof(intptr_t) * 4), - //! Aggressive growing strategy threshold. - kAllocThreshold = 8192 * 1024 -}; - -ASMJIT_ENUM(Limits) { - //! Count of register kinds that are important to Function API and CodeCompiler. - //! The target architecture can define more register kinds for special registers, - //! but these will never map to virtual registers and will never be used to pass - //! and return function arguments and function return values, respectively. - kMaxVRegKinds = 4, - - //! Maximum number of physical registers of all kinds of all supported - //! architectures. This is only important for \ref CodeCompiler and its - //! \ref RAPass (register allocator pass). - //! - //! NOTE: The distribution of these registers is architecture specific. - kMaxPhysRegs = 64, - - //! Maximum alignment. - kMaxAlignment = 64, - - //! Maximum label or symbol length in bytes (take into consideration that a - //! single UTF-8 character can take more than single byte to encode it). - kMaxLabelLength = 2048 -}; - -} // Globals namespace - -// ============================================================================ -// [asmjit::Error] -// ============================================================================ - -//! AsmJit error type (uint32_t). -typedef uint32_t Error; - -//! AsmJit error codes. -ASMJIT_ENUM(ErrorCode) { - //! No error (success). - //! - //! This is default state and state you want. - kErrorOk = 0, - - //! Heap memory allocation failed. - kErrorNoHeapMemory, - - //! Virtual memory allocation failed. - kErrorNoVirtualMemory, - - //! Invalid argument. - kErrorInvalidArgument, - - //! Invalid state. - //! - //! If this error is returned it means that either you are doing something - //! wrong or AsmJit caught itself by doing something wrong. This error should - //! not be underestimated. - kErrorInvalidState, - - //! Invalid or incompatible architecture. - kErrorInvalidArch, - - //! The object is not initialized. - kErrorNotInitialized, - //! The object is already initialized. - kErrorAlreadyInitialized, - - //! Built-in feature was disabled at compile time and it's not available. - kErrorFeatureNotEnabled, - - //! CodeHolder can't have attached more than one \ref Assembler at a time. - kErrorSlotOccupied, - - //! No code generated. - //! - //! Returned by runtime if the \ref CodeHolder contains no code. - kErrorNoCodeGenerated, - //! Code generated is larger than allowed. - kErrorCodeTooLarge, - - //! Attempt to use uninitialized label. - kErrorInvalidLabel, - //! Label index overflow - a single `Assembler` instance can hold more than - //! 2 billion labels (2147483391 to be exact). If there is an attempt to - //! create more labels this error is returned. - kErrorLabelIndexOverflow, - //! Label is already bound. - kErrorLabelAlreadyBound, - //! Label is already defined (named labels). - kErrorLabelAlreadyDefined, - //! Label name is too long. - kErrorLabelNameTooLong, - //! Label must always be local if it's anonymous (without a name). - kErrorInvalidLabelName, - //! Parent id passed to `CodeHolder::newNamedLabelId()` was invalid. - kErrorInvalidParentLabel, - //! Parent id specified for a non-local (global) label. - kErrorNonLocalLabelCantHaveParent, - - //! Relocation index overflow. - kErrorRelocIndexOverflow, - //! Invalid relocation entry. - kErrorInvalidRelocEntry, - - //! Invalid instruction. - kErrorInvalidInstruction, - //! Invalid register type. - kErrorInvalidRegType, - //! Invalid register kind. - kErrorInvalidRegKind, - //! Invalid register's physical id. - kErrorInvalidPhysId, - //! Invalid register's virtual id. - kErrorInvalidVirtId, - //! Invalid prefix combination. - kErrorInvalidPrefixCombination, - //! Invalid LOCK prefix. - kErrorInvalidLockPrefix, - //! Invalid XACQUIRE prefix. - kErrorInvalidXAcquirePrefix, - //! Invalid XACQUIRE prefix. - kErrorInvalidXReleasePrefix, - //! Invalid REP prefix. - kErrorInvalidRepPrefix, - //! Invalid REX prefix. - kErrorInvalidRexPrefix, - //! Invalid mask register (not 'k'). - kErrorInvalidKMaskReg, - //! Invalid {k} use (not supported by the instruction). - kErrorInvalidKMaskUse, - //! Invalid {k}{z} use (not supported by the instruction). - kErrorInvalidKZeroUse, - //! Invalid broadcast - Currently only related to invalid use of AVX-512 {1tox}. - kErrorInvalidBroadcast, - //! Invalid 'embedded-rounding' {er} or 'suppress-all-exceptions' {sae} (AVX-512). - kErrorInvalidEROrSAE, - //! Invalid address used (not encodable). - kErrorInvalidAddress, - //! Invalid index register used in memory address (not encodable). - kErrorInvalidAddressIndex, - //! Invalid address scale (not encodable). - kErrorInvalidAddressScale, - //! Invalid use of 64-bit address. - kErrorInvalidAddress64Bit, - //! Invalid displacement (not encodable). - kErrorInvalidDisplacement, - //! Invalid segment (X86). - kErrorInvalidSegment, - - //! Invalid immediate (out of bounds on X86 and invalid pattern on ARM). - kErrorInvalidImmediate, - - //! Invalid operand size. - kErrorInvalidOperandSize, - //! Ambiguous operand size (memory has zero size while it's required to determine the operation type. - kErrorAmbiguousOperandSize, - //! Mismatching operand size (size of multiple operands doesn't match the operation size). - kErrorOperandSizeMismatch, - - //! Invalid TypeId. - kErrorInvalidTypeId, - //! Invalid use of a 8-bit GPB-HIGH register. - kErrorInvalidUseOfGpbHi, - //! Invalid use of a 64-bit GPQ register in 32-bit mode. - kErrorInvalidUseOfGpq, - //! Invalid use of an 80-bit float (TypeId::kF80). - kErrorInvalidUseOfF80, - //! Some registers in the instruction muse be consecutive (some ARM and AVX512 neural-net instructions). - kErrorNotConsecutiveRegs, - - //! AsmJit requires a physical register, but no one is available. - kErrorNoMorePhysRegs, - //! A variable has been assigned more than once to a function argument (CodeCompiler). - kErrorOverlappedRegs, - //! Invalid register to hold stack arguments offset. - kErrorOverlappingStackRegWithRegArg, - - //! Count of AsmJit error codes. - kErrorCount -}; - -// ============================================================================ -// [asmjit::Internal] -// ============================================================================ - -namespace Internal { - -#if defined(ASMJIT_CUSTOM_ALLOC) && \ - defined(ASMJIT_CUSTOM_REALLOC) && \ - defined(ASMJIT_CUSTOM_FREE) -static ASMJIT_INLINE void* allocMemory(size_t size) noexcept { return ASMJIT_CUSTOM_ALLOC(size); } -static ASMJIT_INLINE void* reallocMemory(void* p, size_t size) noexcept { return ASMJIT_CUSTOM_REALLOC(p, size); } -static ASMJIT_INLINE void releaseMemory(void* p) noexcept { ASMJIT_CUSTOM_FREE(p); } -#elif !defined(ASMJIT_CUSTOM_ALLOC) && \ - !defined(ASMJIT_CUSTOM_REALLOC) && \ - !defined(ASMJIT_CUSTOM_FREE) -static ASMJIT_INLINE void* allocMemory(size_t size) noexcept { return ::malloc(size); } -static ASMJIT_INLINE void* reallocMemory(void* p, size_t size) noexcept { return ::realloc(p, size); } -static ASMJIT_INLINE void releaseMemory(void* p) noexcept { ::free(p); } -#else -# error "[asmjit] You must provide either none or all of ASMJIT_CUSTOM_[ALLOC|REALLOC|FREE]" -#endif - -//! Cast designed to cast between function and void* pointers. -template -static ASMJIT_INLINE Dst ptr_cast(Src p) noexcept { return (Dst)p; } - -} // Internal namespace - -template -static ASMJIT_INLINE Func ptr_as_func(void* func) noexcept { return Internal::ptr_cast(func); } - -template -static ASMJIT_INLINE void* func_as_ptr(Func func) noexcept { return Internal::ptr_cast(func); } - -// ============================================================================ -// [asmjit::DebugUtils] -// ============================================================================ - -namespace DebugUtils { - -//! Returns the error `err` passed. -//! -//! Provided for debugging purposes. Putting a breakpoint inside `errored` can -//! help with tracing the origin of any error reported / returned by AsmJit. -static ASMJIT_INLINE Error errored(Error err) noexcept { return err; } - -//! Get a printable version of `asmjit::Error` code. -ASMJIT_API const char* errorAsString(Error err) noexcept; - -//! Called to output debugging message(s). -ASMJIT_API void debugOutput(const char* str) noexcept; - -//! Called on assertion failure. -//! -//! \param file Source file name where it happened. -//! \param line Line in the source file. -//! \param msg Message to display. -//! -//! If you have problems with assertions put a breakpoint at assertionFailed() -//! function (asmjit/base/globals.cpp) and check the call stack to locate the -//! failing code. -ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept; - -#if defined(ASMJIT_DEBUG) -# define ASMJIT_ASSERT(exp) \ - do { \ - if (ASMJIT_LIKELY(exp)) \ - break; \ - ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #exp); \ - } while (0) -# define ASMJIT_NOT_REACHED() \ - do { \ - ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, \ - "ASMJIT_NOT_REACHED has been reached"); \ - ASMJIT_ASSUME(0); \ - } while (0) -#else -# define ASMJIT_ASSERT(exp) ASMJIT_NOP -# define ASMJIT_NOT_REACHED() ASMJIT_ASSUME(0) -#endif // DEBUG - -//! \internal -//! -//! Used by AsmJit to propagate a possible `Error` produced by `...` to the caller. -#define ASMJIT_PROPAGATE(...) \ - do { \ - ::asmjit::Error _err = __VA_ARGS__; \ - if (ASMJIT_UNLIKELY(_err)) \ - return _err; \ - } while (0) - -} // DebugUtils namespace - -// ============================================================================ -// [asmjit::Init / NoInit] -// ============================================================================ - -#if !defined(ASMJIT_DOCGEN) -struct _Init {}; -static const _Init Init = {}; - -struct _NoInit {}; -static const _NoInit NoInit = {}; -#endif // !ASMJIT_DOCGEN - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_GLOBALS_H diff --git a/libs/asmjit/base/inst.cpp b/libs/asmjit/base/inst.cpp deleted file mode 100644 index cc5ff39e..00000000 --- a/libs/asmjit/base/inst.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Guard] -#include "../asmjit_build.h" -#if defined(ASMJIT_BUILD_X86) - -// [Dependencies] -#include "../base/arch.h" -#include "../base/inst.h" - -#if defined(ASMJIT_BUILD_X86) -# include "../x86/x86instimpl_p.h" -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) -# include "../arm/arminstimpl_p.h" -#endif // ASMJIT_BUILD_ARM - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::Inst - Validate] -// ============================================================================ - -#if !defined(ASMJIT_DISABLE_VALIDATION) -Error Inst::validate(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count) noexcept { - #if defined(ASMJIT_BUILD_X86) - if (ArchInfo::isX86Family(archType)) - return X86InstImpl::validate(archType, detail, operands, count); - #endif - - #if defined(ASMJIT_BUILD_ARM) - if (ArchInfo::isArmFamily(archType)) - return ArmInstImpl::validate(archType, detail, operands, count); - #endif - - return DebugUtils::errored(kErrorInvalidArch); -} -#endif - -// ============================================================================ -// [asmjit::Inst - CheckFeatures] -// ============================================================================ - -#if !defined(ASMJIT_DISABLE_EXTENSIONS) -Error Inst::checkFeatures(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count, CpuFeatures& out) noexcept { - #if defined(ASMJIT_BUILD_X86) - if (ArchInfo::isX86Family(archType)) - return X86InstImpl::checkFeatures(archType, detail, operands, count, out); - #endif - - #if defined(ASMJIT_BUILD_ARM) - if (ArchInfo::isArmFamily(archType)) - return ArmInstImpl::checkFeatures(archType, detail, operands, count, out); - #endif - - return DebugUtils::errored(kErrorInvalidArch); -} -#endif // !defined(ASMJIT_DISABLE_EXTENSIONS) - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // ASMJIT_BUILD_X86 diff --git a/libs/asmjit/base/inst.h b/libs/asmjit/base/inst.h deleted file mode 100644 index 7bb210a8..00000000 --- a/libs/asmjit/base/inst.h +++ /dev/null @@ -1,108 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_INST_H -#define _ASMJIT_BASE_INST_H - -// [Dependencies] -#include "../base/cpuinfo.h" -#include "../base/operand.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::Inst] -// ============================================================================ - -//! Definitions and utilities related to instructions used by all architectures. -struct Inst { - ASMJIT_ENUM(Id) { - kIdNone = 0 //!< Invalid or uninitialized instruction id. - }; - - //! Describes an instruction's jump type, if any. - ASMJIT_ENUM(JumpType) { - kJumpTypeNone = 0, //!< Instruction doesn't jump (regular instruction). - kJumpTypeDirect = 1, //!< Instruction is a unconditional (direct) jump. - kJumpTypeConditional = 2, //!< Instruction is a conditional jump. - kJumpTypeCall = 3, //!< Instruction is a function call. - kJumpTypeReturn = 4 //!< Instruction is a function return. - }; - - // -------------------------------------------------------------------------- - // [Detail] - // -------------------------------------------------------------------------- - - //! Instruction id, options, and extraReg packed in a single structure. This - //! structure exists to simplify analysis and validation API that requires a - //! lot of information about the instruction to be processed. - class Detail { - public: - ASMJIT_INLINE Detail() noexcept - : instId(0), - options(0), - extraReg() {} - - explicit ASMJIT_INLINE Detail(uint32_t instId, uint32_t options = 0) noexcept - : instId(instId), - options(options), - extraReg() {} - - ASMJIT_INLINE Detail(uint32_t instId, uint32_t options, const RegOnly& reg) noexcept - : instId(instId), - options(options), - extraReg(reg) {} - - ASMJIT_INLINE Detail(uint32_t instId, uint32_t options, const Reg& reg) noexcept - : instId(instId), - options(options) { extraReg.init(reg); } - - // ------------------------------------------------------------------------ - // [Accessors] - // ------------------------------------------------------------------------ - - ASMJIT_INLINE bool hasExtraReg() const noexcept { return extraReg.isValid(); } - - // ------------------------------------------------------------------------ - // [Members] - // ------------------------------------------------------------------------ - - uint32_t instId; - uint32_t options; - RegOnly extraReg; - }; - - // -------------------------------------------------------------------------- - // [API] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_DISABLE_VALIDATION) - //! Validate the given instruction. - ASMJIT_API static Error validate(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count) noexcept; -#endif // !ASMJIT_DISABLE_VALIDATION - -#if !defined(ASMJIT_DISABLE_EXTENSIONS) - //! Check CPU features required to execute the given instruction. - ASMJIT_API static Error checkFeatures(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count, CpuFeatures& out) noexcept; -#endif // !defined(ASMJIT_DISABLE_EXTENSIONS) -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_INST_H diff --git a/libs/asmjit/base/logging.cpp b/libs/asmjit/base/logging.cpp deleted file mode 100644 index efb44752..00000000 --- a/libs/asmjit/base/logging.cpp +++ /dev/null @@ -1,497 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Guard] -#include "../asmjit_build.h" -#if !defined(ASMJIT_DISABLE_LOGGING) - -// [Dependencies] -#include "../base/codeholder.h" -#include "../base/codeemitter.h" -#include "../base/logging.h" -#include "../base/utils.h" - -#if !defined(ASMJIT_DISABLE_BUILDER) -# include "../base/codebuilder.h" -#endif // !ASMJIT_DISABLE_BUILDER - -#if !defined(ASMJIT_DISABLE_COMPILER) -# include "../base/codecompiler.h" -#else -namespace asmjit { class VirtReg; } -#endif // !ASMJIT_DISABLE_COMPILER - -#if defined(ASMJIT_BUILD_X86) -# include "../x86/x86logging_p.h" -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) -# include "../arm/armlogging_p.h" -#endif // ASMJIT_BUILD_ARM - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::Logger - Construction / Destruction] -// ============================================================================ - -Logger::Logger() noexcept { - _options = 0; - ::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation)); -} -Logger::~Logger() noexcept {} - -// ============================================================================ -// [asmjit::Logger - Logging] -// ============================================================================ - -Error Logger::logf(const char* fmt, ...) noexcept { - Error err; - - va_list ap; - va_start(ap, fmt); - err = logv(fmt, ap); - va_end(ap); - - return err; -} - -Error Logger::logv(const char* fmt, va_list ap) noexcept { - char buf[1024]; - size_t len = vsnprintf(buf, sizeof(buf), fmt, ap); - - if (len >= sizeof(buf)) - len = sizeof(buf) - 1; - return log(buf, len); -} - -Error Logger::logBinary(const void* data, size_t size) noexcept { - static const char prefix[] = ".data "; - static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - - const uint8_t* s = static_cast(data); - size_t i = size; - - char buffer[128]; - ::memcpy(buffer, prefix, ASMJIT_ARRAY_SIZE(prefix) - 1); - - while (i) { - uint32_t n = static_cast(std::min(i, 16)); - char* p = buffer + ASMJIT_ARRAY_SIZE(prefix) - 1; - - i -= n; - do { - uint32_t c = s[0]; - - p[0] = hex[c >> 4]; - p[1] = hex[c & 15]; - - p += 2; - s += 1; - } while (--n); - - *p++ = '\n'; - ASMJIT_PROPAGATE(log(buffer, (size_t)(p - buffer))); - } - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::Logger - Indentation] -// ============================================================================ - -void Logger::setIndentation(const char* indentation) noexcept { - ::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation)); - if (!indentation) - return; - - size_t length = Utils::strLen(indentation, ASMJIT_ARRAY_SIZE(_indentation) - 1); - ::memcpy(_indentation, indentation, length); -} - -// ============================================================================ -// [asmjit::FileLogger - Construction / Destruction] -// ============================================================================ - -FileLogger::FileLogger(FILE* stream) noexcept : _stream(nullptr) { setStream(stream); } -FileLogger::~FileLogger() noexcept {} - -// ============================================================================ -// [asmjit::FileLogger - Logging] -// ============================================================================ - -Error FileLogger::_log(const char* buf, size_t len) noexcept { - if (!_stream) - return kErrorOk; - - if (len == Globals::kInvalidIndex) - len = strlen(buf); - - fwrite(buf, 1, len, _stream); - return kErrorOk; -} - -// ============================================================================ -// [asmjit::StringLogger - Construction / Destruction] -// ============================================================================ - -StringLogger::StringLogger() noexcept {} -StringLogger::~StringLogger() noexcept {} - -// ============================================================================ -// [asmjit::StringLogger - Logging] -// ============================================================================ - -Error StringLogger::_log(const char* buf, size_t len) noexcept { - return _stringBuilder.appendString(buf, len); -} - -// ============================================================================ -// [asmjit::Logging] -// ============================================================================ - -Error Logging::formatLabel( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - uint32_t labelId) noexcept { - - const LabelEntry* le = emitter->getCode()->getLabelEntry(labelId); - if (ASMJIT_UNLIKELY(!le)) - return sb.appendFormat("InvalidLabel[Id=%u]", static_cast(labelId)); - - if (le->hasName()) { - if (le->hasParent()) { - uint32_t parentId = le->getParentId(); - const LabelEntry* pe = emitter->getCode()->getLabelEntry(parentId); - - if (ASMJIT_UNLIKELY(!pe)) - ASMJIT_PROPAGATE(sb.appendFormat("InvalidLabel[Id=%u]", static_cast(labelId))); - else if (ASMJIT_UNLIKELY(!pe->hasName())) - ASMJIT_PROPAGATE(sb.appendFormat("L%u", Operand::unpackId(parentId))); - else - ASMJIT_PROPAGATE(sb.appendString(pe->getName())); - - ASMJIT_PROPAGATE(sb.appendChar('.')); - } - return sb.appendString(le->getName()); - } - else { - return sb.appendFormat("L%u", Operand::unpackId(labelId)); - } -} - -Error Logging::formatRegister( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - uint32_t archType, - uint32_t regType, - uint32_t regId) noexcept { - -#if defined(ASMJIT_BUILD_X86) - return X86Logging::formatRegister(sb, logOptions, emitter, archType, regType, regId); -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) - return ArmLogging::formatRegister(sb, logOptions, emitter, archType, regType, regId); -#endif // ASMJIT_BUILD_ARM - - return kErrorInvalidArch; -} - -Error Logging::formatOperand( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - uint32_t archType, - const Operand_& op) noexcept { - -#if defined(ASMJIT_BUILD_X86) - return X86Logging::formatOperand(sb, logOptions, emitter, archType, op); -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) - return ArmLogging::formatOperand(sb, logOptions, emitter, archType, op); -#endif // ASMJIT_BUILD_ARM - - return kErrorInvalidArch; -} - -Error Logging::formatInstruction( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - uint32_t archType, - const Inst::Detail& detail, const Operand_* opArray, uint32_t opCount) noexcept { - -#if defined(ASMJIT_BUILD_X86) - return X86Logging::formatInstruction(sb, logOptions, emitter, archType, detail, opArray, opCount); -#endif // ASMJIT_BUILD_X86 - -#if defined(ASMJIT_BUILD_ARM) - return ArmLogging::formatInstruction(sb, logOptions, emitter, archType, detail, opArray, opCount); -#endif // ASMJIT_BUILD_ARM - - return kErrorInvalidArch; -} - -#if !defined(ASMJIT_DISABLE_BUILDER) -static Error formatTypeId(StringBuilder& sb, uint32_t typeId) noexcept { - if (typeId == TypeId::kVoid) - return sb.appendString("void"); - - if (!TypeId::isValid(typeId)) - return sb.appendString("unknown"); - - const char* typeName = "unknown"; - uint32_t typeSize = TypeId::sizeOf(typeId); - - uint32_t elementId = TypeId::elementOf(typeId); - switch (elementId) { - case TypeId::kIntPtr : typeName = "intptr" ; break; - case TypeId::kUIntPtr: typeName = "uintptr"; break; - case TypeId::kI8 : typeName = "i8" ; break; - case TypeId::kU8 : typeName = "u8" ; break; - case TypeId::kI16 : typeName = "i16" ; break; - case TypeId::kU16 : typeName = "u16" ; break; - case TypeId::kI32 : typeName = "i32" ; break; - case TypeId::kU32 : typeName = "u32" ; break; - case TypeId::kI64 : typeName = "i64" ; break; - case TypeId::kU64 : typeName = "u64" ; break; - case TypeId::kF32 : typeName = "f32" ; break; - case TypeId::kF64 : typeName = "f64" ; break; - case TypeId::kF80 : typeName = "f80" ; break; - case TypeId::kMask8 : typeName = "mask8" ; break; - case TypeId::kMask16 : typeName = "mask16" ; break; - case TypeId::kMask32 : typeName = "mask32" ; break; - case TypeId::kMask64 : typeName = "mask64" ; break; - case TypeId::kMmx32 : typeName = "mmx32" ; break; - case TypeId::kMmx64 : typeName = "mmx64" ; break; - } - - uint32_t elementSize = TypeId::sizeOf(elementId); - if (typeSize > elementSize) { - unsigned int numElements = typeSize / elementSize; - return sb.appendFormat("%sx%u", typeName, numElements); - } - else { - return sb.appendString(typeName); - } -} - -static Error formatFuncDetailValue( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - FuncDetail::Value value) noexcept { - - uint32_t typeId = value.getTypeId(); - ASMJIT_PROPAGATE(formatTypeId(sb, typeId)); - - if (value.byReg()) { - ASMJIT_PROPAGATE(sb.appendChar(':')); - ASMJIT_PROPAGATE(Logging::formatRegister(sb, logOptions, emitter, emitter->getArchType(), value.getRegType(), value.getRegId())); - } - - if (value.byStack()) { - ASMJIT_PROPAGATE(sb.appendFormat(":[%d]", static_cast(value.getStackOffset()))); - } - - return kErrorOk; -} - -static Error formatFuncRets( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - const FuncDetail& fd, - VirtReg* const* vRegs) noexcept { - - if (!fd.hasRet()) - return sb.appendString("void"); - - for (uint32_t i = 0; i < fd.getRetCount(); i++) { - if (i) ASMJIT_PROPAGATE(sb.appendString(", ")); - ASMJIT_PROPAGATE(formatFuncDetailValue(sb, logOptions, emitter, fd.getRet(i))); - -#if !defined(ASMJIT_DISABLE_COMPILER) - if (vRegs) - ASMJIT_PROPAGATE(sb.appendFormat(" {%s}", vRegs[i]->getName())); -#endif // !ASMJIT_DISABLE_COMPILER - } - - return kErrorOk; -} - -static Error formatFuncArgs( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - const FuncDetail& fd, - VirtReg* const* vRegs) noexcept { - - for (uint32_t i = 0; i < fd.getArgCount(); i++) { - if (i) ASMJIT_PROPAGATE(sb.appendString(", ")); - ASMJIT_PROPAGATE(formatFuncDetailValue(sb, logOptions, emitter, fd.getArg(i))); - -#if !defined(ASMJIT_DISABLE_COMPILER) - if (vRegs) - ASMJIT_PROPAGATE(sb.appendFormat(" {%s}", vRegs[i]->getName())); -#endif // !ASMJIT_DISABLE_COMPILER - } - - return kErrorOk; -} - -Error Logging::formatNode( - StringBuilder& sb, - uint32_t logOptions, - const CodeBuilder* cb, - const CBNode* node_) noexcept { - - if (node_->hasPosition()) - ASMJIT_PROPAGATE(sb.appendFormat("<%04u> ", node_->getPosition())); - - switch (node_->getType()) { - case CBNode::kNodeInst: { - const CBInst* node = node_->as(); - ASMJIT_PROPAGATE( - Logging::formatInstruction(sb, logOptions, cb, - cb->getArchType(), - node->getInstDetail(), node->getOpArray(), node->getOpCount())); - break; - } - - case CBNode::kNodeLabel: { - const CBLabel* node = node_->as(); - ASMJIT_PROPAGATE(sb.appendFormat("L%u:", Operand::unpackId(node->getId()))); - break; - } - - case CBNode::kNodeData: { - const CBData* node = node_->as(); - ASMJIT_PROPAGATE(sb.appendFormat(".embed (%u bytes)", node->getSize())); - break; - } - - case CBNode::kNodeAlign: { - const CBAlign* node = node_->as(); - ASMJIT_PROPAGATE( - sb.appendFormat(".align %u (%s)", - node->getAlignment(), - node->getMode() == kAlignCode ? "code" : "data")); - break; - } - - case CBNode::kNodeComment: { - const CBComment* node = node_->as(); - ASMJIT_PROPAGATE(sb.appendFormat("; %s", node->getInlineComment())); - break; - } - - case CBNode::kNodeSentinel: { - ASMJIT_PROPAGATE(sb.appendString("[sentinel]")); - break; - } - -#if !defined(ASMJIT_DISABLE_COMPILER) - case CBNode::kNodeFunc: { - const CCFunc* node = node_->as(); - ASMJIT_PROPAGATE(formatLabel(sb, logOptions, cb, node->getId())); - - ASMJIT_PROPAGATE(sb.appendString(": [")); - ASMJIT_PROPAGATE(formatFuncRets(sb, logOptions, cb, node->getDetail(), nullptr)); - ASMJIT_PROPAGATE(sb.appendString("]")); - - ASMJIT_PROPAGATE(sb.appendString("(")); - ASMJIT_PROPAGATE(formatFuncArgs(sb, logOptions, cb, node->getDetail(), node->getArgs())); - ASMJIT_PROPAGATE(sb.appendString(")")); - break; - } - - case CBNode::kNodeFuncExit: { - ASMJIT_PROPAGATE(sb.appendString("[ret]")); - break; - } - - case CBNode::kNodeFuncCall: { - const CCFuncCall* node = node_->as(); - ASMJIT_PROPAGATE( - Logging::formatInstruction(sb, logOptions, cb, - cb->getArchType(), - node->getInstDetail(), node->getOpArray(), node->getOpCount())); - break; - } -#endif // !ASMJIT_DISABLE_COMPILER - - default: { - ASMJIT_PROPAGATE(sb.appendFormat("[unknown (type=%u)]", node_->getType())); - break; - } - } - - return kErrorOk; -} -#endif // !ASMJIT_DISABLE_BUILDER - -Error Logging::formatLine(StringBuilder& sb, const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept { - size_t currentLen = sb.getLength(); - size_t commentLen = comment ? Utils::strLen(comment, kMaxCommentLength) : 0; - - ASMJIT_ASSERT(binLen >= dispLen); - - if ((binLen != 0 && binLen != Globals::kInvalidIndex) || commentLen) { - size_t align = kMaxInstLength; - char sep = ';'; - - for (size_t i = (binLen == Globals::kInvalidIndex); i < 2; i++) { - size_t begin = sb.getLength(); - - // Append align. - if (currentLen < align) - ASMJIT_PROPAGATE(sb.appendChars(' ', align - currentLen)); - - // Append separator. - if (sep) { - ASMJIT_PROPAGATE(sb.appendChar(sep)); - ASMJIT_PROPAGATE(sb.appendChar(' ')); - } - - // Append binary data or comment. - if (i == 0) { - ASMJIT_PROPAGATE(sb.appendHex(binData, binLen - dispLen - imLen)); - ASMJIT_PROPAGATE(sb.appendChars('.', dispLen * 2)); - ASMJIT_PROPAGATE(sb.appendHex(binData + binLen - imLen, imLen)); - if (commentLen == 0) break; - } - else { - ASMJIT_PROPAGATE(sb.appendString(comment, commentLen)); - } - - currentLen += sb.getLength() - begin; - align += kMaxBinaryLength; - sep = '|'; - } - } - - return sb.appendChar('\n'); -} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // !ASMJIT_DISABLE_LOGGING diff --git a/libs/asmjit/base/logging.h b/libs/asmjit/base/logging.h deleted file mode 100644 index 609f1880..00000000 --- a/libs/asmjit/base/logging.h +++ /dev/null @@ -1,288 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_LOGGING_H -#define _ASMJIT_BASE_LOGGING_H - -// [Dependencies] -#include "../base/inst.h" -#include "../base/string.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -#if !defined(ASMJIT_DISABLE_LOGGING) - -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -class CodeEmitter; -class Reg; -struct Operand_; - -#if !defined(ASMJIT_DISABLE_BUILDER) -class CodeBuilder; -class CBNode; -#endif // !ASMJIT_DISABLE_BUILDER - -// ============================================================================ -// [asmjit::Logger] -// ============================================================================ - -//! Abstract logging interface and helpers. -//! -//! This class can be inherited and reimplemented to fit into your logging -//! subsystem. When reimplementing use `Logger::_log()` method to log into -//! a custom stream. -//! -//! There are two \ref Logger implementations offered by AsmJit: -//! - \ref FileLogger - allows to log into a `FILE*` stream. -//! - \ref StringLogger - logs into a \ref StringBuilder. -class ASMJIT_VIRTAPI Logger { -public: - ASMJIT_NONCOPYABLE(Logger) - - // -------------------------------------------------------------------------- - // [Options] - // -------------------------------------------------------------------------- - - //! Logger options. - ASMJIT_ENUM(Options) { - kOptionBinaryForm = 0x00000001, //! Output instructions also in binary form. - kOptionImmExtended = 0x00000002, //! Output a meaning of some immediates. - kOptionHexImmediate = 0x00000004, //! Output constants in hexadecimal form. - kOptionHexDisplacement = 0x00000008 //! Output displacements in hexadecimal form. - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a `Logger` instance. - ASMJIT_API Logger() noexcept; - //! Destroy the `Logger` instance. - ASMJIT_API virtual ~Logger() noexcept; - - // -------------------------------------------------------------------------- - // [Logging] - // -------------------------------------------------------------------------- - - //! Log `str` - must be reimplemented. - virtual Error _log(const char* str, size_t len) noexcept = 0; - - //! Log a string `str`, which is either null terminated or having `len` length. - ASMJIT_INLINE Error log(const char* str, size_t len = Globals::kInvalidIndex) noexcept { return _log(str, len); } - //! Log a content of a `StringBuilder` `str`. - ASMJIT_INLINE Error log(const StringBuilder& str) noexcept { return _log(str.getData(), str.getLength()); } - - //! Format the message by using `sprintf()` and then send to `log()`. - ASMJIT_API Error logf(const char* fmt, ...) noexcept; - //! Format the message by using `vsprintf()` and then send to `log()`. - ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept; - //! Log binary data. - ASMJIT_API Error logBinary(const void* data, size_t size) noexcept; - - // -------------------------------------------------------------------------- - // [Options] - // -------------------------------------------------------------------------- - - //! Get all logger options as a single integer. - ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; } - //! Get the given logger option. - ASMJIT_INLINE bool hasOption(uint32_t option) const noexcept { return (_options & option) != 0; } - ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; } - ASMJIT_INLINE void clearOptions(uint32_t options) noexcept { _options &= ~options; } - - // -------------------------------------------------------------------------- - // [Indentation] - // -------------------------------------------------------------------------- - - //! Get indentation. - ASMJIT_INLINE const char* getIndentation() const noexcept { return _indentation; } - //! Set indentation. - ASMJIT_API void setIndentation(const char* indentation) noexcept; - //! Reset indentation. - ASMJIT_INLINE void resetIndentation() noexcept { setIndentation(nullptr); } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Options, see \ref LoggerOption. - uint32_t _options; - - //! Indentation. - char _indentation[12]; -}; - -// ============================================================================ -// [asmjit::FileLogger] -// ============================================================================ - -//! Logger that can log to a `FILE*` stream. -class ASMJIT_VIRTAPI FileLogger : public Logger { -public: - ASMJIT_NONCOPYABLE(FileLogger) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `FileLogger` that logs to a `FILE` stream. - ASMJIT_API FileLogger(FILE* stream = nullptr) noexcept; - //! Destroy the `FileLogger`. - ASMJIT_API virtual ~FileLogger() noexcept; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get the logging out put stream or null. - ASMJIT_INLINE FILE* getStream() const noexcept { return _stream; } - - //! Set the logging output stream to `stream` or null. - //! - //! NOTE: If the `stream` is null it will disable logging, but it won't - //! stop calling `log()` unless the logger is detached from the - //! \ref Assembler. - ASMJIT_INLINE void setStream(FILE* stream) noexcept { _stream = stream; } - - // -------------------------------------------------------------------------- - // [Logging] - // -------------------------------------------------------------------------- - - ASMJIT_API Error _log(const char* buf, size_t len = Globals::kInvalidIndex) noexcept override; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! C file stream. - FILE* _stream; -}; - -// ============================================================================ -// [asmjit::StringLogger] -// ============================================================================ - -//! Logger that stores everything in an internal string buffer. -class ASMJIT_VIRTAPI StringLogger : public Logger { -public: - ASMJIT_NONCOPYABLE(StringLogger) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create new `StringLogger`. - ASMJIT_API StringLogger() noexcept; - //! Destroy the `StringLogger`. - ASMJIT_API virtual ~StringLogger() noexcept; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get `char*` pointer which represents the resulting string. - //! - //! The pointer is owned by `StringLogger`, it can't be modified or freed. - ASMJIT_INLINE const char* getString() const noexcept { return _stringBuilder.getData(); } - //! Clear the resulting string. - ASMJIT_INLINE void clearString() noexcept { _stringBuilder.clear(); } - - //! Get the length of the string returned by `getString()`. - ASMJIT_INLINE size_t getLength() const noexcept { return _stringBuilder.getLength(); } - - // -------------------------------------------------------------------------- - // [Logging] - // -------------------------------------------------------------------------- - - ASMJIT_API Error _log(const char* buf, size_t len = Globals::kInvalidIndex) noexcept override; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Output string. - StringBuilder _stringBuilder; -}; - -// ============================================================================ -// [asmjit::Logging] -// ============================================================================ - -struct Logging { - ASMJIT_API static Error formatRegister( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - uint32_t archType, - uint32_t regType, - uint32_t regId) noexcept; - - ASMJIT_API static Error formatLabel( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - uint32_t labelId) noexcept; - - ASMJIT_API static Error formatOperand( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - uint32_t archType, - const Operand_& op) noexcept; - - ASMJIT_API static Error formatInstruction( - StringBuilder& sb, - uint32_t logOptions, - const CodeEmitter* emitter, - uint32_t archType, - const Inst::Detail& detail, const Operand_* opArray, uint32_t opCount) noexcept; - -#if !defined(ASMJIT_DISABLE_BUILDER) - ASMJIT_API static Error formatNode( - StringBuilder& sb, - uint32_t logOptions, - const CodeBuilder* cb, - const CBNode* node_) noexcept; -#endif // !ASMJIT_DISABLE_BUILDER - -// Only used by AsmJit internals, not available to users. -#if defined(ASMJIT_EXPORTS) - enum { - // Has to be big to be able to hold all metadata compiler can assign to a - // single instruction. - kMaxCommentLength = 512, - kMaxInstLength = 40, - kMaxBinaryLength = 26 - }; - - static Error formatLine( - StringBuilder& sb, - const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept; -#endif // ASMJIT_EXPORTS -}; -#else -class Logger; -#endif // !ASMJIT_DISABLE_LOGGING - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_LOGGER_H diff --git a/libs/asmjit/base/misc_p.h b/libs/asmjit/base/misc_p.h deleted file mode 100644 index 5024f1c7..00000000 --- a/libs/asmjit/base/misc_p.h +++ /dev/null @@ -1,74 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_MISC_P_H -#define _ASMJIT_BASE_MISC_P_H - -// [Dependencies] -#include "../asmjit_build.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -//! \internal -//! -//! Macro used to populate a table with 16 elements starting at `I`. -#define ASMJIT_TABLE_16(DEF, I) DEF(I + 0), DEF(I + 1), DEF(I + 2), DEF(I + 3), \ - DEF(I + 4), DEF(I + 5), DEF(I + 6), DEF(I + 7), \ - DEF(I + 8), DEF(I + 9), DEF(I + 10), DEF(I + 11), \ - DEF(I + 12), DEF(I + 13), DEF(I + 14), DEF(I + 15) - -#define ASMJIT_TABLE_T_8(TABLE, VALUE, I) \ - TABLE< I + 0 >::VALUE, TABLE< I + 1 >::VALUE, \ - TABLE< I + 2 >::VALUE, TABLE< I + 3 >::VALUE, \ - TABLE< I + 4 >::VALUE, TABLE< I + 5 >::VALUE, \ - TABLE< I + 6 >::VALUE, TABLE< I + 7 >::VALUE - -#define ASMJIT_TABLE_T_16(TABLE, VALUE, I) \ - ASMJIT_TABLE_T_8(TABLE, VALUE, I), \ - ASMJIT_TABLE_T_8(TABLE, VALUE, I + 8) - -#define ASMJIT_TABLE_T_32(TABLE, VALUE, I) \ - ASMJIT_TABLE_T_16(TABLE, VALUE, I), \ - ASMJIT_TABLE_T_16(TABLE, VALUE, I + 16) - -#define ASMJIT_TABLE_T_64(TABLE, VALUE, I) \ - ASMJIT_TABLE_T_32(TABLE, VALUE, I), \ - ASMJIT_TABLE_T_32(TABLE, VALUE, I + 32) - -#define ASMJIT_TABLE_T_128(TABLE, VALUE, I) \ - ASMJIT_TABLE_T_64(TABLE, VALUE, I), \ - ASMJIT_TABLE_T_64(TABLE, VALUE, I + 64) - -#define ASMJIT_TABLE_T_256(TABLE, VALUE, I) \ - ASMJIT_TABLE_T_128(TABLE, VALUE, I), \ - ASMJIT_TABLE_T_128(TABLE, VALUE, I + 128) - -#define ASMJIT_TABLE_T_512(TABLE, VALUE, I) \ - ASMJIT_TABLE_T_256(TABLE, VALUE, I), \ - ASMJIT_TABLE_T_256(TABLE, VALUE, I + 256) - -#define ASMJIT_TABLE_T_1024(TABLE, VALUE, I) \ - ASMJIT_TABLE_T_512(TABLE, VALUE, I), \ - ASMJIT_TABLE_T_512(TABLE, VALUE, I + 512) - -//! \} - -} // asmjit namespace - -//! \} - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_MISC_P_H diff --git a/libs/asmjit/base/operand.cpp b/libs/asmjit/base/operand.cpp deleted file mode 100644 index 09eeea89..00000000 --- a/libs/asmjit/base/operand.cpp +++ /dev/null @@ -1,209 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/operand.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::TypeId] -// ============================================================================ - -template -struct TypeIdSizeOf_T { - enum { - kValue = (ID == TypeId::kI8 ) ? 1 : - (ID == TypeId::kU8 ) ? 1 : - (ID == TypeId::kI16 ) ? 2 : - (ID == TypeId::kU16 ) ? 2 : - (ID == TypeId::kI32 ) ? 4 : - (ID == TypeId::kU32 ) ? 4 : - (ID == TypeId::kI64 ) ? 8 : - (ID == TypeId::kU64 ) ? 8 : - (ID == TypeId::kF32 ) ? 4 : - (ID == TypeId::kF64 ) ? 8 : - (ID == TypeId::kF80 ) ? 10 : - (ID == TypeId::kMask8 ) ? 1 : - (ID == TypeId::kMask16) ? 2 : - (ID == TypeId::kMask32) ? 4 : - (ID == TypeId::kMask64) ? 8 : - (ID == TypeId::kMmx32 ) ? 4 : - (ID == TypeId::kMmx64 ) ? 8 : - (ID >= TypeId::_kVec32Start && ID <= TypeId::_kVec32End ) ? 4 : - (ID >= TypeId::_kVec64Start && ID <= TypeId::_kVec64End ) ? 8 : - (ID >= TypeId::_kVec128Start && ID <= TypeId::_kVec128End) ? 16 : - (ID >= TypeId::_kVec256Start && ID <= TypeId::_kVec256End) ? 32 : - (ID >= TypeId::_kVec512Start && ID <= TypeId::_kVec512End) ? 64 : 0 - }; -}; - -template -struct TypeIdElementOf_T { - enum { - kValue = (ID == TypeId::kMask8 ) ? TypeId::kU8 : - (ID == TypeId::kMask16) ? TypeId::kU16 : - (ID == TypeId::kMask32) ? TypeId::kU32 : - (ID == TypeId::kMask64) ? TypeId::kU64 : - (ID == TypeId::kMmx32 ) ? TypeId::kI32 : - (ID == TypeId::kMmx64 ) ? TypeId::kI64 : - (ID >= TypeId::kI8 && ID <= TypeId::kF80 ) ? ID : - (ID >= TypeId::_kVec32Start && ID <= TypeId::_kVec32End ) ? ID - TypeId::_kVec32Start + TypeId::kI8 : - (ID >= TypeId::_kVec64Start && ID <= TypeId::_kVec64End ) ? ID - TypeId::_kVec64Start + TypeId::kI8 : - (ID >= TypeId::_kVec128Start && ID <= TypeId::_kVec128End) ? ID - TypeId::_kVec128Start + TypeId::kI8 : - (ID >= TypeId::_kVec256Start && ID <= TypeId::_kVec256End) ? ID - TypeId::_kVec256Start + TypeId::kI8 : - (ID >= TypeId::_kVec512Start && ID <= TypeId::_kVec512End) ? ID - TypeId::_kVec512Start + TypeId::kI8 : 0 - }; -}; - -#define R(TMPL, I) TMPL::kValue, TMPL::kValue, \ - TMPL::kValue, TMPL::kValue, \ - TMPL::kValue, TMPL::kValue, \ - TMPL::kValue, TMPL::kValue, \ - TMPL::kValue, TMPL::kValue, \ - TMPL::kValue, TMPL::kValue, \ - TMPL::kValue, TMPL::kValue, \ - TMPL::kValue, TMPL::kValue -ASMJIT_API const TypeId::Info TypeId::_info = { - // SizeOf[128] - { - R(TypeIdSizeOf_T, 0), R(TypeIdSizeOf_T, 16), - R(TypeIdSizeOf_T, 32), R(TypeIdSizeOf_T, 48), - R(TypeIdSizeOf_T, 64), R(TypeIdSizeOf_T, 80), - R(TypeIdSizeOf_T, 96), R(TypeIdSizeOf_T, 112) - }, - - // ElementOf[128] - { - R(TypeIdElementOf_T, 0), R(TypeIdElementOf_T, 16), - R(TypeIdElementOf_T, 32), R(TypeIdElementOf_T, 48), - R(TypeIdElementOf_T, 64), R(TypeIdElementOf_T, 80), - R(TypeIdElementOf_T, 96), R(TypeIdElementOf_T, 112) - } -}; -#undef R - -// ============================================================================ -// [asmjit::Operand - Test] -// ============================================================================ - -#if defined(ASMJIT_TEST) -UNIT(base_operand) { - INFO("Checking operand sizes"); - EXPECT(sizeof(Operand) == 16); - EXPECT(sizeof(Reg) == 16); - EXPECT(sizeof(Mem) == 16); - EXPECT(sizeof(Imm) == 16); - EXPECT(sizeof(Label) == 16); - - INFO("Checking basic functionality of Operand"); - Operand a, b; - Operand dummy; - - EXPECT(a.isNone() == true); - EXPECT(a.isReg() == false); - EXPECT(a.isMem() == false); - EXPECT(a.isImm() == false); - EXPECT(a.isLabel() == false); - EXPECT(a == b); - - EXPECT(a._any.reserved8_4 == 0, "Default constructed Operand should zero its 'reserved8_4' field"); - EXPECT(a._any.reserved12_4 == 0, "Default constructed Operand should zero its 'reserved12_4' field"); - - INFO("Checking basic functionality of Label"); - Label label; - EXPECT(label.isValid() == false); - EXPECT(label.getId() == 0); - - INFO("Checking basic functionality of Reg"); - EXPECT(Reg().isValid() == false, - "Default constructed Reg() should not be valid"); - EXPECT(Reg()._any.reserved8_4 == 0, - "A default constructed Reg() should zero its 'reserved8_4' field"); - EXPECT(Reg()._any.reserved12_4 == 0, - "A default constructed Reg() should zero its 'reserved12_4' field"); - - EXPECT(Reg().isReg() == false, - "Default constructed register should not isReg()"); - EXPECT(dummy.as().isValid() == false, - "Default constructed Operand casted to Reg should not be valid"); - - // Create some register (not specific to any architecture). - uint32_t rSig = Operand::kOpReg | (1 << Operand::kSignatureRegTypeShift) | - (2 << Operand::kSignatureRegKindShift) | - (8 << Operand::kSignatureSizeShift ) ; - Reg r1(Reg::fromSignature(rSig, 5)); - - EXPECT(r1.isValid() == true); - EXPECT(r1.isReg() == true); - EXPECT(r1.isReg(1) == true); - EXPECT(r1.isPhysReg() == true); - EXPECT(r1.isVirtReg() == false); - EXPECT(r1.getSignature() == rSig); - EXPECT(r1.getType() == 1); - EXPECT(r1.getKind() == 2); - EXPECT(r1.getSize() == 8); - EXPECT(r1.getId() == 5); - EXPECT(r1.isReg(1, 5) == true); // RegType and Id. - - EXPECT(r1._any.reserved8_4 == 0, "Reg should have 'reserved8_4' zero"); - EXPECT(r1._any.reserved12_4 == 0, "Reg should have 'reserved12_4' zero"); - - // The same type of register having different id. - Reg r2(r1, 6); - EXPECT(r2.isValid() == true); - EXPECT(r2.isReg() == true); - EXPECT(r2.isReg(1) == true); - EXPECT(r2.isPhysReg() == true); - EXPECT(r2.isVirtReg() == false); - EXPECT(r2.getSignature() == rSig); - EXPECT(r2.getType() == r1.getType()); - EXPECT(r2.getKind() == r1.getKind()); - EXPECT(r2.getSize() == r1.getSize()); - EXPECT(r2.getId() == 6); - EXPECT(r2.isReg(1, 6) == true); - - r1.reset(); - EXPECT(!r1.isValid(), - "Reset register should not be valid"); - EXPECT(!r1.isReg(), - "Reset register should not isReg()"); - - INFO("Checking basic functionality of Mem"); - Mem m; - EXPECT(m.isMem() , "Default constructed Mem() should isMem()"); - EXPECT(m == Mem() , "Two default constructed Mem() operands should be equal"); - EXPECT(m.hasBase() == false , "Default constructed Mem() should not have base specified"); - EXPECT(m.hasIndex() == false , "Default constructed Mem() should not have index specified"); - EXPECT(m.has64BitOffset() == true , "Default constructed Mem() should report 64-bit offset"); - EXPECT(m.getOffset() == 0 , "Default constructed Mem() should have be zero offset / address"); - - m.setOffset(-1); - EXPECT(m.getOffsetLo32() == -1 , "Memory operand must hold a 32-bit offset"); - EXPECT(m.getOffset() == -1 , "32-bit offset must be sign extended to 64 bits"); - - int64_t x = int64_t(ASMJIT_UINT64_C(0xFF00FF0000000001)); - m.setOffset(x); - EXPECT(m.getOffset() == x , "Memory operand must hold a 64-bit offset"); - EXPECT(m.getOffsetLo32() == 1 , "Memory operand must return correct low offset DWORD"); - EXPECT(m.getOffsetHi32() == 0xFF00FF00, "Memory operand must return correct high offset DWORD"); - - INFO("Checking basic functionality of Imm"); - EXPECT(Imm(-1).getInt64() == int64_t(-1), - "Immediate values should by default sign-extend to 64-bits"); -} -#endif // ASMJIT_TEST - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/operand.h b/libs/asmjit/base/operand.h deleted file mode 100644 index 1bdb2a58..00000000 --- a/libs/asmjit/base/operand.h +++ /dev/null @@ -1,1570 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_OPERAND_H -#define _ASMJIT_BASE_OPERAND_H - -// [Dependencies] -#include "../base/utils.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::Operand_] -// ============================================================================ - -//! Constructor-less \ref Operand. -//! -//! Contains no initialization code and can be used safely to define an array -//! of operands that won't be initialized. This is a \ref Operand compatible -//! data structure designed to be statically initialized or `static const`. -struct Operand_ { - // -------------------------------------------------------------------------- - // [Operand Type] - // -------------------------------------------------------------------------- - - //! Operand types that can be encoded in \ref Operand. - ASMJIT_ENUM(OpType) { - kOpNone = 0, //!< Not an operand or not initialized. - kOpReg = 1, //!< Operand is a register. - kOpMem = 2, //!< Operand is a memory. - kOpImm = 3, //!< Operand is an immediate value. - kOpLabel = 4 //!< Operand is a label. - }; - - // -------------------------------------------------------------------------- - // [Operand Signature (Bits)] - // -------------------------------------------------------------------------- - - ASMJIT_ENUM(SignatureBits) { - // Operand type (3 least significant bits). - // |........|........|........|.....XXX| - kSignatureOpShift = 0, - kSignatureOpBits = 0x07U, - kSignatureOpMask = kSignatureOpBits << kSignatureOpShift, - - // Operand size (8 most significant bits). - // |XXXXXXXX|........|........|........| - kSignatureSizeShift = 24, - kSignatureSizeBits = 0xFFU, - kSignatureSizeMask = kSignatureSizeBits << kSignatureSizeShift, - - // Register type (5 bits). - // |........|........|........|XXXXX...| - kSignatureRegTypeShift = 3, - kSignatureRegTypeBits = 0x1FU, - kSignatureRegTypeMask = kSignatureRegTypeBits << kSignatureRegTypeShift, - - // Register kind (4 bits). - // |........|........|....XXXX|........| - kSignatureRegKindShift = 8, - kSignatureRegKindBits = 0x0FU, - kSignatureRegKindMask = kSignatureRegKindBits << kSignatureRegKindShift, - - // Memory base type (5 bits). - // |........|........|........|XXXXX...| - kSignatureMemBaseTypeShift = 3, - kSignatureMemBaseTypeBits = 0x1FU, - kSignatureMemBaseTypeMask = kSignatureMemBaseTypeBits << kSignatureMemBaseTypeShift, - - // Memory index type (5 bits). - // |........|........|...XXXXX|........| - kSignatureMemIndexTypeShift = 8, - kSignatureMemIndexTypeBits = 0x1FU, - kSignatureMemIndexTypeMask = kSignatureMemIndexTypeBits << kSignatureMemIndexTypeShift, - - // Memory base+index combined (10 bits). - // |........|........|...XXXXX|XXXXX...| - kSignatureMemBaseIndexShift = 3, - kSignatureMemBaseIndexBits = 0x3FFU, - kSignatureMemBaseIndexMask = kSignatureMemBaseIndexBits << kSignatureMemBaseIndexShift, - - // Memory should be encoded as absolute immediate (X86|X64). - // |........|........|.XX.....|........| - kSignatureMemAddrTypeShift = 13, - kSignatureMemAddrTypeBits = 0x03U, - kSignatureMemAddrTypeMask = kSignatureMemAddrTypeBits << kSignatureMemAddrTypeShift, - - // This memory operand represents a function argument's stack location (CodeCompiler) - // |........|........|.X......|........| - kSignatureMemArgHomeShift = 15, - kSignatureMemArgHomeBits = 0x01U, - kSignatureMemArgHomeFlag = kSignatureMemArgHomeBits << kSignatureMemArgHomeShift, - - // This memory operand represents a virtual register's home-slot (CodeCompiler). - // |........|........|X.......|........| - kSignatureMemRegHomeShift = 16, - kSignatureMemRegHomeBits = 0x01U, - kSignatureMemRegHomeFlag = kSignatureMemRegHomeBits << kSignatureMemRegHomeShift - }; - - // -------------------------------------------------------------------------- - // [Operand Id] - // -------------------------------------------------------------------------- - - //! Operand id helpers useful for id <-> index translation. - ASMJIT_ENUM(PackedId) { - //! Minimum valid packed-id. - kPackedIdMin = 0x00000100U, - //! Maximum valid packed-id. - kPackedIdMax = 0xFFFFFFFFU, - //! Count of valid packed-ids. - kPackedIdCount = kPackedIdMax - kPackedIdMin + 1 - }; - - // -------------------------------------------------------------------------- - // [Operand Utilities] - // -------------------------------------------------------------------------- - - //! Get if the given `id` is a valid packed-id that can be used by Operand. - //! Packed ids are those equal or greater than `kPackedIdMin` and lesser or - //! equal to `kPackedIdMax`. This concept was created to support virtual - //! registers and to make them distinguishable from physical ones. It allows - //! a single uint32_t to contain either physical register id or virtual - //! register id represented as `packed-id`. This concept is used also for - //! labels to make the API consistent. - static ASMJIT_INLINE bool isPackedId(uint32_t id) noexcept { return id - kPackedIdMin < kPackedIdCount; } - //! Convert a real-id into a packed-id that can be stored in Operand. - static ASMJIT_INLINE uint32_t packId(uint32_t id) noexcept { return id + kPackedIdMin; } - //! Convert a packed-id back to real-id. - static ASMJIT_INLINE uint32_t unpackId(uint32_t id) noexcept { return id - kPackedIdMin; } - - // -------------------------------------------------------------------------- - // [Operand Data] - // -------------------------------------------------------------------------- - - //! Any operand. - struct AnyData { - uint32_t signature; //!< Type of the operand (see \ref OpType) and other data. - uint32_t id; //!< Operand id or `0`. - uint32_t reserved8_4; //!< \internal - uint32_t reserved12_4; //!< \internal - }; - - //! Register operand data. - struct RegData { - uint32_t signature; //!< Type of the operand (always \ref kOpReg) and other data. - uint32_t id; //!< Physical or virtual register id. - uint32_t reserved8_4; //!< \internal - uint32_t reserved12_4; //!< \internal - }; - - //! Memory operand data. - struct MemData { - uint32_t signature; //!< Type of the operand (always \ref kOpMem) and other data. - uint32_t index; //!< INDEX register id or `0`. - - // [BASE + OFF32] vs just [OFF64]. - union { - uint64_t offset64; //!< 64-bit offset, combining low and high 32-bit parts. - struct { -#if ASMJIT_ARCH_LE - uint32_t offsetLo32; //!< 32-bit low offset part. - uint32_t base; //!< 32-bit high offset part or BASE. -#else - uint32_t base; //!< 32-bit high offset part or BASE. - uint32_t offsetLo32; //!< 32-bit low offset part. -#endif - }; - }; - }; - - //! Immediate operand data. - struct ImmData { - uint32_t signature; //!< Type of the operand (always \ref kOpImm) and other data. - uint32_t id; //!< Immediate id (always `0`). - UInt64 value; //!< Immediate value. - }; - - //! Label operand data. - struct LabelData { - uint32_t signature; //!< Type of the operand (always \ref kOpLabel) and other data. - uint32_t id; //!< Label id (`0` if not initialized). - uint32_t reserved8_4; //!< \internal - uint32_t reserved12_4; //!< \internal - }; - - // -------------------------------------------------------------------------- - // [Init & Copy] - // -------------------------------------------------------------------------- - - //! \internal - //! - //! Initialize the operand to `other` (used by constructors). - ASMJIT_INLINE void _init(const Operand_& other) noexcept { ::memcpy(this, &other, sizeof(Operand_)); } - - //! \internal - ASMJIT_INLINE void _initReg(uint32_t signature, uint32_t rd) { - _init_packed_d0_d1(signature, rd); - _init_packed_d2_d3(0, 0); - } - - //! \internal - ASMJIT_INLINE void _init_packed_d0_d1(uint32_t d0, uint32_t d1) noexcept { _packed[0].setPacked_2x32(d0, d1); } - //! \internal - ASMJIT_INLINE void _init_packed_d2_d3(uint32_t d2, uint32_t d3) noexcept { _packed[1].setPacked_2x32(d2, d3); } - - //! \internal - //! - //! Initialize the operand from `other` (used by operator overloads). - ASMJIT_INLINE void copyFrom(const Operand_& other) noexcept { ::memcpy(this, &other, sizeof(Operand_)); } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get if the operand matches the given signature `sign`. - ASMJIT_INLINE bool hasSignature(uint32_t signature) const noexcept { return _signature == signature; } - - //! Get if the operand matches a signature of the `other` operand. - ASMJIT_INLINE bool hasSignature(const Operand_& other) const noexcept { - return _signature == other.getSignature(); - } - - //! Get a 32-bit operand signature. - //! - //! Signature is first 4 bytes of the operand data. It's used mostly for - //! operand checking as it's much faster to check 4 bytes at once than having - //! to check these bytes individually. - ASMJIT_INLINE uint32_t getSignature() const noexcept { return _signature; } - - //! Set the operand signature (see \ref getSignature). - //! - //! Improper use of `setSignature()` can lead to hard-to-debug errors. - ASMJIT_INLINE void setSignature(uint32_t signature) noexcept { _signature = signature; } - - ASMJIT_INLINE bool _hasSignatureData(uint32_t bits) const noexcept { return (_signature & bits) != 0; } - - //! \internal - //! - //! Unpacks information from operand's signature. - ASMJIT_INLINE uint32_t _getSignatureData(uint32_t bits, uint32_t shift) const noexcept { return (_signature >> shift) & bits; } - - //! \internal - //! - //! Packs information to operand's signature. - ASMJIT_INLINE void _setSignatureData(uint32_t value, uint32_t bits, uint32_t shift) noexcept { - ASMJIT_ASSERT(value <= bits); - _signature = (_signature & ~(bits << shift)) | (value << shift); - } - - ASMJIT_INLINE void _addSignatureData(uint32_t data) noexcept { _signature |= data; } - - //! Clears specified bits in operand's signature. - ASMJIT_INLINE void _clearSignatureData(uint32_t bits, uint32_t shift) noexcept { _signature &= ~(bits << shift); } - - //! Get type of the operand, see \ref OpType. - ASMJIT_INLINE uint32_t getOp() const noexcept { return _getSignatureData(kSignatureOpBits, kSignatureOpShift); } - //! Get if the operand is none (\ref kOpNone). - ASMJIT_INLINE bool isNone() const noexcept { return getOp() == 0; } - //! Get if the operand is a register (\ref kOpReg). - ASMJIT_INLINE bool isReg() const noexcept { return getOp() == kOpReg; } - //! Get if the operand is a memory location (\ref kOpMem). - ASMJIT_INLINE bool isMem() const noexcept { return getOp() == kOpMem; } - //! Get if the operand is an immediate (\ref kOpImm). - ASMJIT_INLINE bool isImm() const noexcept { return getOp() == kOpImm; } - //! Get if the operand is a label (\ref kOpLabel). - ASMJIT_INLINE bool isLabel() const noexcept { return getOp() == kOpLabel; } - - //! Get if the operand is a physical register. - ASMJIT_INLINE bool isPhysReg() const noexcept { return isReg() && _reg.id < Globals::kInvalidRegId; } - //! Get if the operand is a virtual register. - ASMJIT_INLINE bool isVirtReg() const noexcept { return isReg() && isPackedId(_reg.id); } - - //! Get if the operand specifies a size (i.e. the size is not zero). - ASMJIT_INLINE bool hasSize() const noexcept { return _hasSignatureData(kSignatureSizeMask); } - //! Get if the size of the operand matches `size`. - ASMJIT_INLINE bool hasSize(uint32_t size) const noexcept { return getSize() == size; } - - //! Get size of the operand (in bytes). - //! - //! The value returned depends on the operand type: - //! * None - Should always return zero size. - //! * Reg - Should always return the size of the register. If the register - //! size depends on architecture (like \ref X86CReg and \ref X86DReg) - //! the size returned should be the greatest possible (so it should - //! return 64-bit size in such case). - //! * Mem - Size is optional and will be in most cases zero. - //! * Imm - Should always return zero size. - //! * Label - Should always return zero size. - ASMJIT_INLINE uint32_t getSize() const noexcept { return _getSignatureData(kSignatureSizeBits, kSignatureSizeShift); } - - //! Get the operand id. - //! - //! The value returned should be interpreted accordingly to the operand type: - //! * None - Should be `0`. - //! * Reg - Physical or virtual register id. - //! * Mem - Multiple meanings - BASE address (register or label id), or - //! high value of a 64-bit absolute address. - //! * Imm - Should be `0`. - //! * Label - Label id if it was created by using `newLabel()` or `0` - //! if the label is invalid or uninitialized. - ASMJIT_INLINE uint32_t getId() const noexcept { return _any.id; } - - //! Get if the operand is 100% equal to `other`. - ASMJIT_INLINE bool isEqual(const Operand_& other) const noexcept { - return (_packed[0] == other._packed[0]) & - (_packed[1] == other._packed[1]) ; - } - - //! Get if the operand is a register matching `rType`. - ASMJIT_INLINE bool isReg(uint32_t rType) const noexcept { - const uint32_t kMsk = (kSignatureOpBits << kSignatureOpShift) | (kSignatureRegTypeBits << kSignatureRegTypeShift); - const uint32_t kSgn = (kOpReg << kSignatureOpShift) | (rType << kSignatureRegTypeShift); - return (_signature & kMsk) == kSgn; - } - - //! Get whether the operand is register and of `type` and `id`. - ASMJIT_INLINE bool isReg(uint32_t rType, uint32_t rId) const noexcept { - return isReg(rType) && getId() == rId; - } - - //! Get whether the operand is a register or memory. - ASMJIT_INLINE bool isRegOrMem() const noexcept { - ASMJIT_ASSERT(kOpMem - kOpReg == 1); - return Utils::inInterval(getOp(), kOpReg, kOpMem); - } - - //! Cast this operand to `T` type. - template - ASMJIT_INLINE T& as() noexcept { return static_cast(*this); } - //! Cast this operand to `T` type (const). - template - ASMJIT_INLINE const T& as() const noexcept { return static_cast(*this); } - - // -------------------------------------------------------------------------- - // [Reset] - // -------------------------------------------------------------------------- - - //! Reset the `Operand` to none. - //! - //! None operand is defined the following way: - //! - Its signature is zero (kOpNone, and the rest zero as well). - //! - Its id is `0`. - //! - The reserved8_4 field is set to `0`. - //! - The reserved12_4 field is set to zero. - //! - //! In other words, reset operands have all members set to zero. Reset operand - //! must match the Operand state right after its construction. Alternatively, - //! if you have an array of operands, you can simply use `memset()`. - //! - //! ``` - //! using namespace asmjit; - //! - //! Operand a; - //! Operand b; - //! assert(a == b); - //! - //! b = x86::eax; - //! assert(a != b); - //! - //! b.reset(); - //! assert(a == b); - //! - //! memset(&b, 0, sizeof(Operand)); - //! assert(a == b); - //! ``` - ASMJIT_INLINE void reset() noexcept { - _init_packed_d0_d1(kOpNone, 0); - _init_packed_d2_d3(0, 0); - } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - template - ASMJIT_INLINE bool operator==(const T& other) const noexcept { return isEqual(other); } - template - ASMJIT_INLINE bool operator!=(const T& other) const noexcept { return !isEqual(other); } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - union { - AnyData _any; //!< Generic data. - RegData _reg; //!< Physical or virtual register data. - MemData _mem; //!< Memory address data. - ImmData _imm; //!< Immediate value data. - LabelData _label; //!< Label data. - - uint32_t _signature; //!< Operand signature (first 32-bits). - UInt64 _packed[2]; //!< Operand packed into two 64-bit integers. - }; -}; - -// ============================================================================ -// [asmjit::Operand] -// ============================================================================ - -//! Operand can contain register, memory location, immediate, or label. -class Operand : public Operand_ { -public: - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create an uninitialized operand. - ASMJIT_INLINE Operand() noexcept { reset(); } - //! Create a reference to `other` operand. - ASMJIT_INLINE Operand(const Operand& other) noexcept { _init(other); } - //! Create a reference to `other` operand. - explicit ASMJIT_INLINE Operand(const Operand_& other) noexcept { _init(other); } - //! Create a completely uninitialized operand (dangerous). - explicit ASMJIT_INLINE Operand(const _NoInit&) noexcept {} - - // -------------------------------------------------------------------------- - // [Clone] - // -------------------------------------------------------------------------- - - //! Clone the `Operand`. - ASMJIT_INLINE Operand clone() const noexcept { return Operand(*this); } - - ASMJIT_INLINE Operand& operator=(const Operand_& other) noexcept { copyFrom(other); return *this; } -}; - -// ============================================================================ -// [asmjit::Label] -// ============================================================================ - -//! Label (jump target or data location). -//! -//! Label represents a location in code typically used as a jump target, but -//! may be also a reference to some data or a static variable. Label has to be -//! explicitly created by CodeEmitter. -//! -//! Example of using labels: -//! -//! ~~~ -//! // Create a CodeEmitter (for example X86Assembler). -//! X86Assembler a; -//! -//! // Create Label instance. -//! Label L1 = a.newLabel(); -//! -//! // ... your code ... -//! -//! // Using label. -//! a.jump(L1); -//! -//! // ... your code ... -//! -//! // Bind label to the current position, see `CodeEmitter::bind()`. -//! a.bind(L1); -//! ~~~ -class Label : public Operand { -public: - //! Type of the Label. - enum Type { - kTypeAnonymous = 0, //!< Anonymous (unnamed) label. - kTypeLocal = 1, //!< Local label (always has parentId). - kTypeGlobal = 2, //!< Global label (never has parentId). - kTypeCount = 3 //!< Number of label types. - }; - - // TODO: Find a better place, find a better name. - enum { - //! Label tag is used as a sub-type, forming a unique signature across all - //! operand types as 0x1 is never associated with any register (reg-type). - //! This means that a memory operand's BASE register can be constructed - //! from virtually any operand (register vs. label) by just assigning its - //! type (reg type or label-tag) and operand id. - kLabelTag = 0x1 - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create new, unassociated label. - ASMJIT_INLINE Label() noexcept : Operand(NoInit) { reset(); } - //! Create a reference to another label. - ASMJIT_INLINE Label(const Label& other) noexcept : Operand(other) {} - - explicit ASMJIT_INLINE Label(uint32_t id) noexcept : Operand(NoInit) { - _init_packed_d0_d1(kOpLabel, id); - _init_packed_d2_d3(0, 0); - } - - explicit ASMJIT_INLINE Label(const _NoInit&) noexcept : Operand(NoInit) {} - - // -------------------------------------------------------------------------- - // [Reset] - // -------------------------------------------------------------------------- - - // TODO: I think that if operand is reset it shouldn't say it's a Label, it - // should be none like all other operands. - ASMJIT_INLINE void reset() noexcept { - _init_packed_d0_d1(kOpLabel, 0); - _init_packed_d2_d3(0, 0); - } - - // -------------------------------------------------------------------------- - // [Label Specific] - // -------------------------------------------------------------------------- - - //! Get if the label was created by CodeEmitter and has an assigned id. - ASMJIT_INLINE bool isValid() const noexcept { return _label.id != 0; } - //! Set label id. - ASMJIT_INLINE void setId(uint32_t id) { _label.id = id; } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE Label& operator=(const Label& other) noexcept { copyFrom(other); return *this; } -}; - -// ============================================================================ -// [asmjit::Reg] -// ============================================================================ - -#define ASMJIT_DEFINE_REG_TRAITS(TRAITS_T, REG_T, TYPE, KIND, SIZE, COUNT, TYPE_ID) \ -template<> \ -struct TRAITS_T < TYPE > { \ - typedef REG_T Reg; \ - \ - enum { \ - kValid = 1, \ - kCount = COUNT, \ - kTypeId = TYPE_ID, \ - \ - kType = TYPE, \ - kKind = KIND, \ - kSize = SIZE, \ - kSignature = (Operand::kOpReg << Operand::kSignatureOpShift ) | \ - (kType << Operand::kSignatureRegTypeShift) | \ - (kKind << Operand::kSignatureRegKindShift) | \ - (kSize << Operand::kSignatureSizeShift ) \ - }; \ -} \ - -#define ASMJIT_DEFINE_ABSTRACT_REG(REG_T, BASE_T) \ -public: \ - /*! Default constructor doesn't setup anything, it's like `Operand()`. */ \ - ASMJIT_INLINE REG_T() ASMJIT_NOEXCEPT \ - : BASE_T() {} \ - \ - /*! Copy the `other` REG_T register operand. */ \ - ASMJIT_INLINE REG_T(const REG_T& other) ASMJIT_NOEXCEPT \ - : BASE_T(other) {} \ - \ - /*! Copy the `other` REG_T register operand having its id set to `rId` */ \ - ASMJIT_INLINE REG_T(const Reg& other, uint32_t rId) ASMJIT_NOEXCEPT \ - : BASE_T(other, rId) {} \ - \ - /*! Create a REG_T register operand based on `signature` and `rId`. */ \ - ASMJIT_INLINE REG_T(const _Init& init, uint32_t signature, uint32_t rId) ASMJIT_NOEXCEPT \ - : BASE_T(init, signature, rId) {} \ - \ - /*! Create a completely uninitialized REG_T register operand (garbage). */ \ - explicit ASMJIT_INLINE REG_T(const _NoInit&) ASMJIT_NOEXCEPT \ - : BASE_T(NoInit) {} \ - \ - /*! Clone the register operand. */ \ - ASMJIT_INLINE REG_T clone() const ASMJIT_NOEXCEPT { return REG_T(*this); } \ - \ - /*! Create a new register from register type and id. */ \ - static ASMJIT_INLINE REG_T fromTypeAndId(uint32_t rType, uint32_t rId) ASMJIT_NOEXCEPT { \ - return REG_T(Init, signatureOf(rType), rId); \ - } \ - \ - /*! Create a new register from signature and id. */ \ - static ASMJIT_INLINE REG_T fromSignature(uint32_t signature, uint32_t rId) ASMJIT_NOEXCEPT { \ - return REG_T(Init, signature, rId); \ - } \ - \ - ASMJIT_INLINE REG_T& operator=(const REG_T& other) ASMJIT_NOEXCEPT { \ - copyFrom(other); return *this; \ - } - -#define ASMJIT_DEFINE_FINAL_REG(REG_T, BASE_T, TRAITS_T) \ - ASMJIT_DEFINE_ABSTRACT_REG(REG_T, BASE_T) \ - \ - /*! Create a REG_T register with `id`. */ \ - explicit ASMJIT_INLINE REG_T(uint32_t rId) ASMJIT_NOEXCEPT \ - : BASE_T(Init, kSignature, rId) {} \ - \ - enum { \ - kThisType = TRAITS_T::kType, \ - kThisKind = TRAITS_T::kKind, \ - kThisSize = TRAITS_T::kSize, \ - kSignature = TRAITS_T::kSignature \ - }; - -//! Structure that contains core register information. -//! -//! This information is compatible with operand's signature (32-bit integer) -//! and `RegInfo` just provides easy way to access it. -struct RegInfo { - ASMJIT_INLINE uint32_t getSignature() const noexcept { - return _signature; - } - - ASMJIT_INLINE uint32_t getOp() const noexcept { - return (_signature >> Operand::kSignatureOpShift) & Operand::kSignatureOpBits; - } - - ASMJIT_INLINE uint32_t getType() const noexcept { - return (_signature >> Operand::kSignatureRegTypeShift) & Operand::kSignatureRegTypeBits; - } - - ASMJIT_INLINE uint32_t getKind() const noexcept { - return (_signature >> Operand::kSignatureRegKindShift) & Operand::kSignatureRegKindBits; - } - - ASMJIT_INLINE uint32_t getSize() const noexcept { - return (_signature >> Operand::kSignatureSizeShift) & Operand::kSignatureSizeBits; - } - - uint32_t _signature; -}; - -//! Physical/Virtual register operand. -class Reg : public Operand { -public: - //! Architecture neutral register types. - //! - //! These must be reused by any platform that contains that types. All GP - //! and VEC registers are also allowed by design to be part of a BASE|INDEX - //! of a memory operand. - ASMJIT_ENUM(RegType) { - kRegNone = 0, //!< No register - unused, invalid, multiple meanings. - // (1 is used as a LabelTag) - kRegGp8Lo = 2, //!< 8-bit low general purpose register (X86). - kRegGp8Hi = 3, //!< 8-bit high general purpose register (X86). - kRegGp16 = 4, //!< 16-bit general purpose register (X86). - kRegGp32 = 5, //!< 32-bit general purpose register (X86|ARM). - kRegGp64 = 6, //!< 64-bit general purpose register (X86|ARM). - kRegVec32 = 7, //!< 32-bit view of a vector register (ARM). - kRegVec64 = 8, //!< 64-bit view of a vector register (ARM). - kRegVec128 = 9, //!< 128-bit view of a vector register (X86|ARM). - kRegVec256 = 10, //!< 256-bit view of a vector register (X86). - kRegVec512 = 11, //!< 512-bit view of a vector register (X86). - kRegVec1024 = 12, //!< 1024-bit view of a vector register (future). - kRegVec2048 = 13, //!< 2048-bit view of a vector register (future). - kRegIP = 14, //!< Universal id of IP/PC register (if separate). - kRegCustom = 15, //!< Start of platform dependent register types (must be honored). - kRegMax = 31 //!< Maximum possible register id of all architectures. - }; - - //! Architecture neutral register kinds. - ASMJIT_ENUM(Kind) { - kKindGp = 0, //!< General purpose register (X86|ARM). - kKindVec = 1, //!< Vector register (X86|ARM). - kKindMax = 15 //!< Maximum possible register kind of all architectures. - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a dummy register operand. - ASMJIT_INLINE Reg() noexcept : Operand() {} - //! Create a new register operand which is the same as `other` . - ASMJIT_INLINE Reg(const Reg& other) noexcept : Operand(other) {} - //! Create a new register operand compatible with `other`, but with a different `rId`. - ASMJIT_INLINE Reg(const Reg& other, uint32_t rId) noexcept : Operand(NoInit) { - _init_packed_d0_d1(other._signature, rId); - _packed[1] = other._packed[1]; - } - - //! Create a register initialized to `signature` and `rId`. - ASMJIT_INLINE Reg(const _Init&, uint32_t signature, uint32_t rId) noexcept : Operand(NoInit) { - _initReg(signature, rId); - } - explicit ASMJIT_INLINE Reg(const _NoInit&) noexcept : Operand(NoInit) {} - - //! Create a new register based on `signature` and `rId`. - static ASMJIT_INLINE Reg fromSignature(uint32_t signature, uint32_t rId) noexcept { return Reg(Init, signature, rId); } - - // -------------------------------------------------------------------------- - // [Reg Specific] - // -------------------------------------------------------------------------- - - //! Get if the register is valid (either virtual or physical). - ASMJIT_INLINE bool isValid() const noexcept { return _signature != 0; } - //! Get if this is a physical register. - ASMJIT_INLINE bool isPhysReg() const noexcept { return _reg.id < Globals::kInvalidRegId; } - //! Get if this is a virtual register (used by \ref CodeCompiler). - ASMJIT_INLINE bool isVirtReg() const noexcept { return isPackedId(_reg.id); } - - //! Get if this register is the same as `other`. - //! - //! This is just an optimization. Registers by default only use the first - //! 8 bytes of the Operand, so this method takes advantage of this knowledge - //! and only compares these 8 bytes. If both operands were created correctly - //! then `isEqual()` and `isSame()` should give the same answer, however, if - //! some operands contains a garbage or other metadata in the upper 8 bytes - //! then `isSame()` may return `true` in cases where `isEqual()` returns - //! false. However. no such case is known at the moment. - ASMJIT_INLINE bool isSame(const Reg& other) const noexcept { return _packed[0] == other._packed[0]; } - - //! Get if the register type matches `rType` - same as `isReg(rType)`, provided for convenience. - ASMJIT_INLINE bool isType(uint32_t rType) const noexcept { return (_signature & kSignatureRegTypeMask) == (rType << kSignatureRegTypeShift); } - //! Get if the register kind matches `rKind`. - ASMJIT_INLINE bool isKind(uint32_t rKind) const noexcept { return (_signature & kSignatureRegKindMask) == (rKind << kSignatureRegKindShift); } - - //! Get if the register is a general purpose register (any size). - ASMJIT_INLINE bool isGp() const noexcept { return isKind(kKindGp); } - //! Get if the register is a vector register. - ASMJIT_INLINE bool isVec() const noexcept { return isKind(kKindVec); } - - using Operand_::isReg; - - //! Same as `isType()`, provided for convenience. - ASMJIT_INLINE bool isReg(uint32_t rType) const noexcept { return isType(rType); } - //! Get if the register type matches `type` and register id matches `rId`. - ASMJIT_INLINE bool isReg(uint32_t rType, uint32_t rId) const noexcept { return isType(rType) && getId() == rId; } - - //! Get the register type. - ASMJIT_INLINE uint32_t getType() const noexcept { return _getSignatureData(kSignatureRegTypeBits, kSignatureRegTypeShift); } - //! Get the register kind. - ASMJIT_INLINE uint32_t getKind() const noexcept { return _getSignatureData(kSignatureRegKindBits, kSignatureRegKindShift); } - - //! Clone the register operand. - ASMJIT_INLINE Reg clone() const noexcept { return Reg(*this); } - - //! Cast this register to `RegT` by also changing its signature. - //! - //! NOTE: Improper use of `cloneAs()` can lead to hard-to-debug errors. - template - ASMJIT_INLINE RegT cloneAs() const noexcept { return RegT(Init, RegT::kSignature, getId()); } - - //! Cast this register to `other` by also changing its signature. - //! - //! NOTE: Improper use of `cloneAs()` can lead to hard-to-debug errors. - template - ASMJIT_INLINE RegT cloneAs(const RegT& other) const noexcept { return RegT(Init, other.getSignature(), getId()); } - - //! Set the register id to `id`. - ASMJIT_INLINE void setId(uint32_t rId) noexcept { _reg.id = rId; } - - //! Set a 32-bit operand signature based on traits of `RegT`. - template - ASMJIT_INLINE void setSignatureT() noexcept { _signature = RegT::kSignature; } - - //! Set register's `signature` and `rId`. - ASMJIT_INLINE void setSignatureAndId(uint32_t signature, uint32_t rId) noexcept { - _signature = signature; - _reg.id = rId; - } - - // -------------------------------------------------------------------------- - // [Reg Statics] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE bool isGp(const Operand_& op) noexcept { - // Check operand type and register kind. Not interested in register type and size. - const uint32_t kSgn = (kOpReg << kSignatureOpShift ) | - (kKindGp << kSignatureRegKindShift) ; - return (op.getSignature() & (kSignatureOpMask | kSignatureRegKindMask)) == kSgn; - } - - //! Get if the `op` operand is either a low or high 8-bit GPB register. - static ASMJIT_INLINE bool isVec(const Operand_& op) noexcept { - // Check operand type and register kind. Not interested in register type and size. - const uint32_t kSgn = (kOpReg << kSignatureOpShift ) | - (kKindVec << kSignatureRegKindShift) ; - return (op.getSignature() & (kSignatureOpMask | kSignatureRegKindMask)) == kSgn; - } - - static ASMJIT_INLINE bool isGp(const Operand_& op, uint32_t rId) noexcept { return isGp(op) & (op.getId() == rId); } - static ASMJIT_INLINE bool isVec(const Operand_& op, uint32_t rId) noexcept { return isVec(op) & (op.getId() == rId); } -}; - -// ============================================================================ -// [asmjit::RegOnly] -// ============================================================================ - -//! RegOnly is 8-byte version of `Reg` that only allows to store either `Reg` -//! or nothing. This class was designed to decrease the space consumed by each -//! extra "operand" in `CodeEmitter` and `CBInst` classes. -struct RegOnly { - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - //! Initialize the `RegOnly` instance to hold register `signature` and `id`. - ASMJIT_INLINE void init(uint32_t signature, uint32_t id) noexcept { - _signature = signature; - _id = id; - } - - ASMJIT_INLINE void init(const Reg& reg) noexcept { init(reg.getSignature(), reg.getId()); } - ASMJIT_INLINE void init(const RegOnly& reg) noexcept { init(reg.getSignature(), reg.getId()); } - - //! Reset the `RegOnly` to none. - ASMJIT_INLINE void reset() noexcept { init(0, 0); } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get if the `ExtraReg` is none (same as calling `Operand_::isNone()`). - ASMJIT_INLINE bool isNone() const noexcept { return _signature == 0; } - //! Get if the register is valid (either virtual or physical). - ASMJIT_INLINE bool isValid() const noexcept { return _signature != 0; } - - //! Get if this is a physical register. - ASMJIT_INLINE bool isPhysReg() const noexcept { return _id < Globals::kInvalidRegId; } - //! Get if this is a virtual register (used by \ref CodeCompiler). - ASMJIT_INLINE bool isVirtReg() const noexcept { return Operand::isPackedId(_id); } - - //! Get register signature or 0. - ASMJIT_INLINE uint32_t getSignature() const noexcept { return _signature; } - //! Get register id or 0. - ASMJIT_INLINE uint32_t getId() const noexcept { return _id; } - - //! \internal - //! - //! Unpacks information from operand's signature. - ASMJIT_INLINE uint32_t _getSignatureData(uint32_t bits, uint32_t shift) const noexcept { return (_signature >> shift) & bits; } - - //! Get the register type. - ASMJIT_INLINE uint32_t getType() const noexcept { return _getSignatureData(Operand::kSignatureRegTypeBits, Operand::kSignatureRegTypeShift); } - //! Get the register kind. - ASMJIT_INLINE uint32_t getKind() const noexcept { return _getSignatureData(Operand::kSignatureRegKindBits, Operand::kSignatureRegKindShift); } - - // -------------------------------------------------------------------------- - // [ToReg] - // -------------------------------------------------------------------------- - - //! Convert back to `RegT` operand. - template - ASMJIT_INLINE RegT toReg() const noexcept { return RegT(Init, _signature, _id); } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Type of the operand, either `kOpNone` or `kOpReg`. - uint32_t _signature; - //! Physical or virtual register id. - uint32_t _id; -}; - -// ============================================================================ -// [asmjit::Mem] -// ============================================================================ - -//! Base class for all memory operands. -//! -//! NOTE: It's tricky to pack all possible cases that define a memory operand -//! into just 16 bytes. The `Mem` splits data into the following parts: -//! -//! BASE - Base register or label - requires 36 bits total. 4 bits are used -//! to encode the type of the BASE operand (label vs. register type) and -//! the remaining 32 bits define the BASE id, which can be a physical or -//! virtual register index. If BASE type is zero, which is never used as -//! a register-type and label doesn't use it as well then BASE field -//! contains a high DWORD of a possible 64-bit absolute address, which is -//! possible on X64. -//! -//! INDEX - Index register (or theoretically Label, which doesn't make sense). -//! Encoding is similar to BASE - it also requires 36 bits and splits the -//! encoding to INDEX type (4 bits defining the register type) and id (32-bits). -//! -//! OFFSET - A relative offset of the address. Basically if BASE is specified -//! the relative displacement adjusts BASE and an optional INDEX. if BASE is -//! not specified then the OFFSET should be considered as ABSOLUTE address -//! (at least on X86/X64). In that case its low 32 bits are stored in -//! DISPLACEMENT field and the remaining high 32 bits are stored in BASE. -//! -//! OTHER FIELDS - There is rest 8 bits that can be used for whatever purpose. -//! The X86Mem operand uses these bits to store segment override -//! prefix and index shift (scale). -class Mem : public Operand { -public: - enum AddrType { - kAddrTypeDefault = 0, - kAddrTypeAbs = 1, - kAddrTypeRel = 2, - kAddrTypeWrt = 3 - }; - - // Shortcuts. - enum SignatureMem { - kSignatureMemAbs = kAddrTypeAbs << kSignatureMemAddrTypeShift, - kSignatureMemRel = kAddrTypeRel << kSignatureMemAddrTypeShift, - kSignatureMemWrt = kAddrTypeWrt << kSignatureMemAddrTypeShift - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Construct a default `Mem` operand, that points to [0]. - ASMJIT_INLINE Mem() noexcept : Operand(NoInit) { reset(); } - ASMJIT_INLINE Mem(const Mem& other) noexcept : Operand(other) {} - - ASMJIT_INLINE Mem(const _Init&, - uint32_t baseType, uint32_t baseId, - uint32_t indexType, uint32_t indexId, - int32_t off, uint32_t size, uint32_t flags) noexcept : Operand(NoInit) { - - uint32_t signature = (baseType << kSignatureMemBaseTypeShift ) | - (indexType << kSignatureMemIndexTypeShift) | - (size << kSignatureSizeShift ) ; - - _init_packed_d0_d1(kOpMem | signature | flags, indexId); - _mem.base = baseId; - _mem.offsetLo32 = static_cast(off); - } - explicit ASMJIT_INLINE Mem(const _NoInit&) noexcept : Operand(NoInit) {} - - // -------------------------------------------------------------------------- - // [Mem Specific] - // -------------------------------------------------------------------------- - - //! Clone `Mem` operand. - ASMJIT_INLINE Mem clone() const noexcept { return Mem(*this); } - - //! Reset the memory operand - after reset the memory points to [0]. - ASMJIT_INLINE void reset() noexcept { - _init_packed_d0_d1(kOpMem, 0); - _init_packed_d2_d3(0, 0); - } - - ASMJIT_INLINE bool hasAddrType() const noexcept { return _hasSignatureData(kSignatureMemAddrTypeMask); } - ASMJIT_INLINE uint32_t getAddrType() const noexcept { return _getSignatureData(kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); } - ASMJIT_INLINE void setAddrType(uint32_t addrType) noexcept { return _setSignatureData(addrType, kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); } - ASMJIT_INLINE void resetAddrType() noexcept { return _clearSignatureData(kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); } - - ASMJIT_INLINE bool isAbs() const noexcept { return getAddrType() == kAddrTypeAbs; } - ASMJIT_INLINE bool isRel() const noexcept { return getAddrType() == kAddrTypeRel; } - ASMJIT_INLINE bool isWrt() const noexcept { return getAddrType() == kAddrTypeWrt; } - - ASMJIT_INLINE void setAbs() noexcept { setAddrType(kAddrTypeAbs); } - ASMJIT_INLINE void setRel() noexcept { setAddrType(kAddrTypeRel); } - ASMJIT_INLINE void setWrt() noexcept { setAddrType(kAddrTypeWrt); } - - ASMJIT_INLINE bool isArgHome() const noexcept { return _hasSignatureData(kSignatureMemArgHomeFlag); } - ASMJIT_INLINE bool isRegHome() const noexcept { return _hasSignatureData(kSignatureMemRegHomeFlag); } - - ASMJIT_INLINE void setArgHome() noexcept { _signature |= kSignatureMemArgHomeFlag; } - ASMJIT_INLINE void setRegHome() noexcept { _signature |= kSignatureMemRegHomeFlag; } - - ASMJIT_INLINE void clearArgHome() noexcept { _signature &= ~kSignatureMemArgHomeFlag; } - ASMJIT_INLINE void clearRegHome() noexcept { _signature &= ~kSignatureMemRegHomeFlag; } - - //! Get if the memory operand has a BASE register or label specified. - ASMJIT_INLINE bool hasBase() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0; } - //! Get if the memory operand has an INDEX register specified. - ASMJIT_INLINE bool hasIndex() const noexcept { return (_signature & kSignatureMemIndexTypeMask) != 0; } - //! Get whether the memory operand has BASE and INDEX register. - ASMJIT_INLINE bool hasBaseOrIndex() const noexcept { return (_signature & kSignatureMemBaseIndexMask) != 0; } - //! Get whether the memory operand has BASE and INDEX register. - ASMJIT_INLINE bool hasBaseAndIndex() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0 && (_signature & kSignatureMemIndexTypeMask) != 0; } - - //! Get if the BASE operand is a register (registers start after `kLabelTag`). - ASMJIT_INLINE bool hasBaseReg() const noexcept { return (_signature & kSignatureMemBaseTypeMask) > (Label::kLabelTag << kSignatureMemBaseTypeShift); } - //! Get if the BASE operand is a label. - ASMJIT_INLINE bool hasBaseLabel() const noexcept { return (_signature & kSignatureMemBaseTypeMask) == (Label::kLabelTag << kSignatureMemBaseTypeShift); } - //! Get if the INDEX operand is a register (registers start after `kLabelTag`). - ASMJIT_INLINE bool hasIndexReg() const noexcept { return (_signature & kSignatureMemIndexTypeMask) > (Label::kLabelTag << kSignatureMemIndexTypeShift); } - - //! Get type of a BASE register (0 if this memory operand doesn't use the BASE register). - //! - //! NOTE: If the returned type is one (a value never associated to a register - //! type) the BASE is not register, but it's a label. One equals to `kLabelTag`. - //! You should always check `hasBaseLabel()` before using `getBaseId()` result. - ASMJIT_INLINE uint32_t getBaseType() const noexcept { return _getSignatureData(kSignatureMemBaseTypeBits, kSignatureMemBaseTypeShift); } - //! Get type of an INDEX register (0 if this memory operand doesn't use the INDEX register). - ASMJIT_INLINE uint32_t getIndexType() const noexcept { return _getSignatureData(kSignatureMemIndexTypeBits, kSignatureMemIndexTypeShift); } - - //! Get both BASE (4:0 bits) and INDEX (9:5 bits) types combined into a single integer. - //! - //! This is used internally for BASE+INDEX validation. - ASMJIT_INLINE uint32_t getBaseIndexType() const noexcept { return _getSignatureData(kSignatureMemBaseIndexBits, kSignatureMemBaseIndexShift); } - - //! Get id of the BASE register or label (if the BASE was specified as label). - ASMJIT_INLINE uint32_t getBaseId() const noexcept { return _mem.base; } - //! Get id of the INDEX register. - ASMJIT_INLINE uint32_t getIndexId() const noexcept { return _mem.index; } - - ASMJIT_INLINE void _setBase(uint32_t rType, uint32_t rId) noexcept { - _setSignatureData(rType, kSignatureMemBaseTypeBits, kSignatureMemBaseTypeShift); - _mem.base = rId; - } - - ASMJIT_INLINE void _setIndex(uint32_t rType, uint32_t rId) noexcept { - _setSignatureData(rType, kSignatureMemIndexTypeBits, kSignatureMemIndexTypeShift); - _mem.index = rId; - } - - ASMJIT_INLINE void setBase(const Reg& base) noexcept { return _setBase(base.getType(), base.getId()); } - ASMJIT_INLINE void setIndex(const Reg& index) noexcept { return _setIndex(index.getType(), index.getId()); } - - //! Reset the memory operand's BASE register / label. - ASMJIT_INLINE void resetBase() noexcept { _setBase(0, 0); } - //! Reset the memory operand's INDEX register. - ASMJIT_INLINE void resetIndex() noexcept { _setIndex(0, 0); } - - //! Set memory operand size. - ASMJIT_INLINE void setSize(uint32_t size) noexcept { - _setSignatureData(size, kSignatureSizeBits, kSignatureSizeShift); - } - - ASMJIT_INLINE bool hasOffset() const noexcept { - int32_t lo = static_cast(_mem.offsetLo32); - int32_t hi = static_cast(_mem.base) & -static_cast(getBaseType() == 0); - return (lo | hi) != 0; - } - - //! Get if the memory operand has 64-bit offset or absolute address. - //! - //! If this is true then `hasBase()` must always report false. - ASMJIT_INLINE bool has64BitOffset() const noexcept { return getBaseType() == 0; } - - //! Get a 64-bit offset or absolute address. - ASMJIT_INLINE int64_t getOffset() const noexcept { - return has64BitOffset() - ? static_cast(_mem.offset64) - : static_cast(static_cast(_mem.offsetLo32)); // Sign-Extend. - } - - //! Get a lower part of a 64-bit offset or absolute address. - ASMJIT_INLINE int32_t getOffsetLo32() const noexcept { return static_cast(_mem.offsetLo32); } - //! Get a higher part of a 64-bit offset or absolute address. - //! - //! NOTE: This function is UNSAFE and returns garbage if `has64BitOffset()` - //! returns false. Never use it blindly without checking it. - ASMJIT_INLINE int32_t getOffsetHi32() const noexcept { return static_cast(_mem.base); } - - //! Set a 64-bit offset or an absolute address to `offset`. - //! - //! NOTE: This functions attempts to set both high and low parts of a 64-bit - //! offset, however, if the operand has a BASE register it will store only the - //! low 32 bits of the offset / address as there is no way to store both BASE - //! and 64-bit offset, and there is currently no architecture that has such - //! capability targeted by AsmJit. - ASMJIT_INLINE void setOffset(int64_t offset) noexcept { - if (has64BitOffset()) - _mem.offset64 = static_cast(offset); - else - _mem.offsetLo32 = static_cast(offset & 0xFFFFFFFF); - } - //! Adjust the offset by a 64-bit `off`. - ASMJIT_INLINE void addOffset(int64_t off) noexcept { - if (has64BitOffset()) - _mem.offset64 += static_cast(off); - else - _mem.offsetLo32 += static_cast(off & 0xFFFFFFFF); - } - //! Reset the memory offset to zero. - ASMJIT_INLINE void resetOffset() noexcept { setOffset(0); } - - //! Set a low 32-bit offset to `off`. - ASMJIT_INLINE void setOffsetLo32(int32_t off) noexcept { - _mem.offsetLo32 = static_cast(off); - } - //! Adjust the offset by `off`. - //! - //! NOTE: This is a fast function that doesn't use the HI 32-bits of a - //! 64-bit offset. Use it only if you know that there is a BASE register - //! and the offset is only 32 bits anyway. - ASMJIT_INLINE void addOffsetLo32(int32_t off) noexcept { - _mem.offsetLo32 += static_cast(off); - } - //! Reset the memory offset to zero. - ASMJIT_INLINE void resetOffsetLo32() noexcept { setOffsetLo32(0); } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE Mem& operator=(const Mem& other) noexcept { copyFrom(other); return *this; } -}; - -// ============================================================================ -// [asmjit::Imm] -// ============================================================================ - -//! Immediate operand. -//! -//! Immediate operand is usually part of instruction itself. It's inlined after -//! or before the instruction opcode. Immediates can be only signed or unsigned -//! integers. -//! -//! To create immediate operand use `imm()` or `imm_u()` non-members or `Imm` -//! constructors. -class Imm : public Operand { -public: - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new immediate value (initial value is 0). - Imm() noexcept : Operand(NoInit) { - _init_packed_d0_d1(kOpImm, 0); - _imm.value.i64 = 0; - } - - //! Create a new signed immediate value, assigning the value to `val`. - explicit Imm(int64_t val) noexcept : Operand(NoInit) { - _init_packed_d0_d1(kOpImm, 0); - _imm.value.i64 = val; - } - - //! Create a new immediate value from `other`. - ASMJIT_INLINE Imm(const Imm& other) noexcept : Operand(other) {} - - explicit ASMJIT_INLINE Imm(const _NoInit&) noexcept : Operand(NoInit) {} - - // -------------------------------------------------------------------------- - // [Immediate Specific] - // -------------------------------------------------------------------------- - - //! Clone `Imm` operand. - ASMJIT_INLINE Imm clone() const noexcept { return Imm(*this); } - - //! Get whether the immediate can be casted to 8-bit signed integer. - ASMJIT_INLINE bool isInt8() const noexcept { return Utils::isInt8(_imm.value.i64); } - //! Get whether the immediate can be casted to 8-bit unsigned integer. - ASMJIT_INLINE bool isUInt8() const noexcept { return Utils::isUInt8(_imm.value.i64); } - - //! Get whether the immediate can be casted to 16-bit signed integer. - ASMJIT_INLINE bool isInt16() const noexcept { return Utils::isInt16(_imm.value.i64); } - //! Get whether the immediate can be casted to 16-bit unsigned integer. - ASMJIT_INLINE bool isUInt16() const noexcept { return Utils::isUInt16(_imm.value.i64); } - - //! Get whether the immediate can be casted to 32-bit signed integer. - ASMJIT_INLINE bool isInt32() const noexcept { return Utils::isInt32(_imm.value.i64); } - //! Get whether the immediate can be casted to 32-bit unsigned integer. - ASMJIT_INLINE bool isUInt32() const noexcept { return Utils::isUInt32(_imm.value.i64); } - - //! Get immediate value as 8-bit signed integer. - ASMJIT_INLINE int8_t getInt8() const noexcept { return static_cast(_imm.value.i32Lo & 0xFF); } - //! Get immediate value as 8-bit unsigned integer. - ASMJIT_INLINE uint8_t getUInt8() const noexcept { return static_cast(_imm.value.u32Lo & 0xFFU); } - //! Get immediate value as 16-bit signed integer. - ASMJIT_INLINE int16_t getInt16() const noexcept { return static_cast(_imm.value.i32Lo & 0xFFFF);} - //! Get immediate value as 16-bit unsigned integer. - ASMJIT_INLINE uint16_t getUInt16() const noexcept { return static_cast(_imm.value.u32Lo & 0xFFFFU);} - - //! Get immediate value as 32-bit signed integer. - ASMJIT_INLINE int32_t getInt32() const noexcept { return _imm.value.i32Lo; } - //! Get low 32-bit signed integer. - ASMJIT_INLINE int32_t getInt32Lo() const noexcept { return _imm.value.i32Lo; } - //! Get high 32-bit signed integer. - ASMJIT_INLINE int32_t getInt32Hi() const noexcept { return _imm.value.i32Hi; } - - //! Get immediate value as 32-bit unsigned integer. - ASMJIT_INLINE uint32_t getUInt32() const noexcept { return _imm.value.u32Lo; } - //! Get low 32-bit signed integer. - ASMJIT_INLINE uint32_t getUInt32Lo() const noexcept { return _imm.value.u32Lo; } - //! Get high 32-bit signed integer. - ASMJIT_INLINE uint32_t getUInt32Hi() const noexcept { return _imm.value.u32Hi; } - - //! Get immediate value as 64-bit signed integer. - ASMJIT_INLINE int64_t getInt64() const noexcept { return _imm.value.i64; } - //! Get immediate value as 64-bit unsigned integer. - ASMJIT_INLINE uint64_t getUInt64() const noexcept { return _imm.value.u64; } - - //! Get immediate value as `intptr_t`. - ASMJIT_INLINE intptr_t getIntPtr() const noexcept { - if (sizeof(intptr_t) == sizeof(int64_t)) - return static_cast(getInt64()); - else - return static_cast(getInt32()); - } - - //! Get immediate value as `uintptr_t`. - ASMJIT_INLINE uintptr_t getUIntPtr() const noexcept { - if (sizeof(uintptr_t) == sizeof(uint64_t)) - return static_cast(getUInt64()); - else - return static_cast(getUInt32()); - } - - //! Set immediate value to 8-bit signed integer `val`. - ASMJIT_INLINE void setInt8(int8_t val) noexcept { _imm.value.i64 = static_cast(val); } - //! Set immediate value to 8-bit unsigned integer `val`. - ASMJIT_INLINE void setUInt8(uint8_t val) noexcept { _imm.value.u64 = static_cast(val); } - - //! Set immediate value to 16-bit signed integer `val`. - ASMJIT_INLINE void setInt16(int16_t val) noexcept { _imm.value.i64 = static_cast(val); } - //! Set immediate value to 16-bit unsigned integer `val`. - ASMJIT_INLINE void setUInt16(uint16_t val) noexcept { _imm.value.u64 = static_cast(val); } - - //! Set immediate value to 32-bit signed integer `val`. - ASMJIT_INLINE void setInt32(int32_t val) noexcept { _imm.value.i64 = static_cast(val); } - //! Set immediate value to 32-bit unsigned integer `val`. - ASMJIT_INLINE void setUInt32(uint32_t val) noexcept { _imm.value.u64 = static_cast(val); } - - //! Set immediate value to 64-bit signed integer `val`. - ASMJIT_INLINE void setInt64(int64_t val) noexcept { _imm.value.i64 = val; } - //! Set immediate value to 64-bit unsigned integer `val`. - ASMJIT_INLINE void setUInt64(uint64_t val) noexcept { _imm.value.u64 = val; } - //! Set immediate value to intptr_t `val`. - ASMJIT_INLINE void setIntPtr(intptr_t val) noexcept { _imm.value.i64 = static_cast(val); } - //! Set immediate value to uintptr_t `val`. - ASMJIT_INLINE void setUIntPtr(uintptr_t val) noexcept { _imm.value.u64 = static_cast(val); } - - //! Set immediate value as unsigned type to `val`. - ASMJIT_INLINE void setPtr(void* p) noexcept { setIntPtr((uint64_t)p); } - //! Set immediate value to `val`. - template - ASMJIT_INLINE void setValue(T val) noexcept { setIntPtr((int64_t)val); } - - // -------------------------------------------------------------------------- - // [Float] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void setFloat(float f) noexcept { - _imm.value.f32Lo = f; - _imm.value.u32Hi = 0; - } - - ASMJIT_INLINE void setDouble(double d) noexcept { - _imm.value.f64 = d; - } - - // -------------------------------------------------------------------------- - // [Truncate] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void truncateTo8Bits() noexcept { - if (ASMJIT_ARCH_64BIT) { - _imm.value.u64 &= static_cast(0x000000FFU); - } - else { - _imm.value.u32Lo &= 0x000000FFU; - _imm.value.u32Hi = 0; - } - } - - ASMJIT_INLINE void truncateTo16Bits() noexcept { - if (ASMJIT_ARCH_64BIT) { - _imm.value.u64 &= static_cast(0x0000FFFFU); - } - else { - _imm.value.u32Lo &= 0x0000FFFFU; - _imm.value.u32Hi = 0; - } - } - - ASMJIT_INLINE void truncateTo32Bits() noexcept { _imm.value.u32Hi = 0; } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - //! Assign `other` to the immediate operand. - ASMJIT_INLINE Imm& operator=(const Imm& other) noexcept { copyFrom(other); return *this; } -}; - -//! Create a signed immediate operand. -static ASMJIT_INLINE Imm imm(int64_t val) noexcept { return Imm(val); } -//! Create an unsigned immediate operand. -static ASMJIT_INLINE Imm imm_u(uint64_t val) noexcept { return Imm(static_cast(val)); } -//! Create an immediate operand from `p`. -template -static ASMJIT_INLINE Imm imm_ptr(T p) noexcept { return Imm(static_cast((intptr_t)p)); } - -// ============================================================================ -// [asmjit::TypeId] -// ============================================================================ - -//! Type-id. -//! -//! This is an additional information that can be used to describe a physical -//! or virtual register. it's used mostly by CodeCompiler to describe register -//! representation (the kind of data stored in the register and the width used) -//! and it's also used by APIs that allow to describe and work with function -//! signatures. -struct TypeId { - // -------------------------------------------------------------------------- - // [Id] - // -------------------------------------------------------------------------- - - enum Id { - kVoid = 0, - - _kIntStart = 32, - _kIntEnd = 41, - - kIntPtr = 32, - kUIntPtr = 33, - - kI8 = 34, - kU8 = 35, - kI16 = 36, - kU16 = 37, - kI32 = 38, - kU32 = 39, - kI64 = 40, - kU64 = 41, - - _kFloatStart = 42, - _kFloatEnd = 44, - - kF32 = 42, - kF64 = 43, - kF80 = 44, - - _kMaskStart = 45, - _kMaskEnd = 48, - - kMask8 = 45, - kMask16 = 46, - kMask32 = 47, - kMask64 = 48, - - _kMmxStart = 49, - _kMmxEnd = 50, - - kMmx32 = 49, - kMmx64 = 50, - - _kVec32Start = 51, - _kVec32End = 60, - - kI8x4 = 51, - kU8x4 = 52, - kI16x2 = 53, - kU16x2 = 54, - kI32x1 = 55, - kU32x1 = 56, - kF32x1 = 59, - - _kVec64Start = 61, - _kVec64End = 70, - - kI8x8 = 61, - kU8x8 = 62, - kI16x4 = 63, - kU16x4 = 64, - kI32x2 = 65, - kU32x2 = 66, - kI64x1 = 67, - kU64x1 = 68, - kF32x2 = 69, - kF64x1 = 70, - - _kVec128Start = 71, - _kVec128End = 80, - - kI8x16 = 71, - kU8x16 = 72, - kI16x8 = 73, - kU16x8 = 74, - kI32x4 = 75, - kU32x4 = 76, - kI64x2 = 77, - kU64x2 = 78, - kF32x4 = 79, - kF64x2 = 80, - - _kVec256Start = 81, - _kVec256End = 90, - - kI8x32 = 81, - kU8x32 = 82, - kI16x16 = 83, - kU16x16 = 84, - kI32x8 = 85, - kU32x8 = 86, - kI64x4 = 87, - kU64x4 = 88, - kF32x8 = 89, - kF64x4 = 90, - - _kVec512Start = 91, - _kVec512End = 100, - - kI8x64 = 91, - kU8x64 = 92, - kI16x32 = 93, - kU16x32 = 94, - kI32x16 = 95, - kU32x16 = 96, - kI64x8 = 97, - kU64x8 = 98, - kF32x16 = 99, - kF64x8 = 100, - - kCount = 101 - }; - - // -------------------------------------------------------------------------- - // [TypeName - Used by Templates] - // -------------------------------------------------------------------------- - - struct Int8 {}; //!< int8_t as C++ type-name. - struct UInt8 {}; //!< uint8_t as C++ type-name. - struct Int16 {}; //!< int16_t as C++ type-name. - struct UInt16 {}; //!< uint16_t as C++ type-name. - struct Int32 {}; //!< int32_t as C++ type-name. - struct UInt32 {}; //!< uint32_t as C++ type-name. - struct Int64 {}; //!< int64_t as C++ type-name. - struct UInt64 {}; //!< uint64_t as C++ type-name. - struct IntPtr {}; //!< intptr_t as C++ type-name. - struct UIntPtr {}; //!< uintptr_t as C++ type-name. - struct Float {}; //!< float as C++ type-name. - struct Double {}; //!< double as C++ type-name. - struct MmxReg {}; //!< MMX register as C++ type-name. - struct Vec128 {}; //!< SIMD128/XMM register as C++ type-name. - struct Vec256 {}; //!< SIMD256/YMM register as C++ type-name. - struct Vec512 {}; //!< SIMD512/ZMM register as C++ type-name. - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - struct Info { - uint8_t sizeOf[128]; - uint8_t elementOf[128]; - }; - - ASMJIT_API static const Info _info; - - static ASMJIT_INLINE bool isVoid(uint32_t typeId) noexcept { return typeId == 0; } - static ASMJIT_INLINE bool isValid(uint32_t typeId) noexcept { return typeId >= _kIntStart && typeId <= _kVec512End; } - static ASMJIT_INLINE bool isAbstract(uint32_t typeId) noexcept { return typeId >= kIntPtr && typeId <= kUIntPtr; } - static ASMJIT_INLINE bool isInt(uint32_t typeId) noexcept { return typeId >= _kIntStart && typeId <= _kIntEnd; } - static ASMJIT_INLINE bool isGpb(uint32_t typeId) noexcept { return typeId >= kI8 && typeId <= kU8; } - static ASMJIT_INLINE bool isGpw(uint32_t typeId) noexcept { return typeId >= kI16 && typeId <= kU16; } - static ASMJIT_INLINE bool isGpd(uint32_t typeId) noexcept { return typeId >= kI32 && typeId <= kU32; } - static ASMJIT_INLINE bool isGpq(uint32_t typeId) noexcept { return typeId >= kI64 && typeId <= kU64; } - static ASMJIT_INLINE bool isFloat(uint32_t typeId) noexcept { return typeId >= _kFloatStart && typeId <= _kFloatEnd; } - static ASMJIT_INLINE bool isMask(uint32_t typeId) noexcept { return typeId >= _kMaskStart && typeId <= _kMaskEnd; } - static ASMJIT_INLINE bool isMmx(uint32_t typeId) noexcept { return typeId >= _kMmxStart && typeId <= _kMmxEnd; } - - static ASMJIT_INLINE bool isVec(uint32_t typeId) noexcept { return typeId >= _kVec32Start && typeId <= _kVec512End; } - static ASMJIT_INLINE bool isVec32(uint32_t typeId) noexcept { return typeId >= _kVec32Start && typeId <= _kVec32End; } - static ASMJIT_INLINE bool isVec64(uint32_t typeId) noexcept { return typeId >= _kVec64Start && typeId <= _kVec64End; } - static ASMJIT_INLINE bool isVec128(uint32_t typeId) noexcept { return typeId >= _kVec128Start && typeId <= _kVec128End; } - static ASMJIT_INLINE bool isVec256(uint32_t typeId) noexcept { return typeId >= _kVec256Start && typeId <= _kVec256End; } - static ASMJIT_INLINE bool isVec512(uint32_t typeId) noexcept { return typeId >= _kVec512Start && typeId <= _kVec512End; } - - static ASMJIT_INLINE uint32_t sizeOf(uint32_t typeId) noexcept { - ASMJIT_ASSERT(typeId < ASMJIT_ARRAY_SIZE(_info.sizeOf)); - return _info.sizeOf[typeId]; - } - - static ASMJIT_INLINE uint32_t elementOf(uint32_t typeId) noexcept { - ASMJIT_ASSERT(typeId < ASMJIT_ARRAY_SIZE(_info.elementOf)); - return _info.elementOf[typeId]; - } - - //! Get an offset to convert a `kIntPtr` and `kUIntPtr` TypeId into a - //! type that matches `gpSize` (general-purpose register size). If you - //! find such TypeId it's then only about adding the offset to it. - //! - //! For example: - //! ~~~ - //! uint32_t gpSize = '4' or '8'; - //! uint32_t deabstractDelta = TypeId::deabstractDeltaOfSize(gpSize); - //! - //! uint32_t typeId = 'some type-id'; - //! - //! // Normalize some typeId into a non-abstract typeId. - //! if (TypeId::isAbstract(typeId)) typeId += deabstractDelta; - //! - //! // The same, but by using TypeId::deabstract() function. - //! typeId = TypeId::deabstract(typeId, deabstractDelta); - //! ~~~ - static ASMJIT_INLINE uint32_t deabstractDeltaOfSize(uint32_t gpSize) noexcept { - return gpSize >= 8 ? kI64 - kIntPtr : kI32 - kIntPtr; - } - - static ASMJIT_INLINE uint32_t deabstract(uint32_t typeId, uint32_t deabstractDelta) noexcept { - return TypeId::isAbstract(typeId) ? typeId += deabstractDelta : typeId; - } -}; - -//! TypeIdOf<> template allows to get a TypeId of a C++ type. -template struct TypeIdOf { - // Don't provide anything if not specialized. -}; -template struct TypeIdOf { - enum { kTypeId = TypeId::kUIntPtr }; -}; - -template -struct TypeIdOfInt { - enum { - kSignatureed = int(~static_cast(0) < static_cast(0)), - kTypeId = (sizeof(T) == 1) ? (int)(kSignatureed ? TypeId::kI8 : TypeId::kU8 ) : - (sizeof(T) == 2) ? (int)(kSignatureed ? TypeId::kI16 : TypeId::kU16) : - (sizeof(T) == 4) ? (int)(kSignatureed ? TypeId::kI32 : TypeId::kU32) : - (sizeof(T) == 8) ? (int)(kSignatureed ? TypeId::kI64 : TypeId::kU64) : (int)TypeId::kVoid - }; -}; - -#define ASMJIT_DEFINE_TYPE_ID(T, TYPE_ID) \ - template<> \ - struct TypeIdOf { enum { kTypeId = TYPE_ID}; } - -ASMJIT_DEFINE_TYPE_ID(signed char , TypeIdOfInt< signed char >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned char , TypeIdOfInt< unsigned char >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(short , TypeIdOfInt< short >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned short , TypeIdOfInt< unsigned short >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(int , TypeIdOfInt< int >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned int , TypeIdOfInt< unsigned int >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(long , TypeIdOfInt< long >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned long , TypeIdOfInt< unsigned long >::kTypeId); -#if ASMJIT_CC_MSC && !ASMJIT_CC_MSC_GE(16, 0, 0) -ASMJIT_DEFINE_TYPE_ID(__int64 , TypeIdOfInt< __int64 >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned __int64 , TypeIdOfInt< unsigned __int64 >::kTypeId); -#else -ASMJIT_DEFINE_TYPE_ID(long long , TypeIdOfInt< long long >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned long long, TypeIdOfInt< unsigned long long >::kTypeId); -#endif -ASMJIT_DEFINE_TYPE_ID(bool , TypeIdOfInt< bool >::kTypeId); -#if ASMJIT_CC_HAS_NATIVE_CHAR -ASMJIT_DEFINE_TYPE_ID(char , TypeIdOfInt< char >::kTypeId); -#endif -#if ASMJIT_CC_HAS_NATIVE_CHAR16_T -ASMJIT_DEFINE_TYPE_ID(char16_t , TypeIdOfInt< char16_t >::kTypeId); -#endif -#if ASMJIT_CC_HAS_NATIVE_CHAR32_T -ASMJIT_DEFINE_TYPE_ID(char32_t , TypeIdOfInt< char32_t >::kTypeId); -#endif -#if ASMJIT_CC_HAS_NATIVE_WCHAR_T -ASMJIT_DEFINE_TYPE_ID(wchar_t , TypeIdOfInt< wchar_t >::kTypeId); -#endif - -ASMJIT_DEFINE_TYPE_ID(void , TypeId::kVoid); -ASMJIT_DEFINE_TYPE_ID(float , TypeId::kF32); -ASMJIT_DEFINE_TYPE_ID(double , TypeId::kF64); - -ASMJIT_DEFINE_TYPE_ID(TypeId::Int8 , TypeId::kI8); -ASMJIT_DEFINE_TYPE_ID(TypeId::UInt8 , TypeId::kU8); -ASMJIT_DEFINE_TYPE_ID(TypeId::Int16 , TypeId::kI16); -ASMJIT_DEFINE_TYPE_ID(TypeId::UInt16 , TypeId::kU16); -ASMJIT_DEFINE_TYPE_ID(TypeId::Int32 , TypeId::kI32); -ASMJIT_DEFINE_TYPE_ID(TypeId::UInt32 , TypeId::kU32); -ASMJIT_DEFINE_TYPE_ID(TypeId::Int64 , TypeId::kI64); -ASMJIT_DEFINE_TYPE_ID(TypeId::UInt64 , TypeId::kU64); -ASMJIT_DEFINE_TYPE_ID(TypeId::IntPtr , TypeId::kIntPtr); -ASMJIT_DEFINE_TYPE_ID(TypeId::UIntPtr , TypeId::kUIntPtr); -ASMJIT_DEFINE_TYPE_ID(TypeId::Float , TypeId::kF32); -ASMJIT_DEFINE_TYPE_ID(TypeId::Double , TypeId::kF64); -ASMJIT_DEFINE_TYPE_ID(TypeId::MmxReg , TypeId::kMmx64); -ASMJIT_DEFINE_TYPE_ID(TypeId::Vec128 , TypeId::kI32x4); -ASMJIT_DEFINE_TYPE_ID(TypeId::Vec256 , TypeId::kI32x8); -ASMJIT_DEFINE_TYPE_ID(TypeId::Vec512 , TypeId::kI32x16); - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_OPERAND_H diff --git a/libs/asmjit/base/osutils.cpp b/libs/asmjit/base/osutils.cpp deleted file mode 100644 index 08ddd7df..00000000 --- a/libs/asmjit/base/osutils.cpp +++ /dev/null @@ -1,228 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/osutils.h" -#include "../base/utils.h" - -#if ASMJIT_OS_POSIX -# include -# include -# include -# include -#endif // ASMJIT_OS_POSIX - -#if ASMJIT_OS_MAC -# include -#endif // ASMJIT_OS_MAC - -#if ASMJIT_OS_WINDOWS -# if defined(_MSC_VER) && _MSC_VER >= 1400 -# include -# else -# define _InterlockedCompareExchange InterlockedCompareExchange -# endif // _MSC_VER -#endif // ASMJIT_OS_WINDOWS - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::OSUtils - Virtual Memory] -// ============================================================================ - -// Windows specific implementation using `VirtualAllocEx` and `VirtualFree`. -#if ASMJIT_OS_WINDOWS -static ASMJIT_NOINLINE const VMemInfo& OSUtils_GetVMemInfo() noexcept { - static VMemInfo vmi; - - if (ASMJIT_UNLIKELY(!vmi.hCurrentProcess)) { - SYSTEM_INFO info; - ::GetSystemInfo(&info); - - vmi.pageSize = Utils::alignToPowerOf2(info.dwPageSize); - vmi.pageGranularity = info.dwAllocationGranularity; - vmi.hCurrentProcess = ::GetCurrentProcess(); - } - - return vmi; -}; - -VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); } - -void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept { - return allocProcessMemory(static_cast(0), size, allocated, flags); -} - -Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept { - return releaseProcessMemory(static_cast(0), p, size); -} - -void* OSUtils::allocProcessMemory(HANDLE hProcess, size_t size, size_t* allocated, uint32_t flags) noexcept { - if (size == 0) - return nullptr; - - const VMemInfo& vmi = OSUtils_GetVMemInfo(); - if (!hProcess) hProcess = vmi.hCurrentProcess; - - // VirtualAllocEx rounds the allocated size to a page size automatically, - // but we need the `alignedSize` so we can store the real allocated size - // into `allocated` output. - size_t alignedSize = Utils::alignTo(size, vmi.pageSize); - - // Windows XP SP2 / Vista+ allow data-execution-prevention (DEP). - DWORD protectFlags = 0; - - if (flags & kVMExecutable) - protectFlags |= (flags & kVMWritable) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; - else - protectFlags |= (flags & kVMWritable) ? PAGE_READWRITE : PAGE_READONLY; - - LPVOID mBase = ::VirtualAllocEx(hProcess, nullptr, alignedSize, MEM_COMMIT | MEM_RESERVE, protectFlags); - if (ASMJIT_UNLIKELY(!mBase)) return nullptr; - - ASMJIT_ASSERT(Utils::isAligned(reinterpret_cast(mBase), vmi.pageSize)); - if (allocated) *allocated = alignedSize; - return mBase; -} - -Error OSUtils::releaseProcessMemory(HANDLE hProcess, void* p, size_t size) noexcept { - const VMemInfo& vmi = OSUtils_GetVMemInfo(); - if (!hProcess) hProcess = vmi.hCurrentProcess; - - if (ASMJIT_UNLIKELY(!::VirtualFreeEx(hProcess, p, 0, MEM_RELEASE))) - return DebugUtils::errored(kErrorInvalidState); - - return kErrorOk; -} -#endif // ASMJIT_OS_WINDOWS - -// Posix specific implementation using `mmap()` and `munmap()`. -#if ASMJIT_OS_POSIX - -// Mac uses MAP_ANON instead of MAP_ANONYMOUS. -#if !defined(MAP_ANONYMOUS) -# define MAP_ANONYMOUS MAP_ANON -#endif // MAP_ANONYMOUS - -static const VMemInfo& OSUtils_GetVMemInfo() noexcept { - static VMemInfo vmi; - if (ASMJIT_UNLIKELY(!vmi.pageSize)) { - size_t pageSize = ::getpagesize(); - vmi.pageSize = pageSize; - vmi.pageGranularity = std::max(pageSize, 65536); - } - return vmi; -}; - -VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); } - -void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept { - const VMemInfo& vmi = OSUtils_GetVMemInfo(); - - size_t alignedSize = Utils::alignTo(size, vmi.pageSize); - int protection = PROT_READ; - - if (flags & kVMWritable ) protection |= PROT_WRITE; - if (flags & kVMExecutable) protection |= PROT_EXEC; - - void* mbase = ::mmap(nullptr, alignedSize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (ASMJIT_UNLIKELY(mbase == MAP_FAILED)) return nullptr; - - if (allocated) *allocated = alignedSize; - return mbase; -} - -Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept { - if (ASMJIT_UNLIKELY(::munmap(p, size) != 0)) - return DebugUtils::errored(kErrorInvalidState); - - return kErrorOk; -} -#endif // ASMJIT_OS_POSIX - -// ============================================================================ -// [asmjit::OSUtils - GetTickCount] -// ============================================================================ - -#if ASMJIT_OS_WINDOWS -static ASMJIT_INLINE uint32_t OSUtils_calcHiRes(const LARGE_INTEGER& now, double freq) noexcept { - return static_cast( - (int64_t)(double(now.QuadPart) / freq) & 0xFFFFFFFF); -} - -uint32_t OSUtils::getTickCount() noexcept { - static volatile uint32_t _hiResTicks; - static volatile double _hiResFreq; - - do { - uint32_t hiResOk = _hiResTicks; - LARGE_INTEGER qpf, now; - - // If for whatever reason this fails, bail to `GetTickCount()`. - if (!::QueryPerformanceCounter(&now)) break; - - // Expected - if we ran through this at least once `hiResTicks` will be - // either 1 or 0xFFFFFFFF. If it's '1' then the Hi-Res counter is available - // and `QueryPerformanceCounter()` can be used. - if (hiResOk == 1) return OSUtils_calcHiRes(now, _hiResFreq); - - // Hi-Res counter is not available, bail to `GetTickCount()`. - if (hiResOk != 0) break; - - // Detect availability of Hi-Res counter, if not available, bail to `GetTickCount()`. - if (!::QueryPerformanceFrequency(&qpf)) { - _InterlockedCompareExchange((LONG*)&_hiResTicks, 0xFFFFFFFF, 0); - break; - } - - double freq = double(qpf.QuadPart) / 1000.0; - _hiResFreq = freq; - - _InterlockedCompareExchange((LONG*)&_hiResTicks, 1, 0); - return OSUtils_calcHiRes(now, freq); - } while (0); - - return ::GetTickCount(); -} -#elif ASMJIT_OS_MAC -uint32_t OSUtils::getTickCount() noexcept { - static mach_timebase_info_data_t _machTime; - - // See Apple's QA1398. - if (ASMJIT_UNLIKELY(_machTime.denom == 0) || mach_timebase_info(&_machTime) != KERN_SUCCESS) - return 0; - - // `mach_absolute_time()` returns nanoseconds, we want milliseconds. - uint64_t t = mach_absolute_time() / 1000000; - - t = t * _machTime.numer / _machTime.denom; - return static_cast(t & 0xFFFFFFFFU); -} -#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 -uint32_t OSUtils::getTickCount() noexcept { - struct timespec ts; - - if (ASMJIT_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0)) - return 0; - - uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000); - return static_cast(t & 0xFFFFFFFFU); -} -#else -#error "[asmjit] OSUtils::getTickCount() is not implemented for your target OS." -uint32_t OSUtils::getTickCount() noexcept { return 0; } -#endif - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/osutils.h b/libs/asmjit/base/osutils.h deleted file mode 100644 index ccf6bee2..00000000 --- a/libs/asmjit/base/osutils.h +++ /dev/null @@ -1,178 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_OSUTILS_H -#define _ASMJIT_BASE_OSUTILS_H - -// [Dependencies] -#include "../base/globals.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::VMemInfo] -// ============================================================================ - -//! Information about OS virtual memory. -struct VMemInfo { -#if ASMJIT_OS_WINDOWS - HANDLE hCurrentProcess; //!< Handle of the current process (Windows). -#endif // ASMJIT_OS_WINDOWS - size_t pageSize; //!< Virtual memory page size. - size_t pageGranularity; //!< Virtual memory page granularity. -}; - -// ============================================================================ -// [asmjit::OSUtils] -// ============================================================================ - -//! OS utilities. -//! -//! Virtual Memory -//! -------------- -//! -//! Provides functions to allocate and release virtual memory that is required -//! to execute dynamically generated code. If both processor and host OS support -//! data-execution-prevention (DEP) then the only way to run machine code is to -//! allocate virtual memory that has `OSUtils::kVMExecutable` flag enabled. All -//! functions provides by OSUtils use internally platform specific API. -//! -//! Benchmarking -//! ------------ -//! -//! OSUtils also provide a function `getTickCount()` that can be used for -//! benchmarking purposes. It's similar to Windows-only `GetTickCount()`, but -//! it's cross-platform and tries to be the most reliable platform specific -//! calls to make the result usable. -struct OSUtils { - // -------------------------------------------------------------------------- - // [Virtual Memory] - // -------------------------------------------------------------------------- - - //! Virtual memory flags. - ASMJIT_ENUM(VMFlags) { - kVMWritable = 0x00000001U, //!< Virtual memory is writable. - kVMExecutable = 0x00000002U //!< Virtual memory is executable. - }; - - ASMJIT_API static VMemInfo getVirtualMemoryInfo() noexcept; - - //! Allocate virtual memory. - ASMJIT_API static void* allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept; - //! Release virtual memory previously allocated by \ref allocVirtualMemory(). - ASMJIT_API static Error releaseVirtualMemory(void* p, size_t size) noexcept; - -#if ASMJIT_OS_WINDOWS - //! Allocate virtual memory of `hProcess` (Windows). - ASMJIT_API static void* allocProcessMemory(HANDLE hProcess, size_t size, size_t* allocated, uint32_t flags) noexcept; - - //! Release virtual memory of `hProcess` (Windows). - ASMJIT_API static Error releaseProcessMemory(HANDLE hProcess, void* p, size_t size) noexcept; -#endif // ASMJIT_OS_WINDOWS - - // -------------------------------------------------------------------------- - // [GetTickCount] - // -------------------------------------------------------------------------- - - //! Get the current CPU tick count, used for benchmarking (1ms resolution). - ASMJIT_API static uint32_t getTickCount() noexcept; -}; - -// ============================================================================ -// [asmjit::Lock] -// ============================================================================ - -//! \internal -//! -//! Lock. -struct Lock { - ASMJIT_NONCOPYABLE(Lock) - - // -------------------------------------------------------------------------- - // [Windows] - // -------------------------------------------------------------------------- - -#if ASMJIT_OS_WINDOWS - typedef CRITICAL_SECTION Handle; - - //! Create a new `Lock` instance. - ASMJIT_INLINE Lock() noexcept { InitializeCriticalSection(&_handle); } - //! Destroy the `Lock` instance. - ASMJIT_INLINE ~Lock() noexcept { DeleteCriticalSection(&_handle); } - - //! Lock. - ASMJIT_INLINE void lock() noexcept { EnterCriticalSection(&_handle); } - //! Unlock. - ASMJIT_INLINE void unlock() noexcept { LeaveCriticalSection(&_handle); } -#endif // ASMJIT_OS_WINDOWS - - // -------------------------------------------------------------------------- - // [Posix] - // -------------------------------------------------------------------------- - -#if ASMJIT_OS_POSIX - typedef pthread_mutex_t Handle; - - //! Create a new `Lock` instance. - ASMJIT_INLINE Lock() noexcept { pthread_mutex_init(&_handle, nullptr); } - //! Destroy the `Lock` instance. - ASMJIT_INLINE ~Lock() noexcept { pthread_mutex_destroy(&_handle); } - - //! Lock. - ASMJIT_INLINE void lock() noexcept { pthread_mutex_lock(&_handle); } - //! Unlock. - ASMJIT_INLINE void unlock() noexcept { pthread_mutex_unlock(&_handle); } -#endif // ASMJIT_OS_POSIX - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Native handle. - Handle _handle; -}; - -// ============================================================================ -// [asmjit::AutoLock] -// ============================================================================ - -//! \internal -//! -//! Scoped lock. -struct AutoLock { - ASMJIT_NONCOPYABLE(AutoLock) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE AutoLock(Lock& target) noexcept : _target(target) { _target.lock(); } - ASMJIT_INLINE ~AutoLock() noexcept { _target.unlock(); } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Reference to the `Lock`. - Lock& _target; -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_OSUTILS_H diff --git a/libs/asmjit/base/regalloc.cpp b/libs/asmjit/base/regalloc.cpp deleted file mode 100644 index cbdfd85e..00000000 --- a/libs/asmjit/base/regalloc.cpp +++ /dev/null @@ -1,594 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Guard] -#include "../asmjit_build.h" -#if !defined(ASMJIT_DISABLE_COMPILER) - -// [Dependencies] -#include "../base/regalloc_p.h" -#include "../base/utils.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::RAPass - Construction / Destruction] -// ============================================================================ - -RAPass::RAPass() noexcept : - CBPass("RA"), - _varMapToVaListOffset(0) {} -RAPass::~RAPass() noexcept {} - -// ============================================================================ -// [asmjit::RAPass - Interface] -// ============================================================================ - -Error RAPass::process(Zone* zone) noexcept { - _zone = zone; - _heap.reset(zone); - _emitComments = (cb()->getGlobalOptions() & CodeEmitter::kOptionLoggingEnabled) != 0; - - Error err = kErrorOk; - CBNode* node = cc()->getFirstNode(); - if (!node) return err; - - do { - if (node->getType() == CBNode::kNodeFunc) { - CCFunc* func = static_cast(node); - node = func->getEnd(); - - err = compile(func); - if (err) break; - } - - // Find a function by skipping all nodes that are not `kNodeFunc`. - do { - node = node->getNext(); - } while (node && node->getType() != CBNode::kNodeFunc); - } while (node); - - _heap.reset(nullptr); - _zone = nullptr; - return err; -} - -Error RAPass::compile(CCFunc* func) noexcept { - ASMJIT_PROPAGATE(prepare(func)); - - Error err; - do { - err = fetch(); - if (err) break; - - err = removeUnreachableCode(); - if (err) break; - - err = livenessAnalysis(); - if (err) break; - -#if !defined(ASMJIT_DISABLE_LOGGING) - if (cc()->getGlobalOptions() & CodeEmitter::kOptionLoggingEnabled) { - err = annotate(); - if (err) break; - } -#endif // !ASMJIT_DISABLE_LOGGING - - err = translate(); - } while (false); - - cleanup(); - - // We alter the compiler cursor, because it doesn't make sense to reference - // it after compilation - some nodes may disappear and it's forbidden to add - // new code after the compilation is done. - cc()->_setCursor(nullptr); - return err; -} - -Error RAPass::prepare(CCFunc* func) noexcept { - CBNode* end = func->getEnd(); - - _func = func; - _stop = end->getNext(); - - _unreachableList.reset(); - _returningList.reset(); - _jccList.reset(); - _contextVd.reset(); - - _memVarCells = nullptr; - _memStackCells = nullptr; - - _mem1ByteVarsUsed = 0; - _mem2ByteVarsUsed = 0; - _mem4ByteVarsUsed = 0; - _mem8ByteVarsUsed = 0; - _mem16ByteVarsUsed = 0; - _mem32ByteVarsUsed = 0; - _mem64ByteVarsUsed = 0; - _memStackCellsUsed = 0; - - _memMaxAlign = 0; - _memVarTotal = 0; - _memStackTotal = 0; - _memAllTotal = 0; - _annotationLength = 12; - - return kErrorOk; -} - -void RAPass::cleanup() noexcept { - VirtReg** virtArray = _contextVd.getData(); - size_t virtCount = _contextVd.getLength(); - - for (size_t i = 0; i < virtCount; i++) { - VirtReg* vreg = virtArray[i]; - vreg->_raId = kInvalidValue; - vreg->resetPhysId(); - } - - _contextVd.reset(); -} - -// ============================================================================ -// [asmjit::RAPass - Mem] -// ============================================================================ - -static ASMJIT_INLINE uint32_t RAGetDefaultAlignment(uint32_t size) { - if (size > 32) - return 64; - else if (size > 16) - return 32; - else if (size > 8) - return 16; - else if (size > 4) - return 8; - else if (size > 2) - return 4; - else if (size > 1) - return 2; - else - return 1; -} - -RACell* RAPass::_newVarCell(VirtReg* vreg) { - ASMJIT_ASSERT(vreg->_memCell == nullptr); - - RACell* cell; - uint32_t size = vreg->getSize(); - - if (vreg->isStack()) { - cell = _newStackCell(size, vreg->getAlignment()); - if (ASMJIT_UNLIKELY(!cell)) return nullptr; - } - else { - cell = static_cast(_zone->alloc(sizeof(RACell))); - if (!cell) goto _NoMemory; - - cell->next = _memVarCells; - cell->offset = 0; - cell->size = size; - cell->alignment = size; - - _memVarCells = cell; - _memMaxAlign = std::max(_memMaxAlign, size); - _memVarTotal += size; - - switch (size) { - case 1: _mem1ByteVarsUsed++ ; break; - case 2: _mem2ByteVarsUsed++ ; break; - case 4: _mem4ByteVarsUsed++ ; break; - case 8: _mem8ByteVarsUsed++ ; break; - case 16: _mem16ByteVarsUsed++; break; - case 32: _mem32ByteVarsUsed++; break; - case 64: _mem64ByteVarsUsed++; break; - - default: - ASMJIT_NOT_REACHED(); - } - } - - vreg->_memCell = cell; - return cell; - -_NoMemory: - cc()->setLastError(DebugUtils::errored(kErrorNoHeapMemory)); - return nullptr; -} - -RACell* RAPass::_newStackCell(uint32_t size, uint32_t alignment) { - RACell* cell = static_cast(_zone->alloc(sizeof(RACell))); - if (ASMJIT_UNLIKELY(!cell)) return nullptr; - - if (alignment == 0) - alignment = RAGetDefaultAlignment(size); - - if (alignment > 64) - alignment = 64; - - ASMJIT_ASSERT(Utils::isPowerOf2(alignment)); - size = Utils::alignTo(size, alignment); - - // Insert it sorted according to the alignment and size. - { - RACell** pPrev = &_memStackCells; - RACell* cur = *pPrev; - - while (cur && ((cur->alignment > alignment) || (cur->alignment == alignment && cur->size > size))) { - pPrev = &cur->next; - cur = *pPrev; - } - - cell->next = cur; - cell->offset = 0; - cell->size = size; - cell->alignment = alignment; - - *pPrev = cell; - _memStackCellsUsed++; - - _memMaxAlign = std::max(_memMaxAlign, alignment); - _memStackTotal += size; - } - - return cell; -} - -Error RAPass::resolveCellOffsets() { - RACell* varCell = _memVarCells; - RACell* stackCell = _memStackCells; - - uint32_t pos64 = 0; - uint32_t pos32 = pos64 + _mem64ByteVarsUsed * 64; - uint32_t pos16 = pos32 + _mem32ByteVarsUsed * 32; - uint32_t pos8 = pos16 + _mem16ByteVarsUsed * 16; - uint32_t pos4 = pos8 + _mem8ByteVarsUsed * 8 ; - uint32_t pos2 = pos4 + _mem4ByteVarsUsed * 4 ; - uint32_t pos1 = pos2 + _mem2ByteVarsUsed * 2 ; - - // Assign home slots. - while (varCell) { - uint32_t size = varCell->size; - uint32_t offset = 0; - - switch (size) { - case 1: offset = pos1 ; pos1 += 1 ; break; - case 2: offset = pos2 ; pos2 += 2 ; break; - case 4: offset = pos4 ; pos4 += 4 ; break; - case 8: offset = pos8 ; pos8 += 8 ; break; - case 16: offset = pos16; pos16 += 16; break; - case 32: offset = pos32; pos32 += 32; break; - case 64: offset = pos64; pos64 += 64; break; - - default: - ASMJIT_NOT_REACHED(); - } - - varCell->offset = static_cast(offset); - varCell = varCell->next; - } - - // Assign stack slots. - uint32_t stackPos = pos1 + _mem1ByteVarsUsed; - while (stackCell) { - uint32_t size = stackCell->size; - uint32_t alignment = stackCell->alignment; - ASMJIT_ASSERT(alignment != 0 && Utils::isPowerOf2(alignment)); - - stackPos = Utils::alignTo(stackPos, alignment); - stackCell->offset = stackPos; - stackCell = stackCell->next; - - stackPos += size; - } - - _memAllTotal = stackPos; - return kErrorOk; -} - -// ============================================================================ -// [asmjit::RAPass - RemoveUnreachableCode] -// ============================================================================ - -Error RAPass::removeUnreachableCode() { - ZoneList::Link* link = _unreachableList.getFirst(); - CBNode* stop = getStop(); - - while (link) { - CBNode* node = link->getValue(); - if (node && node->getPrev() && node != stop) { - // Locate all unreachable nodes. - CBNode* first = node; - do { - if (node->hasPassData()) break; - node = node->getNext(); - } while (node != stop); - - // Remove unreachable nodes that are neither informative nor directives. - if (node != first) { - CBNode* end = node; - node = first; - - // NOTE: The strategy is as follows: - // 1. The algorithm removes everything until it finds a first label. - // 2. After the first label is found it removes only removable nodes. - bool removeEverything = true; - do { - CBNode* next = node->getNext(); - bool remove = node->isRemovable(); - - if (!remove) { - if (node->isLabel()) - removeEverything = false; - remove = removeEverything; - } - - if (remove) - cc()->removeNode(node); - - node = next; - } while (node != end); - } - } - - link = link->getNext(); - } - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::RAPass - Liveness Analysis] -// ============================================================================ - -//! \internal -struct LivenessTarget { - LivenessTarget* prev; //!< Previous target. - CBLabel* node; //!< Target node. - CBJump* from; //!< Jumped from. -}; - -Error RAPass::livenessAnalysis() { - uint32_t bLen = static_cast( - ((_contextVd.getLength() + RABits::kEntityBits - 1) / RABits::kEntityBits)); - - // No variables. - if (bLen == 0) - return kErrorOk; - - CCFunc* func = getFunc(); - CBJump* from = nullptr; - - LivenessTarget* ltCur = nullptr; - LivenessTarget* ltUnused = nullptr; - - ZoneList::Link* retPtr = _returningList.getFirst(); - ASMJIT_ASSERT(retPtr != nullptr); - - CBNode* node = retPtr->getValue(); - RAData* wd; - - size_t varMapToVaListOffset = _varMapToVaListOffset; - RABits* bCur = newBits(bLen); - if (ASMJIT_UNLIKELY(!bCur)) goto NoMem; - - // Allocate bits for code visited first time. -Visit: - for (;;) { - wd = node->getPassData(); - if (wd->liveness) { - if (bCur->_addBitsDelSource(wd->liveness, bCur, bLen)) - goto Patch; - else - goto Done; - } - - RABits* bTmp = copyBits(bCur, bLen); - if (!bTmp) goto NoMem; - - wd = node->getPassData(); - wd->liveness = bTmp; - - uint32_t tiedTotal = wd->tiedTotal; - TiedReg* tiedArray = reinterpret_cast(((uint8_t*)wd) + varMapToVaListOffset); - - for (uint32_t i = 0; i < tiedTotal; i++) { - TiedReg* tied = &tiedArray[i]; - VirtReg* vreg = tied->vreg; - - uint32_t flags = tied->flags; - uint32_t raId = vreg->_raId; - - if ((flags & TiedReg::kWAll) && !(flags & TiedReg::kRAll)) { - // Write-Only. - bTmp->setBit(raId); - bCur->delBit(raId); - } - else { - // Read-Only or Read/Write. - bTmp->setBit(raId); - bCur->setBit(raId); - } - } - - if (node->getType() == CBNode::kNodeLabel) - goto Target; - - if (node == func) - goto Done; - - ASMJIT_ASSERT(node->getPrev()); - node = node->getPrev(); - } - - // Patch already generated liveness bits. -Patch: - for (;;) { - ASMJIT_ASSERT(node->hasPassData()); - ASMJIT_ASSERT(node->getPassData()->liveness != nullptr); - - RABits* bNode = node->getPassData()->liveness; - if (!bNode->_addBitsDelSource(bCur, bLen)) goto Done; - if (node->getType() == CBNode::kNodeLabel) goto Target; - - if (node == func) goto Done; - node = node->getPrev(); - } - -Target: - if (static_cast(node)->getNumRefs() != 0) { - // Push a new LivenessTarget onto the stack if needed. - if (!ltCur || ltCur->node != node) { - // Allocate a new LivenessTarget object (from pool or zone). - LivenessTarget* ltTmp = ltUnused; - - if (ltTmp) { - ltUnused = ltUnused->prev; - } - else { - ltTmp = _zone->allocT( - sizeof(LivenessTarget) - sizeof(RABits) + bLen * sizeof(uintptr_t)); - if (!ltTmp) goto NoMem; - } - - // Initialize and make current - ltTmp->from will be set later on. - ltTmp->prev = ltCur; - ltTmp->node = static_cast(node); - ltCur = ltTmp; - - from = static_cast(node)->getFrom(); - ASMJIT_ASSERT(from != nullptr); - } - else { - from = ltCur->from; - goto JumpNext; - } - - // Visit/Patch. - do { - ltCur->from = from; - bCur->copyBits(node->getPassData()->liveness, bLen); - - if (!from->getPassData()->liveness) { - node = from; - goto Visit; - } - - // Issue #25: Moved 'JumpNext' here since it's important to patch - // code again if there are more live variables than before. -JumpNext: - if (bCur->delBits(from->getPassData()->liveness, bLen)) { - node = from; - goto Patch; - } - - from = from->getJumpNext(); - } while (from); - - // Pop the current LivenessTarget from the stack. - { - LivenessTarget* ltTmp = ltCur; - ltCur = ltCur->prev; - ltTmp->prev = ltUnused; - ltUnused = ltTmp; - } - } - - bCur->copyBits(node->getPassData()->liveness, bLen); - node = node->getPrev(); - if (node->isJmp() || !node->hasPassData()) goto Done; - - wd = node->getPassData(); - if (!wd->liveness) goto Visit; - if (bCur->delBits(wd->liveness, bLen)) goto Patch; - -Done: - if (ltCur) { - node = ltCur->node; - from = ltCur->from; - - goto JumpNext; - } - - retPtr = retPtr->getNext(); - if (retPtr) { - node = retPtr->getValue(); - goto Visit; - } - - return kErrorOk; - -NoMem: - return DebugUtils::errored(kErrorNoHeapMemory); -} - -// ============================================================================ -// [asmjit::RAPass - Annotate] -// ============================================================================ - -Error RAPass::formatInlineComment(StringBuilder& dst, CBNode* node) { -#if !defined(ASMJIT_DISABLE_LOGGING) - RAData* wd = node->getPassData(); - - if (node->hasInlineComment()) - dst.appendString(node->getInlineComment()); - - if (wd && wd->liveness) { - if (dst.getLength() < _annotationLength) - dst.appendChars(' ', _annotationLength - dst.getLength()); - - uint32_t vdCount = static_cast(_contextVd.getLength()); - size_t offset = dst.getLength() + 1; - - dst.appendChar('['); - dst.appendChars(' ', vdCount); - dst.appendChar(']'); - RABits* liveness = wd->liveness; - - uint32_t i; - for (i = 0; i < vdCount; i++) { - if (liveness->getBit(i)) - dst.getData()[offset + i] = '.'; - } - - uint32_t tiedTotal = wd->tiedTotal; - TiedReg* tiedArray = reinterpret_cast(((uint8_t*)wd) + _varMapToVaListOffset); - - for (i = 0; i < tiedTotal; i++) { - TiedReg* tied = &tiedArray[i]; - VirtReg* vreg = tied->vreg; - uint32_t flags = tied->flags; - - char c = 'u'; - if ( (flags & TiedReg::kRAll) && !(flags & TiedReg::kWAll)) c = 'r'; - if (!(flags & TiedReg::kRAll) && (flags & TiedReg::kWAll)) c = 'w'; - if ( (flags & TiedReg::kRAll) && (flags & TiedReg::kWAll)) c = 'x'; - // Uppercase if unused. - if ( (flags & TiedReg::kUnuse)) c -= 'a' - 'A'; - - ASMJIT_ASSERT(offset + vreg->_raId < dst.getLength()); - dst._data[offset + vreg->_raId] = c; - } - } -#endif // !ASMJIT_DISABLE_LOGGING - - return kErrorOk; -} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // !ASMJIT_DISABLE_COMPILER diff --git a/libs/asmjit/base/regalloc_p.h b/libs/asmjit/base/regalloc_p.h deleted file mode 100644 index 53c7aebe..00000000 --- a/libs/asmjit/base/regalloc_p.h +++ /dev/null @@ -1,568 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_REGALLOC_P_H -#define _ASMJIT_BASE_REGALLOC_P_H - -#include "../asmjit_build.h" -#if !defined(ASMJIT_DISABLE_COMPILER) - -// [Dependencies] -#include "../base/codecompiler.h" -#include "../base/zone.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::TiedReg] -// ============================================================================ - -//! Tied register (CodeCompiler) -//! -//! Tied register is used to describe one ore more register operands that share -//! the same virtual register. Tied register contains all the data that is -//! essential for register allocation. -struct TiedReg { - //! Flags. - ASMJIT_ENUM(Flags) { - kRReg = 0x00000001U, //!< Register read. - kWReg = 0x00000002U, //!< Register write. - kXReg = 0x00000003U, //!< Register read-write. - - kRMem = 0x00000004U, //!< Memory read. - kWMem = 0x00000008U, //!< Memory write. - kXMem = 0x0000000CU, //!< Memory read-write. - - kRDecide = 0x00000010U, //!< RA can decide between reg/mem read. - kWDecide = 0x00000020U, //!< RA can decide between reg/mem write. - kXDecide = 0x00000030U, //!< RA can decide between reg/mem read-write. - - kRFunc = 0x00000100U, //!< Function argument passed in register. - kWFunc = 0x00000200U, //!< Function return value passed into register. - kXFunc = 0x00000300U, //!< Function argument and return value. - kRCall = 0x00000400U, //!< Function call operand. - - kSpill = 0x00000800U, //!< Variable should be spilled. - kUnuse = 0x00001000U, //!< Variable should be unused at the end of the instruction/node. - - kRAll = kRReg | kRMem | kRDecide | kRFunc | kRCall, //!< All in-flags. - kWAll = kWReg | kWMem | kWDecide | kWFunc, //!< All out-flags. - - kRDone = 0x00400000U, //!< Already allocated on the input. - kWDone = 0x00800000U, //!< Already allocated on the output. - - kX86GpbLo = 0x10000000U, - kX86GpbHi = 0x20000000U, - kX86Fld4 = 0x40000000U, - kX86Fld8 = 0x80000000U - }; - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void init(VirtReg* vreg, uint32_t flags = 0, uint32_t inRegs = 0, uint32_t allocableRegs = 0) noexcept { - this->vreg = vreg; - this->flags = flags; - this->refCount = 0; - this->inPhysId = Globals::kInvalidRegId; - this->outPhysId = Globals::kInvalidRegId; - this->reserved = 0; - this->inRegs = inRegs; - this->allocableRegs = allocableRegs; - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get whether the variable has to be allocated in a specific input register. - ASMJIT_INLINE uint32_t hasInPhysId() const { return inPhysId != Globals::kInvalidRegId; } - //! Get whether the variable has to be allocated in a specific output register. - ASMJIT_INLINE uint32_t hasOutPhysId() const { return outPhysId != Globals::kInvalidRegId; } - - //! Set the input register index. - ASMJIT_INLINE void setInPhysId(uint32_t index) { inPhysId = static_cast(index); } - //! Set the output register index. - ASMJIT_INLINE void setOutPhysId(uint32_t index) { outPhysId = static_cast(index); } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE TiedReg& operator=(const TiedReg& other) { - ::memcpy(this, &other, sizeof(TiedReg)); - return *this; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Pointer to the associated \ref VirtReg. - VirtReg* vreg; - //! Tied flags. - uint32_t flags; - - union { - struct { - //! How many times the variable is used by the instruction/node. - uint8_t refCount; - //! Input register index or `kInvalidReg` if it's not given. - //! - //! Even if the input register index is not given (i.e. it may by any - //! register), register allocator should assign an index that will be - //! used to persist a variable into this specific index. It's helpful - //! in situations where one variable has to be allocated in multiple - //! registers to determine the register which will be persistent. - uint8_t inPhysId; - //! Output register index or `kInvalidReg` if it's not given. - //! - //! Typically `kInvalidReg` if variable is only used on input. - uint8_t outPhysId; - //! \internal - uint8_t reserved; - }; - - //! \internal - //! - //! Packed data #0. - uint32_t packed; - }; - - //! Mandatory input registers. - //! - //! Mandatory input registers are required by the instruction even if - //! there are duplicates. This schema allows us to allocate one variable - //! in one or more register when needed. Required mostly by instructions - //! that have implicit register operands (imul, cpuid, ...) and function - //! call. - uint32_t inRegs; - - //! Allocable input registers. - //! - //! Optional input registers is a mask of all allocable registers for a given - //! variable where we have to pick one of them. This mask is usually not used - //! when _inRegs is set. If both masks are used then the register - //! allocator tries first to find an intersection between these and allocates - //! an extra slot if not found. - uint32_t allocableRegs; -}; - -// ============================================================================ -// [asmjit::RABits] -// ============================================================================ - -//! Fixed size bit-array. -//! -//! Used by variable liveness analysis. -struct RABits { - // -------------------------------------------------------------------------- - // [Enums] - // -------------------------------------------------------------------------- - - enum { - kEntitySize = static_cast(sizeof(uintptr_t)), - kEntityBits = kEntitySize * 8 - }; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE uintptr_t getBit(uint32_t index) const noexcept { - return (data[index / kEntityBits] >> (index % kEntityBits)) & 1; - } - - ASMJIT_INLINE void setBit(uint32_t index) noexcept { - data[index / kEntityBits] |= static_cast(1) << (index % kEntityBits); - } - - ASMJIT_INLINE void delBit(uint32_t index) noexcept { - data[index / kEntityBits] &= ~(static_cast(1) << (index % kEntityBits)); - } - - // -------------------------------------------------------------------------- - // [Interface] - // -------------------------------------------------------------------------- - - //! Copy bits from `s0`, returns `true` if at least one bit is set in `s0`. - ASMJIT_INLINE bool copyBits(const RABits* s0, uint32_t len) noexcept { - uintptr_t r = 0; - for (uint32_t i = 0; i < len; i++) { - uintptr_t t = s0->data[i]; - data[i] = t; - r |= t; - } - return r != 0; - } - - ASMJIT_INLINE bool addBits(const RABits* s0, uint32_t len) noexcept { - return addBits(this, s0, len); - } - - ASMJIT_INLINE bool addBits(const RABits* s0, const RABits* s1, uint32_t len) noexcept { - uintptr_t r = 0; - for (uint32_t i = 0; i < len; i++) { - uintptr_t t = s0->data[i] | s1->data[i]; - data[i] = t; - r |= t; - } - return r != 0; - } - - ASMJIT_INLINE bool andBits(const RABits* s1, uint32_t len) noexcept { - return andBits(this, s1, len); - } - - ASMJIT_INLINE bool andBits(const RABits* s0, const RABits* s1, uint32_t len) noexcept { - uintptr_t r = 0; - for (uint32_t i = 0; i < len; i++) { - uintptr_t t = s0->data[i] & s1->data[i]; - data[i] = t; - r |= t; - } - return r != 0; - } - - ASMJIT_INLINE bool delBits(const RABits* s1, uint32_t len) noexcept { - return delBits(this, s1, len); - } - - ASMJIT_INLINE bool delBits(const RABits* s0, const RABits* s1, uint32_t len) noexcept { - uintptr_t r = 0; - for (uint32_t i = 0; i < len; i++) { - uintptr_t t = s0->data[i] & ~s1->data[i]; - data[i] = t; - r |= t; - } - return r != 0; - } - - ASMJIT_INLINE bool _addBitsDelSource(RABits* s1, uint32_t len) noexcept { - return _addBitsDelSource(this, s1, len); - } - - ASMJIT_INLINE bool _addBitsDelSource(const RABits* s0, RABits* s1, uint32_t len) noexcept { - uintptr_t r = 0; - for (uint32_t i = 0; i < len; i++) { - uintptr_t a = s0->data[i]; - uintptr_t b = s1->data[i]; - - this->data[i] = a | b; - b &= ~a; - - s1->data[i] = b; - r |= b; - } - return r != 0; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uintptr_t data[1]; -}; - -// ============================================================================ -// [asmjit::RACell] -// ============================================================================ - -//! Register allocator's (RA) memory cell. -struct RACell { - RACell* next; //!< Next active cell. - int32_t offset; //!< Cell offset, relative to base-offset. - uint32_t size; //!< Cell size. - uint32_t alignment; //!< Cell alignment. -}; - -// ============================================================================ -// [asmjit::RAData] -// ============================================================================ - -//! Register allocator's (RA) data associated with each \ref CBNode. -struct RAData { - ASMJIT_INLINE RAData(uint32_t tiedTotal) noexcept - : liveness(nullptr), - state(nullptr), - tiedTotal(tiedTotal) {} - - RABits* liveness; //!< Liveness bits (populated by liveness-analysis). - RAState* state; //!< Optional saved \ref RAState. - uint32_t tiedTotal; //!< Total count of \ref TiedReg regs. -}; - -// ============================================================================ -// [asmjit::RAState] -// ============================================================================ - -//! Variables' state. -struct RAState {}; - -// ============================================================================ -// [asmjit::RAPass] -// ============================================================================ - -//! \internal -//! -//! Register allocator pipeline used by \ref CodeCompiler. -struct RAPass : public CBPass { -public: - ASMJIT_NONCOPYABLE(RAPass) - - typedef void (ASMJIT_CDECL* TraceNodeFunc)(RAPass* self, CBNode* node_, const char* prefix); - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - RAPass() noexcept; - virtual ~RAPass() noexcept; - - // -------------------------------------------------------------------------- - // [Interface] - // -------------------------------------------------------------------------- - - virtual Error process(Zone* zone) noexcept override; - - //! Run the register allocator for a given function `func`. - virtual Error compile(CCFunc* func) noexcept; - - //! Called by `compile()` to prepare the register allocator to process the - //! given function. It should reset and set-up everything (i.e. no states - //! from a previous compilation should prevail). - virtual Error prepare(CCFunc* func) noexcept; - - //! Called after `compile()` to clean everything up, no matter if it - //! succeeded or failed. - virtual void cleanup() noexcept; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get the associated `CodeCompiler`. - ASMJIT_INLINE CodeCompiler* cc() const noexcept { return static_cast(_cb); } - - //! Get function. - ASMJIT_INLINE CCFunc* getFunc() const noexcept { return _func; } - //! Get stop node. - ASMJIT_INLINE CBNode* getStop() const noexcept { return _stop; } - - // -------------------------------------------------------------------------- - // [State] - // -------------------------------------------------------------------------- - - //! Get current state. - ASMJIT_INLINE RAState* getState() const { return _state; } - - //! Load current state from `target` state. - virtual void loadState(RAState* src) = 0; - - //! Save current state, returning new `RAState` instance. - virtual RAState* saveState() = 0; - - //! Change the current state to `target` state. - virtual void switchState(RAState* src) = 0; - - //! Change the current state to the intersection of two states `a` and `b`. - virtual void intersectStates(RAState* a, RAState* b) = 0; - - // -------------------------------------------------------------------------- - // [Context] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE Error assignRAId(VirtReg* vreg) noexcept { - // Likely as a single virtual register would be mostly used more than once, - // this means that each virtual register will hit one bad case (doesn't - // have id) and then all likely cases. - if (ASMJIT_LIKELY(vreg->_raId != kInvalidValue)) return kErrorOk; - - uint32_t raId = static_cast(_contextVd.getLength()); - ASMJIT_PROPAGATE(_contextVd.append(&_heap, vreg)); - - vreg->_raId = raId; - return kErrorOk; - } - - // -------------------------------------------------------------------------- - // [Mem] - // -------------------------------------------------------------------------- - - RACell* _newVarCell(VirtReg* vreg); - RACell* _newStackCell(uint32_t size, uint32_t alignment); - - ASMJIT_INLINE RACell* getVarCell(VirtReg* vreg) { - RACell* cell = vreg->getMemCell(); - return cell ? cell : _newVarCell(vreg); - } - - virtual Error resolveCellOffsets(); - - // -------------------------------------------------------------------------- - // [Bits] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE RABits* newBits(uint32_t len) { - return static_cast( - _zone->allocZeroed(static_cast(len) * RABits::kEntitySize)); - } - - ASMJIT_INLINE RABits* copyBits(const RABits* src, uint32_t len) { - return static_cast( - _zone->dup(src, static_cast(len) * RABits::kEntitySize)); - } - - // -------------------------------------------------------------------------- - // [Fetch] - // -------------------------------------------------------------------------- - - //! Fetch. - //! - //! Fetch iterates over all nodes and gathers information about all variables - //! used. The process generates information required by register allocator, - //! variable liveness analysis and translator. - virtual Error fetch() = 0; - - // -------------------------------------------------------------------------- - // [Unreachable Code] - // -------------------------------------------------------------------------- - - //! Add unreachable-flow data to the unreachable flow list. - ASMJIT_INLINE Error addUnreachableNode(CBNode* node) { - ZoneList::Link* link = _zone->allocT::Link>(); - if (!link) return DebugUtils::errored(kErrorNoHeapMemory); - - link->setValue(node); - _unreachableList.append(link); - - return kErrorOk; - } - - //! Remove unreachable code. - virtual Error removeUnreachableCode(); - - // -------------------------------------------------------------------------- - // [Code-Flow] - // -------------------------------------------------------------------------- - - //! Add returning node (i.e. node that returns and where liveness analysis - //! should start). - ASMJIT_INLINE Error addReturningNode(CBNode* node) { - ZoneList::Link* link = _zone->allocT::Link>(); - if (!link) return DebugUtils::errored(kErrorNoHeapMemory); - - link->setValue(node); - _returningList.append(link); - - return kErrorOk; - } - - //! Add jump-flow data to the jcc flow list. - ASMJIT_INLINE Error addJccNode(CBNode* node) { - ZoneList::Link* link = _zone->allocT::Link>(); - if (!link) return DebugUtils::errored(kErrorNoHeapMemory); - - link->setValue(node); - _jccList.append(link); - - return kErrorOk; - } - - // -------------------------------------------------------------------------- - // [Analyze] - // -------------------------------------------------------------------------- - - //! Perform variable liveness analysis. - //! - //! Analysis phase iterates over nodes in reverse order and generates a bit - //! array describing variables that are alive at every node in the function. - //! When the analysis start all variables are assumed dead. When a read or - //! read/write operations of a variable is detected the variable becomes - //! alive; when only write operation is detected the variable becomes dead. - //! - //! When a label is found all jumps to that label are followed and analysis - //! repeats until all variables are resolved. - virtual Error livenessAnalysis(); - - // -------------------------------------------------------------------------- - // [Annotate] - // -------------------------------------------------------------------------- - - virtual Error annotate() = 0; - virtual Error formatInlineComment(StringBuilder& dst, CBNode* node); - - // -------------------------------------------------------------------------- - // [Translate] - // -------------------------------------------------------------------------- - - //! Translate code by allocating registers and handling state changes. - virtual Error translate() = 0; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - Zone* _zone; //!< Zone passed to `process()`. - ZoneHeap _heap; //!< ZoneHeap that uses `_zone`. - - CCFunc* _func; //!< Function being processed. - CBNode* _stop; //!< Stop node. - - //! \internal - //! - //! Offset (how many bytes to add) to `VarMap` to get `TiedReg` array. Used - //! by liveness analysis shared across all backends. This is needed because - //! `VarMap` is a base class for a specialized version that liveness analysis - //! doesn't use, it just needs `TiedReg` array. - uint32_t _varMapToVaListOffset; - - uint8_t _emitComments; //!< Whether to emit comments. - - ZoneList _unreachableList; //!< Unreachable nodes. - ZoneList _returningList; //!< Returning nodes. - ZoneList _jccList; //!< Jump nodes. - - ZoneVector _contextVd; //!< All variables used by the current function. - RACell* _memVarCells; //!< Memory used to spill variables. - RACell* _memStackCells; //!< Memory used to allocate memory on the stack. - - uint32_t _mem1ByteVarsUsed; //!< Count of 1-byte cells. - uint32_t _mem2ByteVarsUsed; //!< Count of 2-byte cells. - uint32_t _mem4ByteVarsUsed; //!< Count of 4-byte cells. - uint32_t _mem8ByteVarsUsed; //!< Count of 8-byte cells. - uint32_t _mem16ByteVarsUsed; //!< Count of 16-byte cells. - uint32_t _mem32ByteVarsUsed; //!< Count of 32-byte cells. - uint32_t _mem64ByteVarsUsed; //!< Count of 64-byte cells. - uint32_t _memStackCellsUsed; //!< Count of stack memory cells. - - uint32_t _memMaxAlign; //!< Maximum memory alignment used by the function. - uint32_t _memVarTotal; //!< Count of bytes used by variables. - uint32_t _memStackTotal; //!< Count of bytes used by stack. - uint32_t _memAllTotal; //!< Count of bytes used by variables and stack after alignment. - - uint32_t _annotationLength; //!< Default length of an annotated instruction. - RAState* _state; //!< Current RA state. -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // !ASMJIT_DISABLE_COMPILER -#endif // _ASMJIT_BASE_REGALLOC_P_H diff --git a/libs/asmjit/base/runtime.cpp b/libs/asmjit/base/runtime.cpp deleted file mode 100644 index f074885a..00000000 --- a/libs/asmjit/base/runtime.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/assembler.h" -#include "../base/cpuinfo.h" -#include "../base/runtime.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -static ASMJIT_INLINE void hostFlushInstructionCache(const void* p, size_t size) noexcept { - // Only useful on non-x86 architectures. -#if !ASMJIT_ARCH_X86 && !ASMJIT_ARCH_X64 -# if ASMJIT_OS_WINDOWS - // Windows has a built-in support in kernel32.dll. - ::FlushInstructionCache(_memMgr.getProcessHandle(), p, size); -# endif // ASMJIT_OS_WINDOWS -#else - ASMJIT_UNUSED(p); - ASMJIT_UNUSED(size); -#endif // !ASMJIT_ARCH_X86 && !ASMJIT_ARCH_X64 -} - -static ASMJIT_INLINE uint32_t hostDetectNaturalStackAlignment() noexcept { - // Alignment is assumed to match the pointer-size by default. - uint32_t alignment = sizeof(intptr_t); - - // X86 & X64 - // --------- - // - // - 32-bit X86 requires stack to be aligned to 4 bytes. Modern Linux, Mac - // and UNIX guarantees 16-byte stack alignment even on 32-bit. I'm not - // sure about all other UNIX operating systems, because 16-byte alignment - //! is addition to an older specification. - // - 64-bit X86 requires stack to be aligned to at least 16 bytes. -#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 - int kIsModernOS = ASMJIT_OS_LINUX || // Linux & ANDROID. - ASMJIT_OS_MAC || // OSX and iOS. - ASMJIT_OS_BSD ; // BSD variants. - alignment = ASMJIT_ARCH_X64 || kIsModernOS ? 16 : 4; -#endif - - // ARM32 & ARM64 - // ------------- - // - // - 32-bit ARM requires stack to be aligned to 8 bytes. - // - 64-bit ARM requires stack to be aligned to 16 bytes. -#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 - alignment = ASMJIT_ARCH_ARM32 ? 8 : 16; -#endif - - return alignment; -} - - -// ============================================================================ -// [asmjit::Runtime - Construction / Destruction] -// ============================================================================ - -Runtime::Runtime() noexcept - : _codeInfo(), - _runtimeType(kRuntimeNone), - _allocType(VMemMgr::kAllocFreeable) {} -Runtime::~Runtime() noexcept {} - -// ============================================================================ -// [asmjit::HostRuntime - Construction / Destruction] -// ============================================================================ - -HostRuntime::HostRuntime() noexcept { - _runtimeType = kRuntimeJit; - - // Setup the CodeInfo of this Runtime. - _codeInfo._archInfo = CpuInfo::getHost().getArchInfo(); - _codeInfo._stackAlignment = static_cast(hostDetectNaturalStackAlignment()); - _codeInfo._cdeclCallConv = CallConv::kIdHostCDecl; - _codeInfo._stdCallConv = CallConv::kIdHostStdCall; - _codeInfo._fastCallConv = CallConv::kIdHostFastCall; -} -HostRuntime::~HostRuntime() noexcept {} - -// ============================================================================ -// [asmjit::HostRuntime - Interface] -// ============================================================================ - -void HostRuntime::flush(const void* p, size_t size) noexcept { - hostFlushInstructionCache(p, size); -} - -// ============================================================================ -// [asmjit::JitRuntime - Construction / Destruction] -// ============================================================================ - -JitRuntime::JitRuntime() noexcept {} -JitRuntime::~JitRuntime() noexcept {} - -// ============================================================================ -// [asmjit::JitRuntime - Interface] -// ============================================================================ - -Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept { - size_t codeSize = code->getCodeSize(); - if (ASMJIT_UNLIKELY(codeSize == 0)) { - *dst = nullptr; - return DebugUtils::errored(kErrorNoCodeGenerated); - } - - void* p = _memMgr.alloc(codeSize, getAllocType()); - if (ASMJIT_UNLIKELY(!p)) { - *dst = nullptr; - return DebugUtils::errored(kErrorNoVirtualMemory); - } - - // Relocate the code and release the unused memory back to `VMemMgr`. - size_t relocSize = code->relocate(p); - if (ASMJIT_UNLIKELY(relocSize == 0)) { - *dst = nullptr; - _memMgr.release(p); - return DebugUtils::errored(kErrorInvalidState); - } - - if (relocSize < codeSize) - _memMgr.shrink(p, relocSize); - - flush(p, relocSize); - *dst = p; - - return kErrorOk; -} - -Error JitRuntime::_release(void* p) noexcept { - return _memMgr.release(p); -} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/runtime.h b/libs/asmjit/base/runtime.h deleted file mode 100644 index 730b6a8b..00000000 --- a/libs/asmjit/base/runtime.h +++ /dev/null @@ -1,198 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_RUNTIME_H -#define _ASMJIT_BASE_RUNTIME_H - -// [Dependencies] -#include "../base/codeholder.h" -#include "../base/vmem.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -class CodeHolder; - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::Runtime] -// ============================================================================ - -//! Base runtime. -class ASMJIT_VIRTAPI Runtime { -public: - ASMJIT_NONCOPYABLE(Runtime) - - ASMJIT_ENUM(RuntimeType) { - kRuntimeNone = 0, - kRuntimeJit = 1, - kRuntimeRemote = 2 - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a `Runtime` instance. - ASMJIT_API Runtime() noexcept; - //! Destroy the `Runtime` instance. - ASMJIT_API virtual ~Runtime() noexcept; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get CodeInfo of this runtime. - //! - //! CodeInfo can be used to setup a CodeHolder in case you plan to generate a - //! code compatible and executable by this Runtime. - ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; } - - //! Get the Runtime's architecture type, see \ref ArchInfo::Type. - ASMJIT_INLINE uint32_t getArchType() const noexcept { return _codeInfo.getArchType(); } - //! Get the Runtime's architecture sub-type, see \ref ArchInfo::SubType. - ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _codeInfo.getArchSubType(); } - - //! Get the runtime type, see \ref Type. - ASMJIT_INLINE uint32_t getRuntimeType() const noexcept { return _runtimeType; } - - // -------------------------------------------------------------------------- - // [Interface] - // -------------------------------------------------------------------------- - - // NOTE: To allow passing function pointers to `add()` and `release()` the - // virtual methods are prefixed with `_` and called from templates. - - template - ASMJIT_INLINE Error add(Func* dst, CodeHolder* code) noexcept { - return _add(Internal::ptr_cast(dst), code); - } - - template - ASMJIT_INLINE Error release(Func dst) noexcept { - return _release(Internal::ptr_cast(dst)); - } - - //! Allocate a memory needed for a code stored in the \ref CodeHolder and - //! relocate it to the target location. - //! - //! The beginning of the memory allocated for the function is returned in - //! `dst`. If failed the \ref Error code is returned and `dst` is set to null - //! (this means that you don't have to set it to null before calling `add()`). - virtual Error _add(void** dst, CodeHolder* code) noexcept = 0; - - //! Release `p` allocated by `add()`. - virtual Error _release(void* p) noexcept = 0; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - CodeInfo _codeInfo; //!< Basic information about the Runtime's code. - uint8_t _runtimeType; //!< Type of the runtime. - uint8_t _allocType; //!< Type of the allocator the Runtime uses. - uint8_t _reserved[6]; //!< \internal -}; - -// ============================================================================ -// [asmjit::HostRuntime] -// ============================================================================ - -//! Runtime designed to be used in the same process the code is generated in. -class ASMJIT_VIRTAPI HostRuntime : public Runtime { -public: - ASMJIT_NONCOPYABLE(HostRuntime) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a `HostRuntime` instance. - ASMJIT_API HostRuntime() noexcept; - //! Destroy the `HostRuntime` instance. - ASMJIT_API virtual ~HostRuntime() noexcept; - - // -------------------------------------------------------------------------- - // [Interface] - // -------------------------------------------------------------------------- - - //! Flush an instruction cache. - //! - //! This member function is called after the code has been copied to the - //! destination buffer. It is only useful for JIT code generation as it - //! causes a flush of the processor's cache. - //! - //! Flushing is basically a NOP under X86/X64, but is needed by architectures - //! that do not have a transparent instruction cache like ARM. - //! - //! This function can also be overridden to improve compatibility with tools - //! such as Valgrind, however, it's not an official part of AsmJit. - ASMJIT_API virtual void flush(const void* p, size_t size) noexcept; -}; - -// ============================================================================ -// [asmjit::JitRuntime] -// ============================================================================ - -//! Runtime designed to store and execute code generated at runtime (JIT). -class ASMJIT_VIRTAPI JitRuntime : public HostRuntime { -public: - ASMJIT_NONCOPYABLE(JitRuntime) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a `JitRuntime` instance. - ASMJIT_API JitRuntime() noexcept; - //! Destroy the `JitRuntime` instance. - ASMJIT_API virtual ~JitRuntime() noexcept; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get the type of allocation. - ASMJIT_INLINE uint32_t getAllocType() const noexcept { return _allocType; } - //! Set the type of allocation. - ASMJIT_INLINE void setAllocType(uint32_t allocType) noexcept { _allocType = allocType; } - - //! Get the virtual memory manager. - ASMJIT_INLINE VMemMgr* getMemMgr() const noexcept { return const_cast(&_memMgr); } - - // -------------------------------------------------------------------------- - // [Interface] - // -------------------------------------------------------------------------- - - ASMJIT_API Error _add(void** dst, CodeHolder* code) noexcept override; - ASMJIT_API Error _release(void* p) noexcept override; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Virtual memory manager. - VMemMgr _memMgr; -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_RUNTIME_H diff --git a/libs/asmjit/base/simdtypes.h b/libs/asmjit/base/simdtypes.h deleted file mode 100644 index 5c1c75a7..00000000 --- a/libs/asmjit/base/simdtypes.h +++ /dev/null @@ -1,1075 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_SIMDTYPES_H -#define _ASMJIT_BASE_SIMDTYPES_H - -// [Dependencies] -#include "../base/globals.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::Data64] -// ============================================================================ - -//! 64-bit data useful for creating SIMD constants. -union Data64 { - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Set all eight 8-bit signed integers. - static ASMJIT_INLINE Data64 fromI8(int8_t x0) noexcept { - Data64 self; - self.setI8(x0); - return self; - } - - //! Set all eight 8-bit unsigned integers. - static ASMJIT_INLINE Data64 fromU8(uint8_t x0) noexcept { - Data64 self; - self.setU8(x0); - return self; - } - - //! Set all eight 8-bit signed integers. - static ASMJIT_INLINE Data64 fromI8( - int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7) noexcept { - - Data64 self; - self.setI8(x0, x1, x2, x3, x4, x5, x6, x7); - return self; - } - - //! Set all eight 8-bit unsigned integers. - static ASMJIT_INLINE Data64 fromU8( - uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7) noexcept { - - Data64 self; - self.setU8(x0, x1, x2, x3, x4, x5, x6, x7); - return self; - } - - //! Set all four 16-bit signed integers. - static ASMJIT_INLINE Data64 fromI16(int16_t x0) noexcept { - Data64 self; - self.setI16(x0); - return self; - } - - //! Set all four 16-bit unsigned integers. - static ASMJIT_INLINE Data64 fromU16(uint16_t x0) noexcept { - Data64 self; - self.setU16(x0); - return self; - } - - //! Set all four 16-bit signed integers. - static ASMJIT_INLINE Data64 fromI16(int16_t x0, int16_t x1, int16_t x2, int16_t x3) noexcept { - Data64 self; - self.setI16(x0, x1, x2, x3); - return self; - } - - //! Set all four 16-bit unsigned integers. - static ASMJIT_INLINE Data64 fromU16(uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3) noexcept { - Data64 self; - self.setU16(x0, x1, x2, x3); - return self; - } - - //! Set all two 32-bit signed integers. - static ASMJIT_INLINE Data64 fromI32(int32_t x0) noexcept { - Data64 self; - self.setI32(x0); - return self; - } - - //! Set all two 32-bit unsigned integers. - static ASMJIT_INLINE Data64 fromU32(uint32_t x0) noexcept { - Data64 self; - self.setU32(x0); - return self; - } - - //! Set all two 32-bit signed integers. - static ASMJIT_INLINE Data64 fromI32(int32_t x0, int32_t x1) noexcept { - Data64 self; - self.setI32(x0, x1); - return self; - } - - //! Set all two 32-bit unsigned integers. - static ASMJIT_INLINE Data64 fromU32(uint32_t x0, uint32_t x1) noexcept { - Data64 self; - self.setU32(x0, x1); - return self; - } - - //! Set 64-bit signed integer. - static ASMJIT_INLINE Data64 fromI64(int64_t x0) noexcept { - Data64 self; - self.setI64(x0); - return self; - } - - //! Set 64-bit unsigned integer. - static ASMJIT_INLINE Data64 fromU64(uint64_t x0) noexcept { - Data64 self; - self.setU64(x0); - return self; - } - - //! Set all two SP-FP values. - static ASMJIT_INLINE Data64 fromF32(float x0) noexcept { - Data64 self; - self.setF32(x0); - return self; - } - - //! Set all two SP-FP values. - static ASMJIT_INLINE Data64 fromF32(float x0, float x1) noexcept { - Data64 self; - self.setF32(x0, x1); - return self; - } - - //! Set all two SP-FP values. - static ASMJIT_INLINE Data64 fromF64(double x0) noexcept { - Data64 self; - self.setF64(x0); - return self; - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Set all eight 8-bit signed integers. - ASMJIT_INLINE void setI8(int8_t x0) noexcept { - setU8(static_cast(x0)); - } - - //! Set all eight 8-bit unsigned integers. - ASMJIT_INLINE void setU8(uint8_t x0) noexcept { - if (ASMJIT_ARCH_64BIT) { - uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0101010101010101); - uq[0] = xq; - } - else { - uint32_t xd = static_cast(x0) * static_cast(0x01010101U); - ud[0] = xd; - ud[1] = xd; - } - } - - //! Set all eight 8-bit signed integers. - ASMJIT_INLINE void setI8( - int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7) noexcept { - - sb[0] = x0; sb[1] = x1; sb[2] = x2; sb[3] = x3; - sb[4] = x4; sb[5] = x5; sb[6] = x6; sb[7] = x7; - } - - //! Set all eight 8-bit unsigned integers. - ASMJIT_INLINE void setU8( - uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7) noexcept { - - ub[0] = x0; ub[1] = x1; ub[2] = x2; ub[3] = x3; - ub[4] = x4; ub[5] = x5; ub[6] = x6; ub[7] = x7; - } - - //! Set all four 16-bit signed integers. - ASMJIT_INLINE void setI16(int16_t x0) noexcept { - setU16(static_cast(x0)); - } - - //! Set all four 16-bit unsigned integers. - ASMJIT_INLINE void setU16(uint16_t x0) noexcept { - if (ASMJIT_ARCH_64BIT) { - uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0001000100010001); - uq[0] = xq; - } - else { - uint32_t xd = static_cast(x0) * static_cast(0x00010001U); - ud[0] = xd; - ud[1] = xd; - } - } - - //! Set all four 16-bit signed integers. - ASMJIT_INLINE void setI16(int16_t x0, int16_t x1, int16_t x2, int16_t x3) noexcept { - sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3; - } - - //! Set all four 16-bit unsigned integers. - ASMJIT_INLINE void setU16(uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3) noexcept { - uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3; - } - - //! Set all two 32-bit signed integers. - ASMJIT_INLINE void setI32(int32_t x0) noexcept { - sd[0] = x0; sd[1] = x0; - } - - //! Set all two 32-bit unsigned integers. - ASMJIT_INLINE void setU32(uint32_t x0) noexcept { - ud[0] = x0; ud[1] = x0; - } - - //! Set all two 32-bit signed integers. - ASMJIT_INLINE void setI32(int32_t x0, int32_t x1) noexcept { - sd[0] = x0; sd[1] = x1; - } - - //! Set all two 32-bit unsigned integers. - ASMJIT_INLINE void setU32(uint32_t x0, uint32_t x1) noexcept { - ud[0] = x0; ud[1] = x1; - } - - //! Set 64-bit signed integer. - ASMJIT_INLINE void setI64(int64_t x0) noexcept { - sq[0] = x0; - } - - //! Set 64-bit unsigned integer. - ASMJIT_INLINE void setU64(uint64_t x0) noexcept { - uq[0] = x0; - } - - //! Set all two SP-FP values. - ASMJIT_INLINE void setF32(float x0) noexcept { - sf[0] = x0; sf[1] = x0; - } - - //! Set all two SP-FP values. - ASMJIT_INLINE void setF32(float x0, float x1) noexcept { - sf[0] = x0; sf[1] = x1; - } - - //! Set all two SP-FP values. - ASMJIT_INLINE void setF64(double x0) noexcept { - df[0] = x0; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Array of eight 8-bit signed integers. - int8_t sb[8]; - //! Array of eight 8-bit unsigned integers. - uint8_t ub[8]; - //! Array of four 16-bit signed integers. - int16_t sw[4]; - //! Array of four 16-bit unsigned integers. - uint16_t uw[4]; - //! Array of two 32-bit signed integers. - int32_t sd[2]; - //! Array of two 32-bit unsigned integers. - uint32_t ud[2]; - //! Array of one 64-bit signed integer. - int64_t sq[1]; - //! Array of one 64-bit unsigned integer. - uint64_t uq[1]; - - //! Array of two SP-FP values. - float sf[2]; - //! Array of one DP-FP value. - double df[1]; -}; - -// ============================================================================ -// [asmjit::Data128] -// ============================================================================ - -//! 128-bit data useful for creating SIMD constants. -union Data128 { - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Set all sixteen 8-bit signed integers. - static ASMJIT_INLINE Data128 fromI8(int8_t x0) noexcept { - Data128 self; - self.setI8(x0); - return self; - } - - //! Set all sixteen 8-bit unsigned integers. - static ASMJIT_INLINE Data128 fromU8(uint8_t x0) noexcept { - Data128 self; - self.setU8(x0); - return self; - } - - //! Set all sixteen 8-bit signed integers. - static ASMJIT_INLINE Data128 fromI8( - int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 , - int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , - int8_t x8 , int8_t x9 , int8_t x10, int8_t x11, - int8_t x12, int8_t x13, int8_t x14, int8_t x15) noexcept { - - Data128 self; - self.setI8(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); - return self; - } - - //! Set all sixteen 8-bit unsigned integers. - static ASMJIT_INLINE Data128 fromU8( - uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 , - uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , - uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11, - uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15) noexcept { - - Data128 self; - self.setU8(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); - return self; - } - - //! Set all eight 16-bit signed integers. - static ASMJIT_INLINE Data128 fromI16(int16_t x0) noexcept { - Data128 self; - self.setI16(x0); - return self; - } - - //! Set all eight 16-bit unsigned integers. - static ASMJIT_INLINE Data128 fromU16(uint16_t x0) noexcept { - Data128 self; - self.setU16(x0); - return self; - } - - //! Set all eight 16-bit signed integers. - static ASMJIT_INLINE Data128 fromI16( - int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7) noexcept { - - Data128 self; - self.setI16(x0, x1, x2, x3, x4, x5, x6, x7); - return self; - } - - //! Set all eight 16-bit unsigned integers. - static ASMJIT_INLINE Data128 fromU16( - uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7) noexcept { - - Data128 self; - self.setU16(x0, x1, x2, x3, x4, x5, x6, x7); - return self; - } - - //! Set all four 32-bit signed integers. - static ASMJIT_INLINE Data128 fromI32(int32_t x0) noexcept { - Data128 self; - self.setI32(x0); - return self; - } - - //! Set all four 32-bit unsigned integers. - static ASMJIT_INLINE Data128 fromU32(uint32_t x0) noexcept { - Data128 self; - self.setU32(x0); - return self; - } - - //! Set all four 32-bit signed integers. - static ASMJIT_INLINE Data128 fromI32(int32_t x0, int32_t x1, int32_t x2, int32_t x3) noexcept { - Data128 self; - self.setI32(x0, x1, x2, x3); - return self; - } - - //! Set all four 32-bit unsigned integers. - static ASMJIT_INLINE Data128 fromU32(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) noexcept { - Data128 self; - self.setU32(x0, x1, x2, x3); - return self; - } - - //! Set all two 64-bit signed integers. - static ASMJIT_INLINE Data128 fromI64(int64_t x0) noexcept { - Data128 self; - self.setI64(x0); - return self; - } - - //! Set all two 64-bit unsigned integers. - static ASMJIT_INLINE Data128 fromU64(uint64_t x0) noexcept { - Data128 self; - self.setU64(x0); - return self; - } - - //! Set all two 64-bit signed integers. - static ASMJIT_INLINE Data128 fromI64(int64_t x0, int64_t x1) noexcept { - Data128 self; - self.setI64(x0, x1); - return self; - } - - //! Set all two 64-bit unsigned integers. - static ASMJIT_INLINE Data128 fromU64(uint64_t x0, uint64_t x1) noexcept { - Data128 self; - self.setU64(x0, x1); - return self; - } - - //! Set all four SP-FP floats. - static ASMJIT_INLINE Data128 fromF32(float x0) noexcept { - Data128 self; - self.setF32(x0); - return self; - } - - //! Set all four SP-FP floats. - static ASMJIT_INLINE Data128 fromF32(float x0, float x1, float x2, float x3) noexcept { - Data128 self; - self.setF32(x0, x1, x2, x3); - return self; - } - - //! Set all two DP-FP floats. - static ASMJIT_INLINE Data128 fromF64(double x0) noexcept { - Data128 self; - self.setF64(x0); - return self; - } - - //! Set all two DP-FP floats. - static ASMJIT_INLINE Data128 fromF64(double x0, double x1) noexcept { - Data128 self; - self.setF64(x0, x1); - return self; - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Set all sixteen 8-bit signed integers. - ASMJIT_INLINE void setI8(int8_t x0) noexcept { - setU8(static_cast(x0)); - } - - //! Set all sixteen 8-bit unsigned integers. - ASMJIT_INLINE void setU8(uint8_t x0) noexcept { - if (ASMJIT_ARCH_64BIT) { - uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0101010101010101); - uq[0] = xq; - uq[1] = xq; - } - else { - uint32_t xd = static_cast(x0) * static_cast(0x01010101U); - ud[0] = xd; - ud[1] = xd; - ud[2] = xd; - ud[3] = xd; - } - } - - //! Set all sixteen 8-bit signed integers. - ASMJIT_INLINE void setI8( - int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 , - int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , - int8_t x8 , int8_t x9 , int8_t x10, int8_t x11, - int8_t x12, int8_t x13, int8_t x14, int8_t x15) noexcept { - - sb[0 ] = x0 ; sb[1 ] = x1 ; sb[2 ] = x2 ; sb[3 ] = x3 ; - sb[4 ] = x4 ; sb[5 ] = x5 ; sb[6 ] = x6 ; sb[7 ] = x7 ; - sb[8 ] = x8 ; sb[9 ] = x9 ; sb[10] = x10; sb[11] = x11; - sb[12] = x12; sb[13] = x13; sb[14] = x14; sb[15] = x15; - } - - //! Set all sixteen 8-bit unsigned integers. - ASMJIT_INLINE void setU8( - uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 , - uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , - uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11, - uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15) noexcept { - - ub[0 ] = x0 ; ub[1 ] = x1 ; ub[2 ] = x2 ; ub[3 ] = x3 ; - ub[4 ] = x4 ; ub[5 ] = x5 ; ub[6 ] = x6 ; ub[7 ] = x7 ; - ub[8 ] = x8 ; ub[9 ] = x9 ; ub[10] = x10; ub[11] = x11; - ub[12] = x12; ub[13] = x13; ub[14] = x14; ub[15] = x15; - } - - //! Set all eight 16-bit signed integers. - ASMJIT_INLINE void setI16(int16_t x0) noexcept { - setU16(static_cast(x0)); - } - - //! Set all eight 16-bit unsigned integers. - ASMJIT_INLINE void setU16(uint16_t x0) noexcept { - if (ASMJIT_ARCH_64BIT) { - uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0001000100010001); - uq[0] = xq; - uq[1] = xq; - } - else { - uint32_t xd = static_cast(x0) * static_cast(0x00010001U); - ud[0] = xd; - ud[1] = xd; - ud[2] = xd; - ud[3] = xd; - } - } - - //! Set all eight 16-bit signed integers. - ASMJIT_INLINE void setI16( - int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7) noexcept { - - sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3; - sw[4] = x4; sw[5] = x5; sw[6] = x6; sw[7] = x7; - } - - //! Set all eight 16-bit unsigned integers. - ASMJIT_INLINE void setU16( - uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7) noexcept { - - uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3; - uw[4] = x4; uw[5] = x5; uw[6] = x6; uw[7] = x7; - } - - //! Set all four 32-bit signed integers. - ASMJIT_INLINE void setI32(int32_t x0) noexcept { - setU32(static_cast(x0)); - } - - //! Set all four 32-bit unsigned integers. - ASMJIT_INLINE void setU32(uint32_t x0) noexcept { - if (ASMJIT_ARCH_64BIT) { - uint64_t t = (static_cast(x0) << 32) + x0; - uq[0] = t; - uq[1] = t; - } - else { - ud[0] = x0; - ud[1] = x0; - ud[2] = x0; - ud[3] = x0; - } - } - - //! Set all four 32-bit signed integers. - ASMJIT_INLINE void setI32(int32_t x0, int32_t x1, int32_t x2, int32_t x3) noexcept { - sd[0] = x0; sd[1] = x1; sd[2] = x2; sd[3] = x3; - } - - //! Set all four 32-bit unsigned integers. - ASMJIT_INLINE void setU32(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) noexcept { - ud[0] = x0; ud[1] = x1; ud[2] = x2; ud[3] = x3; - } - - //! Set all two 64-bit signed integers. - ASMJIT_INLINE void setI64(int64_t x0) noexcept { - sq[0] = x0; sq[1] = x0; - } - - //! Set all two 64-bit unsigned integers. - ASMJIT_INLINE void setU64(uint64_t x0) noexcept { - uq[0] = x0; uq[1] = x0; - } - - //! Set all two 64-bit signed integers. - ASMJIT_INLINE void setI64(int64_t x0, int64_t x1) noexcept { - sq[0] = x0; sq[1] = x1; - } - - //! Set all two 64-bit unsigned integers. - ASMJIT_INLINE void setU64(uint64_t x0, uint64_t x1) noexcept { - uq[0] = x0; uq[1] = x1; - } - - //! Set all four SP-FP floats. - ASMJIT_INLINE void setF32(float x0) noexcept { - sf[0] = x0; sf[1] = x0; sf[2] = x0; sf[3] = x0; - } - - //! Set all four SP-FP floats. - ASMJIT_INLINE void setF32(float x0, float x1, float x2, float x3) noexcept { - sf[0] = x0; sf[1] = x1; sf[2] = x2; sf[3] = x3; - } - - //! Set all two DP-FP floats. - ASMJIT_INLINE void setF64(double x0) noexcept { - df[0] = x0; df[1] = x0; - } - - //! Set all two DP-FP floats. - ASMJIT_INLINE void setF64(double x0, double x1) noexcept { - df[0] = x0; df[1] = x1; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Array of sixteen 8-bit signed integers. - int8_t sb[16]; - //! Array of sixteen 8-bit unsigned integers. - uint8_t ub[16]; - //! Array of eight 16-bit signed integers. - int16_t sw[8]; - //! Array of eight 16-bit unsigned integers. - uint16_t uw[8]; - //! Array of four 32-bit signed integers. - int32_t sd[4]; - //! Array of four 32-bit unsigned integers. - uint32_t ud[4]; - //! Array of two 64-bit signed integers. - int64_t sq[2]; - //! Array of two 64-bit unsigned integers. - uint64_t uq[2]; - - //! Array of four 32-bit single precision floating points. - float sf[4]; - //! Array of two 64-bit double precision floating points. - double df[2]; -}; - -// ============================================================================ -// [asmjit::Data256] -// ============================================================================ - -//! 256-bit data useful for creating SIMD constants. -union Data256 { - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Set all thirty two 8-bit signed integers. - static ASMJIT_INLINE Data256 fromI8(int8_t x0) noexcept { - Data256 self; - self.setI8(x0); - return self; - } - - //! Set all thirty two 8-bit unsigned integers. - static ASMJIT_INLINE Data256 fromU8(uint8_t x0) noexcept { - Data256 self; - self.setU8(x0); - return self; - } - - //! Set all thirty two 8-bit signed integers. - static ASMJIT_INLINE Data256 fromI8( - int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 , - int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , - int8_t x8 , int8_t x9 , int8_t x10, int8_t x11, - int8_t x12, int8_t x13, int8_t x14, int8_t x15, - int8_t x16, int8_t x17, int8_t x18, int8_t x19, - int8_t x20, int8_t x21, int8_t x22, int8_t x23, - int8_t x24, int8_t x25, int8_t x26, int8_t x27, - int8_t x28, int8_t x29, int8_t x30, int8_t x31) noexcept { - - Data256 self; - self.setI8( - x0, x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31); - return self; - } - - //! Set all thirty two 8-bit unsigned integers. - static ASMJIT_INLINE Data256 fromU8( - uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 , - uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , - uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11, - uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15, - uint8_t x16, uint8_t x17, uint8_t x18, uint8_t x19, - uint8_t x20, uint8_t x21, uint8_t x22, uint8_t x23, - uint8_t x24, uint8_t x25, uint8_t x26, uint8_t x27, - uint8_t x28, uint8_t x29, uint8_t x30, uint8_t x31) noexcept { - - Data256 self; - self.setU8( - x0, x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31); - return self; - } - - //! Set all sixteen 16-bit signed integers. - static ASMJIT_INLINE Data256 fromI16(int16_t x0) noexcept { - Data256 self; - self.setI16(x0); - return self; - } - - //! Set all sixteen 16-bit unsigned integers. - static ASMJIT_INLINE Data256 fromU16(uint16_t x0) noexcept { - Data256 self; - self.setU16(x0); - return self; - } - - //! Set all sixteen 16-bit signed integers. - static ASMJIT_INLINE Data256 fromI16( - int16_t x0, int16_t x1, int16_t x2 , int16_t x3 , int16_t x4 , int16_t x5 , int16_t x6 , int16_t x7 , - int16_t x8, int16_t x9, int16_t x10, int16_t x11, int16_t x12, int16_t x13, int16_t x14, int16_t x15) noexcept { - - Data256 self; - self.setI16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); - return self; - } - - //! Set all sixteen 16-bit unsigned integers. - static ASMJIT_INLINE Data256 fromU16( - uint16_t x0, uint16_t x1, uint16_t x2 , uint16_t x3 , uint16_t x4 , uint16_t x5 , uint16_t x6 , uint16_t x7 , - uint16_t x8, uint16_t x9, uint16_t x10, uint16_t x11, uint16_t x12, uint16_t x13, uint16_t x14, uint16_t x15) noexcept { - - Data256 self; - self.setU16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); - return self; - } - - //! Set all eight 32-bit signed integers. - static ASMJIT_INLINE Data256 fromI32(int32_t x0) noexcept { - Data256 self; - self.setI32(x0); - return self; - } - - //! Set all eight 32-bit unsigned integers. - static ASMJIT_INLINE Data256 fromU32(uint32_t x0) noexcept { - Data256 self; - self.setU32(x0); - return self; - } - - //! Set all eight 32-bit signed integers. - static ASMJIT_INLINE Data256 fromI32( - int32_t x0, int32_t x1, int32_t x2, int32_t x3, - int32_t x4, int32_t x5, int32_t x6, int32_t x7) noexcept { - - Data256 self; - self.setI32(x0, x1, x2, x3, x4, x5, x6, x7); - return self; - } - - //! Set all eight 32-bit unsigned integers. - static ASMJIT_INLINE Data256 fromU32( - uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, - uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) noexcept { - - Data256 self; - self.setU32(x0, x1, x2, x3, x4, x5, x6, x7); - return self; - } - - //! Set all four 64-bit signed integers. - static ASMJIT_INLINE Data256 fromI64(int64_t x0) noexcept { - Data256 self; - self.setI64(x0); - return self; - } - - //! Set all four 64-bit unsigned integers. - static ASMJIT_INLINE Data256 fromU64(uint64_t x0) noexcept { - Data256 self; - self.setU64(x0); - return self; - } - - //! Set all four 64-bit signed integers. - static ASMJIT_INLINE Data256 fromI64(int64_t x0, int64_t x1, int64_t x2, int64_t x3) noexcept { - Data256 self; - self.setI64(x0, x1, x2, x3); - return self; - } - - //! Set all four 64-bit unsigned integers. - static ASMJIT_INLINE Data256 fromU64(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3) noexcept { - Data256 self; - self.setU64(x0, x1, x2, x3); - return self; - } - - //! Set all eight SP-FP floats. - static ASMJIT_INLINE Data256 fromF32(float x0) noexcept { - Data256 self; - self.setF32(x0); - return self; - } - - //! Set all eight SP-FP floats. - static ASMJIT_INLINE Data256 fromF32( - float x0, float x1, float x2, float x3, - float x4, float x5, float x6, float x7) noexcept { - - Data256 self; - self.setF32(x0, x1, x2, x3, x4, x5, x6, x7); - return self; - } - - //! Set all four DP-FP floats. - static ASMJIT_INLINE Data256 fromF64(double x0) noexcept { - Data256 self; - self.setF64(x0); - return self; - } - - //! Set all four DP-FP floats. - static ASMJIT_INLINE Data256 fromF64(double x0, double x1, double x2, double x3) noexcept { - Data256 self; - self.setF64(x0, x1, x2, x3); - return self; - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Set all thirty two 8-bit signed integers. - ASMJIT_INLINE void setI8(int8_t x0) noexcept { - setU8(static_cast(x0)); - } - - //! Set all thirty two 8-bit unsigned integers. - ASMJIT_INLINE void setU8(uint8_t x0) noexcept { - if (ASMJIT_ARCH_64BIT) { - uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0101010101010101); - uq[0] = xq; - uq[1] = xq; - uq[2] = xq; - uq[3] = xq; - } - else { - uint32_t xd = static_cast(x0) * static_cast(0x01010101U); - ud[0] = xd; - ud[1] = xd; - ud[2] = xd; - ud[3] = xd; - ud[4] = xd; - ud[5] = xd; - ud[6] = xd; - ud[7] = xd; - } - } - - //! Set all thirty two 8-bit signed integers. - ASMJIT_INLINE void setI8( - int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 , - int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , - int8_t x8 , int8_t x9 , int8_t x10, int8_t x11, - int8_t x12, int8_t x13, int8_t x14, int8_t x15, - int8_t x16, int8_t x17, int8_t x18, int8_t x19, - int8_t x20, int8_t x21, int8_t x22, int8_t x23, - int8_t x24, int8_t x25, int8_t x26, int8_t x27, - int8_t x28, int8_t x29, int8_t x30, int8_t x31) noexcept { - - sb[0 ] = x0 ; sb[1 ] = x1 ; sb[2 ] = x2 ; sb[3 ] = x3 ; - sb[4 ] = x4 ; sb[5 ] = x5 ; sb[6 ] = x6 ; sb[7 ] = x7 ; - sb[8 ] = x8 ; sb[9 ] = x9 ; sb[10] = x10; sb[11] = x11; - sb[12] = x12; sb[13] = x13; sb[14] = x14; sb[15] = x15; - sb[16] = x16; sb[17] = x17; sb[18] = x18; sb[19] = x19; - sb[20] = x20; sb[21] = x21; sb[22] = x22; sb[23] = x23; - sb[24] = x24; sb[25] = x25; sb[26] = x26; sb[27] = x27; - sb[28] = x28; sb[29] = x29; sb[30] = x30; sb[31] = x31; - } - - //! Set all thirty two 8-bit unsigned integers. - ASMJIT_INLINE void setU8( - uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 , - uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , - uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11, - uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15, - uint8_t x16, uint8_t x17, uint8_t x18, uint8_t x19, - uint8_t x20, uint8_t x21, uint8_t x22, uint8_t x23, - uint8_t x24, uint8_t x25, uint8_t x26, uint8_t x27, - uint8_t x28, uint8_t x29, uint8_t x30, uint8_t x31) noexcept { - - ub[0 ] = x0 ; ub[1 ] = x1 ; ub[2 ] = x2 ; ub[3 ] = x3 ; - ub[4 ] = x4 ; ub[5 ] = x5 ; ub[6 ] = x6 ; ub[7 ] = x7 ; - ub[8 ] = x8 ; ub[9 ] = x9 ; ub[10] = x10; ub[11] = x11; - ub[12] = x12; ub[13] = x13; ub[14] = x14; ub[15] = x15; - ub[16] = x16; ub[17] = x17; ub[18] = x18; ub[19] = x19; - ub[20] = x20; ub[21] = x21; ub[22] = x22; ub[23] = x23; - ub[24] = x24; ub[25] = x25; ub[26] = x26; ub[27] = x27; - ub[28] = x28; ub[29] = x29; ub[30] = x30; ub[31] = x31; - } - - //! Set all sixteen 16-bit signed integers. - ASMJIT_INLINE void setI16(int16_t x0) noexcept { - setU16(static_cast(x0)); - } - - //! Set all eight 16-bit unsigned integers. - ASMJIT_INLINE void setU16(uint16_t x0) noexcept { - if (ASMJIT_ARCH_64BIT) { - uint64_t xq = static_cast(x0) * ASMJIT_UINT64_C(0x0001000100010001); - uq[0] = xq; - uq[1] = xq; - uq[2] = xq; - uq[3] = xq; - } - else { - uint32_t xd = static_cast(x0) * static_cast(0x00010001U); - ud[0] = xd; - ud[1] = xd; - ud[2] = xd; - ud[3] = xd; - ud[4] = xd; - ud[5] = xd; - ud[6] = xd; - ud[7] = xd; - } - } - - //! Set all sixteen 16-bit signed integers. - ASMJIT_INLINE void setI16( - int16_t x0, int16_t x1, int16_t x2 , int16_t x3 , int16_t x4 , int16_t x5 , int16_t x6 , int16_t x7, - int16_t x8, int16_t x9, int16_t x10, int16_t x11, int16_t x12, int16_t x13, int16_t x14, int16_t x15) noexcept { - - sw[0 ] = x0 ; sw[1 ] = x1 ; sw[2 ] = x2 ; sw[3 ] = x3 ; - sw[4 ] = x4 ; sw[5 ] = x5 ; sw[6 ] = x6 ; sw[7 ] = x7 ; - sw[8 ] = x8 ; sw[9 ] = x9 ; sw[10] = x10; sw[11] = x11; - sw[12] = x12; sw[13] = x13; sw[14] = x14; sw[15] = x15; - } - - //! Set all sixteen 16-bit unsigned integers. - ASMJIT_INLINE void setU16( - uint16_t x0, uint16_t x1, uint16_t x2 , uint16_t x3 , uint16_t x4 , uint16_t x5 , uint16_t x6 , uint16_t x7, - uint16_t x8, uint16_t x9, uint16_t x10, uint16_t x11, uint16_t x12, uint16_t x13, uint16_t x14, uint16_t x15) noexcept { - - uw[0 ] = x0 ; uw[1 ] = x1 ; uw[2 ] = x2 ; uw[3 ] = x3 ; - uw[4 ] = x4 ; uw[5 ] = x5 ; uw[6 ] = x6 ; uw[7 ] = x7 ; - uw[8 ] = x8 ; uw[9 ] = x9 ; uw[10] = x10; uw[11] = x11; - uw[12] = x12; uw[13] = x13; uw[14] = x14; uw[15] = x15; - } - - //! Set all eight 32-bit signed integers. - ASMJIT_INLINE void setI32(int32_t x0) noexcept { - setU32(static_cast(x0)); - } - - //! Set all eight 32-bit unsigned integers. - ASMJIT_INLINE void setU32(uint32_t x0) noexcept { - if (ASMJIT_ARCH_64BIT) { - uint64_t xq = (static_cast(x0) << 32) + x0; - uq[0] = xq; - uq[1] = xq; - uq[2] = xq; - uq[3] = xq; - } - else { - ud[0] = x0; - ud[1] = x0; - ud[2] = x0; - ud[3] = x0; - ud[4] = x0; - ud[5] = x0; - ud[6] = x0; - ud[7] = x0; - } - } - - //! Set all eight 32-bit signed integers. - ASMJIT_INLINE void setI32( - int32_t x0, int32_t x1, int32_t x2, int32_t x3, - int32_t x4, int32_t x5, int32_t x6, int32_t x7) noexcept { - - sd[0] = x0; sd[1] = x1; sd[2] = x2; sd[3] = x3; - sd[4] = x4; sd[5] = x5; sd[6] = x6; sd[7] = x7; - } - - //! Set all eight 32-bit unsigned integers. - ASMJIT_INLINE void setU32( - uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, - uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) noexcept { - - ud[0] = x0; ud[1] = x1; ud[2] = x2; ud[3] = x3; - ud[4] = x4; ud[5] = x5; ud[6] = x6; ud[7] = x7; - } - - //! Set all four 64-bit signed integers. - ASMJIT_INLINE void setI64(int64_t x0) noexcept { - sq[0] = x0; sq[1] = x0; sq[2] = x0; sq[3] = x0; - } - - //! Set all four 64-bit unsigned integers. - ASMJIT_INLINE void setU64(uint64_t x0) noexcept { - uq[0] = x0; uq[1] = x0; uq[2] = x0; uq[3] = x0; - } - - //! Set all four 64-bit signed integers. - ASMJIT_INLINE void setI64(int64_t x0, int64_t x1, int64_t x2, int64_t x3) noexcept { - sq[0] = x0; sq[1] = x1; sq[2] = x2; sq[3] = x3; - } - - //! Set all four 64-bit unsigned integers. - ASMJIT_INLINE void setU64(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3) noexcept { - uq[0] = x0; uq[1] = x1; uq[2] = x2; uq[3] = x3; - } - - //! Set all eight SP-FP floats. - ASMJIT_INLINE void setF32(float x0) noexcept { - sf[0] = x0; sf[1] = x0; sf[2] = x0; sf[3] = x0; - sf[4] = x0; sf[5] = x0; sf[6] = x0; sf[7] = x0; - } - - //! Set all eight SP-FP floats. - ASMJIT_INLINE void setF32( - float x0, float x1, float x2, float x3, - float x4, float x5, float x6, float x7) noexcept { - - sf[0] = x0; sf[1] = x1; sf[2] = x2; sf[3] = x3; - sf[4] = x4; sf[5] = x5; sf[6] = x6; sf[7] = x7; - } - - //! Set all four DP-FP floats. - ASMJIT_INLINE void setF64(double x0) noexcept { - df[0] = x0; df[1] = x0; df[2] = x0; df[3] = x0; - } - - //! Set all four DP-FP floats. - ASMJIT_INLINE void setF64(double x0, double x1, double x2, double x3) noexcept { - df[0] = x0; df[1] = x1; df[2] = x2; df[3] = x3; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Array of thirty two 8-bit signed integers. - int8_t sb[32]; - //! Array of thirty two 8-bit unsigned integers. - uint8_t ub[32]; - //! Array of sixteen 16-bit signed integers. - int16_t sw[16]; - //! Array of sixteen 16-bit unsigned integers. - uint16_t uw[16]; - //! Array of eight 32-bit signed integers. - int32_t sd[8]; - //! Array of eight 32-bit unsigned integers. - uint32_t ud[8]; - //! Array of four 64-bit signed integers. - int64_t sq[4]; - //! Array of four 64-bit unsigned integers. - uint64_t uq[4]; - - //! Array of eight 32-bit single precision floating points. - float sf[8]; - //! Array of four 64-bit double precision floating points. - double df[4]; -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_SIMDTYPES_H diff --git a/libs/asmjit/base/string.cpp b/libs/asmjit/base/string.cpp deleted file mode 100644 index 4d0a837c..00000000 --- a/libs/asmjit/base/string.cpp +++ /dev/null @@ -1,353 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/string.h" -#include "../base/utils.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::StringBuilder - Construction / Destruction] -// ============================================================================ - -// Should be placed in read-only memory. -static const char StringBuilder_empty[4] = { 0 }; - -StringBuilder::StringBuilder() noexcept - : _data(const_cast(StringBuilder_empty)), - _length(0), - _capacity(0), - _canFree(false) {} - -StringBuilder::~StringBuilder() noexcept { - if (_canFree) - Internal::releaseMemory(_data); -} - -// ============================================================================ -// [asmjit::StringBuilder - Prepare / Reserve] -// ============================================================================ - -ASMJIT_FAVOR_SIZE char* StringBuilder::prepare(uint32_t op, size_t len) noexcept { - if (op == kStringOpSet) { - // We don't care here, but we can't return a null pointer since it indicates - // failure in memory allocation. - if (len == 0) { - if (_data != StringBuilder_empty) - _data[0] = 0; - - _length = 0; - return _data; - } - - if (_capacity < len) { - if (len >= IntTraits::maxValue() - sizeof(intptr_t) * 2) - return nullptr; - - size_t to = Utils::alignTo(len, sizeof(intptr_t)); - if (to < 256 - sizeof(intptr_t)) - to = 256 - sizeof(intptr_t); - - char* newData = static_cast(Internal::allocMemory(to + sizeof(intptr_t))); - if (!newData) { - clear(); - return nullptr; - } - - if (_canFree) - Internal::releaseMemory(_data); - - _data = newData; - _capacity = to + sizeof(intptr_t) - 1; - _canFree = true; - } - - _data[len] = 0; - _length = len; - - ASMJIT_ASSERT(_length <= _capacity); - return _data; - } - else { - // We don't care here, but we can't return a null pointer since it indicates - // failure of memory allocation. - if (len == 0) - return _data + _length; - - // Overflow. - if (IntTraits::maxValue() - sizeof(intptr_t) * 2 - _length < len) - return nullptr; - - size_t after = _length + len; - if (_capacity < after) { - size_t to = _capacity; - - if (to < 256) - to = 256; - - while (to < 1024 * 1024 && to < after) - to *= 2; - - if (to < after) { - to = after; - if (to < (IntTraits::maxValue() - 1024 * 32)) - to = Utils::alignTo(to, 1024 * 32); - } - - to = Utils::alignTo(to, sizeof(intptr_t)); - char* newData = static_cast(Internal::allocMemory(to + sizeof(intptr_t))); - if (!newData) return nullptr; - - ::memcpy(newData, _data, _length); - if (_canFree) - Internal::releaseMemory(_data); - - _data = newData; - _capacity = to + sizeof(intptr_t) - 1; - _canFree = true; - } - - char* ret = _data + _length; - _data[after] = 0; - _length = after; - - ASMJIT_ASSERT(_length <= _capacity); - return ret; - } -} - -ASMJIT_FAVOR_SIZE Error StringBuilder::reserve(size_t to) noexcept { - if (_capacity >= to) - return kErrorOk; - - if (to >= IntTraits::maxValue() - sizeof(intptr_t) * 2) - return DebugUtils::errored(kErrorNoHeapMemory); - - to = Utils::alignTo(to, sizeof(intptr_t)); - char* newData = static_cast(Internal::allocMemory(to + sizeof(intptr_t))); - - if (!newData) - return DebugUtils::errored(kErrorNoHeapMemory); - - ::memcpy(newData, _data, _length + 1); - if (_canFree) - Internal::releaseMemory(_data); - - _data = newData; - _capacity = to + sizeof(intptr_t) - 1; - _canFree = true; - return kErrorOk; -} - -// ============================================================================ -// [asmjit::StringBuilder - Clear] -// ============================================================================ - -void StringBuilder::clear() noexcept { - if (_data != StringBuilder_empty) - _data[0] = 0; - _length = 0; -} - -// ============================================================================ -// [asmjit::StringBuilder - Methods] -// ============================================================================ - -Error StringBuilder::_opString(uint32_t op, const char* str, size_t len) noexcept { - if (len == Globals::kInvalidIndex) - len = str ? ::strlen(str) : static_cast(0); - - char* p = prepare(op, len); - if (!p) return DebugUtils::errored(kErrorNoHeapMemory); - - ::memcpy(p, str, len); - return kErrorOk; -} - -Error StringBuilder::_opChar(uint32_t op, char c) noexcept { - char* p = prepare(op, 1); - if (!p) return DebugUtils::errored(kErrorNoHeapMemory); - - *p = c; - return kErrorOk; -} - -Error StringBuilder::_opChars(uint32_t op, char c, size_t n) noexcept { - char* p = prepare(op, n); - if (!p) return DebugUtils::errored(kErrorNoHeapMemory); - - ::memset(p, c, n); - return kErrorOk; -} - -static const char StringBuilder_numbers[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -Error StringBuilder::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) noexcept { - if (base < 2 || base > 36) - base = 10; - - char buf[128]; - char* p = buf + ASMJIT_ARRAY_SIZE(buf); - - uint64_t orig = i; - char sign = '\0'; - - // -------------------------------------------------------------------------- - // [Sign] - // -------------------------------------------------------------------------- - - if ((flags & kStringFormatSigned) != 0 && static_cast(i) < 0) { - i = static_cast(-static_cast(i)); - sign = '-'; - } - else if ((flags & kStringFormatShowSign) != 0) { - sign = '+'; - } - else if ((flags & kStringFormatShowSpace) != 0) { - sign = ' '; - } - - // -------------------------------------------------------------------------- - // [Number] - // -------------------------------------------------------------------------- - - do { - uint64_t d = i / base; - uint64_t r = i % base; - - *--p = StringBuilder_numbers[r]; - i = d; - } while (i); - - size_t numberLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p); - - // -------------------------------------------------------------------------- - // [Alternate Form] - // -------------------------------------------------------------------------- - - if ((flags & kStringFormatAlternate) != 0) { - if (base == 8) { - if (orig != 0) - *--p = '0'; - } - if (base == 16) { - *--p = 'x'; - *--p = '0'; - } - } - - // -------------------------------------------------------------------------- - // [Width] - // -------------------------------------------------------------------------- - - if (sign != 0) - *--p = sign; - - if (width > 256) - width = 256; - - if (width <= numberLength) - width = 0; - else - width -= numberLength; - - // -------------------------------------------------------------------------- - // Write] - // -------------------------------------------------------------------------- - - size_t prefixLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberLength; - char* data = prepare(op, prefixLength + width + numberLength); - - if (!data) - return DebugUtils::errored(kErrorNoHeapMemory); - - ::memcpy(data, p, prefixLength); - data += prefixLength; - - ::memset(data, '0', width); - data += width; - - ::memcpy(data, p + prefixLength, numberLength); - return kErrorOk; -} - -Error StringBuilder::_opHex(uint32_t op, const void* data, size_t len) noexcept { - char* dst; - - if (len >= IntTraits::maxValue() / 2 || !(dst = prepare(op, len * 2))) - return DebugUtils::errored(kErrorNoHeapMemory);; - - const char* src = static_cast(data); - for (size_t i = 0; i < len; i++, dst += 2, src++) { - dst[0] = StringBuilder_numbers[(src[0] >> 4) & 0xF]; - dst[1] = StringBuilder_numbers[(src[0] ) & 0xF]; - } - return kErrorOk; -} - -Error StringBuilder::_opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept { - char buf[1024]; - - vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap); - buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0'; - - return _opString(op, buf); -} - -Error StringBuilder::setFormat(const char* fmt, ...) noexcept { - bool result; - - va_list ap; - va_start(ap, fmt); - result = _opVFormat(kStringOpSet, fmt, ap); - va_end(ap); - - return result; -} - -Error StringBuilder::appendFormat(const char* fmt, ...) noexcept { - bool result; - - va_list ap; - va_start(ap, fmt); - result = _opVFormat(kStringOpAppend, fmt, ap); - va_end(ap); - - return result; -} - -bool StringBuilder::eq(const char* str, size_t len) const noexcept { - const char* aData = _data; - const char* bData = str; - - size_t aLength = _length; - size_t bLength = len; - - if (bLength == Globals::kInvalidIndex) { - size_t i; - for (i = 0; i < aLength; i++) - if (aData[i] != bData[i] || bData[i] == 0) - return false; - return bData[i] == 0; - } - else { - if (aLength != bLength) - return false; - return ::memcmp(aData, bData, aLength) == 0; - } -} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/string.h b/libs/asmjit/base/string.h deleted file mode 100644 index 8d1ef166..00000000 --- a/libs/asmjit/base/string.h +++ /dev/null @@ -1,289 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_STRING_H -#define _ASMJIT_BASE_STRING_H - -// [Dependencies] -#include "../base/globals.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::SmallString] -// ============================================================================ - -//! Small string is a template that helps to create strings that can be either -//! statically allocated if they are small, or externally allocated in case -//! their length exceed the limit. The `WholeSize` represents the size of the -//! whole `SmallString` structure, based on that size the maximum size of the -//! internal buffer is determined. -template -class SmallString { -public: - enum { kMaxEmbeddedLength = WholeSize - 5 }; - - ASMJIT_INLINE SmallString() noexcept { reset(); } - ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); } - - ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; } - ASMJIT_INLINE bool isEmbedded() const noexcept { return _length <= kMaxEmbeddedLength; } - ASMJIT_INLINE bool mustEmbed(size_t len) const noexcept { return len <= kMaxEmbeddedLength; } - - ASMJIT_INLINE uint32_t getLength() const noexcept { return _length; } - ASMJIT_INLINE char* getData() const noexcept { - return _length <= kMaxEmbeddedLength ? const_cast(_embedded) : _external[1]; - } - - ASMJIT_INLINE void setEmbedded(const char* data, size_t len) noexcept { - ASMJIT_ASSERT(len <= kMaxEmbeddedLength); - - _length = static_cast(len); - ::memcpy(_embedded, data, len); - _embedded[len] = '\0'; - } - - ASMJIT_INLINE void setExternal(const char* data, size_t len) noexcept { - ASMJIT_ASSERT(len > kMaxEmbeddedLength); - ASMJIT_ASSERT(len <= ~static_cast(0)); - - _length = static_cast(len); - _external[1] = const_cast(data); - } - - union { - struct { - uint32_t _length; - char _embedded[WholeSize - 4]; - }; - char* _external[2]; - }; -}; - -// ============================================================================ -// [asmjit::StringBuilder] -// ============================================================================ - -//! String builder. -//! -//! String builder was designed to be able to build a string using append like -//! operation to append numbers, other strings, or signle characters. It can -//! allocate it's own buffer or use a buffer created on the stack. -//! -//! String builder contains method specific to AsmJit functionality, used for -//! logging or HTML output. -class StringBuilder { -public: - ASMJIT_NONCOPYABLE(StringBuilder) - - //! \internal - //! - //! String operation. - ASMJIT_ENUM(OpType) { - kStringOpSet = 0, //!< Replace the current string by a given content. - kStringOpAppend = 1 //!< Append a given content to the current string. - }; - - //! \internal - //! - //! String format flags. - ASMJIT_ENUM(StringFormatFlags) { - kStringFormatShowSign = 0x00000001, - kStringFormatShowSpace = 0x00000002, - kStringFormatAlternate = 0x00000004, - kStringFormatSigned = 0x80000000 - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_API StringBuilder() noexcept; - ASMJIT_API ~StringBuilder() noexcept; - - ASMJIT_INLINE StringBuilder(const _NoInit&) noexcept {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get string builder capacity. - ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; } - //! Get length. - ASMJIT_INLINE size_t getLength() const noexcept { return _length; } - - //! Get null-terminated string data. - ASMJIT_INLINE char* getData() noexcept { return _data; } - //! Get null-terminated string data (const). - ASMJIT_INLINE const char* getData() const noexcept { return _data; } - - // -------------------------------------------------------------------------- - // [Prepare / Reserve] - // -------------------------------------------------------------------------- - - //! Prepare to set/append. - ASMJIT_API char* prepare(uint32_t op, size_t len) noexcept; - - //! Reserve `to` bytes in string builder. - ASMJIT_API Error reserve(size_t to) noexcept; - - // -------------------------------------------------------------------------- - // [Clear] - // -------------------------------------------------------------------------- - - //! Clear the content in String builder. - ASMJIT_API void clear() noexcept; - - // -------------------------------------------------------------------------- - // [Op] - // -------------------------------------------------------------------------- - - ASMJIT_API Error _opString(uint32_t op, const char* str, size_t len = Globals::kInvalidIndex) noexcept; - ASMJIT_API Error _opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept; - ASMJIT_API Error _opChar(uint32_t op, char c) noexcept; - ASMJIT_API Error _opChars(uint32_t op, char c, size_t n) noexcept; - ASMJIT_API Error _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept; - ASMJIT_API Error _opHex(uint32_t op, const void* data, size_t len) noexcept; - - // -------------------------------------------------------------------------- - // [Set] - // -------------------------------------------------------------------------- - - //! Replace the current string with `str` having `len` characters (or `kInvalidIndex` if it's null terminated). - ASMJIT_INLINE Error setString(const char* str, size_t len = Globals::kInvalidIndex) noexcept { return _opString(kStringOpSet, str, len); } - //! Replace the current content by a formatted string `fmt`. - ASMJIT_API Error setFormat(const char* fmt, ...) noexcept; - //! Replace the current content by a formatted string `fmt` (va_list version). - ASMJIT_INLINE Error setFormatVA(const char* fmt, va_list ap) noexcept { return _opVFormat(kStringOpSet, fmt, ap); } - - //! Replace the current content by a single `c` character. - ASMJIT_INLINE Error setChar(char c) noexcept { return _opChar(kStringOpSet, c); } - //! Replace the current content by `c` character `n` times. - ASMJIT_INLINE Error setChars(char c, size_t n) noexcept { return _opChars(kStringOpSet, c, n); } - - //! Replace the current content by a formatted integer `i` (signed). - ASMJIT_INLINE Error setInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { - return _opNumber(kStringOpSet, i, base, width, flags | kStringFormatSigned); - } - - //! Replace the current content by a formatted integer `i` (unsigned). - ASMJIT_INLINE Error setUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { - return _opNumber(kStringOpSet, i, base, width, flags); - } - - //! Replace the current content by the given `data` converted to a HEX string. - ASMJIT_INLINE Error setHex(const void* data, size_t len) noexcept { - return _opHex(kStringOpSet, data, len); - } - - // -------------------------------------------------------------------------- - // [Append] - // -------------------------------------------------------------------------- - - //! Append string `str` having `len` characters (or `kInvalidIndex` if it's null terminated). - ASMJIT_INLINE Error appendString(const char* str, size_t len = Globals::kInvalidIndex) noexcept { return _opString(kStringOpAppend, str, len); } - //! Append a formatted string `fmt`. - ASMJIT_API Error appendFormat(const char* fmt, ...) noexcept; - //! Append a formatted string `fmt` (va_list version). - ASMJIT_INLINE Error appendFormatVA(const char* fmt, va_list ap) noexcept { return _opVFormat(kStringOpAppend, fmt, ap); } - - //! Append a single `c` character. - ASMJIT_INLINE Error appendChar(char c) noexcept { return _opChar(kStringOpAppend, c); } - //! Append `c` character `n` times. - ASMJIT_INLINE Error appendChars(char c, size_t n) noexcept { return _opChars(kStringOpAppend, c, n); } - - //! Append `i`. - ASMJIT_INLINE Error appendInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { - return _opNumber(kStringOpAppend, static_cast(i), base, width, flags | kStringFormatSigned); - } - - //! Append `i`. - ASMJIT_INLINE Error appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { - return _opNumber(kStringOpAppend, i, base, width, flags); - } - - //! Append the given `data` converted to a HEX string. - ASMJIT_INLINE Error appendHex(const void* data, size_t len) noexcept { - return _opHex(kStringOpAppend, data, len); - } - - // -------------------------------------------------------------------------- - // [Eq] - // -------------------------------------------------------------------------- - - //! Check for equality with other `str` of length `len`. - ASMJIT_API bool eq(const char* str, size_t len = Globals::kInvalidIndex) const noexcept; - //! Check for equality with `other`. - ASMJIT_INLINE bool eq(const StringBuilder& other) const noexcept { return eq(other._data, other._length); } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool operator==(const StringBuilder& other) const noexcept { return eq(other); } - ASMJIT_INLINE bool operator!=(const StringBuilder& other) const noexcept { return !eq(other); } - - ASMJIT_INLINE bool operator==(const char* str) const noexcept { return eq(str); } - ASMJIT_INLINE bool operator!=(const char* str) const noexcept { return !eq(str); } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - char* _data; //!< String data. - size_t _length; //!< String length. - size_t _capacity; //!< String capacity. - size_t _canFree; //!< If the string data can be freed. -}; - -// ============================================================================ -// [asmjit::StringBuilderTmp] -// ============================================================================ - -//! Temporary string builder, has statically allocated `N` bytes. -template -class StringBuilderTmp : public StringBuilder { -public: - ASMJIT_NONCOPYABLE(StringBuilderTmp) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE StringBuilderTmp() noexcept : StringBuilder(NoInit) { - _data = _embeddedData; - _data[0] = 0; - - _length = 0; - _capacity = N; - _canFree = false; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! Embedded data. - char _embeddedData[static_cast( - N + 1 + sizeof(intptr_t)) & ~static_cast(sizeof(intptr_t) - 1)]; -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_STRING_H diff --git a/libs/asmjit/base/utils.cpp b/libs/asmjit/base/utils.cpp deleted file mode 100644 index 91e01700..00000000 --- a/libs/asmjit/base/utils.cpp +++ /dev/null @@ -1,176 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/utils.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [asmjit::Utils - Unit] -// ============================================================================ - -#if defined(ASMJIT_TEST) -UNIT(base_utils) { - uint32_t i; - - INFO("IntTraits<>"); - EXPECT(IntTraits::kIsSigned,"IntTraits should report signed"); - EXPECT(IntTraits::kIsSigned, "IntTraits should report signed"); - EXPECT(IntTraits::kIsSigned, "IntTraits should report signed"); - EXPECT(IntTraits::kIsSigned, "IntTraits should report signed"); - - EXPECT(IntTraits::kIsUnsigned, "IntTraits should report unsigned"); - EXPECT(IntTraits::kIsUnsigned, "IntTraits should report unsigned"); - EXPECT(IntTraits::kIsUnsigned, "IntTraits should report unsigned"); - EXPECT(IntTraits::kIsUnsigned, "IntTraits should report unsigned"); - - EXPECT(IntTraits::kIsSigned, "IntTraits should report signed"); - EXPECT(IntTraits::kIsUnsigned, "IntTraits should report unsigned"); - - EXPECT(IntTraits::kIsIntPtr, "IntTraits should report intptr_t type"); - EXPECT(IntTraits::kIsIntPtr, "IntTraits should report intptr_t type"); - - INFO("Utils::inInterval()"); - EXPECT(Utils::inInterval(11 , 10, 20) == true , "Utils::inInterval should return true if inside"); - EXPECT(Utils::inInterval(101, 10, 20) == false, "Utils::inInterval should return false if outside"); - - INFO("Utils::isInt8()"); - EXPECT(Utils::isInt8(-128) == true , "Utils::isInt8<> should return true if inside"); - EXPECT(Utils::isInt8( 127) == true , "Utils::isInt8<> should return true if inside"); - EXPECT(Utils::isInt8(-129) == false, "Utils::isInt8<> should return false if outside"); - EXPECT(Utils::isInt8( 128) == false, "Utils::isInt8<> should return false if outside"); - - INFO("Utils::isInt16()"); - EXPECT(Utils::isInt16(-32768) == true , "Utils::isInt16<> should return true if inside"); - EXPECT(Utils::isInt16( 32767) == true , "Utils::isInt16<> should return true if inside"); - EXPECT(Utils::isInt16(-32769) == false, "Utils::isInt16<> should return false if outside"); - EXPECT(Utils::isInt16( 32768) == false, "Utils::isInt16<> should return false if outside"); - - INFO("Utils::isInt32()"); - EXPECT(Utils::isInt32( 2147483647 ) == true, "Utils::isInt32 should return true if inside"); - EXPECT(Utils::isInt32(-2147483647 - 1) == true, "Utils::isInt32 should return true if inside"); - EXPECT(Utils::isInt32(ASMJIT_UINT64_C(2147483648)) == false, "Utils::isInt32 should return false if outside"); - EXPECT(Utils::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == false, "Utils::isInt32 should return false if outside"); - EXPECT(Utils::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false, "Utils::isInt32 should return false if outside"); - - INFO("Utils::isUInt8()"); - EXPECT(Utils::isUInt8(0) == true , "Utils::isUInt8<> should return true if inside"); - EXPECT(Utils::isUInt8(255) == true , "Utils::isUInt8<> should return true if inside"); - EXPECT(Utils::isUInt8(256) == false, "Utils::isUInt8<> should return false if outside"); - EXPECT(Utils::isUInt8(-1) == false, "Utils::isUInt8<> should return false if negative"); - - INFO("Utils::isUInt12()"); - EXPECT(Utils::isUInt12(0) == true , "Utils::isUInt12<> should return true if inside"); - EXPECT(Utils::isUInt12(4095) == true , "Utils::isUInt12<> should return true if inside"); - EXPECT(Utils::isUInt12(4096) == false, "Utils::isUInt12<> should return false if outside"); - EXPECT(Utils::isUInt12(-1) == false, "Utils::isUInt12<> should return false if negative"); - - INFO("Utils::isUInt16()"); - EXPECT(Utils::isUInt16(0) == true , "Utils::isUInt16<> should return true if inside"); - EXPECT(Utils::isUInt16(65535) == true , "Utils::isUInt16<> should return true if inside"); - EXPECT(Utils::isUInt16(65536) == false, "Utils::isUInt16<> should return false if outside"); - EXPECT(Utils::isUInt16(-1) == false, "Utils::isUInt16<> should return false if negative"); - - INFO("Utils::isUInt32()"); - EXPECT(Utils::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == true, "Utils::isUInt32 should return true if inside"); - EXPECT(Utils::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false, "Utils::isUInt32 should return false if outside"); - EXPECT(Utils::isUInt32(-1) == false, "Utils::isUInt32 should return false if negative"); - - INFO("Utils::isPower2()"); - for (i = 0; i < 64; i++) { - EXPECT(Utils::isPowerOf2(static_cast(1) << i) == true, - "Utils::isPower2() didn't report power of 2"); - EXPECT(Utils::isPowerOf2((static_cast(1) << i) ^ 0x001101) == false, - "Utils::isPower2() didn't report not power of 2"); - } - - INFO("Utils::mask()"); - for (i = 0; i < 32; i++) { - EXPECT(Utils::mask(i) == (1 << i), - "Utils::mask(%u) should return %X", i, (1 << i)); - } - - INFO("Utils::bits()"); - for (i = 0; i < 32; i++) { - uint32_t expectedBits = 0; - - for (uint32_t b = 0; b < i; b++) - expectedBits |= static_cast(1) << b; - - EXPECT(Utils::bits(i) == expectedBits, - "Utils::bits(%u) should return %X", i, expectedBits); - } - - INFO("Utils::hasBit()"); - for (i = 0; i < 32; i++) { - EXPECT(Utils::hasBit((1 << i), i) == true, - "Utils::hasBit(%X, %u) should return true", (1 << i), i); - } - - INFO("Utils::bitCount()"); - for (i = 0; i < 32; i++) { - EXPECT(Utils::bitCount((1 << i)) == 1, - "Utils::bitCount(%X) should return true", (1 << i)); - } - EXPECT(Utils::bitCount(0x000000F0) == 4, ""); - EXPECT(Utils::bitCount(0x10101010) == 4, ""); - EXPECT(Utils::bitCount(0xFF000000) == 8, ""); - EXPECT(Utils::bitCount(0xFFFFFFF7) == 31, ""); - EXPECT(Utils::bitCount(0x7FFFFFFF) == 31, ""); - - INFO("Utils::findFirstBit()"); - for (i = 0; i < 32; i++) { - EXPECT(Utils::findFirstBit((1 << i)) == i, - "Utils::findFirstBit(%X) should return %u", (1 << i), i); - } - - INFO("Utils::keepNOnesFromRight()"); - EXPECT(Utils::keepNOnesFromRight(0xF, 1) == 0x1, ""); - EXPECT(Utils::keepNOnesFromRight(0xF, 2) == 0x3, ""); - EXPECT(Utils::keepNOnesFromRight(0xF, 3) == 0x7, ""); - EXPECT(Utils::keepNOnesFromRight(0x5, 2) == 0x5, ""); - EXPECT(Utils::keepNOnesFromRight(0xD, 2) == 0x5, ""); - - INFO("Utils::isAligned()"); - EXPECT(Utils::isAligned(0xFFFF, 4) == false, ""); - EXPECT(Utils::isAligned(0xFFF4, 4) == true , ""); - EXPECT(Utils::isAligned(0xFFF8, 8) == true , ""); - EXPECT(Utils::isAligned(0xFFF0, 16) == true , ""); - - INFO("Utils::alignTo()"); - EXPECT(Utils::alignTo(0xFFFF, 4) == 0x10000, ""); - EXPECT(Utils::alignTo(0xFFF4, 4) == 0x0FFF4, ""); - EXPECT(Utils::alignTo(0xFFF8, 8) == 0x0FFF8, ""); - EXPECT(Utils::alignTo(0xFFF0, 16) == 0x0FFF0, ""); - EXPECT(Utils::alignTo(0xFFF0, 32) == 0x10000, ""); - - INFO("Utils::alignToPowerOf2()"); - EXPECT(Utils::alignToPowerOf2(0xFFFF) == 0x10000, ""); - EXPECT(Utils::alignToPowerOf2(0xF123) == 0x10000, ""); - EXPECT(Utils::alignToPowerOf2(0x0F00) == 0x01000, ""); - EXPECT(Utils::alignToPowerOf2(0x0100) == 0x00100, ""); - EXPECT(Utils::alignToPowerOf2(0x1001) == 0x02000, ""); - - INFO("Utils::alignDiff()"); - EXPECT(Utils::alignDiff(0xFFFF, 4) == 1, ""); - EXPECT(Utils::alignDiff(0xFFF4, 4) == 0, ""); - EXPECT(Utils::alignDiff(0xFFF8, 8) == 0, ""); - EXPECT(Utils::alignDiff(0xFFF0, 16) == 0, ""); - EXPECT(Utils::alignDiff(0xFFF0, 32) == 16, ""); -} -#endif // ASMJIT_TEST - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/utils.h b/libs/asmjit/base/utils.h deleted file mode 100644 index b926ceae..00000000 --- a/libs/asmjit/base/utils.h +++ /dev/null @@ -1,1358 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_UTILS_H -#define _ASMJIT_BASE_UTILS_H - -// [Dependencies] -#include "../base/globals.h" - -#if ASMJIT_CC_MSC_GE(14, 0, 0) -# include -#endif // ASMJIT_OS_WINDOWS - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::IntTraits] -// ============================================================================ - -//! \internal -//! \{ -template -struct IntTraitsPrivate {}; // Let it fail if not specialized! - -template<> struct IntTraitsPrivate<1, 0> { typedef int IntType; typedef int8_t SignedType; typedef uint8_t UnsignedType; }; -template<> struct IntTraitsPrivate<1, 1> { typedef int IntType; typedef int8_t SignedType; typedef uint8_t UnsignedType; }; - -template<> struct IntTraitsPrivate<2, 0> { typedef int IntType; typedef int16_t SignedType; typedef uint16_t UnsignedType; }; -template<> struct IntTraitsPrivate<2, 1> { typedef int IntType; typedef int16_t SignedType; typedef uint16_t UnsignedType; }; - -template<> struct IntTraitsPrivate<4, 0> { typedef int64_t IntType; typedef int32_t SignedType; typedef uint32_t UnsignedType; }; -template<> struct IntTraitsPrivate<4, 1> { typedef int IntType; typedef int32_t SignedType; typedef uint32_t UnsignedType; }; - -template<> struct IntTraitsPrivate<8, 0> { typedef int64_t IntType; typedef int64_t SignedType; typedef uint64_t UnsignedType; }; -template<> struct IntTraitsPrivate<8, 1> { typedef int64_t IntType; typedef int64_t SignedType; typedef uint64_t UnsignedType; }; - -//! \internal -template -struct IntTraits { - enum { - kIsSigned = static_cast(~static_cast(0)) < static_cast(0), - kIsUnsigned = !kIsSigned, - kIs8Bit = sizeof(T) == 1, - kIs16Bit = sizeof(T) == 2, - kIs32Bit = sizeof(T) == 4, - kIs64Bit = sizeof(T) == 8, - kIsIntPtr = sizeof(T) == sizeof(intptr_t) - }; - - typedef typename IntTraitsPrivate::IntType IntType; - typedef typename IntTraitsPrivate::SignedType SignedType; - typedef typename IntTraitsPrivate::UnsignedType UnsignedType; - - //! Get a minimum value of `T`. - static ASMJIT_INLINE T minValue() noexcept { - return kIsSigned ? T((~static_cast(0) >> 1) + static_cast(1)) : T(0); - } - - //! Get a maximum value of `T`. - static ASMJIT_INLINE T maxValue() noexcept { - return kIsSigned ? T(~static_cast(0) >> 1) : ~T(0); - } -}; - -//! \} - -// ============================================================================ -// [asmjit::Utils] -// ============================================================================ - -//! AsmJit utilities - integer, string, etc... -namespace Utils { - // -------------------------------------------------------------------------- - // [Float <-> Int] - // -------------------------------------------------------------------------- - - //! \internal - union FloatBits { - int32_t i; - float f; - }; - - //! \internal - union DoubleBits { - int64_t i; - double d; - }; - - //! Bit-cast `float` to a 32-bit integer. - static ASMJIT_INLINE int32_t floatAsInt(float f) noexcept { FloatBits m; m.f = f; return m.i; } - //! Bit-cast 32-bit integer to `float`. - static ASMJIT_INLINE float intAsFloat(int32_t i) noexcept { FloatBits m; m.i = i; return m.f; } - - //! Bit-cast `double` to a 64-bit integer. - static ASMJIT_INLINE int64_t doubleAsInt(double d) noexcept { DoubleBits m; m.d = d; return m.i; } - //! Bit-cast 64-bit integer to `double`. - static ASMJIT_INLINE double intAsDouble(int64_t i) noexcept { DoubleBits m; m.i = i; return m.d; } - - // -------------------------------------------------------------------------- - // [Pack / Unpack] - // -------------------------------------------------------------------------- - - //! Pack four 8-bit integer into a 32-bit integer as it is an array of `{b0,b1,b2,b3}`. - static ASMJIT_INLINE uint32_t pack32_4x8(uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) noexcept { - return ASMJIT_PACK32_4x8(b0, b1, b2, b3); - } - - //! Pack two 32-bit integer into a 64-bit integer as it is an array of `{u0,u1}`. - static ASMJIT_INLINE uint64_t pack64_2x32(uint32_t u0, uint32_t u1) noexcept { - return ASMJIT_ARCH_LE ? (static_cast(u1) << 32) + u0 - : (static_cast(u0) << 32) + u1; - } - - // -------------------------------------------------------------------------- - // [Position of byte (in bit-shift)] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE uint32_t byteShiftOfDWordStruct(uint32_t index) noexcept { - if (ASMJIT_ARCH_LE) - return index * 8; - else - return (sizeof(uint32_t) - 1 - index) * 8; - } - - // -------------------------------------------------------------------------- - // [Lower/Upper] - // -------------------------------------------------------------------------- - - template - static ASMJIT_INLINE T toLower(T c) noexcept { return c ^ (static_cast(c >= T('A') && c <= T('Z')) << 5); } - template - static ASMJIT_INLINE T toUpper(T c) noexcept { return c ^ (static_cast(c >= T('a') && c <= T('z')) << 5); } - - // -------------------------------------------------------------------------- - // [Hash] - // -------------------------------------------------------------------------- - - // \internal - static ASMJIT_INLINE uint32_t hashRound(uint32_t hash, uint32_t c) noexcept { return hash * 65599 + c; } - - // Get a hash of the given string `str` of `len` length. Length must be valid - // as this function doesn't check for a null terminator and allows it in the - // middle of the string. - static ASMJIT_INLINE uint32_t hashString(const char* str, size_t len) noexcept { - uint32_t hVal = 0; - for (uint32_t i = 0; i < len; i++) - hVal = hashRound(hVal, str[i]); - return hVal; - } - - // -------------------------------------------------------------------------- - // [Swap] - // -------------------------------------------------------------------------- - - template - static ASMJIT_INLINE void swap(T& a, T& b) noexcept { - T tmp = a; - a = b; - b = tmp; - } - - // -------------------------------------------------------------------------- - // [InInterval] - // -------------------------------------------------------------------------- - - //! Get whether `x` is greater than or equal to `a` and lesses than or equal to `b`. - template - static ASMJIT_INLINE bool inInterval(T x, T a, T b) noexcept { - return x >= a && x <= b; - } - - // -------------------------------------------------------------------------- - // [AsInt] - // -------------------------------------------------------------------------- - - //! Map an integer `x` of type `T` to `int` or `int64_t` depending on the - //! type. Used internally by AsmJit to dispatch arguments that can be of - //! arbitrary integer type into a function argument that is either `int` or - //! `int64_t`. - template - static ASMJIT_INLINE typename IntTraits::IntType asInt(T x) noexcept { - return static_cast::IntType>(x); - } - - // -------------------------------------------------------------------------- - // [IsInt / IsUInt] - // -------------------------------------------------------------------------- - - //! Get whether the given integer `x` can be casted to a 4-bit signed integer. - template - static ASMJIT_INLINE bool isInt4(T x) noexcept { - typedef typename IntTraits::SignedType SignedType; - typedef typename IntTraits::UnsignedType UnsignedType; - - if (IntTraits::kIsSigned) - return inInterval(SignedType(x), -8, 7); - else - return UnsignedType(x) <= UnsignedType(7U); - } - - //! Get whether the given integer `x` can be casted to an 8-bit signed integer. - template - static ASMJIT_INLINE bool isInt8(T x) noexcept { - typedef typename IntTraits::SignedType SignedType; - typedef typename IntTraits::UnsignedType UnsignedType; - - if (IntTraits::kIsSigned) - return sizeof(T) <= 1 || inInterval(SignedType(x), -128, 127); - else - return UnsignedType(x) <= UnsignedType(127U); - } - - //! Get whether the given integer `x` can be casted to a 16-bit signed integer. - template - static ASMJIT_INLINE bool isInt16(T x) noexcept { - typedef typename IntTraits::SignedType SignedType; - typedef typename IntTraits::UnsignedType UnsignedType; - - if (IntTraits::kIsSigned) - return sizeof(T) <= 2 || inInterval(SignedType(x), -32768, 32767); - else - return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(32767U); - } - - //! Get whether the given integer `x` can be casted to a 32-bit signed integer. - template - static ASMJIT_INLINE bool isInt32(T x) noexcept { - typedef typename IntTraits::SignedType SignedType; - typedef typename IntTraits::UnsignedType UnsignedType; - - if (IntTraits::kIsSigned) - return sizeof(T) <= 4 || inInterval(SignedType(x), -2147483647 - 1, 2147483647); - else - return sizeof(T) <= 2 || UnsignedType(x) <= UnsignedType(2147483647U); - } - - //! Get whether the given integer `x` can be casted to a 4-bit unsigned integer. - template - static ASMJIT_INLINE bool isUInt4(T x) noexcept { - typedef typename IntTraits::UnsignedType UnsignedType; - - if (IntTraits::kIsSigned) - return x >= T(0) && x <= T(15); - else - return UnsignedType(x) <= UnsignedType(15U); - } - - //! Get whether the given integer `x` can be casted to an 8-bit unsigned integer. - template - static ASMJIT_INLINE bool isUInt8(T x) noexcept { - typedef typename IntTraits::UnsignedType UnsignedType; - - if (IntTraits::kIsSigned) - return x >= T(0) && (sizeof(T) <= 1 ? true : x <= T(255)); - else - return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(255U); - } - - //! Get whether the given integer `x` can be casted to a 12-bit unsigned integer (ARM specific). - template - static ASMJIT_INLINE bool isUInt12(T x) noexcept { - typedef typename IntTraits::UnsignedType UnsignedType; - - if (IntTraits::kIsSigned) - return x >= T(0) && (sizeof(T) <= 1 ? true : x <= T(4095)); - else - return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(4095U); - } - - //! Get whether the given integer `x` can be casted to a 16-bit unsigned integer. - template - static ASMJIT_INLINE bool isUInt16(T x) noexcept { - typedef typename IntTraits::UnsignedType UnsignedType; - - if (IntTraits::kIsSigned) - return x >= T(0) && (sizeof(T) <= 2 ? true : x <= T(65535)); - else - return sizeof(T) <= 2 || UnsignedType(x) <= UnsignedType(65535U); - } - - //! Get whether the given integer `x` can be casted to a 32-bit unsigned integer. - template - static ASMJIT_INLINE bool isUInt32(T x) noexcept { - typedef typename IntTraits::UnsignedType UnsignedType; - - if (IntTraits::kIsSigned) - return x >= T(0) && (sizeof(T) <= 4 ? true : x <= T(4294967295U)); - else - return sizeof(T) <= 4 || UnsignedType(x) <= UnsignedType(4294967295U); - } - - // -------------------------------------------------------------------------- - // [IsPowerOf2] - // -------------------------------------------------------------------------- - - //! Get whether the `n` value is a power of two (only one bit is set). - template - static ASMJIT_INLINE bool isPowerOf2(T n) noexcept { - return n != 0 && (n & (n - 1)) == 0; - } - - // -------------------------------------------------------------------------- - // [Mask] - // -------------------------------------------------------------------------- - - //! Generate a bit-mask that has `x` bit set. - static ASMJIT_INLINE uint32_t mask(uint32_t x) noexcept { - ASMJIT_ASSERT(x < 32); - return static_cast(1) << x; - } - - //! Generate a bit-mask that has `x0` and `x1` bits set. - static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1) noexcept { - return mask(x0) | mask(x1); - } - - //! Generate a bit-mask that has `x0`, `x1` and `x2` bits set. - static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2) noexcept { - return mask(x0, x1) | mask(x2); - } - - //! Generate a bit-mask that has `x0`, `x1`, `x2` and `x3` bits set. - static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) noexcept { - return mask(x0, x1) | mask(x2, x3); - } - - //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3` and `x4` bits set. - static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4) noexcept { - return mask(x0, x1) | mask(x2, x3) | mask(x4); - } - - //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4` and `x5` bits set. - static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5) noexcept { - return mask(x0, x1) | mask(x2, x3) | mask(x4, x5); - } - - //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5` and `x6` bits set. - static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6) noexcept { - return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6); - } - - //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6` and `x7` bits set. - static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) noexcept { - return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6, x7); - } - - //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7` and `x8` bits set. - static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8) noexcept { - return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6, x7) | mask(x8); - } - - //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7`, `x8` and `x9` bits set. - static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8, uint32_t x9) noexcept { - return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6, x7) | mask(x8, x9); - } - - // -------------------------------------------------------------------------- - // [Bits] - // -------------------------------------------------------------------------- - - //! Generate a bit-mask that has `x` least significant bits set. - static ASMJIT_INLINE uint32_t bits(uint32_t x) noexcept { - // Shifting more bits than the type has results in undefined behavior. In - // such case asmjit trashes the result by ORing with `overflow` mask, which - // discards the undefined value returned by the shift. - uint32_t overflow = static_cast( - -static_cast(x >= sizeof(uint32_t) * 8)); - - return ((static_cast(1) << x) - 1U) | overflow; - } - - // -------------------------------------------------------------------------- - // [HasBit] - // -------------------------------------------------------------------------- - - //! Get whether `x` has bit `n` set. - template - static ASMJIT_INLINE bool hasBit(T x, Index n) noexcept { - return (x & (static_cast(1) << n)) != 0; - } - - // -------------------------------------------------------------------------- - // [BitCount] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE uint32_t bitCountSlow(uint32_t x) noexcept { - // From: http://graphics.stanford.edu/~seander/bithacks.html - x = x - ((x >> 1) & 0x55555555U); - x = (x & 0x33333333U) + ((x >> 2) & 0x33333333U); - return (((x + (x >> 4)) & 0x0F0F0F0FU) * 0x01010101U) >> 24; - } - - //! Get count of bits in `x`. - static ASMJIT_INLINE uint32_t bitCount(uint32_t x) noexcept { -#if ASMJIT_CC_GCC || ASMJIT_CC_CLANG - return __builtin_popcount(x); -#else - return bitCountSlow(x); -#endif - } - - // -------------------------------------------------------------------------- - // [FirstBitOf] - // -------------------------------------------------------------------------- - - template - struct FirstBitOfTImpl { - enum { - _shift = (In & ASMJIT_UINT64_C(0x0000FFFFFFFFFFFF)) == 0 ? 48 : - (In & ASMJIT_UINT64_C(0x00000000FFFFFFFF)) == 0 ? 32 : - (In & ASMJIT_UINT64_C(0x000000000000FFFF)) == 0 ? 16 : 0, - - kValue = ((In >> _shift) & 0x0001) ? (_shift + 0) : - ((In >> _shift) & 0x0002) ? (_shift + 1) : - ((In >> _shift) & 0x0004) ? (_shift + 2) : - ((In >> _shift) & 0x0008) ? (_shift + 3) : - ((In >> _shift) & 0x0010) ? (_shift + 4) : - ((In >> _shift) & 0x0020) ? (_shift + 5) : - ((In >> _shift) & 0x0040) ? (_shift + 6) : - ((In >> _shift) & 0x0080) ? (_shift + 7) : - ((In >> _shift) & 0x0100) ? (_shift + 8) : - ((In >> _shift) & 0x0200) ? (_shift + 9) : - ((In >> _shift) & 0x0400) ? (_shift + 10) : - ((In >> _shift) & 0x0800) ? (_shift + 11) : - ((In >> _shift) & 0x1000) ? (_shift + 12) : - ((In >> _shift) & 0x2000) ? (_shift + 13) : - ((In >> _shift) & 0x4000) ? (_shift + 14) : - ((In >> _shift) & 0x8000) ? (_shift + 15) : 0 - }; - }; - - template<> - struct FirstBitOfTImpl<0> {}; - - template - static ASMJIT_INLINE uint32_t firstBitOfT() noexcept { return FirstBitOfTImpl::kValue; } - - // -------------------------------------------------------------------------- - // [FindFirstBit] - // -------------------------------------------------------------------------- - - //! \internal - static ASMJIT_INLINE uint32_t findFirstBitSlow(uint32_t mask) noexcept { - // This is a reference (slow) implementation of `findFirstBit()`, used when - // we don't have a C++ compiler support. The implementation speed has been - // improved to check for 2 bits per iteration. - uint32_t i = 1; - - while (mask != 0) { - uint32_t two = mask & 0x3; - if (two != 0x0) - return i - (two & 0x1); - - i += 2; - mask >>= 2; - } - - return 0xFFFFFFFFU; - } - - //! Find a first bit in `mask`. - static ASMJIT_INLINE uint32_t findFirstBit(uint32_t mask) noexcept { -#if ASMJIT_CC_MSC_GE(14, 0, 0) && (ASMJIT_ARCH_X86 || ASMJIT_ARCH_ARM32 || \ - ASMJIT_ARCH_X64 || ASMJIT_ARCH_ARM64) - DWORD i; - if (_BitScanForward(&i, mask)) - return static_cast(i); - else - return 0xFFFFFFFFU; -#elif ASMJIT_CC_GCC_GE(3, 4, 6) || ASMJIT_CC_CLANG - if (mask) - return __builtin_ctz(mask); - else - return 0xFFFFFFFFU; -#else - return findFirstBitSlow(mask); -#endif - } - - // -------------------------------------------------------------------------- - // [Misc] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE uint32_t keepNOnesFromRight(uint32_t mask, uint32_t nBits) noexcept { - uint32_t m = 0x1; - - do { - nBits -= (mask & m) != 0; - m <<= 1; - if (nBits == 0) { - m -= 1; - mask &= m; - break; - } - } while (m); - - return mask; - } - - static ASMJIT_INLINE uint32_t indexNOnesFromRight(uint8_t* dst, uint32_t mask, uint32_t nBits) noexcept { - uint32_t totalBits = nBits; - uint8_t i = 0; - uint32_t m = 0x1; - - do { - if (mask & m) { - *dst++ = i; - if (--nBits == 0) - break; - } - - m <<= 1; - i++; - } while (m); - - return totalBits - nBits; - } - - // -------------------------------------------------------------------------- - // [Alignment] - // -------------------------------------------------------------------------- - - template - static ASMJIT_INLINE bool isAligned(X base, Y alignment) noexcept { - typedef typename IntTraitsPrivate::UnsignedType U; - return ((U)base % (U)alignment) == 0; - } - - template - static ASMJIT_INLINE X alignTo(X x, Y alignment) noexcept { - typedef typename IntTraitsPrivate::UnsignedType U; - return (X)( ((U)x + (U)(alignment - 1)) & ~(static_cast(alignment) - 1) ); - } - - //! Get delta required to align `base` to `alignment`. - template - static ASMJIT_INLINE X alignDiff(X base, Y alignment) noexcept { - return alignTo(base, alignment) - base; - } - - template - static ASMJIT_INLINE T alignToPowerOf2(T base) noexcept { - // Implementation is from "Hacker's Delight" by Henry S. Warren, Jr. - base -= 1; - -#if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable: 4293) -#endif // _MSC_VER - - base = base | (base >> 1); - base = base | (base >> 2); - base = base | (base >> 4); - - // 8/16/32 constants are multiplied by the condition to prevent a compiler - // complaining about the 'shift count >= type width' (GCC). - if (sizeof(T) >= 2) base = base | (base >> ( 8 * (sizeof(T) >= 2))); // Base >> 8. - if (sizeof(T) >= 4) base = base | (base >> (16 * (sizeof(T) >= 4))); // Base >> 16. - if (sizeof(T) >= 8) base = base | (base >> (32 * (sizeof(T) >= 8))); // Base >> 32. - -#if defined(_MSC_VER) -# pragma warning(pop) -#endif // _MSC_VER - - return base + 1; - } - - // -------------------------------------------------------------------------- - // [String] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE size_t strLen(const char* s, size_t maxlen) noexcept { - size_t i; - for (i = 0; i < maxlen; i++) - if (!s[i]) - break; - return i; - } - - static ASMJIT_INLINE const char* findPackedString(const char* p, uint32_t id) noexcept { - uint32_t i = 0; - while (i < id) { - while (p[0]) - p++; - p++; - i++; - } - return p; - } - - //! \internal - //! - //! Compare two instruction names. - //! - //! `a` is a null terminated instruction name from `???InstDB::nameData[]` table. - //! `b` is a non-null terminated instruction name passed to `???Inst::getIdByName()`. - static ASMJIT_INLINE int cmpInstName(const char* a, const char* b, size_t len) noexcept { - for (size_t i = 0; i < len; i++) { - int c = static_cast(static_cast(a[i])) - - static_cast(static_cast(b[i])) ; - if (c != 0) return c; - } - - return static_cast(a[len]); - } - - // -------------------------------------------------------------------------- - // [BSwap] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE uint32_t byteswap32(uint32_t x) noexcept { -#if ASMJIT_CC_MSC - return static_cast(_byteswap_ulong(x)); -#elif ASMJIT_CC_GCC_GE(4, 3, 0) || ASMJIT_CC_CLANG_GE(2, 6, 0) - return __builtin_bswap32(x); -#else - uint32_t y = x & 0x00FFFF00U; - x = (x << 24) + (x >> 24); - y = (y << 8) + (y >> 8); - return x + (y & 0x00FFFF00U); -#endif - } - - // -------------------------------------------------------------------------- - // [ReadMem] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE uint32_t readU8(const void* p) noexcept { - return static_cast(static_cast(p)[0]); - } - - static ASMJIT_INLINE int32_t readI8(const void* p) noexcept { - return static_cast(static_cast(p)[0]); - } - - template - static ASMJIT_INLINE uint32_t readU16xLE(const void* p) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { - return static_cast(static_cast(p)[0]); - } - else { - uint32_t x = static_cast(static_cast(p)[0]); - uint32_t y = static_cast(static_cast(p)[1]); - return x + (y << 8); - } - } - - template - static ASMJIT_INLINE uint32_t readU16xBE(const void* p) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { - return static_cast(static_cast(p)[0]); - } - else { - uint32_t x = static_cast(static_cast(p)[0]); - uint32_t y = static_cast(static_cast(p)[1]); - return (x << 8) + y; - } - } - - template - static ASMJIT_INLINE uint32_t readU16x(const void* p) noexcept { - return ASMJIT_ARCH_LE ? readU16xLE(p) : readU16xBE(p); - } - - template - static ASMJIT_INLINE int32_t readI16xLE(const void* p) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { - return static_cast(static_cast(p)[0]); - } - else { - int32_t x = static_cast(static_cast(p)[0]); - int32_t y = static_cast(static_cast(p)[1]); - return x + (y << 8); - } - } - - template - static ASMJIT_INLINE int32_t readI16xBE(const void* p) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { - return static_cast(static_cast(p)[0]); - } - else { - int32_t x = static_cast(static_cast(p)[0]); - int32_t y = static_cast(static_cast(p)[1]); - return (x << 8) + y; - } - } - - template - static ASMJIT_INLINE int32_t readI16x(const void* p) noexcept { - return ASMJIT_ARCH_LE ? readI16xLE(p) : readI16xBE(p); - } - - static ASMJIT_INLINE uint32_t readU16aLE(const void* p) noexcept { return readU16xLE<2>(p); } - static ASMJIT_INLINE uint32_t readU16uLE(const void* p) noexcept { return readU16xLE<0>(p); } - - static ASMJIT_INLINE uint32_t readU16aBE(const void* p) noexcept { return readU16xBE<2>(p); } - static ASMJIT_INLINE uint32_t readU16uBE(const void* p) noexcept { return readU16xBE<0>(p); } - - static ASMJIT_INLINE uint32_t readU16a(const void* p) noexcept { return readU16x<2>(p); } - static ASMJIT_INLINE uint32_t readU16u(const void* p) noexcept { return readU16x<0>(p); } - - static ASMJIT_INLINE int32_t readI16aLE(const void* p) noexcept { return readI16xLE<2>(p); } - static ASMJIT_INLINE int32_t readI16uLE(const void* p) noexcept { return readI16xLE<0>(p); } - - static ASMJIT_INLINE int32_t readI16aBE(const void* p) noexcept { return readI16xBE<2>(p); } - static ASMJIT_INLINE int32_t readI16uBE(const void* p) noexcept { return readI16xBE<0>(p); } - - static ASMJIT_INLINE int32_t readI16a(const void* p) noexcept { return readI16x<2>(p); } - static ASMJIT_INLINE int32_t readI16u(const void* p) noexcept { return readI16x<0>(p); } - - template - static ASMJIT_INLINE uint32_t readU32xLE(const void* p) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) { - uint32_t x = static_cast(p)[0]; - return ASMJIT_ARCH_LE ? x : byteswap32(x); - } - else { - uint32_t x = readU16xLE(static_cast(p) + 0); - uint32_t y = readU16xLE(static_cast(p) + 2); - return x + (y << 16); - } - } - - template - static ASMJIT_INLINE uint32_t readU32xBE(const void* p) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) { - uint32_t x = static_cast(p)[0]; - return ASMJIT_ARCH_BE ? x : byteswap32(x); - } - else { - uint32_t x = readU16xBE(static_cast(p) + 0); - uint32_t y = readU16xBE(static_cast(p) + 2); - return (x << 16) + y; - } - } - - template - static ASMJIT_INLINE uint32_t readU32x(const void* p) noexcept { - return ASMJIT_ARCH_LE ? readU32xLE(p) : readU32xBE(p); - } - - template - static ASMJIT_INLINE int32_t readI32xLE(const void* p) noexcept { - return static_cast(readU32xLE(p)); - } - - template - static ASMJIT_INLINE int32_t readI32xBE(const void* p) noexcept { - return static_cast(readU32xBE(p)); - } - - template - static ASMJIT_INLINE int32_t readI32x(const void* p) noexcept { - return ASMJIT_ARCH_LE ? readI32xLE(p) : readI32xBE(p); - } - - static ASMJIT_INLINE uint32_t readU32a(const void* p) noexcept { return readU32x<4>(p); } - static ASMJIT_INLINE uint32_t readU32u(const void* p) noexcept { return readU32x<0>(p); } - - static ASMJIT_INLINE uint32_t readU32aLE(const void* p) noexcept { return readU32xLE<4>(p); } - static ASMJIT_INLINE uint32_t readU32uLE(const void* p) noexcept { return readU32xLE<0>(p); } - - static ASMJIT_INLINE uint32_t readU32aBE(const void* p) noexcept { return readU32xBE<4>(p); } - static ASMJIT_INLINE uint32_t readU32uBE(const void* p) noexcept { return readU32xBE<0>(p); } - - static ASMJIT_INLINE int32_t readI32a(const void* p) noexcept { return readI32x<4>(p); } - static ASMJIT_INLINE int32_t readI32u(const void* p) noexcept { return readI32x<0>(p); } - - static ASMJIT_INLINE int32_t readI32aLE(const void* p) noexcept { return readI32xLE<4>(p); } - static ASMJIT_INLINE int32_t readI32uLE(const void* p) noexcept { return readI32xLE<0>(p); } - - static ASMJIT_INLINE int32_t readI32aBE(const void* p) noexcept { return readI32xBE<4>(p); } - static ASMJIT_INLINE int32_t readI32uBE(const void* p) noexcept { return readI32xBE<0>(p); } - - template - static ASMJIT_INLINE uint64_t readU64xLE(const void* p) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) { - return static_cast(p)[0]; - } - else { - uint32_t x = readU32xLE(static_cast(p) + 0); - uint32_t y = readU32xLE(static_cast(p) + 4); - return static_cast(x) + (static_cast(y) << 32); - } - } - - template - static ASMJIT_INLINE uint64_t readU64xBE(const void* p) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) { - return static_cast(p)[0]; - } - else { - uint32_t x = readU32xLE(static_cast(p) + 0); - uint32_t y = readU32xLE(static_cast(p) + 4); - return (static_cast(x) << 32) + static_cast(y); - } - } - - template - static ASMJIT_INLINE uint64_t readU64x(const void* p) noexcept { - return ASMJIT_ARCH_LE ? readU64xLE(p) : readU64xBE(p); - } - - template - static ASMJIT_INLINE int64_t readI64xLE(const void* p) noexcept { - return static_cast(readU64xLE(p)); - } - - template - static ASMJIT_INLINE int64_t readI64xBE(const void* p) noexcept { - return static_cast(readU64xBE(p)); - } - - template - static ASMJIT_INLINE int64_t readI64x(const void* p) noexcept { - return ASMJIT_ARCH_LE ? readI64xLE(p) : readI64xBE(p); - } - - static ASMJIT_INLINE uint64_t readU64a(const void* p) noexcept { return readU64x<8>(p); } - static ASMJIT_INLINE uint64_t readU64u(const void* p) noexcept { return readU64x<0>(p); } - - static ASMJIT_INLINE uint64_t readU64aLE(const void* p) noexcept { return readU64xLE<8>(p); } - static ASMJIT_INLINE uint64_t readU64uLE(const void* p) noexcept { return readU64xLE<0>(p); } - - static ASMJIT_INLINE uint64_t readU64aBE(const void* p) noexcept { return readU64xBE<8>(p); } - static ASMJIT_INLINE uint64_t readU64uBE(const void* p) noexcept { return readU64xBE<0>(p); } - - static ASMJIT_INLINE int64_t readI64a(const void* p) noexcept { return readI64x<8>(p); } - static ASMJIT_INLINE int64_t readI64u(const void* p) noexcept { return readI64x<0>(p); } - - static ASMJIT_INLINE int64_t readI64aLE(const void* p) noexcept { return readI64xLE<8>(p); } - static ASMJIT_INLINE int64_t readI64uLE(const void* p) noexcept { return readI64xLE<0>(p); } - - static ASMJIT_INLINE int64_t readI64aBE(const void* p) noexcept { return readI64xBE<8>(p); } - static ASMJIT_INLINE int64_t readI64uBE(const void* p) noexcept { return readI64xBE<0>(p); } - - // -------------------------------------------------------------------------- - // [WriteMem] - // -------------------------------------------------------------------------- - - static ASMJIT_INLINE void writeU8(void* p, uint32_t x) noexcept { - static_cast(p)[0] = static_cast(x & 0xFFU); - } - - static ASMJIT_INLINE void writeI8(void* p, int32_t x) noexcept { - static_cast(p)[0] = static_cast(x & 0xFF); - } - - template - static ASMJIT_INLINE void writeU16xLE(void* p, uint32_t x) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { - static_cast(p)[0] = static_cast(x & 0xFFFFU); - } - else { - static_cast(p)[0] = static_cast((x ) & 0xFFU); - static_cast(p)[1] = static_cast((x >> 8) & 0xFFU); - } - } - - template - static ASMJIT_INLINE void writeU16xBE(void* p, uint32_t x) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) { - static_cast(p)[0] = static_cast(x & 0xFFFFU); - } - else { - static_cast(p)[0] = static_cast((x >> 8) & 0xFFU); - static_cast(p)[1] = static_cast((x ) & 0xFFU); - } - } - - template - static ASMJIT_INLINE void writeU16x(void* p, uint32_t x) noexcept { - if (ASMJIT_ARCH_LE) - writeU16xLE(p, x); - else - writeU16xBE(p, x); - } - - template - static ASMJIT_INLINE void writeI16xLE(void* p, int32_t x) noexcept { - writeU16xLE(p, static_cast(x)); - } - - template - static ASMJIT_INLINE void writeI16xBE(void* p, int32_t x) noexcept { - writeU16xBE(p, static_cast(x)); - } - - template - static ASMJIT_INLINE void writeI16x(void* p, int32_t x) noexcept { - writeU16x(p, static_cast(x)); - } - - static ASMJIT_INLINE void writeU16aLE(void* p, uint32_t x) noexcept { writeU16xLE<2>(p, x); } - static ASMJIT_INLINE void writeU16uLE(void* p, uint32_t x) noexcept { writeU16xLE<0>(p, x); } - - static ASMJIT_INLINE void writeU16aBE(void* p, uint32_t x) noexcept { writeU16xBE<2>(p, x); } - static ASMJIT_INLINE void writeU16uBE(void* p, uint32_t x) noexcept { writeU16xBE<0>(p, x); } - - static ASMJIT_INLINE void writeU16a(void* p, uint32_t x) noexcept { writeU16x<2>(p, x); } - static ASMJIT_INLINE void writeU16u(void* p, uint32_t x) noexcept { writeU16x<0>(p, x); } - - static ASMJIT_INLINE void writeI16aLE(void* p, int32_t x) noexcept { writeI16xLE<2>(p, x); } - static ASMJIT_INLINE void writeI16uLE(void* p, int32_t x) noexcept { writeI16xLE<0>(p, x); } - - static ASMJIT_INLINE void writeI16aBE(void* p, int32_t x) noexcept { writeI16xBE<2>(p, x); } - static ASMJIT_INLINE void writeI16uBE(void* p, int32_t x) noexcept { writeI16xBE<0>(p, x); } - - static ASMJIT_INLINE void writeI16a(void* p, int32_t x) noexcept { writeI16x<2>(p, x); } - static ASMJIT_INLINE void writeI16u(void* p, int32_t x) noexcept { writeI16x<0>(p, x); } - - template - static ASMJIT_INLINE void writeU32xLE(void* p, uint32_t x) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) { - static_cast(p)[0] = ASMJIT_ARCH_LE ? x : byteswap32(x); - } - else { - writeU16xLE(static_cast(p) + 0, x >> 16); - writeU16xLE(static_cast(p) + 2, x); - } - } - - template - static ASMJIT_INLINE void writeU32xBE(void* p, uint32_t x) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) { - static_cast(p)[0] = ASMJIT_ARCH_BE ? x : byteswap32(x); - } - else { - writeU16xBE(static_cast(p) + 0, x); - writeU16xBE(static_cast(p) + 2, x >> 16); - } - } - - template - static ASMJIT_INLINE void writeU32x(void* p, uint32_t x) noexcept { - if (ASMJIT_ARCH_LE) - writeU32xLE(p, x); - else - writeU32xBE(p, x); - } - - template - static ASMJIT_INLINE void writeI32xLE(void* p, int32_t x) noexcept { - writeU32xLE(p, static_cast(x)); - } - - template - static ASMJIT_INLINE void writeI32xBE(void* p, int32_t x) noexcept { - writeU32xBE(p, static_cast(x)); - } - - template - static ASMJIT_INLINE void writeI32x(void* p, int32_t x) noexcept { - writeU32x(p, static_cast(x)); - } - - static ASMJIT_INLINE void writeU32aLE(void* p, uint32_t x) noexcept { writeU32xLE<4>(p, x); } - static ASMJIT_INLINE void writeU32uLE(void* p, uint32_t x) noexcept { writeU32xLE<0>(p, x); } - - static ASMJIT_INLINE void writeU32aBE(void* p, uint32_t x) noexcept { writeU32xBE<4>(p, x); } - static ASMJIT_INLINE void writeU32uBE(void* p, uint32_t x) noexcept { writeU32xBE<0>(p, x); } - - static ASMJIT_INLINE void writeU32a(void* p, uint32_t x) noexcept { writeU32x<4>(p, x); } - static ASMJIT_INLINE void writeU32u(void* p, uint32_t x) noexcept { writeU32x<0>(p, x); } - - static ASMJIT_INLINE void writeI32aLE(void* p, int32_t x) noexcept { writeI32xLE<4>(p, x); } - static ASMJIT_INLINE void writeI32uLE(void* p, int32_t x) noexcept { writeI32xLE<0>(p, x); } - - static ASMJIT_INLINE void writeI32aBE(void* p, int32_t x) noexcept { writeI32xBE<4>(p, x); } - static ASMJIT_INLINE void writeI32uBE(void* p, int32_t x) noexcept { writeI32xBE<0>(p, x); } - - static ASMJIT_INLINE void writeI32a(void* p, int32_t x) noexcept { writeI32x<4>(p, x); } - static ASMJIT_INLINE void writeI32u(void* p, int32_t x) noexcept { writeI32x<0>(p, x); } - - template - static ASMJIT_INLINE void writeU64xLE(void* p, uint64_t x) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) { - static_cast(p)[0] = x; - } - else { - writeU32xLE(static_cast(p) + 0, static_cast(x >> 32)); - writeU32xLE(static_cast(p) + 4, static_cast(x & 0xFFFFFFFFU)); - } - } - - template - static ASMJIT_INLINE void writeU64xBE(void* p, uint64_t x) noexcept { - ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U); - if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) { - static_cast(p)[0] = x; - } - else { - writeU32xBE(static_cast(p) + 0, static_cast(x & 0xFFFFFFFFU)); - writeU32xBE(static_cast(p) + 4, static_cast(x >> 32)); - } - } - - template - static ASMJIT_INLINE void writeU64x(void* p, uint64_t x) noexcept { - if (ASMJIT_ARCH_LE) - writeU64xLE(p, x); - else - writeU64xBE(p, x); - } - - template - static ASMJIT_INLINE void writeI64xLE(void* p, int64_t x) noexcept { - writeU64xLE(p, static_cast(x)); - } - - template - static ASMJIT_INLINE void writeI64xBE(void* p, int64_t x) noexcept { - writeU64xBE(p, static_cast(x)); - } - - template - static ASMJIT_INLINE void writeI64x(void* p, int64_t x) noexcept { - writeU64x(p, static_cast(x)); - } - - static ASMJIT_INLINE void writeU64aLE(void* p, uint64_t x) noexcept { writeU64xLE<8>(p, x); } - static ASMJIT_INLINE void writeU64uLE(void* p, uint64_t x) noexcept { writeU64xLE<0>(p, x); } - - static ASMJIT_INLINE void writeU64aBE(void* p, uint64_t x) noexcept { writeU64xBE<8>(p, x); } - static ASMJIT_INLINE void writeU64uBE(void* p, uint64_t x) noexcept { writeU64xBE<0>(p, x); } - - static ASMJIT_INLINE void writeU64a(void* p, uint64_t x) noexcept { writeU64x<8>(p, x); } - static ASMJIT_INLINE void writeU64u(void* p, uint64_t x) noexcept { writeU64x<0>(p, x); } - - static ASMJIT_INLINE void writeI64aLE(void* p, int64_t x) noexcept { writeI64xLE<8>(p, x); } - static ASMJIT_INLINE void writeI64uLE(void* p, int64_t x) noexcept { writeI64xLE<0>(p, x); } - - static ASMJIT_INLINE void writeI64aBE(void* p, int64_t x) noexcept { writeI64xBE<8>(p, x); } - static ASMJIT_INLINE void writeI64uBE(void* p, int64_t x) noexcept { writeI64xBE<0>(p, x); } - - static ASMJIT_INLINE void writeI64a(void* p, int64_t x) noexcept { writeI64x<8>(p, x); } - static ASMJIT_INLINE void writeI64u(void* p, int64_t x) noexcept { writeI64x<0>(p, x); } -} // Utils namespace - -// ============================================================================ -// [asmjit::UInt64] -// ============================================================================ - -union UInt64 { - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE UInt64 fromUInt64(uint64_t val) noexcept { - UInt64 data; - data.setUInt64(val); - return data; - } - - ASMJIT_INLINE UInt64 fromUInt64(const UInt64& val) noexcept { - UInt64 data; - data.setUInt64(val); - return data; - } - - // -------------------------------------------------------------------------- - // [Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void reset() noexcept { - if (ASMJIT_ARCH_64BIT) { - u64 = 0; - } - else { - u32[0] = 0; - u32[1] = 0; - } - } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE uint64_t getUInt64() const noexcept { - return u64; - } - - ASMJIT_INLINE UInt64& setUInt64(uint64_t val) noexcept { - u64 = val; - return *this; - } - - ASMJIT_INLINE UInt64& setUInt64(const UInt64& val) noexcept { - if (ASMJIT_ARCH_64BIT) { - u64 = val.u64; - } - else { - u32[0] = val.u32[0]; - u32[1] = val.u32[1]; - } - return *this; - } - - ASMJIT_INLINE UInt64& setPacked_2x32(uint32_t u0, uint32_t u1) noexcept { - if (ASMJIT_ARCH_64BIT) { - u64 = Utils::pack64_2x32(u0, u1); - } - else { - u32[0] = u0; - u32[1] = u1; - } - return *this; - } - - // -------------------------------------------------------------------------- - // [Add] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE UInt64& add(uint64_t val) noexcept { - u64 += val; - return *this; - } - - ASMJIT_INLINE UInt64& add(const UInt64& val) noexcept { - if (ASMJIT_ARCH_64BIT) { - u64 += val.u64; - } - else { - u32[0] += val.u32[0]; - u32[1] += val.u32[1]; - } - return *this; - } - - // -------------------------------------------------------------------------- - // [Sub] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE UInt64& sub(uint64_t val) noexcept { - u64 -= val; - return *this; - } - - ASMJIT_INLINE UInt64& sub(const UInt64& val) noexcept { - if (ASMJIT_ARCH_64BIT) { - u64 -= val.u64; - } - else { - u32[0] -= val.u32[0]; - u32[1] -= val.u32[1]; - } - return *this; - } - - // -------------------------------------------------------------------------- - // [And] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE UInt64& and_(uint64_t val) noexcept { - u64 &= val; - return *this; - } - - ASMJIT_INLINE UInt64& and_(const UInt64& val) noexcept { - if (ASMJIT_ARCH_64BIT) { - u64 &= val.u64; - } - else { - u32[0] &= val.u32[0]; - u32[1] &= val.u32[1]; - } - return *this; - } - - // -------------------------------------------------------------------------- - // [AndNot] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE UInt64& andNot(uint64_t val) noexcept { - u64 &= ~val; - return *this; - } - - ASMJIT_INLINE UInt64& andNot(const UInt64& val) noexcept { - if (ASMJIT_ARCH_64BIT) { - u64 &= ~val.u64; - } - else { - u32[0] &= ~val.u32[0]; - u32[1] &= ~val.u32[1]; - } - return *this; - } - - // -------------------------------------------------------------------------- - // [Or] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE UInt64& or_(uint64_t val) noexcept { - u64 |= val; - return *this; - } - - ASMJIT_INLINE UInt64& or_(const UInt64& val) noexcept { - if (ASMJIT_ARCH_64BIT) { - u64 |= val.u64; - } - else { - u32[0] |= val.u32[0]; - u32[1] |= val.u32[1]; - } - return *this; - } - - // -------------------------------------------------------------------------- - // [Xor] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE UInt64& xor_(uint64_t val) noexcept { - u64 ^= val; - return *this; - } - - ASMJIT_INLINE UInt64& xor_(const UInt64& val) noexcept { - if (ASMJIT_ARCH_64BIT) { - u64 ^= val.u64; - } - else { - u32[0] ^= val.u32[0]; - u32[1] ^= val.u32[1]; - } - return *this; - } - - // -------------------------------------------------------------------------- - // [Eq] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool isZero() const noexcept { - if (ASMJIT_ARCH_64BIT) - return u64 == 0; - else - return (u32[0] | u32[1]) == 0; - } - - ASMJIT_INLINE bool isNonZero() const noexcept { - if (ASMJIT_ARCH_64BIT) - return u64 != 0; - else - return (u32[0] | u32[1]) != 0; - } - - ASMJIT_INLINE bool eq(uint64_t val) const noexcept { - return u64 == val; - } - - ASMJIT_INLINE bool eq(const UInt64& val) const noexcept { - if (ASMJIT_ARCH_64BIT) - return u64 == val.u64; - else - return u32[0] == val.u32[0] && u32[1] == val.u32[1]; - } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE UInt64& operator+=(uint64_t val) noexcept { return add(val); } - ASMJIT_INLINE UInt64& operator+=(const UInt64& val) noexcept { return add(val); } - - ASMJIT_INLINE UInt64& operator-=(uint64_t val) noexcept { return sub(val); } - ASMJIT_INLINE UInt64& operator-=(const UInt64& val) noexcept { return sub(val); } - - ASMJIT_INLINE UInt64& operator&=(uint64_t val) noexcept { return and_(val); } - ASMJIT_INLINE UInt64& operator&=(const UInt64& val) noexcept { return and_(val); } - - ASMJIT_INLINE UInt64& operator|=(uint64_t val) noexcept { return or_(val); } - ASMJIT_INLINE UInt64& operator|=(const UInt64& val) noexcept { return or_(val); } - - ASMJIT_INLINE UInt64& operator^=(uint64_t val) noexcept { return xor_(val); } - ASMJIT_INLINE UInt64& operator^=(const UInt64& val) noexcept { return xor_(val); } - - ASMJIT_INLINE bool operator==(uint64_t val) const noexcept { return eq(val); } - ASMJIT_INLINE bool operator==(const UInt64& val) const noexcept { return eq(val); } - - ASMJIT_INLINE bool operator!=(uint64_t val) const noexcept { return !eq(val); } - ASMJIT_INLINE bool operator!=(const UInt64& val) const noexcept { return !eq(val); } - - ASMJIT_INLINE bool operator<(uint64_t val) const noexcept { return u64 < val; } - ASMJIT_INLINE bool operator<(const UInt64& val) const noexcept { return u64 < val.u64; } - - ASMJIT_INLINE bool operator<=(uint64_t val) const noexcept { return u64 <= val; } - ASMJIT_INLINE bool operator<=(const UInt64& val) const noexcept { return u64 <= val.u64; } - - ASMJIT_INLINE bool operator>(uint64_t val) const noexcept { return u64 > val; } - ASMJIT_INLINE bool operator>(const UInt64& val) const noexcept { return u64 > val.u64; } - - ASMJIT_INLINE bool operator>=(uint64_t val) const noexcept { return u64 >= val; } - ASMJIT_INLINE bool operator>=(const UInt64& val) const noexcept { return u64 >= val.u64; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - int8_t i8[8]; //!< 8-bit signed integer (8x). - uint8_t u8[8]; //!< 8-bit unsigned integer (8x). - - int16_t i16[4]; //!< 16-bit signed integer (4x). - uint16_t u16[4]; //!< 16-bit unsigned integer (4x). - - int32_t i32[2]; //!< 32-bit signed integer (2x). - uint32_t u32[2]; //!< 32-bit unsigned integer (2x). - - int64_t i64; //!< 64-bit signed integer. - uint64_t u64; //!< 64-bit unsigned integer. - - float f32[2]; //!< 32-bit floating point (2x). - double f64; //!< 64-bit floating point. - -#if ASMJIT_ARCH_LE - struct { float f32Lo, f32Hi; }; - struct { int32_t i32Lo, i32Hi; }; - struct { uint32_t u32Lo, u32Hi; }; -#else - struct { float f32Hi, f32Lo; }; - struct { int32_t i32Hi, i32Lo; }; - struct { uint32_t u32Hi, u32Lo; }; -#endif // ASMJIT_ARCH_LE -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_UTILS_H diff --git a/libs/asmjit/base/vmem.cpp b/libs/asmjit/base/vmem.cpp deleted file mode 100644 index 553032a5..00000000 --- a/libs/asmjit/base/vmem.cpp +++ /dev/null @@ -1,1077 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/osutils.h" -#include "../base/utils.h" -#include "../base/vmem.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -// This file contains implementation of virtual memory management for AsmJit -// library. There are several goals I decided to write implementation myself: -// -// - Granularity of allocated blocks is different than granularity for a typical -// C malloc. It is at least 64-bytes so CodeEmitter can guarantee the alignment -// up to 64 bytes, which is the size of a cache-line and it's also required by -// AVX-512 aligned loads and stores. Alignment requirements can grow in the future, -// but at the moment 64 bytes is safe (we may jump to 128 bytes if necessary or -// make it configurable). -// -// - Keep memory manager information outside of the allocated virtual memory -// pages, because these pages allow machine code execution and there should -// be not data required to keep track of these blocks. Another reason is that -// some environments (i.e. iOS) allow to generate and run JIT code, but this -// code has to be set to [Executable, but not Writable]. -// -// - Keep implementation simple and easy to follow. -// -// Implementation is based on bit arrays and binary trees. Bit arrays contain -// information related to allocated and unused blocks of memory. The size of -// a block is described by `MemNode::density`. Count of blocks is stored in -// `MemNode::blocks`. For example if density is 64 and count of blocks is 20, -// memory node contains 64*20 bytes of memory and the smallest possible allocation -// (and also alignment) is 64 bytes. So density is also related to memory -// alignment. Binary trees (RB) are used to enable fast lookup into all addresses -// allocated by memory manager instance. This is used mainly by `VMemPrivate::release()`. -// -// Bit array looks like this (empty = unused, X = used) - Size of block 64: -// -// ------------------------------------------------------------------------- -// | |X|X| | | | | |X|X|X|X|X|X| | | | | | | | | | | | |X| | | | |X|X|X| | | -// ------------------------------------------------------------------------- -// (Maximum continuous block) -// -// These bits show that there are 12 allocated blocks (X) of 64 bytes, so total -// size allocated is 768 bytes. Maximum count of continuous memory is 12 * 64. - -namespace asmjit { - -// ============================================================================ -// [asmjit::VMemMgr - BitOps] -// ============================================================================ - -#define M_DIV(x, y) ((x) / (y)) -#define M_MOD(x, y) ((x) % (y)) - -//! \internal -enum { kBitsPerEntity = (sizeof(size_t) * 8) }; - -//! \internal -//! -//! Set `len` bits in `buf` starting at `index` bit index. -static void _SetBits(size_t* buf, size_t index, size_t len) noexcept { - if (len == 0) - return; - - size_t i = index / kBitsPerEntity; // size_t[] - size_t j = index % kBitsPerEntity; // size_t[][] bit index - - // How many bytes process in the first group. - size_t c = kBitsPerEntity - j; - if (c > len) - c = len; - - // Offset. - buf += i; - - *buf++ |= ((~(size_t)0) >> (kBitsPerEntity - c)) << j; - len -= c; - - while (len >= kBitsPerEntity) { - *buf++ = ~(size_t)0; - len -= kBitsPerEntity; - } - - if (len) - *buf |= ((~(size_t)0) >> (kBitsPerEntity - len)); -} - -// ============================================================================ -// [asmjit::VMemMgr::TypeDefs] -// ============================================================================ - -typedef VMemMgr::RbNode RbNode; -typedef VMemMgr::MemNode MemNode; -typedef VMemMgr::PermanentNode PermanentNode; - -// ============================================================================ -// [asmjit::VMemMgr::RbNode] -// ============================================================================ - -//! \internal -//! -//! Base red-black tree node. -struct VMemMgr::RbNode { - // Implementation is based on article by Julienne Walker (Public Domain), - // including C code and original comments. Thanks for the excellent article. - - RbNode* node[2]; //!< Left[0] and right[1] nodes. - uint8_t* mem; //!< Virtual memory address. - uint32_t red; //!< Node color (red vs. black). -}; - -//! \internal -//! -//! Get if the node is red (nullptr or node with red flag). -static ASMJIT_INLINE bool rbIsRed(RbNode* node) noexcept { - return node && node->red; -} - -//! \internal -//! -//! Check whether the RB tree is valid. -static int rbAssert(RbNode* root) noexcept { - if (!root) return 1; - - RbNode* ln = root->node[0]; - RbNode* rn = root->node[1]; - - // Red violation. - ASMJIT_ASSERT(!(rbIsRed(root) && (rbIsRed(ln) || rbIsRed(rn)))); - - int lh = rbAssert(ln); - int rh = rbAssert(rn); - - // Invalid btree. - ASMJIT_ASSERT(ln == nullptr || ln->mem < root->mem); - ASMJIT_ASSERT(rn == nullptr || rn->mem > root->mem); - - // Black violation. - ASMJIT_ASSERT(!(lh != 0 && rh != 0 && lh != rh)); - - // Only count black links. - if (lh != 0 && rh != 0) - return rbIsRed(root) ? lh : lh + 1; - else - return 0; -} - -//! \internal -//! -//! Single rotation. -static ASMJIT_INLINE RbNode* rbRotateSingle(RbNode* root, int dir) noexcept { - RbNode* save = root->node[!dir]; - - root->node[!dir] = save->node[dir]; - save->node[dir] = root; - - root->red = 1; - save->red = 0; - - return save; -} - -//! \internal -//! -//! Double rotation. -static ASMJIT_INLINE RbNode* rbRotateDouble(RbNode* root, int dir) noexcept { - root->node[!dir] = rbRotateSingle(root->node[!dir], !dir); - return rbRotateSingle(root, dir); -} - -// ============================================================================ -// [asmjit::VMemMgr::MemNode] -// ============================================================================ - -struct VMemMgr::MemNode : public RbNode { - ASMJIT_INLINE void init(MemNode* other) noexcept { - mem = other->mem; - - size = other->size; - used = other->used; - blocks = other->blocks; - density = other->density; - largestBlock = other->largestBlock; - - baUsed = other->baUsed; - baCont = other->baCont; - } - - // Get available space. - ASMJIT_INLINE size_t getAvailable() const noexcept { return size - used; } - - MemNode* prev; // Prev node in list. - MemNode* next; // Next node in list. - - size_t size; // How many bytes contain this node. - size_t used; // How many bytes are used in this node. - size_t blocks; // How many blocks are here. - size_t density; // Minimum count of allocated bytes in this node (also alignment). - size_t largestBlock; // Contains largest block that can be allocated. - - size_t* baUsed; // Contains bits about used blocks (0 = unused, 1 = used). - size_t* baCont; // Contains bits about continuous blocks (0 = stop , 1 = continue). -}; - -// ============================================================================ -// [asmjit::VMemMgr::PermanentNode] -// ============================================================================ - -//! \internal -//! -//! Permanent node. -struct VMemMgr::PermanentNode { - //! Get available space. - ASMJIT_INLINE size_t getAvailable() const noexcept { return size - used; } - - PermanentNode* prev; // Pointer to prev chunk or nullptr. - uint8_t* mem; // Base pointer (virtual memory address). - size_t size; // Count of bytes allocated. - size_t used; // Count of bytes used. -}; - -// ============================================================================ -// [asmjit::VMemMgr - Private] -// ============================================================================ - -//! \internal -//! -//! Helper to avoid `#ifdef`s in the code. -ASMJIT_INLINE uint8_t* vMemMgrAllocVMem(VMemMgr* self, size_t size, size_t* vSize) noexcept { - uint32_t flags = OSUtils::kVMWritable | OSUtils::kVMExecutable; -#if !ASMJIT_OS_WINDOWS - return static_cast(OSUtils::allocVirtualMemory(size, vSize, flags)); -#else - return static_cast(OSUtils::allocProcessMemory(self->_hProcess, size, vSize, flags)); -#endif -} - -//! \internal -//! -//! Helper to avoid `#ifdef`s in the code. -ASMJIT_INLINE Error vMemMgrReleaseVMem(VMemMgr* self, void* p, size_t vSize) noexcept { -#if !ASMJIT_OS_WINDOWS - return OSUtils::releaseVirtualMemory(p, vSize); -#else - return OSUtils::releaseProcessMemory(self->_hProcess, p, vSize); -#endif -} - -//! \internal -//! -//! Check whether the Red-Black tree is valid. -static bool vMemMgrCheckTree(VMemMgr* self) noexcept { - return rbAssert(self->_root) > 0; -} - -//! \internal -//! -//! Alloc virtual memory including a heap memory needed for `MemNode` data. -//! -//! Returns set-up `MemNode*` or nullptr if allocation failed. -static MemNode* vMemMgrCreateNode(VMemMgr* self, size_t size, size_t density) noexcept { - size_t vSize; - uint8_t* vmem = vMemMgrAllocVMem(self, size, &vSize); - if (!vmem) return nullptr; - - size_t blocks = (vSize / density); - size_t bsize = (((blocks + 7) >> 3) + sizeof(size_t) - 1) & ~(size_t)(sizeof(size_t) - 1); - - MemNode* node = static_cast(Internal::allocMemory(sizeof(MemNode))); - uint8_t* data = static_cast(Internal::allocMemory(bsize * 2)); - - // Out of memory. - if (!node || !data) { - vMemMgrReleaseVMem(self, vmem, vSize); - if (node) Internal::releaseMemory(node); - if (data) Internal::releaseMemory(data); - return nullptr; - } - - // Initialize RbNode data. - node->node[0] = nullptr; - node->node[1] = nullptr; - node->mem = vmem; - node->red = 1; - - // Initialize MemNode data. - node->prev = nullptr; - node->next = nullptr; - - node->size = vSize; - node->used = 0; - node->blocks = blocks; - node->density = density; - node->largestBlock = vSize; - - ::memset(data, 0, bsize * 2); - node->baUsed = reinterpret_cast(data); - node->baCont = reinterpret_cast(data + bsize); - - return node; -} - -static void vMemMgrInsertNode(VMemMgr* self, MemNode* node) noexcept { - if (!self->_root) { - // Empty tree case. - self->_root = node; - } - else { - // False tree root. - RbNode head = { { nullptr, nullptr }, 0, 0 }; - - // Grandparent & parent. - RbNode* g = nullptr; - RbNode* t = &head; - - // Iterator & parent. - RbNode* p = nullptr; - RbNode* q = t->node[1] = self->_root; - - int dir = 0; - int last = 0; // Not needed to initialize, but makes some tools happy. - - // Search down the tree. - for (;;) { - if (!q) { - // Insert new node at the bottom. - q = node; - p->node[dir] = node; - } - else if (rbIsRed(q->node[0]) && rbIsRed(q->node[1])) { - // Color flip. - q->red = 1; - q->node[0]->red = 0; - q->node[1]->red = 0; - } - - // Fix red violation. - if (rbIsRed(q) && rbIsRed(p)) { - int dir2 = t->node[1] == g; - t->node[dir2] = q == p->node[last] ? rbRotateSingle(g, !last) : rbRotateDouble(g, !last); - } - - // Stop if found. - if (q == node) - break; - - last = dir; - dir = q->mem < node->mem; - - // Update helpers. - if (g) t = g; - - g = p; - p = q; - q = q->node[dir]; - } - - // Update root. - self->_root = static_cast(head.node[1]); - } - - // Make root black. - self->_root->red = 0; - - // Link with others. - node->prev = self->_last; - - if (!self->_first) { - self->_first = node; - self->_last = node; - self->_optimal = node; - } - else { - node->prev = self->_last; - self->_last->next = node; - self->_last = node; - } -} - -//! \internal -//! -//! Remove node from Red-Black tree. -//! -//! Returns node that should be freed, but it doesn't have to be necessarily -//! the `node` passed. -static MemNode* vMemMgrRemoveNode(VMemMgr* self, MemNode* node) noexcept { - // False tree root. - RbNode head = { { nullptr, nullptr }, 0, 0 }; - - // Helpers. - RbNode* q = &head; - RbNode* p = nullptr; - RbNode* g = nullptr; - - // Found item. - RbNode* f = nullptr; - int dir = 1; - - // Set up. - q->node[1] = self->_root; - - // Search and push a red down. - while (q->node[dir]) { - int last = dir; - - // Update helpers. - g = p; - p = q; - q = q->node[dir]; - dir = q->mem < node->mem; - - // Save found node. - if (q == node) - f = q; - - // Push the red node down. - if (!rbIsRed(q) && !rbIsRed(q->node[dir])) { - if (rbIsRed(q->node[!dir])) { - p = p->node[last] = rbRotateSingle(q, dir); - } - else if (!rbIsRed(q->node[!dir])) { - RbNode* s = p->node[!last]; - - if (s) { - if (!rbIsRed(s->node[!last]) && !rbIsRed(s->node[last])) { - // Color flip. - p->red = 0; - s->red = 1; - q->red = 1; - } - else { - int dir2 = g->node[1] == p; - - if (rbIsRed(s->node[last])) - g->node[dir2] = rbRotateDouble(p, last); - else if (rbIsRed(s->node[!last])) - g->node[dir2] = rbRotateSingle(p, last); - - // Ensure correct coloring. - q->red = g->node[dir2]->red = 1; - g->node[dir2]->node[0]->red = 0; - g->node[dir2]->node[1]->red = 0; - } - } - } - } - } - - // Replace and remove. - ASMJIT_ASSERT(f != nullptr); - ASMJIT_ASSERT(f != &head); - ASMJIT_ASSERT(q != &head); - - if (f != q) { - ASMJIT_ASSERT(f != &head); - static_cast(f)->init(static_cast(q)); - } - - p->node[p->node[1] == q] = q->node[q->node[0] == nullptr]; - - // Update root and make it black. - self->_root = static_cast(head.node[1]); - if (self->_root) self->_root->red = 0; - - // Unlink. - MemNode* next = static_cast(q)->next; - MemNode* prev = static_cast(q)->prev; - - if (prev) - prev->next = next; - else - self->_first = next; - - if (next) - next->prev = prev; - else - self->_last = prev; - - if (self->_optimal == q) - self->_optimal = prev ? prev : next; - - return static_cast(q); -} - -static MemNode* vMemMgrFindNodeByPtr(VMemMgr* self, uint8_t* mem) noexcept { - MemNode* node = self->_root; - while (node) { - uint8_t* nodeMem = node->mem; - - // Go left. - if (mem < nodeMem) { - node = static_cast(node->node[0]); - continue; - } - - // Go right. - uint8_t* nodeEnd = nodeMem + node->size; - if (mem >= nodeEnd) { - node = static_cast(node->node[1]); - continue; - } - - // Match. - break; - } - return node; -} - -static void* vMemMgrAllocPermanent(VMemMgr* self, size_t vSize) noexcept { - static const size_t permanentAlignment = 32; - static const size_t permanentNodeSize = 32768; - - vSize = Utils::alignTo(vSize, permanentAlignment); - - AutoLock locked(self->_lock); - PermanentNode* node = self->_permanent; - - // Try to find space in allocated chunks. - while (node && vSize > node->getAvailable()) - node = node->prev; - - // Or allocate new node. - if (!node) { - size_t nodeSize = permanentNodeSize; - if (nodeSize < vSize) nodeSize = vSize; - - node = static_cast(Internal::allocMemory(sizeof(PermanentNode))); - if (!node) return nullptr; - - node->mem = vMemMgrAllocVMem(self, nodeSize, &node->size); - if (!node->mem) { - Internal::releaseMemory(node); - return nullptr; - } - - node->used = 0; - node->prev = self->_permanent; - self->_permanent = node; - } - - // Finally, copy function code to our space we reserved for. - uint8_t* result = node->mem + node->used; - - // Update Statistics. - node->used += vSize; - self->_usedBytes += vSize; - - // Code can be null to only reserve space for code. - return static_cast(result); -} - -static void* vMemMgrAllocFreeable(VMemMgr* self, size_t vSize) noexcept { - // Current index. - size_t i; - - // How many we need to be freed. - size_t need; - size_t minVSize; - - // Align to 32 bytes by default. - vSize = Utils::alignTo(vSize, 32); - if (vSize == 0) - return nullptr; - - AutoLock locked(self->_lock); - MemNode* node = self->_optimal; - minVSize = self->_blockSize; - - // Try to find memory block in existing nodes. - while (node) { - // Skip this node? - if ((node->getAvailable() < vSize) || (node->largestBlock < vSize && node->largestBlock != 0)) { - MemNode* next = node->next; - - if (node->getAvailable() < minVSize && node == self->_optimal && next) - self->_optimal = next; - - node = next; - continue; - } - - size_t* up = node->baUsed; // Current ubits address. - size_t ubits; // Current ubits[0] value. - size_t bit; // Current bit mask. - size_t blocks = node->blocks; // Count of blocks in node. - size_t cont = 0; // How many bits are currently freed in find loop. - size_t maxCont = 0; // Largest continuous block (bits count). - size_t j; - - need = M_DIV((vSize + node->density - 1), node->density); - i = 0; - - // Try to find node that is large enough. - while (i < blocks) { - ubits = *up++; - - // Fast skip used blocks. - if (ubits == ~(size_t)0) { - if (cont > maxCont) - maxCont = cont; - cont = 0; - - i += kBitsPerEntity; - continue; - } - - size_t max = kBitsPerEntity; - if (i + max > blocks) - max = blocks - i; - - for (j = 0, bit = 1; j < max; bit <<= 1) { - j++; - if ((ubits & bit) == 0) { - if (++cont == need) { - i += j; - i -= cont; - goto L_Found; - } - - continue; - } - - if (cont > maxCont) maxCont = cont; - cont = 0; - } - - i += kBitsPerEntity; - } - - // Because we traversed the entire node, we can set largest node size that - // will be used to cache next traversing. - node->largestBlock = maxCont * node->density; - - node = node->next; - } - - // If we are here, we failed to find existing memory block and we must - // allocate a new one. - { - size_t blockSize = self->_blockSize; - if (blockSize < vSize) blockSize = vSize; - - node = vMemMgrCreateNode(self, blockSize, self->_blockDensity); - if (!node) return nullptr; - - // Update binary tree. - vMemMgrInsertNode(self, node); - ASMJIT_ASSERT(vMemMgrCheckTree(self)); - - // Alloc first node at start. - i = 0; - need = (vSize + node->density - 1) / node->density; - - // Update statistics. - self->_allocatedBytes += node->size; - } - -L_Found: - // Update bits. - _SetBits(node->baUsed, i, need); - _SetBits(node->baCont, i, need - 1); - - // Update statistics. - { - size_t u = need * node->density; - node->used += u; - node->largestBlock = 0; - self->_usedBytes += u; - } - - // And return pointer to allocated memory. - uint8_t* result = node->mem + i * node->density; - ASMJIT_ASSERT(result >= node->mem && result <= node->mem + node->size - vSize); - return result; -} - -//! \internal -//! -//! Reset the whole `VMemMgr` instance, freeing all heap memory allocated an -//! virtual memory allocated unless `keepVirtualMemory` is true (and this is -//! only used when writing data to a remote process). -static void vMemMgrReset(VMemMgr* self, bool keepVirtualMemory) noexcept { - MemNode* node = self->_first; - - while (node) { - MemNode* next = node->next; - - if (!keepVirtualMemory) - vMemMgrReleaseVMem(self, node->mem, node->size); - - Internal::releaseMemory(node->baUsed); - Internal::releaseMemory(node); - - node = next; - } - - self->_allocatedBytes = 0; - self->_usedBytes = 0; - - self->_root = nullptr; - self->_first = nullptr; - self->_last = nullptr; - self->_optimal = nullptr; -} - -// ============================================================================ -// [asmjit::VMemMgr - Construction / Destruction] -// ============================================================================ - -#if !ASMJIT_OS_WINDOWS -VMemMgr::VMemMgr() noexcept { -#else -VMemMgr::VMemMgr(HANDLE hProcess) noexcept { -#endif - - VMemInfo vm = OSUtils::getVirtualMemoryInfo(); - -#if ASMJIT_OS_WINDOWS - _hProcess = hProcess ? hProcess : vm.hCurrentProcess; -#endif // ASMJIT_OS_WINDOWS - - _blockSize = vm.pageGranularity; - _blockDensity = 64; - - _allocatedBytes = 0; - _usedBytes = 0; - - _root = nullptr; - _first = nullptr; - _last = nullptr; - _optimal = nullptr; - - _permanent = nullptr; - _keepVirtualMemory = false; -} - -VMemMgr::~VMemMgr() noexcept { - // Freeable memory cleanup - Also frees the virtual memory if configured to. - vMemMgrReset(this, _keepVirtualMemory); - - // Permanent memory cleanup - Never frees the virtual memory. - PermanentNode* node = _permanent; - while (node) { - PermanentNode* prev = node->prev; - Internal::releaseMemory(node); - node = prev; - } -} - -// ============================================================================ -// [asmjit::VMemMgr - Reset] -// ============================================================================ - -void VMemMgr::reset() noexcept { - vMemMgrReset(this, false); -} - -// ============================================================================ -// [asmjit::VMemMgr - Alloc / Release] -// ============================================================================ - -void* VMemMgr::alloc(size_t size, uint32_t type) noexcept { - if (type == kAllocPermanent) - return vMemMgrAllocPermanent(this, size); - else - return vMemMgrAllocFreeable(this, size); -} - -Error VMemMgr::release(void* p) noexcept { - if (!p) return kErrorOk; - - AutoLock locked(_lock); - MemNode* node = vMemMgrFindNodeByPtr(this, static_cast(p)); - if (!node) return DebugUtils::errored(kErrorInvalidArgument); - - size_t offset = (size_t)((uint8_t*)p - (uint8_t*)node->mem); - size_t bitpos = M_DIV(offset, node->density); - size_t i = (bitpos / kBitsPerEntity); - - size_t* up = node->baUsed + i; // Current ubits address. - size_t* cp = node->baCont + i; // Current cbits address. - size_t ubits = *up; // Current ubits[0] value. - size_t cbits = *cp; // Current cbits[0] value. - size_t bit = (size_t)1 << (bitpos % kBitsPerEntity); - - size_t cont = 0; - bool stop; - - for (;;) { - stop = (cbits & bit) == 0; - ubits &= ~bit; - cbits &= ~bit; - - bit <<= 1; - cont++; - - if (stop || bit == 0) { - *up = ubits; - *cp = cbits; - if (stop) - break; - - ubits = *++up; - cbits = *++cp; - bit = 1; - } - } - - // If the freed block is fully allocated node then it's needed to - // update 'optimal' pointer in memory manager. - if (node->used == node->size) { - MemNode* cur = _optimal; - - do { - cur = cur->prev; - if (cur == node) { - _optimal = node; - break; - } - } while (cur); - } - - // Statistics. - cont *= node->density; - if (node->largestBlock < cont) - node->largestBlock = cont; - - node->used -= cont; - _usedBytes -= cont; - - // If page is empty, we can free it. - if (node->used == 0) { - // Free memory associated with node (this memory is not accessed - // anymore so it's safe). - vMemMgrReleaseVMem(this, node->mem, node->size); - Internal::releaseMemory(node->baUsed); - - node->baUsed = nullptr; - node->baCont = nullptr; - - // Statistics. - _allocatedBytes -= node->size; - - // Remove node. This function can return different node than - // passed into, but data is copied into previous node if needed. - Internal::releaseMemory(vMemMgrRemoveNode(this, node)); - ASMJIT_ASSERT(vMemMgrCheckTree(this)); - } - - return kErrorOk; -} - -Error VMemMgr::shrink(void* p, size_t used) noexcept { - if (!p) return kErrorOk; - if (used == 0) - return release(p); - - AutoLock locked(_lock); - MemNode* node = vMemMgrFindNodeByPtr(this, (uint8_t*)p); - if (!node) return DebugUtils::errored(kErrorInvalidArgument); - - size_t offset = (size_t)((uint8_t*)p - (uint8_t*)node->mem); - size_t bitpos = M_DIV(offset, node->density); - size_t i = (bitpos / kBitsPerEntity); - - size_t* up = node->baUsed + i; // Current ubits address. - size_t* cp = node->baCont + i; // Current cbits address. - size_t ubits = *up; // Current ubits[0] value. - size_t cbits = *cp; // Current cbits[0] value. - size_t bit = (size_t)1 << (bitpos % kBitsPerEntity); - - size_t cont = 0; - size_t usedBlocks = (used + node->density - 1) / node->density; - - bool stop; - - // Find the first block we can mark as free. - for (;;) { - stop = (cbits & bit) == 0; - if (stop) - return kErrorOk; - - if (++cont == usedBlocks) - break; - - bit <<= 1; - if (bit == 0) { - ubits = *++up; - cbits = *++cp; - bit = 1; - } - } - - // Free the tail blocks. - cont = ~(size_t)0; - goto _EnterFreeLoop; - - for (;;) { - stop = (cbits & bit) == 0; - ubits &= ~bit; - -_EnterFreeLoop: - cbits &= ~bit; - - bit <<= 1; - cont++; - - if (stop || bit == 0) { - *up = ubits; - *cp = cbits; - if (stop) - break; - - ubits = *++up; - cbits = *++cp; - bit = 1; - } - } - - // Statistics. - cont *= node->density; - if (node->largestBlock < cont) - node->largestBlock = cont; - - node->used -= cont; - _usedBytes -= cont; - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::VMem - Test] -// ============================================================================ - -#if defined(ASMJIT_TEST) -static void VMemTest_fill(void* a, void* b, int i) noexcept { - int pattern = rand() % 256; - *(int *)a = i; - *(int *)b = i; - ::memset((char*)a + sizeof(int), pattern, i - sizeof(int)); - ::memset((char*)b + sizeof(int), pattern, i - sizeof(int)); -} - -static void VMemTest_verify(void* a, void* b) noexcept { - int ai = *(int*)a; - int bi = *(int*)b; - - EXPECT(ai == bi, - "The length of 'a' (%d) and 'b' (%d) should be same", ai, bi); - - EXPECT(::memcmp(a, b, ai) == 0, - "Pattern (%p) doesn't match", a); -} - -static void VMemTest_stats(VMemMgr& memmgr) noexcept { - INFO("Used : %u", static_cast(memmgr.getUsedBytes())); - INFO("Allocated: %u", static_cast(memmgr.getAllocatedBytes())); -} - -static void VMemTest_shuffle(void** a, void** b, size_t count) noexcept { - for (size_t i = 0; i < count; ++i) { - size_t si = (size_t)rand() % count; - - void* ta = a[i]; - void* tb = b[i]; - - a[i] = a[si]; - b[i] = b[si]; - - a[si] = ta; - b[si] = tb; - } -} - -UNIT(base_vmem) { - VMemMgr memmgr; - - // Should be predictible. - srand(100); - - int i; - int kCount = 200000; - - INFO("Memory alloc/free test - %d allocations", static_cast(kCount)); - - void** a = (void**)Internal::allocMemory(sizeof(void*) * kCount); - void** b = (void**)Internal::allocMemory(sizeof(void*) * kCount); - - EXPECT(a != nullptr && b != nullptr, - "Couldn't allocate %u bytes on heap", kCount * 2); - - INFO("Allocating virtual memory..."); - for (i = 0; i < kCount; i++) { - int r = (rand() % 1000) + 4; - - a[i] = memmgr.alloc(r); - EXPECT(a[i] != nullptr, - "Couldn't allocate %d bytes of virtual memory", r); - ::memset(a[i], 0, r); - } - VMemTest_stats(memmgr); - - INFO("Freeing virtual memory..."); - for (i = 0; i < kCount; i++) { - EXPECT(memmgr.release(a[i]) == kErrorOk, - "Failed to free %p", b[i]); - } - VMemTest_stats(memmgr); - - INFO("Verified alloc/free test - %d allocations", static_cast(kCount)); - for (i = 0; i < kCount; i++) { - int r = (rand() % 1000) + 4; - - a[i] = memmgr.alloc(r); - EXPECT(a[i] != nullptr, - "Couldn't allocate %d bytes of virtual memory", r); - - b[i] = Internal::allocMemory(r); - EXPECT(b[i] != nullptr, - "Couldn't allocate %d bytes on heap", r); - - VMemTest_fill(a[i], b[i], r); - } - VMemTest_stats(memmgr); - - INFO("Shuffling..."); - VMemTest_shuffle(a, b, kCount); - - INFO("Verify and free..."); - for (i = 0; i < kCount / 2; i++) { - VMemTest_verify(a[i], b[i]); - EXPECT(memmgr.release(a[i]) == kErrorOk, - "Failed to free %p", a[i]); - Internal::releaseMemory(b[i]); - } - VMemTest_stats(memmgr); - - INFO("Alloc again"); - for (i = 0; i < kCount / 2; i++) { - int r = (rand() % 1000) + 4; - - a[i] = memmgr.alloc(r); - EXPECT(a[i] != nullptr, - "Couldn't allocate %d bytes of virtual memory", r); - - b[i] = Internal::allocMemory(r); - EXPECT(b[i] != nullptr, - "Couldn't allocate %d bytes on heap"); - - VMemTest_fill(a[i], b[i], r); - } - VMemTest_stats(memmgr); - - INFO("Verify and free..."); - for (i = 0; i < kCount; i++) { - VMemTest_verify(a[i], b[i]); - EXPECT(memmgr.release(a[i]) == kErrorOk, - "Failed to free %p", a[i]); - Internal::releaseMemory(b[i]); - } - VMemTest_stats(memmgr); - - Internal::releaseMemory(a); - Internal::releaseMemory(b); -} -#endif // ASMJIT_TEST - -} // asmjit namespace diff --git a/libs/asmjit/base/vmem.h b/libs/asmjit/base/vmem.h deleted file mode 100644 index 6a1a5133..00000000 --- a/libs/asmjit/base/vmem.h +++ /dev/null @@ -1,154 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_VMEM_H -#define _ASMJIT_BASE_VMEM_H - -// [Dependencies] -#include "../base/globals.h" -#include "../base/osutils.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::VMemMgr] -// ============================================================================ - -//! Reference implementation of memory manager that uses `VMemUtil` to allocate -//! chunks of virtual memory and bit arrays to manage it. -class VMemMgr { -public: - //! Type of virtual memory allocation, see `VMemMgr::alloc()`. - ASMJIT_ENUM(AllocType) { - //! Normal memory allocation, has to be freed by `VMemMgr::release()`. - kAllocFreeable = 0, - //! Allocate permanent memory, can't be freed. - kAllocPermanent = 1 - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - -#if !ASMJIT_OS_WINDOWS - //! Create a `VMemMgr` instance. - ASMJIT_API VMemMgr() noexcept; -#else - //! Create a `VMemMgr` instance. - //! - //! NOTE: When running on Windows it's possible to specify a `hProcess` to - //! be used for memory allocation. Using `hProcess` allows to allocate memory - //! of a remote process. - ASMJIT_API VMemMgr(HANDLE hProcess = static_cast(0)) noexcept; -#endif // ASMJIT_OS_WINDOWS - - //! Destroy the `VMemMgr` instance and free all blocks. - ASMJIT_API ~VMemMgr() noexcept; - - // -------------------------------------------------------------------------- - // [Reset] - // -------------------------------------------------------------------------- - - //! Free all allocated memory. - ASMJIT_API void reset() noexcept; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - -#if ASMJIT_OS_WINDOWS - //! Get the handle of the process memory manager is bound to. - ASMJIT_INLINE HANDLE getProcessHandle() const noexcept { return _hProcess; } -#endif // ASMJIT_OS_WINDOWS - - //! Get how many bytes are currently allocated. - ASMJIT_INLINE size_t getAllocatedBytes() const noexcept { return _allocatedBytes; } - //! Get how many bytes are currently used. - ASMJIT_INLINE size_t getUsedBytes() const noexcept { return _usedBytes; } - - //! Get whether to keep allocated memory after the `VMemMgr` is destroyed. - //! - //! \sa \ref setKeepVirtualMemory. - ASMJIT_INLINE bool getKeepVirtualMemory() const noexcept { return _keepVirtualMemory; } - //! Set whether to keep allocated memory after the memory manager is destroyed. - //! - //! This method is usable when patching code of remote process. You need to - //! allocate process memory, store generated assembler into it and patch the - //! method you want to redirect (into your code). This method affects only - //! VMemMgr destructor. After destruction all internal - //! structures are freed, only the process virtual memory remains. - //! - //! NOTE: Memory allocated with kAllocPermanent is always kept. - //! - //! \sa \ref getKeepVirtualMemory. - ASMJIT_INLINE void setKeepVirtualMemory(bool val) noexcept { _keepVirtualMemory = val; } - - // -------------------------------------------------------------------------- - // [Alloc / Release] - // -------------------------------------------------------------------------- - - //! Allocate a `size` bytes of virtual memory. - //! - //! Note that if you are implementing your own virtual memory manager then you - //! can quitly ignore type of allocation. This is mainly for AsmJit to memory - //! manager that allocated memory will be never freed. - ASMJIT_API void* alloc(size_t size, uint32_t type = kAllocFreeable) noexcept; - //! Free previously allocated memory at a given `address`. - ASMJIT_API Error release(void* p) noexcept; - //! Free extra memory allocated with `p`. - ASMJIT_API Error shrink(void* p, size_t used) noexcept; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -#if ASMJIT_OS_WINDOWS - HANDLE _hProcess; //!< Process passed to `VirtualAllocEx` and `VirtualFree`. -#endif // ASMJIT_OS_WINDOWS - Lock _lock; //!< Lock to enable thread-safe functionality. - - size_t _blockSize; //!< Default block size. - size_t _blockDensity; //!< Default block density. - bool _keepVirtualMemory; //!< Keep virtual memory after destroyed. - - size_t _allocatedBytes; //!< How many bytes are currently allocated. - size_t _usedBytes; //!< How many bytes are currently used. - - //! \internal - //! \{ - - struct RbNode; - struct MemNode; - struct PermanentNode; - - // Memory nodes root. - MemNode* _root; - // Memory nodes list. - MemNode* _first; - MemNode* _last; - MemNode* _optimal; - // Permanent memory. - PermanentNode* _permanent; - - //! \} -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_VMEM_H diff --git a/libs/asmjit/base/zone.cpp b/libs/asmjit/base/zone.cpp deleted file mode 100644 index 6dd535de..00000000 --- a/libs/asmjit/base/zone.cpp +++ /dev/null @@ -1,962 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Dependencies] -#include "../base/utils.h" -#include "../base/zone.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! Zero size block used by `Zone` that doesn't have any memory allocated. -static const Zone::Block Zone_zeroBlock = { nullptr, nullptr, 0, { 0 } }; - -static ASMJIT_INLINE uint32_t Zone_getAlignmentOffsetFromAlignment(uint32_t x) noexcept { - switch (x) { - default: return 0; - case 0 : return 0; - case 1 : return 0; - case 2 : return 1; - case 4 : return 2; - case 8 : return 3; - case 16: return 4; - case 32: return 5; - case 64: return 6; - } -} - -// ============================================================================ -// [asmjit::Zone - Construction / Destruction] -// ============================================================================ - -Zone::Zone(uint32_t blockSize, uint32_t blockAlignment) noexcept - : _ptr(nullptr), - _end(nullptr), - _block(const_cast(&Zone_zeroBlock)), - _blockSize(blockSize), - _blockAlignmentShift(Zone_getAlignmentOffsetFromAlignment(blockAlignment)) {} - -Zone::~Zone() noexcept { - reset(true); -} - -// ============================================================================ -// [asmjit::Zone - Reset] -// ============================================================================ - -void Zone::reset(bool releaseMemory) noexcept { - Block* cur = _block; - - // Can't be altered. - if (cur == &Zone_zeroBlock) - return; - - if (releaseMemory) { - // Since cur can be in the middle of the double-linked list, we have to - // traverse to both directions `prev` and `next` separately. - Block* next = cur->next; - do { - Block* prev = cur->prev; - Internal::releaseMemory(cur); - cur = prev; - } while (cur); - - cur = next; - while (cur) { - next = cur->next; - Internal::releaseMemory(cur); - cur = next; - } - - _ptr = nullptr; - _end = nullptr; - _block = const_cast(&Zone_zeroBlock); - } - else { - while (cur->prev) - cur = cur->prev; - - _ptr = cur->data; - _end = _ptr + cur->size; - _block = cur; - } -} - -// ============================================================================ -// [asmjit::Zone - Alloc] -// ============================================================================ - -void* Zone::_alloc(size_t size) noexcept { - Block* curBlock = _block; - uint8_t* p; - - size_t blockSize = std::max(_blockSize, size); - size_t blockAlignment = getBlockAlignment(); - - // The `_alloc()` method can only be called if there is not enough space - // in the current block, see `alloc()` implementation for more details. - ASMJIT_ASSERT(curBlock == &Zone_zeroBlock || getRemainingSize() < size); - - // If the `Zone` has been cleared the current block doesn't have to be the - // last one. Check if there is a block that can be used instead of allocating - // a new one. If there is a `next` block it's completely unused, we don't have - // to check for remaining bytes. - Block* next = curBlock->next; - if (next && next->size >= size) { - p = Utils::alignTo(next->data, blockAlignment); - - _block = next; - _ptr = p + size; - _end = next->data + next->size; - - return static_cast(p); - } - - // Prevent arithmetic overflow. - if (ASMJIT_UNLIKELY(blockSize > (~static_cast(0) - sizeof(Block) - blockAlignment))) - return nullptr; - - blockSize += blockAlignment; - Block* newBlock = static_cast(Internal::allocMemory(sizeof(Block) + blockSize)); - - if (ASMJIT_UNLIKELY(!newBlock)) - return nullptr; - - // Align the pointer to `blockAlignment` and adjust the size of this block - // accordingly. It's the same as using `blockAlignment - Utils::alignDiff()`, - // just written differently. - p = Utils::alignTo(newBlock->data, blockAlignment); - newBlock->prev = nullptr; - newBlock->next = nullptr; - newBlock->size = blockSize; - - if (curBlock != &Zone_zeroBlock) { - newBlock->prev = curBlock; - curBlock->next = newBlock; - - // Does only happen if there is a next block, but the requested memory - // can't fit into it. In this case a new buffer is allocated and inserted - // between the current block and the next one. - if (next) { - newBlock->next = next; - next->prev = newBlock; - } - } - - _block = newBlock; - _ptr = p + size; - _end = newBlock->data + blockSize; - - return static_cast(p); -} - -void* Zone::allocZeroed(size_t size) noexcept { - void* p = alloc(size); - if (ASMJIT_UNLIKELY(!p)) return p; - return ::memset(p, 0, size); -} - -void* Zone::dup(const void* data, size_t size, bool nullTerminate) noexcept { - if (ASMJIT_UNLIKELY(!data || !size)) return nullptr; - - ASMJIT_ASSERT(size != IntTraits::maxValue()); - uint8_t* m = allocT(size + nullTerminate); - if (ASMJIT_UNLIKELY(!m)) return nullptr; - - ::memcpy(m, data, size); - if (nullTerminate) m[size] = '\0'; - - return static_cast(m); -} - -char* Zone::sformat(const char* fmt, ...) noexcept { - if (ASMJIT_UNLIKELY(!fmt)) return nullptr; - - char buf[512]; - size_t len; - - va_list ap; - va_start(ap, fmt); - - len = vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf) - 1, fmt, ap); - buf[len++] = 0; - - va_end(ap); - return static_cast(dup(buf, len)); -} - -// ============================================================================ -// [asmjit::ZoneHeap - Helpers] -// ============================================================================ - -static bool ZoneHeap_hasDynamicBlock(ZoneHeap* self, ZoneHeap::DynamicBlock* block) noexcept { - ZoneHeap::DynamicBlock* cur = self->_dynamicBlocks; - while (cur) { - if (cur == block) - return true; - cur = cur->next; - } - return false; -} - -// ============================================================================ -// [asmjit::ZoneHeap - Init / Reset] -// ============================================================================ - -void ZoneHeap::reset(Zone* zone) noexcept { - // Free dynamic blocks. - DynamicBlock* block = _dynamicBlocks; - while (block) { - DynamicBlock* next = block->next; - Internal::releaseMemory(block); - block = next; - } - - // Zero the entire class and initialize to the given `zone`. - ::memset(this, 0, sizeof(*this)); - _zone = zone; -} - -// ============================================================================ -// [asmjit::ZoneHeap - Alloc / Release] -// ============================================================================ - -void* ZoneHeap::_alloc(size_t size, size_t& allocatedSize) noexcept { - ASMJIT_ASSERT(isInitialized()); - - // We use our memory pool only if the requested block is of a reasonable size. - uint32_t slot; - if (_getSlotIndex(size, slot, allocatedSize)) { - // Slot reuse. - uint8_t* p = reinterpret_cast(_slots[slot]); - size = allocatedSize; - - if (p) { - _slots[slot] = reinterpret_cast(p)->next; - //printf("ALLOCATED %p of size %d (SLOT %d)\n", p, int(size), slot); - return p; - } - - // So use Zone to allocate a new chunk for us. But before we use it, we - // check if there is enough room for the new chunk in zone, and if not, - // we redistribute the remaining memory in Zone's current block into slots. - Zone* zone = _zone; - p = Utils::alignTo(zone->getCursor(), kBlockAlignment); - size_t remain = (p <= zone->getEnd()) ? (size_t)(zone->getEnd() - p) : size_t(0); - - if (ASMJIT_LIKELY(remain >= size)) { - zone->setCursor(p + size); - //printf("ALLOCATED %p of size %d (SLOT %d)\n", p, int(size), slot); - return p; - } - else { - // Distribute the remaining memory to suitable slots. - if (remain >= kLoGranularity) { - do { - size_t distSize = std::min(remain, kLoMaxSize); - uint32_t distSlot = static_cast((distSize - kLoGranularity) / kLoGranularity); - ASMJIT_ASSERT(distSlot < kLoCount); - - reinterpret_cast(p)->next = _slots[distSlot]; - _slots[distSlot] = reinterpret_cast(p); - - p += distSize; - remain -= distSize; - } while (remain >= kLoGranularity); - zone->setCursor(p); - } - - p = static_cast(zone->_alloc(size)); - if (ASMJIT_UNLIKELY(!p)) { - allocatedSize = 0; - return nullptr; - } - - //printf("ALLOCATED %p of size %d (SLOT %d)\n", p, int(size), slot); - return p; - } - } - else { - // Allocate a dynamic block. - size_t overhead = sizeof(DynamicBlock) + sizeof(DynamicBlock*) + kBlockAlignment; - - // Handle a possible overflow. - if (ASMJIT_UNLIKELY(overhead >= ~static_cast(0) - size)) - return nullptr; - - void* p = Internal::allocMemory(size + overhead); - if (ASMJIT_UNLIKELY(!p)) { - allocatedSize = 0; - return nullptr; - } - - // Link as first in `_dynamicBlocks` double-linked list. - DynamicBlock* block = static_cast(p); - DynamicBlock* next = _dynamicBlocks; - - if (next) - next->prev = block; - - block->prev = nullptr; - block->next = next; - _dynamicBlocks = block; - - // Align the pointer to the guaranteed alignment and store `DynamicBlock` - // at the end of the memory block, so `_releaseDynamic()` can find it. - p = Utils::alignTo(static_cast(p) + sizeof(DynamicBlock) + sizeof(DynamicBlock*), kBlockAlignment); - reinterpret_cast(p)[-1] = block; - - allocatedSize = size; - //printf("ALLOCATED DYNAMIC %p of size %d\n", p, int(size)); - return p; - } -} - -void* ZoneHeap::_allocZeroed(size_t size, size_t& allocatedSize) noexcept { - ASMJIT_ASSERT(isInitialized()); - - void* p = _alloc(size, allocatedSize); - if (ASMJIT_UNLIKELY(!p)) return p; - return ::memset(p, 0, allocatedSize); -} - -void ZoneHeap::_releaseDynamic(void* p, size_t size) noexcept { - ASMJIT_ASSERT(isInitialized()); - //printf("RELEASING DYNAMIC %p of size %d\n", p, int(size)); - - // Pointer to `DynamicBlock` is stored at [-1]. - DynamicBlock* block = reinterpret_cast(p)[-1]; - ASMJIT_ASSERT(ZoneHeap_hasDynamicBlock(this, block)); - - // Unlink and free. - DynamicBlock* prev = block->prev; - DynamicBlock* next = block->next; - - if (prev) - prev->next = next; - else - _dynamicBlocks = next; - - if (next) - next->prev = prev; - - Internal::releaseMemory(block); -} - -// ============================================================================ -// [asmjit::ZoneVectorBase - Helpers] -// ============================================================================ - -Error ZoneVectorBase::_grow(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept { - size_t threshold = Globals::kAllocThreshold / sizeOfT; - size_t capacity = _capacity; - size_t after = _length; - - if (ASMJIT_UNLIKELY(IntTraits::maxValue() - n < after)) - return DebugUtils::errored(kErrorNoHeapMemory); - - after += n; - if (capacity >= after) - return kErrorOk; - - // ZoneVector is used as an array to hold short-lived data structures used - // during code generation. The growing strategy is simple - use small capacity - // at the beginning (very good for ZoneHeap) and then grow quicker to prevent - // successive reallocations. - if (capacity < 4) - capacity = 4; - else if (capacity < 8) - capacity = 8; - else if (capacity < 16) - capacity = 16; - else if (capacity < 64) - capacity = 64; - else if (capacity < 256) - capacity = 256; - - while (capacity < after) { - if (capacity < threshold) - capacity *= 2; - else - capacity += threshold; - } - - return _reserve(heap, sizeOfT, capacity); -} - -Error ZoneVectorBase::_reserve(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept { - size_t oldCapacity = _capacity; - if (oldCapacity >= n) return kErrorOk; - - size_t nBytes = n * sizeOfT; - if (ASMJIT_UNLIKELY(nBytes < n)) - return DebugUtils::errored(kErrorNoHeapMemory); - - size_t allocatedBytes; - uint8_t* newData = static_cast(heap->alloc(nBytes, allocatedBytes)); - - if (ASMJIT_UNLIKELY(!newData)) - return DebugUtils::errored(kErrorNoHeapMemory); - - void* oldData = _data; - if (_length) - ::memcpy(newData, oldData, _length * sizeOfT); - - if (oldData) - heap->release(oldData, oldCapacity * sizeOfT); - - _capacity = allocatedBytes / sizeOfT; - ASMJIT_ASSERT(_capacity >= n); - - _data = newData; - return kErrorOk; -} - -Error ZoneVectorBase::_resize(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept { - size_t length = _length; - if (_capacity < n) { - ASMJIT_PROPAGATE(_grow(heap, sizeOfT, n - length)); - ASMJIT_ASSERT(_capacity >= n); - } - - if (length < n) - ::memset(static_cast(_data) + length * sizeOfT, 0, (n - length) * sizeOfT); - - _length = n; - return kErrorOk; -} - -// ============================================================================ -// [asmjit::ZoneBitVector - Ops] -// ============================================================================ - -Error ZoneBitVector::_resize(ZoneHeap* heap, size_t newLength, size_t idealCapacity, bool newBitsValue) noexcept { - ASMJIT_ASSERT(idealCapacity >= newLength); - - if (newLength <= _length) { - // The size after the resize is lesser than or equal to the current length. - size_t idx = newLength / kBitsPerWord; - size_t bit = newLength % kBitsPerWord; - - // Just set all bits outside of the new length in the last word to zero. - // There is a case that there are not bits to set if `bit` is zero. This - // happens when `newLength` is a multiply of `kBitsPerWord` like 64, 128, - // and so on. In that case don't change anything as that would mean settings - // bits outside of the `_length`. - if (bit) - _data[idx] &= (static_cast(1) << bit) - 1U; - - _length = newLength; - return kErrorOk; - } - - size_t oldLength = _length; - BitWord* data = _data; - - if (newLength > _capacity) { - // Realloc needed... Calculate the minimum capacity (in bytes) requied. - size_t minimumCapacityInBits = Utils::alignTo(idealCapacity, kBitsPerWord); - size_t allocatedCapacity; - - if (ASMJIT_UNLIKELY(minimumCapacityInBits < newLength)) - return DebugUtils::errored(kErrorNoHeapMemory); - - // Normalize to bytes. - size_t minimumCapacity = minimumCapacityInBits / 8; - BitWord* newData = static_cast(heap->alloc(minimumCapacity, allocatedCapacity)); - - if (ASMJIT_UNLIKELY(!newData)) - return DebugUtils::errored(kErrorNoHeapMemory); - - // `allocatedCapacity` now contains number in bytes, we need bits. - size_t allocatedCapacityInBits = allocatedCapacity * 8; - - // Arithmetic overflow should normally not happen. If it happens we just - // change the `allocatedCapacityInBits` to the `minimumCapacityInBits` as - // this value is still safe to be used to call `_heap->release(...)`. - if (ASMJIT_UNLIKELY(allocatedCapacityInBits < allocatedCapacity)) - allocatedCapacityInBits = minimumCapacityInBits; - - if (oldLength) - ::memcpy(newData, data, _wordsPerBits(oldLength)); - - if (data) - heap->release(data, _capacity / 8); - data = newData; - - _data = data; - _capacity = allocatedCapacityInBits; - } - - // Start (of the old length) and end (of the new length) bits - size_t idx = oldLength / kBitsPerWord; - size_t startBit = oldLength % kBitsPerWord; - size_t endBit = newLength % kBitsPerWord; - - // Set new bits to either 0 or 1. The `pattern` is used to set multiple - // bits per bit-word and contains either all zeros or all ones. - BitWord pattern = _patternFromBit(newBitsValue); - - // First initialize the last bit-word of the old length. - if (startBit) { - size_t nBits = 0; - - if (idx == (newLength / kBitsPerWord)) { - // The number of bit-words is the same after the resize. In that case - // we need to set only bits necessary in the current last bit-word. - ASMJIT_ASSERT(startBit < endBit); - nBits = endBit - startBit; - } - else { - // There is be more bit-words after the resize. In that case we don't - // have to be extra careful about the last bit-word of the old length. - nBits = kBitsPerWord - startBit; - } - - data[idx++] |= pattern << nBits; - } - - // Initialize all bit-words after the last bit-word of the old length. - size_t endIdx = _wordsPerBits(newLength); - endIdx -= static_cast(endIdx * kBitsPerWord == newLength); - - while (idx <= endIdx) - data[idx++] = pattern; - - // Clear unused bits of the last bit-word. - if (endBit) - data[endIdx] &= (static_cast(1) << endBit) - 1; - - _length = newLength; - return kErrorOk; -} - -Error ZoneBitVector::_append(ZoneHeap* heap, bool value) noexcept { - size_t kThreshold = Globals::kAllocThreshold * 8; - size_t newLength = _length + 1; - size_t idealCapacity = _capacity; - - if (idealCapacity < 128) - idealCapacity = 128; - else if (idealCapacity <= kThreshold) - idealCapacity *= 2; - else - idealCapacity += kThreshold; - - if (ASMJIT_UNLIKELY(idealCapacity < _capacity)) { - // It's technically impossible that `_length + 1` overflows. - idealCapacity = newLength; - ASMJIT_ASSERT(idealCapacity > _capacity); - } - - return _resize(heap, newLength, idealCapacity, value); -} - -Error ZoneBitVector::fill(size_t from, size_t to, bool value) noexcept { - if (ASMJIT_UNLIKELY(from >= to)) { - if (from > to) - return DebugUtils::errored(kErrorInvalidArgument); - else - return kErrorOk; - } - - ASMJIT_ASSERT(from <= _length); - ASMJIT_ASSERT(to <= _length); - - // This is very similar to `ZoneBitVector::_fill()`, however, since we - // actually set bits that are already part of the container we need to - // special case filiing to zeros and ones. - size_t idx = from / kBitsPerWord; - size_t startBit = from % kBitsPerWord; - - size_t endIdx = to / kBitsPerWord; - size_t endBit = to % kBitsPerWord; - - BitWord* data = _data; - ASMJIT_ASSERT(data != nullptr); - - // Special case for non-zero `startBit`. - if (startBit) { - if (idx == endIdx) { - ASMJIT_ASSERT(startBit < endBit); - - size_t nBits = endBit - startBit; - BitWord mask = ((static_cast(1) << nBits) - 1) << startBit; - - if (value) - data[idx] |= mask; - else - data[idx] &= ~mask; - return kErrorOk; - } - else { - BitWord mask = (static_cast(0) - 1) << startBit; - - if (value) - data[idx++] |= mask; - else - data[idx++] &= ~mask; - } - } - - // Fill all bits in case there is a gap between the current `idx` and `endIdx`. - if (idx < endIdx) { - BitWord pattern = _patternFromBit(value); - do { - data[idx++] = pattern; - } while (idx < endIdx); - } - - // Special case for non-zero `endBit`. - if (endBit) { - BitWord mask = ((static_cast(1) << endBit) - 1); - if (value) - data[endIdx] |= mask; - else - data[endIdx] &= ~mask; - } - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::ZoneStackBase - Init / Reset] -// ============================================================================ - -Error ZoneStackBase::_init(ZoneHeap* heap, size_t middleIndex) noexcept { - ZoneHeap* oldHeap = _heap; - - if (oldHeap) { - Block* block = _block[kSideLeft]; - while (block) { - Block* next = block->getNext(); - oldHeap->release(block, kBlockSize); - block = next; - } - - _heap = nullptr; - _block[kSideLeft] = nullptr; - _block[kSideRight] = nullptr; - } - - - if (heap) { - Block* block = static_cast(heap->alloc(kBlockSize)); - if (ASMJIT_UNLIKELY(!block)) - return DebugUtils::errored(kErrorNoHeapMemory); - - block->_link[kSideLeft] = nullptr; - block->_link[kSideRight] = nullptr; - block->_start = (uint8_t*)block + middleIndex; - block->_end = (uint8_t*)block + middleIndex; - - _heap = heap; - _block[kSideLeft] = block; - _block[kSideRight] = block; - } - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::ZoneStackBase - Ops] -// ============================================================================ - -Error ZoneStackBase::_prepareBlock(uint32_t side, size_t initialIndex) noexcept { - ASMJIT_ASSERT(isInitialized()); - - Block* prev = _block[side]; - ASMJIT_ASSERT(!prev->isEmpty()); - - Block* block = _heap->allocT(kBlockSize); - if (ASMJIT_UNLIKELY(!block)) - return DebugUtils::errored(kErrorNoHeapMemory); - - block->_link[ side] = nullptr; - block->_link[!side] = prev; - block->_start = (uint8_t*)block + initialIndex; - block->_end = (uint8_t*)block + initialIndex; - - prev->_link[side] = block; - _block[side] = block; - - return kErrorOk; -} - -void ZoneStackBase::_cleanupBlock(uint32_t side, size_t middleIndex) noexcept { - Block* block = _block[side]; - ASMJIT_ASSERT(block->isEmpty()); - - Block* prev = block->_link[!side]; - if (prev) { - ASMJIT_ASSERT(prev->_link[side] == block); - _heap->release(block, kBlockSize); - - prev->_link[side] = nullptr; - _block[side] = prev; - } - else if (_block[!side] == prev && prev->isEmpty()) { - // If the container becomes empty center both pointers in the remaining block. - prev->_start = (uint8_t*)prev + middleIndex; - prev->_end = (uint8_t*)prev + middleIndex; - } -} - -// ============================================================================ -// [asmjit::ZoneHashBase - Utilities] -// ============================================================================ - -static uint32_t ZoneHash_getClosestPrime(uint32_t x) noexcept { - static const uint32_t primeTable[] = { - 23, 53, 193, 389, 769, 1543, 3079, 6151, 12289, 24593 - }; - - size_t i = 0; - uint32_t p; - - do { - if ((p = primeTable[i]) > x) - break; - } while (++i < ASMJIT_ARRAY_SIZE(primeTable)); - - return p; -} - -// ============================================================================ -// [asmjit::ZoneHashBase - Reset] -// ============================================================================ - -void ZoneHashBase::reset(ZoneHeap* heap) noexcept { - ZoneHashNode** oldData = _data; - if (oldData != _embedded) - _heap->release(oldData, _bucketsCount * sizeof(ZoneHashNode*)); - - _heap = heap; - _size = 0; - _bucketsCount = 1; - _bucketsGrow = 1; - _data = _embedded; - _embedded[0] = nullptr; -} - -// ============================================================================ -// [asmjit::ZoneHashBase - Rehash] -// ============================================================================ - -void ZoneHashBase::_rehash(uint32_t newCount) noexcept { - ASMJIT_ASSERT(isInitialized()); - - ZoneHashNode** oldData = _data; - ZoneHashNode** newData = reinterpret_cast( - _heap->allocZeroed(static_cast(newCount) * sizeof(ZoneHashNode*))); - - // We can still store nodes into the table, but it will degrade. - if (ASMJIT_UNLIKELY(newData == nullptr)) - return; - - uint32_t i; - uint32_t oldCount = _bucketsCount; - - for (i = 0; i < oldCount; i++) { - ZoneHashNode* node = oldData[i]; - while (node) { - ZoneHashNode* next = node->_hashNext; - uint32_t hMod = node->_hVal % newCount; - - node->_hashNext = newData[hMod]; - newData[hMod] = node; - - node = next; - } - } - - // 90% is the maximum occupancy, can't overflow since the maximum capacity - // is limited to the last prime number stored in the prime table. - if (oldData != _embedded) - _heap->release(oldData, _bucketsCount * sizeof(ZoneHashNode*)); - - _bucketsCount = newCount; - _bucketsGrow = newCount * 9 / 10; - - _data = newData; -} - -// ============================================================================ -// [asmjit::ZoneHashBase - Ops] -// ============================================================================ - -ZoneHashNode* ZoneHashBase::_put(ZoneHashNode* node) noexcept { - uint32_t hMod = node->_hVal % _bucketsCount; - ZoneHashNode* next = _data[hMod]; - - node->_hashNext = next; - _data[hMod] = node; - - if (++_size >= _bucketsGrow && next) { - uint32_t newCapacity = ZoneHash_getClosestPrime(_bucketsCount); - if (newCapacity != _bucketsCount) - _rehash(newCapacity); - } - - return node; -} - -ZoneHashNode* ZoneHashBase::_del(ZoneHashNode* node) noexcept { - uint32_t hMod = node->_hVal % _bucketsCount; - - ZoneHashNode** pPrev = &_data[hMod]; - ZoneHashNode* p = *pPrev; - - while (p) { - if (p == node) { - *pPrev = p->_hashNext; - return node; - } - - pPrev = &p->_hashNext; - p = *pPrev; - } - - return nullptr; -} - -// ============================================================================ -// [asmjit::Zone - Test] -// ============================================================================ - -#if defined(ASMJIT_TEST) -UNIT(base_zonevector) { - Zone zone(8096 - Zone::kZoneOverhead); - ZoneHeap heap(&zone); - - int i; - int kMax = 100000; - - ZoneVector vec; - - INFO("ZoneVector basic tests"); - EXPECT(vec.append(&heap, 0) == kErrorOk); - EXPECT(vec.isEmpty() == false); - EXPECT(vec.getLength() == 1); - EXPECT(vec.getCapacity() >= 1); - EXPECT(vec.indexOf(0) == 0); - EXPECT(vec.indexOf(-11) == Globals::kInvalidIndex); - - vec.clear(); - EXPECT(vec.isEmpty()); - EXPECT(vec.getLength() == 0); - EXPECT(vec.indexOf(0) == Globals::kInvalidIndex); - - for (i = 0; i < kMax; i++) { - EXPECT(vec.append(&heap, i) == kErrorOk); - } - EXPECT(vec.isEmpty() == false); - EXPECT(vec.getLength() == static_cast(kMax)); - EXPECT(vec.indexOf(kMax - 1) == static_cast(kMax - 1)); -} - -UNIT(base_ZoneBitVector) { - Zone zone(8096 - Zone::kZoneOverhead); - ZoneHeap heap(&zone); - - size_t i, count; - size_t kMaxCount = 100; - - ZoneBitVector vec; - EXPECT(vec.isEmpty()); - EXPECT(vec.getLength() == 0); - - INFO("ZoneBitVector::resize()"); - for (count = 1; count < kMaxCount; count++) { - vec.clear(); - EXPECT(vec.resize(&heap, count, false) == kErrorOk); - EXPECT(vec.getLength() == count); - - for (i = 0; i < count; i++) - EXPECT(vec.getAt(i) == false); - - vec.clear(); - EXPECT(vec.resize(&heap, count, true) == kErrorOk); - EXPECT(vec.getLength() == count); - - for (i = 0; i < count; i++) - EXPECT(vec.getAt(i) == true); - } - - INFO("ZoneBitVector::fill()"); - for (count = 1; count < kMaxCount; count += 2) { - vec.clear(); - EXPECT(vec.resize(&heap, count) == kErrorOk); - EXPECT(vec.getLength() == count); - - for (i = 0; i < (count + 1) / 2; i++) { - bool value = static_cast(i & 1); - EXPECT(vec.fill(i, count - i, value) == kErrorOk); - } - - for (i = 0; i < count; i++) { - EXPECT(vec.getAt(i) == static_cast(i & 1)); - } - } -} - -UNIT(base_zonestack) { - Zone zone(8096 - Zone::kZoneOverhead); - ZoneHeap heap(&zone); - ZoneStack stack; - - INFO("ZoneStack contains %d elements per one Block", ZoneStack::kNumBlockItems); - - EXPECT(stack.init(&heap) == kErrorOk); - EXPECT(stack.isEmpty(), "Stack must be empty after `init()`"); - - EXPECT(stack.append(42) == kErrorOk); - EXPECT(!stack.isEmpty() , "Stack must not be empty after an item has been appended"); - EXPECT(stack.pop() == 42, "Stack.pop() must return the item that has been appended last"); - EXPECT(stack.isEmpty() , "Stack must be empty after the last element has been removed"); - - EXPECT(stack.prepend(43) == kErrorOk); - EXPECT(!stack.isEmpty() , "Stack must not be empty after an item has been prepended"); - EXPECT(stack.popFirst() == 43, "Stack.popFirst() must return the item that has been prepended last"); - EXPECT(stack.isEmpty() , "Stack must be empty after the last element has been removed"); - - int i; - int iMin =-100; - int iMax = 100000; - - INFO("Adding items from %d to %d to the stack", iMin, iMax); - for (i = 1; i <= iMax; i++) stack.append(i); - for (i = 0; i >= iMin; i--) stack.prepend(i); - - INFO("Validating popFirst()"); - for (i = iMin; i <= iMax; i++) { - int item = stack.popFirst(); - EXPECT(i == item, "Item '%d' didn't match the item '%d' popped", i, item); - } - EXPECT(stack.isEmpty()); - - INFO("Adding items from %d to %d to the stack", iMin, iMax); - for (i = 0; i >= iMin; i--) stack.prepend(i); - for (i = 1; i <= iMax; i++) stack.append(i); - - INFO("Validating pop()"); - for (i = iMax; i >= iMin; i--) { - int item = stack.pop(); - EXPECT(i == item, "Item '%d' didn't match the item '%d' popped", i, item); - } - EXPECT(stack.isEmpty()); -} -#endif // ASMJIT_TEST - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" diff --git a/libs/asmjit/base/zone.h b/libs/asmjit/base/zone.h deleted file mode 100644 index 5a461a29..00000000 --- a/libs/asmjit/base/zone.h +++ /dev/null @@ -1,1329 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_BASE_ZONE_H -#define _ASMJIT_BASE_ZONE_H - -// [Dependencies] -#include "../base/utils.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -//! \addtogroup asmjit_base -//! \{ - -// ============================================================================ -// [asmjit::Zone] -// ============================================================================ - -//! Memory zone. -//! -//! Zone is an incremental memory allocator that allocates memory by simply -//! incrementing a pointer. It allocates blocks of memory by using standard -//! C `malloc`, but divides these blocks into smaller segments requested by -//! calling `Zone::alloc()` and friends. -//! -//! Zone has no function to release the allocated memory. It has to be released -//! all at once by calling `reset()`. If you need a more friendly allocator that -//! also supports `release()`, consider using \ref Zone with \ref ZoneHeap. -class Zone { -public: - //! \internal - //! - //! A single block of memory. - struct Block { - Block* prev; //!< Link to the previous block. - Block* next; //!< Link to the next block. - size_t size; //!< Size of the block. - uint8_t data[sizeof(void*)]; //!< Data. - }; - - enum { - //! Zone allocator overhead. - kZoneOverhead = Globals::kAllocOverhead + static_cast(sizeof(Block)) - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new instance of `Zone` allocator. - //! - //! The `blockSize` parameter describes the default size of the block. If the - //! `size` parameter passed to `alloc()` is greater than the default size - //! `Zone` will allocate and use a larger block, but it will not change the - //! default `blockSize`. - //! - //! It's not required, but it's good practice to set `blockSize` to a - //! reasonable value that depends on the usage of `Zone`. Greater block sizes - //! are generally safer and perform better than unreasonably low values. - ASMJIT_API Zone(uint32_t blockSize, uint32_t blockAlignment = 0) noexcept; - - //! Destroy the `Zone` instance. - //! - //! This will destroy the `Zone` instance and release all blocks of memory - //! allocated by it. It performs implicit `reset(true)`. - ASMJIT_API ~Zone() noexcept; - - // -------------------------------------------------------------------------- - // [Reset] - // -------------------------------------------------------------------------- - - //! Reset the `Zone` invalidating all blocks allocated. - //! - //! If `releaseMemory` is true all buffers will be released to the system. - ASMJIT_API void reset(bool releaseMemory = false) noexcept; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get the default block size. - ASMJIT_INLINE uint32_t getBlockSize() const noexcept { return _blockSize; } - //! Get the default block alignment. - ASMJIT_INLINE uint32_t getBlockAlignment() const noexcept { return (uint32_t)1 << _blockAlignmentShift; } - //! Get remaining size of the current block. - ASMJIT_INLINE size_t getRemainingSize() const noexcept { return (size_t)(_end - _ptr); } - - //! Get the current zone cursor (dangerous). - //! - //! This is a function that can be used to get exclusive access to the current - //! block's memory buffer. - ASMJIT_INLINE uint8_t* getCursor() noexcept { return _ptr; } - //! Get the end of the current zone block, only useful if you use `getCursor()`. - ASMJIT_INLINE uint8_t* getEnd() noexcept { return _end; } - - //! Set the current zone cursor to `p` (must match the current block). - //! - //! This is a counterpart of `getZoneCursor()`. - ASMJIT_INLINE void setCursor(uint8_t* p) noexcept { - ASMJIT_ASSERT(p >= _ptr && p <= _end); - _ptr = p; - } - - // -------------------------------------------------------------------------- - // [Alloc] - // -------------------------------------------------------------------------- - - //! Allocate `size` bytes of memory. - //! - //! Pointer returned is valid until the `Zone` instance is destroyed or reset - //! by calling `reset()`. If you plan to make an instance of C++ from the - //! given pointer use placement `new` and `delete` operators: - //! - //! ~~~ - //! using namespace asmjit; - //! - //! class Object { ... }; - //! - //! // Create Zone with default block size of approximately 65536 bytes. - //! Zone zone(65536 - Zone::kZoneOverhead); - //! - //! // Create your objects using zone object allocating, for example: - //! Object* obj = static_cast( zone.alloc(sizeof(Object)) ); - // - //! if (!obj) { - //! // Handle out of memory error. - //! } - //! - //! // Placement `new` and `delete` operators can be used to instantiate it. - //! new(obj) Object(); - //! - //! // ... lifetime of your objects ... - //! - //! // To destroy the instance (if required). - //! obj->~Object(); - //! - //! // Reset or destroy `Zone`. - //! zone.reset(); - //! ~~~ - ASMJIT_INLINE void* alloc(size_t size) noexcept { - uint8_t* ptr = _ptr; - size_t remainingBytes = (size_t)(_end - ptr); - - if (ASMJIT_UNLIKELY(remainingBytes < size)) - return _alloc(size); - - _ptr += size; - ASMJIT_ASSERT(_ptr <= _end); - - return static_cast(ptr); - } - - //! Allocate `size` bytes without any checks. - //! - //! Can only be called if `getRemainingSize()` returns size at least equal - //! to `size`. - ASMJIT_INLINE void* allocNoCheck(size_t size) noexcept { - ASMJIT_ASSERT((size_t)(_end - _ptr) >= size); - - uint8_t* ptr = _ptr; - _ptr += size; - return static_cast(ptr); - } - - //! Allocate `size` bytes of zeroed memory. - //! - //! See \ref alloc() for more details. - ASMJIT_API void* allocZeroed(size_t size) noexcept; - - //! Like `alloc()`, but the return pointer is casted to `T*`. - template - ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) noexcept { - return static_cast(alloc(size)); - } - - //! Like `allocNoCheck()`, but the return pointer is casted to `T*`. - template - ASMJIT_INLINE T* allocNoCheckT(size_t size = sizeof(T)) noexcept { - return static_cast(allocNoCheck(size)); - } - - //! Like `allocZeroed()`, but the return pointer is casted to `T*`. - template - ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) noexcept { - return static_cast(allocZeroed(size)); - } - - //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`. - template - ASMJIT_INLINE T* newT() noexcept { - void* p = alloc(sizeof(T)); - if (ASMJIT_UNLIKELY(!p)) - return nullptr; - return new(p) T(); - } - //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`. - template - ASMJIT_INLINE T* newT(P1 p1) noexcept { - void* p = alloc(sizeof(T)); - if (ASMJIT_UNLIKELY(!p)) - return nullptr; - return new(p) T(p1); - } - - //! \internal - ASMJIT_API void* _alloc(size_t size) noexcept; - - //! Helper to duplicate data. - ASMJIT_API void* dup(const void* data, size_t size, bool nullTerminate = false) noexcept; - - //! Helper to duplicate formatted string, maximum length is 256 bytes. - ASMJIT_API char* sformat(const char* str, ...) noexcept; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - uint8_t* _ptr; //!< Pointer in the current block's buffer. - uint8_t* _end; //!< End of the current block's buffer. - Block* _block; //!< Current block. - -#if ASMJIT_ARCH_64BIT - uint32_t _blockSize; //!< Default size of a newly allocated block. - uint32_t _blockAlignmentShift; //!< Minimum alignment of each block. -#else - uint32_t _blockSize : 29; //!< Default size of a newly allocated block. - uint32_t _blockAlignmentShift : 3; //!< Minimum alignment of each block. -#endif -}; - -// ============================================================================ -// [asmjit::ZoneHeap] -// ============================================================================ - -//! Zone-based memory allocator that uses an existing \ref Zone and provides -//! a `release()` functionality on top of it. It uses \ref Zone only for chunks -//! that can be pooled, and uses libc `malloc()` for chunks that are large. -//! -//! The advantage of ZoneHeap is that it can allocate small chunks of memory -//! really fast, and these chunks, when released, will be reused by consecutive -//! calls to `alloc()`. Also, since ZoneHeap uses \ref Zone, you can turn any -//! \ref Zone into a \ref ZoneHeap, and use it in your \ref Pass when necessary. -//! -//! ZoneHeap is used by AsmJit containers to make containers having only -//! few elements fast (and lightweight) and to allow them to grow and use -//! dynamic blocks when require more storage. -class ZoneHeap { - ASMJIT_NONCOPYABLE(ZoneHeap) - - enum { - // In short, we pool chunks of these sizes: - // [32, 64, 96, 128, 192, 256, 320, 384, 448, 512] - - //! How many bytes per a low granularity pool (has to be at least 16). - kLoGranularity = 32, - //! Number of slots of a low granularity pool. - kLoCount = 4, - //! Maximum size of a block that can be allocated in a low granularity pool. - kLoMaxSize = kLoGranularity * kLoCount, - - //! How many bytes per a high granularity pool. - kHiGranularity = 64, - //! Number of slots of a high granularity pool. - kHiCount = 6, - //! Maximum size of a block that can be allocated in a high granularity pool. - kHiMaxSize = kLoMaxSize + kHiGranularity * kHiCount, - - //! Alignment of every pointer returned by `alloc()`. - kBlockAlignment = kLoGranularity - }; - - //! Single-linked list used to store unused chunks. - struct Slot { - //! Link to a next slot in a single-linked list. - Slot* next; - }; - - //! A block of memory that has been allocated dynamically and is not part of - //! block-list used by the allocator. This is used to keep track of all these - //! blocks so they can be freed by `reset()` if not freed explicitly. - struct DynamicBlock { - DynamicBlock* prev; - DynamicBlock* next; - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new `ZoneHeap`. - //! - //! NOTE: To use it, you must first `init()` it. - ASMJIT_INLINE ZoneHeap() noexcept { - ::memset(this, 0, sizeof(*this)); - } - //! Create a new `ZoneHeap` initialized to use `zone`. - explicit ASMJIT_INLINE ZoneHeap(Zone* zone) noexcept { - ::memset(this, 0, sizeof(*this)); - _zone = zone; - } - //! Destroy the `ZoneHeap`. - ASMJIT_INLINE ~ZoneHeap() noexcept { reset(); } - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - //! Get if the `ZoneHeap` is initialized (i.e. has `Zone`). - ASMJIT_INLINE bool isInitialized() const noexcept { return _zone != nullptr; } - - //! Convenience method to initialize the `ZoneHeap` with `zone`. - //! - //! It's the same as calling `reset(zone)`. - ASMJIT_INLINE void init(Zone* zone) noexcept { reset(zone); } - - //! Reset this `ZoneHeap` and also forget about the current `Zone` which - //! is attached (if any). Reset optionally attaches a new `zone` passed, or - //! keeps the `ZoneHeap` in an uninitialized state, if `zone` is null. - ASMJIT_API void reset(Zone* zone = nullptr) noexcept; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get the `Zone` the `ZoneHeap` is using, or null if it's not initialized. - ASMJIT_INLINE Zone* getZone() const noexcept { return _zone; } - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - //! \internal - //! - //! Get the slot index to be used for `size`. Returns `true` if a valid slot - //! has been written to `slot` and `allocatedSize` has been filled with slot - //! exact size (`allocatedSize` can be equal or slightly greater than `size`). - static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot) noexcept { - ASMJIT_ASSERT(size > 0); - if (size > kHiMaxSize) - return false; - - if (size <= kLoMaxSize) - slot = static_cast((size - 1) / kLoGranularity); - else - slot = static_cast((size - kLoMaxSize - 1) / kHiGranularity) + kLoCount; - - return true; - } - - //! \overload - static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot, size_t& allocatedSize) noexcept { - ASMJIT_ASSERT(size > 0); - if (size > kHiMaxSize) - return false; - - if (size <= kLoMaxSize) { - slot = static_cast((size - 1) / kLoGranularity); - allocatedSize = Utils::alignTo(size, kLoGranularity); - } - else { - slot = static_cast((size - kLoMaxSize - 1) / kHiGranularity) + kLoCount; - allocatedSize = Utils::alignTo(size, kHiGranularity); - } - - return true; - } - - // -------------------------------------------------------------------------- - // [Alloc / Release] - // -------------------------------------------------------------------------- - - ASMJIT_API void* _alloc(size_t size, size_t& allocatedSize) noexcept; - ASMJIT_API void* _allocZeroed(size_t size, size_t& allocatedSize) noexcept; - ASMJIT_API void _releaseDynamic(void* p, size_t size) noexcept; - - //! Allocate `size` bytes of memory, ideally from an available pool. - //! - //! NOTE: `size` can't be zero, it will assert in debug mode in such case. - ASMJIT_INLINE void* alloc(size_t size) noexcept { - ASMJIT_ASSERT(isInitialized()); - size_t allocatedSize; - return _alloc(size, allocatedSize); - } - - //! Like `alloc(size)`, but provides a second argument `allocatedSize` that - //! provides a way to know how big the block returned actually is. This is - //! useful for containers to prevent growing too early. - ASMJIT_INLINE void* alloc(size_t size, size_t& allocatedSize) noexcept { - ASMJIT_ASSERT(isInitialized()); - return _alloc(size, allocatedSize); - } - - //! Like `alloc()`, but the return pointer is casted to `T*`. - template - ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) noexcept { - return static_cast(alloc(size)); - } - - //! Like `alloc(size)`, but returns zeroed memory. - ASMJIT_INLINE void* allocZeroed(size_t size) noexcept { - ASMJIT_ASSERT(isInitialized()); - - size_t allocatedSize; - return _allocZeroed(size, allocatedSize); - } - - //! Like `alloc(size, allocatedSize)`, but returns zeroed memory. - ASMJIT_INLINE void* allocZeroed(size_t size, size_t& allocatedSize) noexcept { - ASMJIT_ASSERT(isInitialized()); - - return _allocZeroed(size, allocatedSize); - } - - //! Like `allocZeroed()`, but the return pointer is casted to `T*`. - template - ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) noexcept { - return static_cast(allocZeroed(size)); - } - - //! Release the memory previously allocated by `alloc()`. The `size` argument - //! has to be the same as used to call `alloc()` or `allocatedSize` returned - //! by `alloc()`. - ASMJIT_INLINE void release(void* p, size_t size) noexcept { - ASMJIT_ASSERT(isInitialized()); - - ASMJIT_ASSERT(p != nullptr); - ASMJIT_ASSERT(size != 0); - - uint32_t slot; - if (_getSlotIndex(size, slot)) { - //printf("RELEASING %p of size %d (SLOT %u)\n", p, int(size), slot); - static_cast(p)->next = static_cast(_slots[slot]); - _slots[slot] = static_cast(p); - } - else { - _releaseDynamic(p, size); - } - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - Zone* _zone; //!< Zone used to allocate memory that fits into slots. - Slot* _slots[kLoCount + kHiCount]; //!< Indexed slots containing released memory. - DynamicBlock* _dynamicBlocks; //!< Dynamic blocks for larger allocations (no slots). -}; - -// ============================================================================ -// [asmjit::ZoneList] -// ============================================================================ - -//! \internal -template -class ZoneList { -public: - ASMJIT_NONCOPYABLE(ZoneList) - - // -------------------------------------------------------------------------- - // [Link] - // -------------------------------------------------------------------------- - - //! ZoneList node. - struct Link { - //! Get next node. - ASMJIT_INLINE Link* getNext() const noexcept { return _next; } - //! Get value. - ASMJIT_INLINE T getValue() const noexcept { return _value; } - //! Set value to `value`. - ASMJIT_INLINE void setValue(const T& value) noexcept { _value = value; } - - Link* _next; - T _value; - }; - - // -------------------------------------------------------------------------- - // [Appender] - // -------------------------------------------------------------------------- - - //! Specialized appender that takes advantage of ZoneList structure. You must - //! initialize it and then call done(). - struct Appender { - ASMJIT_INLINE Appender(ZoneList& list) noexcept { init(list); } - - ASMJIT_INLINE void init(ZoneList& list) noexcept { - pPrev = &list._first; - } - - ASMJIT_INLINE void done(ZoneList& list) noexcept { - list._last = *pPrev; - *pPrev = nullptr; - } - - ASMJIT_INLINE void append(Link* node) noexcept { - *pPrev = node; - pPrev = &node->_next; - } - - Link** pPrev; - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE ZoneList() noexcept : _first(nullptr), _last(nullptr) {} - ASMJIT_INLINE ~ZoneList() noexcept {} - - // -------------------------------------------------------------------------- - // [Data] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool isEmpty() const noexcept { return _first != nullptr; } - ASMJIT_INLINE Link* getFirst() const noexcept { return _first; } - ASMJIT_INLINE Link* getLast() const noexcept { return _last; } - - // -------------------------------------------------------------------------- - // [Ops] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void reset() noexcept { - _first = nullptr; - _last = nullptr; - } - - ASMJIT_INLINE void prepend(Link* link) noexcept { - link->_next = _first; - if (!_first) _last = link; - _first = link; - } - - ASMJIT_INLINE void append(Link* link) noexcept { - link->_next = nullptr; - if (!_first) - _first = link; - else - _last->_next = link; - _last = link; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - Link* _first; - Link* _last; -}; - -// ============================================================================ -// [asmjit::ZoneVectorBase] -// ============================================================================ - -//! \internal -class ZoneVectorBase { -public: - ASMJIT_NONCOPYABLE(ZoneVectorBase) - -protected: - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new instance of `ZoneVectorBase`. - explicit ASMJIT_INLINE ZoneVectorBase() noexcept - : _data(nullptr), - _length(0), - _capacity(0) {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - -public: - //! Get if the vector is empty. - ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; } - //! Get vector length. - ASMJIT_INLINE size_t getLength() const noexcept { return _length; } - //! Get vector capacity. - ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; } - - // -------------------------------------------------------------------------- - // [Ops] - // -------------------------------------------------------------------------- - - //! Makes the vector empty (won't change the capacity or data pointer). - ASMJIT_INLINE void clear() noexcept { _length = 0; } - //! Reset the vector data and set its `length` to zero. - ASMJIT_INLINE void reset() noexcept { - _data = nullptr; - _length = 0; - _capacity = 0; - } - - //! Truncate the vector to at most `n` items. - ASMJIT_INLINE void truncate(size_t n) noexcept { - _length = std::min(_length, n); - } - - // -------------------------------------------------------------------------- - // [Memory Management] - // -------------------------------------------------------------------------- - -protected: - ASMJIT_INLINE void _release(ZoneHeap* heap, size_t sizeOfT) noexcept { - if (_data != nullptr) { - heap->release(_data, _capacity * sizeOfT); - reset(); - } - } - - ASMJIT_API Error _grow(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept; - ASMJIT_API Error _resize(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept; - ASMJIT_API Error _reserve(ZoneHeap* heap, size_t sizeOfT, size_t n) noexcept; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -public: - void* _data; //!< Vector data. - size_t _length; //!< Length of the vector. - size_t _capacity; //!< Capacity of the vector. -}; - -// ============================================================================ -// [asmjit::ZoneVector] -// ============================================================================ - -//! Template used to store and manage array of Zone allocated data. -//! -//! This template has these advantages over other std::vector<>: -//! - Always non-copyable (designed to be non-copyable, we want it). -//! - No copy-on-write (some implementations of STL can use it). -//! - Optimized for working only with POD types. -//! - Uses ZoneHeap, thus small vectors are basically for free. -template -class ZoneVector : public ZoneVectorBase { -public: - ASMJIT_NONCOPYABLE(ZoneVector) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Create a new instance of `ZoneVector`. - explicit ASMJIT_INLINE ZoneVector() noexcept : ZoneVectorBase() {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get data. - ASMJIT_INLINE T* getData() noexcept { return static_cast(_data); } - //! \overload - ASMJIT_INLINE const T* getData() const noexcept { return static_cast(_data); } - - // -------------------------------------------------------------------------- - // [Ops] - // -------------------------------------------------------------------------- - - //! Prepend `item` to the vector. - Error prepend(ZoneHeap* heap, const T& item) noexcept { - if (ASMJIT_UNLIKELY(_length == _capacity)) - ASMJIT_PROPAGATE(grow(heap, 1)); - - ::memmove(static_cast(_data) + 1, _data, _length * sizeof(T)); - ::memcpy(_data, &item, sizeof(T)); - - _length++; - return kErrorOk; - } - - //! Insert an `item` at the specified `index`. - Error insert(ZoneHeap* heap, size_t index, const T& item) noexcept { - ASMJIT_ASSERT(index <= _length); - - if (ASMJIT_UNLIKELY(_length == _capacity)) - ASMJIT_PROPAGATE(grow(heap, 1)); - - T* dst = static_cast(_data) + index; - ::memmove(dst + 1, dst, _length - index); - ::memcpy(dst, &item, sizeof(T)); - - _length++; - return kErrorOk; - } - - //! Append `item` to the vector. - Error append(ZoneHeap* heap, const T& item) noexcept { - if (ASMJIT_UNLIKELY(_length == _capacity)) - ASMJIT_PROPAGATE(grow(heap, 1)); - - ::memcpy(static_cast(_data) + _length, &item, sizeof(T)); - - _length++; - return kErrorOk; - } - - Error concat(ZoneHeap* heap, const ZoneVector& other) noexcept { - size_t count = other._length; - if (_capacity - _length < count) - ASMJIT_PROPAGATE(grow(heap, count)); - - ::memcpy(static_cast(_data) + _length, other._data, count * sizeof(T)); - - _length += count; - return kErrorOk; - } - - //! Prepend `item` to the vector (unsafe case). - //! - //! Can only be used together with `willGrow()`. If `willGrow(N)` returns - //! `kErrorOk` then N elements can be added to the vector without checking - //! if there is a place for them. Used mostly internally. - ASMJIT_INLINE void prependUnsafe(const T& item) noexcept { - ASMJIT_ASSERT(_length < _capacity); - T* data = static_cast(_data); - - if (_length) - ::memmove(data + 1, data, _length * sizeof(T)); - - ::memcpy(data, &item, sizeof(T)); - _length++; - } - - //! Append `item` to the vector (unsafe case). - //! - //! Can only be used together with `willGrow()`. If `willGrow(N)` returns - //! `kErrorOk` then N elements can be added to the vector without checking - //! if there is a place for them. Used mostly internally. - ASMJIT_INLINE void appendUnsafe(const T& item) noexcept { - ASMJIT_ASSERT(_length < _capacity); - - ::memcpy(static_cast(_data) + _length, &item, sizeof(T)); - _length++; - } - - //! Concatenate all items of `other` at the end of the vector. - ASMJIT_INLINE void concatUnsafe(const ZoneVector& other) noexcept { - size_t count = other._length; - ASMJIT_ASSERT(_capacity - _length >= count); - - ::memcpy(static_cast(_data) + _length, other._data, count * sizeof(T)); - _length += count; - } - - //! Get index of `val` or `kInvalidIndex` if not found. - ASMJIT_INLINE size_t indexOf(const T& val) const noexcept { - const T* data = static_cast(_data); - size_t length = _length; - - for (size_t i = 0; i < length; i++) - if (data[i] == val) - return i; - - return Globals::kInvalidIndex; - } - - //! Get whether the vector contains `val`. - ASMJIT_INLINE bool contains(const T& val) const noexcept { - return indexOf(val) != Globals::kInvalidIndex; - } - - //! Remove item at index `i`. - ASMJIT_INLINE void removeAt(size_t i) noexcept { - ASMJIT_ASSERT(i < _length); - - T* data = static_cast(_data) + i; - _length--; - ::memmove(data, data + 1, _length - i); - } - - //! Swap this pod-vector with `other`. - ASMJIT_INLINE void swap(ZoneVector& other) noexcept { - Utils::swap(_length, other._length); - Utils::swap(_capacity, other._capacity); - Utils::swap(_data, other._data); - } - - //! Get item at index `i` (const). - ASMJIT_INLINE const T& getAt(size_t i) const noexcept { - ASMJIT_ASSERT(i < _length); - return getData()[i]; - } - - //! Get item at index `i`. - ASMJIT_INLINE T& operator[](size_t i) noexcept { - ASMJIT_ASSERT(i < _length); - return getData()[i]; - } - - //! Get item at index `i`. - ASMJIT_INLINE const T& operator[](size_t i) const noexcept { - ASMJIT_ASSERT(i < _length); - return getData()[i]; - } - - // -------------------------------------------------------------------------- - // [Memory Management] - // -------------------------------------------------------------------------- - - //! Release the memory held by `ZoneVector` back to the `heap`. - ASMJIT_INLINE void release(ZoneHeap* heap) noexcept { _release(heap, sizeof(T)); } - - //! Called to grow the buffer to fit at least `n` elements more. - ASMJIT_INLINE Error grow(ZoneHeap* heap, size_t n) noexcept { return ZoneVectorBase::_grow(heap, sizeof(T), n); } - - //! Resize the vector to hold `n` elements. - //! - //! If `n` is greater than the current length then the additional elements' - //! content will be initialized to zero. If `n` is less than the current - //! length then the vector will be truncated to exactly `n` elements. - ASMJIT_INLINE Error resize(ZoneHeap* heap, size_t n) noexcept { return ZoneVectorBase::_resize(heap, sizeof(T), n); } - - //! Realloc internal array to fit at least `n` items. - ASMJIT_INLINE Error reserve(ZoneHeap* heap, size_t n) noexcept { return ZoneVectorBase::_reserve(heap, sizeof(T), n); } - - ASMJIT_INLINE Error willGrow(ZoneHeap* heap, size_t n = 1) noexcept { - return _capacity - _length < n ? grow(heap, n) : static_cast(kErrorOk); - } -}; - -// ============================================================================ -// [asmjit::ZoneBitVector] -// ============================================================================ - -class ZoneBitVector { -public: - ASMJIT_NONCOPYABLE(ZoneBitVector) - - //! Storage used to store a pack of bits (should by compatible with a machine word). - typedef uintptr_t BitWord; - enum { kBitsPerWord = static_cast(sizeof(BitWord)) * 8 }; - - static ASMJIT_INLINE size_t _wordsPerBits(size_t nBits) noexcept { - return ((nBits + kBitsPerWord) / kBitsPerWord) - 1; - } - - // Return all bits zero if 0 and all bits set if 1. - static ASMJIT_INLINE BitWord _patternFromBit(bool bit) noexcept { - BitWord bitAsWord = static_cast(bit); - ASMJIT_ASSERT(bitAsWord == 0 || bitAsWord == 1); - return static_cast(0) - bitAsWord; - } - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - explicit ASMJIT_INLINE ZoneBitVector() noexcept : - _data(nullptr), - _length(0), - _capacity(0) {} - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get if the bit-vector is empty (has no bits). - ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; } - //! Get a length of this bit-vector (in bits). - ASMJIT_INLINE size_t getLength() const noexcept { return _length; } - //! Get a capacity of this bit-vector (in bits). - ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; } - - //! Get data. - ASMJIT_INLINE BitWord* getData() noexcept { return _data; } - //! \overload - ASMJIT_INLINE const BitWord* getData() const noexcept { return _data; } - - // -------------------------------------------------------------------------- - // [Ops] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void clear() noexcept { - _length = 0; - } - - ASMJIT_INLINE void reset() noexcept { - _data = nullptr; - _length = 0; - _capacity = 0; - } - - ASMJIT_INLINE void truncate(size_t newLength) noexcept { - _length = std::min(_length, newLength); - _clearUnusedBits(); - } - - ASMJIT_INLINE bool getAt(size_t index) const noexcept { - ASMJIT_ASSERT(index < _length); - - size_t idx = index / kBitsPerWord; - size_t bit = index % kBitsPerWord; - return static_cast((_data[idx] >> bit) & 1); - } - - ASMJIT_INLINE void setAt(size_t index, bool value) noexcept { - ASMJIT_ASSERT(index < _length); - - size_t idx = index / kBitsPerWord; - size_t bit = index % kBitsPerWord; - if (value) - _data[idx] |= static_cast(1) << bit; - else - _data[idx] &= ~(static_cast(1) << bit); - } - - ASMJIT_INLINE void toggleAt(size_t index) noexcept { - ASMJIT_ASSERT(index < _length); - - size_t idx = index / kBitsPerWord; - size_t bit = index % kBitsPerWord; - _data[idx] ^= static_cast(1) << bit; - } - - ASMJIT_INLINE Error append(ZoneHeap* heap, bool value) noexcept { - size_t index = _length; - if (ASMJIT_UNLIKELY(index >= _capacity)) - return _append(heap, value); - - size_t idx = index / kBitsPerWord; - size_t bit = index % kBitsPerWord; - - if (bit == 0) - _data[idx] = static_cast(value) << bit; - else - _data[idx] |= static_cast(value) << bit; - - _length++; - return kErrorOk; - } - - ASMJIT_API Error fill(size_t fromIndex, size_t toIndex, bool value) noexcept; - - ASMJIT_INLINE void and_(const ZoneBitVector& other) noexcept { - BitWord* dst = _data; - const BitWord* src = other._data; - - size_t numWords = (std::min(_length, other._length) + kBitsPerWord - 1) / kBitsPerWord; - for (size_t i = 0; i < numWords; i++) - dst[i] = dst[i] & src[i]; - _clearUnusedBits(); - } - - ASMJIT_INLINE void andNot(const ZoneBitVector& other) noexcept { - BitWord* dst = _data; - const BitWord* src = other._data; - - size_t numWords = (std::min(_length, other._length) + kBitsPerWord - 1) / kBitsPerWord; - for (size_t i = 0; i < numWords; i++) - dst[i] = dst[i] & ~src[i]; - _clearUnusedBits(); - } - - ASMJIT_INLINE void or_(const ZoneBitVector& other) noexcept { - BitWord* dst = _data; - const BitWord* src = other._data; - - size_t numWords = (std::min(_length, other._length) + kBitsPerWord - 1) / kBitsPerWord; - for (size_t i = 0; i < numWords; i++) - dst[i] = dst[i] | src[i]; - _clearUnusedBits(); - } - - ASMJIT_INLINE void _clearUnusedBits() noexcept { - size_t idx = _length / kBitsPerWord; - size_t bit = _length % kBitsPerWord; - - if (!bit) return; - _data[idx] &= (static_cast(1) << bit) - 1U; - } - - // -------------------------------------------------------------------------- - // [Memory Management] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void release(ZoneHeap* heap) noexcept { - if (_data != nullptr) { - heap->release(_data, _capacity / 8); - reset(); - } - } - - ASMJIT_INLINE Error resize(ZoneHeap* heap, size_t newLength, bool newBitsValue = false) noexcept { - return _resize(heap, newLength, newLength, newBitsValue); - } - - ASMJIT_API Error _resize(ZoneHeap* heap, size_t newLength, size_t idealCapacity, bool newBitsValue) noexcept; - ASMJIT_API Error _append(ZoneHeap* heap, bool value) noexcept; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - BitWord* _data; //!< Bits. - size_t _length; //!< Length of the bit-vector (in bits). - size_t _capacity; //!< Capacity of the bit-vector (in bits). -}; - -// ============================================================================ -// [asmjit::ZoneStackBase] -// ============================================================================ - -class ZoneStackBase { -public: - enum Side { - kSideLeft = 0, - kSideRight = 1 - }; - - enum { - kBlockSize = ZoneHeap::kHiMaxSize - }; - - struct Block { - ASMJIT_INLINE Block* getPrev() const noexcept { return _link[kSideLeft]; } - ASMJIT_INLINE void setPrev(Block* block) noexcept { _link[kSideLeft] = block; } - - ASMJIT_INLINE Block* getNext() const noexcept { return _link[kSideRight]; } - ASMJIT_INLINE void setNext(Block* block) noexcept { _link[kSideRight] = block; } - - template - ASMJIT_INLINE T* getStart() const noexcept { return static_cast(_start); } - template - ASMJIT_INLINE void setStart(T* start) noexcept { _start = static_cast(start); } - - template - ASMJIT_INLINE T* getEnd() const noexcept { return static_cast(_end); } - template - ASMJIT_INLINE void setEnd(T* end) noexcept { _end = static_cast(end); } - - ASMJIT_INLINE bool isEmpty() const noexcept { return _start == _end; } - - template - ASMJIT_INLINE T* getData() const noexcept { - return static_cast(static_cast((uint8_t*)this + sizeof(Block))); - } - - template - ASMJIT_INLINE bool canPrepend() const noexcept { - return _start > getData(); - } - - template - ASMJIT_INLINE bool canAppend() const noexcept { - size_t kNumBlockItems = (kBlockSize - sizeof(Block)) / sizeof(T); - size_t kBlockEnd = sizeof(Block) + kNumBlockItems * sizeof(T); - return (uintptr_t)_end - (uintptr_t)this < kBlockEnd; - } - - Block* _link[2]; //!< Next and previous blocks. - void* _start; //!< Pointer to the start of the array. - void* _end; //!< Pointer to the end of the array. - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE ZoneStackBase() noexcept { - _heap = nullptr; - _block[0] = nullptr; - _block[1] = nullptr; - } - ASMJIT_INLINE ~ZoneStackBase() noexcept { reset(); } - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool isInitialized() const noexcept { return _heap != nullptr; } - ASMJIT_API Error _init(ZoneHeap* heap, size_t middleIndex) noexcept; - ASMJIT_INLINE Error reset() noexcept { return _init(nullptr, 0); } - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get a `ZoneHeap` attached to this container. - ASMJIT_INLINE ZoneHeap* getHeap() const noexcept { return _heap; } - - ASMJIT_INLINE bool isEmpty() const noexcept { - ASMJIT_ASSERT(isInitialized()); - return _block[0] == _block[1] && _block[0]->isEmpty(); - } - - // -------------------------------------------------------------------------- - // [Ops] - // -------------------------------------------------------------------------- - - ASMJIT_API Error _prepareBlock(uint32_t side, size_t initialIndex) noexcept; - ASMJIT_API void _cleanupBlock(uint32_t side, size_t middleIndex) noexcept; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - ZoneHeap* _heap; //!< ZoneHeap used to allocate data. - Block* _block[2]; //!< First and last blocks. -}; - -// ============================================================================ -// [asmjit::ZoneStack] -// ============================================================================ - -template -class ZoneStack : public ZoneStackBase { -public: - enum { - kNumBlockItems = static_cast((kBlockSize - sizeof(Block)) / sizeof(T)), - kStartBlockIndex = static_cast(sizeof(Block)), - kMidBlockIndex = static_cast(kStartBlockIndex + (kNumBlockItems / 2) * sizeof(T)), - kEndBlockIndex = static_cast(kStartBlockIndex + kNumBlockItems * sizeof(T)) - }; - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE ZoneStack() noexcept {} - ASMJIT_INLINE ~ZoneStack() noexcept {} - - // -------------------------------------------------------------------------- - // [Init / Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE Error init(ZoneHeap* heap) noexcept { return _init(heap, kMidBlockIndex); } - - // -------------------------------------------------------------------------- - // [Ops] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE Error prepend(T item) noexcept { - ASMJIT_ASSERT(isInitialized()); - Block* block = _block[kSideLeft]; - - if (!block->canPrepend()) { - ASMJIT_PROPAGATE(_prepareBlock(kSideLeft, kEndBlockIndex)); - block = _block[kSideLeft]; - } - - T* ptr = block->getStart() - 1; - ASMJIT_ASSERT(ptr >= block->getData() && ptr < block->getData() + kNumBlockItems); - *ptr = item; - block->setStart(ptr); - return kErrorOk; - } - - ASMJIT_INLINE Error append(T item) noexcept { - ASMJIT_ASSERT(isInitialized()); - Block* block = _block[kSideRight]; - - if (!block->canAppend()) { - ASMJIT_PROPAGATE(_prepareBlock(kSideRight, kStartBlockIndex)); - block = _block[kSideRight]; - } - - T* ptr = block->getEnd(); - ASMJIT_ASSERT(ptr >= block->getData() && ptr < block->getData() + kNumBlockItems); - - *ptr++ = item; - block->setEnd(ptr); - return kErrorOk; - } - - ASMJIT_INLINE T popFirst() noexcept { - ASMJIT_ASSERT(isInitialized()); - ASMJIT_ASSERT(!isEmpty()); - - Block* block = _block[kSideLeft]; - ASMJIT_ASSERT(!block->isEmpty()); - - T* ptr = block->getStart(); - T item = *ptr++; - - block->setStart(ptr); - if (block->isEmpty()) - _cleanupBlock(kSideLeft, kMidBlockIndex); - - return item; - } - - ASMJIT_INLINE T pop() noexcept { - ASMJIT_ASSERT(isInitialized()); - ASMJIT_ASSERT(!isEmpty()); - - Block* block = _block[kSideRight]; - ASMJIT_ASSERT(!block->isEmpty()); - - T* ptr = block->getEnd(); - T item = *--ptr; - - block->setEnd(ptr); - if (block->isEmpty()) - _cleanupBlock(kSideRight, kMidBlockIndex); - - return item; - } -}; - -// ============================================================================ -// [asmjit::ZoneHashNode] -// ============================================================================ - -//! Node used by \ref ZoneHash<> template. -//! -//! You must provide function `bool eq(const Key& key)` in order to make -//! `ZoneHash::get()` working. -class ZoneHashNode { -public: - ASMJIT_INLINE ZoneHashNode(uint32_t hVal = 0) noexcept - : _hashNext(nullptr), - _hVal(hVal) {} - - //! Next node in the chain, null if it terminates the chain. - ZoneHashNode* _hashNext; - //! Key hash. - uint32_t _hVal; - //! Should be used by Node that inherits ZoneHashNode, it aligns ZoneHashNode. - uint32_t _customData; -}; - -// ============================================================================ -// [asmjit::ZoneHashBase] -// ============================================================================ - -class ZoneHashBase { -public: - ASMJIT_NONCOPYABLE(ZoneHashBase) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE ZoneHashBase(ZoneHeap* heap) noexcept { - _heap = heap; - _size = 0; - _bucketsCount = 1; - _bucketsGrow = 1; - _data = _embedded; - _embedded[0] = nullptr; - } - ASMJIT_INLINE ~ZoneHashBase() noexcept { reset(nullptr); } - - // -------------------------------------------------------------------------- - // [Reset] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE bool isInitialized() const noexcept { return _heap != nullptr; } - ASMJIT_API void reset(ZoneHeap* heap) noexcept; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - //! Get a `ZoneHeap` attached to this container. - ASMJIT_INLINE ZoneHeap* getHeap() const noexcept { return _heap; } - - ASMJIT_INLINE size_t getSize() const noexcept { return _size; } - - // -------------------------------------------------------------------------- - // [Ops] - // -------------------------------------------------------------------------- - - ASMJIT_API void _rehash(uint32_t newCount) noexcept; - ASMJIT_API ZoneHashNode* _put(ZoneHashNode* node) noexcept; - ASMJIT_API ZoneHashNode* _del(ZoneHashNode* node) noexcept; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - ZoneHeap* _heap; //!< ZoneHeap used to allocate data. - size_t _size; //!< Count of records inserted into the hash table. - uint32_t _bucketsCount; //!< Count of hash buckets. - uint32_t _bucketsGrow; //!< When buckets array should grow. - - ZoneHashNode** _data; //!< Buckets data. - ZoneHashNode* _embedded[1]; //!< Embedded data, used by empty hash tables. -}; - -// ============================================================================ -// [asmjit::ZoneHash] -// ============================================================================ - -//! Low-level hash table specialized for storing string keys and POD values. -//! -//! This hash table allows duplicates to be inserted (the API is so low -//! level that it's up to you if you allow it or not, as you should first -//! `get()` the node and then modify it or insert a new node by using `put()`, -//! depending on the intention). -template -class ZoneHash : public ZoneHashBase { -public: - explicit ASMJIT_INLINE ZoneHash(ZoneHeap* heap = nullptr) noexcept - : ZoneHashBase(heap) {} - ASMJIT_INLINE ~ZoneHash() noexcept {} - - template - ASMJIT_INLINE Node* get(const Key& key) const noexcept { - uint32_t hMod = key.hVal % _bucketsCount; - Node* node = static_cast(_data[hMod]); - - while (node && !key.matches(node)) - node = static_cast(node->_hashNext); - return node; - } - - ASMJIT_INLINE Node* put(Node* node) noexcept { return static_cast(_put(node)); } - ASMJIT_INLINE Node* del(Node* node) noexcept { return static_cast(_del(node)); } -}; - -//! \} - -} // asmjit namespace - -// [Api-End] -#include "../asmjit_apiend.h" - -// [Guard] -#endif // _ASMJIT_BASE_ZONE_H diff --git a/libs/asmjit/x86.h b/libs/asmjit/x86.h deleted file mode 100644 index e8505346..00000000 --- a/libs/asmjit/x86.h +++ /dev/null @@ -1,23 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Guard] -#ifndef _ASMJIT_X86_H -#define _ASMJIT_X86_H - -// [Dependencies] -#include "./base.h" - -#include "./x86/x86assembler.h" -#include "./x86/x86builder.h" -#include "./x86/x86compiler.h" -#include "./x86/x86emitter.h" -#include "./x86/x86inst.h" -#include "./x86/x86misc.h" -#include "./x86/x86operand.h" - -// [Guard] -#endif // _ASMJIT_X86_H diff --git a/libs/asmjit/x86/x86assembler.cpp b/libs/asmjit/x86/x86assembler.cpp deleted file mode 100644 index b305ba55..00000000 --- a/libs/asmjit/x86/x86assembler.cpp +++ /dev/null @@ -1,4617 +0,0 @@ -// [AsmJit] -// Complete x86/x64 JIT and Remote Assembler for C++. -// -// [License] -// Zlib - See LICENSE.md file in the package. - -// [Export] -#define ASMJIT_EXPORTS - -// [Guard] -#include "../asmjit_build.h" -#if defined(ASMJIT_BUILD_X86) - -// [Dependencies] -#include "../base/cpuinfo.h" -#include "../base/logging.h" -#include "../base/misc_p.h" -#include "../base/utils.h" -#include "../x86/x86assembler.h" -#include "../x86/x86logging_p.h" - -// [Api-Begin] -#include "../asmjit_apibegin.h" - -namespace asmjit { - -// ============================================================================ -// [FastUInt8] -// ============================================================================ - -#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 -typedef unsigned char FastUInt8; -#else -typedef unsigned int FastUInt8; -#endif - -// ============================================================================ -// [Constants] -// ============================================================================ - -//! \internal -//! -//! X86/X64 bytes used to encode important prefixes. -enum X86Byte { - //! 1-byte REX prefix mask. - kX86ByteRex = 0x40, - - //! 1-byte REX.W component. - kX86ByteRexW = 0x08, - - //! 2-byte VEX prefix: - //! - `[0]` - `0xC5`. - //! - `[1]` - `RvvvvLpp`. - kX86ByteVex2 = 0xC5, - - //! 3-byte VEX prefix. - //! - `[0]` - `0xC4`. - //! - `[1]` - `RXBmmmmm`. - //! - `[2]` - `WvvvvLpp`. - kX86ByteVex3 = 0xC4, - - //! 3-byte XOP prefix. - //! - `[0]` - `0x8F`. - //! - `[1]` - `RXBmmmmm`. - //! - `[2]` - `WvvvvLpp`. - kX86ByteXop3 = 0x8F, - - //! 4-byte EVEX prefix. - //! - `[0]` - `0x62`. - //! - `[1]` - Payload0 or `P[ 7: 0]` - `[R X B R' 0 0 m m]`. - //! - `[2]` - Payload1 or `P[15: 8]` - `[W v v v v 1 p p]`. - //! - `[3]` - Payload2 or `P[23:16]` - `[z L' L b V' a a a]`. - //! - //! Groups: - //! - `P[ 1: 0]` - OPCODE: EVEX.mmmmm, only lowest 2 bits [1:0] used. - //! - `P[ 3: 2]` - ______: Must be 0. - //! - `P[ 4]` - REG-ID: EVEX.R' - 5th bit of 'RRRRR'. - //! - `P[ 5]` - REG-ID: EVEX.B - 4th bit of 'BBBBB'. - //! - `P[ 6]` - REG-ID: EVEX.X - 5th bit of 'BBBBB' or 4th bit of 'XXXX' (with SIB). - //! - `P[ 7]` - REG-ID: EVEX.R - 4th bit of 'RRRRR'. - //! - `P[ 9: 8]` - OPCODE: EVEX.pp. - //! - `P[ 10]` - ______: Must be 1. - //! - `P[14:11]` - REG-ID: 4 bits of 'VVVV'. - //! - `P[ 15]` - OPCODE: EVEX.W. - //! - `P[18:16]` - REG-ID: K register k0...k7 (Merging/Zeroing Vector Ops). - //! - `P[ 19]` - REG-ID: 5th bit of 'VVVVV'. - //! - `P[ 20]` - OPCODE: Broadcast/Rounding Control/SAE bit. - //! - `P[22.21]` - OPCODE: Vector Length (L' and L) / Rounding Control. - //! - `P[ 23]` - OPCODE: Zeroing/Merging. - kX86ByteEvex = 0x62 -}; - -// AsmJit specific (used to encode VVVVV field in XOP/VEX/EVEX). -enum VexVVVVV { - kVexVVVVVShift = 7, - kVexVVVVVMask = 0x1F << kVexVVVVVShift -}; - -//! \internal -//! -//! Instruction 2-byte/3-byte opcode prefix definition. -struct X86OpCodeMM { - uint8_t len; - uint8_t data[3]; -}; - -//! \internal -//! -//! Mandatory prefixes used to encode legacy [66, F3, F2] or [9B] byte. -static const uint8_t x86OpCodePP[8] = { 0x00, 0x66, 0xF3, 0xF2, 0x00, 0x00, 0x00, 0x9B }; - -//! \internal -//! -//! Instruction 2-byte/3-byte opcode prefix data. -static const X86OpCodeMM x86OpCodeMM[] = { - { 0, { 0x00, 0x00, 0 } }, // #00 (0b0000). - { 1, { 0x0F, 0x00, 0 } }, // #01 (0b0001). - { 2, { 0x0F, 0x38, 0 } }, // #02 (0b0010). - { 2, { 0x0F, 0x3A, 0 } }, // #03 (0b0011). - { 2, { 0x0F, 0x01, 0 } }, // #04 (0b0100). - { 0, { 0x00, 0x00, 0 } }, // #05 (0b0101). - { 0, { 0x00, 0x00, 0 } }, // #06 (0b0110). - { 0, { 0x00, 0x00, 0 } }, // #07 (0b0111). - { 0, { 0x00, 0x00, 0 } }, // #08 (0b1000). - { 0, { 0x00, 0x00, 0 } }, // #09 (0b1001). - { 0, { 0x00, 0x00, 0 } }, // #0A (0b1010). - { 0, { 0x00, 0x00, 0 } }, // #0B (0b1011). - { 0, { 0x00, 0x00, 0 } }, // #0C (0b1100). - { 0, { 0x00, 0x00, 0 } }, // #0D (0b1101). - { 0, { 0x00, 0x00, 0 } }, // #0E (0b1110). - { 0, { 0x00, 0x00, 0 } } // #0F (0b1111). -}; - -static const uint8_t x86SegmentPrefix[8] = { 0x00, 0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65, 0x00 }; -static const uint8_t x86OpCodePushSeg[8] = { 0x00, 0x06, 0x0E, 0x16, 0x1E, 0xA0, 0xA8, 0x00 }; -static const uint8_t x86OpCodePopSeg[8] = { 0x00, 0x07, 0x00, 0x17, 0x1F, 0xA1, 0xA9, 0x00 }; - -// ============================================================================ -// [asmjit::X86MemInfo | X86VEXPrefix | X86LLByRegType | X86CDisp8Table] -// ============================================================================ - -//! \internal -//! -//! Memory operand's info bits. -//! -//! A lookup table that contains various information based on the BASE and INDEX -//! information of a memory operand. This is much better and safer than playing -//! with IFs in the code and can check for errors must faster and better. -enum X86MemInfo_Enum { - kX86MemInfo_0 = 0x00, - - kX86MemInfo_BaseGp = 0x01, //!< Has BASE reg, REX.B can be 1, compatible with REX.B byte. - kX86MemInfo_Index = 0x02, //!< Has INDEX reg, REX.X can be 1, compatible with REX.X byte. - - kX86MemInfo_BaseLabel = 0x10, //!< Base is Label. - kX86MemInfo_BaseRip = 0x20, //!< Base is RIP. - - kX86MemInfo_67H_X86 = 0x40, //!< Address-size override in 32-bit mode. - kX86MemInfo_67H_X64 = 0x80, //!< Address-size override in 64-bit mode. - kX86MemInfo_67H_Mask = 0xC0 //!< Contains all address-size override bits. -}; - -template -struct X86MemInfo_T { - enum { - B = (X ) & 0x1F, - I = (X >> 5) & 0x1F, - - kBase = ((B >= X86Reg::kRegGpw && B <= X86Reg::kRegGpq ) ? kX86MemInfo_BaseGp : - (B == X86Reg::kRegRip ) ? kX86MemInfo_BaseRip : - (B == Label::kLabelTag ) ? kX86MemInfo_BaseLabel : 0), - - kIndex = ((I >= X86Reg::kRegGpw && I <= X86Reg::kRegGpq ) ? kX86MemInfo_Index : - (I >= X86Reg::kRegXmm && I <= X86Reg::kRegZmm ) ? kX86MemInfo_Index : 0), - - k67H = ((B == X86Reg::kRegGpw && I == X86Reg::kRegNone) ? kX86MemInfo_67H_X86 : - (B == X86Reg::kRegGpd && I == X86Reg::kRegNone) ? kX86MemInfo_67H_X64 : - (B == X86Reg::kRegNone && I == X86Reg::kRegGpw ) ? kX86MemInfo_67H_X86 : - (B == X86Reg::kRegNone && I == X86Reg::kRegGpd ) ? kX86MemInfo_67H_X64 : - (B == X86Reg::kRegGpw && I == X86Reg::kRegGpw ) ? kX86MemInfo_67H_X86 : - (B == X86Reg::kRegGpd && I == X86Reg::kRegGpd ) ? kX86MemInfo_67H_X64 : - (B == X86Reg::kRegGpw && I == X86Reg::kRegXmm ) ? kX86MemInfo_67H_X86 : - (B == X86Reg::kRegGpd && I == X86Reg::kRegXmm ) ? kX86MemInfo_67H_X64 : - (B == X86Reg::kRegGpw && I == X86Reg::kRegYmm ) ? kX86MemInfo_67H_X86 : - (B == X86Reg::kRegGpd && I == X86Reg::kRegYmm ) ? kX86MemInfo_67H_X64 : - (B == X86Reg::kRegGpw && I == X86Reg::kRegZmm ) ? kX86MemInfo_67H_X86 : - (B == X86Reg::kRegGpd && I == X86Reg::kRegZmm ) ? kX86MemInfo_67H_X64 : - (B == Label::kLabelTag && I == X86Reg::kRegGpw ) ? kX86MemInfo_67H_X86 : - (B == Label::kLabelTag && I == X86Reg::kRegGpd ) ? kX86MemInfo_67H_X64 : 0), - - kValue = kBase | kIndex | k67H | 0x04 | 0x08 - }; -}; - -// The result stored in the LUT is a combination of -// - 67H - Address override prefix - depends on BASE+INDEX register types and -// the target architecture. -// - REX - A possible combination of REX.[B|X|R|W] bits in REX prefix where -// REX.B and REX.X are possibly masked out, but REX.R and REX.W are -// kept as is. -static const uint8_t x86MemInfo[] = { ASMJIT_TABLE_T_1024(X86MemInfo_T, kValue, 0) }; - -// VEX3 or XOP xor bits applied to the opcode before emitted. The index to this -// table is 'mmmmm' value, which contains all we need. This is only used by a -// 3 BYTE VEX and XOP prefixes, 2 BYTE VEX prefix is handled differently. The -// idea is to minimize the difference between VEX3 vs XOP when encoding VEX -// or XOP instruction. This should minimize the code required to emit such -// instructions and should also make it faster as we don't need any branch to -// decide between VEX3 vs XOP. -// ____ ___ -// [_OPCODE_|WvvvvLpp|RXBmmmmm|VEX3_XOP] -template -struct X86VEXPrefix_T { - enum { kValue = ((X & 0x08) ? kX86ByteXop3 : kX86ByteVex3) | (0xF << 19) | (0x7 << 13) }; -}; -static const uint32_t x86VEXPrefix[] = { ASMJIT_TABLE_T_16(X86VEXPrefix_T, kValue, 0) }; - -// Table that contains LL opcode field addressed by a register size / 16. It's -// used to propagate L.256 or L.512 when YMM or ZMM registers are used, -// respectively. -template -struct X86LLBySizeDiv16_T { - enum { - kValue = (X & (64 >> 4)) ? X86Inst::kOpCode_LL_512 : - (X & (32 >> 4)) ? X86Inst::kOpCode_LL_256 : 0 - }; -}; -static const uint32_t x86LLBySizeDiv16[] = { ASMJIT_TABLE_T_16(X86LLBySizeDiv16_T, kValue, 0) }; - -// Table that contains LL opcode field addressed by a register size / 16. It's -// used to propagate L.256 or L.512 when YMM or ZMM registers are used, -// respectively. -template -struct X86LLByRegType_T { - enum { - kValue = X == X86Reg::kRegZmm ? X86Inst::kOpCode_LL_512 : - X == X86Reg::kRegYmm ? X86Inst::kOpCode_LL_256 : 0 - }; -}; -static const uint32_t x86LLByRegType[] = { ASMJIT_TABLE_T_16(X86LLByRegType_T, kValue, 0) }; - -// Table that contains a scale (shift left) based on 'TTWLL' field and -// the instruction's tuple-type (TT) field. The scale is then applied to -// the BASE-N stored in each opcode to calculate the final compressed -// displacement used by all EVEX encoded instructions. -template -struct X86CDisp8SHL_T { - enum { - TT = (((X) >> 3) << X86Inst::kOpCode_CDTT_Shift), - LL = (((X) >> 0) & 0x3), - W = (((X) >> 2) & 0x1), - - kValue = (TT == X86Inst::kOpCode_CDTT_None ? ((LL==0) ? 0 : (LL==1) ? 0 : 0 ) : - TT == X86Inst::kOpCode_CDTT_ByLL ? ((LL==0) ? 0 : (LL==1) ? 1 : 2 ) : - TT == X86Inst::kOpCode_CDTT_T1W ? ((LL==0) ? W : (LL==1) ? 1+W : 2+W) : - TT == X86Inst::kOpCode_CDTT_DUP ? ((LL==0) ? 0 : (LL==1) ? 2 : 3 ) : 0 ) << X86Inst::kOpCode_CDSHL_Shift - }; -}; -static const uint32_t x86CDisp8SHL[] = { ASMJIT_TABLE_T_32(X86CDisp8SHL_T, kValue, 0) }; - -// Table that contains MOD byte of a 16-bit [BASE + disp] address. -// 0xFF == Invalid. -static const uint8_t x86Mod16BaseTable[8] = { - 0xFF, // AX -> N/A. - 0xFF, // CX -> N/A. - 0xFF, // DX -> N/A. - 0x07, // BX -> 111. - 0xFF, // SP -> N/A. - 0x06, // BP -> 110. - 0x04, // SI -> 100. - 0x05 // DI -> 101. -}; - -// Table that contains MOD byte of a 16-bit [BASE + INDEX + disp] combination. -// 0xFF == Invalid. -template -struct X86Mod16BaseIndexTable_T { - enum { - B = X >> 3, - I = X & 0x7, - - kValue = ((B == X86Gp::kIdBx && I == X86Gp::kIdSi) || (B == X86Gp::kIdSi && I == X86Gp::kIdBx)) ? 0x00 : - ((B == X86Gp::kIdBx && I == X86Gp::kIdDi) || (B == X86Gp::kIdDi && I == X86Gp::kIdBx)) ? 0x01 : - ((B == X86Gp::kIdBp && I == X86Gp::kIdSi) || (B == X86Gp::kIdSi && I == X86Gp::kIdBp)) ? 0x02 : - ((B == X86Gp::kIdBp && I == X86Gp::kIdDi) || (B == X86Gp::kIdDi && I == X86Gp::kIdBp)) ? 0x03 : 0xFF - }; -}; -static const uint8_t x86Mod16BaseIndexTable[] = { ASMJIT_TABLE_T_64(X86Mod16BaseIndexTable_T, kValue, 0) }; - -// ============================================================================ -// [asmjit::X86Assembler - Helpers] -// ============================================================================ - -static ASMJIT_INLINE bool x86IsJmpOrCall(uint32_t instId) noexcept { - return instId == X86Inst::kIdJmp || - instId == X86Inst::kIdCall; -} - -static ASMJIT_INLINE bool x86IsImplicitMem(const Operand_& op, uint32_t base) noexcept { - return op.isMem() && op.as().getBaseId() == base; -} - -static ASMJIT_INLINE int64_t x86SignExtend32To64(int64_t imm) noexcept { - return static_cast(static_cast(imm & 0xFFFFFFFF)); -} - -//! Get `O` field of `opCode`. -static ASMJIT_INLINE uint32_t x86ExtractO(uint32_t opCode) noexcept { - return (opCode >> X86Inst::kOpCode_O_Shift) & 0x07; -} - -static ASMJIT_INLINE uint32_t x86ExtractREX(uint32_t opCode, uint32_t options) noexcept { - // kOpCode_REX was designed in a way that when shifted there will be no bytes - // set except REX.[B|X|R|W]. The returned value forms a real REX prefix byte. - // This case is tested by `X86Inst.cpp`. - return (opCode | options) >> X86Inst::kOpCode_REX_Shift; -} - -//! Combine `regId` and `vvvvvId` into a single value (used by AVX and AVX-512). -static ASMJIT_INLINE uint32_t x86PackRegAndVvvvv(uint32_t regId, uint32_t vvvvvId) noexcept { - return regId + (vvvvvId << kVexVVVVVShift); -} - -static ASMJIT_INLINE uint32_t x86OpCodeLByVMem(const Operand_& op) noexcept { - return x86LLByRegType[op.as().getIndexType()]; -} - -static ASMJIT_INLINE uint32_t x86OpCodeLBySize(uint32_t size) noexcept { - return x86LLBySizeDiv16[size / 16]; -} - -static ASMJIT_INLINE uint32_t x86ExtractLLMM(uint32_t opCode, uint32_t options) noexcept { - uint32_t x = opCode & (X86Inst::kOpCode_LL_Mask | X86Inst::kOpCode_MM_Mask); - uint32_t y = options & X86Inst::kOptionVex3; - return (x | y) >> X86Inst::kOpCode_MM_Shift; -} - -//! Encode MOD byte. -static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept { - ASMJIT_ASSERT(m <= 3); - ASMJIT_ASSERT(o <= 7); - ASMJIT_ASSERT(rm <= 7); - return (m << 6) + (o << 3) + rm; -} - -//! Encode SIB byte. -static ASMJIT_INLINE uint32_t x86EncodeSib(uint32_t s, uint32_t i, uint32_t b) noexcept { - ASMJIT_ASSERT(s <= 3); - ASMJIT_ASSERT(i <= 7); - ASMJIT_ASSERT(b <= 7); - return (s << 6) + (i << 3) + b; -} - -// ============================================================================ -// [asmjit::X86Assembler - Construction / Destruction] -// ============================================================================ - -X86Assembler::X86Assembler(CodeHolder* code) noexcept : Assembler() { - if (code) - code->attach(this); -} -X86Assembler::~X86Assembler() noexcept {} - -// ============================================================================ -// [asmjit::X86Assembler - Events] -// ============================================================================ - -Error X86Assembler::onAttach(CodeHolder* code) noexcept { - uint32_t archType = code->getArchType(); - if (!ArchInfo::isX86Family(archType)) - return DebugUtils::errored(kErrorInvalidArch); - - ASMJIT_PROPAGATE(Base::onAttach(code)); - - if (archType == ArchInfo::kTypeX86) { - // 32 bit architecture - X86. - _setAddressOverrideMask(kX86MemInfo_67H_X86); - _globalOptions |= X86Inst::_kOptionInvalidRex; - _nativeGpArray = x86OpData.gpd; - } - else { - // 64 bit architecture - X64 or X32. - _setAddressOverrideMask(kX86MemInfo_67H_X64); - _nativeGpArray = x86OpData.gpq; - } - - _nativeGpReg = _nativeGpArray[0]; - return kErrorOk; -} - -Error X86Assembler::onDetach(CodeHolder* code) noexcept { - return Base::onDetach(code); -} - -// ============================================================================ -// [asmjit::X86Assembler - Helpers] -// ============================================================================ - -#define EMIT_BYTE(VAL) \ - do { \ - cursor[0] = static_cast((VAL) & 0xFFU); \ - cursor += 1; \ - } while (0) - -#define EMIT_16(VAL) \ - do { \ - Utils::writeU16uLE(cursor, \ - static_cast((VAL) & 0xFFFFU)); \ - cursor += 2; \ - } while (0) - -#define EMIT_32(VAL) \ - do { \ - Utils::writeU32uLE(cursor, \ - static_cast((VAL) & 0xFFFFFFFFU)); \ - cursor += 4; \ - } while (0) - -#define ADD_66H_P(EXP) \ - do { \ - opCode |= (static_cast(EXP) << X86Inst::kOpCode_PP_Shift); \ - } while (0) - -#define ADD_66H_P_BY_SIZE(SIZE) \ - do { \ - opCode |= (static_cast((SIZE) & 0x02)) \ - << (X86Inst::kOpCode_PP_Shift - 1); \ - } while (0) - -#define ADD_REX_W(EXP) \ - do { \ - if (EXP) \ - opCode |= X86Inst::kOpCode_W; \ - } while (0) - -#define ADD_REX_W_BY_SIZE(SIZE) \ - do { \ - if ((SIZE) == 8) \ - opCode |= X86Inst::kOpCode_W; \ - } while (0) - -#define ADD_PREFIX_BY_SIZE(SIZE) \ - do { \ - ADD_66H_P_BY_SIZE(SIZE); \ - ADD_REX_W_BY_SIZE(SIZE); \ - } while (0) - -#define ADD_VEX_W(EXP) \ - do { \ - opCode |= static_cast(EXP) << X86Inst::kOpCode_W_Shift; \ - } while (0) - -#define EMIT_PP(OPCODE) \ - do { \ - uint32_t ppIndex = \ - ((OPCODE ) >> X86Inst::kOpCode_PP_Shift) & \ - (X86Inst::kOpCode_PP_FPUMask >> X86Inst::kOpCode_PP_Shift) ; \ - uint8_t ppCode = x86OpCodePP[ppIndex]; \ - \ - cursor[0] = ppCode; \ - cursor += ppIndex != 0; \ - } while (0) - -#define EMIT_MM_OP(OPCODE) \ - do { \ - uint32_t op = OPCODE & (0x00FF | X86Inst::kOpCode_MM_Mask); \ - \ - uint32_t mmIndex = op >> X86Inst::kOpCode_MM_Shift; \ - const X86OpCodeMM& mmCode = x86OpCodeMM[mmIndex]; \ - \ - if (mmIndex) { \ - cursor[0] = mmCode.data[0]; \ - cursor[1] = mmCode.data[1]; \ - cursor += mmCode.len; \ - } \ - \ - EMIT_BYTE(op); \ - } while (0) - -// If the operand is BPL|SPL|SIL|DIL|R8B-15B -// - Force REX prefix -// If the operand is AH|BH|CH|DH -// - patch its index from 0..3 to 4..7 as encoded by X86. -// - Disallow REX prefix. -#define FIXUP_GPB(REG_OP, REG_ID, ...) \ - do { \ - if (!static_cast(REG_OP).isGpbHi()) { \ - options |= (REG_ID >= 4) ? X86Inst::kOptionRex : 0; \ - } \ - else { \ - options |= X86Inst::_kOptionInvalidRex; \ - REG_ID += 4; \ - } \ - } while (0) - -#define ENC_OPS1(OP0) ((Operand::kOp##OP0)) -#define ENC_OPS2(OP0, OP1) ((Operand::kOp##OP0) + ((Operand::kOp##OP1) << 3)) -#define ENC_OPS3(OP0, OP1, OP2) ((Operand::kOp##OP0) + ((Operand::kOp##OP1) << 3) + ((Operand::kOp##OP2) << 6)) -#define ENC_OPS4(OP0, OP1, OP2, OP3) ((Operand::kOp##OP0) + ((Operand::kOp##OP1) << 3) + ((Operand::kOp##OP2) << 6) + ((Operand::kOp##OP3) << 9)) - -// ============================================================================ -// [asmjit::X86Assembler - Emit] -// ============================================================================ - -Error X86Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { - Error err; - - const Operand_* rmRel; // Memory operand or operand that holds Label|Imm. - uint32_t rmInfo; // Memory operand's info based on x86MemInfo. - uint32_t rbReg; // Memory base or modRM register. - uint32_t rxReg; // Memory index register. - uint32_t opReg; // ModR/M opcode or register id. - uint32_t opCode; // Instruction opcode. - - LabelEntry* label; // Label entry. - RelocEntry* re = nullptr; // Relocation entry. - int32_t relOffset; // Relative offset - FastUInt8 relSize = 0; // Relative size. - - int64_t imVal = 0; // Immediate value (must be 64-bit). - FastUInt8 imLen = 0; // Immediate length. - - const uint32_t kSHR_W_PP = X86Inst::kOpCode_PP_Shift - 16; - const uint32_t kSHR_W_EW = X86Inst::kOpCode_EW_Shift - 23; - - uint8_t* cursor = _bufferPtr; - uint32_t options = static_cast(instId >= X86Inst::_kIdCount) | - static_cast((size_t)(_bufferEnd - cursor) < 16) | - getGlobalOptions() | getOptions(); - - const X86Inst* instData = X86InstDB::instData + instId; - const X86Inst::CommonData* commonData; - - // Handle failure and rare cases first. - const uint32_t kErrorsAndSpecialCases = - CodeEmitter::kOptionMaybeFailureCase | // Error and buffer check. - CodeEmitter::kOptionStrictValidation | // Strict validation. - X86Inst::kOptionRep | // REP/REPZ prefix. - X86Inst::kOptionRepnz | // REPNZ prefix. - X86Inst::kOptionLock | // LOCK prefix. - X86Inst::kOptionXAcquire | // XACQUIRE prefix. - X86Inst::kOptionXRelease ; // XRELEASE prefix. - - // Signature of the first 3 operands. - uint32_t isign3 = o0.getOp() + (o1.getOp() << 3) + (o2.getOp() << 6); - - if (ASMJIT_UNLIKELY(options & kErrorsAndSpecialCases)) { - // Don't do anything if we are in error state. - if (_lastError) return _lastError; - - if (options & CodeEmitter::kOptionMaybeFailureCase) { - // Unknown instruction. - if (ASMJIT_UNLIKELY(instId >= X86Inst::_kIdCount)) - goto InvalidArgument; - - // Grow request, happens rarely. - if ((size_t)(_bufferEnd - cursor) < 16) { - err = _code->growBuffer(&_section->_buffer, 16); - if (ASMJIT_UNLIKELY(err)) goto Failed; - - cursor = _bufferPtr; - options &= ~1; - } - } - - // Strict validation. -#if !defined(ASMJIT_DISABLE_VALIDATION) - if (options & CodeEmitter::kOptionStrictValidation) { - Operand_ opArray[6]; - - opArray[0].copyFrom(o0); - opArray[1].copyFrom(o1); - opArray[2].copyFrom(o2); - opArray[3].copyFrom(o3); - - if (options & kOptionOp4Op5Used) { - opArray[4].copyFrom(_op4); - opArray[5].copyFrom(_op5); - } - else { - opArray[4].reset(); - opArray[5].reset(); - } - - err = Inst::validate(getArchType(), Inst::Detail(instId, options, _extraReg), opArray, 6); - if (ASMJIT_UNLIKELY(err)) goto Failed; - } -#endif // !ASMJIT_DISABLE_VALIDATION - - uint32_t iFlags = instData->getFlags(); - - // LOCK, XACQUIRE, and XRELEASE prefixes. - if (options & X86Inst::kOptionLock) { - bool xAcqRel = (options & (X86Inst::kOptionXAcquire | X86Inst::kOptionXRelease)) != 0; - - if (ASMJIT_UNLIKELY(!(iFlags & (X86Inst::kFlagLock)) && !xAcqRel)) - goto InvalidLockPrefix; - - if (xAcqRel) { - if (ASMJIT_UNLIKELY((options & X86Inst::kOptionXAcquire) && !(iFlags & X86Inst::kFlagXAcquire))) - goto InvalidXAcquirePrefix; - - if (ASMJIT_UNLIKELY((options & X86Inst::kOptionXRelease) && !(iFlags & X86Inst::kFlagXRelease))) - goto InvalidXReleasePrefix; - - EMIT_BYTE((options & X86Inst::kOptionXAcquire) ? 0xF2 : 0xF3); - } - - EMIT_BYTE(0xF0); - } - - // REP and REPNZ prefixes. - if (options & (X86Inst::kOptionRep | X86Inst::kOptionRepnz)) { - if (ASMJIT_UNLIKELY(!(iFlags & (X86Inst::kFlagRep | X86Inst::kFlagRepnz)))) - goto InvalidRepPrefix; - - if (_extraReg.isValid() && ASMJIT_UNLIKELY(_extraReg.getKind() != X86Reg::kKindGp || _extraReg.getId() != X86Gp::kIdCx)) - goto InvalidRepPrefix; - - EMIT_BYTE((options & X86Inst::kOptionRepnz) ? 0xF2 : 0xF3); - } - } - - // -------------------------------------------------------------------------- - // [Encoding Scope] - // -------------------------------------------------------------------------- - - opCode = instData->getMainOpCode(); - opReg = x86ExtractO(opCode); - commonData = &instData->getCommonData(); - - switch (instData->getEncodingType()) { - case X86Inst::kEncodingNone: - goto EmitDone; - - // ------------------------------------------------------------------------ - // [X86] - // ------------------------------------------------------------------------ - - case X86Inst::kEncodingX86Op: - goto EmitX86Op; - - case X86Inst::kEncodingX86Op_O_I8: - if (ASMJIT_UNLIKELY(isign3 != ENC_OPS1(Imm))) - goto InvalidInstruction; - - imVal = o0.as().getUInt8(); - imLen = 1; - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingX86Op_O: - rbReg = 0; - goto EmitX86R; - - case X86Inst::kEncodingX86Op_xAX: - if (isign3 == 0) - goto EmitX86Op; - - if (isign3 == ENC_OPS1(Reg) && o0.getId() == X86Gp::kIdAx) - goto EmitX86Op; - break; - - case X86Inst::kEncodingX86Op_xDX_xAX: - if (isign3 == 0) - goto EmitX86Op; - - if (isign3 == ENC_OPS2(Reg, Reg) && o0.getId() == X86Gp::kIdDx && - o1.getId() == X86Gp::kIdAx) - goto EmitX86Op; - break; - - case X86Inst::kEncodingX86Op_ZAX: - if (isign3 == 0) - goto EmitX86Op; - - rmRel = &o0; - if (isign3 == ENC_OPS1(Mem) && x86IsImplicitMem(o0, X86Gp::kIdAx)) - goto EmitX86OpImplicitMem; - - break; - - case X86Inst::kEncodingX86I_xAX: - // Implicit form. - if (isign3 == ENC_OPS1(Imm)) { - imVal = o0.as().getUInt8(); - imLen = 1; - goto EmitX86Op; - } - - // Explicit form. - if (isign3 == ENC_OPS2(Reg, Imm) && o0.getId() == X86Gp::kIdAx) { - imVal = o1.as().getUInt8(); - imLen = 1; - goto EmitX86Op; - } - break; - - case X86Inst::kEncodingX86M: - rbReg = o0.getId(); - ADD_PREFIX_BY_SIZE(o0.getSize()); - - if (isign3 == ENC_OPS1(Reg)) - goto EmitX86R; - - rmRel = &o0; - if (isign3 == ENC_OPS1(Mem)) - goto EmitX86M; - break; - - case X86Inst::kEncodingX86M_GPB_MulDiv: -CaseX86M_GPB_MulDiv: - // Explicit form? - if (isign3 > 0x7) { - // [AX] <- [AX] div|mul r8. - if (isign3 == ENC_OPS2(Reg, Reg)) { - if (ASMJIT_UNLIKELY(!X86Reg::isGpw(o0, X86Gp::kIdAx) || !X86Reg::isGpb(o1))) - goto InvalidInstruction; - - rbReg = o1.getId(); - FIXUP_GPB(o1, rbReg); - goto EmitX86R; - } - - // [AX] <- [AX] div|mul m8. - if (isign3 == ENC_OPS2(Reg, Mem)) { - if (ASMJIT_UNLIKELY(!X86Reg::isGpw(o0, X86Gp::kIdAx))) - goto InvalidInstruction; - - rmRel = &o1; - goto EmitX86M; - } - - // [?DX:?AX] <- [?DX:?AX] div|mul r16|r32|r64 - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { - if (ASMJIT_UNLIKELY(o0.getSize() != o1.getSize())) - goto InvalidInstruction; - rbReg = o2.getId(); - - opCode++; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86R; - } - - // [?DX:?AX] <- [?DX:?AX] div|mul m16|m32|m64 - if (isign3 == ENC_OPS3(Reg, Reg, Mem)) { - if (ASMJIT_UNLIKELY(o0.getSize() != o1.getSize())) - goto InvalidInstruction; - rmRel = &o2; - - opCode++; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86M; - } - - goto InvalidInstruction; - } - - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingX86M_GPB: - if (isign3 == ENC_OPS1(Reg)) { - rbReg = o0.getId(); - if (o0.getSize() == 1) { - FIXUP_GPB(o0, rbReg); - goto EmitX86R; - } - else { - opCode++; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86R; - } - } - - if (isign3 == ENC_OPS1(Mem)) { - if (ASMJIT_UNLIKELY(o0.getSize() == 0)) - goto AmbiguousOperandSize; - rmRel = &o0; - - opCode += o0.getSize() != 1; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86M_Only: - if (isign3 == ENC_OPS1(Mem)) { - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Rm: - ADD_PREFIX_BY_SIZE(o0.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingX86Rm_NoRexW: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Rm_Raw66H: - // We normally emit either [66|F2|F3], this instruction requires 66+[F2|F3]. - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - - if (o0.getSize() == 2) - EMIT_BYTE(0x66); - else - ADD_REX_W_BY_SIZE(o0.getSize()); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - - if (o0.getSize() == 2) - EMIT_BYTE(0x66); - else - ADD_REX_W_BY_SIZE(o0.getSize()); - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Mr: - ADD_PREFIX_BY_SIZE(o0.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingX86Mr_NoSize: - if (isign3 == ENC_OPS2(Reg, Reg)) { - rbReg = o0.getId(); - opReg = o1.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - rmRel = &o0; - opReg = o1.getId(); - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Arith: - if (isign3 == ENC_OPS2(Reg, Reg)) { - if (o0.getSize() != o1.getSize()) - goto OperandSizeMismatch; - - opReg = o0.getId(); - rbReg = o1.getId(); - - if (o0.getSize() == 1) { - opCode += 2; - FIXUP_GPB(o0, opReg); - FIXUP_GPB(o1, rbReg); - - if (!(options & X86Inst::kOptionModMR)) - goto EmitX86R; - - opCode -= 2; - Utils::swap(opReg, rbReg); - goto EmitX86R; - } - else { - opCode += 3; - ADD_PREFIX_BY_SIZE(o0.getSize()); - - if (!(options & X86Inst::kOptionModMR)) - goto EmitX86R; - - opCode -= 2; - Utils::swap(opReg, rbReg); - goto EmitX86R; - } - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - - if (o0.getSize() == 1) { - FIXUP_GPB(o0, opReg); - opCode += 2; - goto EmitX86M; - } - else { - opCode += 3; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86M; - } - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opReg = o1.getId(); - rmRel = &o0; - - if (o1.getSize() == 1) { - FIXUP_GPB(o1, opReg); - goto EmitX86M; - } - else { - opCode++; - ADD_PREFIX_BY_SIZE(o1.getSize()); - goto EmitX86M; - } - } - - // The remaining instructions use 0x80 opcode. - opCode = 0x80; - - if (isign3 == ENC_OPS2(Reg, Imm)) { - uint32_t size = o0.getSize(); - - rbReg = o0.getId(); - imVal = static_cast(o1).getInt64(); - - if (size == 1) { - FIXUP_GPB(o0, rbReg); - imLen = 1; - } - else { - if (size == 2) { - ADD_66H_P(1); - } - else if (size == 4) { - // Sign extend so isInt8 returns the right result. - imVal = x86SignExtend32To64(imVal); - } - else if (size == 8) { - // In 64-bit mode it's not possible to use 64-bit immediate. - if (Utils::isUInt32(imVal)) { - // Zero-extend `and` by using a 32-bit GPD destination instead of a 64-bit GPQ. - if (instId == X86Inst::kIdAnd) - size = 4; - else if (!Utils::isInt32(imVal)) - goto InvalidImmediate; - } - ADD_REX_W_BY_SIZE(size); - } - - imLen = std::min(size, 4); - if (Utils::isInt8(imVal) && !(options & X86Inst::kOptionLongForm)) - imLen = 1; - } - - // Alternate Form - AL, AX, EAX, RAX. - if (rbReg == 0 && (size == 1 || imLen != 1) && !(options & X86Inst::kOptionLongForm)) { - opCode &= X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_W; - opCode |= ((opReg << 3) | (0x04 + (size != 1))); - imLen = std::min(size, 4); - goto EmitX86Op; - } - - opCode += size != 1 ? (imLen != 1 ? 1 : 3) : 0; - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Mem, Imm)) { - uint32_t memSize = o0.getSize(); - - if (ASMJIT_UNLIKELY(memSize == 0)) - goto AmbiguousOperandSize; - - imVal = static_cast(o1).getInt64(); - imLen = std::min(memSize, 4); - - // Sign extend so isInt8 returns the right result. - if (memSize == 4) - imVal = x86SignExtend32To64(imVal); - - if (Utils::isInt8(imVal) && !(options & X86Inst::kOptionLongForm)) - imLen = 1; - - opCode += memSize != 1 ? (imLen != 1 ? 1 : 3) : 0; - ADD_PREFIX_BY_SIZE(memSize); - - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Bswap: - if (isign3 == ENC_OPS1(Reg)) { - if (ASMJIT_UNLIKELY(o0.getSize() < 4)) - goto InvalidInstruction; - - opReg = o0.getId(); - ADD_REX_W_BY_SIZE(o0.getSize()); - goto EmitX86OpReg; - } - break; - - case X86Inst::kEncodingX86Bt: - if (isign3 == ENC_OPS2(Reg, Reg)) { - ADD_PREFIX_BY_SIZE(o1.getSize()); - opReg = o1.getId(); - rbReg = o0.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - ADD_PREFIX_BY_SIZE(o1.getSize()); - opReg = o1.getId(); - rmRel = &o0; - goto EmitX86M; - } - - // The remaining instructions use the secondary opcode/r. - imVal = static_cast(o1).getInt64(); - imLen = 1; - - opCode = commonData->getAltOpCode(); - opReg = x86ExtractO(opCode); - ADD_PREFIX_BY_SIZE(o0.getSize()); - - if (isign3 == ENC_OPS2(Reg, Imm)) { - rbReg = o0.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Mem, Imm)) { - if (ASMJIT_UNLIKELY(o0.getSize() == 0)) - goto AmbiguousOperandSize; - - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Call: - if (isign3 == ENC_OPS1(Reg)) { - rbReg = o0.getId(); - goto EmitX86R; - } - - rmRel = &o0; - if (isign3 == ENC_OPS1(Mem)) - goto EmitX86M; - - // Call with 32-bit displacement use 0xE8 opcode. Call with 8-bit - // displacement is not encodable so the alternative opcode field - // in X86DB must be zero. - opCode = 0xE8; - opReg = 0; - goto EmitJmpCall; - - case X86Inst::kEncodingX86Cmpxchg: { - // Convert explicit to implicit. - if (isign3 & (0x7 << 6)) { - if (!X86Reg::isGp(o2) || o2.getId() != X86Gp::kIdAx) - goto InvalidInstruction; - isign3 &= 0x3F; - } - - if (isign3 == ENC_OPS2(Reg, Reg)) { - if (o0.getSize() != o1.getSize()) - goto OperandSizeMismatch; - - rbReg = o0.getId(); - opReg = o1.getId(); - - if (o0.getSize() == 1) { - FIXUP_GPB(o0, rbReg); - FIXUP_GPB(o1, opReg); - goto EmitX86R; - } - else { - ADD_PREFIX_BY_SIZE(o0.getSize()); - opCode++; - goto EmitX86R; - } - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opReg = o1.getId(); - rmRel = &o0; - - if (o1.getSize() == 1) { - FIXUP_GPB(o0, opReg); - goto EmitX86M; - } - else { - ADD_PREFIX_BY_SIZE(o1.getSize()); - opCode++; - goto EmitX86M; - } - } - break; - } - - case X86Inst::kEncodingX86Crc: - opReg = o0.getId(); - ADD_REX_W_BY_SIZE(o0.getSize()); - - if (isign3 == ENC_OPS2(Reg, Reg)) { - rbReg = o1.getId(); - - if (o1.getSize() == 1) { - FIXUP_GPB(o1, rbReg); - goto EmitX86R; - } - else { - // This seems to be the only exception of encoding 66F2 PP prefix. - if (o1.getSize() == 2) EMIT_BYTE(0x66); - - opCode++; - goto EmitX86R; - } - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - rmRel = &o1; - if (o1.getSize() == 0) - goto AmbiguousOperandSize; - - // This seems to be the only exception of encoding 66F2 PP prefix. - if (o1.getSize() == 2) EMIT_BYTE(0x66); - - opCode += o1.getSize() != 1; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Enter: - if (isign3 == ENC_OPS2(Imm, Imm)) { - uint32_t iw = static_cast(o0).getUInt16(); - uint32_t ib = static_cast(o1).getUInt8(); - - imVal = iw | (ib << 16); - imLen = 3; - goto EmitX86Op; - } - break; - - case X86Inst::kEncodingX86Imul: - // First process all forms distinct of `kEncodingX86M_OptB_MulDiv`. - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - opCode = 0x6B; - ADD_PREFIX_BY_SIZE(o0.getSize()); - - imVal = static_cast(o2).getInt64(); - imLen = 1; - - if (!Utils::isInt8(imVal) || (options & X86Inst::kOptionLongForm)) { - opCode -= 2; - imLen = o0.getSize() == 2 ? 2 : 4; - } - - opReg = o0.getId(); - rbReg = o1.getId(); - - goto EmitX86R; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Imm)) { - opCode = 0x6B; - ADD_PREFIX_BY_SIZE(o0.getSize()); - - imVal = static_cast(o2).getInt64(); - imLen = 1; - - // Sign extend so isInt8 returns the right result. - if (o0.getSize() == 4) - imVal = x86SignExtend32To64(imVal); - - if (!Utils::isInt8(imVal) || (options & X86Inst::kOptionLongForm)) { - opCode -= 2; - imLen = o0.getSize() == 2 ? 2 : 4; - } - - opReg = o0.getId(); - rmRel = &o1; - - goto EmitX86M; - } - - if (isign3 == ENC_OPS2(Reg, Reg)) { - // Must be explicit 'ax, r8' form. - if (o1.getSize() == 1) - goto CaseX86M_GPB_MulDiv; - - if (o0.getSize() != o1.getSize()) - goto OperandSizeMismatch; - - opReg = o0.getId(); - rbReg = o1.getId(); - - opCode = X86Inst::kOpCode_MM_0F | 0xAF; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - // Must be explicit 'ax, m8' form. - if (o1.getSize() == 1) - goto CaseX86M_GPB_MulDiv; - - opReg = o0.getId(); - rmRel = &o1; - - opCode = X86Inst::kOpCode_MM_0F | 0xAF; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86M; - } - - // Shorthand to imul 'reg, reg, imm'. - if (isign3 == ENC_OPS2(Reg, Imm)) { - opCode = 0x6B; - ADD_PREFIX_BY_SIZE(o0.getSize()); - - imVal = static_cast(o1).getInt64(); - imLen = 1; - - // Sign extend so isInt8 returns the right result. - if (o0.getSize() == 4) - imVal = x86SignExtend32To64(imVal); - - if (!Utils::isInt8(imVal) || (options & X86Inst::kOptionLongForm)) { - opCode -= 2; - imLen = o0.getSize() == 2 ? 2 : 4; - } - - opReg = rbReg = o0.getId(); - goto EmitX86R; - } - - // Try implicit form. - goto CaseX86M_GPB_MulDiv; - - case X86Inst::kEncodingX86In: - if (isign3 == ENC_OPS2(Reg, Imm)) { - if (ASMJIT_UNLIKELY(o0.getId() != X86Gp::kIdAx)) - goto InvalidInstruction; - - imVal = o1.as().getUInt8(); - imLen = 1; - - opCode = commonData->getAltOpCode() + (o0.getSize() != 1); - ADD_66H_P_BY_SIZE(o0.getSize()); - goto EmitX86Op; - } - - if (isign3 == ENC_OPS2(Reg, Reg)) { - if (ASMJIT_UNLIKELY(o0.getId() != X86Gp::kIdAx || o1.getId() != X86Gp::kIdDx)) - goto InvalidInstruction; - - opCode += o0.getSize() != 1; - ADD_66H_P_BY_SIZE(o0.getSize()); - goto EmitX86Op; - } - break; - - case X86Inst::kEncodingX86Ins: - if (isign3 == ENC_OPS2(Mem, Reg)) { - if (ASMJIT_UNLIKELY(!x86IsImplicitMem(o0, X86Gp::kIdDi) || o1.getId() != X86Gp::kIdDx)) - goto InvalidInstruction; - - uint32_t size = o0.getSize(); - if (ASMJIT_UNLIKELY(size == 0)) - goto AmbiguousOperandSize; - - rmRel = &o0; - opCode += (size != 1); - - ADD_66H_P_BY_SIZE(size); - goto EmitX86OpImplicitMem; - } - break; - - case X86Inst::kEncodingX86IncDec: - if (isign3 == ENC_OPS1(Reg)) { - rbReg = o0.getId(); - - if (o0.getSize() == 1) { - FIXUP_GPB(o0, rbReg); - goto EmitX86R; - } - - if (is32Bit()) { - // INC r16|r32 is only encodable in 32-bit mode (collides with REX). - opCode = commonData->getAltOpCode() + (rbReg & 0x07); - ADD_66H_P_BY_SIZE(o0.getSize()); - goto EmitX86Op; - } - else { - opCode++; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86R; - } - } - - if (isign3 == ENC_OPS1(Mem)) { - rmRel = &o0; - opCode += o0.getSize() != 1; - - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Int: - if (isign3 == ENC_OPS1(Imm)) { - imVal = static_cast(o0).getInt64(); - imLen = 1; - goto EmitX86Op; - } - break; - - case X86Inst::kEncodingX86Jcc: - if (_globalHints & CodeEmitter::kHintPredictedJumps) { - if (options & X86Inst::kOptionTaken) - EMIT_BYTE(0x3E); - if (options & X86Inst::kOptionNotTaken) - EMIT_BYTE(0x2E); - } - - rmRel = &o0; - opReg = 0; - goto EmitJmpCall; - - case X86Inst::kEncodingX86JecxzLoop: - rmRel = &o0; - // Explicit jecxz|loop [r|e]cx, dst - if (o0.isReg()) { - if (ASMJIT_UNLIKELY(!X86Reg::isGp(o0, X86Gp::kIdCx))) - goto InvalidInstruction; - - if ((is32Bit() && o0.getSize() == 2) || (is64Bit() && o0.getSize() == 4)) - EMIT_BYTE(0x67); - - rmRel = &o1; - } - - opReg = 0; - goto EmitJmpCall; - - case X86Inst::kEncodingX86Jmp: - if (isign3 == ENC_OPS1(Reg)) { - rbReg = o0.getId(); - goto EmitX86R; - } - - rmRel = &o0; - if (isign3 == ENC_OPS1(Mem)) - goto EmitX86M; - - // Jump encoded with 32-bit displacement use 0xE9 opcode. Jump encoded - // with 8-bit displacement's opcode is stored as an alternative opcode. - opCode = 0xE9; - opReg = 0; - goto EmitJmpCall; - - case X86Inst::kEncodingX86JmpRel: - rmRel = &o0; - goto EmitJmpCall; - - case X86Inst::kEncodingX86Lea: - if (isign3 == ENC_OPS2(Reg, Mem)) { - ADD_PREFIX_BY_SIZE(o0.getSize()); - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Mov: - // Reg <- Reg - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - - // Asmjit uses segment registers indexed from 1 to 6, leaving zero as - // "no segment register used". We have to fix this (decrement the index - // of the register) when emitting MOV instructions which move to/from - // a segment register. The segment register is always `opReg`, because - // the MOV instruction uses either RM or MR encoding. - - // GP <- ?? - if (X86Reg::isGp(o0)) { - // GP <- GP - if (X86Reg::isGp(o1)) { - uint32_t size0 = o0.getSize(); - uint32_t size1 = o1.getSize(); - - if (size0 != size1) { - // We allow 'mov r64, r32' as it's basically zero-extend. - if (size0 == 8 && size1 == 4) - size0 = 4; // Zero extend, don't promote to 64-bit. - else - goto InvalidInstruction; - } - - if (size0 == 1) { - FIXUP_GPB(o0, opReg); - FIXUP_GPB(o1, rbReg); - opCode = 0x8A; - - if (!(options & X86Inst::kOptionModMR)) - goto EmitX86R; - - opCode -= 2; - Utils::swap(opReg, rbReg); - goto EmitX86R; - } - else { - opCode = 0x8B; - ADD_PREFIX_BY_SIZE(size0); - - if (!(options & X86Inst::kOptionModMR)) - goto EmitX86R; - - opCode -= 2; - Utils::swap(opReg, rbReg); - goto EmitX86R; - } - } - - opReg = rbReg; - rbReg = o0.getId(); - - // GP <- SEG - if (X86Reg::isSeg(o1)) { - opCode = 0x8C; - opReg--; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86R; - } - - // GP <- CR - if (X86Reg::isCr(o1)) { - opCode = 0x20 | X86Inst::kOpCode_MM_0F; - - // Use `LOCK MOV` in 32-bit mode if CR8+ register is accessed (AMD extension). - if ((opReg & 0x8) && is32Bit()) { - EMIT_BYTE(0xF0); - opReg &= 0x7; - } - goto EmitX86R; - } - - // GP <- DR - if (X86Reg::isDr(o1)) { - opCode = 0x21 | X86Inst::kOpCode_MM_0F; - goto EmitX86R; - } - } - else { - // ?? <- GP - if (!X86Reg::isGp(o1)) - goto InvalidInstruction; - - // SEG <- GP - if (X86Reg::isSeg(o0)) { - opCode = 0x8E; - opReg--; - ADD_PREFIX_BY_SIZE(o1.getSize()); - goto EmitX86R; - } - - // CR <- GP - if (X86Reg::isCr(o0)) { - opCode = 0x22 | X86Inst::kOpCode_MM_0F; - - // Use `LOCK MOV` in 32-bit mode if CR8+ register is accessed (AMD extension). - if ((opReg & 0x8) && is32Bit()) { - EMIT_BYTE(0xF0); - opReg &= 0x7; - } - goto EmitX86R; - } - - // DR <- GP - if (X86Reg::isDr(o0)) { - opCode = 0x23 | X86Inst::kOpCode_MM_0F; - goto EmitX86R; - } - } - - goto InvalidInstruction; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - - // SEG <- Mem - if (X86Reg::isSeg(o0)) { - opCode = 0x8E; - opReg--; - ADD_PREFIX_BY_SIZE(o1.getSize()); - goto EmitX86M; - } - // Reg <- Mem - else { - if (o0.getSize() == 1) { - opCode = 0; - FIXUP_GPB(o0, opReg); - } - else { - opCode = 1; - ADD_PREFIX_BY_SIZE(o0.getSize()); - } - - // Handle a special form `mov al|ax|eax|rax, [ptr64]` that doesn't use MOD. - if (o0.getId() == X86Gp::kIdAx && !rmRel->as().hasBaseOrIndex()) { - imVal = rmRel->as().getOffset(); - if (!is64Bit() || (is64Bit() && ((options & X86Inst::kOptionLongForm) || !Utils::isInt32(imVal)))) { - opCode += 0xA0; - goto EmitX86OpMovAbs; - } - } - - opCode += 0x8A; - goto EmitX86M; - } - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opReg = o1.getId(); - rmRel = &o0; - - // Mem <- SEG - if (X86Reg::isSeg(o1)) { - opCode = 0x8C; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86M; - } - // Mem <- Reg - else { - if (o1.getSize() == 1) { - opCode = 0; - FIXUP_GPB(o1, opReg); - } - else { - opCode = 1; - ADD_PREFIX_BY_SIZE(o1.getSize()); - } - - // Handle a special form `mov [ptr64], al|ax|eax|rax` that doesn't use MOD. - if (o1.getId() == X86Gp::kIdAx && !rmRel->as().hasBaseOrIndex()) { - imVal = rmRel->as().getOffset(); - if (!is64Bit() || (is64Bit() && ((options & X86Inst::kOptionLongForm) || !Utils::isInt32(imVal)))) { - opCode += 0xA2; - goto EmitX86OpMovAbs; - } - } - - opCode += 0x88; - goto EmitX86M; - } - } - - if (isign3 == ENC_OPS2(Reg, Imm)) { - opReg = o0.getId(); - imLen = o0.getSize(); - - if (imLen == 1) { - FIXUP_GPB(o0, opReg); - - imVal = static_cast(o1).getUInt8(); - opCode = 0xB0; - goto EmitX86OpReg; - } - else { - // 64-bit immediate in 64-bit mode is allowed. - imVal = static_cast(o1).getInt64(); - - // Optimize the instruction size by using a 32-bit immediate if possible. - if (imLen == 8 && !(options & X86Inst::kOptionLongForm)) { - if (Utils::isUInt32(imVal)) { - // Zero-extend by using a 32-bit GPD destination instead of a 64-bit GPQ. - imLen = 4; - } - else if (Utils::isInt32(imVal)) { - // Sign-extend, uses 'C7 /0' opcode. - rbReg = opReg; - - opCode = 0xC7 | X86Inst::kOpCode_W; - opReg = 0; - - imLen = 4; - goto EmitX86R; - } - } - - opCode = 0xB8; - ADD_PREFIX_BY_SIZE(imLen); - goto EmitX86OpReg; - } - } - - if (isign3 == ENC_OPS2(Mem, Imm)) { - uint32_t memSize = o0.getSize(); - - if (ASMJIT_UNLIKELY(memSize == 0)) - goto AmbiguousOperandSize; - - imVal = static_cast(o1).getInt64(); - imLen = std::min(memSize, 4); - - opCode = 0xC6 + (memSize != 1); - opReg = 0; - ADD_PREFIX_BY_SIZE(memSize); - - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86MovsxMovzx: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - ADD_PREFIX_BY_SIZE(o0.getSize()); - - if (o1.getSize() == 1) { - FIXUP_GPB(o1, rbReg); - goto EmitX86R; - } - else { - opCode++; - goto EmitX86R; - } - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opCode += o1.getSize() != 1; - ADD_PREFIX_BY_SIZE(o0.getSize()); - - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Out: - if (isign3 == ENC_OPS2(Imm, Reg)) { - if (ASMJIT_UNLIKELY(o1.getId() != X86Gp::kIdAx)) - goto InvalidInstruction; - - imVal = o0.as().getUInt8(); - imLen = 1; - - opCode = commonData->getAltOpCode() + (o1.getSize() != 1); - ADD_66H_P_BY_SIZE(o1.getSize()); - goto EmitX86Op; - } - - if (isign3 == ENC_OPS2(Reg, Reg)) { - if (ASMJIT_UNLIKELY(o0.getId() != X86Gp::kIdDx || o1.getId() != X86Gp::kIdAx)) - goto InvalidInstruction; - - opCode += o1.getSize() != 1; - ADD_66H_P_BY_SIZE(o1.getSize()); - goto EmitX86Op; - } - break; - - case X86Inst::kEncodingX86Outs: - if (isign3 == ENC_OPS2(Reg, Mem)) { - if (ASMJIT_UNLIKELY(o0.getId() != X86Gp::kIdDx || !x86IsImplicitMem(o1, X86Gp::kIdSi))) - goto InvalidInstruction; - - uint32_t size = o1.getSize(); - if (ASMJIT_UNLIKELY(size == 0)) - goto AmbiguousOperandSize; - - rmRel = &o1; - opCode += (size != 1); - - ADD_66H_P_BY_SIZE(size); - goto EmitX86OpImplicitMem; - } - break; - - case X86Inst::kEncodingX86Push: - if (isign3 == ENC_OPS1(Reg)) { - if (X86Reg::isSeg(o0)) { - uint32_t segment = o0.getId(); - if (ASMJIT_UNLIKELY(segment >= X86Seg::kIdCount)) - goto InvalidSegment; - - if (segment >= X86Seg::kIdFs) - EMIT_BYTE(0x0F); - - EMIT_BYTE(x86OpCodePushSeg[segment]); - goto EmitDone; - } - else { - goto CaseX86Pop_Gp; - } - } - - if (isign3 == ENC_OPS1(Imm)) { - imVal = static_cast(o0).getInt64(); - imLen = 4; - - if (Utils::isInt8(imVal) && !(options & X86Inst::kOptionLongForm)) - imLen = 1; - - opCode = imLen == 1 ? 0x6A : 0x68; - goto EmitX86Op; - } - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingX86Pop: - if (isign3 == ENC_OPS1(Reg)) { - if (X86Reg::isSeg(o0)) { - uint32_t segment = o0.getId(); - if (ASMJIT_UNLIKELY(segment == X86Seg::kIdCs || segment >= X86Seg::kIdCount)) - goto InvalidSegment; - - if (segment >= X86Seg::kIdFs) - EMIT_BYTE(0x0F); - - EMIT_BYTE(x86OpCodePopSeg[segment]); - goto EmitDone; - } - else { -CaseX86Pop_Gp: - // We allow 2 byte, 4 byte, and 8 byte register sizes, although PUSH - // and POP only allow 2 bytes or native size. On 64-bit we simply - // PUSH/POP 64-bit register even if 32-bit register was given. - if (ASMJIT_UNLIKELY(o0.getSize() < 2)) - goto InvalidInstruction; - - opCode = commonData->getAltOpCode(); - opReg = o0.getId(); - - ADD_66H_P_BY_SIZE(o0.getSize()); - goto EmitX86OpReg; - } - } - - if (isign3 == ENC_OPS1(Mem)) { - if (ASMJIT_UNLIKELY(o0.getSize() == 0)) - goto AmbiguousOperandSize; - - if (ASMJIT_UNLIKELY(o0.getSize() != 2 && o0.getSize() != getGpSize())) - goto InvalidInstruction; - - ADD_66H_P_BY_SIZE(o0.getSize()); - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Ret: - if (isign3 == 0) { - // 'ret' without immediate, change C2 to C3. - opCode++; - goto EmitX86Op; - } - - if (isign3 == ENC_OPS1(Imm)) { - imVal = static_cast(o0).getInt64(); - if (imVal == 0 && !(options & X86Inst::kOptionLongForm)) { - // 'ret' without immediate, change C2 to C3. - opCode++; - goto EmitX86Op; - } - else { - imLen = 2; - goto EmitX86Op; - } - } - break; - - case X86Inst::kEncodingX86Rot: - if (o0.isReg()) { - rbReg = o0.getId(); - - if (o0.getSize() == 1) { - FIXUP_GPB(o0, rbReg); - } - else { - opCode++; - ADD_PREFIX_BY_SIZE(o0.getSize()); - } - - if (isign3 == ENC_OPS2(Reg, Reg)) { - if (ASMJIT_UNLIKELY(o1.getId() != X86Gp::kIdCx)) - goto InvalidInstruction; - - opCode += 2; - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Reg, Imm)) { - imVal = static_cast(o1).getInt64() & 0xFF; - imLen = 0; - - if (imVal == 1 && !(options & X86Inst::kOptionLongForm)) - goto EmitX86R; - - imLen = 1; - opCode -= 0x10; - goto EmitX86R; - } - } - else { - opCode += o0.getSize() != 1; - ADD_PREFIX_BY_SIZE(o0.getSize()); - - if (isign3 == ENC_OPS2(Mem, Reg)) { - if (ASMJIT_UNLIKELY(o1.getId() != X86Gp::kIdCx)) - goto InvalidInstruction; - - opCode += 2; - rmRel = &o0; - goto EmitX86M; - } - - if (isign3 == ENC_OPS2(Mem, Imm)) { - if (ASMJIT_UNLIKELY(o0.getSize() == 0)) - goto AmbiguousOperandSize; - - imVal = static_cast(o1).getInt64() & 0xFF; - imLen = 0; - rmRel = &o0; - - if (imVal == 1 && !(options & X86Inst::kOptionLongForm)) - goto EmitX86M; - - imLen = 1; - opCode -= 0x10; - goto EmitX86M; - } - } - break; - - case X86Inst::kEncodingX86Set: - if (isign3 == ENC_OPS1(Reg)) { - rbReg = o0.getId(); - FIXUP_GPB(o0, rbReg); - goto EmitX86R; - } - - if (isign3 == ENC_OPS1(Mem)) { - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86ShldShrd: - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - ADD_PREFIX_BY_SIZE(o0.getSize()); - imVal = static_cast(o2).getInt64(); - imLen = 1; - - opReg = o1.getId(); - rbReg = o0.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS3(Mem, Reg, Imm)) { - ADD_PREFIX_BY_SIZE(o1.getSize()); - imVal = static_cast(o2).getInt64(); - imLen = 1; - - opReg = o1.getId(); - rmRel = &o0; - goto EmitX86M; - } - - // The following instructions use opCode + 1. - opCode++; - - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { - if (ASMJIT_UNLIKELY(o2.getId() != X86Gp::kIdCx)) - goto InvalidInstruction; - - ADD_PREFIX_BY_SIZE(o0.getSize()); - opReg = o1.getId(); - rbReg = o0.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS3(Mem, Reg, Reg)) { - if (ASMJIT_UNLIKELY(o2.getId() != X86Gp::kIdCx)) - goto InvalidInstruction; - - ADD_PREFIX_BY_SIZE(o1.getSize()); - opReg = o1.getId(); - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86StrRm: - if (isign3 == ENC_OPS2(Reg, Mem)) { - rmRel = &o1; - if (ASMJIT_UNLIKELY(rmRel->as().getOffsetLo32() || !X86Reg::isGp(o0.as(), X86Gp::kIdAx))) - goto InvalidInstruction; - - uint32_t size = o0.getSize(); - if (o1.hasSize() && ASMJIT_UNLIKELY(o1.getSize() != size)) - goto OperandSizeMismatch; - - ADD_PREFIX_BY_SIZE(size); - opCode += static_cast(size != 1); - - goto EmitX86OpImplicitMem; - } - break; - - case X86Inst::kEncodingX86StrMr: - if (isign3 == ENC_OPS2(Mem, Reg)) { - rmRel = &o0; - if (ASMJIT_UNLIKELY(rmRel->as().getOffsetLo32() || !X86Reg::isGp(o1.as(), X86Gp::kIdAx))) - goto InvalidInstruction; - - uint32_t size = o1.getSize(); - if (o0.hasSize() && ASMJIT_UNLIKELY(o0.getSize() != size)) - goto OperandSizeMismatch; - - ADD_PREFIX_BY_SIZE(size); - opCode += static_cast(size != 1); - - goto EmitX86OpImplicitMem; - } - break; - - case X86Inst::kEncodingX86StrMm: - if (isign3 == ENC_OPS2(Mem, Mem)) { - if (ASMJIT_UNLIKELY(o0.as().getBaseIndexType() != - o1.as().getBaseIndexType())) - goto InvalidInstruction; - - rmRel = &o1; - if (ASMJIT_UNLIKELY(o0.as().hasOffset())) - goto InvalidInstruction; - - uint32_t size = o1.getSize(); - if (ASMJIT_UNLIKELY(size == 0)) - goto AmbiguousOperandSize; - - if (ASMJIT_UNLIKELY(o0.getSize() != size)) - goto OperandSizeMismatch; - - ADD_PREFIX_BY_SIZE(size); - opCode += static_cast(size != 1); - - goto EmitX86OpImplicitMem; - } - break; - - case X86Inst::kEncodingX86Test: - if (isign3 == ENC_OPS2(Reg, Reg)) { - if (o0.getSize() != o1.getSize()) - goto OperandSizeMismatch; - - rbReg = o0.getId(); - opReg = o1.getId(); - - if (o0.getSize() == 1) { - FIXUP_GPB(o0, rbReg); - FIXUP_GPB(o1, opReg); - goto EmitX86R; - } - else { - opCode++; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86R; - } - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opReg = o1.getId(); - rmRel = &o0; - - if (o1.getSize() == 1) { - FIXUP_GPB(o1, opReg); - goto EmitX86M; - } - else { - opCode++; - ADD_PREFIX_BY_SIZE(o1.getSize()); - goto EmitX86M; - } - } - - // The following instructions use the secondary opcode. - opCode = commonData->getAltOpCode(); - opReg = x86ExtractO(opCode); - - if (isign3 == ENC_OPS2(Reg, Imm)) { - rbReg = o0.getId(); - - if (o0.getSize() == 1) { - FIXUP_GPB(o0, rbReg); - - imVal = static_cast(o1).getUInt8(); - imLen = 1; - } - else { - opCode++; - ADD_PREFIX_BY_SIZE(o0.getSize()); - - imVal = static_cast(o1).getInt64(); - imLen = std::min(o0.getSize(), 4); - } - - // Alternate Form - AL, AX, EAX, RAX. - if (o0.getId() == 0 && !(options & X86Inst::kOptionLongForm)) { - opCode &= X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_W; - opCode |= 0xA8 + (o0.getSize() != 1); - goto EmitX86Op; - } - - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Mem, Imm)) { - if (ASMJIT_UNLIKELY(o0.getSize() == 0)) - goto AmbiguousOperandSize; - - imVal = static_cast(o1).getInt64(); - imLen = std::min(o0.getSize(), 4); - - opCode += (o0.getSize() != 1); - ADD_PREFIX_BY_SIZE(o0.getSize()); - - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Xchg: - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - - if (o0.getSize() == 1) { - FIXUP_GPB(o0, opReg); - goto EmitX86M; - } - else { - opCode++; - ADD_PREFIX_BY_SIZE(o0.getSize()); - goto EmitX86M; - } - } - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingX86Xadd: - if (isign3 == ENC_OPS2(Reg, Reg)) { - rbReg = o0.getId(); - opReg = o1.getId(); - - if (o0.getSize() != o1.getSize()) - goto OperandSizeMismatch; - - if (o0.getSize() == 1) { - FIXUP_GPB(o0, rbReg); - FIXUP_GPB(o1, opReg); - goto EmitX86R; - } - else { - opCode++; - ADD_PREFIX_BY_SIZE(o0.getSize()); - - // Special opcode for 'xchg ?ax, reg'. - if (instId == X86Inst::kIdXchg && (opReg == 0 || rbReg == 0)) { - opCode &= X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_W; - opCode |= 0x90; - // One of `xchg a, b` or `xchg b, a` is AX/EAX/RAX. - opReg += rbReg; - goto EmitX86OpReg; - } - else { - goto EmitX86R; - } - } - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opCode += o1.getSize() != 1; - ADD_PREFIX_BY_SIZE(o1.getSize()); - - opReg = o1.getId(); - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingX86Fence: - rbReg = 0; - goto EmitX86R; - - case X86Inst::kEncodingX86Bndmov: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - - // ModRM encoding: - if (!(options & X86Inst::kOptionModMR)) - goto EmitX86R; - - // ModMR encoding: - opCode = commonData->getAltOpCode(); - std::swap(opReg, rbReg); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opCode = commonData->getAltOpCode(); - - rmRel = &o0; - opReg = o1.getId(); - goto EmitX86M; - } - break; - - // ------------------------------------------------------------------------ - // [FPU] - // ------------------------------------------------------------------------ - - case X86Inst::kEncodingFpuOp: - goto EmitFpuOp; - - case X86Inst::kEncodingFpuArith: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - - // We switch to the alternative opcode if the first operand is zero. - if (opReg == 0) { -CaseFpuArith_Reg: - opCode = ((0xD8 << X86Inst::kOpCode_FPU_2B_Shift) ) + - ((opCode >> X86Inst::kOpCode_FPU_2B_Shift) & 0xFF) + rbReg; - goto EmitFpuOp; - } - else if (rbReg == 0) { - rbReg = opReg; - opCode = ((0xDC << X86Inst::kOpCode_FPU_2B_Shift) ) + - ((opCode ) & 0xFF) + rbReg; - goto EmitFpuOp; - } - else { - goto InvalidInstruction; - } - } - - if (isign3 == ENC_OPS1(Mem)) { -CaseFpuArith_Mem: - // 0xD8/0xDC, depends on the size of the memory operand; opReg is valid. - opCode = (o0.getSize() == 4) ? 0xD8 : 0xDC; - // Clear compressed displacement before going to EmitX86M. - opCode &= ~static_cast(X86Inst::kOpCode_CDSHL_Mask); - - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingFpuCom: - if (isign3 == 0) { - rbReg = 1; - goto CaseFpuArith_Reg; - } - - if (isign3 == ENC_OPS1(Reg)) { - rbReg = o0.getId(); - goto CaseFpuArith_Reg; - } - - if (isign3 == ENC_OPS1(Mem)) { - goto CaseFpuArith_Mem; - } - break; - - case X86Inst::kEncodingFpuFldFst: - if (isign3 == ENC_OPS1(Mem)) { - rmRel = &o0; - - if (o0.getSize() == 4 && commonData->hasFlag(X86Inst::kFlagFpuM32)) { - goto EmitX86M; - } - - if (o0.getSize() == 8 && commonData->hasFlag(X86Inst::kFlagFpuM64)) { - opCode += 4; - goto EmitX86M; - } - - if (o0.getSize() == 10 && commonData->hasFlag(X86Inst::kFlagFpuM80)) { - opCode = commonData->getAltOpCode(); - opReg = x86ExtractO(opCode); - goto EmitX86M; - } - } - - if (isign3 == ENC_OPS1(Reg)) { - if (instId == X86Inst::kIdFld ) { opCode = (0xD9 << X86Inst::kOpCode_FPU_2B_Shift) + 0xC0 + o0.getId(); goto EmitFpuOp; } - if (instId == X86Inst::kIdFst ) { opCode = (0xDD << X86Inst::kOpCode_FPU_2B_Shift) + 0xD0 + o0.getId(); goto EmitFpuOp; } - if (instId == X86Inst::kIdFstp) { opCode = (0xDD << X86Inst::kOpCode_FPU_2B_Shift) + 0xD8 + o0.getId(); goto EmitFpuOp; } - } - break; - - case X86Inst::kEncodingFpuM: - if (isign3 == ENC_OPS1(Mem)) { - // Clear compressed displacement before going to EmitX86M. - opCode &= ~static_cast(X86Inst::kOpCode_CDSHL_Mask); - - rmRel = &o0; - if (o0.getSize() == 2 && commonData->hasFlag(X86Inst::kFlagFpuM16)) { - opCode += 4; - goto EmitX86M; - } - - if (o0.getSize() == 4 && commonData->hasFlag(X86Inst::kFlagFpuM32)) { - goto EmitX86M; - } - - if (o0.getSize() == 8 && commonData->hasFlag(X86Inst::kFlagFpuM64)) { - opCode = commonData->getAltOpCode() & ~static_cast(X86Inst::kOpCode_CDSHL_Mask); - opReg = x86ExtractO(opCode); - goto EmitX86M; - } - } - break; - - case X86Inst::kEncodingFpuRDef: - if (isign3 == 0) { - opCode += 1; - goto EmitFpuOp; - } - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingFpuR: - if (isign3 == ENC_OPS1(Reg)) { - opCode += o0.getId(); - goto EmitFpuOp; - } - break; - - case X86Inst::kEncodingFpuStsw: - if (isign3 == ENC_OPS1(Reg)) { - if (ASMJIT_UNLIKELY(o0.getId() != X86Gp::kIdAx)) - goto InvalidInstruction; - - opCode = commonData->getAltOpCode(); - goto EmitFpuOp; - } - - if (isign3 == ENC_OPS1(Mem)) { - // Clear compressed displacement before going to EmitX86M. - opCode &= ~static_cast(X86Inst::kOpCode_CDSHL_Mask); - - rmRel = &o0; - goto EmitX86M; - } - break; - - // ------------------------------------------------------------------------ - // [Ext] - // ------------------------------------------------------------------------ - - case X86Inst::kEncodingExtPextrw: - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - ADD_66H_P(X86Reg::isXmm(o1)); - - imVal = static_cast(o2).getInt64(); - imLen = 1; - - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS3(Mem, Reg, Imm)) { - // Secondary opcode of 'pextrw' instruction (SSE4.1). - opCode = commonData->getAltOpCode(); - ADD_66H_P(X86Reg::isXmm(o1)); - - imVal = static_cast(o2).getInt64(); - imLen = 1; - - opReg = o1.getId(); - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingExtExtract: - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - ADD_66H_P(X86Reg::isXmm(o1)); - - imVal = static_cast(o2).getInt64(); - imLen = 1; - - opReg = o1.getId(); - rbReg = o0.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS3(Mem, Reg, Imm)) { - ADD_66H_P(X86Reg::isXmm(o1)); - - imVal = static_cast(o2).getInt64(); - imLen = 1; - - opReg = o1.getId(); - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingExtMov: - // GP|MMX|XMM <- GP|MMX|XMM - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - - if (!(options & X86Inst::kOptionModMR) || !commonData->hasAltOpCode()) - goto EmitX86R; - - opCode = commonData->getAltOpCode(); - Utils::swap(opReg, rbReg); - goto EmitX86R; - } - - // GP|MMX|XMM <- Mem - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - - // The following instruction uses opCode[1]. - opCode = commonData->getAltOpCode(); - - // Mem <- GP|MMX|XMM - if (isign3 == ENC_OPS2(Mem, Reg)) { - opReg = o1.getId(); - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingExtMovnti: - if (isign3 == ENC_OPS2(Mem, Reg)) { - ADD_REX_W(X86Reg::isGpq(o1)); - - opReg = o1.getId(); - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingExtMovbe: - if (isign3 == ENC_OPS2(Reg, Mem)) { - if (o0.getSize() == 1) - goto InvalidInstruction; - - ADD_PREFIX_BY_SIZE(o0.getSize()); - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - - // The following instruction uses the secondary opcode. - opCode = commonData->getAltOpCode(); - - if (isign3 == ENC_OPS2(Mem, Reg)) { - if (o1.getSize() == 1) - goto InvalidInstruction; - - ADD_PREFIX_BY_SIZE(o1.getSize()); - opReg = o1.getId(); - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingExtMovd: -CaseExtMovd: - opReg = o0.getId(); - ADD_66H_P(X86Reg::isXmm(o0)); - - // MMX/XMM <- Gp - if (isign3 == ENC_OPS2(Reg, Reg) && X86Reg::isGp(o1)) { - rbReg = o1.getId(); - goto EmitX86R; - } - - // MMX/XMM <- Mem - if (isign3 == ENC_OPS2(Reg, Mem)) { - rmRel = &o1; - goto EmitX86M; - } - - // The following instructions use the secondary opcode. - opCode &= X86Inst::kOpCode_W; - opCode |= commonData->getAltOpCode(); - opReg = o1.getId(); - ADD_66H_P(X86Reg::isXmm(o1)); - - // GP <- MMX/XMM - if (isign3 == ENC_OPS2(Reg, Reg) && X86Reg::isGp(o0)) { - rbReg = o0.getId(); - goto EmitX86R; - } - - // Mem <- MMX/XMM - if (isign3 == ENC_OPS2(Mem, Reg)) { - rmRel = &o0; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingExtMovq: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - - // MMX <- MMX - if (X86Reg::isMm(o0) && X86Reg::isMm(o1)) { - opCode = X86Inst::kOpCode_PP_00 | X86Inst::kOpCode_MM_0F | 0x6F; - - if (!(options & X86Inst::kOptionModMR)) - goto EmitX86R; - - opCode += 0x10; - Utils::swap(opReg, rbReg); - goto EmitX86R; - } - - // XMM <- XMM - if (X86Reg::isXmm(o0) && X86Reg::isXmm(o1)) { - opCode = X86Inst::kOpCode_PP_F3 | X86Inst::kOpCode_MM_0F | 0x7E; - - if (!(options & X86Inst::kOptionModMR)) - goto EmitX86R; - - opCode = X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_MM_0F | 0xD6; - Utils::swap(opReg, rbReg); - goto EmitX86R; - } - - // MMX <- XMM (MOVDQ2Q) - if (X86Reg::isMm(o0) && X86Reg::isXmm(o1)) { - opCode = X86Inst::kOpCode_PP_F2 | X86Inst::kOpCode_MM_0F | 0xD6; - goto EmitX86R; - } - - // XMM <- MMX (MOVQ2DQ) - if (X86Reg::isXmm(o0) && X86Reg::isMm(o1)) { - opCode = X86Inst::kOpCode_PP_F3 | X86Inst::kOpCode_MM_0F | 0xD6; - goto EmitX86R; - } - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - - // MMX <- Mem - if (X86Reg::isMm(o0)) { - opCode = X86Inst::kOpCode_PP_00 | X86Inst::kOpCode_MM_0F | 0x6F; - goto EmitX86M; - } - - // XMM <- Mem - if (X86Reg::isXmm(o0)) { - opCode = X86Inst::kOpCode_PP_F3 | X86Inst::kOpCode_MM_0F | 0x7E; - goto EmitX86M; - } - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opReg = o1.getId(); - rmRel = &o0; - - // Mem <- MMX - if (X86Reg::isMm(o1)) { - opCode = X86Inst::kOpCode_PP_00 | X86Inst::kOpCode_MM_0F | 0x7F; - goto EmitX86M; - } - - // Mem <- XMM - if (X86Reg::isXmm(o1)) { - opCode = X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_MM_0F | 0xD6; - goto EmitX86M; - } - } - - // MOVQ in other case is simply a MOVD instruction promoted to 64-bit. - opCode |= X86Inst::kOpCode_W; - goto CaseExtMovd; - - case X86Inst::kEncodingExtRm_XMM0: - if (ASMJIT_UNLIKELY(!o2.isNone() && !X86Reg::isXmm(o2, 0))) - goto InvalidInstruction; - - isign3 &= 0x3F; - goto CaseExtRm; - - case X86Inst::kEncodingExtRm_ZDI: - if (ASMJIT_UNLIKELY(!o2.isNone() && !x86IsImplicitMem(o2, X86Gp::kIdDi))) - goto InvalidInstruction; - - isign3 &= 0x3F; - goto CaseExtRm; - - case X86Inst::kEncodingExtRm_Wx: - ADD_REX_W(X86Reg::isGpq(o0) || o1.getSize() == 8); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingExtRm: -CaseExtRm: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingExtRm_P: - if (isign3 == ENC_OPS2(Reg, Reg)) { - ADD_66H_P(X86Reg::isXmm(o0) | X86Reg::isXmm(o1)); - - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - ADD_66H_P(X86Reg::isXmm(o0)); - - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingExtRmRi: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - - // The following instruction uses the secondary opcode. - opCode = commonData->getAltOpCode(); - opReg = x86ExtractO(opCode); - - if (isign3 == ENC_OPS2(Reg, Imm)) { - imVal = static_cast(o1).getInt64(); - imLen = 1; - - rbReg = o0.getId(); - goto EmitX86R; - } - break; - - case X86Inst::kEncodingExtRmRi_P: - if (isign3 == ENC_OPS2(Reg, Reg)) { - ADD_66H_P(X86Reg::isXmm(o0) | X86Reg::isXmm(o1)); - - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - ADD_66H_P(X86Reg::isXmm(o0)); - - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - - // The following instruction uses the secondary opcode. - opCode = commonData->getAltOpCode(); - opReg = x86ExtractO(opCode); - - if (isign3 == ENC_OPS2(Reg, Imm)) { - ADD_66H_P(X86Reg::isXmm(o0)); - - imVal = static_cast(o1).getInt64(); - imLen = 1; - - rbReg = o0.getId(); - goto EmitX86R; - } - break; - - case X86Inst::kEncodingExtRmi: - imVal = static_cast(o2).getInt64(); - imLen = 1; - - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Imm)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - break; - - case X86Inst::kEncodingExtRmi_P: - imVal = static_cast(o2).getInt64(); - imLen = 1; - - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - ADD_66H_P(X86Reg::isXmm(o0) | X86Reg::isXmm(o1)); - - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Imm)) { - ADD_66H_P(X86Reg::isXmm(o0)); - - opReg = o0.getId(); - rmRel = &o1; - goto EmitX86M; - } - break; - - // ------------------------------------------------------------------------ - // [Extrq / Insertq (SSE4A)] - // ------------------------------------------------------------------------ - - case X86Inst::kEncodingExtExtrq: - opReg = o0.getId(); - rbReg = o1.getId(); - - if (isign3 == ENC_OPS2(Reg, Reg)) - goto EmitX86R; - - // The following instruction uses the secondary opcode. - opCode = commonData->getAltOpCode(); - - if (isign3 == ENC_OPS3(Reg, Imm, Imm)) { - imVal = (static_cast(o1).getUInt32() ) + - (static_cast(o2).getUInt32() << 8) ; - imLen = 2; - - rbReg = x86ExtractO(opCode); - goto EmitX86R; - } - break; - - case X86Inst::kEncodingExtInsertq: { - const uint32_t isign4 = isign3 + (o3.getOp() << 9); - opReg = o0.getId(); - rbReg = o1.getId(); - - if (isign4 == ENC_OPS2(Reg, Reg)) - goto EmitX86R; - - // The following instruction uses the secondary opcode. - opCode = commonData->getAltOpCode(); - - if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { - imVal = (static_cast(o2).getUInt32() ) + - (static_cast(o3).getUInt32() << 8) ; - imLen = 2; - goto EmitX86R; - } - break; - } - - // ------------------------------------------------------------------------ - // [3dNow] - // ------------------------------------------------------------------------ - - case X86Inst::kEncodingExt3dNow: - // Every 3dNow instruction starts with 0x0F0F and the actual opcode is - // stored as 8-bit immediate. - imVal = opCode & 0xFF; - imLen = 1; - - opCode = X86Inst::kOpCode_MM_0F | 0x0F; - opReg = o0.getId(); - - if (isign3 == ENC_OPS2(Reg, Reg)) { - rbReg = o1.getId(); - goto EmitX86R; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - rmRel = &o1; - goto EmitX86M; - } - break; - - // ------------------------------------------------------------------------ - // [VEX/EVEX] - // ------------------------------------------------------------------------ - - case X86Inst::kEncodingVexOp: - goto EmitVexEvexOp; - - case X86Inst::kEncodingVexKmov: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - - // Form 'k, reg'. - if (X86Reg::isGp(o1)) { - opCode = commonData->getAltOpCode(); - goto EmitVexEvexR; - } - - // Form 'reg, k'. - if (X86Reg::isGp(o0)) { - opCode = commonData->getAltOpCode() + 1; - goto EmitVexEvexR; - } - - // Form 'k, k'. - if (!(options & X86Inst::kOptionModMR)) - goto EmitVexEvexR; - - opCode++; - Utils::swap(opReg, rbReg); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - - goto EmitVexEvexM; - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opReg = o1.getId(); - rmRel = &o0; - - opCode++; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexM: - if (isign3 == ENC_OPS1(Mem)) { - rmRel = &o0; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexM_VM: - if (isign3 == ENC_OPS1(Mem)) { - opCode |= x86OpCodeLByVMem(o0); - rmRel = &o0; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexMr_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o1.getId(); - rbReg = o0.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opReg = o1.getId(); - rmRel = &o0; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexMr_VM: - if (isign3 == ENC_OPS2(Mem, Reg)) { - opCode |= std::max(x86OpCodeLByVMem(o0), x86OpCodeLBySize(o1.getSize())); - - opReg = o1.getId(); - rmRel = &o0; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexMri_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexMri: - imVal = static_cast(o2).getInt64(); - imLen = 1; - - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - opReg = o1.getId(); - rbReg = o0.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Mem, Reg, Imm)) { - opReg = o1.getId(); - rmRel = &o0; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRm_ZDI: - if (ASMJIT_UNLIKELY(!o2.isNone() && !x86IsImplicitMem(o2, X86Gp::kIdDi))) - goto InvalidInstruction; - - isign3 &= 0x3F; - goto CaseVexRm; - - case X86Inst::kEncodingVexRm_Wx: - ADD_REX_W(X86Reg::isGpq(o0) | X86Reg::isGpq(o1)); - goto CaseVexRm; - - case X86Inst::kEncodingVexRm_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRm: -CaseVexRm: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRm_VM: - if (isign3 == ENC_OPS2(Reg, Mem)) { - opCode |= std::max(x86OpCodeLByVMem(o1), x86OpCodeLBySize(o0.getSize())); - opReg = o0.getId(); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRm_T1_4X: { - if (!(options & kOptionOp4Op5Used)) - goto InvalidInstruction; - - if (X86Reg::isZmm(o0 ) && X86Reg::isZmm(o1) && - X86Reg::isZmm(o2 ) && X86Reg::isZmm(o3) && - X86Reg::isZmm(_op4) && _op5.isMem()) { - - // Registers [o1, o2, o3, _op4] must start aligned and must be consecutive. - uint32_t i1 = o1.getId(); - uint32_t i2 = o2.getId(); - uint32_t i3 = o3.getId(); - uint32_t i4 = _op4.getId(); - - if (ASMJIT_UNLIKELY((i1 & 0x3) != 0 || i2 != i1 + 1 || i3 != i1 + 2 || i4 != i1 + 3)) - goto NotConsecutiveRegs; - - opReg = o0.getId(); - rmRel = &_op5; - goto EmitVexEvexM; - } - break; - } - - case X86Inst::kEncodingVexRmi_Wx: - ADD_REX_W(X86Reg::isGpq(o0) | X86Reg::isGpq(o1)); - goto CaseVexRmi; - - case X86Inst::kEncodingVexRmi_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRmi: -CaseVexRmi: - imVal = static_cast(o2).getInt64(); - imLen = 1; - - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Imm)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRvm: -CaseVexRvm: - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { -CaseVexRvm_R: - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Reg, Mem)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRvm_ZDX_Wx: - if (ASMJIT_UNLIKELY(!o3.isNone() && !X86Reg::isGp(o3, X86Gp::kIdDx))) - goto InvalidInstruction; - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRvm_Wx: - ADD_REX_W(X86Reg::isGpq(o0) | (o2.getSize() == 8)); - goto CaseVexRvm; - - case X86Inst::kEncodingVexRvm_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - goto CaseVexRvm; - - case X86Inst::kEncodingVexRvmr_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRvmr: { - const uint32_t isign4 = isign3 + (o3.getOp() << 9); - imVal = o3.getId() << 4; - imLen = 1; - - if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - goto EmitVexEvexR; - } - - if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - goto EmitVexEvexM; - } - break; - } - - case X86Inst::kEncodingVexRvmi_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRvmi: { - const uint32_t isign4 = isign3 + (o3.getOp() << 9); - imVal = static_cast(o3).getInt64(); - imLen = 1; - - if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - goto EmitVexEvexR; - } - - if (isign4 == ENC_OPS4(Reg, Reg, Mem, Imm)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - goto EmitVexEvexM; - } - break; - } - - case X86Inst::kEncodingVexRmv_Wx: - ADD_REX_W(X86Reg::isGpq(o0) | X86Reg::isGpq(o2)); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRmv: - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId()); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId()); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRmvRm_VM: - if (isign3 == ENC_OPS2(Reg, Mem)) { - opCode = commonData->getAltOpCode(); - opCode |= std::max(x86OpCodeLByVMem(o1), x86OpCodeLBySize(o0.getSize())); - - opReg = o0.getId(); - rmRel = &o1; - goto EmitVexEvexM; - } - - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRmv_VM: - if (isign3 == ENC_OPS3(Reg, Mem, Reg)) { - opCode |= std::max(x86OpCodeLByVMem(o1), x86OpCodeLBySize(o0.getSize() | o2.getSize())); - - opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId()); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - - - case X86Inst::kEncodingVexRmvi: { - const uint32_t isign4 = isign3 + (o3.getOp() << 9); - imVal = static_cast(o3).getInt64(); - imLen = 1; - - if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId()); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - if (isign4 == ENC_OPS4(Reg, Mem, Reg, Imm)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId()); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - } - - case X86Inst::kEncodingVexMovdMovq: - if (isign3 == ENC_OPS2(Reg, Reg)) { - if (X86Reg::isGp(o0)) { - opCode = commonData->getAltOpCode(); - ADD_REX_W_BY_SIZE(o0.getSize()); - opReg = o1.getId(); - rbReg = o0.getId(); - goto EmitVexEvexR; - } - - if (X86Reg::isGp(o1)) { - ADD_REX_W_BY_SIZE(o1.getSize()); - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - // If this is a 'W' version (movq) then allow also vmovq 'xmm|xmm' form. - if (opCode & X86Inst::kOpCode_EW) { - opCode &= ~(X86Inst::kOpCode_PP_VEXMask | X86Inst::kOpCode_MM_Mask | 0xFF); - opCode |= (X86Inst::kOpCode_PP_F3 | X86Inst::kOpCode_MM_0F | 0x7E); - - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - if (opCode & X86Inst::kOpCode_EW) { - opCode &= ~(X86Inst::kOpCode_PP_VEXMask | X86Inst::kOpCode_MM_Mask | 0xFF); - opCode |= (X86Inst::kOpCode_PP_F3 | X86Inst::kOpCode_MM_0F | 0x7E); - } - - opReg = o0.getId(); - rmRel = &o1; - goto EmitVexEvexM; - } - - // The following instruction uses the secondary opcode. - opCode = commonData->getAltOpCode(); - - if (isign3 == ENC_OPS2(Mem, Reg)) { - if (opCode & X86Inst::kOpCode_EW) { - opCode &= ~(X86Inst::kOpCode_PP_VEXMask | X86Inst::kOpCode_MM_Mask | 0xFF); - opCode |= (X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_MM_0F | 0xD6); - } - - opReg = o1.getId(); - rmRel = &o0; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRmMr_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRmMr: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitVexEvexM; - } - - // The following instruction uses the secondary opcode. - opCode &= X86Inst::kOpCode_LL_Mask; - opCode |= commonData->getAltOpCode(); - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opReg = o1.getId(); - rmRel = &o0; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRvmRmv: - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId()); - rbReg = o1.getId(); - - if (!(options & X86Inst::kOptionModMR)) - goto EmitVexEvexR; - - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - - ADD_VEX_W(true); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId()); - rmRel = &o1; - goto EmitVexEvexM; - } - - if (isign3 == ENC_OPS3(Reg, Reg, Mem)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - - ADD_VEX_W(true); - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRvmRmi_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRvmRmi: - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Reg, Mem)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - goto EmitVexEvexM; - } - - // The following instructions use the secondary opcode. - opCode &= X86Inst::kOpCode_LL_Mask; - opCode |= commonData->getAltOpCode(); - - imVal = static_cast(o2).getInt64(); - imLen = 1; - - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Imm)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRvmRmvRmi: - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId()); - rbReg = o1.getId(); - - if (!(options & X86Inst::kOptionModMR)) - goto EmitVexEvexR; - - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - - ADD_VEX_W(true); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId()); - rmRel = &o1; - - goto EmitVexEvexM; - } - - if (isign3 == ENC_OPS3(Reg, Reg, Mem)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - - ADD_VEX_W(true); - goto EmitVexEvexM; - } - - // The following instructions use the secondary opcode. - opCode = commonData->getAltOpCode(); - - imVal = static_cast(o2).getInt64(); - imLen = 1; - - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - opReg = o0.getId(); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Imm)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRvmMr: - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Reg, Mem)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - goto EmitVexEvexM; - } - - // The following instructions use the secondary opcode. - opCode = commonData->getAltOpCode(); - - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = o1.getId(); - rbReg = o0.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opReg = o1.getId(); - rmRel = &o0; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRvmMvr_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRvmMvr: - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Reg, Mem)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - goto EmitVexEvexM; - } - - // The following instruction uses the secondary opcode. - opCode &= X86Inst::kOpCode_LL_Mask; - opCode |= commonData->getAltOpCode(); - - if (isign3 == ENC_OPS3(Mem, Reg, Reg)) { - opReg = x86PackRegAndVvvvv(o2.getId(), o1.getId()); - rmRel = &o0; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRvmVmi_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRvmVmi: - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Reg, Mem)) { - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - goto EmitVexEvexM; - } - - // The following instruction uses the secondary opcode. - opCode &= X86Inst::kOpCode_LL_Mask; - opCode |= commonData->getAltOpCode(); - opReg = x86ExtractO(opCode); - - imVal = static_cast(o2).getInt64(); - imLen = 1; - - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - opReg = x86PackRegAndVvvvv(opReg, o0.getId()); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Imm)) { - opReg = x86PackRegAndVvvvv(opReg, o0.getId()); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexVm_Wx: - ADD_REX_W(X86Reg::isGpq(o0) | X86Reg::isGpq(o1)); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexVm: - if (isign3 == ENC_OPS2(Reg, Reg)) { - opReg = x86PackRegAndVvvvv(opReg, o0.getId()); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = x86PackRegAndVvvvv(opReg, o0.getId()); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexEvexVmi_Lx: - if (isign3 == ENC_OPS3(Reg, Mem, Imm)) - opCode |= X86Inst::kOpCode_MM_ForceEvex; - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexVmi_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexVmi: - imVal = static_cast(o2).getInt64(); - imLen = 1; - - if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - opReg = x86PackRegAndVvvvv(opReg, o0.getId()); - rbReg = o1.getId(); - goto EmitVexEvexR; - } - - if (isign3 == ENC_OPS3(Reg, Mem, Imm)) { - opReg = x86PackRegAndVvvvv(opReg, o0.getId()); - rmRel = &o1; - goto EmitVexEvexM; - } - break; - - case X86Inst::kEncodingVexRvrmRvmr_Lx: - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingVexRvrmRvmr: { - const uint32_t isign4 = isign3 + (o3.getOp() << 9); - - if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { - imVal = o3.getId() << 4; - imLen = 1; - - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - - goto EmitVexEvexR; - } - - if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) { - imVal = o2.getId() << 4; - imLen = 1; - - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o3; - - ADD_VEX_W(true); - goto EmitVexEvexM; - } - - if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) { - imVal = o3.getId() << 4; - imLen = 1; - - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - - goto EmitVexEvexM; - } - break; - } - - case X86Inst::kEncodingVexRvrmiRvmri_Lx: { - if (!(options & CodeEmitter::kOptionOp4Op5Used) || !_op4.isImm()) - goto InvalidInstruction; - - const uint32_t isign4 = isign3 + (o3.getOp() << 9); - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize() | o2.getSize() | o3.getSize()); - - imVal = static_cast(_op4).getUInt8() & 0x0F; - imLen = 1; - - if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { - imVal |= o3.getId() << 4; - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - - goto EmitVexEvexR; - } - - if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) { - imVal |= o2.getId() << 4; - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o3; - - ADD_VEX_W(true); - goto EmitVexEvexM; - } - - if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) { - imVal |= o3.getId() << 4; - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - - goto EmitVexEvexM; - } - break; - } - - case X86Inst::kEncodingVexMovssMovsd: - if (isign3 == ENC_OPS3(Reg, Reg, Reg)) { - goto CaseVexRvm_R; - } - - if (isign3 == ENC_OPS2(Reg, Mem)) { - opReg = o0.getId(); - rmRel = &o1; - goto EmitVexEvexM; - } - - if (isign3 == ENC_OPS2(Mem, Reg)) { - opCode = commonData->getAltOpCode(); - opReg = o1.getId(); - rmRel = &o0; - goto EmitVexEvexM; - } - break; - - // ------------------------------------------------------------------------ - // [FMA4] - // ------------------------------------------------------------------------ - - case X86Inst::kEncodingFma4_Lx: - // It's fine to just check the first operand, second is just for sanity. - opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize()); - ASMJIT_FALLTHROUGH; - - case X86Inst::kEncodingFma4: { - const uint32_t isign4 = isign3 + (o3.getOp() << 9); - - if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { - imVal = o3.getId() << 4; - imLen = 1; - - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rbReg = o2.getId(); - - goto EmitVexEvexR; - } - - if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) { - imVal = o2.getId() << 4; - imLen = 1; - - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o3; - - ADD_VEX_W(true); - goto EmitVexEvexM; - } - - if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) { - imVal = o3.getId() << 4; - imLen = 1; - - opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId()); - rmRel = &o2; - - goto EmitVexEvexM; - } - break; - } - } - goto InvalidInstruction; - - // -------------------------------------------------------------------------- - // [Emit - X86] - // -------------------------------------------------------------------------- - -EmitX86OpMovAbs: - imLen = getGpSize(); - - // Segment-override prefix. - if (rmRel->as().hasSegment()) - EMIT_BYTE(x86SegmentPrefix[rmRel->as().getSegmentId()]); - -EmitX86Op: - // Emit mandatory instruction prefix. - EMIT_PP(opCode); - - // Emit REX prefix (64-bit only). - { - uint32_t rex = x86ExtractREX(opCode, options); - if (rex) { - if (options & X86Inst::_kOptionInvalidRex) - goto InvalidRexPrefix; - EMIT_BYTE(rex | kX86ByteRex); - } - } - - // Emit instruction opcodes. - EMIT_MM_OP(opCode); - - if (imLen != 0) - goto EmitImm; - else - goto EmitDone; - -EmitX86OpReg: - // Emit mandatory instruction prefix. - EMIT_PP(opCode); - - // Emit REX prefix (64-bit only). - { - uint32_t rex = x86ExtractREX(opCode, options) | - (opReg >> 3); // Rex.B (0x01). - if (rex) { - EMIT_BYTE(rex | kX86ByteRex); - if (options & X86Inst::_kOptionInvalidRex) - goto InvalidRexPrefix; - opReg &= 0x7; - } - } - - // Emit instruction opcodes. - opCode += opReg; - EMIT_MM_OP(opCode); - - if (imLen != 0) - goto EmitImm; - else - goto EmitDone; - -EmitX86OpImplicitMem: - // NOTE: Don't change the emit order here, it's compatible with KeyStone/LLVM. - rmInfo = x86MemInfo[rmRel->as().getBaseIndexType()]; - if (ASMJIT_UNLIKELY(rmRel->as().hasOffset() || (rmInfo & kX86MemInfo_Index))) - goto InvalidInstruction; - - // Emit mandatory instruction prefix. - EMIT_PP(opCode); - - // Emit REX prefix (64-bit only). - { - uint32_t rex = x86ExtractREX(opCode, options); - if (rex) { - if (options & X86Inst::_kOptionInvalidRex) - goto InvalidRexPrefix; - EMIT_BYTE(rex | kX86ByteRex); - } - } - - // Segment-override prefix. - if (rmRel->as().hasSegment()) - EMIT_BYTE(x86SegmentPrefix[rmRel->as().getSegmentId()]); - - // Address-override prefix. - if (rmInfo & _getAddressOverrideMask()) - EMIT_BYTE(0x67); - - // Emit instruction opcodes. - EMIT_MM_OP(opCode); - - if (imLen != 0) - goto EmitImm; - else - goto EmitDone; - -EmitX86R: - // Mandatory instruction prefix. - EMIT_PP(opCode); - - // Rex prefix (64-bit only). - { - uint32_t rex = x86ExtractREX(opCode, options) | - ((opReg & 0x08) >> 1) | // REX.R (0x04). - ((rbReg ) >> 3) ; // REX.B (0x01). - if (rex) { - if (options & X86Inst::_kOptionInvalidRex) - goto InvalidRexPrefix; - EMIT_BYTE(rex | kX86ByteRex); - opReg &= 0x07; - rbReg &= 0x07; - } - } - - // Instruction opcodes. - EMIT_MM_OP(opCode); - // ModR. - EMIT_BYTE(x86EncodeMod(3, opReg, rbReg)); - - if (imLen != 0) - goto EmitImm; - else - goto EmitDone; - -EmitX86M: - ASMJIT_ASSERT(rmRel != nullptr); - ASMJIT_ASSERT(rmRel->getOp() == Operand::kOpMem); - rmInfo = x86MemInfo[rmRel->as().getBaseIndexType()]; - - // GP instructions have never compressed displacement specified. - ASMJIT_ASSERT((opCode & X86Inst::kOpCode_CDSHL_Mask) == 0); - - // Segment-override prefix. - if (rmRel->as().hasSegment()) - EMIT_BYTE(x86SegmentPrefix[rmRel->as().getSegmentId()]); - - // Address-override prefix. - if (rmInfo & _getAddressOverrideMask()) - EMIT_BYTE(0x67); - - // Mandatory instruction prefix. - EMIT_PP(opCode); - - rbReg = rmRel->as().getBaseId(); - rxReg = rmRel->as().getIndexId(); - - // REX prefix (64-bit only). - { - uint32_t rex; - - rex = (rbReg >> 3) & 0x01; // REX.B (0x01). - rex |= (rxReg >> 2) & 0x02; // REX.X (0x02). - rex |= (opReg >> 1) & 0x04; // REX.R (0x04). - - rex &= rmInfo; - rex |= x86ExtractREX(opCode, options); - - if (rex) { - if (options & X86Inst::_kOptionInvalidRex) - goto InvalidRexPrefix; - EMIT_BYTE(rex | kX86ByteRex); - opReg &= 0x07; - } - } - - // Instruction opcodes. - EMIT_MM_OP(opCode); - // ... Fall through ... - - // -------------------------------------------------------------------------- - // [Emit - MOD/SIB] - // -------------------------------------------------------------------------- - -EmitModSib: - if (!(rmInfo & (kX86MemInfo_Index | kX86MemInfo_67H_X86))) { - // ==========|> [BASE + DISP8|DISP32]. - if (rmInfo & kX86MemInfo_BaseGp) { - rbReg &= 0x7; - relOffset = rmRel->as().getOffsetLo32(); - - uint32_t mod = x86EncodeMod(0, opReg, rbReg); - if (rbReg == X86Gp::kIdSp) { - // [XSP|R12]. - if (relOffset == 0) { - EMIT_BYTE(mod); - EMIT_BYTE(x86EncodeSib(0, 4, 4)); - } - // [XSP|R12 + DISP8|DISP32]. - else { - uint32_t cdShift = (opCode & X86Inst::kOpCode_CDSHL_Mask) >> X86Inst::kOpCode_CDSHL_Shift; - int32_t cdOffset = relOffset >> cdShift; - - if (Utils::isInt8(cdOffset) && relOffset == (cdOffset << cdShift)) { - EMIT_BYTE(mod + 0x40); // <- MOD(1, opReg, rbReg). - EMIT_BYTE(x86EncodeSib(0, 4, 4)); - EMIT_BYTE(cdOffset & 0xFF); - } - else { - EMIT_BYTE(mod + 0x80); // <- MOD(2, opReg, rbReg). - EMIT_BYTE(x86EncodeSib(0, 4, 4)); - EMIT_32(relOffset); - } - } - } - else if (rbReg != X86Gp::kIdBp && relOffset == 0) { - // [BASE]. - EMIT_BYTE(mod); - } - else { - // [BASE + DISP8|DISP32]. - uint32_t cdShift = (opCode & X86Inst::kOpCode_CDSHL_Mask) >> X86Inst::kOpCode_CDSHL_Shift; - int32_t cdOffset = relOffset >> cdShift; - - if (Utils::isInt8(cdOffset) && relOffset == (cdOffset << cdShift)) { - EMIT_BYTE(mod + 0x40); - EMIT_BYTE(cdOffset & 0xFF); - } - else { - EMIT_BYTE(mod + 0x80); - EMIT_32(relOffset); - } - } - } - // ==========|> [ABSOLUTE | DISP32]. - else if (!(rmInfo & (kX86MemInfo_BaseLabel | kX86MemInfo_BaseRip))) { - if (is32Bit()) { - relOffset = rmRel->as().getOffsetLo32(); - EMIT_BYTE(x86EncodeMod(0, opReg, 5)); - EMIT_32(relOffset); - } - else { - uint64_t baseAddress = getCodeInfo().getBaseAddress(); - relOffset = rmRel->as().getOffsetLo32(); - - // Prefer absolute addressing mode if FS|GS segment override is present. - bool absoluteValid = rmRel->as().getOffsetHi32() == (relOffset >> 31); - bool preferAbsolute = (rmRel->as().getSegmentId() >= X86Seg::kIdFs) || rmRel->as().isAbs(); - - // If we know the base address and the memory operand points to an - // absolute address it's possible to calculate REL32 that can be - // be used as [RIP+REL32] in 64-bit mode. - if (baseAddress != Globals::kNoBaseAddress && !preferAbsolute) { - const uint32_t kModRel32Size = 5; - uint64_t rip64 = baseAddress + - static_cast((uintptr_t)(cursor - _bufferData)) + imLen + kModRel32Size; - - uint64_t rel64 = static_cast(rmRel->as().getOffset()) - rip64; - if (Utils::isInt32(static_cast(rel64))) { - EMIT_BYTE(x86EncodeMod(0, opReg, 5)); - EMIT_32(static_cast(rel64 & 0xFFFFFFFFU)); - if (imLen != 0) - goto EmitImm; - else - goto EmitDone; - } - } - - if (ASMJIT_UNLIKELY(!absoluteValid)) - goto InvalidAddress64Bit; - - EMIT_BYTE(x86EncodeMod(0, opReg, 4)); - EMIT_BYTE(x86EncodeSib(0, 4, 5)); - EMIT_32(relOffset); - } - } - // ==========|> [LABEL|RIP + DISP32] - else { - EMIT_BYTE(x86EncodeMod(0, opReg, 5)); - - if (is32Bit()) { -EmitModSib_LabelRip_X86: - if (ASMJIT_UNLIKELY(_code->_relocations.willGrow(&_code->_baseHeap) != kErrorOk)) - goto NoHeapMemory; - - relOffset = rmRel->as().getOffsetLo32(); - if (rmInfo & kX86MemInfo_BaseLabel) { - // [LABEL->ABS]. - label = _code->getLabelEntry(rmRel->as().getBaseId()); - if (!label) goto InvalidLabel; - - err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, 4); - if (ASMJIT_UNLIKELY(err)) goto Failed; - - re->_sourceSectionId = _section->getId(); - re->_sourceOffset = static_cast((uintptr_t)(cursor - _bufferData)); - re->_data = static_cast(relOffset); - - if (label->isBound()) { - // Bound label. - re->_data += static_cast(label->getOffset()); - EMIT_32(0); - } - else { - // Non-bound label. - relOffset = -4 - imLen; - relSize = 4; - goto EmitRel; - } - } - else { - // [RIP->ABS]. - err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, 4); - if (ASMJIT_UNLIKELY(err)) goto Failed; - - re->_sourceSectionId = _section->getId(); - re->_sourceOffset = static_cast((uintptr_t)(cursor - _bufferData)); - re->_data = re->_sourceOffset + static_cast(static_cast(relOffset)); - EMIT_32(0); - } - } - else { - relOffset = rmRel->as().getOffsetLo32(); - if (rmInfo & kX86MemInfo_BaseLabel) { - // [RIP]. - label = _code->getLabelEntry(rmRel->as().getBaseId()); - if (!label) goto InvalidLabel; - - relOffset -= (4 + imLen); - if (label->isBound()) { - // Bound label. - relOffset += label->getOffset() - static_cast((intptr_t)(cursor - _bufferData)); - EMIT_32(static_cast(relOffset)); - } - else { - // Non-bound label. - relSize = 4; - goto EmitRel; - } - } - else { - // [RIP]. - EMIT_32(static_cast(relOffset)); - } - } - } - } - else if (!(rmInfo & kX86MemInfo_67H_X86)) { - // ESP|RSP can't be used as INDEX in pure SIB mode, however, VSIB mode - // allows XMM4|YMM4|ZMM4 (that's why the check is before the label). - if (ASMJIT_UNLIKELY(rxReg == X86Gp::kIdSp)) goto InvalidAddressIndex; - -EmitModVSib: - rxReg &= 0x7; - - // ==========|> [BASE + INDEX + DISP8|DISP32]. - if (rmInfo & kX86MemInfo_BaseGp) { - rbReg &= 0x7; - relOffset = rmRel->as().getOffsetLo32(); - - uint32_t mod = x86EncodeMod(0, opReg, 4); - uint32_t sib = x86EncodeSib(rmRel->as().getShift(), rxReg, rbReg); - - if (relOffset == 0 && rbReg != X86Gp::kIdBp) { - // [BASE + INDEX << SHIFT]. - EMIT_BYTE(mod); - EMIT_BYTE(sib); - } - else { - uint32_t cdShift = (opCode & X86Inst::kOpCode_CDSHL_Mask) >> X86Inst::kOpCode_CDSHL_Shift; - int32_t cdOffset = relOffset >> cdShift; - - if (Utils::isInt8(cdOffset) && relOffset == (cdOffset << cdShift)) { - // [BASE + INDEX << SHIFT + DISP8]. - EMIT_BYTE(mod + 0x40); // <- MOD(1, opReg, 4). - EMIT_BYTE(sib); - EMIT_BYTE(cdOffset); - } - else { - // [BASE + INDEX << SHIFT + DISP32]. - EMIT_BYTE(mod + 0x80); // <- MOD(2, opReg, 4). - EMIT_BYTE(sib); - EMIT_32(relOffset); - } - } - } - // ==========|> [INDEX + DISP32]. - else if (!(rmInfo & (kX86MemInfo_BaseLabel | kX86MemInfo_BaseRip))) { - // [INDEX << SHIFT + DISP32]. - EMIT_BYTE(x86EncodeMod(0, opReg, 4)); - EMIT_BYTE(x86EncodeSib(rmRel->as().getShift(), rxReg, 5)); - - relOffset = rmRel->as().getOffsetLo32(); - EMIT_32(relOffset); - } - // ==========|> [LABEL|RIP + INDEX + DISP32]. - else { - if (is32Bit()) { - EMIT_BYTE(x86EncodeMod(0, opReg, 4)); - EMIT_BYTE(x86EncodeSib(rmRel->as().getShift(), rxReg, 5)); - goto EmitModSib_LabelRip_X86; - } - else { - // NOTE: This also handles VSIB+RIP, which is not allowed in 64-bit mode. - goto InvalidAddress; - } - } - } - else { - // 16-bit address mode (32-bit mode with 67 override prefix). - relOffset = (static_cast(rmRel->as().getOffsetLo32()) << 16) >> 16; - - // NOTE: 16-bit addresses don't use SIB byte and their encoding differs. We - // use a table-based approach to calculate the proper MOD byte as it's easier. - // Also, not all BASE [+ INDEX] combinations are supported in 16-bit mode, so - // this may fail. - const uint32_t kBaseGpIdx = (kX86MemInfo_BaseGp | kX86MemInfo_Index); - - if (rmInfo & kBaseGpIdx) { - // ==========|> [BASE + INDEX + DISP16]. - uint32_t mod; - - rbReg &= 0x7; - rxReg &= 0x7; - - if ((rmInfo & kBaseGpIdx) == kBaseGpIdx) { - uint32_t shf = rmRel->as().getShift(); - if (ASMJIT_UNLIKELY(shf != 0)) - goto InvalidAddress; - mod = x86Mod16BaseIndexTable[(rbReg << 3) + rxReg]; - } - else { - if (rmInfo & kX86MemInfo_Index) - rbReg = rxReg; - mod = x86Mod16BaseTable[rbReg]; - } - - if (ASMJIT_UNLIKELY(mod == 0xFF)) - goto InvalidAddress; - - mod += opReg << 3; - if (relOffset == 0 && mod != 0x06) { - EMIT_BYTE(mod); - } - else if (Utils::isInt8(relOffset)) { - EMIT_BYTE(mod + 0x40); - EMIT_BYTE(relOffset); - } - else { - EMIT_BYTE(mod + 0x80); - EMIT_16(relOffset); - } - } - else { - // Not supported in 16-bit addresses. - if (rmInfo & (kX86MemInfo_BaseRip | kX86MemInfo_BaseLabel)) - goto InvalidAddress; - - // ==========|> [DISP16]. - EMIT_BYTE(opReg | 0x06); - EMIT_16(relOffset); - } - } - - if (imLen != 0) - goto EmitImm; - else - goto EmitDone; - - // -------------------------------------------------------------------------- - // [Emit - FPU] - // -------------------------------------------------------------------------- - -EmitFpuOp: - // Mandatory instruction prefix. - EMIT_PP(opCode); - - // FPU instructions consist of two opcodes. - EMIT_BYTE(opCode >> X86Inst::kOpCode_FPU_2B_Shift); - EMIT_BYTE(opCode); - goto EmitDone; - - // -------------------------------------------------------------------------- - // [Emit - VEX / EVEX] - // -------------------------------------------------------------------------- - -EmitVexEvexOp: - { - // These don't use immediate. - ASMJIT_ASSERT(imLen == 0); - - // Only 'vzeroall' and 'vzeroupper' instructions use this encoding, they - // don't define 'W' to be '1' so we can just check the 'mmmmm' field. Both - // functions can encode by using VEV2 prefix so VEV3 is basically only used - // when forced from outside. - ASMJIT_ASSERT((opCode & X86Inst::kOpCode_W) == 0); - - uint32_t x = ((opCode & X86Inst::kOpCode_MM_Mask ) >> (X86Inst::kOpCode_MM_Shift )) | - ((opCode & X86Inst::kOpCode_LL_Mask ) >> (X86Inst::kOpCode_LL_Shift - 10)) | - ((opCode & X86Inst::kOpCode_PP_VEXMask) >> (X86Inst::kOpCode_PP_Shift - 8)) | - ((options & X86Inst::kOptionVex3 ) >> (X86Inst::kOpCode_MM_Shift )) ; - if (x & 0x04U) { - x = (x & (0x4 ^ 0xFFFF)) << 8; // [00000000|00000Lpp|0000m0mm|00000000]. - x ^= (kX86ByteVex3) | // [........|00000Lpp|0000m0mm|__VEX3__]. - (0x07U << 13) | // [........|00000Lpp|1110m0mm|__VEX3__]. - (0x0FU << 19) | // [........|01111Lpp|1110m0mm|__VEX3__]. - (opCode << 24) ; // [_OPCODE_|01111Lpp|1110m0mm|__VEX3__]. - - EMIT_32(x); - goto EmitDone; - } - else { - x = ((x >> 8) ^ x) ^ 0xF9; - EMIT_BYTE(kX86ByteVex2); - EMIT_BYTE(x); - EMIT_BYTE(opCode); - goto EmitDone; - } - } - -EmitVexEvexR: - { - // VEX instructions use only 0-1 BYTE immediate. - ASMJIT_ASSERT(imLen <= 1); - - // Construct `x` - a complete EVEX|VEX prefix. - uint32_t x = ((opReg << 4) & 0xF980U) | // [........|........|Vvvvv..R|R.......]. - ((rbReg << 2) & 0x0060U) | // [........|........|........|.BB.....]. - (x86ExtractLLMM(opCode, options)) | // [........|.LL.....|Vvvvv..R|RBBmmmmm]. - (_extraReg.getId() << 16); // [........|.LL..aaa|Vvvvv..R|RBBmmmmm]. - opReg &= 0x7; - - // Mark invalid VEX (force EVEX) case: // [@.......|.LL..aaa|Vvvvv..R|RBBmmmmm]. - x |= (~commonData->getFlags() & X86Inst::kFlagVex) << (31 - Utils::firstBitOfT()); - - // Handle AVX512 options by a single branch. - const uint32_t kAvx512Options = X86Inst::kOptionZMask | - X86Inst::kOption1ToX | - X86Inst::kOptionSAE | - X86Inst::kOptionER ; - if (options & kAvx512Options) { - // Memory broadcast without a memory operand is invalid. - if (ASMJIT_UNLIKELY(options & X86Inst::kOption1ToX)) - goto InvalidBroadcast; - - // TODO: {sae} and {er} - x |= options & X86Inst::kOptionZMask; // [@.......|zLL..aaa|Vvvvv..R|RBBmmmmm]. - } - - // Check if EVEX is required by checking bits in `x` : [@.......|xx...xxx|x......x|.x.x....]. - if (x & 0x80C78150U) { - uint32_t y = ((x << 4) & 0x00080000U) | // [@.......|....V...|........|........]. - ((x >> 4) & 0x00000010U) ; // [@.......|....V...|........|...R....]. - x = (x & 0x00FF78E3U) | y; // [........|zLL.Vaaa|0vvvv000|RBBR00mm]. - x = (x << 8) | // [zLL.Vaaa|0vvvv000|RBBR00mm|00000000]. - ((opCode >> kSHR_W_PP) & 0x00830000U) | // [zLL.Vaaa|Wvvvv0pp|RBBR00mm|00000000]. - ((opCode >> kSHR_W_EW) & 0x00800000U) ; // [zLL.Vaaa|Wvvvv0pp|RBBR00mm|00000000] (added EVEX.W). - // _ ____ ____ - x ^= 0x087CF000U | kX86ByteEvex; // [zLL.Vaaa|Wvvvv1pp|RBBR00mm|01100010]. - - EMIT_32(x); - EMIT_BYTE(opCode); - - rbReg &= 0x7; - EMIT_BYTE(x86EncodeMod(3, opReg, rbReg)); - - if (imLen == 0) goto EmitDone; - EMIT_BYTE(imVal & 0xFF); - goto EmitDone; - } - - // Not EVEX, prepare `x` for VEX2 or VEX3: x = [........|00L00000|0vvvv000|R0B0mmmm]. - x |= ((opCode >> (kSHR_W_PP + 8)) & 0x8300U) | // [00000000|00L00000|Wvvvv0pp|R0B0mmmm]. - ((x >> 11 ) & 0x0400U) ; // [00000000|00L00000|WvvvvLpp|R0B0mmmm]. - - // Check if VEX3 is required / forced: [........|........|x.......|..x..x..]. - if (x & 0x0008024U) { - uint32_t xorMsk = x86VEXPrefix[x & 0xF] | (opCode << 24); - - // Clear 'FORCE-VEX3' bit and all high bits. - x = (x & (0x4 ^ 0xFFFF)) << 8; // [00000000|WvvvvLpp|R0B0m0mm|00000000]. - // ____ _ _ - x ^= xorMsk; // [_OPCODE_|WvvvvLpp|R1Bmmmmm|VEX3|XOP]. - EMIT_32(x); - - rbReg &= 0x7; - EMIT_BYTE(x86EncodeMod(3, opReg, rbReg)); - - if (imLen == 0) goto EmitDone; - EMIT_BYTE(imVal & 0xFF); - goto EmitDone; - } - else { - // 'mmmmm' must be '00001'. - ASMJIT_ASSERT((x & 0x1F) == 0x01); - - x = ((x >> 8) ^ x) ^ 0xF9; - EMIT_BYTE(kX86ByteVex2); - EMIT_BYTE(x); - EMIT_BYTE(opCode); - - rbReg &= 0x7; - EMIT_BYTE(x86EncodeMod(3, opReg, rbReg)); - - if (imLen == 0) goto EmitDone; - EMIT_BYTE(imVal & 0xFF); - goto EmitDone; - } - } - -EmitVexEvexM: - ASMJIT_ASSERT(rmRel != nullptr); - ASMJIT_ASSERT(rmRel->getOp() == Operand::kOpMem); - rmInfo = x86MemInfo[rmRel->as().getBaseIndexType()]; - - // Segment-override prefix. - if (rmRel->as().hasSegment()) - EMIT_BYTE(x86SegmentPrefix[rmRel->as().getSegmentId()]); - - // Address-override prefix. - if (rmInfo & _getAddressOverrideMask()) - EMIT_BYTE(0x67); - - rbReg = rmRel->as().hasBaseReg() ? rmRel->as().getBaseId() : uint32_t(0); - rxReg = rmRel->as().hasIndexReg() ? rmRel->as().getIndexId() : uint32_t(0); - - { - // VEX instructions use only 0-1 BYTE immediate. - ASMJIT_ASSERT(imLen <= 1); - - // Construct `x` - a complete EVEX|VEX prefix. - uint32_t x = ((opReg << 4 ) & 0x0000F980U) | // [........|........|Vvvvv..R|R.......]. - ((rxReg << 3 ) & 0x00000040U) | // [........|........|........|.X......]. - ((rxReg << 15) & 0x00080000U) | // [........|....X...|........|........]. - ((rbReg << 2 ) & 0x00000020U) | // [........|........|........|..B.....]. - (x86ExtractLLMM(opCode, options)) | // [........|.LL.X...|Vvvvv..R|RXBmmmmm]. - (_extraReg.getId() << 16) ; // [........|.LL.Xaaa|Vvvvv..R|RXBmmmmm]. - opReg &= 0x07U; - - // Mark invalid VEX (force EVEX) case: // [@.......|.LL.Xaaa|Vvvvv..R|RXBmmmmm]. - x |= (~commonData->getFlags() & X86Inst::kFlagVex) << (31 - Utils::firstBitOfT()); - - // Handle AVX512 options by a single branch. - const uint32_t kAvx512Options = X86Inst::kOption1ToX | - X86Inst::kOptionZMask | - X86Inst::kOptionSAE | - X86Inst::kOptionER ; - if (options & kAvx512Options) { - // {er} and {sae} are both invalid if memory operand is used. - if (ASMJIT_UNLIKELY(options & (X86Inst::kOptionSAE | X86Inst::kOptionER))) - goto InvalidEROrSAE; - - x |= options & (X86Inst::kOption1ToX | // [@.......|.LLbXaaa|Vvvvv..R|RXBmmmmm]. - X86Inst::kOptionZMask); // [@.......|zLLbXaaa|Vvvvv..R|RXBmmmmm]. - } - - // Check if EVEX is required by checking bits in `x` : [@.......|xx.xxxxx|x......x|...x....]. - if (x & 0x80DF8110U) { - uint32_t y = ((x << 4) & 0x00080000U) | // [@.......|....V...|........|........]. - ((x >> 4) & 0x00000010U) ; // [@.......|....V...|........|...R....]. - x = (x & 0x00FF78E3U) | y; // [........|zLLbVaaa|0vvvv000|RXBR00mm]. - x = (x << 8) | // [zLLbVaaa|0vvvv000|RBBR00mm|00000000]. - ((opCode >> kSHR_W_PP) & 0x00830000U) | // [zLLbVaaa|Wvvvv0pp|RBBR00mm|00000000]. - ((opCode >> kSHR_W_EW) & 0x00800000U) ; // [zLLbVaaa|Wvvvv0pp|RBBR00mm|00000000] (added EVEX.W). - // _ ____ ____ - x ^= 0x087CF000U | kX86ByteEvex; // [zLLbVaaa|Wvvvv1pp|RBBR00mm|01100010]. - - EMIT_32(x); - EMIT_BYTE(opCode); - - if (opCode & 0x10000000U) { - // Broadcast, change the compressed displacement scale to either x4 (SHL 2) or x8 (SHL 3) - // depending on instruction's W. If 'W' is 1 'SHL' must be 3, otherwise it must be 2. - opCode &=~static_cast(X86Inst::kOpCode_CDSHL_Mask); - opCode |= ((x & 0x00800000U) ? 3 : 2) << X86Inst::kOpCode_CDSHL_Shift; - } - else { - // Add the compressed displacement 'SHF' to the opcode based on 'TTWLL'. - uint32_t TTWLL = ((opCode >> (X86Inst::kOpCode_CDTT_Shift - 3)) & 0x18) + - ((opCode >> (X86Inst::kOpCode_W_Shift - 2)) & 0x04) + - ((x >> 29) & 0x3); - opCode += x86CDisp8SHL[TTWLL]; - } - } - else { - // Not EVEX, prepare `x` for VEX2 or VEX3: x = [........|00L00000|0vvvv000|RXB0mmmm]. - x |= ((opCode >> (kSHR_W_PP + 8)) & 0x8300U) | // [00000000|00L00000|Wvvvv0pp|RXB0mmmm]. - ((x >> 11 ) & 0x0400U) ; // [00000000|00L00000|WvvvvLpp|RXB0mmmm]. - - // Clear a possible CDisp specified by EVEX. - opCode &= ~X86Inst::kOpCode_CDSHL_Mask; - - // Check if VEX3 is required / forced: [........|........|x.......|.xx..x..]. - if (x & 0x0008064U) { - uint32_t xorMsk = x86VEXPrefix[x & 0xF] | (opCode << 24); - - // Clear 'FORCE-VEX3' bit and all high bits. - x = (x & (0x4 ^ 0xFFFF)) << 8; // [00000000|WvvvvLpp|RXB0m0mm|00000000]. - // ____ ___ - x ^= xorMsk; // [_OPCODE_|WvvvvLpp|RXBmmmmm|VEX3_XOP]. - EMIT_32(x); - } - else { - // 'mmmmm' must be '00001'. - ASMJIT_ASSERT((x & 0x1F) == 0x01); - - x = ((x >> 8) ^ x) ^ 0xF9; - EMIT_BYTE(kX86ByteVex2); - EMIT_BYTE(x); - EMIT_BYTE(opCode); - } - } - } - - // MOD|SIB address. - if (!commonData->hasFlag(X86Inst::kFlagVsib)) - goto EmitModSib; - - // MOD|VSIB address without INDEX is invalid. - if (rmInfo & kX86MemInfo_Index) - goto EmitModVSib; - goto InvalidInstruction; - - // -------------------------------------------------------------------------- - // [Emit - Jmp/Jcc/Call] - // -------------------------------------------------------------------------- - - // TODO: Should be adjusted after the support for multiple sections feature is added. -EmitJmpCall: - { - // Emit REX prefix if asked for (64-bit only). - uint32_t rex = x86ExtractREX(opCode, options); - if (rex) { - if (options & X86Inst::_kOptionInvalidRex) - goto InvalidRexPrefix; - EMIT_BYTE(rex | kX86ByteRex); - } - - uint64_t ip = static_cast((intptr_t)(cursor - _bufferData)); - uint32_t rel32 = 0; - uint32_t opCode8 = commonData->getAltOpCode(); - - uint32_t inst8Size = 1 + 1; // OPCODE + REL8 . - uint32_t inst32Size = 1 + 4; // [PREFIX] OPCODE + REL32. - - // Jcc instructions with 32-bit displacement use 0x0F prefix, - // other instructions don't. No other prefixes are used by X86. - ASMJIT_ASSERT((opCode8 & X86Inst::kOpCode_MM_Mask) == 0); - ASMJIT_ASSERT((opCode & X86Inst::kOpCode_MM_Mask) == 0 || - (opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F); - - // Only one of these should be used at the same time. - inst32Size += static_cast(opReg != 0); - inst32Size += static_cast((opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F); - - if (rmRel->isLabel()) { - label = _code->getLabelEntry(rmRel->as