#include "runtime.h"
#if !RUNTIME_IOS
#include
#include
#endif
#include "mono/jit/jit.h"
#include "mono/metadata/environment.h"
#include "mono/utils/mono-publib.h"
#include "mono/utils/mono-logger.h"
#include "mono/metadata/assembly.h"
#include "mono/metadata/mono-debug.h"
#include "mono/metadata/exception.h"
#include
#include
#include
#include
#include
typedef char bool;
#define false 0
#define true 1
MonoDomain *g_domain;
char* mono_runtime_bundle_path;
char* mono_runtime_reload_path;
bool
file_exists(const char *path)
{
struct stat buffer;
return stat(path, &buffer) == 0;
}
char *
strdup_printf(const char *msg, ...)
{
va_list args;
char *formatted = NULL;
va_start(args, msg);
printf(formatted, msg, args);
va_end(args);
return formatted;
}
extern const char *ios_bundle_path(void);
const char * runtime_bundle_path(void)
{
if(mono_runtime_bundle_path != NULL)
return mono_runtime_bundle_path;
#if RUNTIME_IOS
mono_runtime_bundle_path = ios_bundle_path();
#else
if ((mono_runtime_bundle_path = _getcwd(NULL, 0)) == NULL)
perror("getcwd error");
else
printf("doc_path=%s\n", mono_runtime_bundle_path);
#endif
return mono_runtime_bundle_path;
}
MonoAssembly*
load_assembly(const char *name, const char *culture)
{
char *load_dir = mono_runtime_reload_path;
char path[1024];
int res;
const char *post = name + strlen(name) -4;
if (culture && strcmp(culture, ""))
res = snprintf(path, sizeof(path) - 1, "%s/%s/%s", load_dir, culture, name);
else if(strcmp(post, ".dll") == 0 || strcmp(post, ".exe") == 0)
res = snprintf(path, sizeof(path) - 1, "%s/%s", load_dir, name);
else
res = snprintf(path, sizeof(path) - 1, "%s/%s.dll", load_dir, name);
assert(res > 0);
if (!file_exists(path))
{
load_dir = runtime_bundle_path();
if (culture && strcmp(culture, ""))
res = snprintf(path, sizeof(path) - 1, "%s/Managed/%s/%s", load_dir, culture, name);
else if (strcmp(post, ".dll") == 0 || strcmp(post, ".exe") == 0)
res = snprintf(path, sizeof(path) - 1, "%s/Managed/%s", load_dir, name);
else
res = snprintf(path, sizeof(path) - 1, "%s/Managed/%s.dll", load_dir, name);
assert(res > 0);
}
printf("load_assembly load path: %s \n", path);
if (file_exists(path)) {
MonoAssembly *assembly = mono_assembly_open(path, NULL);
assert(assembly);
return assembly;
}
return NULL;
}
void check_mono_exception(MonoException* mono);
static void main_function (MonoDomain *domain, const char *file, int argc, char** argv)
{
MonoAssembly *assembly = load_assembly("Adapter.wrapper.dll", NULL);
if (!assembly)
return;
MonoImage* img = mono_assembly_get_image(assembly);
MonoClass* klass = mono_class_from_name(img, "PureScript.Mono", "ScriptEngine");
MonoMethod* main = mono_class_get_method_from_name(klass, "Main", 1);
/*
* mono_jit_exec() will run the Main() method in the assembly.
* The return value needs to be looked up from
* System.Environment.ExitCode.
*/
//mono_jit_exec(domain, assembly, argc, argv);
MonoObject *exc = NULL;
int res = mono_runtime_run_main(main, argc, argv, &exc);
check_mono_exception(exc);
/*if (exc != NULL)
return;
assembly = load_assembly(file, NULL);
if (!assembly)
return;
img = mono_assembly_get_image(assembly);
klass = mono_class_from_name(img, "", "MonoEntry");
main = mono_class_get_method_from_name(klass, "Main", 1);
int res = mono_runtime_run_main(main, argc, argv, &exc);
//mono_runtime_invoke(main, 0, NULL, &exc);
check_mono_exception(exc);*/
}
const char* resolve_assembly(const char* request);
static MonoAssembly*
assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void* user_data)
{
const char *name = resolve_assembly(mono_assembly_name_get_name(aname));
const char *culture = mono_assembly_name_get_culture(aname);
return load_assembly(name, culture);
}
void
log_callback_default(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data)
{
printf("(%s %s) %s", log_domain, log_level, message);
if (fatal) {
printf("Exit code: %d.", 1);
exit(1);
}
}
MonoObject *
mono_exception_property(MonoObject *obj, const char *name, char is_virtual)
{
MonoMethod *get = NULL;
MonoMethod *get_virt = NULL;
MonoObject *exc = NULL;
get = mono_class_get_method_from_name(mono_get_exception_class(), name, 0);
if (get) {
if (is_virtual) {
get_virt = mono_object_get_virtual_method(obj, get);
if (get_virt)
get = get_virt;
}
return (MonoObject *)mono_runtime_invoke(get, obj, NULL, &exc);
}
else {
printf("Could not find the property System.Exception.%s", name);
}
return NULL;
}
static char *
fetch_exception_property_string(MonoObject *obj, const char *name, bool is_virtual)
{
MonoString *str = (MonoString *)mono_exception_property(obj, name, is_virtual);
return str ? mono_string_to_utf8(str) : NULL;
}
void
unhandled_exception_handler(MonoObject *exc, void *user_data)
{
//NSMutableString *msg = [[NSMutableString alloc] init];
MonoClass *type = mono_object_get_class(exc);
const char* type_name = mono_class_get_name(type);
//char *type_name = strdup_printf("%s.%s", mono_class_get_namespace(type), mono_class_get_name(type));
char *trace = fetch_exception_property_string(exc, "get_StackTrace", true);
char *message = fetch_exception_property_string(exc, "get_Message", true);
printf("Unhandled managed exception:\n");
printf("%s (%s)\n%s\n", message, type_name, trace ? trace : "");
if (trace != NULL)
mono_free(trace);
if (message != NULL)
mono_free(message);
//os_log_info (OS_LOG_DEFAULT, "%@", msg);
printf("Exit code: %d.", 1);
exit(1);
}
/*
static int malloc_count = 0;
static void* custom_malloc(size_t bytes)
{
++malloc_count;
return malloc(bytes);
}*/
/* Implemented by generated code */
void mono_register_icall(void);
void register_assembly_map();
#if RUNTIME_IOS
#define __STRDUP strdup
void mono_ios_runtime_init(void);
#else
#define __STRDUP _strdup
#endif
void mono_debug() {
mono_debug_init(MONO_DEBUG_FORMAT_MONO);
static const char* options[] = {
"--soft-breakpoints",
"--debugger-agent=transport=dt_socket,address=127.0.0.1:10001,embedding=1,server=y,suspend=n"
};
mono_jit_parse_options(sizeof(options) / sizeof(char*), (char**)options);
}
int
mono_setup(char* reloadDir, const char* file) {
mono_runtime_reload_path = __STRDUP(reloadDir);
int retval = 0;
//MonoAllocatorVTable mem_vtable = {custom_malloc};
//mono_set_allocator_vtable (&mem_vtable);
mono_install_assembly_preload_hook(assembly_preload_hook, NULL);
mono_install_unhandled_exception_hook(unhandled_exception_handler, NULL);
mono_trace_set_log_handler(log_callback_default, NULL);
mono_set_signal_chaining(true);
mono_set_crash_chaining(true);
mono_debug();
#if RUNTIME_IOS
const char* rootdir = runtime_bundle_path();
#else
const char* rootdir = mono_runtime_reload_path;
#endif
mono_set_dirs(rootdir, rootdir);
/*
* Load the default Mono configuration file, this is needed
* if you are planning on using the dllmaps defined on the
* system configuration
*/
//mono_config_parse (NULL);
/*
* mono_jit_init() creates a domain: each assembly is
* loaded and run in a MonoDomain.
*/
#if RUNTIME_IOS
mono_ios_runtime_init();
#endif
g_domain = mono_jit_init (file);
mono_domain_set(g_domain, false);
register_assembly_map();
/*
* We add our special internal call, so that C# code
* can call us back.
*/
mono_register_icall();
char *managed_argv[2];
managed_argv[0] = file;
managed_argv[1] = file;
main_function (g_domain, file, 2, managed_argv);
return retval;
}
int mono_exit()
{
int retval = mono_environment_exitcode_get ();
mono_jit_cleanup (mono_domain_get());
return retval;
}