diff --git a/CMakeLists.txt b/CMakeLists.txt index 53c34af..03e4645 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ project(pslang CXX) add_subdirectory(libs/type) add_subdirectory(libs/ast) add_subdirectory(libs/parser) +add_subdirectory(libs/jit) add_subdirectory(libs/interpreter) add_subdirectory(apps/interpreter) diff --git a/apps/interpreter/source/main.cpp b/apps/interpreter/source/main.cpp index 393fcce..279db92 100644 --- a/apps/interpreter/source/main.cpp +++ b/apps/interpreter/source/main.cpp @@ -46,6 +46,7 @@ int main(int argc, char ** argv) std::cout << " -t, --trace Trace each line of execution\n"; std::cout << " -d, --dump Dump all variables after processing all files\n"; std::cout << " -p, --print Print the AST after parsing each file\n"; + std::cout << " -j, --jit Just-in-time compile & execute the code instead of interpreting\n"; return 0; } @@ -55,6 +56,7 @@ int main(int argc, char ** argv) bool dump = false; bool dump_ast = false; + bool jit = false; std::vector filenames; std::vector parsed; @@ -79,6 +81,13 @@ int main(int argc, char ** argv) continue; } + if (std::strcmp(argv[arg], "-j") == 0 || std::strcmp(argv[arg], "--jit") == 0) + { + std::cerr << "Warning: JIT-compilation not supported yet" << std::endl; + jit = true; + continue; + } + try { filenames.push_back(argv[arg]); diff --git a/libs/jit/CMakeLists.txt b/libs/jit/CMakeLists.txt new file mode 100644 index 0000000..fe266bf --- /dev/null +++ b/libs/jit/CMakeLists.txt @@ -0,0 +1,6 @@ +file(GLOB_RECURSE PSLANG_JIT_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp") +file(GLOB_RECURSE PSLANG_JIT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp") + +add_library(pslang-jit STATIC ${PSLANG_JIT_HEADERS} ${PSLANG_JIT_SOURCES}) +target_include_directories(pslang-jit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(pslang-jit PUBLIC pslang-ast) diff --git a/libs/jit/include/pslang/jit/abi.hpp b/libs/jit/include/pslang/jit/abi.hpp new file mode 100644 index 0000000..9f3c098 --- /dev/null +++ b/libs/jit/include/pslang/jit/abi.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace pslang::jit +{ + + enum class abi + { + itanium, + msvc, + arm, + }; + +} diff --git a/libs/jit/include/pslang/jit/blob.hpp b/libs/jit/include/pslang/jit/blob.hpp new file mode 100644 index 0000000..e026e26 --- /dev/null +++ b/libs/jit/include/pslang/jit/blob.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +namespace pslang::jit +{ + + struct blob + { + std::shared_ptr data; + std::size_t size; + + blob() + : data{nullptr} + , size{0} + {} + + blob(std::shared_ptr data, std::size_t size) + : data{std::move(data)} + , size{size} + {} + + blob(blob && other) + : data{std::move(other.data)} + , size{other.size} + { + other.size = 0; + } + + blob & operator = (blob && other) + { + if (this == &other) + return *this; + + data = std::move(other.data); + size = other.size; + other.size = 0; + return *this; + } + }; + +} diff --git a/libs/jit/include/pslang/jit/compiled_module.hpp b/libs/jit/include/pslang/jit/compiled_module.hpp new file mode 100644 index 0000000..c0de14f --- /dev/null +++ b/libs/jit/include/pslang/jit/compiled_module.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#include +#include + +namespace pslang::jit +{ + + struct compiled_module + { + blob memory; + std::unordered_map symbol_table; + std::size_t entry_point; + jit::abi abi; + }; + +} diff --git a/libs/jit/include/pslang/jit/executable.hpp b/libs/jit/include/pslang/jit/executable.hpp new file mode 100644 index 0000000..4f0d372 --- /dev/null +++ b/libs/jit/include/pslang/jit/executable.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace pslang::jit +{ + + compiled_module make_host_executable(compiled_module module); + +} diff --git a/libs/jit/include/pslang/jit/jit.hpp b/libs/jit/include/pslang/jit/jit.hpp new file mode 100644 index 0000000..405bc97 --- /dev/null +++ b/libs/jit/include/pslang/jit/jit.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include +#include + +namespace pslang::jit +{ + + compiled_module compile(ast::statement_list_ptr const & statements, abi abi); + +} diff --git a/libs/jit/source/executable.cpp b/libs/jit/source/executable.cpp new file mode 100644 index 0000000..50a29ae --- /dev/null +++ b/libs/jit/source/executable.cpp @@ -0,0 +1,32 @@ +#include + +#include + +#ifdef __linux__ +#include +#endif + +namespace pslang::jit +{ + + compiled_module make_host_executable(compiled_module module) + { +#ifdef __linux__ + if (module.abi != abi::itanium) + throw std::runtime_error("Abi mismatch"); + + auto ptr = (std::uint8_t *)mmap(nullptr, module.memory.size, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + auto shared_ptr = std::shared_ptr(ptr, [size = module.memory.size](std::uint8_t * ptr){ munmap(ptr, size); }); + + return compiled_module { + .memory = blob(shared_ptr, module.memory.size), + .symbol_table = std::move(module.symbol_table), + .entry_point = module.entry_point, + .abi = module.abi, + }; +#else + throw std::runtime_error("Host-executable modules are not supported for this platform"); +#endif + } + +} diff --git a/libs/jit/source/jit.cpp b/libs/jit/source/jit.cpp new file mode 100644 index 0000000..228feb0 --- /dev/null +++ b/libs/jit/source/jit.cpp @@ -0,0 +1,16 @@ +#include + +namespace pslang::jit +{ + + compiled_module compile(ast::statement_list_ptr const & /* statements */, jit::abi abi) + { + return { + .memory = {}, + .symbol_table = {}, + .entry_point = 0, + .abi = abi, + }; + } + +}