toptensoftware / RichTextKit

Rich text rendering for SkiaSharp
Other
366 stars 73 forks source link

Exception: Attempting to JIT #32

Open charlenni opened 3 years ago

charlenni commented 3 years ago

I get, while using RichTextKit, the following error when calling Layout with FontFamily=null (default for new Font() ) or FontFamily="".

Error Message: "Attempting to JIT compile method 'bool Topten.RichTextKit.FontFallback/d__2:MoveNext ()' while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.\n"

StackTrace: at Topten.RichTextKit.TextBlock.AddDirectionalRun (Topten.RichTextKit.StyleRun styleRun, System.Int32 start, System.Int32 length, Topten.RichTextKit.TextDirection direction, Topten.RichTextKit.IStyle style) [0x00057] in <19e5ac464bd84f9c875ac01889614bdc>:0

What did I wrong?

janusw commented 3 years ago

The exception is is fact a System.ExecutionEngineException.

The full stack trace for RichTextKit is:

  at Topten.RichTextKit.TextBlock.AddDirectionalRun (Topten.RichTextKit.StyleRun styleRun, System.Int32 start, System.Int32 length, Topten.RichTextKit.TextDirection direction, Topten.RichTextKit.IStyle style) [0x00057] in <19e5ac464bd84f9c875ac01889614bdc>:0 
  at Topten.RichTextKit.TextBlock.BuildFontRuns () [0x002e6] in <19e5ac464bd84f9c875ac01889614bdc>:0 
  at Topten.RichTextKit.TextBlock.Layout () [0x000f5] in <19e5ac464bd84f9c875ac01889614bdc>:0 

What did I wrong?

The question is not what you did wrong, but since when this occurs and which change (probably in Xamarin.iOS) triggers it.

I see this with Visual Studio for Mac 8.9 and Xamarin.iOS 14.14.2.5. I assume the problem did not occur with VS for Mac 8.8 (and whatever Xamarin.iOS version it came with), but I'm not completely sure about that.

See Mapsui/Mapsui#1093 for a way to reproduce this.

janusw commented 3 years ago

Possibly relevant: https://docs.microsoft.com/en-us/xamarin/ios/troubleshooting/troubleshooting#systemexecutionengineexception-attempting-to-jit-compile-method-wrapper-managed-to-managed-foosystemcollectionsgenericicollection1get_count-

toptensoftware commented 3 years ago

Thanks for reporting. Unfortunately I don't have an iOS dev environment setup here (and not keen to set it up just for this one issue).

This seems like an issue with Xamarin AOT more than RichTextKit itself. If someone wants to investigate further and work out a fix for this then I'm happy to merge it.

charlenni commented 3 years ago

I investigate a little further. With the link @janusw provided (thank you), I would say, the relevant line is 1164 of TextBlock.cs. We get problems with the FontFallback.GetFontRuns(). It seems, that Xamarin.iOS „optimize“ the code, so that it leaves the FontFallback.GetFontRuns(). The suggestion for such a problem is mentioned in the above article: call it by yourself before this line. But I‘m not sure, ho to do this.

Any ideas?

charlenni commented 3 years ago

@janusw Could you try to change the linking of the iOS version. Some users had used „Don‘t link“ to solve this problem.

janusw commented 3 years ago

@janusw Could you try to change the linking of the iOS version. Some users had used „Don‘t link“ to solve this problem.

Tried to use "Don't link" for Mapsui.Samples.Forms.iOS, but that does not seem to help unfortunately.

janusw commented 3 years ago

I investigate a little further. With the link @janusw provided (thank you), I would say, the relevant line is 1164 of TextBlock.cs.

Yes, I think that's the one.

We get problems with the FontFallback.GetFontRuns(). It seems, that Xamarin.iOS „optimize“ the code, so that it leaves the FontFallback.GetFontRuns(). The suggestion for such a problem is mentioned in the above article: call it by yourself before this line. But I‘m not sure, ho to do this.

Any ideas?

I'm not quite sure. Maybe take apart the for loop and call MoveNext explicitly? (I might try that tonight.)

Or maybe the link is not fully to the point, after all. The error message is slightly different.

Btw, which section of https://docs.microsoft.com/en-us/xamarin/ios/internals/limitations do you think is the relevant one here?

janusw commented 3 years ago

We get problems with the FontFallback.GetFontRuns(). It seems, that Xamarin.iOS „optimize“ the code, so that it leaves the FontFallback.GetFontRuns(). The suggestion for such a problem is mentioned in the above article: call it by yourself before this line. But I‘m not sure, ho to do this. Any ideas?

I'm not quite sure. Maybe take apart the for loop and call MoveNext explicitly? (I might try that tonight.)

Something like this should do it:

----------------------- Topten.RichTextKit/TextBlock.cs -----------------------
index 5e75472..21f78e7 100644
@@ -1161,9 +1161,11 @@ namespace Topten.RichTextKit
             var codePointsSlice = _codePoints.SubSlice(start, length);

             // Split into font fallback runs
-            foreach (var fontRun in FontFallback.GetFontRuns(codePointsSlice, typeface, style.ReplacementCharacter))
+            IEnumerator<FontFallback.Run> runEnum = FontFallback.GetFontRuns(codePointsSlice, typeface, style.ReplacementCharacter).GetEnumerator();
+            while (runEnum.MoveNext())
             {
                 // Add this run
+                var fontRun = runEnum.Current;
                 AddFontRun(styleRun, start + fontRun.Start, fontRun.Length, direction, style, fontRun.Typeface, typeface);
             }
         }

Haven't tried if it helps ...

janusw commented 3 years ago

Something like this should do it:

[..]

Haven't tried if it helps ...

AFAICT this does not help, either. I built a nupkg of RichTextKit with that change and used it with Mapsui, but I still get the same error message.

Maybe the usage of iterator blocks in FontFallback.GetFontRuns is the problem (in connection with the limited generics support on iOS)?

janusw commented 3 years ago

Maybe it would be useful to add a Xamarin.iOS sample project to the RichTextKit solution, in order to reproduce and debug this problem more easily?

janusw commented 3 years ago

As documented in the Mapsui issue (Mapsui/Mapsui#1093), there are similar problems on MacOS as well:

Error: Unexpected error in skia renderer, System.MissingMethodException: Method not found: void SkiaSharp.SKFont.GetGlyphs(System.ReadOnlySpan`1<int>,System.Span`1<uint16>)
  at Topten.RichTextKit.TextBlock.AddDirectionalRun (Topten.RichTextKit.StyleRun styleRun, System.Int32 start, System.Int32 length, Topten.RichTextKit.TextDirection direction, Topten.RichTextKit.IStyle style) [0x00067] in <7a0d8e75b4754a86a12c1b7c67b845cc>:0 
  at Topten.RichTextKit.TextBlock.BuildFontRuns () [0x0032c] in <7a0d8e75b4754a86a12c1b7c67b845cc>:0 
  at Topten.RichTextKit.TextBlock.Layout () [0x0010a] in <7a0d8e75b4754a86a12c1b7c67b845cc>:0 

The error message is quite different here, but the place where the failure occurs is basically the same (FontFallback.GetFontRuns). I assume they're somehow related.

Does anyone have an idea what could cause this kind of error?

slarti-zak commented 3 years ago

We are also facing this Problem in an Xamarin.Ios Build for

SIGABRT: Method not found: void SkiaSharp.SKFont.GetGlyphs(System.ReadOnlySpan`1<int>,System.Span`1<uint16>)
TextBlock.AddDirectionalRun (Topten.RichTextKit.StyleRun styleRun, System.Int32 start, System.Int32 length, Topten.RichTextKit.TextDirection direction, Topten.RichTextKit.IStyle style)
TextBlock.BuildFontRuns ()
TextBlock.Layout ()

In Versions:

The error exists even if linker is set to none.

The Problem did not occur on older Xamarin Versions with the same library versions. Maybe some Span related errors on the Xamarin side?

janusw commented 3 years ago

We are also facing this Problem in an Xamarin.Ios Build for

Good to hear that others get the same error. Do you possibly have a simple reproducer?

pauldendulk commented 3 years ago

Any plans on how to proceed on this issue?

toptensoftware commented 3 years ago

As mentioned above, I'm not setup for iOS development and busy with other work at the moment. If someone in the community wants to look into it and submit a PR I'll happily merge it.

janusw commented 3 years ago

After some more digging, I found https://github.com/xamarin/xamarin-macios/issues/4218, which refers to https://github.com/xamarin/xamarin-macios/issues/3949, where the suggested fix is to migrate to a PackageReference project. Tried this with Mapsui.Samples.Forms.iOS. Didn't help :/

janusw commented 3 years ago

Also found: https://stackoverflow.com/questions/12837517/system-executionengineexception-attempting-to-jit-compile-method-only-in-debug/12840169#12840169

This suggests as a workaround to use a reference type instead of a value type, so I tried converting Topten.RichTextKit.FontFallback.Run from a struct to a class:

--------------- Topten.RichTextKit/FontFallback/FontFallback.cs ---------------
index 6210df3..d91f9ce 100644
@@ -30,7 +30,7 @@ namespace Topten.RichTextKit
         /// <summary>
         /// Specified details about a font fallback run
         /// </summary>
-        public struct Run
+        public class Run
         {
             /// <summary>
             /// The starting code point index of this run

But, again, this does not seem to help.

Further tricks for hinting the compiler ("pre-seeding") are played e.g. in https://github.com/SIDOVSKY/EBind/blob/main/EBind/Platform/AotCompilerHints.ios.cs, which links to the above StackOverflow question. See also the comments in https://github.com/SIDOVSKY/EBind#aot-compilation-. I don't really understand the details of what's being done there, but maybe someone else can figure out a fix for our case based on this?

But since my struct-to-class workaround attempt also does not work, maybe our problem still has a different origin? Apparently there can be various reasons why the AOT compiler might fail to generate code ...

janusw commented 3 years ago

After all the failed workarounds, I have high hopes that this might actually fix the problem: https://github.com/xamarin/xamarin-macios/pull/10928

Some of the issues referenced there sound very similar to the diagnostics here.

toptensoftware commented 3 years ago

I posted a message to Matt Leibowitz (the lead dev on SkiaSharp) about this in case he had any ideas, his response:

Looks like it could be a bug with something in the iOS system. Could you get the folks to report an issue on the xamarin/xamarin-macios repo with a repo if possible. Then the team can have something to track. You can also mark as regression if it was working before.

Source

juanpgarces commented 3 years ago

If anyone is interested. I was getting the same exception (not for JIT compilation) but when rendering TextBlocks into a SkiaSharp Canvas.

Method not found: void SkiaSharp.SKFont.GetGlyphs(System.ReadOnlySpan`1<int>,System.Span`1<uint16>)
TextBlock.AddDirectionalRun (Topten.RichTextKit.StyleRun styleRun, System.Int32 start, System.Int32 length, Topten.RichTextKit.TextDirection direction, Topten.RichTextKit.IStyle style)
TextBlock.BuildFontRuns ()
TextBlock.Layout ()

After some investigation I found out that this only happens with the Xamarin.iOS SDK version 14.14.2.5 not on 14.10.0.4 or below. So that's what I used as my workaround.

janusw commented 3 years ago

After some investigation I found out that this only happens with the Xamarin.iOS SDK version 14.14.2.5 not on 14.10.0.4 or below.

Yes, this is definitely a regression (see my comments above). Thanks for figuring out a 'good' version.

So that's what I used as my workaround.

How did you do the downgrade? I was not able to find a proper way to downgrade VS for Mac.

juanpgarces commented 3 years ago

@janusw, I have not tested this but I think the only way is to uninstall and re-install an older version of VS. For now I was able to just modify the DevOps pipeline in the app building to select the 'good' SDK (I am not currently debugging my app, just needed to fix the buggy deployment).

janusw commented 3 years ago

@janusw, I have not tested this but I think the only way is to uninstall and re-install an older version of VS.

Yes, but I don't know where to download an older version. The installer that one gets from the official VS download site will only install the latest version 8.9. The only download of an 'older' VS version that I found is for VS 2017, which is very old.

toptensoftware commented 3 years ago

Pleased to hear this isn't an issue with RichTextKit. Has someone reported this to the Xamarin iOS team?

(I'd do it myself except I don't have a repo project as suggested by Matt above).

janusw commented 3 years ago

After all the failed workarounds, I have high hopes that this might actually fix the problem: xamarin/xamarin-macios#10928

Today I installed VS for Mac 8.10 Preview (build 967) with Xamarin.iOS 14.17.0.247 and Xamarin.Mac 7.11.0.247, which is supposed to include the fix mentioned above, but unfortunately it looks like my high hopes are being disappointed ...

Regarding iOS, this version seems much worse than before. I'm not able to build any iOS app due to strange errors (System.EntryPointNotFoundException: xamarin_release_managed_ref). So I can not check if the JIT exceptions are gone.

Regarding MacOS, building seems to work well, but I still see the same errors as before (System.MissingMethodException: Method not found: void SkiaSharp.SKFont.GetGlyphs).

😭

janusw commented 3 years ago

Today I installed VS for Mac 8.10 Preview (build 967) with Xamarin.iOS 14.17.0.247 and Xamarin.Mac 7.11.0.247, which is supposed to include the fix mentioned above, but unfortunately it looks like my high hopes are being disappointed ...

Regarding iOS, this version seems much worse than before. I'm not able to build any iOS app due to strange errors (System.EntryPointNotFoundException: xamarin_release_managed_ref).

This might be https://github.com/xamarin/xamarin-macios/issues/11151

janusw commented 3 years ago

Pleased to hear this isn't an issue with RichTextKit. Has someone reported this to the Xamarin iOS team?

I just did: https://github.com/xamarin/xamarin-macios/issues/11219 (should have done this much earlier, but better late than never!)

janusw commented 3 years ago

After all the bad news, finally some good news: I actually managed to find a viable workaround, namely downgrading Xamarin.iOS only (without downgrading VS). Initially I was not sure if this is viable at all, but once you find the download link to the relevant package version, it's actually pretty simple ...

So, I just downloaded https://dl.xamarin.com/MonoTouch/Mac/xamarin.ios-14.10.0.4.pkg (found via homebrew, see also https://github.com/xamarin/xamarin-macios/issues/11218) and installed it on Mac OS. After that, VS for Mac corrently detects the changed version and automatically uses it without any further setup needed.

janusw commented 3 years ago

As documented in the Mapsui issue (Mapsui/Mapsui#1093), there are similar problems on MacOS as well:

Error: Unexpected error in skia renderer, System.MissingMethodException: Method not found: void SkiaSharp.SKFont.GetGlyphs(System.ReadOnlySpan`1<int>,System.Span`1<uint16>)
  at Topten.RichTextKit.TextBlock.AddDirectionalRun (Topten.RichTextKit.StyleRun styleRun, System.Int32 start, System.Int32 length, Topten.RichTextKit.TextDirection direction, Topten.RichTextKit.IStyle style) [0x00067] in <7a0d8e75b4754a86a12c1b7c67b845cc>:0 
  at Topten.RichTextKit.TextBlock.BuildFontRuns () [0x0032c] in <7a0d8e75b4754a86a12c1b7c67b845cc>:0 
  at Topten.RichTextKit.TextBlock.Layout () [0x0010a] in <7a0d8e75b4754a86a12c1b7c67b845cc>:0 

The error message is quite different here, but the place where the failure occurs is basically the same (FontFallback.GetFontRuns). I assume they're somehow related.

For the MacOS problem, in contrast to iOS, I was not able to fix it by downgrading Xamarin.Mac, unfortunately ...

janusw commented 3 years ago

For the MacOS problem, in contrast to iOS, I was not able to fix it by downgrading Xamarin.Mac, unfortunately ...

To be a bit more precise here: I went as far back as Xamarin.Mac version 6.22.1.16, and that behaves in the same way as the current Xamarin.Mac 7.10.0.5.

I was not able to check earlier versions of Xamarin.Mac (such as 6.20.x and before), because they don't seem to work with the current VS4Mac version 8.9.8. I get the following error during nuget restore:

error MSB4226: The imported project "/Library/Frameworks/Mono.framework/Versions/6.12.0/lib/mono/xbuild/Xamarin/Mac/Xamarin.Mac.CSharp.targets" was not found.
Also, tried to find "Xamarin/Mac/Xamarin.Mac.CSharp.targets" in the fallback search path(s) for $(MSBuildExtensionsPath) - "/Library/Frameworks/Mono.framework/External/xbuild/" and "/Applications/Visual Studio.app/Contents/Resources/lib/monodevelop/AddIns/docker/MonoDevelop.Docker/MSbuild" .
These search paths are defined in "/Users/janus/Library/Caches/VisualStudio/8.0/MSBuild/12174_1/MonoDevelop.MSBuildBuilder.exe.config".
Confirm that the path in the <Import> declaration is correct, and that the file exists on disk in one of the search paths.
wouterst79 commented 3 years ago

I seem to have run into a similar issue. I'm using SkiaSharp.Harfbuzz in a different package (SkiaSharp.TextBlocks) which I reference in a second package, which is referenced by my iOS app.

Since upgrading to the lastest Xamarin.iOS, I get

Method not found: void SkiaSharp.SKTextBlobBuilder.AddPositionedRun(System.ReadOnlySpan1,SkiaSharp.SKFont,System.ReadOnlySpan1<SkiaSharp.SKPoint>)

when trying to render any text to a SkiaSharp surface. Adding Skia packages (and even referencing the dlls as referenced dlls instead of as nuget packages) doesn't solve the problem. (note my project is configured with link nothing).

When I add code to make this call directly in my .iOS project, it looks like there's a resolution issue with System.Memory:

image

which looks similar to https://github.com/xamarin/xamarin-macios/issues/5687

Adding System.Memory with IncludeAssets="None" (with, or without the above call in my iOS project) solves my issue:

image

    <PackageReference Include="System.Memory" IncludeAssets="None">
      <Version>4.5.4</Version>
    </PackageReference>

System.ExecutionEngineException: Attempting to JIT compile method 'void SkiaSharp.TextBlocks.GlyphSpan:g__paintspan|17_0 (int,int,int,System.ReadOnlySpan`1,SkiaSharp.TextBlocks.GlyphSpan/<>c__DisplayClass17_0&)' while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.

janusw commented 3 years ago

Adding System.Memory with IncludeAssets="None" (with, or without the above call in my iOS project) solves my issue:

    <PackageReference Include="System.Memory" IncludeAssets="None">
      <Version>4.5.4</Version>
    </PackageReference>

Amazing! I can confirm that this indeed fixes the Mapsui/RichTextKit problem as well, both on iOS and Mac. So we finally have a real workaround that does not require downgrading Xamarin.iOS any more (which became kind of annoying recently, because the old Xamarin.iOS does not work with the latest XCode any more).

@wouterst79 Your're my hero of the day! 😄 🎉 👍

talmurshidi commented 3 years ago

Adding System.Memory with IncludeAssets="None" (with, or without the above call in my iOS project) solves my issue:

image


    <PackageReference Include="System.Memory" IncludeAssets="None">
      <Version>4.5.4</Version>
    </PackageReference>

Thank you. This is solved my problem with SkiaSharp

vchelaru commented 2 years ago

I have found that explicitly referencing System.Memory 4.5.0 nuget package in the iOS project also solves the problem. More details here for anyone who is interested:

https://stackoverflow.com/questions/70570062/why-does-adding-system-memory-reference-break-my-ios-project