Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Remove reflections: Misc and Summary #1137

Merged
merged 25 commits into from
Oct 11, 2023
Merged

Conversation

karakasa
Copy link
Contributor

@karakasa karakasa commented Jul 28, 2023

try to fix #957

I found some upstream dependencies don't support AOT therefore NPOI cannot be completed AOTed. The library will get some performance improvement from removing reflections though.

@tonyqus What are your thoughts on this? These are the issues I've witnessed.

  1. Following features relies on reflection.
Feature Description Mitigation
XWPFTableRow.CloneRow Relies on deepcopying CT_* objects, hence NPOI.Util.ObjectExtensions.Copy<T>(). Needs testing. Probably keep metadata by rd.xml or source generators for deepcopy. Perhaps it will just work.
XML (de)serialization, as well as NPOI.OpenXml4Net.Util.XmlHelper XMLSerializer and enum names relies on reflections obviously. It looks like AOT compiler handles well. Thorough tests are needed.
  1. Following methods are converted from dynamic dispatch to static lookup. These may prevent some later-injected custom encryptor, record types, etc. I think it's fine. Maybe it's better to use source generators. They will lead to a slight increase of binary size.
Class Method
NPOI.DDF.DefaultEscherRecordFactory Entire Class #1159
NPOI.HSSF.Record.RecordFactory Entire Class #1159
NPOI.POIFS.Crypt.EncryptionInfo GetBuilder #1160
NPOI.XSSF.UserModel.XSSFFactory CreateDocumentPart #1157
NPOI.XSSF.UserModel.XWPFFactory CreateDocumentPart #1157
  1. The following classes / methods, using reflection, are useless.
Target Reason
NPOI.HSSF.UserModel.OperationEvaluatorFactory Wrong use of reflection. Maybe incorrectly ported from Java. #1161
NPOI.POIFS.NIO.FileBackedDataSource.unmap Entire method contains no code. Seems Java-specific. #1161
NPOI.SS.Formula.Eval.Forked.ForkedEvaluator.CreateEvaluationWorkbook Don't work at all because of typo. 'NPOI.XSSF.UserMode', forgetting the last 'l' #1161
NPOI.OpenXml4Net.Util.ZipSecureFile.AddThreshold The code is used to deal with ZIP bombs but Java-specific. We should come up with ways in CLR. #1161
NPOI.Util.POILogFactory.GetLogger I doubt if the following line would work, because _loggerClassName is Name of the type but Type.GetType requires FullName. It all ends up using the null logger. #1162
  1. Others
Feature Description
NPOI.SS.Formula.OperationEvaluatorFactory.Add Reflection is used to ensure singleton-pattern. Can be removed if we're sure. this
Ptg, OperandPtg IClonable is removed from Ptg because not used and requires deepcopy, except for OperandPtg. After inspection, all derived classes of OperandPtg contain only value-type members so MemberwiseClone is enough. (besides, Ptg.IClonable.Clone() throws NotImplementedException so I doubt anyone is using it.) this
HSSFColor Slightly refactored #1158
(T[])ArrayList.ToArray(typeof(T)) Rewritten as extension method this
  1. Dependencies AOT compiler complains about. Not necessarily non-AOTable. It's possible to remove some of them.
Library State Comments
System.Configuration.ConfigurationManager Produce trim warnings. Solely used in NPOI.Util.SystemOutLogger & NPOI.Util.POILogFactory Not dealt with
Enums.NET Removed Relies on Reflection. Converted into static dispatch & built-in methods #1156
  1. Probably need to add net8.0 as another target since .NET 6 doesn't fully support AOT and AOT analyzers. But the Github CI/action don't support .NET 8.

  2. Generally there's no breaking change, except Remove reflections in POI Logger #1162

@karakasa karakasa changed the title Remove reflection dependencies Remove reflection dependencies and prepare NPOI for AOT Jul 28, 2023
@karakasa

This comment was marked as outdated.

@karakasa
Copy link
Contributor Author

karakasa commented Jul 29, 2023

btw comparsion of loading XSSF file. The performance is better for smaller files. And it looks like no obvious performance gains from removing Reflections alone.

File Version Time (s)
Large (30M) PR w/ AOT 35.687
Large (30M) PR 36.676
Large (30M) Nuget 36.086
Small (600K) PR w/ AOT 0.332
Small (600K) PR 0.747
Small (600K) Nuget 0.765

Nuget: the nuget version.

@karakasa

This comment was marked as outdated.

@@ -22,7 +22,7 @@ public T Parse(Stream stream)
}
public T Create()
{
return (T)Activator.CreateInstance(typeof(T));
return new T();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Although new T() uses Activator.CreateInstance internally, this semantic is slightly different for AOT analyzers I believe.

@karakasa karakasa changed the title Remove reflection dependencies and prepare NPOI for AOT Remove reflections: Misc and Summary Aug 12, 2023
@karakasa karakasa marked this pull request as ready for review August 12, 2023 06:13
@@ -37,7 +37,8 @@ public OperandPtg Copy()
{
try
{
return (OperandPtg)Clone();
// REMOVE-REFLECTION: After careful inspection, MemberwiseClone() should be enough for all built-in OpreandPtgs.
return (OperandPtg)MemberwiseClone();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

All derived classes of OperandPtg holds only value types (some unused members are not, but that's fine).

// private virtual object Clone()
//{
//return this.Copy();
//}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not used elsewhere. And IClonable.Clone throws NotImplementedException, see below.

@tonyqus tonyqus changed the base branch from master to aot August 13, 2023 14:18
@tonyqus
Copy link
Member

tonyqus commented Aug 13, 2023

I created a new branch called AOT. AOT branch will become a RC version for NPOI vNext. I'd like to compare the performance between AOT and non-AOT release.

@tonyqus tonyqus added this to the NPOI 2.7.1 milestone Aug 13, 2023
@tonyqus tonyqus added the aot label Aug 17, 2023
@tonyqus tonyqus merged commit 96836a6 into nissl-lab:aot Oct 11, 2023
2 checks passed
@karakasa karakasa deleted the remove_reflection branch October 12, 2023 03:34
@tonyqus tonyqus modified the milestones: NPOI 2.7.1, NPOI AOT May 9, 2024
@josephmoresena
Copy link

I created a new branch called AOT. AOT branch will become a RC version for NPOI vNext. I'd like to compare the performance between AOT and non-AOT release.

Thanks, I'm here if you want some help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support NativeAOT
3 participants