Skip to content

Commit

Permalink
cancel more unnecessary constructor call (#1260)
Browse files Browse the repository at this point in the history
* cancel more unnecessary constructor call

* delete ProcessFields

* update GAS

* Merge branch 'master' into pr/1260

* master:
  remove artifact opcodes line number (#1261)

# Conflicts:
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Array.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_ClassInit.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Foreach.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Initializer.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Instance.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Linq.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_MemberAccess.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_PostfixUnary.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_PropertyMethod.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Record.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Recursion.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Tuple.cs
#	tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Types.cs
#	tests/Neo.SmartContract.Framework.UnitTests/TestingArtifacts/Contract_Storage.cs
#	tests/Neo.SmartContract.Framework.UnitTests/TestingArtifacts/Contract_Stored.cs

---------

Co-authored-by: Jim8y <[email protected]>
  • Loading branch information
Hecate2 and Jim8y authored Dec 12, 2024
1 parent d8a043b commit 028445c
Show file tree
Hide file tree
Showing 35 changed files with 162 additions and 257 deletions.
19 changes: 2 additions & 17 deletions src/Neo.Compiler.CSharp/MethodConvert/ConstructorConvert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,6 @@ namespace Neo.Compiler;

internal partial class MethodConvert
{
private void ProcessFields(SemanticModel model)
{
_initSlot = true;
IFieldSymbol[] fields = Symbol.ContainingType.GetFields();
for (int i = 0; i < fields.Length; i++)
{
ProcessFieldInitializer(model, fields[i], () =>
{
AddInstruction(OpCode.LDARG0);
Push(i);
}, () =>
{
AddInstruction(OpCode.SETITEM);
});
}
}

private void ProcessConstructorInitializer(SemanticModel model)
{
INamedTypeSymbol type = Symbol.ContainingType;
Expand All @@ -46,6 +29,8 @@ private void ProcessConstructorInitializer(SemanticModel model)
ConstructorInitializerSyntax? initializer = ((ConstructorDeclarationSyntax?)SyntaxNode)?.Initializer;
if (initializer is null)
{
if (baseType.ContainingNamespace.ToString() == "Neo.SmartContract.Framework" && baseType.Name == "SmartContract")
return;
IMethodSymbol baseConstructor = baseType.InstanceConstructors.First(p => p.Parameters.Length == 0);
if (baseType.DeclaringSyntaxReferences.IsEmpty && baseConstructor.GetAttributes().All(p => p.AttributeClass!.ContainingAssembly.Name != "Neo.SmartContract.Framework"))
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,12 @@ private void ConvertObjectCreationExpression(SemanticModel model, BaseObjectCrea
// an optimization to avoid PACK + billions of SETITEM
if (TryOptimizedObjectCreation(model, expression, type, constructor))
return;
CreateObject(model, type, null);
CreateObject(model, type);
}
CallInstanceMethod(model, constructor, needCreateObject, arguments);
if (!constructor.DeclaringSyntaxReferences.IsEmpty)
CallInstanceMethod(model, constructor, needCreateObject, arguments);
if (expression.Initializer is not null)
{
ConvertObjectCreationExpressionInitializer(model, expression.Initializer);
}
}

/// <summary>
Expand Down
4 changes: 4 additions & 0 deletions src/Neo.Compiler.CSharp/MethodConvert/Helpers/CallHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ private void CallInstanceMethod(SemanticModel model, IMethodSymbol symbol, bool

var (convert, methodCallingConvention) = GetMethodConvertAndCallingConvention(model, symbol);

if (convert != null && convert.Instructions.Count == 1 && convert.Instructions[0].OpCode == OpCode.RET && !symbol.IsExtern)
return; // Do not call meaningless contructors
if (NeedInstanceConstructor(symbol) && convert != null && convert.Instructions.Count >= 2)
{
Instruction initslot = convert.Instructions[0];
Expand Down Expand Up @@ -107,6 +109,8 @@ private void CallMethodWithInstanceExpression(SemanticModel model, IMethodSymbol

var (convert, methodCallingConvention) = GetMethodConvertAndCallingConvention(model, symbol, instanceExpression);

if (convert != null && convert.Instructions.Count == 1 && convert.Instructions[0].OpCode == OpCode.RET && !symbol.IsExtern)
return; // Do not call meaningless contructors
if (NeedInstanceConstructor(symbol) && convert != null && convert.Instructions.Count >= 2)
{
Instruction initslot = convert.Instructions[0];
Expand Down
29 changes: 3 additions & 26 deletions src/Neo.Compiler.CSharp/MethodConvert/Helpers/ConvertHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ private void InitializeFieldsBasedOnMethodKind(SemanticModel model)
switch (Symbol.MethodKind)
{
case MethodKind.Constructor:
ProcessFields(model);
ProcessConstructorInitializer(model);
break;
case MethodKind.StaticConstructor:
Expand Down Expand Up @@ -153,7 +152,7 @@ private void FinalizeMethod()
Jump(OpCode.JMPIFNOT_L, notNullTarget);

MethodConvert constructor = _context.ConvertMethod(model, attribute.AttributeConstructor!);
CreateObject(model, attribute.AttributeClass, null);
CreateObject(model, attribute.AttributeClass);
foreach (var arg in attribute.ConstructorArguments.Reverse())
Push(arg.Value);
Push(attribute.ConstructorArguments.Length);
Expand Down Expand Up @@ -183,29 +182,7 @@ private void FinalizeMethod()
return instruction;
}

private void InitializeFieldForObject(SemanticModel model, IFieldSymbol field, InitializerExpressionSyntax? initializer)
{
ExpressionSyntax? expression = null;
if (initializer is not null)
{
foreach (var e in initializer.Expressions)
{
if (e is not AssignmentExpressionSyntax ae)
throw new CompilationException(initializer, DiagnosticId.SyntaxNotSupported, $"Unsupported initializer: {initializer}");
if (SymbolEqualityComparer.Default.Equals(field, model.GetSymbolInfo(ae.Left).Symbol))
{
expression = ae.Right;
break;
}
}
}
if (expression is null)
PushDefault(field.Type);
else
ConvertExpression(model, expression);
}

private void CreateObject(SemanticModel model, ITypeSymbol type, InitializerExpressionSyntax? initializer)
private void CreateObject(SemanticModel model, ITypeSymbol type)
{
var members = type.GetAllMembers().Where(p => !p.IsStatic).ToArray();
var fields = members.OfType<IFieldSymbol>().ToArray();
Expand All @@ -226,7 +203,7 @@ private void CreateObject(SemanticModel model, ITypeSymbol type, InitializerExpr
}

foreach (var field in fields.Reverse()) // PACK and PACKSTRUCT works in a reversed way
InitializeFieldForObject(model, field, initializer);
ProcessFieldInitializer(model, field, null, null);
Push(fields.Length + needVirtualMethodTable);
AddInstruction(type.IsValueType || type.IsRecord ? OpCode.PACKSTRUCT : OpCode.PACK);
}
Expand Down
22 changes: 8 additions & 14 deletions src/Neo.Compiler.CSharp/MethodConvert/MethodConvert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public void Convert(SemanticModel model)
public void ConvertForward(SemanticModel model, MethodConvert target)
{
INamedTypeSymbol type = Symbol.ContainingType;
CreateObject(model, type, null);
CreateObject(model, type);
IMethodSymbol? constructor = type.InstanceConstructors.FirstOrDefault(p => p.Parameters.Length == 0)
?? throw new CompilationException(type, DiagnosticId.NoParameterlessConstructor, "The contract class requires a parameterless constructor.");
CallInstanceMethod(model, constructor, true, Array.Empty<ArgumentSyntax>());
Expand Down Expand Up @@ -246,22 +246,16 @@ private void ProcessFieldInitializer(SemanticModel model, IFieldSymbol field, Ac
initializer = syntax.Initializer;
}

if (initializer is null)
{
if (field.Type.GetStackItemType() == StackItemType.Boolean ||
field.Type.GetStackItemType() == StackItemType.Integer)
{
preInitialize?.Invoke();
PushDefault(field.Type);
postInitialize?.Invoke();
}
return;
}
using (InsertSequencePoint(syntaxNode))
{
preInitialize?.Invoke();
model = model.Compilation.GetSemanticModel(syntaxNode.SyntaxTree);
ConvertExpression(model, initializer.Value, syntaxNode);
if (initializer is null)
PushDefault(field.Type);
else
{
model = model.Compilation.GetSemanticModel(syntaxNode.SyntaxTree);
ConvertExpression(model, initializer.Value, syntaxNode);
}
postInitialize?.Invoke();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ public abstract class Contract_Array(Neo.SmartContract.Testing.SmartContractInit
{
#region Compiled data

public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Array"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""getTreeByteLengthPrefix"",""parameters"":[],""returntype"":""ByteArray"",""offset"":0,""safe"":false},{""name"":""getTreeByteLengthPrefix2"",""parameters"":[],""returntype"":""ByteArray"",""offset"":2,""safe"":false},{""name"":""testJaggedArray"",""parameters"":[],""returntype"":""Array"",""offset"":4,""safe"":false},{""name"":""testJaggedByteArray"",""parameters"":[],""returntype"":""Array"",""offset"":42,""safe"":false},{""name"":""testIntArray"",""parameters"":[],""returntype"":""Array"",""offset"":88,""safe"":false},{""name"":""testDefaultArray"",""parameters"":[],""returntype"":""Boolean"",""offset"":118,""safe"":false},{""name"":""testIntArrayInit"",""parameters"":[],""returntype"":""Array"",""offset"":136,""safe"":false},{""name"":""testIntArrayInit2"",""parameters"":[],""returntype"":""Array"",""offset"":161,""safe"":false},{""name"":""testIntArrayInit3"",""parameters"":[],""returntype"":""Array"",""offset"":186,""safe"":false},{""name"":""testDynamicArrayInit"",""parameters"":[{""name"":""length"",""type"":""Integer""}],""returntype"":""Array"",""offset"":211,""safe"":false},{""name"":""testDynamicArrayStringInit"",""parameters"":[{""name"":""input"",""type"":""String""}],""returntype"":""ByteArray"",""offset"":287,""safe"":false},{""name"":""testStructArray"",""parameters"":[],""returntype"":""Any"",""offset"":294,""safe"":false},{""name"":""testDefaultState"",""parameters"":[],""returntype"":""Any"",""offset"":337,""safe"":false},{""name"":""testEmptyArray"",""parameters"":[],""returntype"":""Array"",""offset"":351,""safe"":false},{""name"":""testStructArrayInit"",""parameters"":[],""returntype"":""Any"",""offset"":358,""safe"":false},{""name"":""testByteArrayOwner"",""parameters"":[],""returntype"":""ByteArray"",""offset"":410,""safe"":false},{""name"":""testByteArrayOwnerCall"",""parameters"":[],""returntype"":""ByteArray"",""offset"":412,""safe"":false},{""name"":""testSupportedStandards"",""parameters"":[],""returntype"":""Array"",""offset"":415,""safe"":false},{""name"":""testElementBinding"",""parameters"":[],""returntype"":""Void"",""offset"":417,""safe"":false},{""name"":""testCollectionexpressions"",""parameters"":[],""returntype"":""Array"",""offset"":453,""safe"":false},{""name"":""_initialize"",""parameters"":[],""returntype"":""Void"",""offset"":536,""safe"":false}],""events"":[]},""permissions"":[{""contract"":""0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0"",""methods"":[""itoa""]},{""contract"":""0xda65b600f7124ce6c79950c1772a36403104f2be"",""methods"":[""getBlock""]}],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}");
public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Array"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""getTreeByteLengthPrefix"",""parameters"":[],""returntype"":""ByteArray"",""offset"":0,""safe"":false},{""name"":""getTreeByteLengthPrefix2"",""parameters"":[],""returntype"":""ByteArray"",""offset"":2,""safe"":false},{""name"":""testJaggedArray"",""parameters"":[],""returntype"":""Array"",""offset"":4,""safe"":false},{""name"":""testJaggedByteArray"",""parameters"":[],""returntype"":""Array"",""offset"":42,""safe"":false},{""name"":""testIntArray"",""parameters"":[],""returntype"":""Array"",""offset"":88,""safe"":false},{""name"":""testDefaultArray"",""parameters"":[],""returntype"":""Boolean"",""offset"":118,""safe"":false},{""name"":""testIntArrayInit"",""parameters"":[],""returntype"":""Array"",""offset"":136,""safe"":false},{""name"":""testIntArrayInit2"",""parameters"":[],""returntype"":""Array"",""offset"":161,""safe"":false},{""name"":""testIntArrayInit3"",""parameters"":[],""returntype"":""Array"",""offset"":186,""safe"":false},{""name"":""testDynamicArrayInit"",""parameters"":[{""name"":""length"",""type"":""Integer""}],""returntype"":""Array"",""offset"":211,""safe"":false},{""name"":""testDynamicArrayStringInit"",""parameters"":[{""name"":""input"",""type"":""String""}],""returntype"":""ByteArray"",""offset"":287,""safe"":false},{""name"":""testStructArray"",""parameters"":[],""returntype"":""Any"",""offset"":294,""safe"":false},{""name"":""testDefaultState"",""parameters"":[],""returntype"":""Any"",""offset"":318,""safe"":false},{""name"":""testEmptyArray"",""parameters"":[],""returntype"":""Array"",""offset"":329,""safe"":false},{""name"":""testStructArrayInit"",""parameters"":[],""returntype"":""Any"",""offset"":336,""safe"":false},{""name"":""testByteArrayOwner"",""parameters"":[],""returntype"":""ByteArray"",""offset"":385,""safe"":false},{""name"":""testByteArrayOwnerCall"",""parameters"":[],""returntype"":""ByteArray"",""offset"":387,""safe"":false},{""name"":""testSupportedStandards"",""parameters"":[],""returntype"":""Array"",""offset"":390,""safe"":false},{""name"":""testElementBinding"",""parameters"":[],""returntype"":""Void"",""offset"":392,""safe"":false},{""name"":""testCollectionexpressions"",""parameters"":[],""returntype"":""Array"",""offset"":428,""safe"":false},{""name"":""_initialize"",""parameters"":[],""returntype"":""Void"",""offset"":511,""safe"":false}],""events"":[]},""permissions"":[{""contract"":""0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0"",""methods"":[""itoa""]},{""contract"":""0xda65b600f7124ce6c79950c1772a36403104f2be"",""methods"":[""getBlock""]}],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}");

/// <summary>
/// Optimization: "All"
/// </summary>
public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable<Neo.SmartContract.NefFile>(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK+8gQxQDYqd8FQmcfmTBL3ALZl2ghnZXRCbG9jawEAAQ/A7znO4OTpJcbCoGp54UQN2G/OrARpdG9hAQABDwAA/VQCWEBZQFcEABQTEhEUwHAYFxYVFMBxERITERTAchITFBUUwHNramloFMBAVwQADAQBAgME2zBwDAQFBgcI2zBxDAQBAwIB2zByDAQFBAMC2zBza2ppaBTAQFcBABPEIXAQSmgQUdBFEUpoEVHQRRJKaBJR0EVoQFcBABPEIXBoEM4QlyYECEAJQFcBABMSERPAcBRKaBFR0EUVSmgSUdBFaEBXAQATEhETwHAUSmgRUdBFFUpoElHQRWhAVwEAExIRE8BwFEpoEVHQRRVKaBJR0EVoQFcCAXjEIXAQcSI8aUpoaVHQRWlKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9xRWl4tSTDaEBXAAF4yohAVwIAEAsLE79KNBJwE8QAcWhKaRJR0EVpEs5AVwABeBAL0HgRC9B4EhDQQFcBABALCxO/SjTncGhAVwEAwnBoQFcDABALCxO/SjTScGgRwHFpEM5yakBXAQAMFPZkQ0mNOHjTK5lOThKDxpNEIdr+2zBwaEBaQDTgQFtAVwMAEDcAAHBoEcBxaUrYJAQQznJqStgkBxTONwEAQc/nR5ZAVwcAGBcWFRQTEhEYwHAMBXRocmVlDAN0d28MA29uZRPAcRkYFxPAFhUUE8ATEhETwBPAchMSERPAcxYVFBPAdBkYFxPAdW1saxPAdm5qaWgUv0BWBAwCAQPbMGAMAgED2zBhDBT2ZENJjTh40yuZTk4Sg8aTRCHa/tswYgwGTkVQLTEwDAVORVAtNRLAY0B6B66z"));
public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable<Neo.SmartContract.NefFile>(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK+8gQxQDYqd8FQmcfmTBL3ALZl2ghnZXRCbG9jawEAAQ/A7znO4OTpJcbCoGp54UQN2G/OrARpdG9hAQABDwAA/TsCWEBZQFcEABQTEhEUwHAYFxYVFMBxERITERTAchITFBUUwHNramloFMBAVwQADAQBAgME2zBwDAQFBgcI2zBxDAQBAwIB2zByDAQFBAMC2zBza2ppaBTAQFcBABPEIXAQSmgQUdBFEUpoEVHQRRJKaBJR0EVoQFcBABPEIXBoEM4QlyYECEAJQFcBABMSERPAcBRKaBFR0EUVSmgSUdBFaEBXAQATEhETwHAUSmgRUdBFFUpoElHQRWhAVwEAExIRE8BwFEpoEVHQRRVKaBJR0EVoQFcCAXjEIXAQcSI8aUpoaVHQRWlKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9xRWl4tSTDaEBXAAF4yohAVwIAEAsLE79wE8QAcWhKaRJR0EVpEs5AVwEAEAsLE79waEBXAQDCcGhAVwMAEAsLE79waBHAcWkQznJqQFcBAAwU9mRDSY04eNMrmU5OEoPGk0Qh2v7bMHBoQFpANOBAW0BXAwAQNwAAcGgRwHFpStgkBBDOcmpK2CQHFM43AQBBz+dHlkBXBwAYFxYVFBMSERjAcAwFdGhyZWUMA3R3bwwDb25lE8BxGRgXE8AWFRQTwBMSERPAE8ByExIRE8BzFhUUE8B0GRgXE8B1bWxrE8B2bmppaBS/QFYEDAIBA9swYAwCAQPbMGEMFPZkQ0mNOHjTK5lOThKDxpNEIdr+2zBiDAZORVAtMTAMBU5FUC01EsBjQHQkW6o="));

#endregion

Expand Down Expand Up @@ -168,15 +168,13 @@ public abstract class Contract_Array(Neo.SmartContract.Testing.SmartContractInit
/// Unsafe method
/// </summary>
/// <remarks>
/// Script: VwEAEAsLE79KNOdwaEA=
/// Script: VwEAEAsLE79waEA=
/// INITSLOT 0100 [64 datoshi]
/// PUSH0 [1 datoshi]
/// PUSHNULL [1 datoshi]
/// PUSHNULL [1 datoshi]
/// PUSH3 [1 datoshi]
/// PACKSTRUCT [2048 datoshi]
/// DUP [2 datoshi]
/// CALL E7 [512 datoshi]
/// STLOC0 [2 datoshi]
/// LDLOC0 [2 datoshi]
/// RET [0 datoshi]
Expand Down Expand Up @@ -503,15 +501,13 @@ public abstract class Contract_Array(Neo.SmartContract.Testing.SmartContractInit
/// Unsafe method
/// </summary>
/// <remarks>
/// Script: VwIAEAsLE79KNBJwE8QAcWhKaRJR0EVpEs5A
/// Script: VwIAEAsLE79wE8QAcWhKaRJR0EVpEs5A
/// INITSLOT 0200 [64 datoshi]
/// PUSH0 [1 datoshi]
/// PUSHNULL [1 datoshi]
/// PUSHNULL [1 datoshi]
/// PUSH3 [1 datoshi]
/// PACKSTRUCT [2048 datoshi]
/// DUP [2 datoshi]
/// CALL 12 [512 datoshi]
/// STLOC0 [2 datoshi]
/// PUSH3 [1 datoshi]
/// NEWARRAY_T 00 'Any' [512 datoshi]
Expand All @@ -535,15 +531,13 @@ public abstract class Contract_Array(Neo.SmartContract.Testing.SmartContractInit
/// Unsafe method
/// </summary>
/// <remarks>
/// Script: VwMAEAsLE79KNNJwaBHAcWkQznJqQA==
/// Script: VwMAEAsLE79waBHAcWkQznJqQA==
/// INITSLOT 0300 [64 datoshi]
/// PUSH0 [1 datoshi]
/// PUSHNULL [1 datoshi]
/// PUSHNULL [1 datoshi]
/// PUSH3 [1 datoshi]
/// PACKSTRUCT [2048 datoshi]
/// DUP [2 datoshi]
/// CALL D2 [512 datoshi]
/// STLOC0 [2 datoshi]
/// LDLOC0 [2 datoshi]
/// PUSH1 [1 datoshi]
Expand Down
Loading

0 comments on commit 028445c

Please sign in to comment.