mirror of
https://github.com/HeyPuter/gex.git
synced 2026-11-13 20:12:43 -10:00
unity-dotnet P4 groundwork: the rest of the API UnityPlayer uses
tools/unity-dotnet/mono/host/gexmono-unity.c: adapters for what upstream Mono lacks or has only with a callback the guest can't give it: Unity's mono_unity_* (object and array header layout, class/field/method/type queries, 2D/3D arrays, the empty string, error conversion, data dir and main args), the legacy names Unity looks up (userdata, profiler install, incremental-GC knobs, appdomain refs, ...), the guest-callback ones (mono_assembly_foreach, mono_stack_walk[_no_il], mono_trace_set_log_handler, mono_set_find_plugin_callback, mono_dl_fallback_register), and assembly search paths (.NET's CoreLib and facades first, GEXMONO_ASSEMBLIES, then Unity's Managed directory). Unity's memory-profiler hooks report nothing. MonoClass gains unity_user_data (UnityPlayer reads it at its offset). dl_load consults Unity's find-plugin callback and its own dl fallback after the guest's dlopen. Everything hand-written is left out of the generated adapters. tests/unity-dotnet/embed still PASS. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01CaUXC2hGSgLjSxdmve9dnD
This commit is contained in:
4 files changed
+477
-13
No files matched your search
@@ -88,16 +88,18 @@ step_provider() {
|
||||
local INC="-nostdinc -isystem $SR/include -isystem $(clang -print-resource-dir)/include -I$P -I$OUT/src/src/mono -I$UD/provider -I$HERE/host -I$OUT/obj -I$OUT/src/src/mono/mono/eglib -I$OUT/obj/mono/eglib -I$OUT/src/src/native"
|
||||
llvm-nm --defined-only -j "$L"/mini/libmonosgen-2.0.a "$L"/mini/libmono-ee-interp.a "$L"/mini/libmono-component-*-stub-static.a \
|
||||
"$L"/mini/libmono-component-marshal-ilgen-static.a 2>/dev/null | grep '^mono_' | sort -u > have.txt
|
||||
python3 "$HERE/host/gen-adapters.py" --abi sysv --skip "$HERE/host/gexmono-skip.txt" --have have.txt \
|
||||
# Everything written by hand (gexmono-provider.c's skip list, gexmono-unity.c's U(...)) is not generated.
|
||||
{ cat "$HERE/host/gexmono-skip.txt"; sed -n 's/^U(\(mono_[a-z0-9_]*\)).*/\1/p' "$HERE/host/gexmono-unity.c"; } > skip.txt
|
||||
python3 "$HERE/host/gen-adapters.py" --abi sysv --skip skip.txt --have have.txt \
|
||||
"$P"/mono/*/details/*-functions.h "$P"/mono/*/details/*-types.h > adapters.c 2> adapters.log
|
||||
python3 "$HERE/host/gen-m2n.py" "$HERE/host/m2n-extra.txt" > m2n.c
|
||||
for f in adapters.c m2n.c "$HERE/host/gexmono-provider.c" "$UD/provider/gexprov64.c" "$UD/provider/gexprov64-table.s"; do
|
||||
for f in adapters.c m2n.c "$HERE/host/gexmono-provider.c" "$HERE/host/gexmono-unity.c" "$UD/provider/gexprov64.c" "$UD/provider/gexprov64-table.s"; do
|
||||
clang $WASM64_CFLAGS $INC -Wno-unused-command-line-argument -Wno-deprecated-declarations -c "$f" -o "$(basename "${f%.*}").o"
|
||||
done
|
||||
clang $WASM64_CFLAGS $INC -I"$N/libs/Common" -I"$OUT/objnative/Common" -I"$N/libs/System.Native" -I"$N" -I"$N/libs" \
|
||||
-c "$N/libs/System.Native/entrypoints.c" -o entrypoints-System.Native.o
|
||||
wasm-ld -mwasm64 --experimental-pic -pie --no-entry --shared-memory --import-memory --max-memory=17179869184 -o mono.wasm \
|
||||
gexmono-provider.o gexprov64.o gexprov64-table.o adapters.o m2n.o entrypoints-System.Native.o "$OUT/objnative/System.Native/libSystem.Native.a" \
|
||||
gexmono-provider.o gexmono-unity.o gexprov64.o gexprov64-table.o adapters.o m2n.o entrypoints-System.Native.o "$OUT/objnative/System.Native/libSystem.Native.a" \
|
||||
"$L"/mini/libmonosgen-2.0.a "$L"/mini/libmono-ee-interp.a "$L"/mini/libmono-component-marshal-ilgen-static.a \
|
||||
"$L"/mini/libmono-component-hot_reload-stub-static.a "$L"/mini/libmono-component-debugger-stub-static.a \
|
||||
"$L"/mini/libmono-component-diagnostics_tracing-stub-static.a "$L"/mini/libmono-wasm-nosimd.a \
|
||||
|
||||
@@ -64,21 +64,54 @@ call2 (uint64_t fn, uint64_t a, uint64_t b)
|
||||
|
||||
#define GUEST_RTLD_LAZY 1
|
||||
|
||||
extern uint64_t gexmono_find_plugin, gexmono_dl_fallback [4];
|
||||
|
||||
static uint64_t
|
||||
call4 (uint64_t fn, uint64_t a, uint64_t b, uint64_t c, uint64_t d)
|
||||
{
|
||||
gexp_call k = { 0 };
|
||||
k.ireg [0] = a, k.ireg [1] = b, k.ireg [2] = c, k.ireg [3] = d;
|
||||
k.nireg = 4;
|
||||
gexp_call_guest (fn, &k);
|
||||
return k.rax;
|
||||
}
|
||||
|
||||
static void *
|
||||
guest_handle (uint64_t h, int unity)
|
||||
{
|
||||
DlHandle *d = calloc (1, sizeof *d);
|
||||
d->guest = h;
|
||||
d->lib = unity ? "unity" : NULL;
|
||||
return d;
|
||||
}
|
||||
|
||||
static void *
|
||||
dl_load (const char *name, int flags, char **err, void *user_data)
|
||||
{
|
||||
for (size_t i = 0; name && i < sizeof native_libs / sizeof native_libs [0]; i++)
|
||||
if (!strcmp (name, native_libs [i].lib))
|
||||
return (void *)&native_libs [i];
|
||||
/* Unity's find-plugin callback names a plugin's path. */
|
||||
const char *path = name;
|
||||
if (name && gexmono_find_plugin) {
|
||||
const char *p = (const char *)(uintptr_t)call2 (gexmono_find_plugin, (uint64_t)(uintptr_t)name, 0);
|
||||
if (p)
|
||||
path = p;
|
||||
}
|
||||
uint64_t open = guest_fn ("dlopen", &guest_dlopen);
|
||||
if (!open)
|
||||
return NULL;
|
||||
uint64_t h = call2 (open, (uint64_t)(uintptr_t)name, GUEST_RTLD_LAZY);
|
||||
if (!h)
|
||||
return NULL;
|
||||
DlHandle *d = calloc (1, sizeof *d);
|
||||
d->guest = h;
|
||||
return d;
|
||||
if (open) {
|
||||
uint64_t h = call2 (open, (uint64_t)(uintptr_t)path, GUEST_RTLD_LAZY);
|
||||
if (h)
|
||||
return guest_handle (h, 0);
|
||||
}
|
||||
/* Unity's own fallback: load (name, flags, &err, user_data). */
|
||||
if (gexmono_dl_fallback [0] && name) {
|
||||
char *e = NULL;
|
||||
uint64_t h = call4 (gexmono_dl_fallback [0], (uint64_t)(uintptr_t)name, flags, (uint64_t)(uintptr_t)&e, gexmono_dl_fallback [3]);
|
||||
if (h)
|
||||
return guest_handle (h, 1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
@@ -86,10 +119,14 @@ dl_symbol (void *handle, const char *name, char **err, void *user_data)
|
||||
{
|
||||
const DlHandle *d = handle;
|
||||
const void *p = NULL;
|
||||
if (d->resolve)
|
||||
if (d->resolve) {
|
||||
p = d->resolve (name);
|
||||
else if (guest_fn ("dlsym", &guest_dlsym))
|
||||
} else if (d->lib && gexmono_dl_fallback [1]) {
|
||||
char *e = NULL;
|
||||
p = (const void *)(uintptr_t)call4 (gexmono_dl_fallback [1], d->guest, (uint64_t)(uintptr_t)name, (uint64_t)(uintptr_t)&e, gexmono_dl_fallback [3]);
|
||||
} else if (guest_fn ("dlsym", &guest_dlsym)) {
|
||||
p = (const void *)(uintptr_t)call2 (guest_dlsym, d->guest, (uint64_t)(uintptr_t)name);
|
||||
}
|
||||
if (!p && err)
|
||||
*err = strdup ("gexmono: symbol not found");
|
||||
return (void *)p;
|
||||
|
||||
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* gexmono-unity.c: the parts of Unity's Mono embedding API that upstream Mono
|
||||
* lacks or has without a callback the guest can give it (docs/unity-dotnet.md
|
||||
* §2): the mono_unity_* functions of Unity's fork, the legacy names Unity
|
||||
* still looks up, and the functions taking guest callbacks. Semantics follow
|
||||
* Unity-Technologies/mono (unity-utils.c and friends); what only serves
|
||||
* Unity's memory profiler reports nothing.
|
||||
*
|
||||
* Each is a gex F_body adapter (gexprov64.h), listed in gexmono_unity_adapters.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "gexmono-adapters.h"
|
||||
#include <mono/metadata/class-internals.h>
|
||||
#include <mono/metadata/object-internals.h>
|
||||
#include <mono/metadata/metadata-internals.h>
|
||||
#include <mono/metadata/domain-internals.h>
|
||||
#include <mono/metadata/assembly-internals.h>
|
||||
#include <mono/metadata/custom-attrs-internals.h>
|
||||
#include <mono/metadata/reflection-internals.h>
|
||||
#include <mono/utils/mono-error-internals.h>
|
||||
#include <mono/utils/mono-logger-internals.h>
|
||||
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
void *gex_class_get_userdata (MonoClass *klass);
|
||||
void gex_class_set_userdata (MonoClass *klass, void *userdata);
|
||||
int gex_class_get_userdata_offset (void);
|
||||
gboolean gex_class_is_inited (MonoClass *klass);
|
||||
guint32 gex_class_get_data_size (MonoClass *klass);
|
||||
|
||||
#define A(i) gexp_arg (ctx, i)
|
||||
#define P(i) ((void *)(uintptr_t)A (i))
|
||||
#define U(name) GEXP_SYSV (gexp_##name)
|
||||
#define ENTER gexp_enter (ctx)
|
||||
#define RET(v) do { GEXP_RET_U64 (ctx, (uint64_t)(v)); return gexp_return (ctx, ret); } while (0)
|
||||
#define RETV return gexp_return (ctx, ret)
|
||||
|
||||
/* A guest callback: call it by the guest's ABI with integer arguments. */
|
||||
static uint64_t
|
||||
guest_cb (uint64_t fn, int n, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4)
|
||||
{
|
||||
gexp_call c = { 0 };
|
||||
uint64_t a [5] = { a0, a1, a2, a3, a4 };
|
||||
for (int i = 0; i < n; i++)
|
||||
c.ireg [i] = a [i];
|
||||
c.nireg = n;
|
||||
gexp_call_guest (fn, &c);
|
||||
return c.rax;
|
||||
}
|
||||
|
||||
/* ---- the object layout Unity reads directly ---- */
|
||||
|
||||
U(mono_unity_object_header_size) { ENTER; RET (sizeof (MonoObject)); }
|
||||
U(mono_unity_array_object_header_size) { ENTER; RET (offsetof (MonoArray, vector)); }
|
||||
U(mono_unity_offset_of_array_length_in_array_object_header) { ENTER; RET (offsetof (MonoArray, max_length)); }
|
||||
U(mono_unity_offset_of_array_bounds_in_array_object_header) { ENTER; RET (offsetof (MonoArray, bounds)); }
|
||||
U(mono_unity_allocation_granularity) { ENTER; RET (2 * sizeof (void *)); }
|
||||
|
||||
/* ---- classes, types, fields, methods ---- */
|
||||
|
||||
U(mono_class_get_userdata) { ENTER; RET (gex_class_get_userdata (P (0))); }
|
||||
U(mono_class_set_userdata) { ENTER; gex_class_set_userdata (P (0), P (1)); RETV; }
|
||||
U(mono_class_get_userdata_offset) { ENTER; RET ((uint32_t)gex_class_get_userdata_offset ()); }
|
||||
U(mono_class_is_blittable) { ENTER; RET (m_class_is_blittable ((MonoClass *)P (0))); }
|
||||
U(mono_class_is_generic) { ENTER; RET (mono_class_is_gtd ((MonoClass *)P (0))); }
|
||||
U(mono_class_is_inflated) { ENTER; RET (mono_class_is_ginst ((MonoClass *)P (0))); }
|
||||
U(mono_unity_class_is_interface) { ENTER; RET (MONO_CLASS_IS_INTERFACE_INTERNAL ((MonoClass *)P (0))); }
|
||||
U(mono_unity_class_is_abstract) { ENTER; RET ((mono_class_get_flags ((MonoClass *)P (0)) & TYPE_ATTRIBUTE_ABSTRACT) != 0); }
|
||||
U(mono_unity_class_is_inited) { ENTER; RET (gex_class_is_inited (P (0))); }
|
||||
U(mono_unity_class_has_failure) { ENTER; RET (mono_class_has_failure ((MonoClass *)P (0))); }
|
||||
U(mono_unity_class_get_data_size) { ENTER; RET (gex_class_get_data_size (P (0))); }
|
||||
U(mono_unity_class_is_open_constructed_type) { ENTER; RET (mono_class_is_open_constructed_type (m_class_get_byval_arg ((MonoClass *)P (0)))); }
|
||||
U(mono_unity_class_try_get_vtable) { ENTER; RET (mono_class_try_get_vtable ((MonoClass *)P (1))); }
|
||||
U(mono_unity_class_field_is_literal) { ENTER; RET ((((MonoClassField *)P (0))->type->attrs & FIELD_ATTRIBUTE_LITERAL) != 0); }
|
||||
U(mono_unity_class_get_generic_type_definition)
|
||||
{
|
||||
ENTER;
|
||||
MonoClass *k = P (0);
|
||||
RET (mono_class_is_ginst (k) ? mono_class_get_generic_class (k)->container_class : NULL);
|
||||
}
|
||||
U(mono_unity_class_get) { ENTER; ERROR_DECL (e); MonoClass *k = mono_class_get_checked (P (0), (guint32)A (1), e); mono_error_cleanup (e); RET (k); }
|
||||
U(mono_unity_class_get_checked) { ENTER; RET (mono_class_get_checked (P (0), (guint32)A (1), P (2))); }
|
||||
U(mono_unity_field_from_token_checked) { ENTER; RET (mono_field_from_token_checked (P (0), (guint32)A (1), P (2), P (3), P (4))); }
|
||||
U(mono_unity_get_method_checked) { ENTER; RET (mono_get_method_checked (P (0), (guint32)A (1), P (2), P (3), P (4))); }
|
||||
U(mono_unity_type_is_pointer_type) { ENTER; RET (((MonoType *)P (0))->type == MONO_TYPE_PTR); }
|
||||
U(mono_unity_type_is_static) { ENTER; RET ((((MonoType *)P (0))->attrs & FIELD_ATTRIBUTE_STATIC) != 0); }
|
||||
U(mono_type_get_attrs) { ENTER; RET (((MonoType *)P (0))->attrs); }
|
||||
U(mono_unity_vtable_get_static_field_data) { ENTER; RET (mono_vtable_get_static_field_data (P (0))); }
|
||||
U(mono_method_signature_checked) { ENTER; RET (mono_method_signature_checked (P (0), P (1))); }
|
||||
U(mono_method_signature_checked_slow) { ENTER; RET (mono_method_signature_checked_slow (P (0), P (1))); }
|
||||
U(mono_unity_type_get_name_full_chunked)
|
||||
{
|
||||
ENTER;
|
||||
char *name = mono_type_get_name_full (P (0), MONO_TYPE_NAME_FORMAT_IL);
|
||||
if (name) {
|
||||
guest_cb (A (1), 2, (uintptr_t)name, A (2), 0, 0, 0);
|
||||
g_free (name);
|
||||
}
|
||||
RETV;
|
||||
}
|
||||
|
||||
/* ---- custom attributes ---- */
|
||||
|
||||
U(mono_custom_attrs_get_attrs)
|
||||
{
|
||||
ENTER;
|
||||
MonoCustomAttrInfo *ainfo = P (0);
|
||||
void **iter = P (1);
|
||||
MonoClass *r = NULL;
|
||||
if (iter && ainfo->num_attrs) {
|
||||
int index = GPOINTER_TO_INT (*iter);
|
||||
if (index < ainfo->num_attrs) {
|
||||
r = ainfo->attrs [index].ctor->klass;
|
||||
*iter = GINT_TO_POINTER (index + 1);
|
||||
}
|
||||
}
|
||||
RET (r);
|
||||
}
|
||||
U(mono_custom_attrs_construct_by_type) { ENTER; RET (mono_custom_attrs_construct (P (0))); }
|
||||
U(mono_unity_custom_attrs_construct) { ENTER; RET (mono_custom_attrs_construct (P (0))); }
|
||||
|
||||
/* ---- arrays, strings, errors ---- */
|
||||
|
||||
U(mono_unity_array_new_2d)
|
||||
{
|
||||
ENTER;
|
||||
uintptr_t lengths [2] = { A (2), A (3) };
|
||||
ERROR_DECL (e);
|
||||
MonoArray *r = mono_array_new_full_checked (mono_class_create_array (P (1), 2), lengths, NULL, e);
|
||||
mono_error_cleanup (e);
|
||||
RET (r);
|
||||
}
|
||||
U(mono_unity_array_new_3d)
|
||||
{
|
||||
ENTER;
|
||||
uintptr_t lengths [3] = { A (2), A (3), A (4) };
|
||||
ERROR_DECL (e);
|
||||
MonoArray *r = mono_array_new_full_checked (mono_class_create_array (P (1), 3), lengths, NULL, e);
|
||||
mono_error_cleanup (e);
|
||||
RET (r);
|
||||
}
|
||||
U(mono_unity_string_empty_wrapper) { ENTER; RET (mono_string_empty_internal (mono_domain_get ())); }
|
||||
U(mono_unity_error_convert_to_exception) { ENTER; RET (mono_error_convert_to_exception (P (0))); }
|
||||
U(mono_unity_loader_get_last_error_and_error_prepare_exception) { ENTER; RET (0); }
|
||||
U(mono_unity_g_free) { ENTER; g_free (P (0)); RETV; }
|
||||
U(mono_assembly_name_parse) { ENTER; RET (mono_assembly_name_parse (P (0), P (1))); }
|
||||
|
||||
/* ---- runtime set-up Unity does, single-domain on .NET ---- */
|
||||
|
||||
static char *data_dir;
|
||||
U(mono_unity_set_data_dir) { ENTER; g_free (data_dir); data_dir = g_strdup (P (0)); RETV; }
|
||||
U(mono_unity_set_embeddinghostname) { ENTER; RETV; }
|
||||
U(mono_unity_domain_set_config) { ENTER; RETV; }
|
||||
U(mono_unity_runtime_set_main_args) { ENTER; mono_runtime_set_main_args ((int)A (0), P (1)); RETV; }
|
||||
U(mono_unity_install_memory_callbacks) { ENTER; RETV; } /* Mono keeps its own allocator */
|
||||
U(mono_unity_install_unitytls_interface) { ENTER; RETV; } /* Mono's TLS stack is not .NET's */
|
||||
U(mono_unity_set_vprintf_func) { ENTER; RETV; }
|
||||
U(mono_unity_jit_cleanup) { ENTER; RETV; }
|
||||
U(mono_set_defaults) { ENTER; RETV; }
|
||||
U(mono_parse_default_optimizations) { ENTER; RET (0); }
|
||||
U(mono_verifier_set_mode) { ENTER; RETV; }
|
||||
U(mono_set_ignore_version_and_key_when_finding_assemblies_already_loaded) { ENTER; RETV; }
|
||||
U(mono_runtime_unhandled_exception_policy_set) { ENTER; RETV; }
|
||||
U(mono_threads_set_shutting_down) { ENTER; RETV; }
|
||||
U(mono_thread_suspend_all_other_threads) { ENTER; RETV; }
|
||||
U(mono_thread_pool_cleanup) { ENTER; RETV; }
|
||||
U(mono_thread_push_appdomain_ref) { ENTER; RETV; }
|
||||
U(mono_thread_pop_appdomain_ref) { ENTER; RETV; }
|
||||
U(mono_thread_has_sufficient_execution_stack) { ENTER; RET (1); }
|
||||
U(mono_gchandle_is_in_domain) { ENTER; RET (1); }
|
||||
U(mono_gchandle_is_in_domain_v2) { ENTER; RET (1); }
|
||||
U(mono_pmip) { ENTER; RET (0); }
|
||||
U(mono_debug_lookup_source_location_by_il) { ENTER; RET (0); }
|
||||
|
||||
/* ---- the GC: Boehm-like, never incremental ---- */
|
||||
|
||||
static int gc_mode; /* MONO_GC_MODE_ENABLED 0, DISABLED 1, MANUAL 2 (Unity's) */
|
||||
U(mono_unity_gc_set_mode) { ENTER; gc_mode = (int)A (0); RETV; }
|
||||
U(mono_unity_gc_disable) { ENTER; gc_mode = 1; RETV; }
|
||||
U(mono_unity_gc_enable) { ENTER; gc_mode = 0; RETV; }
|
||||
U(mono_unity_gc_is_disabled) { ENTER; RET (gc_mode == 1); }
|
||||
U(mono_gc_is_incremental) { ENTER; RET (0); }
|
||||
U(mono_gc_set_incremental) { ENTER; RETV; }
|
||||
U(mono_gc_collect_a_little) { ENTER; RET (0); }
|
||||
U(mono_gc_get_max_time_slice_ns) { ENTER; RET (0); }
|
||||
U(mono_gc_set_max_time_slice_ns) { ENTER; RETV; }
|
||||
U(mono_gc_start_incremental_collection) { ENTER; RETV; }
|
||||
U(mono_gc_set_heap_validate_frequency) { ENTER; RETV; }
|
||||
U(mono_gc_set_heap_verifier_callback) { ENTER; RETV; }
|
||||
U(mono_unity_stop_gc_world) { ENTER; RETV; }
|
||||
U(mono_unity_start_gc_world) { ENTER; RETV; }
|
||||
U(mono_unity_heap_validation_from_statics) { ENTER; RETV; }
|
||||
|
||||
/* ---- Unity's memory profiler: reports nothing ---- */
|
||||
|
||||
U(mono_unity_assembly_mempool_chunk_foreach) { ENTER; RETV; }
|
||||
U(mono_unity_domain_mempool_chunk_foreach) { ENTER; RETV; }
|
||||
U(mono_unity_root_domain_mempool_chunk_foreach) { ENTER; RETV; }
|
||||
U(mono_unity_image_set_mempool_chunk_foreach) { ENTER; RETV; }
|
||||
U(mono_unity_gc_handles_foreach_get_target) { ENTER; RETV; }
|
||||
U(mono_unity_gc_heap_foreach) { ENTER; RETV; }
|
||||
U(mono_unity_class_for_each) { ENTER; RETV; }
|
||||
U(mono_unity_capture_memory_snapshot) { ENTER; RET (0); }
|
||||
U(mono_unity_free_captured_memory_snapshot) { ENTER; RETV; }
|
||||
U(mono_unity_liveness_allocate_struct) { ENTER; RET (calloc (1, 64)); }
|
||||
U(mono_unity_liveness_free_struct) { ENTER; free (P (0)); RETV; }
|
||||
U(mono_unity_liveness_finalize) { ENTER; RETV; }
|
||||
U(mono_unity_liveness_calculation_begin) { ENTER; RET (calloc (1, 64)); }
|
||||
U(mono_unity_liveness_calculation_end) { ENTER; free (P (0)); RETV; }
|
||||
U(mono_unity_liveness_calculation_from_root) { ENTER; RETV; }
|
||||
U(mono_unity_liveness_calculation_from_statics) { ENTER; RETV; }
|
||||
U(mono_unity_liveness_start_gc_world) { ENTER; RETV; }
|
||||
U(mono_unity_liveness_stop_gc_world) { ENTER; RETV; }
|
||||
U(mono_unity_managed_callstack) { ENTER; RET (0); }
|
||||
U(mono_unity_lock_dynamic_function_access_tables64) { ENTER; RETV; }
|
||||
U(mono_unity_unlock_dynamic_function_access_tables64) { ENTER; RETV; }
|
||||
U(mono_profiler_install) { ENTER; RETV; }
|
||||
U(mono_profiler_install_gc) { ENTER; RETV; }
|
||||
U(mono_profiler_set_events) { ENTER; RETV; }
|
||||
U(mono_profiler_load) { ENTER; RETV; }
|
||||
U(mono_profiler_create) { ENTER; static char handle [64]; RET (handle); }
|
||||
U(mono_profiler_enable_coverage) { ENTER; RET (0); }
|
||||
U(mono_profiler_set_coverage_filter_callback) { ENTER; RETV; }
|
||||
U(mono_profiler_get_coverage_data) { ENTER; RET (0); }
|
||||
U(mono_profiler_get_all_coverage_data) { ENTER; RETV; }
|
||||
U(mono_profiler_reset_coverage) { ENTER; RETV; }
|
||||
U(mono_profiler_reset_all_coverage) { ENTER; RETV; }
|
||||
|
||||
/* ---- guest callbacks ---- */
|
||||
|
||||
/* mono_assembly_foreach (func, user_data): func (assembly, user_data). */
|
||||
typedef struct { uint64_t fn, data; } GuestCb;
|
||||
static void
|
||||
assembly_cb (gpointer assembly, gpointer d)
|
||||
{
|
||||
GuestCb *c = d;
|
||||
guest_cb (c->fn, 2, (uintptr_t)assembly, c->data, 0, 0, 0);
|
||||
}
|
||||
U(mono_assembly_foreach) { ENTER; GuestCb c = { A (0), A (1) }; mono_assembly_foreach (assembly_cb, &c); RETV; }
|
||||
|
||||
/* mono_stack_walk[_no_il] (func, user_data): func (method, native_offset,
|
||||
* il_offset, managed, data) returns TRUE to stop. */
|
||||
static gboolean
|
||||
stack_cb (MonoMethod *m, gint32 native, gint32 il, gboolean managed, gpointer d)
|
||||
{
|
||||
GuestCb *c = d;
|
||||
return (int)guest_cb (c->fn, 5, (uintptr_t)m, (uint32_t)native, (uint32_t)il, managed, c->data) != 0;
|
||||
}
|
||||
U(mono_stack_walk) { ENTER; GuestCb c = { A (0), A (1) }; mono_stack_walk (stack_cb, &c); RETV; }
|
||||
U(mono_stack_walk_no_il) { ENTER; GuestCb c = { A (0), A (1) }; mono_stack_walk_no_il (stack_cb, &c); RETV; }
|
||||
|
||||
/* mono_trace_set_log_handler (callback, user_data): callback (domain, level,
|
||||
* message, fatal, user_data). */
|
||||
static GuestCb log_cb;
|
||||
static void
|
||||
log_handler (const char *domain, const char *level, const char *message, mono_bool fatal, void *d)
|
||||
{
|
||||
guest_cb (log_cb.fn, 5, (uintptr_t)domain, (uintptr_t)level, (uintptr_t)message, fatal, log_cb.data);
|
||||
}
|
||||
U(mono_trace_set_log_handler) { ENTER; log_cb.fn = A (0); log_cb.data = A (1); mono_trace_set_log_handler (log_handler, NULL); RETV; }
|
||||
|
||||
/* ---- where assemblies and native plugins come from ----
|
||||
* Unity's own BCL (mscorlib and the rest of its Mono profile) does not run
|
||||
* on upstream Mono: .NET's CoreLib and Framework facades (GEXMONO_ASSEMBLIES)
|
||||
* stand in for it. Unity's game assemblies come from where it says. */
|
||||
|
||||
char *gexmono_unity_managed_dir;
|
||||
|
||||
static void
|
||||
set_assemblies_path (const char *unity_path)
|
||||
{
|
||||
const char *ours = getenv ("GEXMONO_ASSEMBLIES");
|
||||
GString *s = g_string_new (ours ? ours : "");
|
||||
if (unity_path && *unity_path) {
|
||||
if (s->len)
|
||||
g_string_append_c (s, ':');
|
||||
g_string_append (s, unity_path);
|
||||
g_free (gexmono_unity_managed_dir);
|
||||
gexmono_unity_managed_dir = g_strdup (unity_path);
|
||||
char *colon = strchr (gexmono_unity_managed_dir, ':');
|
||||
if (colon)
|
||||
*colon = 0;
|
||||
}
|
||||
mono_set_assemblies_path (s->str);
|
||||
g_string_free (s, TRUE);
|
||||
}
|
||||
|
||||
U(mono_set_dirs) { ENTER; set_assemblies_path (P (0)); RETV; }
|
||||
U(mono_set_assemblies_path) { ENTER; set_assemblies_path (P (0)); RETV; }
|
||||
U(mono_set_assemblies_path_null_separated)
|
||||
{
|
||||
ENTER;
|
||||
GString *s = g_string_new ("");
|
||||
for (const char *p = P (0); p && *p; p += strlen (p) + 1) {
|
||||
if (s->len)
|
||||
g_string_append_c (s, ':');
|
||||
g_string_append (s, p);
|
||||
}
|
||||
set_assemblies_path (s->str);
|
||||
g_string_free (s, TRUE);
|
||||
RETV;
|
||||
}
|
||||
|
||||
/* Unity's find-plugin callback, const char *(*)(const char *name): the path
|
||||
* of a native plugin; dl_load (gexmono-provider.c) asks it first. */
|
||||
uint64_t gexmono_find_plugin;
|
||||
U(mono_set_find_plugin_callback) { ENTER; gexmono_find_plugin = A (0); RETV; }
|
||||
|
||||
/* Unity's own dl fallback (load, symbol, close, user_data), kept for
|
||||
* dl_load/dl_symbol after the guest's dlopen (gexmono-provider.c). */
|
||||
uint64_t gexmono_dl_fallback [4];
|
||||
U(mono_dl_fallback_register)
|
||||
{
|
||||
ENTER;
|
||||
for (int i = 0; i < 4; i++)
|
||||
gexmono_dl_fallback [i] = A (i);
|
||||
RET (calloc (1, 16));
|
||||
}
|
||||
|
||||
#define L(n) gexp_##n,
|
||||
__attribute__((used)) gexp_body_t const gexmono_unity_adapters [] = {
|
||||
L(mono_unity_object_header_size) L(mono_unity_array_object_header_size)
|
||||
L(mono_unity_offset_of_array_length_in_array_object_header) L(mono_unity_offset_of_array_bounds_in_array_object_header)
|
||||
L(mono_unity_allocation_granularity) L(mono_class_get_userdata) L(mono_class_set_userdata)
|
||||
L(mono_class_get_userdata_offset) L(mono_class_is_blittable) L(mono_class_is_generic) L(mono_class_is_inflated)
|
||||
L(mono_unity_class_is_interface) L(mono_unity_class_is_abstract) L(mono_unity_class_is_inited)
|
||||
L(mono_unity_class_has_failure) L(mono_unity_class_get_data_size) L(mono_unity_class_is_open_constructed_type)
|
||||
L(mono_unity_class_try_get_vtable) L(mono_unity_class_field_is_literal) L(mono_unity_class_get_generic_type_definition)
|
||||
L(mono_unity_class_get) L(mono_unity_class_get_checked) L(mono_unity_field_from_token_checked)
|
||||
L(mono_unity_get_method_checked) L(mono_unity_type_is_pointer_type) L(mono_unity_type_is_static) L(mono_type_get_attrs)
|
||||
L(mono_unity_vtable_get_static_field_data) L(mono_method_signature_checked) L(mono_method_signature_checked_slow)
|
||||
L(mono_unity_type_get_name_full_chunked) L(mono_custom_attrs_get_attrs) L(mono_custom_attrs_construct_by_type)
|
||||
L(mono_unity_custom_attrs_construct) L(mono_unity_array_new_2d) L(mono_unity_array_new_3d)
|
||||
L(mono_unity_string_empty_wrapper) L(mono_unity_error_convert_to_exception)
|
||||
L(mono_unity_loader_get_last_error_and_error_prepare_exception) L(mono_unity_g_free) L(mono_assembly_name_parse)
|
||||
L(mono_unity_set_data_dir) L(mono_unity_set_embeddinghostname) L(mono_unity_domain_set_config)
|
||||
L(mono_unity_runtime_set_main_args) L(mono_unity_install_memory_callbacks) L(mono_unity_install_unitytls_interface)
|
||||
L(mono_unity_set_vprintf_func) L(mono_unity_jit_cleanup) L(mono_set_defaults) L(mono_parse_default_optimizations)
|
||||
L(mono_verifier_set_mode) L(mono_set_ignore_version_and_key_when_finding_assemblies_already_loaded)
|
||||
L(mono_runtime_unhandled_exception_policy_set) L(mono_threads_set_shutting_down)
|
||||
L(mono_thread_suspend_all_other_threads) L(mono_thread_pool_cleanup) L(mono_thread_push_appdomain_ref)
|
||||
L(mono_thread_pop_appdomain_ref) L(mono_thread_has_sufficient_execution_stack) L(mono_gchandle_is_in_domain)
|
||||
L(mono_gchandle_is_in_domain_v2) L(mono_pmip) L(mono_debug_lookup_source_location_by_il)
|
||||
L(mono_unity_gc_set_mode) L(mono_unity_gc_disable) L(mono_unity_gc_enable) L(mono_unity_gc_is_disabled)
|
||||
L(mono_gc_is_incremental) L(mono_gc_set_incremental) L(mono_gc_collect_a_little) L(mono_gc_get_max_time_slice_ns)
|
||||
L(mono_gc_set_max_time_slice_ns) L(mono_gc_start_incremental_collection) L(mono_gc_set_heap_validate_frequency)
|
||||
L(mono_gc_set_heap_verifier_callback) L(mono_unity_stop_gc_world) L(mono_unity_start_gc_world)
|
||||
L(mono_unity_heap_validation_from_statics) L(mono_unity_assembly_mempool_chunk_foreach)
|
||||
L(mono_unity_domain_mempool_chunk_foreach) L(mono_unity_root_domain_mempool_chunk_foreach)
|
||||
L(mono_unity_image_set_mempool_chunk_foreach) L(mono_unity_gc_handles_foreach_get_target) L(mono_unity_gc_heap_foreach)
|
||||
L(mono_unity_class_for_each) L(mono_unity_capture_memory_snapshot) L(mono_unity_free_captured_memory_snapshot)
|
||||
L(mono_unity_liveness_allocate_struct) L(mono_unity_liveness_free_struct) L(mono_unity_liveness_finalize)
|
||||
L(mono_unity_liveness_calculation_begin) L(mono_unity_liveness_calculation_end)
|
||||
L(mono_unity_liveness_calculation_from_root) L(mono_unity_liveness_calculation_from_statics)
|
||||
L(mono_unity_liveness_start_gc_world) L(mono_unity_liveness_stop_gc_world) L(mono_unity_managed_callstack)
|
||||
L(mono_unity_lock_dynamic_function_access_tables64) L(mono_unity_unlock_dynamic_function_access_tables64)
|
||||
L(mono_profiler_install) L(mono_profiler_install_gc) L(mono_profiler_set_events) L(mono_profiler_load)
|
||||
L(mono_profiler_create) L(mono_profiler_enable_coverage) L(mono_profiler_set_coverage_filter_callback)
|
||||
L(mono_profiler_get_coverage_data) L(mono_profiler_get_all_coverage_data) L(mono_profiler_reset_coverage)
|
||||
L(mono_profiler_reset_all_coverage) L(mono_assembly_foreach) L(mono_stack_walk) L(mono_stack_walk_no_il)
|
||||
L(mono_trace_set_log_handler) L(mono_set_dirs) L(mono_set_assemblies_path) L(mono_set_assemblies_path_null_separated)
|
||||
L(mono_set_find_plugin_callback) L(mono_dl_fallback_register)
|
||||
0
|
||||
};
|
||||
@@ -150,6 +150,64 @@ index 8d5fba2b6..6cc1e1aad 100644
|
||||
#endif // !HOST_WASI
|
||||
+
|
||||
+#endif /* !HOST_GEX */
|
||||
diff --git a/src/mono/mono/metadata/class-accessors.c b/src/mono/mono/metadata/class-accessors.c
|
||||
index 1a89c07ce..5fbcd696a 100644
|
||||
--- a/src/mono/mono/metadata/class-accessors.c
|
||||
+++ b/src/mono/mono/metadata/class-accessors.c
|
||||
@@ -717,3 +717,36 @@ mono_wasm_jit_class_vtable_off (void)
|
||||
{
|
||||
return (int) G_STRUCT_OFFSET (MonoClass, vtable);
|
||||
}
|
||||
+
|
||||
+#ifdef HOST_GEX
|
||||
+/* gex (noita-wasm docs/unity-dotnet.md): Unity's per-class pointer. */
|
||||
+void *
|
||||
+gex_class_get_userdata (MonoClass *klass)
|
||||
+{
|
||||
+ return klass->unity_user_data;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+gex_class_set_userdata (MonoClass *klass, void *userdata)
|
||||
+{
|
||||
+ klass->unity_user_data = userdata;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+gex_class_get_userdata_offset (void)
|
||||
+{
|
||||
+ return (int)offsetof (MonoClass, unity_user_data);
|
||||
+}
|
||||
+
|
||||
+gboolean
|
||||
+gex_class_is_inited (MonoClass *klass)
|
||||
+{
|
||||
+ return m_class_is_inited (klass);
|
||||
+}
|
||||
+
|
||||
+guint32
|
||||
+gex_class_get_data_size (MonoClass *klass)
|
||||
+{
|
||||
+ return mono_class_data_size (klass);
|
||||
+}
|
||||
+#endif
|
||||
diff --git a/src/mono/mono/metadata/class-private-definition.h b/src/mono/mono/metadata/class-private-definition.h
|
||||
index 005cd0593..d47afef76 100644
|
||||
--- a/src/mono/mono/metadata/class-private-definition.h
|
||||
+++ b/src/mono/mono/metadata/class-private-definition.h
|
||||
@@ -130,6 +130,12 @@ struct _MonoClass {
|
||||
MonoPropertyBag infrequent_data;
|
||||
|
||||
void *variant_search_table;
|
||||
+
|
||||
+#ifdef HOST_GEX
|
||||
+ /* gex: Unity's per-class pointer (mono_class_get/set_userdata), which
|
||||
+ * UnityPlayer also reads at its offset (mono_class_get_userdata_offset). */
|
||||
+ void *unity_user_data;
|
||||
+#endif
|
||||
};
|
||||
|
||||
struct _MonoClassDef {
|
||||
diff --git a/src/mono/mono/metadata/sgen-mono.c b/src/mono/mono/metadata/sgen-mono.c
|
||||
index 787ca8c2f..ed1afb5a7 100644
|
||||
--- a/src/mono/mono/metadata/sgen-mono.c
|
||||
|
||||
Reference in new issue
Block a user