Skip to content
This repository has been archived by the owner on Jan 2, 2023. It is now read-only.

misc: extern functions #7

Merged
merged 2 commits into from
May 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ else ()
endif ()

set_target_properties(MunRuntime PROPERTIES
IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/bin/${MUN_OS}/mun_runtime${CMAKE_SHARED_LIBRARY_SUFFIX}
IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/bin/${MUN_OS}/${CMAKE_SHARED_LIBRARY_PREFIX}mun_runtime${CMAKE_SHARED_LIBRARY_SUFFIX}
)

if (WIN32)
Expand Down
2 changes: 1 addition & 1 deletion external/md5
Submodule md5 updated 2 files
+26 −23 include/md5.h
+20 −10 test/main.cc
37 changes: 37 additions & 0 deletions include/mun/function.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef MUN_FUNCTION_H_
#define MUN_FUNCTION_H_

#include <string>
#include <vector>

#include "mun/runtime_capi.h"
#include "mun/type_info.h"

namespace mun {
/**
* A wrapper around a C function with type information.
*/
struct RuntimeFunction {
/**
* Constructs a `RuntimeFunction` from a generic function pointer and a name.
* \param name The name of the function used when added to the runtime
* \param fn_ptr The function pointer to add
*/
template <typename TRet, typename... TArgs>
baszalmstra marked this conversation as resolved.
Show resolved Hide resolved
RuntimeFunction(std::string_view name, TRet(__cdecl* fn_ptr)(TArgs...))
: name(name),
arg_types({arg_type_info<TArgs>()...}),
ret_type(return_type_info<TRet>()),
fn_ptr(reinterpret_cast<const void*>(fn_ptr)) {}

RuntimeFunction(const RuntimeFunction&) = default;
RuntimeFunction(RuntimeFunction&&) = default;

std::string name;
std::vector<MunTypeInfo const*> arg_types;
std::optional<MunTypeInfo const*> ret_type;
const void* fn_ptr;
};
} // namespace mun

#endif
1 change: 0 additions & 1 deletion include/mun/gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <optional>

#include "mun/error.h"
#include "runtime.h"

namespace mun {
class Runtime;
Expand Down
7 changes: 3 additions & 4 deletions include/mun/invoke_fn.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "mun/invoke_result.h"
#include "mun/marshal.h"
#include "mun/reflection.h"
#include "mun/runtime.h"

namespace mun {
Expand Down Expand Up @@ -80,12 +81,10 @@ InvokeResult<Output, Args...> invoke_fn(Runtime& runtime, std::string_view fn_na
<< std::endl;

return make_error(runtime, fn_name, args...);
;
}

auto fn =
reinterpret_cast<typename Marshal<Output>::type (*)(typename Marshal<Args>::type...)>(
fn_info->fn_ptr);
auto fn = reinterpret_cast<typename Marshal<Output>::type(__cdecl*)(
typename Marshal<Args>::type...)>(const_cast<void*>(fn_info->fn_ptr));
if constexpr (std::is_same_v<Output, void>) {
fn(args...);
return InvokeResult<Output, Args...>(std::monostate{});
Expand Down
87 changes: 31 additions & 56 deletions include/mun/reflection.h
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
#ifndef MUN_REFLECTION_H_
#define MUN_REFLECTION_H_

#include <md5.h>

#include <algorithm>
#include <cstdint>
#include <iterator>
#include <optional>

#include "mun/runtime_capi.h"
#include "mun/struct_ref.h"
#include "mun/type_info.h"

namespace mun {
namespace details {
constexpr MunGuid type_guid(const char* type_name) noexcept {
const auto hash = md5::compute(type_name);
return MunGuid{
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15],
};
}
} // namespace details

constexpr inline bool operator==(const MunGuid& lhs, const MunGuid& rhs) noexcept {
for (auto idx = 0; idx < 16; ++idx) {
if (lhs.b[idx] != rhs.b[idx]) {
Expand All @@ -35,6 +23,24 @@ constexpr inline bool operator!=(const MunGuid& lhs, const MunGuid& rhs) noexcep
return !(lhs == rhs);
}

template <typename T>
struct ArgumentReflection {
static constexpr const char* type_name(const T&) noexcept { return TypeInfo<T>::Type.name; }
static constexpr MunGuid type_guid(const T&) noexcept { return TypeInfo<T>::Type.guid; }
};

template <typename T>
struct ReturnTypeReflection {
static constexpr const char* type_name() noexcept { return TypeInfo<T>::Type.name; }
static constexpr MunGuid type_guid() noexcept { return TypeInfo<T>::Type.guid; }
};

template <>
struct ReturnTypeReflection<void> {
static constexpr const char* type_name() noexcept { return "core::empty"; }
static constexpr MunGuid type_guid() noexcept { return details::type_guid(type_name()); }
};

namespace reflection {
template <typename T, typename U>
constexpr bool equal_types() noexcept {
Expand All @@ -54,6 +60,18 @@ inline std::optional<std::pair<const char*, const char*>> equals_argument_type(

template <typename T>
inline std::optional<std::pair<const char*, const char*>> equals_return_type(
const MunTypeInfo& type_info) noexcept;

} // namespace reflection

} // namespace mun

#include "struct_ref.h"

namespace mun {
namespace reflection {
template <typename T>
std::optional<std::pair<const char*, const char*>> equals_return_type(
const MunTypeInfo& type_info) noexcept {
if (type_info.group == MunTypeGroup::FundamentalTypes) {
if (type_info.guid != ReturnTypeReflection<T>::type_guid()) {
Expand All @@ -66,49 +84,6 @@ inline std::optional<std::pair<const char*, const char*>> equals_return_type(
return std::nullopt;
}
} // namespace reflection

template <typename T>
struct ArgumentReflection;

template <typename T>
struct ReturnTypeReflection;

#define IMPL_PRIMITIVE_TYPE_REFLECTION(ty, name_literal) \
template <> \
struct ReturnTypeReflection<ty> { \
static constexpr const char* type_name() noexcept { return name_literal; } \
static constexpr MunGuid type_guid() noexcept { return details::type_guid(type_name()); } \
}; \
\
template <> \
struct ArgumentReflection<ty> { \
static constexpr const char* type_name(const ty&) noexcept { \
return ReturnTypeReflection<ty>::type_name(); \
} \
static constexpr MunGuid type_guid(const ty&) noexcept { \
return ReturnTypeReflection<ty>::type_guid(); \
} \
};

IMPL_PRIMITIVE_TYPE_REFLECTION(bool, "core::bool");
IMPL_PRIMITIVE_TYPE_REFLECTION(float, "core::f32");
IMPL_PRIMITIVE_TYPE_REFLECTION(double, "core::f64");
IMPL_PRIMITIVE_TYPE_REFLECTION(int8_t, "core::i8");
IMPL_PRIMITIVE_TYPE_REFLECTION(int16_t, "core::i16");
IMPL_PRIMITIVE_TYPE_REFLECTION(int32_t, "core::i32");
IMPL_PRIMITIVE_TYPE_REFLECTION(int64_t, "core::i64");
// IMPL_PRIMITIVE_TYPE_REFLECTION(int128_t, "core::i128");
IMPL_PRIMITIVE_TYPE_REFLECTION(uint8_t, "core::u8");
IMPL_PRIMITIVE_TYPE_REFLECTION(uint16_t, "core::u16");
IMPL_PRIMITIVE_TYPE_REFLECTION(uint32_t, "core::u32");
IMPL_PRIMITIVE_TYPE_REFLECTION(uint64_t, "core::u64");
// IMPL_PRIMITIVE_TYPE_REFLECTION(uint128_t, "core::u128");

template <>
struct ReturnTypeReflection<void> {
static constexpr const char* type_name() noexcept { return "core::empty"; }
static constexpr MunGuid type_guid() noexcept { return details::type_guid(type_name()); }
};
} // namespace mun

#endif
45 changes: 42 additions & 3 deletions include/mun/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@
#include <string_view>

#include "mun/error.h"
#include "mun/function.h"
#include "mun/runtime_capi.h"

namespace mun {

struct RuntimeOptions;

/** A wrapper around a `MunRuntimeHandle`.
*
* Frees the corresponding runtime object on destruction, if it exists.
*/
class Runtime {
friend std::optional<Runtime> make_runtime(std::string_view library_path,
const RuntimeOptions& options,
Error* out_error) noexcept;

/** Constructs a runtime from an instantiated `MunRuntimeHandle`.
Expand Down Expand Up @@ -148,19 +153,53 @@ class Runtime {
MunRuntimeHandle m_handle;
};

/** Construct a new runtime that loads the library at `library_path` and its
dependencies.
struct RuntimeOptions {
/**
* The interval at which changes to the disk are detected. `0` will initialize this value to
* default.
*/
uint32_t delay_ms = 0;

/**
* A list of functions to add to the runtime, these functions can be called from Mun as *extern*
* functions.
*/
std::vector<RuntimeFunction> functions;
};

/** Construct a new runtime that loads the library at `library_path` and its dependencies.
*
* On failure, the error is returned through the `out_error` pointer, if set.
*
* \param library_path the path to a Mun library
* \param options Additional options used by the construction of a runtime
* \param out_error optionally, a pointer to an `Error` instance
* \return potentially, a runtime
baszalmstra marked this conversation as resolved.
Show resolved Hide resolved
.*/
inline std::optional<Runtime> make_runtime(std::string_view library_path,
const RuntimeOptions& options = {},
Error* out_error = nullptr) noexcept {
std::vector<MunFunctionDefinition> function_definitions(options.functions.size());
for (size_t i = 0; i < options.functions.size(); ++i) {
auto& definition = function_definitions[i];
const auto& func = options.functions[i];
definition = MunFunctionDefinition{
MunFunctionPrototype{
func.name.c_str(),
MunFunctionSignature{func.arg_types.data(),
func.ret_type.has_value() ? func.ret_type.value() : nullptr,
static_cast<uint16_t>(func.arg_types.size())}},
func.fn_ptr};
}

MunRuntimeOptions runtime_options;
runtime_options.delay_ms = options.delay_ms;
runtime_options.functions =
function_definitions.empty() ? nullptr : function_definitions.data();
runtime_options.num_functions = static_cast<uint32_t>(function_definitions.size());

MunRuntimeHandle handle;
if (auto error = Error(mun_runtime_create(library_path.data(), &handle))) {
if (auto error = Error(mun_runtime_create(library_path.data(), runtime_options, &handle))) {
if (out_error) {
*out_error = std::move(error);
}
Expand Down
32 changes: 31 additions & 1 deletion include/mun/runtime_capi.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,34 @@ typedef struct {
const void *fn_ptr;
} MunFunctionDefinition;

/**
* Options required to construct a [`RuntimeHandle`] through [`mun_runtime_create`]
*
* # Safety
*
* This struct contains raw pointers as parameters. Passing pointers to invalid data, will lead to
* undefined behavior.
*/
typedef struct {
/**
* The interval at which changes to the disk are detected. `0` will initialize this value to
* default.
*/
uint32_t delay_ms;
/**
* Function definitions that should be inserted in the runtime before a mun library is loaded.
* This is useful to initialize `extern` functions used in a mun library.
*
* If the [`num_functions`] fields is non-zero this field must contain a pointer to an array
* of [`abi::FunctionDefinition`]s.
*/
const MunFunctionDefinition *functions;
/**
* The number of functions in the [`functions`] array.
*/
uint32_t num_functions;
} MunRuntimeOptions;

/**
* Represents a struct declaration.
*
Expand Down Expand Up @@ -339,7 +367,9 @@ MunErrorHandle mun_gc_unroot(MunRuntimeHandle handle, MunGcPtr obj);
* This function receives raw pointers as parameters. If any of the arguments is a null pointer,
* an error will be returned. Passing pointers to invalid data, will lead to undefined behavior.
*/
MunErrorHandle mun_runtime_create(const char *library_path, MunRuntimeHandle *handle);
MunErrorHandle mun_runtime_create(const char *library_path,
MunRuntimeOptions options,
MunRuntimeHandle *handle);

/**
* Destructs the runtime corresponding to `handle`.
Expand Down
Loading