Skip to content

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods - #90875

Merged
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods
Aug 24, 2023
Merged

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods#90875
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods

Conversation

@kotlarmilos

@kotlarmiloskotlarmilos commented Aug 21, 2023

Copy link
Copy Markdown
Member

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, this arg should be null.

Contributes to #90732

@kotlarmiloskotlarmilos added this to the 8.0.0 milestone Aug 21, 2023
@kotlarmiloskotlarmilos self-assigned this Aug 21, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, the receiver's type is null. In these scenarios, the call cannot be made through constrained_gsharedvt_call_setup, and the type is retrieved from vtable of a class.

Hopefully fixes #90732

Author:kotlarmilos
Assignees:kotlarmilos
Labels:

area-Codegen-AOT-mono, os-ios

Milestone:8.0.0

@LeVladIonescu

Copy link
Copy Markdown
Contributor

Can you also add the testcase here?

@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

Good idea. We will add a test case once we confirm this is the right fix.

break;
default:
/* Object.GetType () is an intrinsic under netcore */
if (!mono_class_is_ginst (cmethod->klass) && !cmethod->is_inflated && !strcmp (cmethod->name, "GetType")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this code was a special case for call to Object.GetType () by returning vt->type. Your change just makes every static virtual call do the same thing instead of running the actual method !?

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, here is the reasoning behind this change. Before the optimization of constrained calls from gshared methods in #79339, the type was retrieved as vt = mono_class_vtable_checked (klass, error);, in the same way as it is done here. After that, in #65126 arguments of static virtual methods are handled in the same way as for Object.GetType ():

/* !fsig->hasthis is for the wrapper for the Object.GetType () icall or static virtual methods */
if ((fsig->hasthis||m_method_is_static (cmethod)) &&fsig->param_count) {

Additionally, there is a note that the mp is null in case of static virtual methods, which is why the constrained_gsharedvt_call_setup fails:

/*
* mono_gsharedvt_constrained_call:
*
* Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
* the arguments to the method in the format used by mono_runtime_invoke_checked ().
* MP is NULL if CMETHOD is a static virtual method.
*/
MonoObject*
mono_gsharedvt_constrained_call (gpointermp, MonoMethod*cmethod, MonoClass*klass,
MonoGsharedvtConstrainedCallInfo*info, guint8*deref_args, gpointer*args)
{

My assumption was that it shouldn't reach the constrained_gsharedvt_call_setup in this case.

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

After offline discussion, the above ^ was a wild assumption :) The static methods should be handled in constrained_gsharedvt_call_setup as @BrzVlad suggested.

@BrzVlad

BrzVlad commented Aug 22, 2023

Copy link
Copy Markdown
Member

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

@kotlarmilos

kotlarmilos commented Aug 22, 2023

Copy link
Copy Markdown
MemberAuthor

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

Thanks for feedback! It should be already handled here:

/* Lookup the virtual method */
mono_class_setup_vtable (klass);
g_assert (m_class_get_vtable (klass));
vt_slot=mono_method_get_vtable_slot (cmethod);
if (mono_class_is_interface (cmethod->klass)) {
iface_offset=mono_class_interface_offset (klass, cmethod->klass);
g_assert (iface_offset!=-1);
vt_slot+=iface_offset;
}
m=m_class_get_vtable (klass) [vt_slot];
if (cmethod->is_inflated) {
m=mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
return_val_if_nok (error, NULL);
}

Do you think we can avoid this_obj assignment if receiver's type (mp) is null?

@kotlarmilos
kotlarmilos marked this pull request as ready for review August 22, 2023 16:04
@kotlarmiloskotlarmilos changed the title [mono][wip] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methodsAug 22, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

public class test
{
[Fact]
public static int TestEntryPoint()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test seems quite trivial. Would it even fail on CI ? Or is the failure dependent on compilation flags that we don't use on CI.

@kotlarmiloskotlarmilosAug 23, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The issue occurred in full AOT mode only. This test is used locally to reproduce and fix the issue, which is similar to the customer reported issue. Do you think it should be expanded?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you disable your fix will this test fail on CI currently ?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Before adding a new test, we should verify if it is not already covered on the CI. This will be done once the AOT job is fixed. The customer issue won't be closed until we verify that this case has test coverage.

@kotlarmilos
kotlarmilos merged commit 0c4329b into dotnet:mainAug 24, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/5964549560

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@kotlarmilos@LeVladIonescu@BrzVlad
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods by kotlarmilos · Pull Request #90875 · dotnet/runtime · GitHub
Skip to content

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods - #90875

Merged
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods
Aug 24, 2023
Merged

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods#90875
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods

Conversation

@kotlarmilos

@kotlarmiloskotlarmilos commented Aug 21, 2023

Copy link
Copy Markdown
Member

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, this arg should be null.

Contributes to #90732

@kotlarmiloskotlarmilos added this to the 8.0.0 milestone Aug 21, 2023
@kotlarmiloskotlarmilos self-assigned this Aug 21, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, the receiver's type is null. In these scenarios, the call cannot be made through constrained_gsharedvt_call_setup, and the type is retrieved from vtable of a class.

Hopefully fixes #90732

Author:kotlarmilos
Assignees:kotlarmilos
Labels:

area-Codegen-AOT-mono, os-ios

Milestone:8.0.0

@LeVladIonescu

Copy link
Copy Markdown
Contributor

Can you also add the testcase here?

@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

Good idea. We will add a test case once we confirm this is the right fix.

break;
default:
/* Object.GetType () is an intrinsic under netcore */
if (!mono_class_is_ginst (cmethod->klass) && !cmethod->is_inflated && !strcmp (cmethod->name, "GetType")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this code was a special case for call to Object.GetType () by returning vt->type. Your change just makes every static virtual call do the same thing instead of running the actual method !?

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, here is the reasoning behind this change. Before the optimization of constrained calls from gshared methods in #79339, the type was retrieved as vt = mono_class_vtable_checked (klass, error);, in the same way as it is done here. After that, in #65126 arguments of static virtual methods are handled in the same way as for Object.GetType ():

/* !fsig->hasthis is for the wrapper for the Object.GetType () icall or static virtual methods */
if ((fsig->hasthis||m_method_is_static (cmethod)) &&fsig->param_count) {

Additionally, there is a note that the mp is null in case of static virtual methods, which is why the constrained_gsharedvt_call_setup fails:

/*
* mono_gsharedvt_constrained_call:
*
* Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
* the arguments to the method in the format used by mono_runtime_invoke_checked ().
* MP is NULL if CMETHOD is a static virtual method.
*/
MonoObject*
mono_gsharedvt_constrained_call (gpointermp, MonoMethod*cmethod, MonoClass*klass,
MonoGsharedvtConstrainedCallInfo*info, guint8*deref_args, gpointer*args)
{

My assumption was that it shouldn't reach the constrained_gsharedvt_call_setup in this case.

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

After offline discussion, the above ^ was a wild assumption :) The static methods should be handled in constrained_gsharedvt_call_setup as @BrzVlad suggested.

@BrzVlad

BrzVlad commented Aug 22, 2023

Copy link
Copy Markdown
Member

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

@kotlarmilos

kotlarmilos commented Aug 22, 2023

Copy link
Copy Markdown
MemberAuthor

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

Thanks for feedback! It should be already handled here:

/* Lookup the virtual method */
mono_class_setup_vtable (klass);
g_assert (m_class_get_vtable (klass));
vt_slot=mono_method_get_vtable_slot (cmethod);
if (mono_class_is_interface (cmethod->klass)) {
iface_offset=mono_class_interface_offset (klass, cmethod->klass);
g_assert (iface_offset!=-1);
vt_slot+=iface_offset;
}
m=m_class_get_vtable (klass) [vt_slot];
if (cmethod->is_inflated) {
m=mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
return_val_if_nok (error, NULL);
}

Do you think we can avoid this_obj assignment if receiver's type (mp) is null?

@kotlarmilos
kotlarmilos marked this pull request as ready for review August 22, 2023 16:04
@kotlarmiloskotlarmilos changed the title [mono][wip] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methodsAug 22, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

public class test
{
[Fact]
public static int TestEntryPoint()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test seems quite trivial. Would it even fail on CI ? Or is the failure dependent on compilation flags that we don't use on CI.

@kotlarmiloskotlarmilosAug 23, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The issue occurred in full AOT mode only. This test is used locally to reproduce and fix the issue, which is similar to the customer reported issue. Do you think it should be expanded?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you disable your fix will this test fail on CI currently ?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Before adding a new test, we should verify if it is not already covered on the CI. This will be done once the AOT job is fixed. The customer issue won't be closed until we verify that this case has test coverage.

@kotlarmilos
kotlarmilos merged commit 0c4329b into dotnet:mainAug 24, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/5964549560

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@kotlarmilos@LeVladIonescu@BrzVlad
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods by kotlarmilos · Pull Request #90875 · dotnet/runtime · GitHub
Skip to content

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods - #90875

Merged
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods
Aug 24, 2023
Merged

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods#90875
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods

Conversation

@kotlarmilos

@kotlarmiloskotlarmilos commented Aug 21, 2023

Copy link
Copy Markdown
Member

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, this arg should be null.

Contributes to #90732

@kotlarmiloskotlarmilos added this to the 8.0.0 milestone Aug 21, 2023
@kotlarmiloskotlarmilos self-assigned this Aug 21, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, the receiver's type is null. In these scenarios, the call cannot be made through constrained_gsharedvt_call_setup, and the type is retrieved from vtable of a class.

Hopefully fixes #90732

Author:kotlarmilos
Assignees:kotlarmilos
Labels:

area-Codegen-AOT-mono, os-ios

Milestone:8.0.0

@LeVladIonescu

Copy link
Copy Markdown
Contributor

Can you also add the testcase here?

@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

Good idea. We will add a test case once we confirm this is the right fix.

break;
default:
/* Object.GetType () is an intrinsic under netcore */
if (!mono_class_is_ginst (cmethod->klass) && !cmethod->is_inflated && !strcmp (cmethod->name, "GetType")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this code was a special case for call to Object.GetType () by returning vt->type. Your change just makes every static virtual call do the same thing instead of running the actual method !?

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, here is the reasoning behind this change. Before the optimization of constrained calls from gshared methods in #79339, the type was retrieved as vt = mono_class_vtable_checked (klass, error);, in the same way as it is done here. After that, in #65126 arguments of static virtual methods are handled in the same way as for Object.GetType ():

/* !fsig->hasthis is for the wrapper for the Object.GetType () icall or static virtual methods */
if ((fsig->hasthis||m_method_is_static (cmethod)) &&fsig->param_count) {

Additionally, there is a note that the mp is null in case of static virtual methods, which is why the constrained_gsharedvt_call_setup fails:

/*
* mono_gsharedvt_constrained_call:
*
* Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
* the arguments to the method in the format used by mono_runtime_invoke_checked ().
* MP is NULL if CMETHOD is a static virtual method.
*/
MonoObject*
mono_gsharedvt_constrained_call (gpointermp, MonoMethod*cmethod, MonoClass*klass,
MonoGsharedvtConstrainedCallInfo*info, guint8*deref_args, gpointer*args)
{

My assumption was that it shouldn't reach the constrained_gsharedvt_call_setup in this case.

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

After offline discussion, the above ^ was a wild assumption :) The static methods should be handled in constrained_gsharedvt_call_setup as @BrzVlad suggested.

@BrzVlad

BrzVlad commented Aug 22, 2023

Copy link
Copy Markdown
Member

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

@kotlarmilos

kotlarmilos commented Aug 22, 2023

Copy link
Copy Markdown
MemberAuthor

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

Thanks for feedback! It should be already handled here:

/* Lookup the virtual method */
mono_class_setup_vtable (klass);
g_assert (m_class_get_vtable (klass));
vt_slot=mono_method_get_vtable_slot (cmethod);
if (mono_class_is_interface (cmethod->klass)) {
iface_offset=mono_class_interface_offset (klass, cmethod->klass);
g_assert (iface_offset!=-1);
vt_slot+=iface_offset;
}
m=m_class_get_vtable (klass) [vt_slot];
if (cmethod->is_inflated) {
m=mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
return_val_if_nok (error, NULL);
}

Do you think we can avoid this_obj assignment if receiver's type (mp) is null?

@kotlarmilos
kotlarmilos marked this pull request as ready for review August 22, 2023 16:04
@kotlarmiloskotlarmilos changed the title [mono][wip] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methodsAug 22, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

public class test
{
[Fact]
public static int TestEntryPoint()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test seems quite trivial. Would it even fail on CI ? Or is the failure dependent on compilation flags that we don't use on CI.

@kotlarmiloskotlarmilosAug 23, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The issue occurred in full AOT mode only. This test is used locally to reproduce and fix the issue, which is similar to the customer reported issue. Do you think it should be expanded?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you disable your fix will this test fail on CI currently ?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Before adding a new test, we should verify if it is not already covered on the CI. This will be done once the AOT job is fixed. The customer issue won't be closed until we verify that this case has test coverage.

@kotlarmilos
kotlarmilos merged commit 0c4329b into dotnet:mainAug 24, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/5964549560

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@kotlarmilos@LeVladIonescu@BrzVlad
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods by kotlarmilos · Pull Request #90875 · dotnet/runtime · GitHub
Skip to content

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods - #90875

Merged
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods
Aug 24, 2023
Merged

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods#90875
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods

Conversation

@kotlarmilos

@kotlarmiloskotlarmilos commented Aug 21, 2023

Copy link
Copy Markdown
Member

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, this arg should be null.

Contributes to #90732

@kotlarmiloskotlarmilos added this to the 8.0.0 milestone Aug 21, 2023
@kotlarmiloskotlarmilos self-assigned this Aug 21, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, the receiver's type is null. In these scenarios, the call cannot be made through constrained_gsharedvt_call_setup, and the type is retrieved from vtable of a class.

Hopefully fixes #90732

Author:kotlarmilos
Assignees:kotlarmilos
Labels:

area-Codegen-AOT-mono, os-ios

Milestone:8.0.0

@LeVladIonescu

Copy link
Copy Markdown
Contributor

Can you also add the testcase here?

@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

Good idea. We will add a test case once we confirm this is the right fix.

break;
default:
/* Object.GetType () is an intrinsic under netcore */
if (!mono_class_is_ginst (cmethod->klass) && !cmethod->is_inflated && !strcmp (cmethod->name, "GetType")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this code was a special case for call to Object.GetType () by returning vt->type. Your change just makes every static virtual call do the same thing instead of running the actual method !?

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, here is the reasoning behind this change. Before the optimization of constrained calls from gshared methods in #79339, the type was retrieved as vt = mono_class_vtable_checked (klass, error);, in the same way as it is done here. After that, in #65126 arguments of static virtual methods are handled in the same way as for Object.GetType ():

/* !fsig->hasthis is for the wrapper for the Object.GetType () icall or static virtual methods */
if ((fsig->hasthis||m_method_is_static (cmethod)) &&fsig->param_count) {

Additionally, there is a note that the mp is null in case of static virtual methods, which is why the constrained_gsharedvt_call_setup fails:

/*
* mono_gsharedvt_constrained_call:
*
* Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
* the arguments to the method in the format used by mono_runtime_invoke_checked ().
* MP is NULL if CMETHOD is a static virtual method.
*/
MonoObject*
mono_gsharedvt_constrained_call (gpointermp, MonoMethod*cmethod, MonoClass*klass,
MonoGsharedvtConstrainedCallInfo*info, guint8*deref_args, gpointer*args)
{

My assumption was that it shouldn't reach the constrained_gsharedvt_call_setup in this case.

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

After offline discussion, the above ^ was a wild assumption :) The static methods should be handled in constrained_gsharedvt_call_setup as @BrzVlad suggested.

@BrzVlad

BrzVlad commented Aug 22, 2023

Copy link
Copy Markdown
Member

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

@kotlarmilos

kotlarmilos commented Aug 22, 2023

Copy link
Copy Markdown
MemberAuthor

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

Thanks for feedback! It should be already handled here:

/* Lookup the virtual method */
mono_class_setup_vtable (klass);
g_assert (m_class_get_vtable (klass));
vt_slot=mono_method_get_vtable_slot (cmethod);
if (mono_class_is_interface (cmethod->klass)) {
iface_offset=mono_class_interface_offset (klass, cmethod->klass);
g_assert (iface_offset!=-1);
vt_slot+=iface_offset;
}
m=m_class_get_vtable (klass) [vt_slot];
if (cmethod->is_inflated) {
m=mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
return_val_if_nok (error, NULL);
}

Do you think we can avoid this_obj assignment if receiver's type (mp) is null?

@kotlarmilos
kotlarmilos marked this pull request as ready for review August 22, 2023 16:04
@kotlarmiloskotlarmilos changed the title [mono][wip] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methodsAug 22, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

public class test
{
[Fact]
public static int TestEntryPoint()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test seems quite trivial. Would it even fail on CI ? Or is the failure dependent on compilation flags that we don't use on CI.

@kotlarmiloskotlarmilosAug 23, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The issue occurred in full AOT mode only. This test is used locally to reproduce and fix the issue, which is similar to the customer reported issue. Do you think it should be expanded?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you disable your fix will this test fail on CI currently ?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Before adding a new test, we should verify if it is not already covered on the CI. This will be done once the AOT job is fixed. The customer issue won't be closed until we verify that this case has test coverage.

@kotlarmilos
kotlarmilos merged commit 0c4329b into dotnet:mainAug 24, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/5964549560

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@kotlarmilos@LeVladIonescu@BrzVlad
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' [mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods by kotlarmilos · Pull Request #90875 · dotnet/runtime · GitHub
Skip to content

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods - #90875

Merged
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods
Aug 24, 2023
Merged

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods#90875
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods

Conversation

@kotlarmilos

@kotlarmiloskotlarmilos commented Aug 21, 2023

Copy link
Copy Markdown
Member

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, this arg should be null.

Contributes to #90732

@kotlarmiloskotlarmilos added this to the 8.0.0 milestone Aug 21, 2023
@kotlarmiloskotlarmilos self-assigned this Aug 21, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, the receiver's type is null. In these scenarios, the call cannot be made through constrained_gsharedvt_call_setup, and the type is retrieved from vtable of a class.

Hopefully fixes #90732

Author:kotlarmilos
Assignees:kotlarmilos
Labels:

area-Codegen-AOT-mono, os-ios

Milestone:8.0.0

@LeVladIonescu

Copy link
Copy Markdown
Contributor

Can you also add the testcase here?

@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

Good idea. We will add a test case once we confirm this is the right fix.

break;
default:
/* Object.GetType () is an intrinsic under netcore */
if (!mono_class_is_ginst (cmethod->klass) && !cmethod->is_inflated && !strcmp (cmethod->name, "GetType")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this code was a special case for call to Object.GetType () by returning vt->type. Your change just makes every static virtual call do the same thing instead of running the actual method !?

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, here is the reasoning behind this change. Before the optimization of constrained calls from gshared methods in #79339, the type was retrieved as vt = mono_class_vtable_checked (klass, error);, in the same way as it is done here. After that, in #65126 arguments of static virtual methods are handled in the same way as for Object.GetType ():

/* !fsig->hasthis is for the wrapper for the Object.GetType () icall or static virtual methods */
if ((fsig->hasthis||m_method_is_static (cmethod)) &&fsig->param_count) {

Additionally, there is a note that the mp is null in case of static virtual methods, which is why the constrained_gsharedvt_call_setup fails:

/*
* mono_gsharedvt_constrained_call:
*
* Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
* the arguments to the method in the format used by mono_runtime_invoke_checked ().
* MP is NULL if CMETHOD is a static virtual method.
*/
MonoObject*
mono_gsharedvt_constrained_call (gpointermp, MonoMethod*cmethod, MonoClass*klass,
MonoGsharedvtConstrainedCallInfo*info, guint8*deref_args, gpointer*args)
{

My assumption was that it shouldn't reach the constrained_gsharedvt_call_setup in this case.

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

After offline discussion, the above ^ was a wild assumption :) The static methods should be handled in constrained_gsharedvt_call_setup as @BrzVlad suggested.

@BrzVlad

BrzVlad commented Aug 22, 2023

Copy link
Copy Markdown
Member

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

@kotlarmilos

kotlarmilos commented Aug 22, 2023

Copy link
Copy Markdown
MemberAuthor

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

Thanks for feedback! It should be already handled here:

/* Lookup the virtual method */
mono_class_setup_vtable (klass);
g_assert (m_class_get_vtable (klass));
vt_slot=mono_method_get_vtable_slot (cmethod);
if (mono_class_is_interface (cmethod->klass)) {
iface_offset=mono_class_interface_offset (klass, cmethod->klass);
g_assert (iface_offset!=-1);
vt_slot+=iface_offset;
}
m=m_class_get_vtable (klass) [vt_slot];
if (cmethod->is_inflated) {
m=mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
return_val_if_nok (error, NULL);
}

Do you think we can avoid this_obj assignment if receiver's type (mp) is null?

@kotlarmilos
kotlarmilos marked this pull request as ready for review August 22, 2023 16:04
@kotlarmiloskotlarmilos changed the title [mono][wip] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methodsAug 22, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

public class test
{
[Fact]
public static int TestEntryPoint()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test seems quite trivial. Would it even fail on CI ? Or is the failure dependent on compilation flags that we don't use on CI.

@kotlarmiloskotlarmilosAug 23, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The issue occurred in full AOT mode only. This test is used locally to reproduce and fix the issue, which is similar to the customer reported issue. Do you think it should be expanded?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you disable your fix will this test fail on CI currently ?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Before adding a new test, we should verify if it is not already covered on the CI. This will be done once the AOT job is fixed. The customer issue won't be closed until we verify that this case has test coverage.

@kotlarmilos
kotlarmilos merged commit 0c4329b into dotnet:mainAug 24, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/5964549560

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@kotlarmilos@LeVladIonescu@BrzVlad
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods by kotlarmilos · Pull Request #90875 · dotnet/runtime · GitHub
Skip to content

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods - #90875

Merged
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods
Aug 24, 2023
Merged

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods#90875
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods

Conversation

@kotlarmilos

@kotlarmiloskotlarmilos commented Aug 21, 2023

Copy link
Copy Markdown
Member

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, this arg should be null.

Contributes to #90732

@kotlarmiloskotlarmilos added this to the 8.0.0 milestone Aug 21, 2023
@kotlarmiloskotlarmilos self-assigned this Aug 21, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, the receiver's type is null. In these scenarios, the call cannot be made through constrained_gsharedvt_call_setup, and the type is retrieved from vtable of a class.

Hopefully fixes #90732

Author:kotlarmilos
Assignees:kotlarmilos
Labels:

area-Codegen-AOT-mono, os-ios

Milestone:8.0.0

@LeVladIonescu

Copy link
Copy Markdown
Contributor

Can you also add the testcase here?

@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

Good idea. We will add a test case once we confirm this is the right fix.

break;
default:
/* Object.GetType () is an intrinsic under netcore */
if (!mono_class_is_ginst (cmethod->klass) && !cmethod->is_inflated && !strcmp (cmethod->name, "GetType")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this code was a special case for call to Object.GetType () by returning vt->type. Your change just makes every static virtual call do the same thing instead of running the actual method !?

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, here is the reasoning behind this change. Before the optimization of constrained calls from gshared methods in #79339, the type was retrieved as vt = mono_class_vtable_checked (klass, error);, in the same way as it is done here. After that, in #65126 arguments of static virtual methods are handled in the same way as for Object.GetType ():

/* !fsig->hasthis is for the wrapper for the Object.GetType () icall or static virtual methods */
if ((fsig->hasthis||m_method_is_static (cmethod)) &&fsig->param_count) {

Additionally, there is a note that the mp is null in case of static virtual methods, which is why the constrained_gsharedvt_call_setup fails:

/*
* mono_gsharedvt_constrained_call:
*
* Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
* the arguments to the method in the format used by mono_runtime_invoke_checked ().
* MP is NULL if CMETHOD is a static virtual method.
*/
MonoObject*
mono_gsharedvt_constrained_call (gpointermp, MonoMethod*cmethod, MonoClass*klass,
MonoGsharedvtConstrainedCallInfo*info, guint8*deref_args, gpointer*args)
{

My assumption was that it shouldn't reach the constrained_gsharedvt_call_setup in this case.

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

After offline discussion, the above ^ was a wild assumption :) The static methods should be handled in constrained_gsharedvt_call_setup as @BrzVlad suggested.

@BrzVlad

BrzVlad commented Aug 22, 2023

Copy link
Copy Markdown
Member

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

@kotlarmilos

kotlarmilos commented Aug 22, 2023

Copy link
Copy Markdown
MemberAuthor

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

Thanks for feedback! It should be already handled here:

/* Lookup the virtual method */
mono_class_setup_vtable (klass);
g_assert (m_class_get_vtable (klass));
vt_slot=mono_method_get_vtable_slot (cmethod);
if (mono_class_is_interface (cmethod->klass)) {
iface_offset=mono_class_interface_offset (klass, cmethod->klass);
g_assert (iface_offset!=-1);
vt_slot+=iface_offset;
}
m=m_class_get_vtable (klass) [vt_slot];
if (cmethod->is_inflated) {
m=mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
return_val_if_nok (error, NULL);
}

Do you think we can avoid this_obj assignment if receiver's type (mp) is null?

@kotlarmilos
kotlarmilos marked this pull request as ready for review August 22, 2023 16:04
@kotlarmiloskotlarmilos changed the title [mono][wip] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methodsAug 22, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

public class test
{
[Fact]
public static int TestEntryPoint()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test seems quite trivial. Would it even fail on CI ? Or is the failure dependent on compilation flags that we don't use on CI.

@kotlarmiloskotlarmilosAug 23, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The issue occurred in full AOT mode only. This test is used locally to reproduce and fix the issue, which is similar to the customer reported issue. Do you think it should be expanded?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you disable your fix will this test fail on CI currently ?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Before adding a new test, we should verify if it is not already covered on the CI. This will be done once the AOT job is fixed. The customer issue won't be closed until we verify that this case has test coverage.

@kotlarmilos
kotlarmilos merged commit 0c4329b into dotnet:mainAug 24, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/5964549560

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@kotlarmilos@LeVladIonescu@BrzVlad
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods by kotlarmilos · Pull Request #90875 · dotnet/runtime · GitHub
Skip to content

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods - #90875

Merged
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods
Aug 24, 2023
Merged

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods#90875
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods

Conversation

@kotlarmilos

@kotlarmiloskotlarmilos commented Aug 21, 2023

Copy link
Copy Markdown
Member

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, this arg should be null.

Contributes to #90732

@kotlarmiloskotlarmilos added this to the 8.0.0 milestone Aug 21, 2023
@kotlarmiloskotlarmilos self-assigned this Aug 21, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, the receiver's type is null. In these scenarios, the call cannot be made through constrained_gsharedvt_call_setup, and the type is retrieved from vtable of a class.

Hopefully fixes #90732

Author:kotlarmilos
Assignees:kotlarmilos
Labels:

area-Codegen-AOT-mono, os-ios

Milestone:8.0.0

@LeVladIonescu

Copy link
Copy Markdown
Contributor

Can you also add the testcase here?

@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

Good idea. We will add a test case once we confirm this is the right fix.

break;
default:
/* Object.GetType () is an intrinsic under netcore */
if (!mono_class_is_ginst (cmethod->klass) && !cmethod->is_inflated && !strcmp (cmethod->name, "GetType")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this code was a special case for call to Object.GetType () by returning vt->type. Your change just makes every static virtual call do the same thing instead of running the actual method !?

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, here is the reasoning behind this change. Before the optimization of constrained calls from gshared methods in #79339, the type was retrieved as vt = mono_class_vtable_checked (klass, error);, in the same way as it is done here. After that, in #65126 arguments of static virtual methods are handled in the same way as for Object.GetType ():

/* !fsig->hasthis is for the wrapper for the Object.GetType () icall or static virtual methods */
if ((fsig->hasthis||m_method_is_static (cmethod)) &&fsig->param_count) {

Additionally, there is a note that the mp is null in case of static virtual methods, which is why the constrained_gsharedvt_call_setup fails:

/*
* mono_gsharedvt_constrained_call:
*
* Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
* the arguments to the method in the format used by mono_runtime_invoke_checked ().
* MP is NULL if CMETHOD is a static virtual method.
*/
MonoObject*
mono_gsharedvt_constrained_call (gpointermp, MonoMethod*cmethod, MonoClass*klass,
MonoGsharedvtConstrainedCallInfo*info, guint8*deref_args, gpointer*args)
{

My assumption was that it shouldn't reach the constrained_gsharedvt_call_setup in this case.

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

After offline discussion, the above ^ was a wild assumption :) The static methods should be handled in constrained_gsharedvt_call_setup as @BrzVlad suggested.

@BrzVlad

BrzVlad commented Aug 22, 2023

Copy link
Copy Markdown
Member

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

@kotlarmilos

kotlarmilos commented Aug 22, 2023

Copy link
Copy Markdown
MemberAuthor

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

Thanks for feedback! It should be already handled here:

/* Lookup the virtual method */
mono_class_setup_vtable (klass);
g_assert (m_class_get_vtable (klass));
vt_slot=mono_method_get_vtable_slot (cmethod);
if (mono_class_is_interface (cmethod->klass)) {
iface_offset=mono_class_interface_offset (klass, cmethod->klass);
g_assert (iface_offset!=-1);
vt_slot+=iface_offset;
}
m=m_class_get_vtable (klass) [vt_slot];
if (cmethod->is_inflated) {
m=mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
return_val_if_nok (error, NULL);
}

Do you think we can avoid this_obj assignment if receiver's type (mp) is null?

@kotlarmilos
kotlarmilos marked this pull request as ready for review August 22, 2023 16:04
@kotlarmiloskotlarmilos changed the title [mono][wip] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methodsAug 22, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

public class test
{
[Fact]
public static int TestEntryPoint()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test seems quite trivial. Would it even fail on CI ? Or is the failure dependent on compilation flags that we don't use on CI.

@kotlarmiloskotlarmilosAug 23, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The issue occurred in full AOT mode only. This test is used locally to reproduce and fix the issue, which is similar to the customer reported issue. Do you think it should be expanded?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you disable your fix will this test fail on CI currently ?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Before adding a new test, we should verify if it is not already covered on the CI. This will be done once the AOT job is fixed. The customer issue won't be closed until we verify that this case has test coverage.

@kotlarmilos
kotlarmilos merged commit 0c4329b into dotnet:mainAug 24, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/5964549560

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@kotlarmilos@LeVladIonescu@BrzVlad
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); [mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods by kotlarmilos · Pull Request #90875 · dotnet/runtime · GitHub
Skip to content

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods - #90875

Merged
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods
Aug 24, 2023
Merged

[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods#90875
kotlarmilos merged 5 commits into
dotnet:mainfrom
kotlarmilos:bugfix/static-virtual-methods

Conversation

@kotlarmilos

@kotlarmiloskotlarmilos commented Aug 21, 2023

Copy link
Copy Markdown
Member

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, this arg should be null.

Contributes to #90732

@kotlarmiloskotlarmilos added this to the 8.0.0 milestone Aug 21, 2023
@kotlarmiloskotlarmilos self-assigned this Aug 21, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR extends mono_gsharedvt_constrained_call JIT icall to handle static virtual methods. If cmethod is a static virtual method, the receiver's type is null. In these scenarios, the call cannot be made through constrained_gsharedvt_call_setup, and the type is retrieved from vtable of a class.

Hopefully fixes #90732

Author:kotlarmilos
Assignees:kotlarmilos
Labels:

area-Codegen-AOT-mono, os-ios

Milestone:8.0.0

@LeVladIonescu

Copy link
Copy Markdown
Contributor

Can you also add the testcase here?

@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

Good idea. We will add a test case once we confirm this is the right fix.

break;
default:
/* Object.GetType () is an intrinsic under netcore */
if (!mono_class_is_ginst (cmethod->klass) && !cmethod->is_inflated && !strcmp (cmethod->name, "GetType")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this code was a special case for call to Object.GetType () by returning vt->type. Your change just makes every static virtual call do the same thing instead of running the actual method !?

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, here is the reasoning behind this change. Before the optimization of constrained calls from gshared methods in #79339, the type was retrieved as vt = mono_class_vtable_checked (klass, error);, in the same way as it is done here. After that, in #65126 arguments of static virtual methods are handled in the same way as for Object.GetType ():

/* !fsig->hasthis is for the wrapper for the Object.GetType () icall or static virtual methods */
if ((fsig->hasthis||m_method_is_static (cmethod)) &&fsig->param_count) {

Additionally, there is a note that the mp is null in case of static virtual methods, which is why the constrained_gsharedvt_call_setup fails:

/*
* mono_gsharedvt_constrained_call:
*
* Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
* the arguments to the method in the format used by mono_runtime_invoke_checked ().
* MP is NULL if CMETHOD is a static virtual method.
*/
MonoObject*
mono_gsharedvt_constrained_call (gpointermp, MonoMethod*cmethod, MonoClass*klass,
MonoGsharedvtConstrainedCallInfo*info, guint8*deref_args, gpointer*args)
{

My assumption was that it shouldn't reach the constrained_gsharedvt_call_setup in this case.

@kotlarmiloskotlarmilosAug 22, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

After offline discussion, the above ^ was a wild assumption :) The static methods should be handled in constrained_gsharedvt_call_setup as @BrzVlad suggested.

@BrzVlad

BrzVlad commented Aug 22, 2023

Copy link
Copy Markdown
Member

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

@kotlarmilos

kotlarmilos commented Aug 22, 2023

Copy link
Copy Markdown
MemberAuthor

As far as my understanding goes, when you get below to constrained_gsharedvt_call_setup, you have the constrained class in klass (which should implement the method to be called) and the static virtual method to be called in cmethod (double check this). This is enough information to resolve the actual implementation of cmethod in klass, just need find out why the code crashes.

Thanks for feedback! It should be already handled here:

/* Lookup the virtual method */
mono_class_setup_vtable (klass);
g_assert (m_class_get_vtable (klass));
vt_slot=mono_method_get_vtable_slot (cmethod);
if (mono_class_is_interface (cmethod->klass)) {
iface_offset=mono_class_interface_offset (klass, cmethod->klass);
g_assert (iface_offset!=-1);
vt_slot+=iface_offset;
}
m=m_class_get_vtable (klass) [vt_slot];
if (cmethod->is_inflated) {
m=mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
return_val_if_nok (error, NULL);
}

Do you think we can avoid this_obj assignment if receiver's type (mp) is null?

@kotlarmilos
kotlarmilos marked this pull request as ready for review August 22, 2023 16:04
@kotlarmiloskotlarmilos changed the title [mono][wip] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods[mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methodsAug 22, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

public class test
{
[Fact]
public static int TestEntryPoint()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test seems quite trivial. Would it even fail on CI ? Or is the failure dependent on compilation flags that we don't use on CI.

@kotlarmiloskotlarmilosAug 23, 2023

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The issue occurred in full AOT mode only. This test is used locally to reproduce and fix the issue, which is similar to the customer reported issue. Do you think it should be expanded?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you disable your fix will this test fail on CI currently ?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Before adding a new test, we should verify if it is not already covered on the CI. This will be done once the AOT job is fixed. The customer issue won't be closed until we verify that this case has test coverage.

@kotlarmilos
kotlarmilos merged commit 0c4329b into dotnet:mainAug 24, 2023
@kotlarmilos

Copy link
Copy Markdown
MemberAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/5964549560

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@kotlarmilos@LeVladIonescu@BrzVlad