From 06aceb7015f3bd2ff019ef5920d2354eb2ea2c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksey=20Kliger=20=28=CE=BBgeek=29?= Date: Fri, 26 Aug 2022 20:33:35 -0400 Subject: [PATCH] Revert "[MONO] Move marshal-ilgen into a component (#71203)" (#74675) This reverts commit de32c4466489090fdd41574d1be2945fd03ab7f2. --- .../Directory.Build.props | 7 - .../System.Diagnostics.Tracing.Tests.csproj | 2 +- src/mono/mono.proj | 3 +- src/mono/mono/component/CMakeLists.txt | 53 +- .../mono/component/marshal-ilgen-noilgen.c | 186 -- .../mono/component/marshal-ilgen-noilgen.h | 11 - src/mono/mono/component/marshal-ilgen-stub.c | 41 - src/mono/mono/component/marshal-ilgen.c | 2861 ----------------- src/mono/mono/metadata/CMakeLists.txt | 3 +- src/mono/mono/metadata/components.c | 6 - src/mono/mono/metadata/components.h | 11 +- src/mono/mono/metadata/marshal-ilgen.c | 2830 ++++++++++++++++ .../{component => metadata}/marshal-ilgen.h | 34 +- src/mono/mono/metadata/marshal-lightweight.c | 6 +- src/mono/mono/metadata/marshal-lightweight.h | 1 - src/mono/mono/metadata/marshal-noilgen.c | 190 +- src/mono/mono/metadata/marshal-noilgen.h | 15 - src/mono/mono/metadata/marshal.c | 70 +- src/mono/mono/metadata/marshal.h | 57 - src/mono/mono/mini/CMakeLists.txt | 2 +- .../msbuild/android/build/AndroidApp.targets | 5 - src/mono/msbuild/apple/build/AppleApp.targets | 6 - src/mono/sample/iOS/Program.csproj | 4 - src/mono/wasm/build/WasmApp.InTree.props | 1 - src/mono/wasm/build/WasmApp.Native.targets | 3 - src/mono/wasm/runtime/CMakeLists.txt | 1 - src/tests/build.proj | 4 +- 27 files changed, 3047 insertions(+), 3366 deletions(-) delete mode 100644 src/mono/mono/component/marshal-ilgen-noilgen.c delete mode 100644 src/mono/mono/component/marshal-ilgen-noilgen.h delete mode 100644 src/mono/mono/component/marshal-ilgen-stub.c delete mode 100644 src/mono/mono/component/marshal-ilgen.c create mode 100644 src/mono/mono/metadata/marshal-ilgen.c rename src/mono/mono/{component => metadata}/marshal-ilgen.h (73%) delete mode 100644 src/mono/mono/metadata/marshal-noilgen.h diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props index 61f577981d136..07d77161002bc 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props @@ -205,13 +205,6 @@ - - - - - - - diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj index 75300d8460ba8..35b1a833abb56 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj +++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj @@ -6,7 +6,7 @@ true - diagnostics_tracing;marshal-ilgen + diagnostics_tracing diff --git a/src/mono/mono.proj b/src/mono/mono.proj index 26ca5545d761b..38731e968660a 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -733,8 +733,7 @@ - - + diff --git a/src/mono/mono/component/CMakeLists.txt b/src/mono/mono/component/CMakeLists.txt index d83c9144af07f..7c864322f5f37 100644 --- a/src/mono/mono/component/CMakeLists.txt +++ b/src/mono/mono/component/CMakeLists.txt @@ -6,12 +6,9 @@ set(MONO_EVENTPIPE_GEN_INCLUDE_PATH "${CMAKE_CURRENT_BINARY_DIR}/eventpipe") set(MONO_HOT_RELOAD_COMPONENT_NAME "hot_reload") set(MONO_DIAGNOSTICS_TRACING_COMPONENT_NAME "diagnostics_tracing") set(MONO_DEBUGGER_COMPONENT_NAME "debugger") -set(MONO_MARSHAL_ILGEN_COMPONENT_NAME "marshal-ilgen") # a list of every component. set(components "") -# a list of components needed by the AOT compiler -set(components_for_aot "") # the sources for each individiable component define a new # component_name-sources list for each component, and a @@ -82,53 +79,17 @@ set(${MONO_DIAGNOSTICS_TRACING_COMPONENT_NAME}-dependencies ${MONO_DIAGNOSTICS_TRACING_COMPONENT_NAME}-gen-sources ) -# marshal-ilgen -list(APPEND components - ${MONO_MARSHAL_ILGEN_COMPONENT_NAME} -) -list(APPEND components_for_aot - ${MONO_MARSHAL_ILGEN_COMPONENT_NAME} -) - -set(${MONO_MARSHAL_ILGEN_COMPONENT_NAME}-sources - ${MONO_COMPONENT_PATH}/marshal-ilgen.c - ${MONO_COMPONENT_PATH}/marshal-ilgen.h - ${MONO_COMPONENT_PATH}/marshal-ilgen-noilgen.c - ${MONO_COMPONENT_PATH}/marshal-ilgen-noilgen.h -) - -# For every component not build into the AOT compiler, build the stub instead -set(stubs_for_aot "") -foreach (component IN LISTS components) - if (NOT (component IN_LIST components_for_aot)) - list(APPEND stubs_for_aot "${component}") - endif() -endforeach() - - -set(${MONO_MARSHAL_ILGEN_COMPONENT_NAME}-stub-sources - ${MONO_COMPONENT_PATH}/marshal-ilgen-stub.c -) - -if (AOT_COMPONENTS) - set(components_to_build ${components_for_aot}) - set(stubs_to_build ${stubs_for_aot}) -else() - set(components_to_build ${components}) - set(stubs_to_build ${components}) -endif() - # from here down, all the components are treated in the same way #define a library for each component and component stub function(define_component_libs) # NOTE: keep library naming pattern in sync with RuntimeComponentManifest.targets - if (AOT_COMPONENTS OR NOT DISABLE_LIBS ) - foreach(component IN LISTS components_to_build) + if (NOT DISABLE_LIBS) + foreach(component IN LISTS components) add_library("mono-component-${component}-static" STATIC $) install(TARGETS "mono-component-${component}-static" LIBRARY) endforeach() - foreach(component IN LISTS stubs_to_build) + foreach(component IN LISTS components) add_library("mono-component-${component}-stub-static" STATIC $) install(TARGETS "mono-component-${component}-stub-static" LIBRARY) endforeach() @@ -142,7 +103,7 @@ target_sources(component_base INTERFACE ) target_link_libraries(component_base INTERFACE monoapi) -if(NOT AOT_COMPONENTS AND (DISABLE_COMPONENTS OR DISABLE_LIBS)) +if(DISABLE_COMPONENTS OR DISABLE_LIBS) set(DISABLE_COMPONENT_OBJECTS 1) endif() @@ -162,7 +123,7 @@ endforeach() if(NOT DISABLE_COMPONENTS AND NOT STATIC_COMPONENTS) # define a shared library for each component - foreach(component IN LISTS components_to_build) + foreach(component IN LISTS components) # NOTE: keep library naming pattern in sync with RuntimeComponentManifest.targets if(HOST_WIN32) add_library("mono-component-${component}" SHARED "${${component}-sources}") @@ -194,14 +155,14 @@ if(NOT DISABLE_COMPONENTS AND NOT STATIC_COMPONENTS) #define a library for each component and component stub define_component_libs() -elseif(AOT_COMPONENTS OR (NOT DISABLE_COMPONENTS AND STATIC_COMPONENTS)) +elseif(NOT DISABLE_COMPONENTS AND STATIC_COMPONENTS) #define a library for each component and component stub define_component_libs() # define a list of mono-components objects for mini if building a shared libmono with static-linked components set(mono-components-objects "") - foreach(component IN LISTS components_to_build) + foreach(component IN LISTS components) list(APPEND mono-components-objects $) endforeach() diff --git a/src/mono/mono/component/marshal-ilgen-noilgen.c b/src/mono/mono/component/marshal-ilgen-noilgen.c deleted file mode 100644 index 6cf9dfd5ac628..0000000000000 --- a/src/mono/mono/component/marshal-ilgen-noilgen.c +++ /dev/null @@ -1,186 +0,0 @@ -#include "mono/component/marshal-ilgen.h" -#include "mono/component/marshal-ilgen-noilgen.h" - -#ifndef ENABLE_ILGEN -static int -emit_marshal_array_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - MonoType *object_type = mono_get_object_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = object_type; - break; - case MARSHAL_ACTION_MANAGED_CONV_IN: - *conv_arg_type = int_type; - break; - } - return conv_arg; -} - -static int -emit_marshal_ptr_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - return conv_arg; -} -#endif - -#if !defined(ENABLE_ILGEN) || defined(DISABLE_NONBLITTABLE) -static int -emit_marshal_vtype_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - return conv_arg; -} - -static int -emit_marshal_string_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = int_type; - break; - case MARSHAL_ACTION_MANAGED_CONV_IN: - *conv_arg_type = int_type; - break; - } - return conv_arg; -} - -static int -emit_marshal_safehandle_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - if (action == MARSHAL_ACTION_CONV_IN) - *conv_arg_type = int_type; - return conv_arg; -} - -static int -emit_marshal_handleref_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - if (action == MARSHAL_ACTION_CONV_IN) - *conv_arg_type = int_type; - return conv_arg; -} - -static int -emit_marshal_object_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - if (action == MARSHAL_ACTION_CONV_IN) - *conv_arg_type = int_type; - return conv_arg; -} - -static int -emit_marshal_variant_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - g_assert_not_reached (); -} - -static int -emit_marshal_asany_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - return conv_arg; -} - -static int -emit_marshal_boolean_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: - if (m_type_is_byref (t)) - *conv_arg_type = int_type; - else - *conv_arg_type = mono_marshal_boolean_conv_in_get_local_type (spec, NULL); - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: { - MonoClass* conv_arg_class = mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec, NULL); - if (m_type_is_byref (t)) - *conv_arg_type = m_class_get_this_arg (conv_arg_class); - else - *conv_arg_type = m_class_get_byval_arg (conv_arg_class); - break; - } - - } - return conv_arg; -} - -static int -emit_marshal_char_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - return conv_arg; -} - -static int -emit_marshal_custom_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - if (action == MARSHAL_ACTION_CONV_IN && t->type == MONO_TYPE_VALUETYPE) - *conv_arg_type = int_type; - return conv_arg; -} -#endif - -#ifndef ENABLE_ILGEN - -void -mono_marshal_noilgen_init_heavyweight (void) -{ - MonoMarshalILgenCallbacks ilgen_cb; - - ilgen_cb.version = MONO_MARSHAL_CALLBACKS_VERSION; - ilgen_cb.emit_marshal_array = emit_marshal_array_noilgen; - ilgen_cb.emit_marshal_vtype = emit_marshal_vtype_noilgen; - ilgen_cb.emit_marshal_string = emit_marshal_string_noilgen; - ilgen_cb.emit_marshal_safehandle = emit_marshal_safehandle_noilgen; - ilgen_cb.emit_marshal_handleref = emit_marshal_handleref_noilgen; - ilgen_cb.emit_marshal_object = emit_marshal_object_noilgen; - ilgen_cb.emit_marshal_variant = emit_marshal_variant_noilgen; - ilgen_cb.emit_marshal_asany = emit_marshal_asany_noilgen; - ilgen_cb.emit_marshal_boolean = emit_marshal_boolean_noilgen; - ilgen_cb.emit_marshal_custom = emit_marshal_custom_noilgen; - ilgen_cb.emit_marshal_ptr = emit_marshal_ptr_noilgen; - - ilgen_cb.emit_marshal_char = emit_marshal_char_noilgen; - mono_install_marshal_callbacks_ilgen(&ilgen_cb); -} - -#endif \ No newline at end of file diff --git a/src/mono/mono/component/marshal-ilgen-noilgen.h b/src/mono/mono/component/marshal-ilgen-noilgen.h deleted file mode 100644 index 5e877c223833c..0000000000000 --- a/src/mono/mono/component/marshal-ilgen-noilgen.h +++ /dev/null @@ -1,11 +0,0 @@ -/** - * \file - * Copyright 2022 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ -#ifndef __MARSHAL_ILGEN_NOILGEN_H__ -#define __MARSHAL_ILGEN_NOILGEN_H__ - -void mono_marshal_noilgen_init_heavyweight (void); - -#endif // __MARSHAL_ILGEN_NOILGEN_H__ \ No newline at end of file diff --git a/src/mono/mono/component/marshal-ilgen-stub.c b/src/mono/mono/component/marshal-ilgen-stub.c deleted file mode 100644 index 8182c95b7e286..0000000000000 --- a/src/mono/mono/component/marshal-ilgen-stub.c +++ /dev/null @@ -1,41 +0,0 @@ - -#include -#include -#include - -static bool -marshal_ilgen_available (void) -{ - return false; -} - -static int -stub_emit_marshal_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action, MonoMarshalLightweightCallbacks* lightweigth_cb) -{ - return 0; -} - -static void -mono_component_marshal_ilgen_stub_init(void) -{ -} - -static void -stub_mono_marshal_ilgen_install_callbacks_mono (IlgenCallbacksToMono *callbacks) -{ -} - -static MonoComponentMarshalILgen component_func_table = { - { MONO_COMPONENT_ITF_VERSION, &marshal_ilgen_available }, - mono_component_marshal_ilgen_stub_init, - stub_emit_marshal_ilgen, - stub_mono_marshal_ilgen_install_callbacks_mono -}; - -MonoComponentMarshalILgen* -mono_component_marshal_ilgen_init (void) -{ - return &component_func_table; -} diff --git a/src/mono/mono/component/marshal-ilgen.c b/src/mono/mono/component/marshal-ilgen.c deleted file mode 100644 index e6deeea556409..0000000000000 --- a/src/mono/mono/component/marshal-ilgen.c +++ /dev/null @@ -1,2861 +0,0 @@ - -#include "mono/metadata/debug-helpers.h" -#include "metadata/marshal.h" -#include "component/marshal-ilgen.h" -#include "mono/component/marshal-ilgen.h" -#include "mono/component/marshal-ilgen-noilgen.h" -#include "metadata/marshal-lightweight.h" -#include "metadata/marshal-shared.h" -#include "metadata/method-builder-ilgen.h" -#include "metadata/custom-attrs-internals.h" -#include "metadata/class-init.h" -#include "mono/metadata/class-internals.h" -#include "metadata/reflection-internals.h" -#include "mono/metadata/handle.h" -#include "mono/component/component.h" - -#define OPDEF(a,b,c,d,e,f,g,h,i,j) \ - a = i, - -enum { -#include "mono/cil/opcode.def" - LAST = 0xff -}; -#undef OPDEF - -#define mono_mb_emit_jit_icall(mb, name) (cb_to_mono->mb_emit_icall_id ((mb), MONO_JIT_ICALL_ ## name)) - -static GENERATE_GET_CLASS_WITH_CACHE (date_time, "System", "DateTime"); -static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, "System.Runtime.InteropServices", "ICustomMarshaler"); - -static void emit_string_free_icall (MonoMethodBuilder *mb, MonoMarshalConv conv); - -static void mono_marshal_ilgen_legacy_init (void); - -static gboolean ilgen_cb_inited = FALSE; -static MonoMarshalILgenCallbacks ilgen_marshal_cb; - -static IlgenCallbacksToMono *cb_to_mono; - -static bool -marshal_ilgen_available (void) -{ - return true; -} - -static MonoComponentMarshalILgen component_func_table = { - { MONO_COMPONENT_ITF_VERSION, &marshal_ilgen_available }, - &mono_marshal_ilgen_init, - &mono_emit_marshal_ilgen, - &mono_marshal_ilgen_install_callbacks_mono -}; - - -MonoComponentMarshalILgen* -mono_component_marshal_ilgen_init (void) -{ - return &component_func_table; -} - -void -mono_install_marshal_callbacks_ilgen (MonoMarshalILgenCallbacks *cb) -{ - g_assert (!ilgen_cb_inited); - g_assert (cb->version == MONO_MARSHAL_CALLBACKS_VERSION); - memcpy (&ilgen_marshal_cb, cb, sizeof (MonoMarshalILgenCallbacks)); - ilgen_cb_inited = TRUE; -} - -void -mono_marshal_ilgen_install_callbacks_mono (IlgenCallbacksToMono *callbacks) -{ - cb_to_mono = callbacks; -} - -static void -emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var) -{ - /* Call DestroyStructure */ - /* FIXME: Only do this if needed */ - cb_to_mono->mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - cb_to_mono->mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); - cb_to_mono->mb_emit_ldloc (mb, struct_var); - mono_mb_emit_jit_icall (mb, mono_struct_delete_old); -} - -static int -emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - MonoClass *klass = mono_class_from_mono_type_internal (t); - MonoMarshalNative encoding; - - encoding = cb_to_mono->get_string_encoding (m->piinfo, spec); - MonoType *int_type = cb_to_mono->get_int_type (); - MonoType *object_type = cb_to_mono->get_object_type (); - - MonoClass *eklass = m_class_get_element_class (klass); - - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = object_type; - conv_arg = cb_to_mono->mb_add_local (mb, object_type); - - if (m_class_is_blittable (eklass)) { - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL)); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - } else { -#ifdef DISABLE_NONBLITTABLE - char *msg = g_strdup ("Non-blittable marshalling conversion is disabled"); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); -#else - guint32 label1, label2, label3; - int index_var, src_var, dest_ptr, esize; - MonoMarshalConv conv; - gboolean is_string = FALSE; - - dest_ptr = cb_to_mono->mb_add_local (mb, int_type); - - if (eklass == cb_to_mono->mono_defaults->string_class) { - is_string = TRUE; - conv = cb_to_mono->get_string_to_ptr_conv (m->piinfo, spec); - } - else if (eklass == cb_to_mono->try_get_stringbuilder_class ()) { - is_string = TRUE; - conv = cb_to_mono->get_stringbuilder_to_ptr_conv (m->piinfo, spec); - } - else - conv = MONO_MARSHAL_CONV_INVALID; - - if (is_string && conv == MONO_MARSHAL_CONV_INVALID) { - char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - src_var = cb_to_mono->mb_add_local (mb, object_type); - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - cb_to_mono->mb_emit_stloc (mb, src_var); - - /* Check null */ - cb_to_mono->mb_emit_ldloc (mb, src_var); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - cb_to_mono->mb_emit_ldloc (mb, src_var); - label1 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - if (is_string) - esize = TARGET_SIZEOF_VOID_P; - else if (eklass == cb_to_mono->mono_defaults->char_class) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/ - esize = cb_to_mono->pinvoke_is_unicode (m->piinfo) ? 2 : 1; - else - esize = cb_to_mono->class_native_size (eklass, NULL); - - /* allocate space for the native struct and store the address */ - cb_to_mono->mb_emit_icon (mb, esize); - cb_to_mono->mb_emit_ldloc (mb, src_var); - cb_to_mono->mb_emit_byte (mb, CEE_LDLEN); - - if (eklass == cb_to_mono->mono_defaults->string_class) { - /* Make the array bigger for the terminating null */ - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_1); - cb_to_mono->mb_emit_byte (mb, CEE_ADD); - } - cb_to_mono->mb_emit_byte (mb, CEE_MUL); - cb_to_mono->mb_emit_byte (mb, CEE_PREFIX1); - cb_to_mono->mb_emit_byte (mb, CEE_LOCALLOC); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_stloc (mb, dest_ptr); - - /* Emit marshalling loop */ - index_var = cb_to_mono->mb_add_local (mb, int_type); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_0); - cb_to_mono->mb_emit_stloc (mb, index_var); - label2 = cb_to_mono->mb_get_label (mb); - cb_to_mono->mb_emit_ldloc (mb, index_var); - cb_to_mono->mb_emit_ldloc (mb, src_var); - cb_to_mono->mb_emit_byte (mb, CEE_LDLEN); - label3 = cb_to_mono->mb_emit_branch (mb, CEE_BGE); - - /* Emit marshalling code */ - - if (is_string) { - int stind_op; - cb_to_mono->mb_emit_ldloc (mb, dest_ptr); - cb_to_mono->mb_emit_ldloc (mb, src_var); - cb_to_mono->mb_emit_ldloc (mb, index_var); - cb_to_mono->mb_emit_byte (mb, CEE_LDELEM_REF); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, &stind_op)); - cb_to_mono->mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); - } else { - /* set the src_ptr */ - cb_to_mono->mb_emit_ldloc (mb, src_var); - cb_to_mono->mb_emit_ldloc (mb, index_var); - cb_to_mono->mb_emit_op (mb, CEE_LDELEMA, eklass); - cb_to_mono->mb_emit_stloc (mb, 0); - - /* set dst_ptr */ - cb_to_mono->mb_emit_ldloc (mb, dest_ptr); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv_full (mb, eklass, FALSE, 0, eklass == cb_to_mono->mono_defaults->char_class ? encoding : (MonoMarshalNative)-1); - } - - cb_to_mono->mb_emit_add_to_local (mb, GINT_TO_UINT16 (index_var), 1); - cb_to_mono->mb_emit_add_to_local (mb, GINT_TO_UINT16 (dest_ptr), esize); - - cb_to_mono->mb_emit_branch_label (mb, CEE_BR, label2); - - cb_to_mono->mb_patch_branch (mb, label3); - - if (eklass == cb_to_mono->mono_defaults->string_class) { - /* Null terminate */ - cb_to_mono->mb_emit_ldloc (mb, dest_ptr); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_0); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_I); - } - - cb_to_mono->mb_patch_branch (mb, label1); -#endif - } - - break; - - case MARSHAL_ACTION_CONV_OUT: { -#ifndef DISABLE_NONBLITTABLE - gboolean need_convert, need_free; - /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */ - need_convert = ((eklass == cb_to_mono->mono_defaults->char_class) && (encoding == MONO_NATIVE_LPWSTR)) || (eklass == cb_to_mono->try_get_stringbuilder_class ()) || (t->attrs & PARAM_ATTRIBUTE_OUT); - need_free = cb_to_mono->need_free (m_class_get_byval_arg (eklass), m->piinfo, spec); - - if ((t->attrs & PARAM_ATTRIBUTE_OUT) && spec && spec->native == MONO_NATIVE_LPARRAY && spec->data.array_data.param_num != -1) { - int param_num = spec->data.array_data.param_num; - MonoType *param_type; - - param_type = m->sig->params [param_num]; - - if (m_type_is_byref (param_type) && param_type->type != MONO_TYPE_I4) { - char *msg = g_strdup ("Not implemented."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - if (m_type_is_byref (t) ) { - cb_to_mono->mb_emit_ldarg (mb, argnum); - - /* Create the managed array */ - cb_to_mono->mb_emit_ldarg (mb, param_num); - if (m_type_is_byref (m->sig->params [param_num])) - // FIXME: Support other types - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I4); - cb_to_mono->mb_emit_byte (mb, CEE_CONV_OVF_I); - cb_to_mono->mb_emit_op (mb, CEE_NEWARR, eklass); - /* Store into argument */ - cb_to_mono->mb_emit_byte (mb, CEE_STIND_REF); - } - } - - if (need_convert || need_free) { - /* FIXME: Optimize blittable case */ - guint32 label1, label2, label3; - int index_var, src_ptr, loc, esize; - - if ((eklass == cb_to_mono->try_get_stringbuilder_class ()) || (eklass == cb_to_mono->mono_defaults->string_class)) - esize = TARGET_SIZEOF_VOID_P; - else if (eklass == cb_to_mono->mono_defaults->char_class) - esize = cb_to_mono->pinvoke_is_unicode (m->piinfo) ? 2 : 1; - else - esize = cb_to_mono->class_native_size (eklass, NULL); - src_ptr = cb_to_mono->mb_add_local (mb, int_type); - loc = cb_to_mono->mb_add_local (mb, int_type); - - /* Check null */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - label1 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_stloc (mb, src_ptr); - - /* Emit marshalling loop */ - index_var = cb_to_mono->mb_add_local (mb, int_type); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_0); - cb_to_mono->mb_emit_stloc (mb, index_var); - label2 = cb_to_mono->mb_get_label (mb); - cb_to_mono->mb_emit_ldloc (mb, index_var); - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_REF); - cb_to_mono->mb_emit_byte (mb, CEE_LDLEN); - label3 = cb_to_mono->mb_emit_branch (mb, CEE_BGE); - - /* Emit marshalling code */ - - if (eklass == cb_to_mono->try_get_stringbuilder_class ()) { - gboolean need_free2; - MonoMarshalConv conv = cb_to_mono->get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2); - - g_assert (conv != MONO_MARSHAL_CONV_INVALID); - - /* dest */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - cb_to_mono->mb_emit_ldloc (mb, index_var); - cb_to_mono->mb_emit_byte (mb, CEE_LDELEM_REF); - - /* src */ - cb_to_mono->mb_emit_ldloc (mb, src_ptr); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, NULL)); - - if (need_free) { - /* src */ - cb_to_mono->mb_emit_ldloc (mb, src_ptr); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - - mono_mb_emit_jit_icall (mb, mono_marshal_free); - } - } - else if (eklass == cb_to_mono->mono_defaults->string_class) { - if (need_free) { - /* src */ - cb_to_mono->mb_emit_ldloc (mb, src_ptr); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - - mono_mb_emit_jit_icall (mb, mono_marshal_free); - } - } - else { - if (need_convert) { - /* set the src_ptr */ - cb_to_mono->mb_emit_ldloc (mb, src_ptr); - cb_to_mono->mb_emit_stloc (mb, 0); - - /* set dst_ptr */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_REF); - cb_to_mono->mb_emit_ldloc (mb, index_var); - cb_to_mono->mb_emit_op (mb, CEE_LDELEMA, eklass); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == cb_to_mono->mono_defaults->char_class ? encoding : (MonoMarshalNative)-1); - } - - if (need_free) { - cb_to_mono->mb_emit_ldloc (mb, src_ptr); - cb_to_mono->mb_emit_stloc (mb, loc); - - emit_struct_free (mb, eklass, loc); - } - } - - cb_to_mono->mb_emit_add_to_local (mb, GINT_TO_UINT16 (index_var), 1); - cb_to_mono->mb_emit_add_to_local (mb, GINT_TO_UINT16 (src_ptr), esize); - - cb_to_mono->mb_emit_branch_label (mb, CEE_BR, label2); - - cb_to_mono->mb_patch_branch (mb, label1); - cb_to_mono->mb_patch_branch (mb, label3); - } -#endif - - if (m_class_is_blittable (eklass)) { - /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */ - - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_REF); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL)); - } - - break; - } - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - else - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_RESULT: { - cb_to_mono->mb_emit_byte (mb, CEE_POP); - char *msg = g_strdup_printf ("Cannot marshal 'return value': Invalid managed/unmanaged type combination."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_IN: { - guint32 label1, label2, label3; - int index_var, src_ptr, esize, param_num, num_elem; - MonoMarshalConv conv; - gboolean is_string = FALSE; - - conv_arg = cb_to_mono->mb_add_local (mb, object_type); - *conv_arg_type = int_type; - - if (m_type_is_byref (t)) { - char *msg = g_strdup ("Byref array marshalling to managed code is not implemented."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - if (!spec) { - char *msg = g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - - switch (spec->native) { - case MONO_NATIVE_LPARRAY: - break; - case MONO_NATIVE_SAFEARRAY: -#ifndef DISABLE_COM - if (spec->data.safearray_data.elem_type != MONO_VARIANT_VARIANT) { - char *msg = g_strdup ("Only SAFEARRAY(VARIANT) marshalling to managed code is implemented."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action); -#endif - default: { - char *msg = g_strdup ("Unsupported array type marshalling to managed code."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - } - - /* FIXME: t is from the method which is wrapped, not the delegate type */ - /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */ - - param_num = spec->data.array_data.param_num; - num_elem = spec->data.array_data.num_elem; - if (spec->data.array_data.elem_mult == 0) - /* param_num is not specified */ - param_num = -1; - - if (param_num == -1) { - if (num_elem <= 0) { - char *msg = g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - } - - /* FIXME: Optimize blittable case */ - -#ifndef DISABLE_NONBLITTABLE - if (eklass == cb_to_mono->mono_defaults->string_class) { - is_string = TRUE; - gboolean need_free; - conv = cb_to_mono->get_ptr_to_string_conv (m->piinfo, spec, &need_free); - } - else if (eklass == cb_to_mono->try_get_stringbuilder_class ()) { - is_string = TRUE; - gboolean need_free; - conv = cb_to_mono->get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free); - } - else - conv = MONO_MARSHAL_CONV_INVALID; -#endif - - cb_to_mono->load_type_info (eklass); - - if (is_string) - esize = TARGET_SIZEOF_VOID_P; - else - esize = cb_to_mono->class_native_size (eklass, NULL); - src_ptr = cb_to_mono->mb_add_local (mb, int_type); - - cb_to_mono->mb_emit_byte (mb, CEE_LDNULL); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - /* Check param index */ - if (param_num != -1) { - if (param_num >= m->sig->param_count) { - char *msg = g_strdup ("Array size control parameter index is out of range."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - switch (m->sig->params [param_num]->type) { - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - break; - default: { - char *msg = g_strdup ("Array size control parameter must be an integral type."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - } - } - - /* Check null */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - label1 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_stloc (mb, src_ptr); - - /* Create managed array */ - /* - * The LPArray marshalling spec says that sometimes param_num starts - * from 1, sometimes it starts from 0. But MS seems to allways start - * from 0. - */ - - if (param_num == -1) { - cb_to_mono->mb_emit_icon (mb, num_elem); - } else { - cb_to_mono->mb_emit_ldarg (mb, param_num); - if (num_elem > 0) { - cb_to_mono->mb_emit_icon (mb, num_elem); - cb_to_mono->mb_emit_byte (mb, CEE_ADD); - } - cb_to_mono->mb_emit_byte (mb, CEE_CONV_OVF_I); - } - - cb_to_mono->mb_emit_op (mb, CEE_NEWARR, eklass); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - if (m_class_is_blittable (eklass)) { - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_byte (mb, CEE_CONV_I); - cb_to_mono->mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); - cb_to_mono->mb_emit_byte (mb, CEE_ADD); - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_byte (mb, CEE_LDLEN); - cb_to_mono->mb_emit_icon (mb, esize); - cb_to_mono->mb_emit_byte (mb, CEE_MUL); - cb_to_mono->mb_emit_byte (mb, CEE_PREFIX1); - cb_to_mono->mb_emit_byte (mb, CEE_CPBLK); - cb_to_mono->mb_patch_branch (mb, label1); - break; - } -#ifdef DISABLE_NONBLITTABLE - else { - char *msg = g_strdup ("Non-blittable marshalling conversion is disabled"); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - } -#else - /* Emit marshalling loop */ - index_var = cb_to_mono->mb_add_local (mb, int_type); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_0); - cb_to_mono->mb_emit_stloc (mb, index_var); - label2 = cb_to_mono->mb_get_label (mb); - cb_to_mono->mb_emit_ldloc (mb, index_var); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_byte (mb, CEE_LDLEN); - label3 = cb_to_mono->mb_emit_branch (mb, CEE_BGE); - - /* Emit marshalling code */ - if (is_string) { - g_assert (conv != MONO_MARSHAL_CONV_INVALID); - - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_ldloc (mb, index_var); - - cb_to_mono->mb_emit_ldloc (mb, src_ptr); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, NULL)); - cb_to_mono->mb_emit_byte (mb, CEE_STELEM_REF); - } - else { - char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - - cb_to_mono->mb_emit_add_to_local (mb, GINT_TO_UINT16 (index_var), 1); - cb_to_mono->mb_emit_add_to_local (mb, GINT_TO_UINT16 (src_ptr), esize); - - cb_to_mono->mb_emit_branch_label (mb, CEE_BR, label2); - - cb_to_mono->mb_patch_branch (mb, label1); - cb_to_mono->mb_patch_branch (mb, label3); -#endif - - break; - } - case MARSHAL_ACTION_MANAGED_CONV_OUT: { - guint32 label1, label2, label3; - int index_var, dest_ptr, esize, param_num, num_elem; - MonoMarshalConv conv; - gboolean is_string = FALSE; - - if (!spec) - /* Already handled in CONV_IN */ - break; - - /* These are already checked in CONV_IN */ - g_assert (!m_type_is_byref (t)); - g_assert (spec->native == MONO_NATIVE_LPARRAY); - g_assert (t->attrs & PARAM_ATTRIBUTE_OUT); - - param_num = spec->data.array_data.param_num; - num_elem = spec->data.array_data.num_elem; - - if (spec->data.array_data.elem_mult == 0) - /* param_num is not specified */ - param_num = -1; - - if (param_num == -1) { - if (num_elem <= 0) { - g_assert_not_reached (); - } - } - - /* FIXME: Optimize blittable case */ - -#ifndef DISABLE_NONBLITTABLE - if (eklass == cb_to_mono->mono_defaults->string_class) { - is_string = TRUE; - conv = cb_to_mono->get_string_to_ptr_conv (m->piinfo, spec); - } - else if (eklass == cb_to_mono->try_get_stringbuilder_class ()) { - is_string = TRUE; - conv = cb_to_mono->get_stringbuilder_to_ptr_conv (m->piinfo, spec); - } - else - conv = MONO_MARSHAL_CONV_INVALID; -#endif - - cb_to_mono->load_type_info (eklass); - - if (is_string) - esize = TARGET_SIZEOF_VOID_P; - else - esize = cb_to_mono->class_native_size (eklass, NULL); - - dest_ptr = cb_to_mono->mb_add_local (mb, int_type); - - /* Check null */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - label1 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_stloc (mb, dest_ptr); - - if (m_class_is_blittable (eklass)) { - /* dest */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - /* src */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_byte (mb, CEE_CONV_I); - cb_to_mono->mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); - cb_to_mono->mb_emit_byte (mb, CEE_ADD); - /* length */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_byte (mb, CEE_LDLEN); - cb_to_mono->mb_emit_icon (mb, esize); - cb_to_mono->mb_emit_byte (mb, CEE_MUL); - cb_to_mono->mb_emit_byte (mb, CEE_PREFIX1); - cb_to_mono->mb_emit_byte (mb, CEE_CPBLK); - cb_to_mono->mb_patch_branch (mb, label1); - break; - } - -#ifndef DISABLE_NONBLITTABLE - /* Emit marshalling loop */ - index_var = cb_to_mono->mb_add_local (mb, int_type); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_0); - cb_to_mono->mb_emit_stloc (mb, index_var); - label2 = cb_to_mono->mb_get_label (mb); - cb_to_mono->mb_emit_ldloc (mb, index_var); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_byte (mb, CEE_LDLEN); - label3 = cb_to_mono->mb_emit_branch (mb, CEE_BGE); - - /* Emit marshalling code */ - if (is_string) { - int stind_op; - g_assert (conv != MONO_MARSHAL_CONV_INVALID); - - /* dest */ - cb_to_mono->mb_emit_ldloc (mb, dest_ptr); - - /* src */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_ldloc (mb, index_var); - - cb_to_mono->mb_emit_byte (mb, CEE_LDELEM_REF); - - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, &stind_op)); - cb_to_mono->mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); - } - else { - char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - - cb_to_mono->mb_emit_add_to_local (mb, GINT_TO_UINT16 (index_var), 1); - cb_to_mono->mb_emit_add_to_local (mb, GINT_TO_UINT16 (dest_ptr), esize); - - cb_to_mono->mb_emit_branch_label (mb, CEE_BR, label2); - - cb_to_mono->mb_patch_branch (mb, label1); - cb_to_mono->mb_patch_branch (mb, label3); -#endif - - break; - } - case MARSHAL_ACTION_MANAGED_CONV_RESULT: { -#ifndef DISABLE_NONBLITTABLE - guint32 label1, label2, label3; - int index_var, src, dest, esize; - MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID; - gboolean is_string = FALSE; - - g_assert (!m_type_is_byref (t)); - - cb_to_mono->load_type_info (eklass); - - if (eklass == cb_to_mono->mono_defaults->string_class) { - is_string = TRUE; - conv = cb_to_mono->get_string_to_ptr_conv (m->piinfo, spec); - } - else { - g_assert_not_reached (); - } - - if (is_string) - esize = TARGET_SIZEOF_VOID_P; - else if (eklass == cb_to_mono->mono_defaults->char_class) - esize = cb_to_mono->pinvoke_is_unicode (m->piinfo) ? 2 : 1; - else - esize = cb_to_mono->class_native_size (eklass, NULL); - - src = cb_to_mono->mb_add_local (mb, object_type); - dest = cb_to_mono->mb_add_local (mb, int_type); - - cb_to_mono->mb_emit_stloc (mb, src); - cb_to_mono->mb_emit_ldloc (mb, src); - cb_to_mono->mb_emit_stloc (mb, 3); - - /* Check for null */ - cb_to_mono->mb_emit_ldloc (mb, src); - label1 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - /* Allocate native array */ - cb_to_mono->mb_emit_icon (mb, esize); - cb_to_mono->mb_emit_ldloc (mb, src); - cb_to_mono->mb_emit_byte (mb, CEE_LDLEN); - - if (eklass == cb_to_mono->mono_defaults->string_class) { - /* Make the array bigger for the terminating null */ - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_1); - cb_to_mono->mb_emit_byte (mb, CEE_ADD); - } - cb_to_mono->mb_emit_byte (mb, CEE_MUL); - mono_mb_emit_jit_icall (mb, ves_icall_marshal_alloc); - cb_to_mono->mb_emit_stloc (mb, dest); - cb_to_mono->mb_emit_ldloc (mb, dest); - cb_to_mono->mb_emit_stloc (mb, 3); - - /* Emit marshalling loop */ - index_var = cb_to_mono->mb_add_local (mb, int_type); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_0); - cb_to_mono->mb_emit_stloc (mb, index_var); - label2 = cb_to_mono->mb_get_label (mb); - cb_to_mono->mb_emit_ldloc (mb, index_var); - cb_to_mono->mb_emit_ldloc (mb, src); - cb_to_mono->mb_emit_byte (mb, CEE_LDLEN); - label3 = cb_to_mono->mb_emit_branch (mb, CEE_BGE); - - /* Emit marshalling code */ - if (is_string) { - int stind_op; - g_assert (conv != MONO_MARSHAL_CONV_INVALID); - - /* dest */ - cb_to_mono->mb_emit_ldloc (mb, dest); - - /* src */ - cb_to_mono->mb_emit_ldloc (mb, src); - cb_to_mono->mb_emit_ldloc (mb, index_var); - - cb_to_mono->mb_emit_byte (mb, CEE_LDELEM_REF); - - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, &stind_op)); - cb_to_mono->mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); - } - else { - char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - - cb_to_mono->mb_emit_add_to_local (mb, GINT_TO_UINT16 (index_var), 1); - cb_to_mono->mb_emit_add_to_local (mb, GINT_TO_UINT16 (dest), esize); - - cb_to_mono->mb_emit_branch_label (mb, CEE_BR, label2); - - cb_to_mono->mb_patch_branch (mb, label3); - cb_to_mono->mb_patch_branch (mb, label1); -#endif - break; - } - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static gboolean -emit_native_wrapper_validate_signature (MonoMethodBuilder *mb, MonoMethodSignature* sig, MonoMarshalSpec** mspecs) -{ - if (mspecs) { - for (int i = 0; i < sig->param_count; i ++) { - if (mspecs [i + 1] && mspecs [i + 1]->native == MONO_NATIVE_CUSTOM) { - if (!mspecs [i + 1]->data.custom_data.custom_name || *mspecs [i + 1]->data.custom_data.custom_name == '\0') { - cb_to_mono->mb_emit_exception_full (mb, "System", "TypeLoadException", g_strdup ("Missing ICustomMarshaler type")); - return FALSE; - } - - switch (sig->params[i]->type) { - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_VALUETYPE: - break; - - default: - cb_to_mono->mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", g_strdup_printf ("custom marshalling of type %x is currently not supported", sig->params[i]->type)); - return FALSE; - } - } - else if (sig->params[i]->type == MONO_TYPE_VALUETYPE) { - MonoMarshalType *marshal_type = mono_marshal_load_type_info (mono_class_from_mono_type_internal (sig->params [i])); - for (guint32 field_idx = 0; field_idx < marshal_type->num_fields; ++field_idx) { - if (marshal_type->fields [field_idx].mspec && marshal_type->fields [field_idx].mspec->native == MONO_NATIVE_CUSTOM) { - cb_to_mono->mb_emit_exception_full (mb, "System", "TypeLoadException", g_strdup ("Value type includes custom marshaled fields")); - return FALSE; - } - } - } - } - } - - return TRUE; -} - -static int -emit_marshal_ptr_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - switch (action) { - case MARSHAL_ACTION_CONV_IN: - /* MS seems to allow this in some cases, ie. bxc #158 */ - /* - if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type_internal (t->data.type)->blittable) { - char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1); - cb_to_mono->mb_emit_exception_marshal_directive (m->mb, msg); - } - */ - break; - - case MARSHAL_ACTION_PUSH: - cb_to_mono->mb_emit_ldarg (mb, argnum); - break; - - case MARSHAL_ACTION_CONV_RESULT: - /* no conversions necessary */ - cb_to_mono->mb_emit_stloc (mb, 3); - break; - - default: - break; - } - return conv_arg; -} - -static int -emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - MonoType *int_type = cb_to_mono->get_int_type (); - MonoType *boolean_type = m_class_get_byval_arg (cb_to_mono->mono_defaults->boolean_class); - - switch (action) { - case MARSHAL_ACTION_CONV_IN: { - MonoType *local_type; - int label_false; - guint8 ldc_op = CEE_LDC_I4_1; - - local_type = cb_to_mono->boolean_conv_in_get_local_type (spec, &ldc_op); - if (m_type_is_byref (t)) - *conv_arg_type = int_type; - else - *conv_arg_type = local_type; - conv_arg = cb_to_mono->mb_add_local (mb, local_type); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I1); - label_false = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - cb_to_mono->mb_emit_byte (mb, ldc_op); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - cb_to_mono->mb_patch_branch (mb, label_false); - - break; - } - - case MARSHAL_ACTION_CONV_OUT: - { - int label_false, label_end; - if (!m_type_is_byref (t)) - break; - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - - label_false = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_1); - - label_end = cb_to_mono->mb_emit_branch (mb, CEE_BR); - cb_to_mono->mb_patch_branch (mb, label_false); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_0); - cb_to_mono->mb_patch_branch (mb, label_end); - - cb_to_mono->mb_emit_byte (mb, CEE_STIND_I1); - break; - } - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - else if (conv_arg) - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - else - cb_to_mono->mb_emit_ldarg (mb, argnum); - break; - - case MARSHAL_ACTION_CONV_RESULT: - /* maybe we need to make sure that it fits within 8 bits */ - cb_to_mono->mb_emit_stloc (mb, 3); - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: { - MonoClass* conv_arg_class = cb_to_mono->mono_defaults->int32_class; - guint8 ldop = CEE_LDIND_I4; - int label_null, label_false; - - conv_arg_class = cb_to_mono->boolean_managed_conv_in_get_conv_arg_class (spec, &ldop); - conv_arg = cb_to_mono->mb_add_local (mb, boolean_type); - - if (m_type_is_byref (t)) - *conv_arg_type = m_class_get_this_arg (conv_arg_class); - else - *conv_arg_type = m_class_get_byval_arg (conv_arg_class); - - - cb_to_mono->mb_emit_ldarg (mb, argnum); - - /* Check null */ - if (m_type_is_byref (t)) { - label_null = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, ldop); - } else - label_null = 0; - - label_false = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_1); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - cb_to_mono->mb_patch_branch (mb, label_false); - - if (m_type_is_byref (t)) - cb_to_mono->mb_patch_branch (mb, label_null); - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_OUT: { - guint8 stop = CEE_STIND_I4; - guint8 ldc_op = CEE_LDC_I4_1; - int label_null,label_false, label_end; - - if (!m_type_is_byref (t)) - break; - if (spec) { - switch (spec->native) { - case MONO_NATIVE_I1: - case MONO_NATIVE_U1: - stop = CEE_STIND_I1; - break; - case MONO_NATIVE_VARIANTBOOL: - stop = CEE_STIND_I2; - ldc_op = CEE_LDC_I4_M1; - break; - default: - break; - } - } - - /* Check null */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - label_null = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - - label_false = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - cb_to_mono->mb_emit_byte (mb, ldc_op); - label_end = cb_to_mono->mb_emit_branch (mb, CEE_BR); - - cb_to_mono->mb_patch_branch (mb, label_false); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_0); - cb_to_mono->mb_patch_branch (mb, label_end); - - cb_to_mono->mb_emit_byte (mb, stop); - cb_to_mono->mb_patch_branch (mb, label_null); - break; - } - - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static int -emit_marshal_char_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - - switch (action) { - case MARSHAL_ACTION_PUSH: - /* fixme: dont know how to marshal that. We cant simply - * convert it to a one byte UTF8 character, because an - * unicode character may need more that one byte in UTF8 */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - break; - - case MARSHAL_ACTION_CONV_RESULT: - /* fixme: we need conversions here */ - cb_to_mono->mb_emit_stloc (mb, 3); - break; - - default: - break; - } - return conv_arg; -} - -static int -emit_marshal_custom_ilgen_throw_exception (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg, MarshalAction action) -{ - /* Throw exception and emit compensation code, if neccesary */ - switch (action) { - case MARSHAL_ACTION_CONV_IN: - case MARSHAL_ACTION_MANAGED_CONV_IN: - case MARSHAL_ACTION_CONV_RESULT: - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - if ((action == MARSHAL_ACTION_CONV_RESULT) || (action == MARSHAL_ACTION_MANAGED_CONV_RESULT)) - cb_to_mono->mb_emit_byte (mb, CEE_POP); - - cb_to_mono->mb_emit_exception_full (mb, exc_nspace, exc_name, msg); - - break; - case MARSHAL_ACTION_PUSH: - cb_to_mono->mb_emit_byte (mb, CEE_LDNULL); - break; - default: - break; - } - - return 0; -} - -static int -emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - ERROR_DECL (error); - MonoType *mtype; - MonoClass *mklass; - static MonoClass *ICustomMarshaler = NULL; - static MonoMethod *cleanup_native, *cleanup_managed; - static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed; - MonoMethodBuilder *mb = m->mb; - MonoAssemblyLoadContext *alc = mono_alc_get_ambient (); - guint32 loc1; - int pos2; - - MonoType *int_type = cb_to_mono->get_int_type (); - MonoType *object_type = cb_to_mono->get_object_type (); - - if (!ICustomMarshaler) { - MonoClass *klass = mono_class_try_get_icustom_marshaler_class (); - if (!klass) - return emit_marshal_custom_ilgen_throw_exception (mb, "System", "ApplicationException", g_strdup ("Current profile doesn't support ICustomMarshaler"), action); - - cleanup_native = cb_to_mono->get_method_nofail (klass, "CleanUpNativeData", 1, 0); - g_assert (cleanup_native); - - cleanup_managed = cb_to_mono->get_method_nofail (klass, "CleanUpManagedData", 1, 0); - g_assert (cleanup_managed); - - marshal_managed_to_native = cb_to_mono->get_method_nofail (klass, "MarshalManagedToNative", 1, 0); - g_assert (marshal_managed_to_native); - - marshal_native_to_managed = cb_to_mono->get_method_nofail (klass, "MarshalNativeToManaged", 1, 0); - g_assert (marshal_native_to_managed); - - cb_to_mono->memory_barrier (); - ICustomMarshaler = klass; - } - - if (spec->data.custom_data.image) - mtype = cb_to_mono->reflection_type_from_name_checked (spec->data.custom_data.custom_name, alc, spec->data.custom_data.image, error); - else - mtype = cb_to_mono->reflection_type_from_name_checked (spec->data.custom_data.custom_name, alc, m->image, error); - - if (!mtype) - return emit_marshal_custom_ilgen_throw_exception (mb, "System", "TypeLoadException", g_strdup ("Failed to load ICustomMarshaler type"), action); - - mklass = mono_class_from_mono_type_internal (mtype); - g_assert (mklass != NULL); - - switch (action) { - case MARSHAL_ACTION_CONV_IN: - switch (t->type) { - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_VALUETYPE: - break; - - default: - g_warning ("custom marshalling of type %x is currently not supported", t->type); - g_assert_not_reached (); - break; - } - - conv_arg = cb_to_mono->mb_add_local (mb, int_type); - - cb_to_mono->mb_emit_byte (mb, CEE_LDNULL); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) - break; - - /* Minic MS.NET behavior */ - if (!m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN)) - break; - - /* Check for null */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - cb_to_mono->emit_marshal_custom_get_instance (mb, mklass, spec); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_REF); - - if (t->type == MONO_TYPE_VALUETYPE) { - /* - * Since we can't determine the type of the argument, we - * will assume the unmanaged function takes a pointer. - */ - *conv_arg_type = int_type; - - cb_to_mono->mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (t)); - } - - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - cb_to_mono->mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_CONV_OUT: - /* Check for null */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_OUT)) { - cb_to_mono->mb_emit_ldarg (mb, argnum); - - cb_to_mono->emit_marshal_custom_get_instance (mb, mklass, spec); - cb_to_mono->mb_emit_byte (mb, CEE_DUP); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_REF); - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); - - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_REF); - } else if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) { - cb_to_mono->mb_emit_ldarg (mb, argnum); - - cb_to_mono->emit_marshal_custom_get_instance (mb, mklass, spec); - - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_REF); - } else if (t->attrs & PARAM_ATTRIBUTE_OUT) { - cb_to_mono->emit_marshal_custom_get_instance (mb, mklass, spec); - - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); - /* We have nowhere to store the result */ - cb_to_mono->mb_emit_byte (mb, CEE_POP); - } - - // Only call cleanup_native if MARSHAL_ACTION_CONV_IN called marshal_managed_to_native. - if (!(m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) && - !(!m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN))) { - cb_to_mono->emit_marshal_custom_get_instance (mb, mklass, spec); - - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, cleanup_native); - } - - cb_to_mono->mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - else - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_RESULT: - cb_to_mono->mb_emit_stloc (mb, 3); - - /* Check for null */ - cb_to_mono->mb_emit_ldloc (mb, 3); - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - cb_to_mono->emit_marshal_custom_get_instance (mb, mklass, spec); - - cb_to_mono->mb_emit_ldloc (mb, 3); - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); - cb_to_mono->mb_emit_stloc (mb, 3); - - cb_to_mono->mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: - switch (t->type) { - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_VALUETYPE: - case MONO_TYPE_BOOLEAN: - break; - - default: - g_warning ("custom marshalling of type %x is currently not supported", t->type); - g_assert_not_reached (); - break; - } - - conv_arg = cb_to_mono->mb_add_local (mb, object_type); - - cb_to_mono->mb_emit_byte (mb, CEE_LDNULL); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - if (m_type_is_byref (t) && t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - /* Check for null */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - cb_to_mono->emit_marshal_custom_get_instance (mb, mklass, spec); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - cb_to_mono->mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - g_assert (!m_type_is_byref (t)); - - loc1 = cb_to_mono->mb_add_local (mb, object_type); - - cb_to_mono->mb_emit_stloc (mb, 3); - - cb_to_mono->mb_emit_ldloc (mb, 3); - cb_to_mono->mb_emit_stloc (mb, loc1); - - /* Check for null */ - cb_to_mono->mb_emit_ldloc (mb, 3); - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - cb_to_mono->emit_marshal_custom_get_instance (mb, mklass, spec); - cb_to_mono->mb_emit_byte (mb, CEE_DUP); - - cb_to_mono->mb_emit_ldloc (mb, 3); - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); - cb_to_mono->mb_emit_stloc (mb, 3); - - cb_to_mono->mb_emit_ldloc (mb, loc1); - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); - - cb_to_mono->mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_MANAGED_CONV_OUT: - - /* Check for null */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - if (m_type_is_byref (t)) { - cb_to_mono->mb_emit_ldarg (mb, argnum); - - cb_to_mono->emit_marshal_custom_get_instance (mb, mklass, spec); - - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_I); - } - - // Only call cleanup_managed if MARSHAL_ACTION_MANAGED_CONV_IN called marshal_native_to_managed. - if (!(m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { - cb_to_mono->emit_marshal_custom_get_instance (mb, mklass, spec); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); - } - - cb_to_mono->mb_patch_branch (mb, pos2); - break; - - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static int -emit_marshal_asany_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - - MonoType *int_type = cb_to_mono->get_int_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: { - MonoMarshalNative encoding = cb_to_mono->get_string_encoding (m->piinfo, NULL); - - g_assert (t->type == MONO_TYPE_OBJECT); - g_assert (!m_type_is_byref (t)); - - conv_arg = cb_to_mono->mb_add_local (mb, int_type); - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_icon (mb, encoding); - cb_to_mono->mb_emit_icon (mb, t->attrs); - mono_mb_emit_jit_icall (mb, mono_marshal_asany); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - break; - } - - case MARSHAL_ACTION_PUSH: - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_OUT: { - MonoMarshalNative encoding = cb_to_mono->get_string_encoding (m->piinfo, NULL); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_icon (mb, encoding); - cb_to_mono->mb_emit_icon (mb, t->attrs); - mono_mb_emit_jit_icall (mb, mono_marshal_free_asany); - break; - } - - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static int -emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - MonoClass *klass, *date_time_class; - int pos = 0, pos2; - - klass = mono_class_from_mono_type_internal (t); - - date_time_class = mono_class_get_date_time_class (); - - MonoType *int_type = cb_to_mono->get_int_type (); - MonoType *double_type = m_class_get_byval_arg (cb_to_mono->mono_defaults->double_class); - - switch (action) { - case MARSHAL_ACTION_CONV_IN: - if (klass == date_time_class) { - /* Convert it to an OLE DATE type */ - - conv_arg = cb_to_mono->mb_add_local (mb, double_type); - - if (m_type_is_byref (t)) { - cb_to_mono->mb_emit_ldarg (mb, argnum); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - } - - if (!(m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { - if (!m_type_is_byref (t)) - m->csig->params [argnum - m->csig->hasthis] = double_type; - - MONO_STATIC_POINTER_INIT (MonoMethod, to_oadate) - to_oadate = cb_to_mono->get_method_nofail (date_time_class, "ToOADate", 0, 0); - g_assert (to_oadate); - MONO_STATIC_POINTER_INIT_END (MonoMethod, to_oadate) - - cb_to_mono->mb_emit_ldarg_addr (mb, argnum); - cb_to_mono->mb_emit_managed_call (mb, to_oadate, NULL); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - } - - if (m_type_is_byref (t)) - cb_to_mono->mb_patch_branch (mb, pos); - break; - } - - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) - break; - - conv_arg = cb_to_mono->mb_add_local (mb, int_type); - - /* store the address of the source into local variable 0 */ - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_ldarg (mb, argnum); - else - cb_to_mono->mb_emit_ldarg_addr (mb, argnum); - - cb_to_mono->mb_emit_stloc (mb, 0); - - /* allocate space for the native struct and - * store the address into local variable 1 (dest) */ - cb_to_mono->mb_emit_icon (mb, cb_to_mono->class_native_size (klass, NULL)); - cb_to_mono->mb_emit_byte (mb, CEE_PREFIX1); - cb_to_mono->mb_emit_byte (mb, CEE_LOCALLOC); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - if (m_type_is_byref (t)) { - cb_to_mono->mb_emit_ldloc (mb, 0); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - } - - if (!(m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { - /* set dst_ptr */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, FALSE); - } - - if (m_type_is_byref (t)) - cb_to_mono->mb_patch_branch (mb, pos); - break; - - case MARSHAL_ACTION_PUSH: - if (spec && spec->native == MONO_NATIVE_LPSTRUCT) { - /* FIXME: */ - g_assert (!m_type_is_byref (t)); - - /* Have to change the signature since the vtype is passed byref */ - m->csig->params [argnum - m->csig->hasthis] = int_type; - - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) - cb_to_mono->mb_emit_ldarg_addr (mb, argnum); - else - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - break; - } - - if (klass == date_time_class) { - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - else - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - break; - } - - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { - cb_to_mono->mb_emit_ldarg (mb, argnum); - break; - } - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - if (!m_type_is_byref (t)) { - cb_to_mono->mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - cb_to_mono->mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, klass); - } - break; - - case MARSHAL_ACTION_CONV_OUT: - if (klass == date_time_class) { - /* Convert from an OLE DATE type */ - - if (!m_type_is_byref (t)) - break; - - if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) { - - MONO_STATIC_POINTER_INIT (MonoMethod, from_oadate) - from_oadate = cb_to_mono->get_method_nofail (date_time_class, "FromOADate", 1, 0); - MONO_STATIC_POINTER_INIT_END (MonoMethod, from_oadate) - - g_assert (from_oadate); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_managed_call (mb, from_oadate, NULL); - cb_to_mono->mb_emit_op (mb, CEE_STOBJ, date_time_class); - } - break; - } - - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) - break; - - if (m_type_is_byref (t)) { - /* dst = argument */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_stloc (mb, 1); - - cb_to_mono->mb_emit_ldloc (mb, 1); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) { - /* src = tmp_locals [i] */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_stloc (mb, 0); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, TRUE); - } - } - - emit_struct_free (mb, klass, conv_arg); - - if (m_type_is_byref (t)) - cb_to_mono->mb_patch_branch (mb, pos); - break; - - case MARSHAL_ACTION_CONV_RESULT: - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass)) { - cb_to_mono->mb_emit_stloc (mb, 3); - break; - } - - /* load pointer to returned value type */ - g_assert (m->vtaddr_var); - cb_to_mono->mb_emit_ldloc (mb, m->vtaddr_var); - /* store the address of the source into local variable 0 */ - cb_to_mono->mb_emit_stloc (mb, 0); - /* set dst_ptr */ - cb_to_mono->mb_emit_ldloc_addr (mb, 3); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, TRUE); - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { - conv_arg = 0; - break; - } - - conv_arg = cb_to_mono->mb_add_local (mb, m_class_get_byval_arg (klass)); - - if (t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_ldarg (mb, argnum); - else - cb_to_mono->mb_emit_ldarg_addr (mb, argnum); - cb_to_mono->mb_emit_stloc (mb, 0); - - if (m_type_is_byref (t)) { - cb_to_mono->mb_emit_ldloc (mb, 0); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - } - - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, TRUE); - - if (m_type_is_byref (t)) - cb_to_mono->mb_patch_branch (mb, pos); - break; - - case MARSHAL_ACTION_MANAGED_CONV_OUT: - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) - break; - if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT)) - break; - - /* Check for null */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - /* Set src */ - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - cb_to_mono->mb_emit_stloc (mb, 0); - - /* Set dest */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, FALSE); - - cb_to_mono->mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { - cb_to_mono->mb_emit_stloc (mb, 3); - m->retobj_var = 0; - break; - } - - /* load pointer to returned value type */ - g_assert (m->vtaddr_var); - cb_to_mono->mb_emit_ldloc (mb, m->vtaddr_var); - - /* store the address of the source into local variable 0 */ - cb_to_mono->mb_emit_stloc (mb, 0); - /* allocate space for the native struct and - * store the address into dst_ptr */ - m->retobj_var = cb_to_mono->mb_add_local (mb, int_type); - m->retobj_class = klass; - g_assert (m->retobj_var); - cb_to_mono->mb_emit_icon (mb, cb_to_mono->class_native_size (klass, NULL)); - cb_to_mono->mb_emit_byte (mb, CEE_CONV_I); - mono_mb_emit_jit_icall (mb, ves_icall_marshal_alloc); - cb_to_mono->mb_emit_stloc (mb, 1); - cb_to_mono->mb_emit_ldloc (mb, 1); - cb_to_mono->mb_emit_stloc (mb, m->retobj_var); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, FALSE); - break; - - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static void -emit_string_free_icall (MonoMethodBuilder *mb, MonoMarshalConv conv) -{ - if (conv == MONO_MARSHAL_CONV_BSTR_STR || conv == MONO_MARSHAL_CONV_ANSIBSTR_STR || conv == MONO_MARSHAL_CONV_TBSTR_STR) - mono_mb_emit_jit_icall (mb, mono_free_bstr); - else - mono_mb_emit_jit_icall (mb, mono_marshal_free); -} - -static int -emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - MonoMarshalNative encoding = cb_to_mono->get_string_encoding (m->piinfo, spec); - MonoMarshalConv conv = cb_to_mono->get_string_to_ptr_conv (m->piinfo, spec); - gboolean need_free; - - MonoType *int_type = cb_to_mono->get_int_type (); - MonoType *object_type = cb_to_mono->get_object_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = int_type; - conv_arg = cb_to_mono->mb_add_local (mb, int_type); - - if (m_type_is_byref (t)) { - if (t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - } else { - cb_to_mono->mb_emit_ldarg (mb, argnum); - } - - if (conv == MONO_MARSHAL_CONV_INVALID) { - char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - } else { - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, NULL)); - - cb_to_mono->mb_emit_stloc (mb, conv_arg); - } - break; - - case MARSHAL_ACTION_CONV_OUT: - conv = cb_to_mono->get_ptr_to_string_conv (m->piinfo, spec, &need_free); - if (conv == MONO_MARSHAL_CONV_INVALID) { - char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - if (encoding == MONO_NATIVE_VBBYREFSTR) { - - if (!m_type_is_byref (t)) { - char *msg = g_strdup ("VBByRefStr marshalling requires a ref parameter."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - MONO_STATIC_POINTER_INIT (MonoMethod, method) - - method = cb_to_mono->get_method_nofail (cb_to_mono->mono_defaults->string_class, "get_Length", -1, 0); - - MONO_STATIC_POINTER_INIT_END (MonoMethod, method) - - /* - * Have to allocate a new string with the same length as the original, and - * copy the contents of the buffer pointed to by CONV_ARG into it. - */ - g_assert (m_type_is_byref (t)); - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - cb_to_mono->mb_emit_managed_call (mb, method, NULL); - mono_mb_emit_jit_icall (mb, mono_string_new_len_wrapper); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_REF); - } else if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { - int stind_op; - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, &stind_op)); - cb_to_mono->mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); - need_free = TRUE; - } - - if (need_free) { - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - emit_string_free_icall (mb, conv); - } - break; - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t) && encoding != MONO_NATIVE_VBBYREFSTR) - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - else - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_RESULT: - cb_to_mono->mb_emit_stloc (mb, 0); - - conv = cb_to_mono->get_ptr_to_string_conv (m->piinfo, spec, &need_free); - if (conv == MONO_MARSHAL_CONV_INVALID) { - char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - cb_to_mono->mb_emit_ldloc (mb, 0); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, NULL)); - cb_to_mono->mb_emit_stloc (mb, 3); - - /* free the string */ - cb_to_mono->mb_emit_ldloc (mb, 0); - emit_string_free_icall (mb, conv); - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: - conv_arg = cb_to_mono->mb_add_local (mb, object_type); - - *conv_arg_type = int_type; - - if (m_type_is_byref (t)) { - if (t->attrs & PARAM_ATTRIBUTE_OUT) - break; - } - - conv = cb_to_mono->get_ptr_to_string_conv (m->piinfo, spec, &need_free); - if (conv == MONO_MARSHAL_CONV_INVALID) { - char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, NULL)); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_MANAGED_CONV_OUT: - if (m_type_is_byref (t)) { - if (conv_arg) { - int stind_op; - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, &stind_op)); - cb_to_mono->mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); - } - } - break; - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - if (cb_to_mono->conv_to_icall (conv, NULL) == MONO_JIT_ICALL_mono_marshal_string_to_utf16) - /* We need to make a copy so the caller is able to free it */ - mono_mb_emit_jit_icall (mb, mono_marshal_string_to_utf16_copy); - else - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, NULL)); - cb_to_mono->mb_emit_stloc (mb, 3); - break; - - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static int -emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - MonoType *int_type = cb_to_mono->get_int_type (); - MonoType *boolean_type = m_class_get_byval_arg (cb_to_mono->mono_defaults->boolean_class); - - switch (action){ - case MARSHAL_ACTION_CONV_IN: { - int dar_release_slot, pos; - - conv_arg = cb_to_mono->mb_add_local (mb, int_type); - *conv_arg_type = int_type; - - if (!*cb_to_mono->get_sh_dangerous_add_ref()) - cb_to_mono->init_safe_handle (); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRTRUE); - cb_to_mono->mb_emit_exception (mb, "ArgumentNullException", NULL); - - cb_to_mono->mb_patch_branch (mb, pos); - - /* Create local to hold the ref parameter to DangerousAddRef */ - dar_release_slot = cb_to_mono->mb_add_local (mb, boolean_type); - - /* set release = false; */ - cb_to_mono->mb_emit_icon (mb, 0); - cb_to_mono->mb_emit_stloc (mb, dar_release_slot); - - if (m_type_is_byref (t)) { - int old_handle_value_slot = cb_to_mono->mb_add_local (mb, int_type); - - if (!cb_to_mono->is_in (t)) { - cb_to_mono->mb_emit_icon (mb, 0); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - } else { - /* safehandle.DangerousAddRef (ref release) */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_REF); - cb_to_mono->mb_emit_ldloc_addr (mb, dar_release_slot); - cb_to_mono->mb_emit_managed_call (mb, *cb_to_mono->get_sh_dangerous_add_ref(), NULL); - - /* Pull the handle field from SafeHandle */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_REF); - cb_to_mono->mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - cb_to_mono->mb_emit_byte (mb, CEE_DUP); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - cb_to_mono->mb_emit_stloc (mb, old_handle_value_slot); - } - } else { - /* safehandle.DangerousAddRef (ref release) */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc_addr (mb, dar_release_slot); - cb_to_mono->mb_emit_managed_call (mb, *cb_to_mono->get_sh_dangerous_add_ref(), NULL); - - /* Pull the handle field from SafeHandle */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - } - - break; - } - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - else - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_OUT: { - /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */ - int dar_release_slot = conv_arg + 1; - int label_next = 0; - - if (!*cb_to_mono->get_sh_dangerous_release()) - cb_to_mono->init_safe_handle (); - - if (m_type_is_byref (t)) { - /* If there was SafeHandle on input we have to release the reference to it */ - if (cb_to_mono->is_in (t)) { - cb_to_mono->mb_emit_ldloc (mb, dar_release_slot); - label_next = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - cb_to_mono->mb_emit_managed_call (mb, *cb_to_mono->get_sh_dangerous_release (), NULL); - cb_to_mono->mb_patch_branch (mb, label_next); - } - - if (cb_to_mono->is_out (t)) { - ERROR_DECL (local_error); - MonoMethod *ctor; - - /* - * If the SafeHandle was marshalled on input we can skip the marshalling on - * output if the handle value is identical. - */ - if (cb_to_mono->is_in (t)) { - int old_handle_value_slot = dar_release_slot + 1; - cb_to_mono->mb_emit_ldloc (mb, old_handle_value_slot); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - label_next = cb_to_mono->mb_emit_branch (mb, CEE_BEQ); - } - - /* - * Create an empty SafeHandle (of correct derived type). - * - * FIXME: If an out-of-memory situation or exception happens here we will - * leak the handle. We should move the allocation of the SafeHandle to the - * input marshalling code to prevent that. - */ - ctor = mono_class_get_method_from_name_checked (t->data.klass, ".ctor", 0, 0, local_error); - if (ctor == NULL || !is_ok (local_error)){ - cb_to_mono->mb_emit_exception (mb, "MissingMethodException", "parameterless constructor required"); - mono_error_cleanup (local_error); - break; - } - - /* refval = new SafeHandleDerived ()*/ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_op (mb, CEE_NEWOBJ, ctor); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_REF); - - /* refval.handle = returned_handle */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_REF); - cb_to_mono->mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_I); - - if (cb_to_mono->is_in (t) && label_next) { - cb_to_mono->mb_patch_branch (mb, label_next); - } - } - } else { - cb_to_mono->mb_emit_ldloc (mb, dar_release_slot); - label_next = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_managed_call (mb, *cb_to_mono->get_sh_dangerous_release (), NULL); - cb_to_mono->mb_patch_branch (mb, label_next); - } - break; - } - - case MARSHAL_ACTION_CONV_RESULT: { - ERROR_DECL (error); - MonoMethod *ctor = NULL; - int intptr_handle_slot; - - if (mono_class_is_abstract (t->data.klass)) { - cb_to_mono->mb_emit_byte (mb, CEE_POP); - cb_to_mono->mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract")); - break; - } - - ctor = mono_class_get_method_from_name_checked (t->data.klass, ".ctor", 0, 0, error); - if (ctor == NULL || !is_ok (error)){ - mono_error_cleanup (error); - cb_to_mono->mb_emit_byte (mb, CEE_POP); - cb_to_mono->mb_emit_exception (mb, "MissingMethodException", "parameterless constructor required"); - break; - } - /* Store the IntPtr results into a local */ - intptr_handle_slot = cb_to_mono->mb_add_local (mb, int_type); - cb_to_mono->mb_emit_stloc (mb, intptr_handle_slot); - - /* Create return value */ - cb_to_mono->mb_emit_op (mb, CEE_NEWOBJ, ctor); - cb_to_mono->mb_emit_stloc (mb, 3); - - /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */ - cb_to_mono->mb_emit_ldloc (mb, 3); - cb_to_mono->mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); - cb_to_mono->mb_emit_ldloc (mb, intptr_handle_slot); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_I); - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_IN: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); - break; - - case MARSHAL_ACTION_MANAGED_CONV_OUT: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); - break; - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n"); - break; - default: - printf ("Unhandled case for MarshalAction: %d\n", action); - } - return conv_arg; -} - -static int -emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - - MonoType *int_type = cb_to_mono->get_int_type (); - switch (action){ - case MARSHAL_ACTION_CONV_IN: { - conv_arg = cb_to_mono->mb_add_local (mb, int_type); - *conv_arg_type = int_type; - - if (m_type_is_byref (t)) { - char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)"); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - cb_to_mono->mb_emit_ldarg_addr (mb, argnum); - cb_to_mono->mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoHandleRef, handle)); - cb_to_mono->mb_emit_byte (mb, CEE_ADD); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - break; - } - - case MARSHAL_ACTION_PUSH: - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_OUT: { - /* no resource release required */ - break; - } - - case MARSHAL_ACTION_CONV_RESULT: { - char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)"); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_IN: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); - break; - - case MARSHAL_ACTION_MANAGED_CONV_OUT: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); - break; - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n"); - break; - default: - fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action); - } - return conv_arg; -} - -static int -emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - MonoClass *klass = mono_class_from_mono_type_internal (t); - int pos, pos2, loc; - - MonoType *int_type = cb_to_mono->get_int_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = int_type; - conv_arg = cb_to_mono->mb_add_local (mb, int_type); - - m->orig_conv_args [argnum] = 0; - - if (mono_class_from_mono_type_internal (t) == cb_to_mono->mono_defaults->object_class) { - char *msg = g_strdup_printf ("Marshalling of type object is not implemented"); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - if (m_class_is_delegate (klass)) { - if (m_type_is_byref (t)) { - if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { - char *msg = g_strdup_printf ("Byref marshalling of delegates is not implemented."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - } - cb_to_mono->mb_emit_byte (mb, CEE_LDNULL); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - } else { - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL)); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - } - } else if (klass == cb_to_mono->try_get_stringbuilder_class ()) { - MonoMarshalNative encoding = cb_to_mono->get_string_encoding (m->piinfo, spec); - MonoMarshalConv conv = cb_to_mono->get_stringbuilder_to_ptr_conv (m->piinfo, spec); - -#if 0 - if (m_type_is_byref (t)) { - if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { - char *msg = g_strdup_printf ("Byref marshalling of stringbuilders is not implemented."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - } - break; - } -#endif - - if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT)) - break; - - if (conv == MONO_MARSHAL_CONV_INVALID) { - char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, NULL)); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - } else if (m_class_is_blittable (klass)) { - cb_to_mono->mb_emit_byte (mb, CEE_LDNULL); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - cb_to_mono->mb_patch_branch (mb, pos); - break; - } else { - cb_to_mono->mb_emit_byte (mb, CEE_LDNULL); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - if (m_type_is_byref (t)) { - /* we dont need any conversions for out parameters */ - if (t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - - } else { - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - cb_to_mono->mb_emit_byte (mb, CEE_MONO_OBJADDR); - } - - /* store the address of the source into local variable 0 */ - cb_to_mono->mb_emit_stloc (mb, 0); - cb_to_mono->mb_emit_ldloc (mb, 0); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - /* allocate space for the native struct and store the address */ - cb_to_mono->mb_emit_icon (mb, cb_to_mono->class_native_size (klass, NULL)); - cb_to_mono->mb_emit_byte (mb, CEE_PREFIX1); - cb_to_mono->mb_emit_byte (mb, CEE_LOCALLOC); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - if (m_type_is_byref (t)) { - /* Need to store the original buffer so we can free it later */ - m->orig_conv_args [argnum] = cb_to_mono->mb_add_local (mb, int_type); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_stloc (mb, m->orig_conv_args [argnum]); - } - - /* set the src_ptr */ - cb_to_mono->mb_emit_ldloc (mb, 0); - cb_to_mono->mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - cb_to_mono->mb_emit_stloc (mb, 0); - - /* set dst_ptr */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, FALSE); - - cb_to_mono->mb_patch_branch (mb, pos); - } - break; - - case MARSHAL_ACTION_CONV_OUT: - if (klass == cb_to_mono->try_get_stringbuilder_class ()) { - gboolean need_free; - MonoMarshalNative encoding; - MonoMarshalConv conv; - - encoding = cb_to_mono->get_string_encoding (m->piinfo, spec); - conv = cb_to_mono->get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free); - - g_assert (encoding != -1); - - if (m_type_is_byref (t)) { - //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT)); - - need_free = TRUE; - - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - - switch (encoding) { - case MONO_NATIVE_LPWSTR: - mono_mb_emit_jit_icall (mb, mono_string_utf16_to_builder2); - break; - case MONO_NATIVE_LPSTR: - mono_mb_emit_jit_icall (mb, mono_string_utf8_to_builder2); - break; - case MONO_NATIVE_UTF8STR: - mono_mb_emit_jit_icall (mb, mono_string_utf8_to_builder2); - break; - default: - g_assert_not_reached (); - } - - cb_to_mono->mb_emit_byte (mb, CEE_STIND_REF); - } else if (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN)) { - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (conv, NULL)); - } - - if (need_free) { - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_jit_icall (mb, mono_marshal_free); - } - break; - } - - if (m_class_is_delegate (klass)) { - if (m_type_is_byref (t)) { - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - cb_to_mono->mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_REF); - } - break; - } - - if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) { - /* allocate a new object */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - cb_to_mono->mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_REF); - } - - /* dst = *argument */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - - cb_to_mono->mb_emit_stloc (mb, 1); - - cb_to_mono->mb_emit_ldloc (mb, 1); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - if (m_type_is_byref (t) || (t->attrs & PARAM_ATTRIBUTE_OUT)) { - cb_to_mono->mb_emit_ldloc (mb, 1); - cb_to_mono->mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); - cb_to_mono->mb_emit_byte (mb, CEE_ADD); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* src = tmp_locals [i] */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_stloc (mb, 0); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, TRUE); - - /* Free the structure returned by the native code */ - emit_struct_free (mb, klass, conv_arg); - - if (m->orig_conv_args [argnum]) { - /* - * If the native function changed the pointer, then free - * the original structure plus the new pointer. - */ - cb_to_mono->mb_emit_ldloc (mb, m->orig_conv_args [argnum]); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BEQ); - - if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { - g_assert (m->orig_conv_args [argnum]); - - emit_struct_free (mb, klass, m->orig_conv_args [argnum]); - } - - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_jit_icall (mb, mono_marshal_free); - - cb_to_mono->mb_patch_branch (mb, pos2); - } - } - else - /* Free the original structure passed to native code */ - emit_struct_free (mb, klass, conv_arg); - - cb_to_mono->mb_patch_branch (mb, pos); - break; - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - else - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_RESULT: - if (m_class_is_delegate (klass)) { - g_assert (!m_type_is_byref (t)); - cb_to_mono->mb_emit_stloc (mb, 0); - cb_to_mono->mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - cb_to_mono->mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); - cb_to_mono->mb_emit_ldloc (mb, 0); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); - cb_to_mono->mb_emit_stloc (mb, 3); - } else if (klass == cb_to_mono->try_get_stringbuilder_class ()) { - // FIXME: - char *msg = g_strdup_printf ("Return marshalling of stringbuilders is not implemented."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - } else { - /* set src */ - cb_to_mono->mb_emit_stloc (mb, 0); - - /* Make a copy since emit_conv modifies local 0 */ - loc = cb_to_mono->mb_add_local (mb, int_type); - cb_to_mono->mb_emit_ldloc (mb, 0); - cb_to_mono->mb_emit_stloc (mb, loc); - - cb_to_mono->mb_emit_byte (mb, CEE_LDNULL); - cb_to_mono->mb_emit_stloc (mb, 3); - - cb_to_mono->mb_emit_ldloc (mb, 0); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - /* allocate result object */ - - cb_to_mono->mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - cb_to_mono->mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); - cb_to_mono->mb_emit_stloc (mb, 3); - - /* set dst */ - - cb_to_mono->mb_emit_ldloc (mb, 3); - cb_to_mono->mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* emit conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, TRUE); - - emit_struct_free (mb, klass, loc); - - /* Free the pointer allocated by unmanaged code */ - cb_to_mono->mb_emit_ldloc (mb, loc); - mono_mb_emit_jit_icall (mb, mono_marshal_free); - cb_to_mono->mb_patch_branch (mb, pos); - } - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: - conv_arg = cb_to_mono->mb_add_local (mb, m_class_get_byval_arg (klass)); - - if (m_class_is_delegate (klass)) { - cb_to_mono->mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - cb_to_mono->mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - break; - } - - if (klass == cb_to_mono->try_get_stringbuilder_class ()) { - MonoMarshalNative encoding; - - encoding = cb_to_mono->get_string_encoding (m->piinfo, spec); - - // FIXME: - g_assert (encoding == MONO_NATIVE_LPSTR || encoding == MONO_NATIVE_UTF8STR); - - g_assert (!m_type_is_byref (t)); - g_assert (encoding != -1); - - cb_to_mono->mb_emit_ldarg (mb, argnum); - mono_mb_emit_jit_icall (mb, mono_string_utf8_to_builder2); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - break; - } - - /* The class can not have an automatic layout */ - if (mono_class_is_auto_layout (klass)) { - cb_to_mono->mb_emit_auto_layout_exception (mb, klass); - break; - } - - if (t->attrs & PARAM_ATTRIBUTE_OUT) { - cb_to_mono->mb_emit_byte (mb, CEE_LDNULL); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - break; - } - - /* Set src */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) { - /* Check for NULL and raise an exception */ - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BRTRUE); - - cb_to_mono->mb_emit_exception (mb, "ArgumentNullException", NULL); - - cb_to_mono->mb_patch_branch (mb, pos2); - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, CEE_LDIND_I); - } - - cb_to_mono->mb_emit_stloc (mb, 0); - - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_0); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - - cb_to_mono->mb_emit_ldloc (mb, 0); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRFALSE); - - /* Create and set dst */ - cb_to_mono->mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - cb_to_mono->mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, TRUE); - - cb_to_mono->mb_patch_branch (mb, pos); - break; - - case MARSHAL_ACTION_MANAGED_CONV_OUT: - if (m_class_is_delegate (klass)) { - if (m_type_is_byref (t)) { - int stind_op; - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op)); - cb_to_mono->mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); - break; - } - } - - if (m_type_is_byref (t)) { - /* Check for null */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRTRUE); - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_byte (mb, CEE_LDC_I4_0); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_I); - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BR); - - cb_to_mono->mb_patch_branch (mb, pos); - - /* Set src */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - cb_to_mono->mb_emit_stloc (mb, 0); - - /* Allocate and set dest */ - cb_to_mono->mb_emit_icon (mb, cb_to_mono->class_native_size (klass, NULL)); - cb_to_mono->mb_emit_byte (mb, CEE_CONV_I); - mono_mb_emit_jit_icall (mb, ves_icall_marshal_alloc); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* Update argument pointer */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc (mb, 1); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_I); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, FALSE); - - cb_to_mono->mb_patch_branch (mb, pos2); - } else if (klass == cb_to_mono->try_get_stringbuilder_class ()) { - // FIXME: What to do here ? - } else { - /* byval [Out] marshalling */ - - /* FIXME: Handle null */ - - /* Set src */ - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - cb_to_mono->mb_emit_stloc (mb, 0); - - /* Set dest */ - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - cb_to_mono->emit_struct_conv (mb, klass, FALSE); - } - break; - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - if (m_class_is_delegate (klass)) { - cb_to_mono->mb_emit_icall_id (mb, cb_to_mono->conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL)); - cb_to_mono->mb_emit_stloc (mb, 3); - break; - } - - /* The class can not have an automatic layout */ - if (mono_class_is_auto_layout (klass)) { - cb_to_mono->mb_emit_auto_layout_exception (mb, klass); - break; - } - - cb_to_mono->mb_emit_stloc (mb, 0); - /* Check for null */ - cb_to_mono->mb_emit_ldloc (mb, 0); - pos = cb_to_mono->mb_emit_branch (mb, CEE_BRTRUE); - cb_to_mono->mb_emit_byte (mb, CEE_LDNULL); - cb_to_mono->mb_emit_stloc (mb, 3); - pos2 = cb_to_mono->mb_emit_branch (mb, CEE_BR); - - cb_to_mono->mb_patch_branch (mb, pos); - - /* Set src */ - cb_to_mono->mb_emit_ldloc (mb, 0); - cb_to_mono->mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - cb_to_mono->mb_emit_stloc (mb, 0); - - /* Allocate and set dest */ - cb_to_mono->mb_emit_icon (mb, cb_to_mono->class_native_size (klass, NULL)); - cb_to_mono->mb_emit_byte (mb, CEE_CONV_I); - mono_mb_emit_jit_icall (mb, ves_icall_marshal_alloc); - cb_to_mono->mb_emit_byte (mb, CEE_DUP); - cb_to_mono->mb_emit_stloc (mb, 1); - cb_to_mono->mb_emit_stloc (mb, 3); - - cb_to_mono->emit_struct_conv (mb, klass, FALSE); - - cb_to_mono->mb_patch_branch (mb, pos2); - break; - - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static int -emit_marshal_variant_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ -#ifndef DISABLE_COM - MonoMethodBuilder *mb = m->mb; - MonoType *variant_type = m_class_get_byval_arg (mono_class_get_variant_class ()); - MonoType *variant_type_byref = mono_class_get_byref_type (mono_class_get_variant_class ()); - MonoType *object_type = cb_to_mono->get_object_type (); - - switch (action) { - case MARSHAL_ACTION_CONV_IN: { - conv_arg = cb_to_mono->mb_add_local (mb, variant_type); - - if (m_type_is_byref (t)) - *conv_arg_type = variant_type_byref; - else - *conv_arg_type = variant_type; - - if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - cb_to_mono->mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_byte(mb, CEE_LDIND_REF); - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - cb_to_mono->mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL); - break; - } - - case MARSHAL_ACTION_CONV_OUT: { - if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - cb_to_mono->mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL); - cb_to_mono->mb_emit_byte (mb, CEE_STIND_REF); - } - - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - cb_to_mono->mb_emit_managed_call (mb, mono_get_Variant_Clear (), NULL); - break; - } - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_ldloc_addr (mb, conv_arg); - else - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_RESULT: { - char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_IN: { - conv_arg = cb_to_mono->mb_add_local (mb, object_type); - - if (m_type_is_byref (t)) - *conv_arg_type = variant_type_byref; - else - *conv_arg_type = variant_type; - - if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - if (m_type_is_byref (t)) - cb_to_mono->mb_emit_ldarg (mb, argnum); - else - cb_to_mono->mb_emit_ldarg_addr (mb, argnum); - cb_to_mono->mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL); - cb_to_mono->mb_emit_stloc (mb, conv_arg); - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_OUT: { - if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { - cb_to_mono->mb_emit_ldloc (mb, conv_arg); - cb_to_mono->mb_emit_ldarg (mb, argnum); - cb_to_mono->mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL); - } - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: { - char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); - cb_to_mono->mb_emit_exception_marshal_directive (mb, msg); - break; - } - - default: - g_assert_not_reached (); - } -#endif /* DISABLE_COM */ - - return conv_arg; -} - - -static MonoMarshalILgenCallbacks * -get_marshal_cb (void) -{ - if (G_UNLIKELY (!ilgen_cb_inited)) { -#ifdef ENABLE_ILGEN - mono_marshal_ilgen_init (); -#else - mono_marshal_noilgen_init_heavyweight (); -#endif - } - return &ilgen_marshal_cb; -} - -int -mono_emit_marshal_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action, MonoMarshalLightweightCallbacks* lightweigth_cb) -{ - if (spec && spec->native == MONO_NATIVE_CUSTOM) - return get_marshal_cb ()->emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action); - - if (spec && spec->native == MONO_NATIVE_ASANY) - return get_marshal_cb ()->emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action); - - switch (t->type) { - case MONO_TYPE_VALUETYPE: - if (t->data.klass == cb_to_mono->class_try_get_handleref_class ()) - return get_marshal_cb ()->emit_marshal_handleref (m, argnum, t, spec, conv_arg, conv_arg_type, action); - - return get_marshal_cb ()->emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_STRING: - return get_marshal_cb ()->emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: -#if !defined(DISABLE_COM) - if (spec && spec->native == MONO_NATIVE_STRUCT) - return get_marshal_cb ()->emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action); -#endif - -#if !defined(DISABLE_COM) - if ((spec && (spec->native == MONO_NATIVE_IUNKNOWN || - spec->native == MONO_NATIVE_IDISPATCH || - spec->native == MONO_NATIVE_INTERFACE)) || - (t->type == MONO_TYPE_CLASS && mono_cominterop_is_interface(t->data.klass))) - return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action); - if (spec && (spec->native == MONO_NATIVE_SAFEARRAY) && - (spec->data.safearray_data.elem_type == MONO_VARIANT_VARIANT) && - ((action == MARSHAL_ACTION_CONV_OUT) || (action == MARSHAL_ACTION_CONV_IN) || (action == MARSHAL_ACTION_PUSH))) - return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action); -#endif - - if (cb_to_mono->try_get_safehandle_class () != NULL && t->data.klass && - cb_to_mono->is_subclass_of_internal (t->data.klass, cb_to_mono->try_get_safehandle_class (), FALSE)) - return get_marshal_cb ()->emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action); - - return get_marshal_cb ()->emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - return get_marshal_cb ()->emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_BOOLEAN: - return get_marshal_cb ()->emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_PTR: - return get_marshal_cb ()->emit_marshal_ptr (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_CHAR: - return get_marshal_cb ()->emit_marshal_char (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_R4: - case MONO_TYPE_R8: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - case MONO_TYPE_FNPTR: - return lightweigth_cb->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_GENERICINST: - if (mono_type_generic_inst_is_valuetype (t)) - return get_marshal_cb ()->emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action); - else - return get_marshal_cb ()->emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); - default: - return conv_arg; - } -} - -void -mono_marshal_ilgen_init (void) -{ - MonoMarshalILgenCallbacks cb; - cb.version = MONO_MARSHAL_CALLBACKS_VERSION; - cb.emit_marshal_array = emit_marshal_array_ilgen; - cb.emit_marshal_ptr = emit_marshal_ptr_ilgen; - cb.emit_marshal_char = emit_marshal_char_ilgen; - cb.emit_marshal_vtype = emit_marshal_vtype_ilgen; - cb.emit_marshal_string = emit_marshal_string_ilgen; - cb.emit_marshal_variant = emit_marshal_variant_ilgen; - cb.emit_marshal_safehandle = emit_marshal_safehandle_ilgen; - cb.emit_marshal_object = emit_marshal_object_ilgen; - cb.emit_marshal_boolean = emit_marshal_boolean_ilgen; - cb.emit_marshal_custom = emit_marshal_custom_ilgen; - cb.emit_marshal_asany = emit_marshal_asany_ilgen; - cb.emit_marshal_handleref = emit_marshal_handleref_ilgen; - -#ifdef DISABLE_NONBLITTABLE - mono_marshal_noilgen_init_blittable (&cb); -#endif - mono_install_marshal_callbacks_ilgen (&cb); -} - - diff --git a/src/mono/mono/metadata/CMakeLists.txt b/src/mono/mono/metadata/CMakeLists.txt index 69394f0aba1d0..3eb15313804f3 100644 --- a/src/mono/mono/metadata/CMakeLists.txt +++ b/src/mono/mono/metadata/CMakeLists.txt @@ -16,6 +16,8 @@ set(ilgen_base_sources method-builder-ilgen.c method-builder-ilgen.h method-builder-ilgen-internals.h + marshal-ilgen.c + marshal-ilgen.h marshal-lightweight.c marshal-lightweight.h marshal-shared.c @@ -95,7 +97,6 @@ set(metadata_common_sources marshal.h marshal-internals.h marshal-noilgen.c - marshal-noilgen.h mempool.c mempool.h mempool-internals.h diff --git a/src/mono/mono/metadata/components.c b/src/mono/mono/metadata/components.c index 204c3d9c462f8..f6f94a0b507c9 100644 --- a/src/mono/mono/metadata/components.c +++ b/src/mono/mono/metadata/components.c @@ -43,9 +43,6 @@ typedef struct _MonoComponentEntry { #define DEBUGGER_LIBRARY_NAME "debugger" #define DEBUGGER_COMPONENT_NAME DEBUGGER_LIBRARY_NAME -#define MARSHAL_ILGEN_LIBRARY_NAME "marshal-ilgen" -#define MARSHAL_ILGEN_COMPONENT_NAME "marshal_ilgen" - MonoComponentHotReload *mono_component_hot_reload_private_ptr = NULL; MonoComponentDebugger *mono_component_debugger_private_ptr = NULL; @@ -53,8 +50,6 @@ MonoComponentDebugger *mono_component_debugger_private_ptr = NULL; MonoComponentEventPipe *mono_component_event_pipe_private_ptr = NULL; MonoComponentDiagnosticsServer *mono_component_diagnostics_server_private_ptr = NULL; -MonoComponentMarshalILgen* mono_component_marshal_ilgen_private_ptr = NULL; - // DiagnosticsServer/EventPipe components currently hosted by diagnostics_tracing library. #define DIAGNOSTICS_TRACING_LIBRARY_NAME "diagnostics_tracing" #define EVENT_PIPE_COMPONENT_NAME "event_pipe" @@ -66,7 +61,6 @@ MonoComponentEntry components[] = { { HOT_RELOAD_LIBRARY_NAME, HOT_RELOAD_COMPONENT_NAME, COMPONENT_INIT_FUNC (hot_reload), (MonoComponent**)&mono_component_hot_reload_private_ptr, NULL }, { DIAGNOSTICS_TRACING_LIBRARY_NAME, EVENT_PIPE_COMPONENT_NAME, COMPONENT_INIT_FUNC (event_pipe), (MonoComponent**)&mono_component_event_pipe_private_ptr, NULL }, { DIAGNOSTICS_TRACING_LIBRARY_NAME, DIAGNOSTICS_SERVER_COMPONENT_NAME, COMPONENT_INIT_FUNC (diagnostics_server), (MonoComponent**)&mono_component_diagnostics_server_private_ptr, NULL }, - { MARSHAL_ILGEN_LIBRARY_NAME, MARSHAL_ILGEN_COMPONENT_NAME, COMPONENT_INIT_FUNC (marshal_ilgen), (MonoComponent**)&mono_component_marshal_ilgen_private_ptr, NULL } }; #ifndef STATIC_COMPONENTS diff --git a/src/mono/mono/metadata/components.h b/src/mono/mono/metadata/components.h index f6b8696d194f0..aba0317458943 100644 --- a/src/mono/mono/metadata/components.h +++ b/src/mono/mono/metadata/components.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -25,7 +24,6 @@ extern MonoComponentHotReload *mono_component_hot_reload_private_ptr; extern MonoComponentEventPipe *mono_component_event_pipe_private_ptr; extern MonoComponentDiagnosticsServer *mono_component_diagnostics_server_private_ptr; extern MonoComponentDebugger *mono_component_debugger_private_ptr; -extern MonoComponentMarshalILgen *mono_component_marshal_ilgen_private_ptr; /* Declare each component's getter function here */ static inline @@ -56,11 +54,4 @@ mono_component_debugger (void) return mono_component_debugger_private_ptr; } -static inline -MonoComponentMarshalILgen* -mono_component_marshal_ilgen (void) -{ - return mono_component_marshal_ilgen_private_ptr; -} - -#endif/*_MONO_METADATA_COMPONENTS_H*/ \ No newline at end of file +#endif/*_MONO_METADATA_COMPONENTS_H*/ diff --git a/src/mono/mono/metadata/marshal-ilgen.c b/src/mono/mono/metadata/marshal-ilgen.c new file mode 100644 index 0000000000000..ceceb70149f21 --- /dev/null +++ b/src/mono/mono/metadata/marshal-ilgen.c @@ -0,0 +1,2830 @@ +#include "mono/metadata/debug-helpers.h" +#include "metadata/marshal.h" +#include "metadata/marshal-ilgen.h" +#include "metadata/marshal-lightweight.h" +#include "metadata/marshal-shared.h" +#include "metadata/method-builder-ilgen.h" +#include "metadata/custom-attrs-internals.h" +#include "metadata/class-init.h" +#include "mono/metadata/class-internals.h" +#include "metadata/reflection-internals.h" +#include "mono/metadata/handle.h" + + + +#define OPDEF(a,b,c,d,e,f,g,h,i,j) \ + a = i, + +enum { +#include "mono/cil/opcode.def" + LAST = 0xff +}; +#undef OPDEF + +static GENERATE_GET_CLASS_WITH_CACHE (date_time, "System", "DateTime"); +static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, "System.Runtime.InteropServices", "ICustomMarshaler"); + +static void emit_string_free_icall (MonoMethodBuilder *mb, MonoMarshalConv conv); + +// TODO: Does this need to loose the mono_ prefix? +static void mono_marshal_ilgen_legacy_init (void); + +static gboolean ilgen_cb_inited = FALSE; +static MonoMarshalIlgenCallbacks ilgen_marshal_cb; + +void +mono_install_marshal_callbacks_ilgen (MonoMarshalIlgenCallbacks *cb) +{ + g_assert (!ilgen_cb_inited); + g_assert (cb->version == MONO_MARSHAL_CALLBACKS_VERSION); + memcpy (&ilgen_marshal_cb, cb, sizeof (MonoMarshalIlgenCallbacks)); + ilgen_cb_inited = TRUE; +} + + +static void +emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var) +{ + /* Call DestroyStructure */ + /* FIXME: Only do this if needed */ + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); + mono_mb_emit_ldloc (mb, struct_var); + mono_mb_emit_icall (mb, mono_struct_delete_old); +} + +static int +emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoClass *klass = mono_class_from_mono_type_internal (t); + MonoMarshalNative encoding; + + encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + MonoType *int_type = mono_get_int_type (); + MonoType *object_type = mono_get_object_type (); + + MonoClass *eklass = m_class_get_element_class (klass); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = object_type; + conv_arg = mono_mb_add_local (mb, object_type); + + if (m_class_is_blittable (eklass)) { + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL)); + mono_mb_emit_stloc (mb, conv_arg); + } else { +#ifdef DISABLE_NONBLITTABLE + char *msg = g_strdup ("Non-blittable marshalling conversion is disabled"); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); +#else + guint32 label1, label2, label3; + int index_var, src_var, dest_ptr, esize; + MonoMarshalConv conv; + gboolean is_string = FALSE; + + dest_ptr = mono_mb_add_local (mb, int_type); + + if (eklass == mono_defaults.string_class) { + is_string = TRUE; + conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); + } + else if (eklass == mono_class_try_get_stringbuilder_class ()) { + is_string = TRUE; + conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); + } + else + conv = MONO_MARSHAL_CONV_INVALID; + + if (is_string && conv == MONO_MARSHAL_CONV_INVALID) { + char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + src_var = mono_mb_add_local (mb, object_type); + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, src_var); + + /* Check null */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_stloc (mb, conv_arg); + mono_mb_emit_ldloc (mb, src_var); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + if (is_string) + esize = TARGET_SIZEOF_VOID_P; + else if (eklass == mono_defaults.char_class) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/ + esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1; + else + esize = mono_class_native_size (eklass, NULL); + + /* allocate space for the native struct and store the address */ + mono_mb_emit_icon (mb, esize); + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_byte (mb, CEE_LDLEN); + + if (eklass == mono_defaults.string_class) { + /* Make the array bigger for the terminating null */ + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_byte (mb, CEE_ADD); + } + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_LOCALLOC); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, dest_ptr); + + /* Emit marshalling loop */ + index_var = mono_mb_add_local (mb, int_type); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Emit marshalling code */ + + if (is_string) { + int stind_op; + mono_mb_emit_ldloc (mb, dest_ptr); + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_byte (mb, CEE_LDELEM_REF); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); + mono_mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); + } else { + /* set the src_ptr */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_op (mb, CEE_LDELEMA, eklass); + mono_mb_emit_stloc (mb, 0); + + /* set dst_ptr */ + mono_mb_emit_ldloc (mb, dest_ptr); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv_full (mb, eklass, FALSE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1); + } + + mono_mb_emit_add_to_local (mb, GINT_TO_UINT16 (index_var), 1); + mono_mb_emit_add_to_local (mb, GINT_TO_UINT16 (dest_ptr), esize); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label3); + + if (eklass == mono_defaults.string_class) { + /* Null terminate */ + mono_mb_emit_ldloc (mb, dest_ptr); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_byte (mb, CEE_STIND_I); + } + + mono_mb_patch_branch (mb, label1); +#endif + } + + break; + + case MARSHAL_ACTION_CONV_OUT: { +#ifndef DISABLE_NONBLITTABLE + gboolean need_convert, need_free; + /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */ + need_convert = ((eklass == mono_defaults.char_class) && (encoding == MONO_NATIVE_LPWSTR)) || (eklass == mono_class_try_get_stringbuilder_class ()) || (t->attrs & PARAM_ATTRIBUTE_OUT); + need_free = mono_marshal_need_free (m_class_get_byval_arg (eklass), m->piinfo, spec); + + if ((t->attrs & PARAM_ATTRIBUTE_OUT) && spec && spec->native == MONO_NATIVE_LPARRAY && spec->data.array_data.param_num != -1) { + int param_num = spec->data.array_data.param_num; + MonoType *param_type; + + param_type = m->sig->params [param_num]; + + if (m_type_is_byref (param_type) && param_type->type != MONO_TYPE_I4) { + char *msg = g_strdup ("Not implemented."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + if (m_type_is_byref (t) ) { + mono_mb_emit_ldarg (mb, argnum); + + /* Create the managed array */ + mono_mb_emit_ldarg (mb, param_num); + if (m_type_is_byref (m->sig->params [param_num])) + // FIXME: Support other types + mono_mb_emit_byte (mb, CEE_LDIND_I4); + mono_mb_emit_byte (mb, CEE_CONV_OVF_I); + mono_mb_emit_op (mb, CEE_NEWARR, eklass); + /* Store into argument */ + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + } + + if (need_convert || need_free) { + /* FIXME: Optimize blittable case */ + guint32 label1, label2, label3; + int index_var, src_ptr, loc, esize; + + if ((eklass == mono_class_try_get_stringbuilder_class ()) || (eklass == mono_defaults.string_class)) + esize = TARGET_SIZEOF_VOID_P; + else if (eklass == mono_defaults.char_class) + esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1; + else + esize = mono_class_native_size (eklass, NULL); + src_ptr = mono_mb_add_local (mb, int_type); + loc = mono_mb_add_local (mb, int_type); + + /* Check null */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, src_ptr); + + /* Emit marshalling loop */ + index_var = mono_mb_add_local (mb, int_type); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Emit marshalling code */ + + if (eklass == mono_class_try_get_stringbuilder_class ()) { + gboolean need_free2; + MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2); + + g_assert (conv != MONO_MARSHAL_CONV_INVALID); + + /* dest */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_byte (mb, CEE_LDELEM_REF); + + /* src */ + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); + + if (need_free) { + /* src */ + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_icall (mb, mono_marshal_free); + } + } + else if (eklass == mono_defaults.string_class) { + if (need_free) { + /* src */ + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_icall (mb, mono_marshal_free); + } + } + else { + if (need_convert) { + /* set the src_ptr */ + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_stloc (mb, 0); + + /* set dst_ptr */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_op (mb, CEE_LDELEMA, eklass); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1); + } + + if (need_free) { + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_stloc (mb, loc); + + emit_struct_free (mb, eklass, loc); + } + } + + mono_mb_emit_add_to_local (mb, GINT_TO_UINT16 (index_var), 1); + mono_mb_emit_add_to_local (mb, GINT_TO_UINT16 (src_ptr), esize); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label1); + mono_mb_patch_branch (mb, label3); + } +#endif + + if (m_class_is_blittable (eklass)) { + /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */ + + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL)); + } + + break; + } + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: { + mono_mb_emit_byte (mb, CEE_POP); + char *msg = g_strdup_printf ("Cannot marshal 'return value': Invalid managed/unmanaged type combination."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: { + guint32 label1, label2, label3; + int index_var, src_ptr, esize, param_num, num_elem; + MonoMarshalConv conv; + gboolean is_string = FALSE; + + conv_arg = mono_mb_add_local (mb, object_type); + *conv_arg_type = int_type; + + if (m_type_is_byref (t)) { + char *msg = g_strdup ("Byref array marshalling to managed code is not implemented."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + if (!spec) { + char *msg = g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + + switch (spec->native) { + case MONO_NATIVE_LPARRAY: + break; + case MONO_NATIVE_SAFEARRAY: +#ifndef DISABLE_COM + if (spec->data.safearray_data.elem_type != MONO_VARIANT_VARIANT) { + char *msg = g_strdup ("Only SAFEARRAY(VARIANT) marshalling to managed code is implemented."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action); +#endif + default: { + char *msg = g_strdup ("Unsupported array type marshalling to managed code."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + } + + /* FIXME: t is from the method which is wrapped, not the delegate type */ + /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */ + + param_num = spec->data.array_data.param_num; + num_elem = spec->data.array_data.num_elem; + if (spec->data.array_data.elem_mult == 0) + /* param_num is not specified */ + param_num = -1; + + if (param_num == -1) { + if (num_elem <= 0) { + char *msg = g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + } + + /* FIXME: Optimize blittable case */ + +#ifndef DISABLE_NONBLITTABLE + if (eklass == mono_defaults.string_class) { + is_string = TRUE; + gboolean need_free; + conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); + } + else if (eklass == mono_class_try_get_stringbuilder_class ()) { + is_string = TRUE; + gboolean need_free; + conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free); + } + else + conv = MONO_MARSHAL_CONV_INVALID; +#endif + + mono_marshal_load_type_info (eklass); + + if (is_string) + esize = TARGET_SIZEOF_VOID_P; + else + esize = mono_class_native_size (eklass, NULL); + src_ptr = mono_mb_add_local (mb, int_type); + + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + + /* Check param index */ + if (param_num != -1) { + if (param_num >= m->sig->param_count) { + char *msg = g_strdup ("Array size control parameter index is out of range."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + switch (m->sig->params [param_num]->type) { + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + break; + default: { + char *msg = g_strdup ("Array size control parameter must be an integral type."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + } + } + + /* Check null */ + mono_mb_emit_ldarg (mb, argnum); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_stloc (mb, src_ptr); + + /* Create managed array */ + /* + * The LPArray marshalling spec says that sometimes param_num starts + * from 1, sometimes it starts from 0. But MS seems to always start + * from 0. + */ + + if (param_num == -1) { + mono_mb_emit_icon (mb, num_elem); + } else { + mono_mb_emit_ldarg (mb, param_num); + if (num_elem > 0) { + mono_mb_emit_icon (mb, num_elem); + mono_mb_emit_byte (mb, CEE_ADD); + } + mono_mb_emit_byte (mb, CEE_CONV_OVF_I); + } + + mono_mb_emit_op (mb, CEE_NEWARR, eklass); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_class_is_blittable (eklass)) { + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_LDLEN); + mono_mb_emit_icon (mb, esize); + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CPBLK); + mono_mb_patch_branch (mb, label1); + break; + } +#ifdef DISABLE_NONBLITTABLE + else { + char *msg = g_strdup ("Non-blittable marshalling conversion is disabled"); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + } +#else + /* Emit marshalling loop */ + index_var = mono_mb_add_local (mb, int_type); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Emit marshalling code */ + if (is_string) { + g_assert (conv != MONO_MARSHAL_CONV_INVALID); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldloc (mb, index_var); + + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); + mono_mb_emit_byte (mb, CEE_STELEM_REF); + } + else { + char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + + mono_mb_emit_add_to_local (mb, GINT_TO_UINT16 (index_var), 1); + mono_mb_emit_add_to_local (mb, GINT_TO_UINT16 (src_ptr), esize); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label1); + mono_mb_patch_branch (mb, label3); +#endif + + break; + } + case MARSHAL_ACTION_MANAGED_CONV_OUT: { + guint32 label1, label2, label3; + int index_var, dest_ptr, esize, param_num, num_elem; + MonoMarshalConv conv; + gboolean is_string = FALSE; + + if (!spec) + /* Already handled in CONV_IN */ + break; + + /* These are already checked in CONV_IN */ + g_assert (!m_type_is_byref (t)); + g_assert (spec->native == MONO_NATIVE_LPARRAY); + g_assert (t->attrs & PARAM_ATTRIBUTE_OUT); + + param_num = spec->data.array_data.param_num; + num_elem = spec->data.array_data.num_elem; + + if (spec->data.array_data.elem_mult == 0) + /* param_num is not specified */ + param_num = -1; + + if (param_num == -1) { + if (num_elem <= 0) { + g_assert_not_reached (); + } + } + + /* FIXME: Optimize blittable case */ + +#ifndef DISABLE_NONBLITTABLE + if (eklass == mono_defaults.string_class) { + is_string = TRUE; + conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); + } + else if (eklass == mono_class_try_get_stringbuilder_class ()) { + is_string = TRUE; + conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); + } + else + conv = MONO_MARSHAL_CONV_INVALID; +#endif + + mono_marshal_load_type_info (eklass); + + if (is_string) + esize = TARGET_SIZEOF_VOID_P; + else + esize = mono_class_native_size (eklass, NULL); + + dest_ptr = mono_mb_add_local (mb, int_type); + + /* Check null */ + mono_mb_emit_ldloc (mb, conv_arg); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_stloc (mb, dest_ptr); + + if (m_class_is_blittable (eklass)) { + /* dest */ + mono_mb_emit_ldarg (mb, argnum); + /* src */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); + mono_mb_emit_byte (mb, CEE_ADD); + /* length */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_LDLEN); + mono_mb_emit_icon (mb, esize); + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CPBLK); + mono_mb_patch_branch (mb, label1); + break; + } + +#ifndef DISABLE_NONBLITTABLE + /* Emit marshalling loop */ + index_var = mono_mb_add_local (mb, int_type); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Emit marshalling code */ + if (is_string) { + int stind_op; + g_assert (conv != MONO_MARSHAL_CONV_INVALID); + + /* dest */ + mono_mb_emit_ldloc (mb, dest_ptr); + + /* src */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldloc (mb, index_var); + + mono_mb_emit_byte (mb, CEE_LDELEM_REF); + + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); + mono_mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); + } + else { + char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + + mono_mb_emit_add_to_local (mb, GINT_TO_UINT16 (index_var), 1); + mono_mb_emit_add_to_local (mb, GINT_TO_UINT16 (dest_ptr), esize); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label1); + mono_mb_patch_branch (mb, label3); +#endif + + break; + } + case MARSHAL_ACTION_MANAGED_CONV_RESULT: { +#ifndef DISABLE_NONBLITTABLE + guint32 label1, label2, label3; + int index_var, src, dest, esize; + MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID; + gboolean is_string = FALSE; + + g_assert (!m_type_is_byref (t)); + + mono_marshal_load_type_info (eklass); + + if (eklass == mono_defaults.string_class) { + is_string = TRUE; + conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); + } + else { + g_assert_not_reached (); + } + + if (is_string) + esize = TARGET_SIZEOF_VOID_P; + else if (eklass == mono_defaults.char_class) + esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1; + else + esize = mono_class_native_size (eklass, NULL); + + src = mono_mb_add_local (mb, object_type); + dest = mono_mb_add_local (mb, int_type); + + mono_mb_emit_stloc (mb, src); + mono_mb_emit_ldloc (mb, src); + mono_mb_emit_stloc (mb, 3); + + /* Check for null */ + mono_mb_emit_ldloc (mb, src); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* Allocate native array */ + mono_mb_emit_icon (mb, esize); + mono_mb_emit_ldloc (mb, src); + mono_mb_emit_byte (mb, CEE_LDLEN); + + if (eklass == mono_defaults.string_class) { + /* Make the array bigger for the terminating null */ + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_byte (mb, CEE_ADD); + } + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_icall (mb, ves_icall_marshal_alloc); + mono_mb_emit_stloc (mb, dest); + mono_mb_emit_ldloc (mb, dest); + mono_mb_emit_stloc (mb, 3); + + /* Emit marshalling loop */ + index_var = mono_mb_add_local (mb, int_type); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, src); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Emit marshalling code */ + if (is_string) { + int stind_op; + g_assert (conv != MONO_MARSHAL_CONV_INVALID); + + /* dest */ + mono_mb_emit_ldloc (mb, dest); + + /* src */ + mono_mb_emit_ldloc (mb, src); + mono_mb_emit_ldloc (mb, index_var); + + mono_mb_emit_byte (mb, CEE_LDELEM_REF); + + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); + mono_mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); + } + else { + char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + + mono_mb_emit_add_to_local (mb, GINT_TO_UINT16 (index_var), 1); + mono_mb_emit_add_to_local (mb, GINT_TO_UINT16 (dest), esize); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label3); + mono_mb_patch_branch (mb, label1); +#endif + break; + } + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static gboolean +emit_native_wrapper_validate_signature (MonoMethodBuilder *mb, MonoMethodSignature* sig, MonoMarshalSpec** mspecs) +{ + if (mspecs) { + for (int i = 0; i < sig->param_count; i ++) { + if (mspecs [i + 1] && mspecs [i + 1]->native == MONO_NATIVE_CUSTOM) { + if (!mspecs [i + 1]->data.custom_data.custom_name || *mspecs [i + 1]->data.custom_data.custom_name == '\0') { + mono_mb_emit_exception_full (mb, "System", "TypeLoadException", g_strdup ("Missing ICustomMarshaler type")); + return FALSE; + } + + switch (sig->params[i]->type) { + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_VALUETYPE: + break; + + default: + mono_mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", g_strdup_printf ("custom marshalling of type %x is currently not supported", sig->params[i]->type)); + return FALSE; + } + } + else if (sig->params[i]->type == MONO_TYPE_VALUETYPE) { + MonoMarshalType *marshal_type = mono_marshal_load_type_info (mono_class_from_mono_type_internal (sig->params [i])); + for (guint32 field_idx = 0; field_idx < marshal_type->num_fields; ++field_idx) { + if (marshal_type->fields [field_idx].mspec && marshal_type->fields [field_idx].mspec->native == MONO_NATIVE_CUSTOM) { + mono_mb_emit_exception_full (mb, "System", "TypeLoadException", g_strdup ("Value type includes custom marshaled fields")); + return FALSE; + } + } + } + } + } + + return TRUE; +} + +static int +emit_marshal_ptr_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + switch (action) { + case MARSHAL_ACTION_CONV_IN: + /* MS seems to allow this in some cases, ie. bxc #158 */ + /* + if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type_internal (t->data.type)->blittable) { + char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1); + mono_marshal_shared_mb_emit_exception_marshal_directive (m->mb, msg); + } + */ + break; + + case MARSHAL_ACTION_PUSH: + mono_mb_emit_ldarg (mb, argnum); + break; + + case MARSHAL_ACTION_CONV_RESULT: + /* no conversions necessary */ + mono_mb_emit_stloc (mb, 3); + break; + + default: + break; + } + return conv_arg; +} + +static int +emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoType *int_type = mono_get_int_type (); + MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: { + MonoType *local_type; + int label_false; + guint8 ldc_op = CEE_LDC_I4_1; + + local_type = mono_marshal_boolean_conv_in_get_local_type (spec, &ldc_op); + if (m_type_is_byref (t)) + *conv_arg_type = int_type; + else + *conv_arg_type = local_type; + conv_arg = mono_mb_add_local (mb, local_type); + + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I1); + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, ldc_op); + mono_mb_emit_stloc (mb, conv_arg); + mono_mb_patch_branch (mb, label_false); + + break; + } + + case MARSHAL_ACTION_CONV_OUT: + { + int label_false, label_end; + if (!m_type_is_byref (t)) + break; + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + + label_end = mono_mb_emit_branch (mb, CEE_BR); + mono_mb_patch_branch (mb, label_false); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_patch_branch (mb, label_end); + + mono_mb_emit_byte (mb, CEE_STIND_I1); + break; + } + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else if (conv_arg) + mono_mb_emit_ldloc (mb, conv_arg); + else + mono_mb_emit_ldarg (mb, argnum); + break; + + case MARSHAL_ACTION_CONV_RESULT: + /* maybe we need to make sure that it fits within 8 bits */ + mono_mb_emit_stloc (mb, 3); + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: { + MonoClass* conv_arg_class = mono_defaults.int32_class; + guint8 ldop = CEE_LDIND_I4; + int label_null, label_false; + + conv_arg_class = mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec, &ldop); + conv_arg = mono_mb_add_local (mb, boolean_type); + + if (m_type_is_byref (t)) + *conv_arg_type = m_class_get_this_arg (conv_arg_class); + else + *conv_arg_type = m_class_get_byval_arg (conv_arg_class); + + + mono_mb_emit_ldarg (mb, argnum); + + /* Check null */ + if (m_type_is_byref (t)) { + label_null = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, ldop); + } else + label_null = 0; + + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_stloc (mb, conv_arg); + mono_mb_patch_branch (mb, label_false); + + if (m_type_is_byref (t)) + mono_mb_patch_branch (mb, label_null); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_OUT: { + guint8 stop = CEE_STIND_I4; + guint8 ldc_op = CEE_LDC_I4_1; + int label_null,label_false, label_end; + + if (!m_type_is_byref (t)) + break; + if (spec) { + switch (spec->native) { + case MONO_NATIVE_I1: + case MONO_NATIVE_U1: + stop = CEE_STIND_I1; + break; + case MONO_NATIVE_VARIANTBOOL: + stop = CEE_STIND_I2; + ldc_op = CEE_LDC_I4_M1; + break; + default: + break; + } + } + + /* Check null */ + mono_mb_emit_ldarg (mb, argnum); + label_null = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, ldc_op); + label_end = mono_mb_emit_branch (mb, CEE_BR); + + mono_mb_patch_branch (mb, label_false); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_patch_branch (mb, label_end); + + mono_mb_emit_byte (mb, stop); + mono_mb_patch_branch (mb, label_null); + break; + } + + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static int +emit_marshal_char_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + + switch (action) { + case MARSHAL_ACTION_PUSH: + /* fixme: dont know how to marshal that. We cant simply + * convert it to a one byte UTF8 character, because an + * unicode character may need more that one byte in UTF8 */ + mono_mb_emit_ldarg (mb, argnum); + break; + + case MARSHAL_ACTION_CONV_RESULT: + /* fixme: we need conversions here */ + mono_mb_emit_stloc (mb, 3); + break; + + default: + break; + } + return conv_arg; +} + +static int +emit_marshal_custom_ilgen_throw_exception (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg, MarshalAction action) +{ + /* Throw exception and emit compensation code, if necessary */ + switch (action) { + case MARSHAL_ACTION_CONV_IN: + case MARSHAL_ACTION_MANAGED_CONV_IN: + case MARSHAL_ACTION_CONV_RESULT: + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + if ((action == MARSHAL_ACTION_CONV_RESULT) || (action == MARSHAL_ACTION_MANAGED_CONV_RESULT)) + mono_mb_emit_byte (mb, CEE_POP); + + mono_mb_emit_exception_full (mb, exc_nspace, exc_name, msg); + + break; + case MARSHAL_ACTION_PUSH: + mono_mb_emit_byte (mb, CEE_LDNULL); + break; + default: + break; + } + + return 0; +} + +static int +emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + ERROR_DECL (error); + MonoType *mtype; + MonoClass *mklass; + static MonoClass *ICustomMarshaler = NULL; + static MonoMethod *cleanup_native, *cleanup_managed; + static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed; + MonoMethodBuilder *mb = m->mb; + MonoAssemblyLoadContext *alc = mono_alc_get_ambient (); + guint32 loc1; + int pos2; + + MonoType *int_type = mono_get_int_type (); + MonoType *object_type = mono_get_object_type (); + + if (!ICustomMarshaler) { + MonoClass *klass = mono_class_try_get_icustom_marshaler_class (); + if (!klass) + return emit_marshal_custom_ilgen_throw_exception (mb, "System", "ApplicationException", g_strdup ("Current profile doesn't support ICustomMarshaler"), action); + + cleanup_native = mono_marshal_shared_get_method_nofail (klass, "CleanUpNativeData", 1, 0); + g_assert (cleanup_native); + + cleanup_managed = mono_marshal_shared_get_method_nofail (klass, "CleanUpManagedData", 1, 0); + g_assert (cleanup_managed); + + marshal_managed_to_native = mono_marshal_shared_get_method_nofail (klass, "MarshalManagedToNative", 1, 0); + g_assert (marshal_managed_to_native); + + marshal_native_to_managed = mono_marshal_shared_get_method_nofail (klass, "MarshalNativeToManaged", 1, 0); + g_assert (marshal_native_to_managed); + + mono_memory_barrier (); + ICustomMarshaler = klass; + } + + if (spec->data.custom_data.image) + mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, alc, spec->data.custom_data.image, error); + else + mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, alc, m->image, error); + + if (!mtype) + return emit_marshal_custom_ilgen_throw_exception (mb, "System", "TypeLoadException", g_strdup ("Failed to load ICustomMarshaler type"), action); + + mklass = mono_class_from_mono_type_internal (mtype); + g_assert (mklass != NULL); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: + switch (t->type) { + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_VALUETYPE: + break; + + default: + g_warning ("custom marshalling of type %x is currently not supported", t->type); + g_assert_not_reached (); + break; + } + + conv_arg = mono_mb_add_local (mb, int_type); + + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) + break; + + /* Minic MS.NET behavior */ + if (!m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN)) + break; + + /* Check for null */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); + + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_REF); + + if (t->type == MONO_TYPE_VALUETYPE) { + /* + * Since we can't determine the type of the argument, we + * will assume the unmanaged function takes a pointer. + */ + *conv_arg_type = int_type; + + mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (t)); + } + + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_CONV_OUT: + /* Check for null */ + mono_mb_emit_ldloc (mb, conv_arg); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_OUT)) { + mono_mb_emit_ldarg (mb, argnum); + + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); + mono_mb_emit_byte (mb, CEE_DUP); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } else if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) { + mono_mb_emit_ldarg (mb, argnum); + + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } else if (t->attrs & PARAM_ATTRIBUTE_OUT) { + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); + /* We have nowhere to store the result */ + mono_mb_emit_byte (mb, CEE_POP); + } + + // Only call cleanup_native if MARSHAL_ACTION_CONV_IN called marshal_managed_to_native. + if (!(m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) && + !(!m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN))) { + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); + + mono_mb_emit_ldloc (mb, conv_arg); + + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native); + } + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: + mono_mb_emit_stloc (mb, 3); + + /* Check for null */ + mono_mb_emit_ldloc (mb, 3); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); + + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); + mono_mb_emit_stloc (mb, 3); + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: + switch (t->type) { + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_VALUETYPE: + case MONO_TYPE_BOOLEAN: + break; + + default: + g_warning ("custom marshalling of type %x is currently not supported", t->type); + g_assert_not_reached (); + break; + } + + conv_arg = mono_mb_add_local (mb, object_type); + + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_type_is_byref (t) && t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + /* Check for null */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); + + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + g_assert (!m_type_is_byref (t)); + + loc1 = mono_mb_add_local (mb, object_type); + + mono_mb_emit_stloc (mb, 3); + + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_stloc (mb, loc1); + + /* Check for null */ + mono_mb_emit_ldloc (mb, 3); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); + mono_mb_emit_byte (mb, CEE_DUP); + + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); + mono_mb_emit_stloc (mb, 3); + + mono_mb_emit_ldloc (mb, loc1); + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + + /* Check for null */ + mono_mb_emit_ldloc (mb, conv_arg); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + if (m_type_is_byref (t)) { + mono_mb_emit_ldarg (mb, argnum); + + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); + mono_mb_emit_byte (mb, CEE_STIND_I); + } + + // Only call cleanup_managed if MARSHAL_ACTION_MANAGED_CONV_IN called marshal_native_to_managed. + if (!(m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); + } + + mono_mb_patch_branch (mb, pos2); + break; + + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static int +emit_marshal_asany_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + + MonoType *int_type = mono_get_int_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: { + MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL); + + g_assert (t->type == MONO_TYPE_OBJECT); + g_assert (!m_type_is_byref (t)); + + conv_arg = mono_mb_add_local (mb, int_type); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_icon (mb, encoding); + mono_mb_emit_icon (mb, t->attrs); + mono_mb_emit_icall (mb, mono_marshal_asany); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + case MARSHAL_ACTION_PUSH: + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_OUT: { + MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icon (mb, encoding); + mono_mb_emit_icon (mb, t->attrs); + mono_mb_emit_icall (mb, mono_marshal_free_asany); + break; + } + + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static int +emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoClass *klass, *date_time_class; + int pos = 0, pos2; + + klass = mono_class_from_mono_type_internal (t); + + date_time_class = mono_class_get_date_time_class (); + + MonoType *int_type = mono_get_int_type (); + MonoType *double_type = m_class_get_byval_arg (mono_defaults.double_class); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: + if (klass == date_time_class) { + /* Convert it to an OLE DATE type */ + + conv_arg = mono_mb_add_local (mb, double_type); + + if (m_type_is_byref (t)) { + mono_mb_emit_ldarg (mb, argnum); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + } + + if (!(m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { + if (!m_type_is_byref (t)) + m->csig->params [argnum - m->csig->hasthis] = double_type; + + MONO_STATIC_POINTER_INIT (MonoMethod, to_oadate) + to_oadate = mono_marshal_shared_get_method_nofail (date_time_class, "ToOADate", 0, 0); + g_assert (to_oadate); + MONO_STATIC_POINTER_INIT_END (MonoMethod, to_oadate) + + mono_mb_emit_ldarg_addr (mb, argnum); + mono_mb_emit_managed_call (mb, to_oadate, NULL); + mono_mb_emit_stloc (mb, conv_arg); + } + + if (m_type_is_byref (t)) + mono_mb_patch_branch (mb, pos); + break; + } + + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) + break; + + conv_arg = mono_mb_add_local (mb, int_type); + + /* store the address of the source into local variable 0 */ + if (m_type_is_byref (t)) + mono_mb_emit_ldarg (mb, argnum); + else + mono_mb_emit_ldarg_addr (mb, argnum); + + mono_mb_emit_stloc (mb, 0); + + /* allocate space for the native struct and + * store the address into local variable 1 (dest) */ + mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_LOCALLOC); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_type_is_byref (t)) { + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + } + + if (!(m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { + /* set dst_ptr */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + } + + if (m_type_is_byref (t)) + mono_mb_patch_branch (mb, pos); + break; + + case MARSHAL_ACTION_PUSH: + if (spec && spec->native == MONO_NATIVE_LPSTRUCT) { + /* FIXME: */ + g_assert (!m_type_is_byref (t)); + + /* Have to change the signature since the vtype is passed byref */ + m->csig->params [argnum - m->csig->hasthis] = int_type; + + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) + mono_mb_emit_ldarg_addr (mb, argnum); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + } + + if (klass == date_time_class) { + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + } + + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { + mono_mb_emit_ldarg (mb, argnum); + break; + } + mono_mb_emit_ldloc (mb, conv_arg); + if (!m_type_is_byref (t)) { + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, klass); + } + break; + + case MARSHAL_ACTION_CONV_OUT: + if (klass == date_time_class) { + /* Convert from an OLE DATE type */ + + if (!m_type_is_byref (t)) + break; + + if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) { + + MONO_STATIC_POINTER_INIT (MonoMethod, from_oadate) + from_oadate = mono_marshal_shared_get_method_nofail (date_time_class, "FromOADate", 1, 0); + MONO_STATIC_POINTER_INIT_END (MonoMethod, from_oadate) + + g_assert (from_oadate); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_managed_call (mb, from_oadate, NULL); + mono_mb_emit_op (mb, CEE_STOBJ, date_time_class); + } + break; + } + + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) + break; + + if (m_type_is_byref (t)) { + /* dst = argument */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_stloc (mb, 1); + + mono_mb_emit_ldloc (mb, 1); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) { + /* src = tmp_locals [i] */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, 0); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + } + } + + emit_struct_free (mb, klass, conv_arg); + + if (m_type_is_byref (t)) + mono_mb_patch_branch (mb, pos); + break; + + case MARSHAL_ACTION_CONV_RESULT: + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass)) { + mono_mb_emit_stloc (mb, 3); + break; + } + + /* load pointer to returned value type */ + g_assert (m->vtaddr_var); + mono_mb_emit_ldloc (mb, m->vtaddr_var); + /* store the address of the source into local variable 0 */ + mono_mb_emit_stloc (mb, 0); + /* set dst_ptr */ + mono_mb_emit_ldloc_addr (mb, 3); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { + conv_arg = 0; + break; + } + + conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass)); + + if (t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + if (m_type_is_byref (t)) + mono_mb_emit_ldarg (mb, argnum); + else + mono_mb_emit_ldarg_addr (mb, argnum); + mono_mb_emit_stloc (mb, 0); + + if (m_type_is_byref (t)) { + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + } + + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + + if (m_type_is_byref (t)) + mono_mb_patch_branch (mb, pos); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) + break; + if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT)) + break; + + /* Check for null */ + mono_mb_emit_ldarg (mb, argnum); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* Set src */ + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_stloc (mb, 0); + + /* Set dest */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { + mono_mb_emit_stloc (mb, 3); + m->retobj_var = 0; + break; + } + + /* load pointer to returned value type */ + g_assert (m->vtaddr_var); + mono_mb_emit_ldloc (mb, m->vtaddr_var); + + /* store the address of the source into local variable 0 */ + mono_mb_emit_stloc (mb, 0); + /* allocate space for the native struct and + * store the address into dst_ptr */ + m->retobj_var = mono_mb_add_local (mb, int_type); + m->retobj_class = klass; + g_assert (m->retobj_var); + mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icall (mb, ves_icall_marshal_alloc); + mono_mb_emit_stloc (mb, 1); + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_stloc (mb, m->retobj_var); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + break; + + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static void +emit_string_free_icall (MonoMethodBuilder *mb, MonoMarshalConv conv) +{ + if (conv == MONO_MARSHAL_CONV_BSTR_STR || conv == MONO_MARSHAL_CONV_ANSIBSTR_STR || conv == MONO_MARSHAL_CONV_TBSTR_STR) + mono_mb_emit_icall (mb, mono_free_bstr); + else + mono_mb_emit_icall (mb, mono_marshal_free); +} + +static int +emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + MonoMarshalConv conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); + gboolean need_free; + + MonoType *int_type = mono_get_int_type (); + MonoType *object_type = mono_get_object_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = int_type; + conv_arg = mono_mb_add_local (mb, int_type); + + if (m_type_is_byref (t)) { + if (t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_I); + } else { + mono_mb_emit_ldarg (mb, argnum); + } + + if (conv == MONO_MARSHAL_CONV_INVALID) { + char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + } else { + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); + + mono_mb_emit_stloc (mb, conv_arg); + } + break; + + case MARSHAL_ACTION_CONV_OUT: + conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); + if (conv == MONO_MARSHAL_CONV_INVALID) { + char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + if (encoding == MONO_NATIVE_VBBYREFSTR) { + + if (!m_type_is_byref (t)) { + char *msg = g_strdup ("VBByRefStr marshalling requires a ref parameter."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + MONO_STATIC_POINTER_INIT (MonoMethod, method) + + method = mono_marshal_shared_get_method_nofail (mono_defaults.string_class, "get_Length", -1, 0); + + MONO_STATIC_POINTER_INIT_END (MonoMethod, method) + + /* + * Have to allocate a new string with the same length as the original, and + * copy the contents of the buffer pointed to by CONV_ARG into it. + */ + g_assert (m_type_is_byref (t)); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_managed_call (mb, method, NULL); + mono_mb_emit_icall (mb, mono_string_new_len_wrapper); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } else if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { + int stind_op; + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); + mono_mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); + need_free = TRUE; + } + + if (need_free) { + mono_mb_emit_ldloc (mb, conv_arg); + emit_string_free_icall (mb, conv); + } + break; + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t) && encoding != MONO_NATIVE_VBBYREFSTR) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: + mono_mb_emit_stloc (mb, 0); + + conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); + if (conv == MONO_MARSHAL_CONV_INVALID) { + char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); + mono_mb_emit_stloc (mb, 3); + + /* free the string */ + mono_mb_emit_ldloc (mb, 0); + emit_string_free_icall (mb, conv); + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: + conv_arg = mono_mb_add_local (mb, object_type); + + *conv_arg_type = int_type; + + if (m_type_is_byref (t)) { + if (t->attrs & PARAM_ATTRIBUTE_OUT) + break; + } + + conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); + if (conv == MONO_MARSHAL_CONV_INVALID) { + char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); + mono_mb_emit_stloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + if (m_type_is_byref (t)) { + if (conv_arg) { + int stind_op; + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); + mono_mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); + } + } + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + if (mono_marshal_shared_conv_to_icall (conv, NULL) == MONO_JIT_ICALL_mono_marshal_string_to_utf16) + /* We need to make a copy so the caller is able to free it */ + mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy); + else + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); + mono_mb_emit_stloc (mb, 3); + break; + + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static int +emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoType *int_type = mono_get_int_type (); + MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class); + + switch (action){ + case MARSHAL_ACTION_CONV_IN: { + int dar_release_slot, pos; + + conv_arg = mono_mb_add_local (mb, int_type); + *conv_arg_type = int_type; + + if (!*mono_marshal_shared_get_sh_dangerous_add_ref()) + mono_marshal_shared_init_safe_handle (); + + mono_mb_emit_ldarg (mb, argnum); + pos = mono_mb_emit_branch (mb, CEE_BRTRUE); + mono_mb_emit_exception (mb, "ArgumentNullException", NULL); + + mono_mb_patch_branch (mb, pos); + + /* Create local to hold the ref parameter to DangerousAddRef */ + dar_release_slot = mono_mb_add_local (mb, boolean_type); + + /* set release = false; */ + mono_mb_emit_icon (mb, 0); + mono_mb_emit_stloc (mb, dar_release_slot); + + if (m_type_is_byref (t)) { + int old_handle_value_slot = mono_mb_add_local (mb, int_type); + + if (!mono_marshal_shared_is_in (t)) { + mono_mb_emit_icon (mb, 0); + mono_mb_emit_stloc (mb, conv_arg); + } else { + /* safehandle.DangerousAddRef (ref release) */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldloc_addr (mb, dar_release_slot); + mono_mb_emit_managed_call (mb, *mono_marshal_shared_get_sh_dangerous_add_ref(), NULL); + + /* Pull the handle field from SafeHandle */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_DUP); + mono_mb_emit_stloc (mb, conv_arg); + mono_mb_emit_stloc (mb, old_handle_value_slot); + } + } else { + /* safehandle.DangerousAddRef (ref release) */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc_addr (mb, dar_release_slot); + mono_mb_emit_managed_call (mb, *mono_marshal_shared_get_sh_dangerous_add_ref(), NULL); + + /* Pull the handle field from SafeHandle */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, conv_arg); + } + + break; + } + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_OUT: { + /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */ + int dar_release_slot = conv_arg + 1; + int label_next = 0; + + if (!*mono_marshal_shared_get_sh_dangerous_release()) + mono_marshal_shared_init_safe_handle (); + + if (m_type_is_byref (t)) { + /* If there was SafeHandle on input we have to release the reference to it */ + if (mono_marshal_shared_is_in (t)) { + mono_mb_emit_ldloc (mb, dar_release_slot); + label_next = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_managed_call (mb, *mono_marshal_shared_get_sh_dangerous_release (), NULL); + mono_mb_patch_branch (mb, label_next); + } + + if (mono_marshal_shared_is_out (t)) { + ERROR_DECL (local_error); + MonoMethod *ctor; + + /* + * If the SafeHandle was marshalled on input we can skip the marshalling on + * output if the handle value is identical. + */ + if (mono_marshal_shared_is_in (t)) { + int old_handle_value_slot = dar_release_slot + 1; + mono_mb_emit_ldloc (mb, old_handle_value_slot); + mono_mb_emit_ldloc (mb, conv_arg); + label_next = mono_mb_emit_branch (mb, CEE_BEQ); + } + + /* + * Create an empty SafeHandle (of correct derived type). + * + * FIXME: If an out-of-memory situation or exception happens here we will + * leak the handle. We should move the allocation of the SafeHandle to the + * input marshalling code to prevent that. + */ + ctor = mono_class_get_method_from_name_checked (t->data.klass, ".ctor", 0, 0, local_error); + if (ctor == NULL || !is_ok (local_error)){ + mono_mb_emit_exception (mb, "MissingMethodException", "parameterless constructor required"); + mono_error_cleanup (local_error); + break; + } + + /* refval = new SafeHandleDerived ()*/ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_op (mb, CEE_NEWOBJ, ctor); + mono_mb_emit_byte (mb, CEE_STIND_REF); + + /* refval.handle = returned_handle */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_STIND_I); + + if (mono_marshal_shared_is_in (t) && label_next) { + mono_mb_patch_branch (mb, label_next); + } + } + } else { + mono_mb_emit_ldloc (mb, dar_release_slot); + label_next = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_managed_call (mb, *mono_marshal_shared_get_sh_dangerous_release (), NULL); + mono_mb_patch_branch (mb, label_next); + } + break; + } + + case MARSHAL_ACTION_CONV_RESULT: { + ERROR_DECL (error); + MonoMethod *ctor = NULL; + int intptr_handle_slot; + + if (mono_class_is_abstract (t->data.klass)) { + mono_mb_emit_byte (mb, CEE_POP); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract")); + break; + } + + ctor = mono_class_get_method_from_name_checked (t->data.klass, ".ctor", 0, 0, error); + if (ctor == NULL || !is_ok (error)){ + mono_error_cleanup (error); + mono_mb_emit_byte (mb, CEE_POP); + mono_mb_emit_exception (mb, "MissingMethodException", "parameterless constructor required"); + break; + } + /* Store the IntPtr results into a local */ + intptr_handle_slot = mono_mb_add_local (mb, int_type); + mono_mb_emit_stloc (mb, intptr_handle_slot); + + /* Create return value */ + mono_mb_emit_op (mb, CEE_NEWOBJ, ctor); + mono_mb_emit_stloc (mb, 3); + + /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */ + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_ldloc (mb, intptr_handle_slot); + mono_mb_emit_byte (mb, CEE_STIND_I); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n"); + break; + default: + printf ("Unhandled case for MarshalAction: %d\n", action); + } + return conv_arg; +} + +static int +emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + + MonoType *int_type = mono_get_int_type (); + switch (action){ + case MARSHAL_ACTION_CONV_IN: { + conv_arg = mono_mb_add_local (mb, int_type); + *conv_arg_type = int_type; + + if (m_type_is_byref (t)) { + char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)"); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + mono_mb_emit_ldarg_addr (mb, argnum); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoHandleRef, handle)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + case MARSHAL_ACTION_PUSH: + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_OUT: { + /* no resource release required */ + break; + } + + case MARSHAL_ACTION_CONV_RESULT: { + char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)"); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n"); + break; + default: + fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action); + } + return conv_arg; +} + +static int +emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoClass *klass = mono_class_from_mono_type_internal (t); + int pos, pos2, loc; + + MonoType *int_type = mono_get_int_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = int_type; + conv_arg = mono_mb_add_local (mb, int_type); + + m->orig_conv_args [argnum] = 0; + + if (mono_class_from_mono_type_internal (t) == mono_defaults.object_class) { + char *msg = g_strdup_printf ("Marshalling of type object is not implemented"); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + if (m_class_is_delegate (klass)) { + if (m_type_is_byref (t)) { + if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { + char *msg = g_strdup_printf ("Byref marshalling of delegates is not implemented."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + } + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + } else { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL)); + mono_mb_emit_stloc (mb, conv_arg); + } + } else if (klass == mono_class_try_get_stringbuilder_class ()) { + MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); + +#if 0 + if (m_type_is_byref (t)) { + if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { + char *msg = g_strdup_printf ("Byref marshalling of stringbuilders is not implemented."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + } + break; + } +#endif + + if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT)) + break; + + if (conv == MONO_MARSHAL_CONV_INVALID) { + char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); + mono_mb_emit_stloc (mb, conv_arg); + } else if (m_class_is_blittable (klass)) { + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_emit_ldarg (mb, argnum); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_patch_branch (mb, pos); + break; + } else { + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_type_is_byref (t)) { + /* we dont need any conversions for out parameters */ + if (t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_I); + + } else { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); + } + + /* store the address of the source into local variable 0 */ + mono_mb_emit_stloc (mb, 0); + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* allocate space for the native struct and store the address */ + mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_LOCALLOC); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_type_is_byref (t)) { + /* Need to store the original buffer so we can free it later */ + m->orig_conv_args [argnum] = mono_mb_add_local (mb, int_type); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, m->orig_conv_args [argnum]); + } + + /* set the src_ptr */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 0); + + /* set dst_ptr */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + + mono_mb_patch_branch (mb, pos); + } + break; + + case MARSHAL_ACTION_CONV_OUT: + if (klass == mono_class_try_get_stringbuilder_class ()) { + gboolean need_free; + MonoMarshalNative encoding; + MonoMarshalConv conv; + + encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free); + + g_assert (encoding != -1); + + if (m_type_is_byref (t)) { + //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT)); + + need_free = TRUE; + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + + switch (encoding) { + case MONO_NATIVE_LPWSTR: + mono_mb_emit_icall (mb, mono_string_utf16_to_builder2); + break; + case MONO_NATIVE_LPSTR: + mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); + break; + case MONO_NATIVE_UTF8STR: + mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); + break; + default: + g_assert_not_reached (); + } + + mono_mb_emit_byte (mb, CEE_STIND_REF); + } else if (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN)) { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); + } + + if (need_free) { + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall (mb, mono_marshal_free); + } + break; + } + + if (m_class_is_delegate (klass)) { + if (m_type_is_byref (t)) { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + break; + } + + if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) { + /* allocate a new object */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + + /* dst = *argument */ + mono_mb_emit_ldarg (mb, argnum); + + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_stloc (mb, 1); + + mono_mb_emit_ldloc (mb, 1); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + if (m_type_is_byref (t) || (t->attrs & PARAM_ATTRIBUTE_OUT)) { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_stloc (mb, 1); + + /* src = tmp_locals [i] */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, 0); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + + /* Free the structure returned by the native code */ + emit_struct_free (mb, klass, conv_arg); + + if (m->orig_conv_args [argnum]) { + /* + * If the native function changed the pointer, then free + * the original structure plus the new pointer. + */ + mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]); + mono_mb_emit_ldloc (mb, conv_arg); + pos2 = mono_mb_emit_branch (mb, CEE_BEQ); + + if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { + g_assert (m->orig_conv_args [argnum]); + + emit_struct_free (mb, klass, m->orig_conv_args [argnum]); + } + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall (mb, mono_marshal_free); + + mono_mb_patch_branch (mb, pos2); + } + } + else + /* Free the original structure passed to native code */ + emit_struct_free (mb, klass, conv_arg); + + mono_mb_patch_branch (mb, pos); + break; + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: + if (m_class_is_delegate (klass)) { + g_assert (!m_type_is_byref (t)); + mono_mb_emit_stloc (mb, 0); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); + mono_mb_emit_stloc (mb, 3); + } else if (klass == mono_class_try_get_stringbuilder_class ()) { + // FIXME: + char *msg = g_strdup_printf ("Return marshalling of stringbuilders is not implemented."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + } else { + /* set src */ + mono_mb_emit_stloc (mb, 0); + + /* Make a copy since emit_conv modifies local 0 */ + loc = mono_mb_add_local (mb, int_type); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_stloc (mb, loc); + + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, 3); + + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* allocate result object */ + + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); + mono_mb_emit_stloc (mb, 3); + + /* set dst */ + + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 1); + + /* emit conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + + emit_struct_free (mb, klass, loc); + + /* Free the pointer allocated by unmanaged code */ + mono_mb_emit_ldloc (mb, loc); + mono_mb_emit_icall (mb, mono_marshal_free); + mono_mb_patch_branch (mb, pos); + } + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: + conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass)); + + if (m_class_is_delegate (klass)) { + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + if (klass == mono_class_try_get_stringbuilder_class ()) { + MonoMarshalNative encoding; + + encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + + // FIXME: + g_assert (encoding == MONO_NATIVE_LPSTR || encoding == MONO_NATIVE_UTF8STR); + + g_assert (!m_type_is_byref (t)); + g_assert (encoding != -1); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + /* The class can not have an automatic layout */ + if (mono_class_is_auto_layout (klass)) { + mono_mb_emit_auto_layout_exception (mb, klass); + break; + } + + if (t->attrs & PARAM_ATTRIBUTE_OUT) { + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + /* Set src */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) { + /* Check for NULL and raise an exception */ + pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE); + + mono_mb_emit_exception (mb, "ArgumentNullException", NULL); + + mono_mb_patch_branch (mb, pos2); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_I); + } + + mono_mb_emit_stloc (mb, 0); + + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* Create and set dst */ + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); + mono_mb_emit_stloc (mb, conv_arg); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + + mono_mb_patch_branch (mb, pos); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + if (m_class_is_delegate (klass)) { + if (m_type_is_byref (t)) { + int stind_op; + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op)); + mono_mb_emit_byte (mb, GINT_TO_UINT8 (stind_op)); + break; + } + } + + if (m_type_is_byref (t)) { + /* Check for null */ + mono_mb_emit_ldloc (mb, conv_arg); + pos = mono_mb_emit_branch (mb, CEE_BRTRUE); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_byte (mb, CEE_STIND_I); + pos2 = mono_mb_emit_branch (mb, CEE_BR); + + mono_mb_patch_branch (mb, pos); + + /* Set src */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 0); + + /* Allocate and set dest */ + mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icall (mb, ves_icall_marshal_alloc); + mono_mb_emit_stloc (mb, 1); + + /* Update argument pointer */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, CEE_STIND_I); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + + mono_mb_patch_branch (mb, pos2); + } else if (klass == mono_class_try_get_stringbuilder_class ()) { + // FIXME: What to do here ? + } else { + /* byval [Out] marshalling */ + + /* FIXME: Handle null */ + + /* Set src */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 0); + + /* Set dest */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + } + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + if (m_class_is_delegate (klass)) { + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL)); + mono_mb_emit_stloc (mb, 3); + break; + } + + /* The class can not have an automatic layout */ + if (mono_class_is_auto_layout (klass)) { + mono_mb_emit_auto_layout_exception (mb, klass); + break; + } + + mono_mb_emit_stloc (mb, 0); + /* Check for null */ + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRTRUE); + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, 3); + pos2 = mono_mb_emit_branch (mb, CEE_BR); + + mono_mb_patch_branch (mb, pos); + + /* Set src */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 0); + + /* Allocate and set dest */ + mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icall (mb, ves_icall_marshal_alloc); + mono_mb_emit_byte (mb, CEE_DUP); + mono_mb_emit_stloc (mb, 1); + mono_mb_emit_stloc (mb, 3); + + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + + mono_mb_patch_branch (mb, pos2); + break; + + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static int +emit_marshal_variant_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ +#ifndef DISABLE_COM + MonoMethodBuilder *mb = m->mb; + MonoType *variant_type = m_class_get_byval_arg (mono_class_get_variant_class ()); + MonoType *variant_type_byref = mono_class_get_byref_type (mono_class_get_variant_class ()); + MonoType *object_type = mono_get_object_type (); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: { + conv_arg = mono_mb_add_local (mb, variant_type); + + if (m_type_is_byref (t)) + *conv_arg_type = variant_type_byref; + else + *conv_arg_type = variant_type; + + if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte(mb, CEE_LDIND_REF); + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL); + break; + } + + case MARSHAL_ACTION_CONV_OUT: { + if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, mono_get_Variant_Clear (), NULL); + break; + } + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: { + char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: { + conv_arg = mono_mb_add_local (mb, object_type); + + if (m_type_is_byref (t)) + *conv_arg_type = variant_type_byref; + else + *conv_arg_type = variant_type; + + if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + if (m_type_is_byref (t)) + mono_mb_emit_ldarg (mb, argnum); + else + mono_mb_emit_ldarg_addr (mb, argnum); + mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_OUT: { + if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL); + } + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: { + char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + default: + g_assert_not_reached (); + } +#endif /* DISABLE_COM */ + + return conv_arg; +} + +static MonoMarshalIlgenCallbacks * +get_marshal_cb (void) +{ + if (G_UNLIKELY (!ilgen_cb_inited)) { +#ifdef ENABLE_ILGEN + mono_marshal_ilgen_init (); +#else + mono_marshal_noilgen_init_heavyweight (); +#endif + } + return &ilgen_marshal_cb; +} + +int +mono_emit_marshal_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action, MonoMarshalLightweightCallbacks* lightweigth_cb) +{ + if (spec && spec->native == MONO_NATIVE_CUSTOM) + return get_marshal_cb ()->emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action); + + if (spec && spec->native == MONO_NATIVE_ASANY) + return get_marshal_cb ()->emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action); + + switch (t->type) { + case MONO_TYPE_VALUETYPE: + if (t->data.klass == mono_class_try_get_handleref_class ()) + return get_marshal_cb ()->emit_marshal_handleref (m, argnum, t, spec, conv_arg, conv_arg_type, action); + + return get_marshal_cb ()->emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_STRING: + return get_marshal_cb ()->emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: +#if !defined(DISABLE_COM) + if (spec && spec->native == MONO_NATIVE_STRUCT) + return get_marshal_cb ()->emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action); +#endif + +#if !defined(DISABLE_COM) + if ((spec && (spec->native == MONO_NATIVE_IUNKNOWN || + spec->native == MONO_NATIVE_IDISPATCH || + spec->native == MONO_NATIVE_INTERFACE)) || + (t->type == MONO_TYPE_CLASS && mono_cominterop_is_interface(t->data.klass))) + return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action); + if (spec && (spec->native == MONO_NATIVE_SAFEARRAY) && + (spec->data.safearray_data.elem_type == MONO_VARIANT_VARIANT) && + ((action == MARSHAL_ACTION_CONV_OUT) || (action == MARSHAL_ACTION_CONV_IN) || (action == MARSHAL_ACTION_PUSH))) + return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action); +#endif + + if (mono_class_try_get_safehandle_class () != NULL && t->data.klass && + mono_class_is_subclass_of_internal (t->data.klass, mono_class_try_get_safehandle_class (), FALSE)) + return get_marshal_cb ()->emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action); + + return get_marshal_cb ()->emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + return get_marshal_cb ()->emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_BOOLEAN: + return get_marshal_cb ()->emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_PTR: + return get_marshal_cb ()->emit_marshal_ptr (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_CHAR: + return get_marshal_cb ()->emit_marshal_char (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_FNPTR: + return lightweigth_cb->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_GENERICINST: + if (mono_type_generic_inst_is_valuetype (t)) + return get_marshal_cb ()->emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action); + else + return get_marshal_cb ()->emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); + default: + return conv_arg; + } +} + +void +mono_marshal_ilgen_init (void) +{ + MonoMarshalIlgenCallbacks cb; + cb.version = MONO_MARSHAL_CALLBACKS_VERSION; + cb.emit_marshal_array = emit_marshal_array_ilgen; + cb.emit_marshal_ptr = emit_marshal_ptr_ilgen; + cb.emit_marshal_char = emit_marshal_char_ilgen; + cb.emit_marshal_vtype = emit_marshal_vtype_ilgen; + cb.emit_marshal_string = emit_marshal_string_ilgen; + cb.emit_marshal_variant = emit_marshal_variant_ilgen; + cb.emit_marshal_safehandle = emit_marshal_safehandle_ilgen; + cb.emit_marshal_object = emit_marshal_object_ilgen; + cb.emit_marshal_boolean = emit_marshal_boolean_ilgen; + cb.emit_marshal_custom = emit_marshal_custom_ilgen; + cb.emit_marshal_asany = emit_marshal_asany_ilgen; + cb.emit_marshal_handleref = emit_marshal_handleref_ilgen; + +#ifdef DISABLE_NONBLITTABLE + mono_marshal_noilgen_init_blittable (&cb); +#endif + mono_install_marshal_callbacks_ilgen (&cb); +} + + diff --git a/src/mono/mono/component/marshal-ilgen.h b/src/mono/mono/metadata/marshal-ilgen.h similarity index 73% rename from src/mono/mono/component/marshal-ilgen.h rename to src/mono/mono/metadata/marshal-ilgen.h index 08768a374483a..1b3914588fb2e 100644 --- a/src/mono/mono/component/marshal-ilgen.h +++ b/src/mono/mono/metadata/marshal-ilgen.h @@ -1,24 +1,9 @@ -/** - * \file - * Copyright 2022 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ + #ifndef __MARSHAL_ILGEN_H__ #define __MARSHAL_ILGEN_H__ #include "metadata/marshal-lightweight.h" #include "metadata/marshal.h" -#include "mono/component/component.h" - -typedef struct MonoComponentMarshalILgen { - MonoComponent component; - void (*ilgen_init) (void); - int (*emit_marshal_ilgen) (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action, MonoMarshalLightweightCallbacks* lightweigth_cb); - void (*install_callbacks_mono) (IlgenCallbacksToMono *callbacks); - -} MonoComponentMarshalILgen; typedef struct { int version; @@ -34,23 +19,24 @@ typedef struct { int (*emit_marshal_custom) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); int (*emit_marshal_asany) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); int (*emit_marshal_handleref) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); -} MonoMarshalILgenCallbacks; - -MONO_COMPONENT_EXPORT_ENTRYPOINT -MonoComponentMarshalILgen* mono_component_marshal_ilgen_init (void); +} MonoMarshalIlgenCallbacks; void -mono_install_marshal_callbacks_ilgen (MonoMarshalILgenCallbacks *cb); +mono_install_marshal_callbacks_ilgen (MonoMarshalIlgenCallbacks *cb); + MONO_API void mono_marshal_ilgen_init (void); +void +mono_marshal_noilgen_init_heavyweight (void); + +void +mono_marshal_noilgen_init_lightweight (void); + int mono_emit_marshal_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action, MonoMarshalLightweightCallbacks* lightweigth_cb); -void -mono_marshal_ilgen_install_callbacks_mono (IlgenCallbacksToMono *callbacks); - #endif // __MARSHAL_ILGEN_H__ \ No newline at end of file diff --git a/src/mono/mono/metadata/marshal-lightweight.c b/src/mono/mono/metadata/marshal-lightweight.c index 0c9a5258063ca..70a8ee0ede294 100644 --- a/src/mono/mono/metadata/marshal-lightweight.c +++ b/src/mono/mono/metadata/marshal-lightweight.c @@ -8,13 +8,14 @@ #include #endif -#include "mono/metadata/method-builder-ilgen.h" -#include "mono/metadata/method-builder-ilgen-internals.h" +#include "metadata/method-builder-ilgen.h" +#include "metadata/method-builder-ilgen-internals.h" #include #include #include "cil-coff.h" #include "metadata/marshal.h" #include "metadata/marshal-internals.h" +#include "metadata/marshal-ilgen.h" #include "metadata/marshal-lightweight.h" #include "metadata/marshal-shared.h" #include "metadata/tabledefs.h" @@ -23,7 +24,6 @@ #include "mono/metadata/abi-details.h" #include "mono/metadata/class-abi-details.h" #include "mono/metadata/class-init.h" -#include "mono/metadata/components.h" #include "mono/metadata/debug-helpers.h" #include "mono/metadata/threads.h" #include "mono/metadata/monitor.h" diff --git a/src/mono/mono/metadata/marshal-lightweight.h b/src/mono/mono/metadata/marshal-lightweight.h index b25d9cc9f2aba..8dfd4803a9649 100644 --- a/src/mono/mono/metadata/marshal-lightweight.h +++ b/src/mono/mono/metadata/marshal-lightweight.h @@ -5,7 +5,6 @@ */ #ifndef __MONO_MARSHAL_LIGHTWEIGHT_H__ #define __MONO_MARSHAL_LIGHTWEIGHT_H__ -#include MONO_API void mono_marshal_lightweight_init (void); diff --git a/src/mono/mono/metadata/marshal-noilgen.c b/src/mono/mono/metadata/marshal-noilgen.c index 8d6f75981cd87..ae073fcaf7f8e 100644 --- a/src/mono/mono/metadata/marshal-noilgen.c +++ b/src/mono/mono/metadata/marshal-noilgen.c @@ -1,13 +1,38 @@ #include "config.h" + #include -#include -#include -#include +#include "metadata/marshal-internals.h" +#include "metadata/marshal.h" +#include "metadata/marshal-ilgen.h" #include "utils/mono-compiler.h" #ifndef ENABLE_ILGEN +static int +emit_marshal_array_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + MonoType *object_type = mono_get_object_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = object_type; + break; + case MARSHAL_ACTION_MANAGED_CONV_IN: + *conv_arg_type = int_type; + break; + } + return conv_arg; +} - +static int +emit_marshal_ptr_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + return conv_arg; +} static int emit_marshal_scalar_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, @@ -18,6 +43,136 @@ emit_marshal_scalar_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, } #endif +#if !defined(ENABLE_ILGEN) || defined(DISABLE_NONBLITTABLE) +static int +emit_marshal_boolean_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: + if (m_type_is_byref (t)) + *conv_arg_type = int_type; + else + *conv_arg_type = mono_marshal_boolean_conv_in_get_local_type (spec, NULL); + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: { + MonoClass* conv_arg_class = mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec, NULL); + if (m_type_is_byref (t)) + *conv_arg_type = m_class_get_this_arg (conv_arg_class); + else + *conv_arg_type = m_class_get_byval_arg (conv_arg_class); + break; + } + + } + return conv_arg; +} + +static int +emit_marshal_char_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + return conv_arg; +} + +static int +emit_marshal_custom_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + if (action == MARSHAL_ACTION_CONV_IN && t->type == MONO_TYPE_VALUETYPE) + *conv_arg_type = int_type; + return conv_arg; +} + +static int +emit_marshal_asany_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + return conv_arg; +} + +static int +emit_marshal_vtype_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + return conv_arg; +} + +static int +emit_marshal_string_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = int_type; + break; + case MARSHAL_ACTION_MANAGED_CONV_IN: + *conv_arg_type = int_type; + break; + } + return conv_arg; +} + +static int +emit_marshal_safehandle_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + if (action == MARSHAL_ACTION_CONV_IN) + *conv_arg_type = int_type; + return conv_arg; +} + + +static int +emit_marshal_handleref_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + if (action == MARSHAL_ACTION_CONV_IN) + *conv_arg_type = int_type; + return conv_arg; +} + +static int +emit_marshal_object_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + if (action == MARSHAL_ACTION_CONV_IN) + *conv_arg_type = int_type; + return conv_arg; +} + +static int +emit_marshal_variant_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + g_assert_not_reached (); +} +#endif + #ifndef ENABLE_ILGEN static void emit_managed_wrapper_noilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoGCHandle target_handle, MonoError *error) @@ -251,13 +406,38 @@ mono_marshal_noilgen_init_lightweight (void) } +void +mono_marshal_noilgen_init_heavyweight (void) +{ + MonoMarshalIlgenCallbacks ilgen_cb; + + ilgen_cb.version = MONO_MARSHAL_CALLBACKS_VERSION; + ilgen_cb.emit_marshal_array = emit_marshal_array_noilgen; + ilgen_cb.emit_marshal_vtype = emit_marshal_vtype_noilgen; + ilgen_cb.emit_marshal_string = emit_marshal_string_noilgen; + ilgen_cb.emit_marshal_safehandle = emit_marshal_safehandle_noilgen; + ilgen_cb.emit_marshal_handleref = emit_marshal_handleref_noilgen; + ilgen_cb.emit_marshal_object = emit_marshal_object_noilgen; + ilgen_cb.emit_marshal_variant = emit_marshal_variant_noilgen; + ilgen_cb.emit_marshal_asany = emit_marshal_asany_noilgen; + ilgen_cb.emit_marshal_boolean = emit_marshal_boolean_noilgen; + ilgen_cb.emit_marshal_custom = emit_marshal_custom_noilgen; + ilgen_cb.emit_marshal_ptr = emit_marshal_ptr_noilgen; + + ilgen_cb.emit_marshal_char = emit_marshal_char_noilgen; + mono_install_marshal_callbacks_ilgen(&ilgen_cb); +} + #else void mono_marshal_noilgen_init_lightweight (void) { } - +void +mono_marshal_noilgen_init_heavyweight (void) +{ +} #endif #ifdef DISABLE_NONBLITTABLE diff --git a/src/mono/mono/metadata/marshal-noilgen.h b/src/mono/mono/metadata/marshal-noilgen.h deleted file mode 100644 index c9cafee09fbbd..0000000000000 --- a/src/mono/mono/metadata/marshal-noilgen.h +++ /dev/null @@ -1,15 +0,0 @@ -/** - * \file - * Copyright 2022 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ -#ifndef __MARSHAL_NOILGEN_H__ -#define __MARSHAL_NOILGEN_H__ - -void -mono_marshal_noilgen_init_lightweight (void); - -void -mono_marshal_noilgen_init_heavyweight (void); - -#endif // __MARSHAL_NOILGEN_H__ \ No newline at end of file diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 47b1a66a979ca..6caac8e640b33 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -32,7 +32,7 @@ MONO_PRAGMA_WARNING_POP() #include "cil-coff.h" #include "metadata/marshal.h" #include "metadata/marshal-internals.h" -#include "metadata/marshal-shared.h" +#include "metadata/marshal-ilgen.h" #include "metadata/marshal-lightweight.h" #include "metadata/method-builder.h" #include "metadata/method-builder-internals.h" @@ -41,10 +41,8 @@ MONO_PRAGMA_WARNING_POP() #include #include "mono/metadata/abi-details.h" #include "mono/metadata/class-abi-details.h" -#include "mono/metadata/components.h" #include "mono/metadata/debug-helpers.h" #include "mono/metadata/threads.h" -#include "mono/metadata/marshal-noilgen.h" #include "mono/metadata/monitor.h" #include "mono/metadata/class-init.h" #include "mono/metadata/class-internals.h" @@ -129,66 +127,6 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callconv_attribute, "System. static gboolean type_is_blittable (MonoType *type); -static IlgenCallbacksToMono ilgenCallbacksToMono = { - &mono_get_object_type, - &mono_marshal_get_ptr_to_string_conv, - &mono_class_is_subclass_of_internal, - &mono_class_native_size, - &mono_class_try_get_handleref_class, - &mono_class_try_get_safehandle_class, - &mono_class_try_get_stringbuilder_class, - &mono_defaults, - &mono_marshal_boolean_conv_in_get_local_type, - &mono_marshal_boolean_managed_conv_in_get_conv_arg_class, - &mono_marshal_get_ptr_to_stringbuilder_conv, - &mono_marshal_get_string_encoding, - &mono_marshal_get_string_to_ptr_conv, - &mono_marshal_get_stringbuilder_to_ptr_conv, - &mono_marshal_load_type_info, - &mono_marshal_shared_conv_to_icall, - &mono_marshal_shared_emit_marshal_custom_get_instance, - &mono_marshal_shared_emit_struct_conv, - &mono_marshal_shared_emit_struct_conv_full, - &mono_marshal_shared_get_method_nofail, - &mono_marshal_shared_get_sh_dangerous_add_ref, - &mono_marshal_shared_get_sh_dangerous_release, - &mono_marshal_shared_init_safe_handle, - &mono_marshal_shared_is_in, - &mono_marshal_shared_is_out, - &mono_marshal_shared_mb_emit_exception_marshal_directive, - &mono_mb_add_local, - &mono_mb_emit_add_to_local, - &mono_mb_emit_auto_layout_exception, - &mono_mb_emit_branch, - &mono_mb_emit_branch_label, - &mono_mb_emit_byte, - &mono_mb_emit_exception, - &mono_mb_emit_exception_full, - &mono_mb_emit_icall_id, - &mono_mb_emit_icon, - &mono_mb_emit_ldarg, - &mono_mb_emit_ldarg_addr, - &mono_mb_emit_ldflda, - &mono_mb_emit_ldloc, - &mono_mb_emit_ldloc_addr, - &mono_mb_emit_managed_call, - &mono_mb_emit_op, - &mono_mb_emit_stloc, - &mono_mb_get_label, - &mono_mb_patch_branch, - &mono_pinvoke_is_unicode, - &mono_reflection_type_from_name_checked, - &mono_memory_barrier, - &mono_marshal_need_free, - &mono_get_int_type -}; - -IlgenCallbacksToMono* -mono_marshal_get_mono_callbacks_for_ilgen (void) -{ - return &ilgenCallbacksToMono; -} - static MonoImage* get_method_image (MonoMethod *method) { @@ -3222,9 +3160,8 @@ mono_emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, if (!m->runtime_marshalling_enabled) return mono_emit_disabled_marshal (m, argnum, t, spec, conv_arg, conv_arg_type, action); - mono_component_marshal_ilgen()->install_callbacks_mono(mono_marshal_get_mono_callbacks_for_ilgen()); - return mono_component_marshal_ilgen()->emit_marshal_ilgen(m, argnum, t, spec, conv_arg, conv_arg_type, action, get_marshal_cb()); -} + return mono_emit_marshal_ilgen(m, argnum, t, spec, conv_arg, conv_arg_type, action, get_marshal_cb()); +} static void mono_marshal_set_callconv_for_type(MonoType *type, MonoMethodSignature *csig, gboolean *skip_gc_trans /*out*/) @@ -6323,6 +6260,7 @@ get_marshal_cb (void) mono_marshal_noilgen_init_lightweight (); #endif } + return &marshal_lightweight_cb; } diff --git a/src/mono/mono/metadata/marshal.h b/src/mono/mono/metadata/marshal.h index e4244ad07c7b4..93aeb28667de5 100644 --- a/src/mono/mono/metadata/marshal.h +++ b/src/mono/mono/metadata/marshal.h @@ -348,60 +348,6 @@ typedef struct { int (*emit_marshal_scalar) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); } MonoMarshalLightweightCallbacks; -typedef struct { - MonoType* (*get_object_type) (void); - MonoMarshalConv (*get_ptr_to_string_conv) (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free); - gboolean (*is_subclass_of_internal) (MonoClass *klass, MonoClass *klassc, gboolean check_interfaces); - gint32 (*class_native_size) (MonoClass *klass, guint32 *align); - MonoClass* (*class_try_get_handleref_class) (void); - MonoClass* (*try_get_safehandle_class) (void); - MonoClass* (*try_get_stringbuilder_class) (void); - MonoDefaults* mono_defaults; - MonoType* (*boolean_conv_in_get_local_type) (MonoMarshalSpec *spec, guint8 *ldc_op /*out*/); - MonoClass* (*boolean_managed_conv_in_get_conv_arg_class) (MonoMarshalSpec *spec, guint8 *ldop/*out*/); - MonoMarshalConv (*get_ptr_to_stringbuilder_conv) (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free); - MonoMarshalNative (*get_string_encoding) (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec); - MonoMarshalConv (*get_string_to_ptr_conv) (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec); - MonoMarshalConv (*get_stringbuilder_to_ptr_conv) (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec); - MonoMarshalType* (*load_type_info) (MonoClass* klass); - MonoJitICallId (*conv_to_icall) (MonoMarshalConv conv, int *ind_store_type); - void (*emit_marshal_custom_get_instance) (MonoMethodBuilder *mb, MonoClass *klass, MonoMarshalSpec *spec); - void (*emit_struct_conv) (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object); - void (*emit_struct_conv_full) (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, int offset_of_first_child_field, MonoMarshalNative string_encoding); - MonoMethod* (*get_method_nofail) (MonoClass *klass, const char *method_name, int num_params, int flags); - MonoMethod** (*get_sh_dangerous_add_ref) (void); - MonoMethod** (*get_sh_dangerous_release) (void); - void (*init_safe_handle) (void); - gboolean (*is_in) (const MonoType *t); - gboolean (*is_out) (const MonoType *t); - void (*mb_emit_exception_marshal_directive) (MonoMethodBuilder *mb, char *msg); - int (*mb_add_local) (MonoMethodBuilder *mb, MonoType *type); - void (*mb_emit_add_to_local) (MonoMethodBuilder *mb, guint16 local, gint32 incr); - void (*mb_emit_auto_layout_exception) (MonoMethodBuilder *mb, MonoClass *klass); - guint32 (*mb_emit_branch) (MonoMethodBuilder *mb, guint8 op); - void (*mb_emit_branch_label) (MonoMethodBuilder *mb, guint8 op, guint32 label); - void (*mb_emit_byte) (MonoMethodBuilder *mb, guint8 op); - void (*mb_emit_exception) (MonoMethodBuilder *mb, const char *exc_name, const char *msg); - void (*mb_emit_exception_full) (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg); - void (*mb_emit_icall_id) (MonoMethodBuilder *mb, MonoJitICallId jit_icall_id); - void (*mb_emit_icon) (MonoMethodBuilder *mb, gint32 value); - void (*mb_emit_ldarg) (MonoMethodBuilder *mb, guint argnum); - void (*mb_emit_ldarg_addr) (MonoMethodBuilder *mb, guint argnum); - void (*mb_emit_ldflda) (MonoMethodBuilder *mb, gint32 offset); - void (*mb_emit_ldloc) (MonoMethodBuilder *mb, guint num); - void (*mb_emit_ldloc_addr) (MonoMethodBuilder *mb, guint argnum); - void (*mb_emit_managed_call) (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig); - void (*mb_emit_op) (MonoMethodBuilder *mb, guint8 op, gpointer data); - void (*mb_emit_stloc) (MonoMethodBuilder *mb, guint num); - int (*mb_get_label) (MonoMethodBuilder *mb); - void (*mb_patch_branch) (MonoMethodBuilder *mb, guint32 pos); - gboolean (*pinvoke_is_unicode) (MonoMethodPInvoke *piinfo); - MonoType* (*reflection_type_from_name_checked) (char *name, MonoAssemblyLoadContext *alc, MonoImage *image, MonoError *error); - void (*memory_barrier) (void); - gboolean (*need_free) (MonoType *t, MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec); - MonoType* (*get_int_type) (void); -} IlgenCallbacksToMono; - /*type of the function pointer of methods returned by mono_marshal_get_runtime_invoke*/ typedef MonoObject *(*RuntimeInvokeFunction) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method); @@ -756,7 +702,4 @@ mono_mb_create_and_cache_full (GHashTable *cache, gpointer key, MonoMethodBuilder *mb, MonoMethodSignature *sig, int max_stack, WrapperInfo *info, gboolean *out_found); -IlgenCallbacksToMono* -mono_marshal_get_mono_callbacks_for_ilgen (void); - #endif /* __MONO_MARSHAL_H__ */ diff --git a/src/mono/mono/mini/CMakeLists.txt b/src/mono/mono/mini/CMakeLists.txt index 6ef0ebf57b4ea..9e74fd9e16fb4 100644 --- a/src/mono/mono/mini/CMakeLists.txt +++ b/src/mono/mono/mini/CMakeLists.txt @@ -349,7 +349,7 @@ add_library(monosgen-static STATIC $;$ - - - marshal-ilgen - - - - - - marshal-ilgen - - - - marshal-ilgen - - <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a" Condition="'$(FeatureWasmPerfTracing)' != 'true' and $(FeatureWasmThreads) != 'true'"/> <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-stub-static.a" /> - <_MonoRuntimeComponentDontLink Include="libmono-component-marshal-ilgen-stub-static.a" /> diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index 14070469f0d20..dfe3a169d5604 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -31,9 +31,6 @@ <_MonoComponent Include="hot_reload;debugger" /> - - <_MonoComponent Include="marshal-ilgen" /> - diff --git a/src/mono/wasm/runtime/CMakeLists.txt b/src/mono/wasm/runtime/CMakeLists.txt index 76a17f73e0cf9..c852a7df1df61 100644 --- a/src/mono/wasm/runtime/CMakeLists.txt +++ b/src/mono/wasm/runtime/CMakeLists.txt @@ -19,7 +19,6 @@ target_link_libraries(dotnet ${MONO_ARTIFACTS_DIR}/libmono-component-hot_reload-static.a ${MONO_ARTIFACTS_DIR}/libmono-component-debugger-static.a ${MONO_ARTIFACTS_DIR}/libmono-component-diagnostics_tracing-stub-static.a - ${MONO_ARTIFACTS_DIR}/libmono-component-marshal-ilgen-static.a ${MONO_ARTIFACTS_DIR}/libmono-ee-interp.a ${MONO_ARTIFACTS_DIR}/libmonosgen-2.0.a ${MONO_ARTIFACTS_DIR}/libmono-ilgen.a diff --git a/src/tests/build.proj b/src/tests/build.proj index e2716558b9d8a..37236bad27175 100644 --- a/src/tests/build.proj +++ b/src/tests/build.proj @@ -185,7 +185,7 @@ $(BuildDir)\apk $(XUnitTestBinBase)$(CategoryWithSlash)\$(Category).apk False - diagnostics_tracing;marshal-ilgen + diagnostics_tracing 127.0.0.1:9000,nosuspend,listen True $(ArtifactsBinDir)microsoft.netcore.app.runtime.android-$(TargetArchitecture)\$(Configuration)\runtimes\android-$(TargetArchitecture)\ @@ -272,7 +272,7 @@ $(CMDDIR_GrandParent)/$(CategoryWithSlash)/$(XUnitWrapperFileName) $(IntermediateOutputPath)\iOSApps\$(Category) $(XUnitTestBinBase)$(CategoryWithSlash)\$(Category).app - diagnostics_tracing;marshal-ilgen + diagnostics_tracing