Skip to content

Commit

Permalink
[generator] Cache static final field values.
Browse files Browse the repository at this point in the history
  • Loading branch information
jpobst committed Aug 27, 2024
1 parent 51b784a commit 8417edd
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 10 deletions.
13 changes: 9 additions & 4 deletions src/Xamarin.SourceWriter/Models/TypeReferenceWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,17 @@ public TypeReferenceWriter (string ns, string name)

public virtual void WriteTypeReference (CodeWriter writer)
{
if (Namespace.HasValue ())
writer.Write ($"{Namespace}.{Name}{NullableOperator} ");
else
writer.Write ($"{Name}{NullableOperator} ");
writer.Write ($"{ToString ()} ");
}

string NullableOperator => Nullable ? "?" : string.Empty;

public override string ToString ()
{
if (Namespace.HasValue ())
return $"{Namespace}.{Name}{NullableOperator}";

return $"{Name}{NullableOperator}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public class Field : ApiVersionsSupport.IApiAvailability, ISourceLineInfo

public bool NeedsProperty => !IsStatic || !IsFinal || string.IsNullOrEmpty (Value) || Symbol.IsArray || !primitive_types.Contains (Symbol.JavaName);

public string CachedMemberName => $"_{Name}_cache";

public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context)
{
Symbol = opt.SymbolTable.Lookup (TypeName, type_params);
Expand Down
35 changes: 29 additions & 6 deletions tools/generator/SourceWriters/BoundFieldAsProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class BoundFieldAsProperty : PropertyWriter
{
readonly Field field;
readonly CodeGenerationOptions opt;
readonly FieldWriter? cached_field;

public BoundFieldAsProperty (GenBase type, Field field, CodeGenerationOptions opt)
{
Expand Down Expand Up @@ -59,10 +60,22 @@ public BoundFieldAsProperty (GenBase type, Field field, CodeGenerationOptions op

if (!field.IsConst)
HasSet = true;

// This is considerably harder to support if we don't have NRT, due to the
// differences in handling nullable value and reference types.
if (field.IsConst && opt.SupportNullableReferenceTypes)
cached_field = new FieldWriter {
Name = field.CachedMemberName,
Type = new TypeReferenceWriter (fieldType.TrimEnd ('?')) { Nullable = true },
IsStatic = true,
UseExplicitPrivateKeyword = type is InterfaceGen,
};
}

public override void Write (CodeWriter writer)
{
cached_field?.Write (writer);

// This is just a temporary hack to write the [GeneratedEnum] attribute before the // Metadata.xml
// comment so that we are 100% equal to pre-refactor.
var generated_attr = Attributes.OfType<GeneratedEnumAttr> ().FirstOrDefault ();
Expand All @@ -82,6 +95,13 @@ public override void WriteAttributes (CodeWriter writer)

protected override void WriteGetterBody (CodeWriter writer)
{
var cached_field_type = cached_field is not null ? new TypeReferenceWriter (cached_field.Type.Namespace, cached_field.Type.Name) : null;

if (cached_field is not null) {
writer.WriteLine ($"if ({field.CachedMemberName} != null) return ({cached_field_type}){field.CachedMemberName};");
writer.WriteLine ();
}

writer.WriteLine ($"const string __id = \"{field.JavaName}.{field.Symbol.JniName}\";");
writer.WriteLine ();

Expand All @@ -93,24 +113,27 @@ protected override void WriteGetterBody (CodeWriter writer)

writer.WriteLine ($"var __v = {field.Symbol.ReturnCast}_members.{indirect}.{invoke} (__id{(field.IsStatic ? "" : ", this")});");

var cache_setter = cached_field is not null ? $"({PropertyType})({field.CachedMemberName} = " : "";
var cache_setter_end = cached_field is not null ? ")" : "";

if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) {
if (field.Symbol.NativeType == field.Symbol.FullName) {
writer.WriteLine ("return __v;");
writer.WriteLine ($"return {cache_setter}__v{cache_setter_end};");
return;
}
writer.Write ("return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<");
writer.Write ($"return {cache_setter}global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<");
PropertyType.WriteTypeReference (writer);
writer.Write (">(ref __v, JniObjectReferenceOptions.Copy)");
writer.WriteLine (";");
writer.WriteLine ($"{cache_setter_end};");
return;
}

if (field.Symbol.IsArray) {
writer.WriteLine ($"return global::Android.Runtime.JavaArray<{opt.GetOutputName (field.Symbol.ElementType)}>.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef);");
writer.WriteLine ($"return {cache_setter}global::Android.Runtime.JavaArray<{opt.GetOutputName (field.Symbol.ElementType)}>.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef){cache_setter_end};");
} else if (field.Symbol.NativeType != field.Symbol.FullName) {
writer.WriteLine ($"return {field.Symbol.ReturnCast}{(field.Symbol.FromNative (opt, invokeType != "Object" ? "__v" : "__v.Handle", true) + opt.GetNullForgiveness (field))};");
writer.WriteLine ($"return {cache_setter}{field.Symbol.ReturnCast}{(field.Symbol.FromNative (opt, invokeType != "Object" ? "__v" : "__v.Handle", true) + opt.GetNullForgiveness (field))}{cache_setter_end};");
} else {
writer.WriteLine ("return __v;");
writer.WriteLine ($"return {cache_setter}__v{cache_setter_end};");
}
}

Expand Down
1 change: 1 addition & 0 deletions tools/generator/generator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>$(DotNetTargetFramework)</TargetFramework>
<OutputType>Exe</OutputType>
<DefineConstants>$(DefineConstants);GENERATOR;HAVE_CECIL;JCW_ONLY_TYPE_NAMES</DefineConstants>
<Nullable>annotations</Nullable>
</PropertyGroup>

<Import Project="..\..\TargetFrameworkDependentValues.props" />
Expand Down

0 comments on commit 8417edd

Please sign in to comment.