|
39 | 39 | #include "mono/metadata/handle.h"
|
40 | 40 | #include "mono/metadata/custom-attrs-internals.h"
|
41 | 41 | #include "mono/metadata/icall-internals.h"
|
| 42 | +#include "mono/metadata/unsafe-accessor.h" |
42 | 43 | #include "mono/utils/mono-tls.h"
|
43 | 44 | #include "mono/utils/mono-memory-model.h"
|
44 | 45 | #include "mono/utils/atomic.h"
|
@@ -2319,6 +2320,79 @@ emit_array_accessor_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, Mo
|
2319 | 2320 | mono_mb_emit_byte (mb, CEE_RET);
|
2320 | 2321 | }
|
2321 | 2322 |
|
| 2323 | +static void |
| 2324 | +emit_unsafe_accessor_field_wrapper (MonoMethodBuilder *mb, MonoMethod *accessor_method, MonoMethodSignature *sig, MonoGenericContext *ctx, MonoUnsafeAccessorKind kind, const char *member_name) |
| 2325 | +{ |
| 2326 | + // Field access requires a single argument for target type and a return type. |
| 2327 | + g_assert (kind == MONO_UNSAFE_ACCESSOR_FIELD || kind == MONO_UNSAFE_ACCESSOR_STATIC_FIELD); |
| 2328 | + g_assert (member_name != NULL); |
| 2329 | + |
| 2330 | + MonoType *target_type = sig->params[0]; // params[0] is the field's parent |
| 2331 | + MonoType *ret_type = sig->ret; |
| 2332 | + if (sig->param_count != 1 || target_type == NULL || sig->ret->type == MONO_TYPE_VOID) { |
| 2333 | + mono_mb_emit_exception_full (mb, "System", "BadImageFormatException", "Invalid usage of UnsafeAccessorAttribute."); |
| 2334 | + return; |
| 2335 | + } |
| 2336 | + |
| 2337 | + MonoClass *target_class = mono_class_from_mono_type_internal (target_type); |
| 2338 | + gboolean target_byref = m_type_is_byref (target_type); |
| 2339 | + gboolean target_valuetype = m_class_is_valuetype (target_class); |
| 2340 | + gboolean ret_byref = m_type_is_byref (ret_type); |
| 2341 | + if (!ret_byref || (kind == MONO_UNSAFE_ACCESSOR_FIELD && target_valuetype && !target_byref)) { |
| 2342 | + mono_mb_emit_exception_full (mb, "System", "BadImageFormatException", "Invalid usage of UnsafeAccessorAttribute."); |
| 2343 | + return; |
| 2344 | + } |
| 2345 | + |
| 2346 | + MonoClassField *target_field = mono_class_get_field_from_name_full (target_class, member_name, NULL); |
| 2347 | + if (target_field == NULL || !mono_metadata_type_equal_full (target_field->type, m_class_get_byval_arg (mono_class_from_mono_type_internal (ret_type)), TRUE)) { |
| 2348 | + mono_mb_emit_exception_full (mb, "System", "MissingFieldException", |
| 2349 | + g_strdup_printf("No '%s' in '%s'. Or the type of '%s' doesn't match", member_name, m_class_get_name (target_class), member_name)); |
| 2350 | + return; |
| 2351 | + } |
| 2352 | + gboolean is_field_static = !!(target_field->type->attrs & FIELD_ATTRIBUTE_STATIC); |
| 2353 | + if ((kind == MONO_UNSAFE_ACCESSOR_FIELD && is_field_static) || (kind == MONO_UNSAFE_ACCESSOR_STATIC_FIELD && !is_field_static)) { |
| 2354 | + mono_mb_emit_exception_full (mb, "System", "MissingFieldException", g_strdup_printf("UnsafeAccessorKind does not match expected static modifier on field '%s' in '%s'", member_name, m_class_get_name (target_class))); |
| 2355 | + return; |
| 2356 | + } |
| 2357 | + |
| 2358 | + if (kind == MONO_UNSAFE_ACCESSOR_FIELD) |
| 2359 | + mono_mb_emit_ldarg (mb, 0); |
| 2360 | + mono_mb_emit_op (mb, kind == MONO_UNSAFE_ACCESSOR_FIELD ? CEE_LDFLDA : CEE_LDSFLDA, target_field); |
| 2361 | + mono_mb_emit_byte (mb, CEE_RET); |
| 2362 | +} |
| 2363 | + |
| 2364 | +static void |
| 2365 | +emit_unsafe_accessor_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *accessor_method, MonoMethodSignature *sig, MonoGenericContext *ctx, MonoUnsafeAccessorKind kind, const char *member_name) |
| 2366 | +{ |
| 2367 | + if (accessor_method->is_generic) { |
| 2368 | + mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "UnsafeAccessor_Generics"); |
| 2369 | + return; |
| 2370 | + } |
| 2371 | + |
| 2372 | + if (!m_method_is_static (accessor_method)) { |
| 2373 | + mono_mb_emit_exception_full (mb, "System", "BadImageFormatException", "UnsafeAccessor_NonStatic"); |
| 2374 | + return; |
| 2375 | + } |
| 2376 | + |
| 2377 | + switch (kind) { |
| 2378 | + case MONO_UNSAFE_ACCESSOR_FIELD: |
| 2379 | + case MONO_UNSAFE_ACCESSOR_STATIC_FIELD: |
| 2380 | + emit_unsafe_accessor_field_wrapper (mb, accessor_method, sig, ctx, kind, member_name); |
| 2381 | + return; |
| 2382 | + case MONO_UNSAFE_ACCESSOR_CTOR: |
| 2383 | + // TODO |
| 2384 | + mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "UnsafeAccessor"); |
| 2385 | + return; |
| 2386 | + case MONO_UNSAFE_ACCESSOR_METHOD: |
| 2387 | + case MONO_UNSAFE_ACCESSOR_STATIC_METHOD: |
| 2388 | + // TODO |
| 2389 | + mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "UnsafeAccessor"); |
| 2390 | + return; |
| 2391 | + default: |
| 2392 | + g_assert_not_reached(); // some unknown wrapper kind |
| 2393 | + } |
| 2394 | +} |
| 2395 | + |
2322 | 2396 | static void
|
2323 | 2397 | emit_generic_array_helper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *csig)
|
2324 | 2398 | {
|
@@ -3158,6 +3232,7 @@ mono_marshal_lightweight_init (void)
|
3158 | 3232 | cb.emit_synchronized_wrapper = emit_synchronized_wrapper_ilgen;
|
3159 | 3233 | cb.emit_unbox_wrapper = emit_unbox_wrapper_ilgen;
|
3160 | 3234 | cb.emit_array_accessor_wrapper = emit_array_accessor_wrapper_ilgen;
|
| 3235 | + cb.emit_unsafe_accessor_wrapper = emit_unsafe_accessor_wrapper_ilgen; |
3161 | 3236 | cb.emit_generic_array_helper = emit_generic_array_helper_ilgen;
|
3162 | 3237 | cb.emit_thunk_invoke_wrapper = emit_thunk_invoke_wrapper_ilgen;
|
3163 | 3238 | cb.emit_create_string_hack = emit_create_string_hack_ilgen;
|
|
0 commit comments