sq / JSIL

CIL to Javascript Compiler
http://jsil.org/
Other
1.73k stars 240 forks source link

Unconstrained generic parameters generate inefficient struct copies #107

Open kg opened 12 years ago

kg commented 12 years ago

As described in issue #105, if a function or class has a generic parameter that is constrained, you can pass a struct as the parameter. This will cause behavior to diverge from C# because the body of the generic method(s) is not generated with struct copies in the appropriate place(s) because the generic parameter is not a struct according to TypeUtil.

At present, if the parameter is constrained with ': struct', copies will be generated, but a complete solution needs to ensure that it works at runtime if you pass a struct as an unconstrained generic parameter.

This probably means that for generic methods, and all methods within a generic class, function bodies should be generated as if all the generic parameters are structs, and then instead of .MemberwiseClone(), a special .CloneForParameter(T) is inserted instead. Then as an optimization, some codegen can be done on the fly in $Of$NoInitialize to remove the clone calls if a parameter is known not to be a struct.

kg commented 12 years ago

6cf8588036be0b49813df5e1ee610eab958a0f1d fixes this, with two caveats:

The optimizer is too clever so it will (safely) eliminate some copies, which has the side effect of causing object.ReferenceEquals to return true when it would return false in the .NET runtime (because casting a struct to an interface pointer doesn't box it or cause a copy, I think). This means that StructGenericParameter.cs does not pass.

The JSIL.CloneParameter calls probably have a tangible performance impact in loops and they could also introduce failures in unusual code paths. The right fix here is probably to dynamically convert the CloneParameter calls into MemberwiseClone calls (or remove them) based on the actual type of the parameter (in .Of() for generic types, and when binding generic parameters for generic methods).