Skip to content

Commit

Permalink
emit call to params collection (readonlyspan<T>)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubmisek committed Feb 21, 2025
1 parent 88766bb commit 86a266e
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 102 deletions.
26 changes: 19 additions & 7 deletions src/Peachpie.CodeAnalysis/CodeGen/CodeGenerator.Emit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -872,8 +872,8 @@ public TypeSymbol Emit_PhpArray_Empty()
.Expect(CoreTypes.PhpArray);
}

public void Emit_NewArray(TypeSymbol elementType, ImmutableArray<BoundArgument> values) => Emit_NewArray(elementType, values, a => Emit(a.Value));
public void Emit_NewArray(TypeSymbol elementType, ImmutableArray<BoundExpression> values) => Emit_NewArray(elementType, values, a => Emit(a));
public TypeSymbol Emit_NewArray(TypeSymbol elementType, ImmutableArray<BoundArgument> values) => Emit_NewArray(elementType, values, a => Emit(a.Value));
public TypeSymbol Emit_NewArray(TypeSymbol elementType, ImmutableArray<BoundExpression> values) => Emit_NewArray(elementType, values, a => Emit(a));

public TypeSymbol Emit_NewArray(TypeSymbol elementType, int length)
{
Expand Down Expand Up @@ -1857,12 +1857,17 @@ internal TypeSymbol EmitCall(ILOpCode code, MethodSymbol method, BoundExpression
continue;
}

if (p.IsParams)
if (p.IsParams) // params T[], or params ReadOnlySpan<T>
{
Debug.Assert(parameters.Length == param_index + 1, $"params should be the last parameter, at {method.ContainingType.PhpName()}::{method.Name}()."); // p is last one
Debug.Assert(p.Type.IsArray(), $"params should be of type array, at {method.ContainingType.PhpName()}::{method.Name}().");
Debug.Assert(p.Type.IsArray() || p.Type.IsReadOnlySpan(null), $"params should be of type array or ReadOnlySpan, at {method.ContainingType.PhpName()}::{method.Name}().");

TypeSymbol result_type; // type of array emitted on stack

var p_element = ((ArrayTypeSymbol)p.Type).ElementType;
var p_element =
p.Type is ArrayTypeSymbol arrType ? arrType.ElementType :
p.Type is ConstructedNamedTypeSymbol spanType ? spanType.TypeArguments[0] :
throw ExceptionUtilities.UnexpectedValue(p.Type);

if (arg_params_index >= 0)
{
Expand Down Expand Up @@ -1893,7 +1898,9 @@ internal TypeSymbol EmitCall(ILOpCode code, MethodSymbol method, BoundExpression
_il.EmitOpCode(ILOpCode.Newarr);
EmitSymbolToken(p_element, null);

var params_loc = GetTemporaryLocal(p.Type, false);
result_type = ArrayTypeSymbol.CreateSZArray(this.DeclaringCompilation.SourceAssembly, p_element);

var params_loc = GetTemporaryLocal(result_type, false);
_il.EmitLocalStore(params_loc);

// { arg_i, ..., arg_(n-1) }
Expand Down Expand Up @@ -1930,13 +1937,18 @@ internal TypeSymbol EmitCall(ILOpCode code, MethodSymbol method, BoundExpression
}
else
{
// TODO: 1 argument can be marshaled to ReadOnlySpan<T> without allocation

// easy case,
// wrap remaining arguments to array
var values = (arg_index < arguments.Length) ? arguments.Skip(arg_index).AsImmutable() : ImmutableArray<BoundArgument>.Empty;
arg_index += values.Length;
Emit_NewArray(p_element, values);
result_type = Emit_NewArray(p_element, values);
}

// eventually convert to ReadOnlySpan<T>
EmitConvert(result_type, 0, p.Type);

break; // p is last one
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,11 +508,15 @@ protected override T VisitRoutineCall(BoundRoutineCall x)

if (i == ps.Length - 1 && p.IsParams) // vararg
{
// handle [Params]
// - resolve the SZArray element type
// handle params:
// - resolve the params element type
// - check the all the arguments
Debug.Assert(p.Type.IsSZArray(), "[Params] parameter expected to be of type Array.");
var elementType = (p.Type as ArrayTypeSymbol)?.ElementType;

var elementType =
p.IsParamsArray && p.Type != null ? ((ArrayTypeSymbol)p.Type).ElementType : // params T[]
p.IsParamsCollection && p.Type != null ? ((ConstructedNamedTypeSymbol)p.Type).TypeArguments[0] : // params ReadOnlySpan< T >
null;

if (elementType != null)
{
int varargIndex = 0;
Expand Down
6 changes: 2 additions & 4 deletions src/Peachpie.CodeAnalysis/Symbols/PE/PEFieldSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -473,13 +473,11 @@ public override ImmutableArray<AttributeData> GetAttributes()
if (FilterOutDecimalConstantAttribute())
{
// filter out DecimalConstantAttribute
CustomAttributeHandle ignore1;
CustomAttributeHandle ignore2;
var attributes = containingPEModuleSymbol.GetCustomAttributesForToken(
_handle,
out ignore1,
out _,
AttributeDescription.DecimalConstantAttribute,
out ignore2,
out _,
default(AttributeDescription));

ImmutableInterlocked.InterlockedInitialize(ref _lazyCustomAttributes, attributes);
Expand Down
59 changes: 40 additions & 19 deletions src/Peachpie.CodeAnalysis/Symbols/PE/PEModuleSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,10 @@ internal void LoadCustomAttributesFilterExtensions(EntityHandle token,
internal ImmutableArray<AttributeData> GetCustomAttributesFilterExtensions(EntityHandle token, out bool foundExtension)
{
CustomAttributeHandle extensionAttribute;
CustomAttributeHandle ignore;
var result = GetCustomAttributesForToken(token,
out extensionAttribute,
AttributeDescription.CaseSensitiveExtensionAttribute,
out ignore,
default(AttributeDescription));
out extensionAttribute, AttributeDescription.CaseSensitiveExtensionAttribute,
out _, default(AttributeDescription)
);

foundExtension = !extensionAttribute.IsNil;
return result;
Expand All @@ -239,10 +237,14 @@ internal ImmutableArray<AttributeData> GetCustomAttributesForToken(EntityHandle
out CustomAttributeHandle filteredOutAttribute1,
AttributeDescription filterOut1,
out CustomAttributeHandle filteredOutAttribute2,
AttributeDescription filterOut2)
AttributeDescription filterOut2,
out CustomAttributeHandle filteredOutAttribute3,
AttributeDescription filterOut3)
{
filteredOutAttribute1 = default(CustomAttributeHandle);
filteredOutAttribute2 = default(CustomAttributeHandle);
filteredOutAttribute1 = default;
filteredOutAttribute2 = default;
filteredOutAttribute3 = default;

ArrayBuilder<AttributeData> customAttributesBuilder = null;

try
Expand All @@ -267,6 +269,15 @@ internal ImmutableArray<AttributeData> GetCustomAttributesForToken(EntityHandle
continue;
}

if (filterOut3.Signatures != null &&
Module.GetTargetAttributeSignatureIndex(customAttributeHandle, filterOut3) != -1)
{
// It is important to capture the last application of the attribute that we run into,
// it makes a difference for default and constant values.
filteredOutAttribute3 = customAttributeHandle;
continue;
}

if (customAttributesBuilder == null)
{
customAttributesBuilder = ArrayBuilder<AttributeData>.GetInstance();
Expand All @@ -289,13 +300,11 @@ internal ImmutableArray<AttributeData> GetCustomAttributesForToken(EntityHandle
internal ImmutableArray<AttributeData> GetCustomAttributesForToken(EntityHandle token)
{
// Do not filter anything and therefore ignore the out results
CustomAttributeHandle ignore1;
CustomAttributeHandle ignore2;
return GetCustomAttributesForToken(token,
out ignore1,
default(AttributeDescription),
out ignore2,
default(AttributeDescription));
out _, default(AttributeDescription),
out _, default(AttributeDescription),
out _, default(AttributeDescription)
);
}

/// <summary>
Expand All @@ -307,13 +316,25 @@ internal ImmutableArray<AttributeData> GetCustomAttributesForToken(EntityHandle
internal ImmutableArray<AttributeData> GetCustomAttributesForToken(EntityHandle token,
out CustomAttributeHandle paramArrayAttribute)
{
CustomAttributeHandle ignore;
return GetCustomAttributesForToken(
token,
out paramArrayAttribute,
AttributeDescription.ParamArrayAttribute,
out ignore,
default(AttributeDescription));
out paramArrayAttribute, AttributeDescription.ParamArrayAttribute,
out _, default,
out _, default
);
}

internal ImmutableArray<AttributeData> GetCustomAttributesForToken(EntityHandle token,
out CustomAttributeHandle filteredOutAttribute1,
AttributeDescription filterOut1,
out CustomAttributeHandle filteredOutAttribute2,
AttributeDescription filterOut2)
{
return GetCustomAttributesForToken(token,
out filteredOutAttribute1, filterOut1,
out filteredOutAttribute2, filterOut2,
out _, default
);
}


Expand Down
Loading

0 comments on commit 86a266e

Please sign in to comment.