Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[mono] generic wrapper methods for unsafe accessors#101732

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
lambdageek merged 31 commits intodotnet:mainfromlambdageek:hack-generic-wrappers
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
Show all changes
31 commits
Select commitHold shift + click to select a range
81285fb
WIP HACK: always AOT wrappers, even for generics, not the actual acce…
lambdageekApr 25, 2024
3d59833
cleanup
lambdageekApr 29, 2024
fbd3b89
checkpoint generic wrapper methods
lambdageekApr 30, 2024
34381f7
fix msvc build
lambdageekApr 30, 2024
ecaff9e
hack
lambdageekApr 30, 2024
06be3b4
fix build
lambdageekMay 1, 2024
430f822
clean WIP printfs
lambdageekMay 1, 2024
5789ab7
use generic method owner caches
lambdageekMay 1, 2024
374c1e7
lookup unsafe accessor wrapper instances in aot-runtime
lambdageekMay 1, 2024
db8cbad
cleanup marshaling - dont' use ctx as a flag
lambdageekMay 1, 2024
f252a47
handle some generic field accessors
lambdageekMay 2, 2024
e424b64
issues.targets: enable some unsafe accessor AOT tests
lambdageekMay 2, 2024
03c72f7
WIP: looks like methods are working too?
lambdageekMay 2, 2024
6fcefc6
[metadata] add ability to inflate wrapper data
lambdageekMay 6, 2024
ccbd0ba
[marshal] refactor unsafe accessor; opt into inflate_wrapper_data
lambdageekMay 6, 2024
0c824fc
Merge remote-tracking branch 'origin/main' into hack-generic-wrappers
lambdageekMay 6, 2024
56516b2
comment out printfs
lambdageekMay 6, 2024
769ae55
inflate MonoMethod wrapper data; impl ctor generic unsafe accessors
lambdageekMay 6, 2024
9688f2b
fix windows build
lambdageekMay 6, 2024
70aaa2e
[aot] handle case of partial generic sharing for unsafe accessor
lambdageekMay 7, 2024
e814387
[aot] for unsafe accessor wrappers with no name, record a length 0
lambdageekMay 7, 2024
03208db
[aot-runtime] try to fix gsharedvt lookup
lambdageekMay 8, 2024
c244dd2
better comments; remove fied FIXMEs
lambdageekMay 9, 2024
2ff358b
update HelloWorld sample to support either normal AOT or FullAOT
lambdageekMay 9, 2024
25f9e99
revert HelloWorld sample code changes
lambdageekMay 9, 2024
0374f2b
rename helper methods
lambdageekMay 9, 2024
9786200
apply suggestions from code review
lambdageekMay 10, 2024
ceb5345
DRY. compute inflate_generic_data in one place
lambdageekMay 13, 2024
342fe1d
Just do one loop for inflating generic wrapper data
lambdageekMay 13, 2024
a667f53
better comments
lambdageekMay 13, 2024
0bf0f61
DRY. move common AOT code to mini.c
lambdageekMay 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
[marshal] refactor unsafe accessor; opt into inflate_wrapper_data
Try to separate the ideas of "the call to the UnsafeAccessor methodwas inflated, so we need to inflate the wrapper" and "theUnsafeAccessor method is a generic method definition, so the wrappershould be a generic method definition, too"
  • Loading branch information
@lambdageek
lambdageek committedMay 6, 2024
commitccbd0ba817f79b47d88d1e251ff1364d1cc1ef2d
2 changes: 2 additions & 0 deletionssrc/mono/mono/metadata/marshal-lightweight.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2369,6 +2369,8 @@ emit_unsafe_accessor_field_wrapper (MonoMethodBuilder *mb, gboolean to_be_inflat
if (kind == MONO_UNSAFE_ACCESSOR_FIELD)
mono_mb_emit_ldarg (mb, 0);
mono_mb_emit_op (mb, kind == MONO_UNSAFE_ACCESSOR_FIELD ? CEE_LDFLDA : CEE_LDSFLDA, target_field);
if ((accessor_method->is_generic || to_be_inflated))
mono_mb_set_wrapper_data_kind (mb, MONO_MB_ILGEN_WRAPPER_DATA_FIELD);
mono_mb_emit_byte (mb, CEE_RET);
}

Expand Down
90 changes: 69 additions & 21 deletionssrc/mono/mono/metadata/marshal.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5229,45 +5229,82 @@ mono_marshal_get_unsafe_accessor_wrapper (MonoMethod *accessor_method, MonoUnsaf
MonoGenericContainer *container = NULL;
MonoMethod *orig_method = NULL;
WrapperInfo *info;
gboolean is_generic = FALSE;
/* generic_wrapper == TRUE means we will create a generic wrapper method. */
gboolean generic_wrapper = FALSE;
/* is_inflated == TRUE means we will inflate the wrapper method - the */
gboolean is_inflated = FALSE;
/* is_generic and is_inflated might be set independently, depending on how we're called. */

if (member_name == NULL && kind != MONO_UNSAFE_ACCESSOR_CTOR)
member_name = accessor_method->name;

printf("CAME IN: %s (generic = %d, inflated = %d)\n", mono_method_full_name(accessor_method, TRUE), accessor_method->is_generic?1:0, accessor_method->is_inflated?1:0);

/*
* the method is either a generic method definition, or it might be inflated, not both at
* the same time.
*/
g_assert (!(accessor_method->is_generic && accessor_method->is_inflated));


if (accessor_method->is_inflated) {
MonoMethod *declaring = ((MonoMethodInflated*)accessor_method)->declaring;
if (declaring->is_generic) {
// JIT gets here sometimes.
generic_wrapper = TRUE;
}
is_inflated = TRUE;
}

if (accessor_method->is_generic) {
// FullAOT compilation with gshared or gsharedvt will get here.
/* got a generic method definition. need to make a generic method definition wrapper */
g_assert (!accessor_method->is_inflated);
is_generic = TRUE;
} else if (accessor_method->is_inflated) {
generic_wrapper = TRUE;
}

if (is_inflated) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Theis_inflated appears redundant sinceaccessor_method is already passed to theemit_unsafe_accessor_[field/ctor/method]_wrapper function.

Canaccessor_method->is_inflated be used directly instead of theis_inflated variable? The idea is to make the wrapper inflated if the accessor method is inflated and removegboolean to_be_inflated.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

It's not redundant. Note that below on line 5272 we reassignaccessor_method to be the declaring method. So we would have to switch fromaccessor_method->is_inflated toorig_method->is_inflated in this function. And down inemit_unsafe_accessor_wrapper we don't haveorig_method available.

Honestly what I would prefer is to makeemit_unsafe_accessor_wrapper not to take anaccessor_method argument at all. We can figure out the target class from the signature, and if we need to inflate the target method we can figure that out from the generic context. But there's other (mostly error checking) stuff that we can only get fromaccessor_method: like whether it's static.

But there's a good point here: I always just need to knowgboolean inflate_generic_data = accessor_method->is_generic || is_inflated inemit_unsafe_accessor_{ctor/method/field}_wrapper. So I will update marshal.c to just pass that down, instead of computing it in three different places.

kotlarmilos reacted with thumbs up emoji
// FIXME: this always tries to compile a generic version of the accessor method and
// then inflate it. But maybe we dont' want to do that (particularly for field
// accessors). In particular if there is no method_inst, we're looking at an
// accessor method inside a generic class (alwayst a ginst? or sometimes a gtd?)
// In that case we might just want to compile the instance.

g_assert (!is_generic);
orig_method = accessor_method;
ctx = &((MonoMethodInflated*)accessor_method)->context;
accessor_method = ((MonoMethodInflated*)accessor_method)->declaring;
container = mono_method_get_generic_container (accessor_method);
if (!container)
container = mono_class_try_get_generic_container (accessor_method->klass); //FIXME is this a case of a try?
g_assert (container);
is_inflated = TRUE;
if (!generic_wrapper) {
orig_method = accessor_method;
ctx = &((MonoMethodInflated*)accessor_method)->context;
accessor_method = ((MonoMethodInflated*)accessor_method)->declaring;
container = mono_method_get_generic_container (accessor_method);
if (!container)
container = mono_class_try_get_generic_container (accessor_method->klass); //FIXME is this a case of a try?
g_assert (container);
} else {
// FIXME:
// in this case do we need to mess with the context and container?
//
// class C<T> {
// public static extern void AccessorMethod<U>(List<T> t, List<U> u);
// }
//
// when we need to make a wrapper
//
// public static extern void wrapper_AccessorMethod<U2>(List<T>, List<U2> u);
//
// where we substitute the new gparams of the wrapper, but leave the
// gparams of C<T> unchanged.
//
orig_method = accessor_method;
ctx = &((MonoMethodInflated*)accessor_method)->context;
accessor_method = ((MonoMethodInflated*)accessor_method)->declaring;
container = mono_method_get_generic_container (accessor_method);
if (!container)
container = mono_class_try_get_generic_container (accessor_method->klass); //FIXME is this a case of a try?
g_assert (container);
}
}

printf("work on: %s (generic = %d, inflated = %d)\n", mono_method_full_name(accessor_method, TRUE), accessor_method->is_generic?1:0, accessor_method->is_inflated?1:0);

/*
* the method is either a generic method definition, or it might be inflated, not both at
* the same time.
*/
g_assert (!(is_generic && is_inflated));

/*
* Check cache
*/
Expand All@@ -5284,16 +5321,17 @@ mono_marshal_get_unsafe_accessor_wrapper (MonoMethod *accessor_method, MonoUnsaf
printf ("Cache miss\n");

mb = mono_mb_new (accessor_method->klass, accessor_method->name, MONO_WRAPPER_OTHER);
if (is_generic) {
if (generic_wrapper) {
// If the accessor method was generic, make the wrapper generic, too.

// Load a copy of the generic params of the accessor method
mb->method->is_generic =is_generic;
mb->method->is_generic =generic_wrapper;
container = mono_class_try_get_generic_container (accessor_method->klass);
container = mono_metadata_load_generic_params (m_class_get_image (accessor_method->klass), accessor_method->token, container, /*owner:*/mb->method);
mono_method_set_generic_container (mb->method, container);

MonoGenericContext inst_ctx = {0,};
// FIXME: if is_inflated, do we need to mess with ctx?
inst_ctx.method_inst = container->context.method_inst;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Why only the method context is set here? What about the class context?

Copy link
MemberAuthor

@lambdageeklambdageekMay 10, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

So conceptually if both the class is generic and thestatic extern accessor method is generic, when we make a wrapper we want its signature to use the same exact class gparams as the accessor method (conceptually both the accessor method and the wrapper are members of the class). But we want it to use its own brand new method gparams. So we take the original signature of hte access method and replace the method gparams:

classG<T>{publicstaticexternTuple<T,U>Accessor<U>(Tt,Uu);// wrapper:// public static extern Tuple<T, U2> wrapper_Accessor<U2>(T t, U2 u);}

so it's as if the wrapper instead of having a gparam namedU has a gparam namedU2. And so if we just take signature of the accessor, we have to replace allUs byU2. But theT is the same


ERROR_DECL (error);
Expand All@@ -5308,8 +5346,12 @@ mono_marshal_get_unsafe_accessor_wrapper (MonoMethod *accessor_method, MonoUnsaf

get_marshal_cb ()->mb_skip_visibility (mb);

if (generic_wrapper || is_inflated) {
// wrapper data will mention MonoClassField* and MonoMethod* that need to be inflated
get_marshal_cb ()->mb_inflate_wrapper_data (mb);
}

// TODO: pass container, too
// TODO: passing the ctx is not super useful because accessor_method is always the generic version of the method, even if is_inflated == TRUE. pass `is_inflated` instead
get_marshal_cb ()->emit_unsafe_accessor_wrapper (mb, accessor_method, sig, is_inflated, kind, member_name);

info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_UNSAFE_ACCESSOR);
Expand All@@ -5321,6 +5363,12 @@ mono_marshal_get_unsafe_accessor_wrapper (MonoMethod *accessor_method, MonoUnsaf
MonoMethod *def;
def = mono_mb_create_and_cache_full (cache, accessor_method, mb, sig, sig->param_count + 16, info, NULL);
res = cache_generic_wrapper (cache, orig_method, def, ctx, orig_method);
// FIXME: this right here is where things went bad when we inflated the generic
// wrapper. The reason is because all the MonoMethodWrapper:method_data is still
// refering to the generic class. But in the JIT case we don't have generic
// sharing, and so none of that stuff will get substituted, probably.

// Why does this work for class context generic wrappers?
} else {
res = mono_mb_create_and_cache_full (cache, accessor_method, mb, sig, sig->param_count + 16, info, NULL);
}
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp