From e26c9145c8f0e3c9ca2336b87f16b797e0cab2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20M=C3=AD=C5=A1ek?= Date: Sat, 15 Jun 2024 22:22:59 +0200 Subject: [PATCH] test compilation of a simple global function --- .../Context.Script.cs | 14 ++- src/Peachpie.Runtime/Attributes.cs | 2 +- .../Peachpie.App.Tests/CompiledILTest.cs | 90 +++++++++++++++++++ .../Peachpie.App.Tests.csproj | 1 + 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 src/Tests/Peachpie.App.Tests/CompiledILTest.cs diff --git a/src/Peachpie.Library.Scripting/Context.Script.cs b/src/Peachpie.Library.Scripting/Context.Script.cs index 8b103c7bbf..7ff59c7df3 100644 --- a/src/Peachpie.Library.Scripting/Context.Script.cs +++ b/src/Peachpie.Library.Scripting/Context.Script.cs @@ -15,11 +15,23 @@ namespace Peachpie.Library.Scripting { + /// + /// Represents a script created by . + /// + [PhpHidden] + public interface IScript : Context.IScript + { + /// + /// Assembly byte content. + /// + ImmutableArray Image { get; } + } + /// /// Script representing a compiled submission. /// [DebuggerDisplay("Script ({AssemblyName.Name})")] - sealed class Script : Context.IScript + sealed class Script : IScript { #region Fields & Properties diff --git a/src/Peachpie.Runtime/Attributes.cs b/src/Peachpie.Runtime/Attributes.cs index b0f86b133a..179afbe6f0 100644 --- a/src/Peachpie.Runtime/Attributes.cs +++ b/src/Peachpie.Runtime/Attributes.cs @@ -171,7 +171,7 @@ public TargetPhpLanguageAttribute(string langVersion, bool shortOpenTag) /// /// Marks public declarations that won't be visible in the PHP context. /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] public sealed class PhpHiddenAttribute : Attribute { } diff --git a/src/Tests/Peachpie.App.Tests/CompiledILTest.cs b/src/Tests/Peachpie.App.Tests/CompiledILTest.cs new file mode 100644 index 0000000000..91c5775fb4 --- /dev/null +++ b/src/Tests/Peachpie.App.Tests/CompiledILTest.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Pchp.Core; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.CSharp; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.Metadata; +using Peachpie.Library.Scripting; +using System.Reflection.PortableExecutable; +using System.Reflection.Metadata; +using ICSharpCode.Decompiler.CSharp.Syntax; + + +namespace Peachpie.App.Tests +{ + [TestClass] + public class CompiledILTest + { + static IScript Compile(string code) + { + using (var ctx = Context.CreateConsole(string.Empty)) + { + return (IScript)Context.DefaultScriptingProvider.CreateScript(new Context.ScriptOptions() + { + Context = ctx, + Location = new Location(Path.Combine(Directory.GetCurrentDirectory(), "fake.php"), 0, 0), + EmitDebugInformation = true, + IsSubmission = false, + AdditionalReferences = new string[] { + typeof(CompiledILTest).Assembly.Location, + }, + }, code); + } + } + + static CSharpDecompiler Decompile(IScript script) + { + var fileName = "fake.dll"; + var file = new PEFile(fileName, new PEReader(script.Image)); + + var resolver = new UniversalAssemblyResolver( + fileName, + false, + file.DetectTargetFrameworkId(), + file.DetectRuntimePack(), + PEStreamOptions.PrefetchMetadata, + MetadataReaderOptions.None + ); + + return new CSharpDecompiler(new DecompilerTypeSystem(file, resolver), new DecompilerSettings() { }); + } + + static bool DecompileFunction(IScript script, string fnname, out IMethod method, out AstNode ast) + { + var minfo = script.GetGlobalRoutineHandle(fnname).Single(); + + var decompiler = Decompile(script); + var mainType = decompiler.TypeSystem.FindType(new FullTypeName(minfo.DeclaringType.FullName)).GetDefinition(); + + method = mainType.Methods.Single(m => m.Name == minfo.Name); + ast = decompiler.Decompile(method.MetadataToken).LastChild; + + return true; + } + + [TestMethod] + public void TestSimpleFunction() + { + var script = Compile(@" +