Compare commits

...

1 Commits
16632 ... 11094

Author SHA1 Message Date
Martin-Molinero
8a0ec41449 Fix mono running in research 2021-03-10 16:46:34 -03:00
3 changed files with 148 additions and 0 deletions

View File

@@ -47,6 +47,12 @@ RUN chmod -R 777 ${WORK}
RUN pip install clr-loader
# Work around for https://github.com/pythonnet/clr-loader/issues/8
COPY ffi_hack_mono.py /opt/miniconda3/lib/python3.6/site-packages/clr_loader/ffi/mono.py
COPY hack_mono.py /opt/miniconda3/lib/python3.6/site-packages/clr_loader/mono.py
ENV LD_LIBRARY_PATH=/lib/
RUN ln -s /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libc.so
EXPOSE 8888
WORKDIR $WORK

30
Research/ffi_hack_mono.py Normal file
View File

@@ -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);
"""
)

112
Research/hack_mono.py Normal file
View File

@@ -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)