From 275a9f8d41518fcf2579885ef7fd15df45dc4deb Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Sat, 15 Jun 2024 05:32:11 +0300 Subject: [PATCH 01/10] rework branch logic in vm --- runtime/ishtar.generator/generators/types.cs | 6 + runtime/ishtar.vm/VirtualMachine.cs | 359 ++----------------- runtime/ishtar.vm/vm.shit.cs | 132 +++++++ 3 files changed, 166 insertions(+), 331 deletions(-) diff --git a/runtime/ishtar.generator/generators/types.cs b/runtime/ishtar.generator/generators/types.cs index 0a55d862..f1ff9c99 100644 --- a/runtime/ishtar.generator/generators/types.cs +++ b/runtime/ishtar.generator/generators/types.cs @@ -122,6 +122,12 @@ public static VeinClass DetermineType(this ExpressionSyntax exp, GeneratorContex return lt == rt ? lt : ExplicitConversion(lt, rt); } + if (exp is UnaryExpressionSyntax unary) + { + if (unary.OperatorType.IsLogic()) + return VeinTypeCode.TYPE_BOOLEAN.AsClass()(Types.Storage); + // todo + } context.LogError($"Cannot determine expression.", exp); throw new SkipStatementException(); } diff --git a/runtime/ishtar.vm/VirtualMachine.cs b/runtime/ishtar.vm/VirtualMachine.cs index 83523ec5..f9c42a5f 100644 --- a/runtime/ishtar.vm/VirtualMachine.cs +++ b/runtime/ishtar.vm/VirtualMachine.cs @@ -805,340 +805,35 @@ void ForceFail(RuntimeIshtarClass* clazz) } } break; + case EQL_T: + case EQL_F: + { + ++ip; + --sp; + var first = *sp; + *sp = _comparer(first, default, invocation->last_ip, invocation); + println($"$$$ {invocation->last_ip} : {debug_comparer_get_symbol(first, default, invocation->last_ip)} == {sp->data.i == 1}"); + sp++; + } + break; case EQL_H: - { - ++ip; - --sp; - var second = *sp; - --sp; - var first = *sp; - - println($"$$$ EQL_H : {first.data.i} > {second.data.i} == {first.data.i < second.data.i}"); - - if (first.type == second.type) - { - switch (first.type) - { - case TYPE_I1: - if (first.data.b > second.data.b) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_U1: - if (first.data.ub > second.data.ub) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_I2: - if (first.data.s > second.data.s) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_U2: - if (first.data.us > second.data.us) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_I4: - if (first.data.i > second.data.i) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_U4: - if (first.data.ui > second.data.ui) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_I8: - if (first.data.l > second.data.l) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_U8: - if (first.data.ul > second.data.ul) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_R2: - if (first.data.hf > second.data.hf) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_R4: - if (first.data.f_r4 > second.data.f_r4) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_R8: - if (first.data.f > second.data.f) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_R16: - if (first.data.d > second.data.d) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - default: - throw new NotImplementedException(); - } - sp++; - } - else - throw new NotImplementedException(); - } - break; case EQL_L: - { - ++ip; - --sp; - var second = *sp; - --sp; - var first = *sp; - - println($"$$$ : {first.data.i} < {second.data.i} == {first.data.i < second.data.i}"); + case EQL_NN: + case EQL_HQ: + case EQL_LQ: + case EQL_NQ: + { + ++ip; + --sp; + var first = *sp; + --sp; + var second = *sp; - if (first.type == second.type) - { - switch (first.type) - { - case TYPE_I1: - if (first.data.b < second.data.b) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_U1: - if (first.data.ub < second.data.ub) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_I2: - if (first.data.s < second.data.s) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_U2: - if (first.data.us < second.data.us) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_I4: - if (first.data.i < second.data.i) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_U4: - if (first.data.ui < second.data.ui) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_I8: - if (first.data.l < second.data.l) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_U8: - if (first.data.ul < second.data.ul) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_R2: - if (first.data.hf < second.data.hf) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_R4: - if (first.data.f_r4 < second.data.f_r4) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_R8: - if (first.data.f < second.data.f) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - case TYPE_R16: - if (first.data.d < second.data.d) - { - sp->type = TYPE_I4; - sp->data.i = 1; - } - else - { - sp->type = TYPE_I4; - sp->data.i = 0; - } - break; - default: - throw new NotImplementedException(); - } - sp++; - } - else - throw new NotImplementedException(); - } - break; + *sp = _comparer(first, second, invocation->last_ip, invocation); + println($"$$$ {invocation->last_ip} : {debug_comparer_get_symbol(first, second, invocation->last_ip)} == {sp->data.i == 1}"); + sp++; + } + break; case JMP_L: { ++ip; @@ -1232,6 +927,7 @@ void ForceFail(RuntimeIshtarClass* clazz) jump_now(); else ++ip; break; case TYPE_I4: + case TYPE_BOOLEAN: if (first.data.i != 0) jump_now(); else ++ip; break; @@ -1432,6 +1128,7 @@ void ForceFail(RuntimeIshtarClass* clazz) jump_now(); else ++ip; break; case TYPE_I4: + case TYPE_BOOLEAN: if (first.data.i == 0) jump_now(); else ++ip; break; diff --git a/runtime/ishtar.vm/vm.shit.cs b/runtime/ishtar.vm/vm.shit.cs index 526f1b67..6ec32fff 100644 --- a/runtime/ishtar.vm/vm.shit.cs +++ b/runtime/ishtar.vm/vm.shit.cs @@ -1,15 +1,147 @@ namespace ishtar { using System.Collections.Generic; + using System.Numerics; + using System.Runtime.CompilerServices; using runtime; using vein.reflection; using vein.runtime; + using static OpCodeValue; using static vein.runtime.VeinTypeCode; public unsafe partial class VirtualMachine { private void act(ref T t1, ref T t2, A_OperationDelegate actor) => actor(ref t1, ref t2); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private stackval _comparer(in stackval first, in stackval second, OpCodeValue operation, CallFrame* frame) + { + if (operation is not EQL_F and not EQL_T && first.type != second.type) + { + switch (first.type) + { + case TYPE_I4 when second.type is TYPE_BOOLEAN: + break; + case TYPE_BOOLEAN when second.type is TYPE_I4: + break; + default: + FastFail(WNE.TYPE_MISMATCH, "", frame); + return default; + } + } + + var result = (first.type) switch + { + TYPE_I4 or TYPE_BOOLEAN or TYPE_CHAR + => comparer(first.data.i, second.data.i, operation), + TYPE_I1 => comparer(first.data.b, second.data.b, operation), + TYPE_U1 => comparer(first.data.ub, second.data.ub, operation), + TYPE_I2 => comparer(first.data.s, second.data.s, operation), + TYPE_U2 => comparer(first.data.us, second.data.us, operation), + TYPE_U4 => comparer(first.data.ui, second.data.ui, operation), + TYPE_I8 => comparer(first.data.l, second.data.l, operation), + TYPE_U8 => comparer(first.data.ul, second.data.ul, operation), + TYPE_R2 => comparer(first.data.hf, second.data.hf, operation), + TYPE_R4 => comparer(first.data.f_r4, second.data.f_r4, operation), + TYPE_R8 => comparer(first.data.f, second.data.f, operation), + TYPE_R16 => comparer(first.data.d, second.data.d, operation), + TYPE_RAW => comparer(first.data.p, second.data.p, operation), + _ => throw new ArgumentOutOfRangeException() + }; + + if (result is -1) + { + FastFail(WNE.STATE_CORRUPT, "", frame); + return default; + } + + return new stackval() + { + data = { i = result }, + type = TYPE_BOOLEAN + }; + } + + private const int _true = 1; + private const int _false = 0; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private string debug_comparer_get_symbol(in stackval first, in stackval second, OpCodeValue operation) + { + return (first.type) switch + { + TYPE_I4 or TYPE_BOOLEAN or TYPE_CHAR + => debug_comparer_get_symbol(first.data.i, second.data.i, operation), + TYPE_I1 => debug_comparer_get_symbol(first.data.b, second.data.b, operation), + TYPE_U1 => debug_comparer_get_symbol(first.data.ub, second.data.ub, operation), + TYPE_I2 => debug_comparer_get_symbol(first.data.s, second.data.s, operation), + TYPE_U2 => debug_comparer_get_symbol(first.data.us, second.data.us, operation), + TYPE_U4 => debug_comparer_get_symbol(first.data.ui, second.data.ui, operation), + TYPE_I8 => debug_comparer_get_symbol(first.data.l, second.data.l, operation), + TYPE_U8 => debug_comparer_get_symbol(first.data.ul, second.data.ul, operation), + TYPE_R2 => debug_comparer_get_symbol(first.data.hf, second.data.hf, operation), + TYPE_R4 => debug_comparer_get_symbol(first.data.f_r4, second.data.f_r4, operation), + TYPE_R8 => debug_comparer_get_symbol(first.data.f, second.data.f, operation), + TYPE_R16 => debug_comparer_get_symbol(first.data.d, second.data.d, operation), + TYPE_RAW => debug_comparer_get_symbol(first.data.p, second.data.p, operation), + _ => throw new ArgumentOutOfRangeException() + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static string debug_comparer_get_symbol(TNumber first, TNumber second, OpCodeValue operation) + where TNumber : INumber + => (operation) switch + { + EQL_F => $"{first} == {TNumber.Zero}", + EQL_H => $"{first} > {second}", + EQL_L => $"{first} < {second}", + EQL_T => $"{first} == {TNumber.One}", + EQL_NN => $"{first} != {second}", + EQL_HQ => $"{first} >= {second}", + EQL_LQ => $"{first} <= {second}", + EQL_NQ => $"{first} == {second}", + _ => "INVALID" + }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int comparer( + TNumber first, + TNumber second, + OpCodeValue operation) + where TNumber : INumber => + (operation) switch + { + + EQL_F when first == TNumber.Zero => _true, + EQL_F => _false, + + EQL_H when first > second => _true, + EQL_H => _false, + + EQL_L when first < second => _true, + EQL_L => _false, + + EQL_T when first == TNumber.One => _true, + EQL_T => _false, + + EQL_NN when first != second => _true, + EQL_NN => _false, + + EQL_HQ when first >= second => _true, + EQL_HQ => _false, + + EQL_LQ when first <= second => _true, + EQL_LQ => _false, + + EQL_NQ when first == second => _true, + EQL_NQ => _false, + + _ => -1 + }; + + public RuntimeQualityTypeName* readTypeName(uint index, RuntimeIshtarModule* module, CallFrame* frame) { if (module->types_table->TryGetValue((int)index, out var result)) From 0cf2166dd0b25e95ae943ace8ce058241ad4664d Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Sat, 15 Jun 2024 05:32:58 +0300 Subject: [PATCH 02/10] fixes exiting from scopes and getting bad behavior collision check --- runtime/ishtar.generator/GeneratorContext.cs | 2 +- runtime/ishtar.generator/VeinScope.cs | 29 +++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/runtime/ishtar.generator/GeneratorContext.cs b/runtime/ishtar.generator/GeneratorContext.cs index f069460d..67c2e417 100644 --- a/runtime/ishtar.generator/GeneratorContext.cs +++ b/runtime/ishtar.generator/GeneratorContext.cs @@ -39,7 +39,7 @@ public IDisposable CreateScope() { if (CurrentScope is not null) return CurrentScope.EnterScope(); - CurrentScope = new VeinScope(this); + CurrentScope = new VeinScope(this, null); Scopes.Add(CurrentMethod, CurrentScope); return new ScopeTransit(CurrentScope); } diff --git a/runtime/ishtar.generator/VeinScope.cs b/runtime/ishtar.generator/VeinScope.cs index 9f319f12..1a6375dd 100644 --- a/runtime/ishtar.generator/VeinScope.cs +++ b/runtime/ishtar.generator/VeinScope.cs @@ -2,6 +2,7 @@ namespace ishtar; using System; using System.Collections.Generic; +using System.Threading; using emit; using vein.runtime; using vein.syntax; @@ -11,13 +12,16 @@ public class VeinScope public VeinScope TopScope { get; } public List Scopes { get; } = new(); public GeneratorContext Context { get; } + public ulong ScopeId { get; } public Dictionary variables { get; } = new(); public Dictionary locals_index { get; } = new(); + private static ulong _id; public VeinScope(GeneratorContext gen, VeinScope owner = null) { + ScopeId = Interlocked.Increment(ref _id); this.Context = gen; if (owner is null) return; @@ -35,11 +39,29 @@ public void EnsureExceptionLocal(ILGenerator gen, IdentifierExpression id, int c public VeinScope ExitScope() { if (this.TopScope is null) + { + return null; throw new CannotExistMainScopeException(); + } Context.CurrentScope = this.TopScope; return this.TopScope; } + public VeinScope ExitScope(bool allowExitFromRoot) + { + try + { + return ExitScope(); + } + catch (CannotExistMainScopeException e) + { + if (!allowExitFromRoot) + throw; + } + + return null; + } + public IDisposable EnterScope() { var result = new VeinScope(Context, this); @@ -77,9 +99,8 @@ public VeinScope DefineVariable(IdentifierExpression id, VeinClass type, int loc } -public class ScopeTransit : IDisposable +public class ScopeTransit(VeinScope scope) : IDisposable { - public readonly VeinScope Scope; - public ScopeTransit(VeinScope scope) => Scope = scope; - public void Dispose() => Scope.ExitScope(); + public readonly VeinScope Scope = scope; + public void Dispose() => Scope.ExitScope(true); } From 61cd634b641fd061395611dab52fd2c57307968d Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Sat, 15 Jun 2024 05:34:02 +0300 Subject: [PATCH 03/10] correction scope logic --- compiler/compilation/parts/bodies.cs | 2 +- .../ast/expressions/functions/CorruptedChainException.cs | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/compiler/compilation/parts/bodies.cs b/compiler/compilation/parts/bodies.cs index b1d56d96..876ff2df 100644 --- a/compiler/compilation/parts/bodies.cs +++ b/compiler/compilation/parts/bodies.cs @@ -45,7 +45,7 @@ private void GenerateBody(MethodBuilder method, BlockSyntax block, DocumentDecla var generator = method.GetGenerator(); Context.Document = doc; Context.CurrentMethod = method; - Context.CreateScope(); + using var scope = Context.CreateScope(); generator.StoreIntoMetadata("context", Context); foreach (var statement in block.Statements) diff --git a/lib/ast/syntax/ast/expressions/functions/CorruptedChainException.cs b/lib/ast/syntax/ast/expressions/functions/CorruptedChainException.cs index b8dfefa7..adeb81c2 100644 --- a/lib/ast/syntax/ast/expressions/functions/CorruptedChainException.cs +++ b/lib/ast/syntax/ast/expressions/functions/CorruptedChainException.cs @@ -3,10 +3,5 @@ namespace vein.syntax; using Sprache; using stl; -public class CorruptedChainException : VeinParseException -{ - public CorruptedChainException(ExpressionSyntax e) : - base($"Transform is not found in '{e.ExpressionString}'", new Position(0, 0, 0)) - { - } -} +public class CorruptedChainException(ExpressionSyntax e) + : VeinParseException($"Transform is not found in '{e.ExpressionString}'", new Position(0, 0, 0), e); From b7d8e25a0de731e3295a0c0ab35f031cf1325b9e Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Sat, 15 Jun 2024 05:35:04 +0300 Subject: [PATCH 04/10] use diag label name --- runtime/ishtar.base/emit/ILGenerator.cs | 20 +++++++++--------- runtime/ishtar.base/emit/Label.cs | 21 +++---------------- runtime/ishtar.generator/generators/cycles.cs | 6 +++--- runtime/ishtar.generator/generators/logic.cs | 3 ++- 4 files changed, 18 insertions(+), 32 deletions(-) diff --git a/runtime/ishtar.base/emit/ILGenerator.cs b/runtime/ishtar.base/emit/ILGenerator.cs index 982043aa..efd3ea3d 100644 --- a/runtime/ishtar.base/emit/ILGenerator.cs +++ b/runtime/ishtar.base/emit/ILGenerator.cs @@ -352,7 +352,7 @@ public Label BeginTryBlock() Emit(OpCodes.SEH_ENTER, (int)exceptionIndex); - var label = DefineLabel(); + var label = DefineLabel("seh-enter"); var info = new ExceptionBlockInfo(ILOffset, label); exceptionBlocks[exceptionIndex++] = info; @@ -401,13 +401,13 @@ public int BeginCatchBlock(VeinClass? type) if (info.EndTryLabel == default) { - info.EndTryLabel = DefineLabel(); + info.EndTryLabel = DefineLabel("catch-start"); UseLabel(info.EndTryLabel); } /* temporary shit */ Emit(OpCodes.NOP); - var label = DefineLabel(); + var label = DefineLabel("seh-temp-label"); UseLabel(label); /* */ @@ -427,7 +427,7 @@ public virtual void BeginFinallyBlock() Emit(OpCodes.SEH_LEAVE_S, endLabel); UseLabel(endLabel); - Label finallyEndLabel = DefineLabel(); + Label finallyEndLabel = DefineLabel("finally-end"); info.SetFinallyEndLabel(finallyEndLabel); info.MarkFinallyAddr(ILOffset); WriteDebugMetadata($"/* finally block @0x{info.StartAddr:X} */"); @@ -450,19 +450,19 @@ public ILGenerator WriteDebugMetadata(string str, int pos = 0) /// Define label for future use. /// /// - public virtual Label DefineLabel() + public virtual Label DefineLabel(string name) { _labels ??= new int[4]; if (_labels_count >= _labels.Length) _labels = IncreaseCapacity(_labels); _labels[_labels_count] = -1; - return new Label(_labels_count++); + return new Label(_labels_count++, name); } /// /// Define multiple labels for future use. /// - public virtual Label[] DefineLabel(uint size) => - Enumerable.Range(0, (int)size).Select(_ => DefineLabel()).ToArray(); + public virtual Label[] DefineLabel(uint size, string name) => + Enumerable.Range(0, (int)size).Select(x => DefineLabel($"name.{x}")).ToArray(); /// /// Use label in current position. @@ -476,7 +476,7 @@ public virtual void UseLabel(Label loc) if (_labels[loc.Value] != -1) throw new UndefinedLabelException(); _labels[loc.Value] = _position; - DebugAppendLine($"/* defined-label id: 0x{loc.Value:X}, offset: 0x{_position:X} */"); + DebugAppendLine($"/* defined-label id: 0x{loc.Value:X}, offset: 0x{_position:X} [{loc.Name}] */"); } /// /// Get labels positions. @@ -486,7 +486,7 @@ public virtual void UseLabel(Label loc) internal byte[] BakeByteArray() { if (_position == 0) - return new byte[0]; + return Array.Empty(); using var mem = new MemoryStream(); using var bin = new BinaryWriter(mem); diff --git a/runtime/ishtar.base/emit/Label.cs b/runtime/ishtar.base/emit/Label.cs index cac3855d..75dc3eb0 100644 --- a/runtime/ishtar.base/emit/Label.cs +++ b/runtime/ishtar.base/emit/Label.cs @@ -2,24 +2,9 @@ namespace ishtar.emit { using System; - public readonly struct Label : IEquatable