mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-06 06:28:39 +00:00
Implement shl, shr, or (#82)
This commit is contained in:
@@ -78,6 +78,9 @@ type NullaryIlOp =
|
||||
| Not
|
||||
| Shr
|
||||
| Shr_un
|
||||
/// Shifts an integer value to the left (in zeroes) by a specified number of bits, pushing the result onto the evaluation stack.
|
||||
/// Top of stack is number of bits to be shifted.
|
||||
/// Inserts a zero bit in the lowest positions.
|
||||
| Shl
|
||||
| Conv_ovf_i
|
||||
| Conv_ovf_u
|
||||
|
@@ -16,6 +16,18 @@ module TestPureCases =
|
||||
|
||||
let unimplemented =
|
||||
[
|
||||
{
|
||||
FileName = "TestShl.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = None
|
||||
}
|
||||
{
|
||||
FileName = "TestShr.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = None
|
||||
}
|
||||
{
|
||||
FileName = "Threads.cs"
|
||||
ExpectedReturnCode = 3
|
||||
@@ -100,18 +112,9 @@ module TestPureCases =
|
||||
}
|
||||
{
|
||||
FileName = "ArgumentOrdering.cs"
|
||||
ExpectedReturnCode = 42
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain =
|
||||
[
|
||||
// localVar
|
||||
CliType.Numeric (CliNumericType.Int32 42)
|
||||
// t
|
||||
CliType.ValueType [ CliType.Numeric (CliNumericType.Int32 42) ]
|
||||
// return value
|
||||
CliType.Numeric (CliNumericType.Int32 42)
|
||||
]
|
||||
|> Some
|
||||
LocalVariablesOfMain = None
|
||||
}
|
||||
{
|
||||
FileName = "BasicLock.cs"
|
||||
@@ -197,6 +200,12 @@ module TestPureCases =
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = None
|
||||
}
|
||||
{
|
||||
FileName = "TestOr.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = None
|
||||
}
|
||||
]
|
||||
|
||||
[<TestCaseSource(nameof cases)>]
|
||||
|
@@ -31,6 +31,9 @@
|
||||
<EmbeddedResource Include="sourcesPure\Threads.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\ResizeArray.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\ArgumentOrdering.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\TestShl.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\TestShr.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\TestOr.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\CustomDelegate.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\Ldind.cs" />
|
||||
</ItemGroup>
|
||||
|
@@ -10,10 +10,40 @@ public class Program
|
||||
}
|
||||
}
|
||||
|
||||
public struct Calculator
|
||||
{
|
||||
private int baseValue;
|
||||
|
||||
public Calculator(int initial)
|
||||
{
|
||||
baseValue = initial;
|
||||
}
|
||||
|
||||
public int Add(int a, int b, int c)
|
||||
{
|
||||
return baseValue + a + b + c;
|
||||
}
|
||||
|
||||
public int SubtractIsh(int a, int b)
|
||||
{
|
||||
return baseValue - a + b;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
int localVar = 42;
|
||||
TestStruct t = new TestStruct(ref localVar);
|
||||
return t.Value;
|
||||
if (t.Value != 42) return 1;
|
||||
|
||||
Calculator calc = new Calculator(10);
|
||||
int addResult = calc.Add(1, 2, 3); // Should be 10 + 1 + 2 + 3 = 16
|
||||
if (addResult != 16) return 2;
|
||||
|
||||
// Test 2: Verify order matters
|
||||
int subResult = calc.SubtractIsh(3, 2); // Should be 10 - 3 + 2 = 9
|
||||
if (subResult != 9) return 3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
41
WoofWare.PawPrint.Test/sourcesPure/TestOr.cs
Normal file
41
WoofWare.PawPrint.Test/sourcesPure/TestOr.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
public class TestOr
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
// Test 1: Bitwise OR with Int32
|
||||
int a32 = 12; // Binary: 1100
|
||||
int b32 = 10; // Binary: 1010
|
||||
int result32 = a32 | b32; // Should be 14 (Binary: 1110)
|
||||
if (result32 != 14) return 1;
|
||||
|
||||
// Test 2: Bitwise OR with Int64
|
||||
long a64 = 0x00FF00FFL;
|
||||
long b64 = 0xFF00FF00L;
|
||||
long result64 = a64 | b64;
|
||||
if (result64 != 0xFFFFFFFFL) return 2;
|
||||
|
||||
// Test 3: Mixed bitwise OR (Int32 and native int)
|
||||
int aMixed = 15; // Binary: 1111
|
||||
nint bMixed = 240; // Binary: 11110000
|
||||
nint resultMixed = aMixed | bMixed; // Should be 255 (Binary: 11111111)
|
||||
if (resultMixed != 255) return 3;
|
||||
|
||||
// Test 4: OR with itself
|
||||
int self = 42;
|
||||
int selfResult = self | self;
|
||||
if (selfResult != 42) return 4;
|
||||
|
||||
// Test 5: OR with 0
|
||||
int withZero = 123;
|
||||
int zeroResult = withZero | 0;
|
||||
if (zeroResult != 123) return 5;
|
||||
|
||||
// Test 6: Native int OR native int
|
||||
nint nativeA = 0x0F;
|
||||
nint nativeB = 0xF0;
|
||||
nint nativeResult = nativeA | nativeB; // Should be 0xFF
|
||||
if (nativeResult != 0xFF) return 6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
34
WoofWare.PawPrint.Test/sourcesPure/TestShl.cs
Normal file
34
WoofWare.PawPrint.Test/sourcesPure/TestShl.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
public class TestShl
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
// Test 1: Shift Left with Int32
|
||||
int value32 = 5; // Binary: 0101
|
||||
int shift32 = 2;
|
||||
int result32 = value32 << shift32; // Should be 20 (Binary: 10100)
|
||||
if (result32 != 20) return 1;
|
||||
|
||||
// Test 2: Shift Left with Int64
|
||||
long value64 = 7L; // Binary: 0111
|
||||
int shift64 = 3;
|
||||
long result64 = value64 << shift64; // Should be 56 (Binary: 111000)
|
||||
if (result64 != 56L) return 2;
|
||||
|
||||
// Test 3: Shift by 0
|
||||
int noShiftValue = 42;
|
||||
int noShiftResult = noShiftValue << 0;
|
||||
if (noShiftResult != 42) return 3;
|
||||
|
||||
// Test 4: Shift by 1
|
||||
int singleShiftResult = noShiftValue << 1;
|
||||
if (singleShiftResult != 84) return 4;
|
||||
|
||||
// Test 5: Shift with native int
|
||||
nint nativeValue = 3;
|
||||
int nativeShift = 4;
|
||||
nint nativeResult = nativeValue << nativeShift; // Should be 48
|
||||
if (nativeResult != 48) return 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
35
WoofWare.PawPrint.Test/sourcesPure/TestShr.cs
Normal file
35
WoofWare.PawPrint.Test/sourcesPure/TestShr.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
public class TestShr
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
// Test 1: Shift Right with Int32
|
||||
int value32 = 20; // Binary: 10100
|
||||
int shift32 = 2;
|
||||
int result32 = value32 >> shift32; // Should be 5 (Binary: 0101)
|
||||
if (result32 != 5) return 1;
|
||||
|
||||
// Test 2: Shift Right with Int64
|
||||
long value64 = 56L; // Binary: 111000
|
||||
int shift64 = 3;
|
||||
long result64 = value64 >> shift64; // Should be 7 (Binary: 0111)
|
||||
if (result64 != 7L) return 2;
|
||||
|
||||
// Test 3: Right shift preserving sign (negative number)
|
||||
int negative = -16;
|
||||
int negativeResult = negative >> 2; // Should be -4
|
||||
if (negativeResult != -4) return 3;
|
||||
|
||||
// Test 4: Shift by 0
|
||||
int noShiftValue = 99;
|
||||
int noShiftResult = noShiftValue >> 0;
|
||||
if (noShiftResult != 99) return 4;
|
||||
|
||||
// Test 5: Shift with native int
|
||||
nint nativeValue = 48;
|
||||
int nativeShift = 4;
|
||||
nint nativeResult = nativeValue >> nativeShift; // Should be 3
|
||||
if (nativeResult != 3) return 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -152,7 +152,7 @@ type CliType =
|
||||
| RuntimePointer of CliRuntimePointer
|
||||
/// This is *not* a CLI type as such. I don't actually know its status. A value type is represented simply
|
||||
/// as a concatenated list of its fields.
|
||||
| ValueType of CliType list
|
||||
| ValueType of (string * CliType) list
|
||||
|
||||
/// In fact any non-zero value will do for True, but we'll use 1
|
||||
static member OfBool (b : bool) = CliType.Bool (if b then 1uy else 0uy)
|
||||
@@ -223,7 +223,7 @@ module CliType =
|
||||
|> List.filter (fun field -> not (field.Attributes.HasFlag FieldAttributes.Static))
|
||||
|> List.map (fun fi ->
|
||||
match zeroOf assemblies corelib sourceAssy typeGenerics methodGenerics fi.Signature with
|
||||
| CliTypeResolutionResult.Resolved ty -> Ok ty
|
||||
| CliTypeResolutionResult.Resolved ty -> Ok (fi.Name, ty)
|
||||
| CliTypeResolutionResult.FirstLoad a -> Error a
|
||||
)
|
||||
|> Result.allOkOrError
|
||||
@@ -257,7 +257,7 @@ module CliType =
|
||||
|> List.filter (fun field -> not (field.Attributes.HasFlag FieldAttributes.Static))
|
||||
|> List.map (fun fi ->
|
||||
match zeroOf assemblies corelib assy typeGenerics methodGenerics fi.Signature with
|
||||
| CliTypeResolutionResult.Resolved ty -> Ok ty
|
||||
| CliTypeResolutionResult.Resolved ty -> Ok (fi.Name, ty)
|
||||
| CliTypeResolutionResult.FirstLoad a -> Error a
|
||||
)
|
||||
|> Result.allOkOrError
|
||||
|
@@ -10,7 +10,8 @@ type EvalStackValue =
|
||||
| ObjectRef of ManagedHeapAddress
|
||||
// Fraser thinks this isn't really a thing in CoreCLR
|
||||
// | TransientPointer of TransientPointerSource
|
||||
| UserDefinedValueType of EvalStackValue list
|
||||
/// Mapping of field name to value
|
||||
| UserDefinedValueType of (string * EvalStackValue) list
|
||||
|
||||
override this.ToString () =
|
||||
match this with
|
||||
@@ -21,7 +22,11 @@ type EvalStackValue =
|
||||
| EvalStackValue.ManagedPointer managedPointerSource -> $"Pointer(%O{managedPointerSource})"
|
||||
| EvalStackValue.ObjectRef managedHeapAddress -> $"ObjectRef(%O{managedHeapAddress})"
|
||||
| EvalStackValue.UserDefinedValueType evalStackValues ->
|
||||
let desc = evalStackValues |> List.map string<EvalStackValue> |> String.concat " | "
|
||||
let desc =
|
||||
evalStackValues
|
||||
|> List.map (snd >> string<EvalStackValue>)
|
||||
|> String.concat " | "
|
||||
|
||||
$"Struct(%s{desc})"
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
@@ -87,8 +92,8 @@ module EvalStackValue =
|
||||
/// Then truncates to int64.
|
||||
let convToUInt64 (value : EvalStackValue) : int64 option =
|
||||
match value with
|
||||
| EvalStackValue.Int32 i -> if i >= 0 then Some (int64 i) else failwith "TODO"
|
||||
| EvalStackValue.Int64 int64 -> failwith "todo"
|
||||
| EvalStackValue.Int32 i -> Some (int64 (uint32 i))
|
||||
| EvalStackValue.Int64 int64 -> Some int64
|
||||
| EvalStackValue.NativeInt nativeIntSource -> failwith "todo"
|
||||
| EvalStackValue.Float f -> failwith "todo"
|
||||
| EvalStackValue.ManagedPointer managedPointerSource -> failwith "todo"
|
||||
@@ -102,7 +107,7 @@ module EvalStackValue =
|
||||
| CliNumericType.Int32 _ ->
|
||||
match popped with
|
||||
| EvalStackValue.Int32 i -> CliType.Numeric (CliNumericType.Int32 i)
|
||||
| EvalStackValue.UserDefinedValueType [ popped ] -> toCliTypeCoerced target popped
|
||||
| EvalStackValue.UserDefinedValueType [ popped ] -> toCliTypeCoerced target (snd popped)
|
||||
| i -> failwith $"TODO: %O{i}"
|
||||
| CliNumericType.Int64 _ ->
|
||||
match popped with
|
||||
@@ -177,7 +182,7 @@ module EvalStackValue =
|
||||
| _ -> failwith "TODO"
|
||||
| EvalStackValue.UserDefinedValueType fields ->
|
||||
match fields with
|
||||
| [ esv ] -> toCliTypeCoerced target esv
|
||||
| [ esv ] -> toCliTypeCoerced target (snd esv)
|
||||
| fields -> failwith $"TODO: don't know how to coerce struct of {fields} to a pointer"
|
||||
| _ -> failwith $"TODO: {popped}"
|
||||
| CliType.Bool _ ->
|
||||
@@ -237,12 +242,22 @@ module EvalStackValue =
|
||||
match popped with
|
||||
| EvalStackValue.UserDefinedValueType popped ->
|
||||
if fields.Length <> popped.Length then
|
||||
failwith "mismatch"
|
||||
failwith
|
||||
$"mismatch: popped value type {popped} (length %i{popped.Length}) into {fields} (length %i{fields.Length})"
|
||||
|
||||
List.map2 toCliTypeCoerced fields popped |> CliType.ValueType
|
||||
List.map2
|
||||
(fun (name1, v1) (name2, v2) ->
|
||||
if name1 <> name2 then
|
||||
failwith $"TODO: name mismatch, {name1} vs {name2}"
|
||||
|
||||
name1, toCliTypeCoerced v1 v2
|
||||
)
|
||||
fields
|
||||
popped
|
||||
|> CliType.ValueType
|
||||
| popped ->
|
||||
match fields with
|
||||
| [ target ] -> toCliTypeCoerced target popped
|
||||
| [ _, target ] -> toCliTypeCoerced target popped
|
||||
| _ -> failwith $"TODO: {popped} into value type {target}"
|
||||
|
||||
let rec ofCliType (v : CliType) : EvalStackValue =
|
||||
@@ -283,7 +298,10 @@ module EvalStackValue =
|
||||
|> EvalStackValue.ManagedPointer
|
||||
| CliRuntimePointerSource.Heap addr -> EvalStackValue.ObjectRef addr
|
||||
| CliRuntimePointerSource.Null -> EvalStackValue.ManagedPointer ManagedPointerSource.Null
|
||||
| CliType.ValueType fields -> fields |> List.map ofCliType |> EvalStackValue.UserDefinedValueType
|
||||
| CliType.ValueType fields ->
|
||||
fields
|
||||
|> List.map (fun (name, f) -> name, ofCliType f)
|
||||
|> EvalStackValue.UserDefinedValueType
|
||||
|
||||
type EvalStack =
|
||||
{
|
||||
|
@@ -151,4 +151,4 @@ module EvalStackValueComparisons =
|
||||
| EvalStackValue.ManagedPointer var1, EvalStackValue.NativeInt var2 ->
|
||||
failwith $"TODO (CEQ): managed pointer vs nativeint"
|
||||
| EvalStackValue.ManagedPointer _, _ -> failwith $"bad ceq: ManagedPointer vs {var2}"
|
||||
| EvalStackValue.UserDefinedValueType _, _ -> failwith $"bad ceq: UserDefinedValueType vs {var2}"
|
||||
| EvalStackValue.UserDefinedValueType _, _ -> failwith $"bad ceq: {var1} vs {var2}"
|
||||
|
@@ -496,7 +496,8 @@ module IlMachineState =
|
||||
| ResolvedBaseType.Object -> state |> pushToEvalStack (CliType.OfManagedObject constructing) currentThread
|
||||
| ResolvedBaseType.ValueType ->
|
||||
state
|
||||
|> pushToEvalStack (CliType.ValueType (Seq.toList constructed.Fields.Values)) currentThread
|
||||
// TODO: ordering of fields probably important
|
||||
|> pushToEvalStack (CliType.ValueType (Map.toList constructed.Fields)) currentThread
|
||||
| ResolvedBaseType.Enum -> failwith "TODO"
|
||||
| None ->
|
||||
match threadStateAtEndOfMethod.MethodState.EvaluationStack.Values with
|
||||
@@ -572,7 +573,7 @@ module IlMachineState =
|
||||
let arg =
|
||||
let rec go (arg : EvalStackValue) =
|
||||
match arg with
|
||||
| EvalStackValue.UserDefinedValueType [ s ] -> go s
|
||||
| EvalStackValue.UserDefinedValueType [ _, s ] -> go s
|
||||
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> failwith "TODO: throw NRE"
|
||||
| EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr) -> Some addr
|
||||
| s -> failwith $"TODO: called with unrecognised arg %O{s}"
|
||||
@@ -580,7 +581,7 @@ module IlMachineState =
|
||||
go arg
|
||||
|
||||
let state =
|
||||
pushToEvalStack (CliType.ValueType [ CliType.ObjectRef arg ]) currentThread state
|
||||
pushToEvalStack (CliType.ValueType [ "m_type", CliType.ObjectRef arg ]) currentThread state
|
||||
|> advanceProgramCounter currentThread
|
||||
|
||||
Some state
|
||||
@@ -706,7 +707,7 @@ module IlMachineState =
|
||||
| ManagedPointerSource.Null -> failwith "TODO: throw NRE"
|
||||
| EvalStackValue.NativeInt src -> failwith "TODO"
|
||||
| EvalStackValue.ObjectRef ptr -> failwith "TODO"
|
||||
| EvalStackValue.UserDefinedValueType [ field ] -> go field
|
||||
| EvalStackValue.UserDefinedValueType [ _, field ] -> go field
|
||||
| EvalStackValue.UserDefinedValueType []
|
||||
| EvalStackValue.UserDefinedValueType (_ :: _ :: _)
|
||||
| EvalStackValue.Int32 _
|
||||
|
@@ -438,8 +438,8 @@ module NullaryIlOp =
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
|> ExecutionResult.Stepped
|
||||
| Sub ->
|
||||
let val1, state = IlMachineState.popEvalStack currentThread state
|
||||
let val2, state = IlMachineState.popEvalStack currentThread state
|
||||
let val1, state = IlMachineState.popEvalStack currentThread state
|
||||
let result = BinaryArithmetic.execute ArithmeticOperation.sub val1 val2
|
||||
|
||||
state
|
||||
@@ -475,11 +475,119 @@ module NullaryIlOp =
|
||||
| Mul_ovf_un -> failwith "TODO: Mul_ovf_un unimplemented"
|
||||
| Div -> failwith "TODO: Div unimplemented"
|
||||
| Div_un -> failwith "TODO: Div_un unimplemented"
|
||||
| Shr -> failwith "TODO: Shr unimplemented"
|
||||
| Shr ->
|
||||
let shift, state = IlMachineState.popEvalStack currentThread state
|
||||
let number, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let shift =
|
||||
match shift with
|
||||
| EvalStackValue.Int32 i -> i
|
||||
| EvalStackValue.NativeInt (NativeIntSource.Verbatim i) -> int<int64> i
|
||||
| _ -> failwith $"Not allowed shift of {shift}"
|
||||
|
||||
let result =
|
||||
// See table III.6
|
||||
match number with
|
||||
| EvalStackValue.Int32 i -> i >>> shift |> EvalStackValue.Int32
|
||||
| EvalStackValue.Int64 i -> i >>> shift |> EvalStackValue.Int64
|
||||
| EvalStackValue.NativeInt (NativeIntSource.Verbatim i) ->
|
||||
(i >>> shift) |> NativeIntSource.Verbatim |> EvalStackValue.NativeInt
|
||||
| _ -> failwith $"Not allowed to shift {number}"
|
||||
|
||||
let state =
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' result currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||
| Shr_un -> failwith "TODO: Shr_un unimplemented"
|
||||
| Shl -> failwith "TODO: Shl unimplemented"
|
||||
| And -> failwith "TODO: And unimplemented"
|
||||
| Or -> failwith "TODO: Or unimplemented"
|
||||
| Shl ->
|
||||
let shift, state = IlMachineState.popEvalStack currentThread state
|
||||
let number, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let shift =
|
||||
match shift with
|
||||
| EvalStackValue.Int32 i -> i
|
||||
| EvalStackValue.NativeInt (NativeIntSource.Verbatim i) -> int<int64> i
|
||||
| _ -> failwith $"Not allowed shift of {shift}"
|
||||
|
||||
let result =
|
||||
// See table III.6
|
||||
match number with
|
||||
| EvalStackValue.Int32 i -> i <<< shift |> EvalStackValue.Int32
|
||||
| EvalStackValue.Int64 i -> i <<< shift |> EvalStackValue.Int64
|
||||
| EvalStackValue.NativeInt (NativeIntSource.Verbatim i) ->
|
||||
(i <<< shift) |> NativeIntSource.Verbatim |> EvalStackValue.NativeInt
|
||||
| _ -> failwith $"Not allowed to shift {number}"
|
||||
|
||||
let state =
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' result currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||
| And ->
|
||||
let v2, state = IlMachineState.popEvalStack currentThread state
|
||||
let v1, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let result =
|
||||
match v1, v2 with
|
||||
| EvalStackValue.Int32 v1, EvalStackValue.Int32 v2 -> v1 &&& v2 |> EvalStackValue.Int32
|
||||
| EvalStackValue.Int32 v1, EvalStackValue.NativeInt (NativeIntSource.Verbatim v2) ->
|
||||
int64<int32> v1 &&& v2 |> NativeIntSource.Verbatim |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.Int32 _, EvalStackValue.NativeInt _ ->
|
||||
failwith $"can't do binary operation on non-verbatim native int {v2}"
|
||||
| EvalStackValue.Int64 v1, EvalStackValue.Int64 v2 -> v1 &&& v2 |> EvalStackValue.Int64
|
||||
| EvalStackValue.NativeInt (NativeIntSource.Verbatim v1), EvalStackValue.Int32 v2 ->
|
||||
v1 &&& int64<int32> v2 |> NativeIntSource.Verbatim |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.NativeInt _, EvalStackValue.Int32 _ ->
|
||||
failwith $"can't do binary operation on non-verbatim native int {v1}"
|
||||
| EvalStackValue.NativeInt (NativeIntSource.Verbatim v1),
|
||||
EvalStackValue.NativeInt (NativeIntSource.Verbatim v2) ->
|
||||
v1 &&& v2 |> NativeIntSource.Verbatim |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.NativeInt (NativeIntSource.Verbatim _), EvalStackValue.NativeInt _ ->
|
||||
failwith $"can't do binary operation on non-verbatim native int {v2}"
|
||||
| EvalStackValue.NativeInt _, EvalStackValue.NativeInt (NativeIntSource.Verbatim _) ->
|
||||
failwith $"can't do binary operation on non-verbatim native int {v1}"
|
||||
| _, _ -> failwith $"refusing to do binary operation on {v1} and {v2}"
|
||||
|
||||
let state =
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' result currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||
| Or ->
|
||||
let v2, state = IlMachineState.popEvalStack currentThread state
|
||||
let v1, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let result =
|
||||
match v1, v2 with
|
||||
| EvalStackValue.Int32 v1, EvalStackValue.Int32 v2 -> v1 ||| v2 |> EvalStackValue.Int32
|
||||
| EvalStackValue.Int32 v1, EvalStackValue.NativeInt (NativeIntSource.Verbatim v2) ->
|
||||
int64<int32> v1 ||| v2 |> NativeIntSource.Verbatim |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.Int32 _, EvalStackValue.NativeInt _ ->
|
||||
failwith $"can't do binary operation on non-verbatim native int {v2}"
|
||||
| EvalStackValue.Int64 v1, EvalStackValue.Int64 v2 -> v1 ||| v2 |> EvalStackValue.Int64
|
||||
| EvalStackValue.NativeInt (NativeIntSource.Verbatim v1), EvalStackValue.Int32 v2 ->
|
||||
v1 ||| int64<int32> v2 |> NativeIntSource.Verbatim |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.NativeInt _, EvalStackValue.Int32 _ ->
|
||||
failwith $"can't do binary operation on non-verbatim native int {v1}"
|
||||
| EvalStackValue.NativeInt (NativeIntSource.Verbatim v1),
|
||||
EvalStackValue.NativeInt (NativeIntSource.Verbatim v2) ->
|
||||
v1 ||| v2 |> NativeIntSource.Verbatim |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.NativeInt (NativeIntSource.Verbatim _), EvalStackValue.NativeInt _ ->
|
||||
failwith $"can't do binary operation on non-verbatim native int {v2}"
|
||||
| EvalStackValue.NativeInt _, EvalStackValue.NativeInt (NativeIntSource.Verbatim _) ->
|
||||
failwith $"can't do binary operation on non-verbatim native int {v1}"
|
||||
| _, _ -> failwith $"refusing to do binary operation on {v1} and {v2}"
|
||||
|
||||
let state =
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' result currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||
| Xor -> failwith "TODO: Xor unimplemented"
|
||||
| Conv_I ->
|
||||
let popped, state = IlMachineState.popEvalStack currentThread state
|
||||
|
@@ -679,7 +679,11 @@ module internal UnaryMetadataIlOp =
|
||||
IlMachineState.pushToEvalStack currentValue thread state
|
||||
| ManagedPointerSource.Null -> failwith "TODO: raise NullReferenceException"
|
||||
| EvalStackValue.ObjectRef managedHeapAddress -> failwith $"todo: {managedHeapAddress}"
|
||||
| EvalStackValue.UserDefinedValueType _ as udvt -> IlMachineState.pushToEvalStack' udvt thread state
|
||||
| EvalStackValue.UserDefinedValueType fields ->
|
||||
let result =
|
||||
fields |> List.pick (fun (k, v) -> if k = field.Name then Some v else None)
|
||||
|
||||
IlMachineState.pushToEvalStack' result thread state
|
||||
|
||||
state
|
||||
|> IlMachineState.advanceProgramCounter thread
|
||||
@@ -1016,7 +1020,10 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
let (_, alloc), state = IlMachineState.getOrAllocateType baseClassTypes handle state
|
||||
|
||||
IlMachineState.pushToEvalStack (CliType.ValueType [ CliType.ObjectRef (Some alloc) ]) thread state
|
||||
IlMachineState.pushToEvalStack
|
||||
(CliType.ValueType [ "m_type", CliType.ObjectRef (Some alloc) ])
|
||||
thread
|
||||
state
|
||||
| _ -> failwith $"Unexpected metadata token %O{metadataToken} in LdToken"
|
||||
|
||||
state
|
||||
|
Reference in New Issue
Block a user