-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6c7353d
commit d42a009
Showing
3 changed files
with
148 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# flake8: noqa | ||
|
||
cdef = [] | ||
|
||
cdef.append( | ||
""" | ||
typedef struct _MonoDomain MonoDomain; | ||
typedef struct _MonoAssembly MonoAssembly; | ||
typedef struct _MonoImage MonoImage; | ||
typedef struct _MonoMethodDesc MonoMethodDesc; | ||
typedef struct _MonoMethod MonoMethod; | ||
typedef struct _MonoObject MonoObject; | ||
MonoDomain* mono_jit_init(const char *root_domain_name); | ||
void mono_jit_cleanup(MonoDomain *domain); | ||
MonoAssembly* mono_domain_assembly_open(MonoDomain *domain, const char *name); | ||
MonoImage* mono_assembly_get_image(MonoAssembly *assembly); | ||
void mono_config_parse(const char* path); | ||
void mono_domain_set_config(MonoDomain *domain, const char *base_dir, const char *config_file_name); | ||
MonoMethodDesc* mono_method_desc_new(const char* name, bool include_namespace); | ||
MonoMethod* mono_method_desc_search_in_image(MonoMethodDesc *method_desc, MonoImage *image); | ||
void mono_method_desc_free(MonoMethodDesc *method_desc); | ||
MonoObject* mono_runtime_invoke(MonoMethod *method, void *obj, void **params, MonoObject **exc); | ||
void* mono_object_unbox(MonoObject *object); | ||
""" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import atexit | ||
|
||
from .ffi import load_mono, ffi | ||
|
||
|
||
__all__ = ["Mono"] | ||
|
||
|
||
_MONO = None | ||
_ROOT_DOMAIN = None | ||
|
||
|
||
class Mono: | ||
def __init__(self, libmono, domain=None, config_file=None): | ||
self._assemblies = {} | ||
|
||
initialize(config_file=config_file, libmono=libmono) | ||
|
||
if domain is None: | ||
self._domain = _ROOT_DOMAIN | ||
else: | ||
raise NotImplementedError | ||
|
||
def get_callable(self, assembly_path, typename, function): | ||
assembly = self._assemblies.get(assembly_path) | ||
if not assembly: | ||
assembly = _MONO.mono_domain_assembly_open( | ||
self._domain, assembly_path.encode("utf8") | ||
) | ||
_check_result(assembly, f"Unable to load assembly {assembly_path}") | ||
self._assemblies[assembly_path] = assembly | ||
|
||
image = _MONO.mono_assembly_get_image(assembly) | ||
_check_result(image, "Unable to load image from assembly") | ||
|
||
desc = MethodDesc(typename, function) | ||
method = desc.search(image) | ||
_check_result( | ||
method, f"Could not find method {typename}.{function} in assembly" | ||
) | ||
|
||
return MonoMethod(method) | ||
|
||
|
||
class MethodDesc: | ||
def __init__(self, typename, function): | ||
self._desc = f"{typename}:{function}" | ||
self._ptr = _MONO.mono_method_desc_new( | ||
self._desc.encode("utf8"), 1 # include_namespace | ||
) | ||
|
||
def search(self, image): | ||
return _MONO.mono_method_desc_search_in_image(self._ptr, image) | ||
|
||
def __del__(self): | ||
if _MONO: | ||
_MONO.mono_method_desc_free(self._ptr) | ||
|
||
|
||
class MonoMethod: | ||
def __init__(self, ptr): | ||
self._ptr = ptr | ||
|
||
def __call__(self, ptr, size): | ||
exception = ffi.new("MonoObject**") | ||
params = ffi.new("void*[2]") | ||
|
||
# Keep these alive until the function is called by assigning them locally | ||
ptr_ptr = ffi.new("void**", ptr) | ||
size_ptr = ffi.new("int32_t*", size) | ||
|
||
params[0] = ptr_ptr | ||
params[1] = size_ptr | ||
|
||
res = _MONO.mono_runtime_invoke(self._ptr, ffi.NULL, params, exception) | ||
_check_result(res, "Failed to call method") | ||
|
||
unboxed = ffi.cast("int32_t*", _MONO.mono_object_unbox(res)) | ||
_check_result(unboxed, "Failed to convert result to int") | ||
|
||
return unboxed[0] | ||
|
||
|
||
def initialize(config_file: str, libmono: str) -> None: | ||
global _MONO, _ROOT_DOMAIN | ||
if _MONO is None: | ||
_MONO = load_mono(libmono) | ||
|
||
if config_file is None: | ||
config_bytes = ffi.NULL | ||
else: | ||
config_bytes = config_file.encode("utf8") | ||
|
||
_ROOT_DOMAIN = _MONO.mono_jit_init(b"clr_loader") | ||
|
||
_MONO.mono_domain_set_config(_ROOT_DOMAIN, b"/etc/mono/", b"config"); | ||
|
||
_check_result(_ROOT_DOMAIN, "Failed to initialize Mono") | ||
atexit.register(_release) | ||
|
||
|
||
def _release(): | ||
global _MONO, _ROOT_DOMAIN | ||
if _ROOT_DOMAIN is not None and _MONO is not None: | ||
_MONO.mono_jit_cleanup(_ROOT_DOMAIN) | ||
_MONO = None | ||
_ROOT_DOMAIN = None | ||
|
||
|
||
def _check_result(res, msg): | ||
if res == ffi.NULL or not res: | ||
raise RuntimeError(msg) |