public static Instruction[] Assemble(List<Instruction> bytecode) { int length = 0; var labels = new Dictionary<string, int>(); foreach (var instruction in bytecode) { if (instruction.Opcode == Instruction.Opcodes.Label) { var label = (string)instruction.Arguments; if (labels.ContainsKey(label)) { Utils.Panic(); } labels[label] = length; } else { length++; } } var result = new Instruction[length]; var index = 0; foreach (var instruction in bytecode) { if (instruction.Opcode != Instruction.Opcodes.Label) { result[index] = instruction; index++; if (instruction.Opcode == Instruction.Opcodes.Fjump || instruction.Opcode == Instruction.Opcodes.Tjump || instruction.Opcode == Instruction.Opcodes.Jump || instruction.Opcode == Instruction.Opcodes.Block) { instruction.Arguments = labels[(string)instruction.Arguments]; } else if (instruction.Opcode == Instruction.Opcodes.Fn) { var args = (object[])instruction.Arguments; var label = (string)args[0]; instruction.Arguments = new int[] { labels [label], (int)args [1] }; } instruction.NumericOpcode = Utils.GetNumericOpcode(instruction.Opcode); } } return result; }
public static MemoryStream SerializeBytecodeToStream(Instruction[] bytecode) { return Serialization.BytecodeSerializer.SerializeBytecode (bytecode); }
public static byte[] SerializeBytecode(Instruction[] bytecode) { return Serialization.BytecodeSerializer.SerializeBytecode (bytecode).ToArray(); }
public static string PrintAssembledBytecode(Instruction[] bytecode) { var labels = Utils.GetNumericLabels (bytecode); var sb = new StringBuilder (); for (var i = 0; i < bytecode.Length; i++) { if (labels.Contains (i)) { sb.AppendLine (String.Format ("{0}:", i)); } sb.Append (bytecode [i].ToString ()); } if (labels.Contains (bytecode.Length)) { sb.AppendLine (String.Format ("{0}:", bytecode.Length)); } return sb.ToString (); }
internal static byte[] ComputeBytecodeMd5(Instruction[] bytecode) { var ms = Api.SerializeBytecodeToStream(bytecode); using (var md5 = MD5.Create()) { ms.Seek(0, SeekOrigin.Begin); return md5.ComputeHash(ms); } }
static byte GetNumericOpcode(Instruction.Opcodes opcode) { switch (opcode) { case Instruction.Opcodes.Jump: return 0; case Instruction.Opcodes.Const: return 1; case Instruction.Opcodes.Prim0: return 2; case Instruction.Opcodes.Prim: return 3; case Instruction.Opcodes.Call: return 4; case Instruction.Opcodes.CallJ: return 5; case Instruction.Opcodes.Fjump: return 6; case Instruction.Opcodes.Lset: return 7; case Instruction.Opcodes.Pop: return 8; case Instruction.Opcodes.Lget: return 9; case Instruction.Opcodes.Fn: return 10; case Instruction.Opcodes.NewFrame: return 11; case Instruction.Opcodes.DropFrame: return 12; case Instruction.Opcodes.Args: return 13; case Instruction.Opcodes.Return: return 14; case Instruction.Opcodes.Block: return 15; case Instruction.Opcodes.PopBlock: return 16; case Instruction.Opcodes.BlockReturn: return 17; case Instruction.Opcodes.Context: return 18; case Instruction.Opcodes.Tjump: return 19; case Instruction.Opcodes.FileName: return 20; case Instruction.Opcodes.VmVersion: return 20; case Instruction.Opcodes.VmSourcesMd5: return 20; case Instruction.Opcodes.VmBytecodeMd5: return 20; case Instruction.Opcodes.Div: return 21; case Instruction.Opcodes.Mod: return 22; case Instruction.Opcodes.Neq: return 23; case Instruction.Opcodes.Lt: return 24; case Instruction.Opcodes.Add: return 25; case Instruction.Opcodes.Gref: return 26; case Instruction.Opcodes.Eq: return 27; case Instruction.Opcodes.Apush: return 28; case Instruction.Opcodes.GrefDot: return 29; case Instruction.Opcodes.Sub: return 30; case Instruction.Opcodes.Neg: return 31; case Instruction.Opcodes.Mul: return 32; case Instruction.Opcodes.Shl: return 33; case Instruction.Opcodes.Shr: return 34; case Instruction.Opcodes.Pow: return 35; case Instruction.Opcodes.Floor: return 36; case Instruction.Opcodes.Lte: return 37; case Instruction.Opcodes.Gt: return 38; case Instruction.Opcodes.Gte: return 39; case Instruction.Opcodes.Not: return 40; case Instruction.Opcodes.And: return 41; case Instruction.Opcodes.Ior: return 42; case Instruction.Opcodes.Xor: return 43; case Instruction.Opcodes.Keys: return 44; case Instruction.Opcodes.HasKey: return 45; case Instruction.Opcodes.Apop: return 46; case Instruction.Opcodes.SetIndexed: return 47; case Instruction.Opcodes.Len: return 48; case Instruction.Opcodes.IsString: return 49; case Instruction.Opcodes.IsHash: return 50; case Instruction.Opcodes.IsBool: return 51; case Instruction.Opcodes.IsArray: return 52; case Instruction.Opcodes.IsNumber: return 53; case Instruction.Opcodes.IsInteger: return 54; case Instruction.Opcodes.IsCallable: return 55; default: Utils.Panic(); return 0; } }
internal static void SetBytecodeMd5(Instruction[] bytecode, string md5) { foreach (var instruction in bytecode) { if (instruction.Opcode == Instruction.Opcodes.VmBytecodeMd5) { instruction.Arguments = md5; return; } } }
internal static string GetSourcesMd5(Instruction[] bytecode) { foreach (var instruction in bytecode) { if (instruction.Opcode == Instruction.Opcodes.VmSourcesMd5) { return (string)instruction.Arguments; } } Utils.Panic(); return null; }
internal static HashSet<int> GetNumericLabels(Instruction[] bytecode) { var result = new HashSet<int>(); foreach (var instruction in bytecode) { switch (instruction.Opcode) { case Instruction.Opcodes.Jump: result.Add((int)instruction.Arguments); break; case Instruction.Opcodes.Fjump: result.Add((int)instruction.Arguments); break; case Instruction.Opcodes.Fn: result.Add (((int[])instruction.Arguments)[0]); break; case Instruction.Opcodes.Block: result.Add((int)instruction.Arguments); break; case Instruction.Opcodes.Tjump: result.Add((int)instruction.Arguments); break; } } return result; }