public static Instruction Push(object value) { if (value == null) { return _null ?? (_null = new PushInstruction(null)); } if (value is bool) { if ((bool)value) { return _true ?? (_true = new PushInstruction(value)); } else { return _false ?? (_false = new PushInstruction(value)); } } if (value is int) { int i = (int)value; if (i >= PushIntMinCachedValue && i <= PushIntMaxCachedValue) { if (_ints == null) { _ints = new Instruction[PushIntMaxCachedValue - PushIntMinCachedValue + 1]; } i -= PushIntMinCachedValue; return _ints[i] ?? (_ints[i] = new PushInstruction(value)); } } return new PushInstruction(value); }
private static CodeInfo DeserializeAssembly(string name, IEnumerable <Instruction> instructions, uint bcv, StringsListBuilder strings, IDictionary <string, uint> objectIndices) { uint size = 0; var labels = new Dictionary <string, uint>(); foreach (var inst in instructions) { if (inst is Label labelInst) { if (labelInst.LabelValue is string label) { labels[label] = size * sizeof(int); } } else { size += InstSize(inst, bcv); } } IList <Tuple <ReferenceSignature, uint> > functionReferences = new List <Tuple <ReferenceSignature, uint> >(); IList <Tuple <ReferenceSignature, uint> > variableReferences = new List <Tuple <ReferenceSignature, uint> >(); var binaryInstructions = new List <AnyInstruction>(); size = 0; foreach (var inst in instructions) { if (inst is Label) { continue; } var op = new OpCodes { VersionE = inst.OpCode.VersionE, VersionF = inst.OpCode.VersionF }; var type = DisasmExt.Kind(op, bcv); AnyInstruction bininst = new AnyInstruction(); switch (type) { case InstructionKind.Set: var setinst = (Set)inst; bininst.Set = new SetInstruction { DestVar = new Reference(setinst.VariableType, 0), Instance = GetInstanceType(setinst.InstanceType, setinst.InstanceName, objectIndices), OpCode = op, Types = new TypePair(setinst.Type1, setinst.Type2) }; variableReferences.Add(new Tuple <ReferenceSignature, uint>(new ReferenceSignature { Name = setinst.TargetVariable, InstanceType = setinst.InstanceType, Instance = setinst.InstanceType == InstanceType.Local ? name : null, VariableType = setinst.VariableType, VariableIndex = setinst.VariableIndex }, size)); break; case InstructionKind.Push: var bp = new PushInstruction { OpCode = op, Type = ((Push)inst).Type }; if (bp.Type == DataType.Variable) { var p = (PushVariable)inst; bp.Value = (short)GetInstanceType(p.InstanceType, p.InstanceName, objectIndices); bp.ValueRest = new Reference(p.VariableType, 0).val; variableReferences.Add(new Tuple <ReferenceSignature, uint>(new ReferenceSignature { Name = p.VariableName, InstanceType = p.InstanceType, Instance = p.InstanceType == InstanceType.Local ? name : null, VariableType = p.VariableType, VariableIndex = p.VariableIndex }, size)); } else { var p = (PushConst)inst; switch (p.Type) { case DataType.Int16: bp.Value = (short)(long)p.Value; break; case DataType.Boolean: bp.ValueRest = (uint)(long)p.Value; break; case DataType.Double: case DataType.Single: bp.ValueRest = BitConverter.ToUInt64(BitConverter.GetBytes(Convert.ToDouble(p.Value)), 0); break; case DataType.Int32: case DataType.Int64: bp.ValueRest = BitConverter.ToUInt64(BitConverter.GetBytes(unchecked ((long)(p.Value))), 0); break; case DataType.String: bp.ValueRest = strings.GetIndex((string)p.Value); break; } } bininst.Push = bp; break; case InstructionKind.Call: var callinst = (Call)inst; bininst.Call = new CallInstruction { Arguments = (ushort)callinst.Arguments, Function = new Reference(callinst.FunctionType, 0), OpCode = op, ReturnType = callinst.ReturnType }; functionReferences.Add(new Tuple <ReferenceSignature, uint>(new ReferenceSignature { Name = callinst.FunctionName, InstanceType = InstanceType.StackTopOrGlobal, VariableType = callinst.FunctionType, VariableIndex = -1 }, size)); break; case InstructionKind.Break: var breakinst = (Break)inst; bininst.Break = new BreakInstruction { OpCode = op, Signal = (short)breakinst.Signal, Type = breakinst.Type }; break; case InstructionKind.DoubleType: var doubleinst = (DoubleType)inst; bininst.DoubleType = new DoubleTypeInstruction { OpCode = op, Types = new TypePair(doubleinst.Type1, doubleinst.Type2) }; if (inst is Compare cmpinst) { bininst.DoubleType.ComparisonType = cmpinst.ComparisonType; } break; case InstructionKind.SingleType: var singleinst = (SingleType)inst; bininst.SingleType = new SingleTypeInstruction { OpCode = op, Type = singleinst.Type }; if (inst is Dup dupinst) { bininst.SingleType.DupExtra = dupinst.Extra; } break; case InstructionKind.Goto: var gotoinst = (Branch)inst; uint absTarget = 0; if (gotoinst.Label is long) { absTarget = (uint)(long)(gotoinst.Label); } else if (gotoinst.Label is string) { absTarget = labels[(string)gotoinst.Label]; } else if (gotoinst.Label == null) { bininst.Goto = new BranchInstruction { Offset = new Int24(0xF00000), OpCode = op }; break; } else { Console.Error.WriteLine($"Error in {name}: Can't use label {gotoinst.Label}"); break; } var relTarget = (int)absTarget - (int)size; uint offset = unchecked ((uint)relTarget); if (relTarget < 0) { offset &= 0xFFFFFF; offset += 0x1000000; } offset /= 4; bininst.Goto = new BranchInstruction { Offset = new Int24(offset), OpCode = op }; break; default: Console.Error.WriteLine($"Error in {name}: Unknown instruction type {type}!"); continue; } binaryInstructions.Add(bininst); unsafe { size += DisasmExt.Size(&bininst, bcv) * 4; } } return(new CodeInfo { Size = (int)size, InstructionsCopy = binaryInstructions.ToArray(), functionReferences = functionReferences, variableReferences = variableReferences }); }