private List <CilSigArg> CompleteSigArgs(CilInstructionMethod instruction, CilMethod method) { var isInstanceCall = instruction.CallConv.IsInstance; var instanceSigArg = new CilSigArg { Id = ".this", Type = instruction.TypeSpec.GetCilType(_program) }; var result = isInstanceCall ? (new List <CilSigArg> { instanceSigArg }).Concat(instruction.SigArgs).ToList() : instruction.SigArgs; var start = isInstanceCall ? 1 : 0; for (int i = start; i < result.Count; i++) { result[i].Id = isInstanceCall ? method.Arguments[i - 1].Id : method.Arguments[i].Id; } return(result); }
public JSExpression Translate(CilAssembly assembly, CilType type, CilMethod method) { if (type.IsIgnored) { throw new ArgumentException("cannot translate method of ignored class"); } if (method.NeedTranslation == false) { return(null); } var r = method.GetReplacement(); if (r != null && r.Kind == ReplacementKind.Function) { return(new JSRaw { Value = r.Replacement }); } if (type.IsUserDelegate) { return(TranslateDelegateMethod(method)); } else { return(TranslateNormalMethod(assembly, type, method)); } }
public BlockTranslator(Context context, CilAssembly assembly, CilType type, CilMethod method, JSExpression this_) : base(context) { this.type = type; this.assembly = assembly; this.method = method; this.this_ = this_; }
public void Run(CilMethod method) { IList <OpExpression> infos = method.OpTree; if (infos.Any() == false) { return; } infos.First().StackBefore = new List <StackUseDefinition>(); var methodBody = method.MethodBody; var processStack = new Stack <OpExpression>(); var handlers = methodBody != null ? methodBody.ExceptionHandlingClauses : new List <ExceptionHandlingClause>(); foreach (var handler in handlers.Where(h => h.TryOffset == 0)) { var handlerStart = method.OpTree.First(i => i.Position == handler.HandlerOffset); if (handler.Flags == ExceptionHandlingClauseOptions.Clause) { handlerStart.StackBefore = new List <StackUseDefinition> { new StackUseDefinition { Definitions = new List <Node> { new ExceptionNode() } } }; } else { handlerStart.StackBefore = new List <StackUseDefinition>(); } processStack.Push(handlerStart); } processStack.Push(infos.First()); while (processStack.Any()) { var opInfo = processStack.Pop(); // // Part I var newStack = GetStackAfter(opInfo); // // Part II: update branch targets UpdateTargets(processStack, opInfo, newStack); } }
public void Run(CilMethod method) { IEnumerable <OpExpression> opAst = method.OpTree; foreach (var op in opAst) { ProcessOp(op, op); } }
public void Run(CilMethod method) { IEnumerable <OpExpression> opAst = method.OpTree; method.ReferencedTypes = opAst .SelectMany(op => FindTypes(method, op)) .SelectMany(t => ExpandGenericTypes(t)) .Distinct() .ToArray(); }
public void Run(CilMethod method) { method.OpTree = method.OpTree //.Where(o => o.StackBefore != null) // unreachable .Where( o => false == ( o.Instruction.OpCode.Name == "br.s" && ((o.Targeting.Count == 1 && o.Targeting[0] == o.Prev) || o.Targeting.Count == 0) && o.Targets.Count == 1 && o.Targets[0] == o.Next)) .ToList(); }
public void Run(CilMethod method, List <OpExpression> infos) { processStack.Push(infos.First()); //foreach (var opInfo in infos) while (processStack.Any()) { var opInfo = processStack.Pop(); Process(opInfo); } }
public static int GetPushCount(CilMethod method, OpInstruction instruction) { switch (instruction.OpCode.StackBehaviourPush) { case StackBehaviour.Push0: return(0); case StackBehaviour.Push1: case StackBehaviour.Pushi: case StackBehaviour.Pushi8: case StackBehaviour.Pushr4: case StackBehaviour.Pushr8: case StackBehaviour.Pushref: return(1); case StackBehaviour.Varpush: if (instruction.OpCode.Name.StartsWith("call")) { if (instruction.Data is ConstructorInfo) { return(0); } var mi = (MethodInfo)instruction.Data; if (mi.ReturnType.FullName == "System.Void") { return(0); } else { return(1); } } else { throw new NotImplementedException(); } case StackBehaviour.Push1_push1: if (instruction.OpCode.Name == "dup") { return(2); } else { throw new NotImplementedException(); } default: throw new NotImplementedException(); } }
private static List <ProtectedRegion> GetRegions(CilMethod method) { var mtdb = method.MethodBody; if (mtdb == null) { return new List <ProtectedRegion>() { null } } ; var ex = mtdb .ExceptionHandlingClauses .GroupBy(e => new { e.TryOffset, e.TryLength }); var regions = new List <ProtectedRegion>(); foreach (var clauseGroup in ex) { var result = new ProtectedRegion(); var key = clauseGroup.Key; result.TrySpan = new ProtectedRegionSpan(key.TryOffset, key.TryOffset + key.TryLength, RegionKind.Try); result.CatchSpan = clauseGroup .Where(e => e.Flags == ExceptionHandlingClauseOptions.Clause) .Select( e => new ProtectedRegionSpan(e.HandlerOffset, e.HandlerOffset + e.HandlerLength, RegionKind.Catch) { CatchType = e.CatchType }) .ToList(); var finallyClause = clauseGroup.FirstOrDefault(f => f.Flags == ExceptionHandlingClauseOptions.Finally); if (finallyClause != null) { result.FinallySpan = new ProtectedRegionSpan(finallyClause.HandlerOffset, finallyClause.HandlerOffset + finallyClause.HandlerLength, RegionKind.Finally); } var faultClause = clauseGroup.FirstOrDefault(f => f.Flags == ExceptionHandlingClauseOptions.Fault); if (faultClause != null) { result.FaultSpan = new ProtectedRegionSpan(faultClause.HandlerOffset, faultClause.HandlerOffset + faultClause.HandlerLength, RegionKind.Fault); } regions.Add(result); } return(regions); } }
public CilMethodState(CilMethod method, List <CilSigArg> argTypes, List <IValue> argValues, CilProgram program) { Instruction = method.Instructions.First(); EvaluationStack = new CilEvaluationStack(); MethodInfo = new CilMethodInfo(method); Locals = new CilOrderedDictionary(method.Locals, program); Arguments = new CilOrderedDictionary(argTypes, program); for (int i = 0; i < argValues.Count; i++) { Arguments.Store(null, i, argValues[i]); } }
public void Run(CilMethod method) { IList <OpExpression> infos = method.OpTree; method.Locals = method .MethodBody .LocalVariables .Select(v => new LocalInfo { ReflectionObject = v }) .ToArray(); // TODO: this is probably not enough. need to do proper flow analysis. foreach (var op in infos) { if (op.Instruction.OpCode.Name.StartsWith("stloc")) { int id; if (op.Instruction.Data != null) { id = int.Parse(op.Instruction.Data.ToString()); } else { id = int.Parse(op.Instruction.OpCode.Name.Substring(5).Replace(".s", ".").Replace(".", "")); } method.Locals[id].IsAssigned = true; } else if (op.Instruction.OpCode.Name.StartsWith("ldloc")) { int id; if (op.Instruction.Data != null) { id = int.Parse(op.Instruction.Data.ToString()); } else { id = int.Parse(op.Instruction.OpCode.Name.Substring(5).Replace(".s", ".").Replace(".", "")); } method.Locals[id].IsUsed = true; if (!method.Locals[id].IsAssigned) { method.Locals[id].NeedInit = true; } } } }
private static int GetParameterCount(CilMethod method) { var ps = method .ReflectionMethod .GetParameters() .Length; if (false == method.ReflectionMethod.IsStatic) { ps++; } return(ps); }
private JSFunctionDelcaration CreateGenericFunction(CilMethod method, JSFunctionDelcaration function) { var mi = method.ReflectionMethod; // For static methods on generic classes, the type arguments are passed to // the method at the call site rather than wired through the generic class type. var types = GetGenericParameterList(mi); return(new JSFunctionDelcaration { Body = { new JSExpressionStatement { Expression = new JSReturnExpression{ Expression = function } } }, Parameters = types.Select(t => new JSFunctionParameter { Name = t.Name }).ToList() }); }
private JSExpression TranslateDelegateMethod(CilMethod method) { // TODO: we should avoid the extra trampoline for invoking delegates. // We could leave the codegen here though as it can be useful for reflection later switch (method.Name) { case "Invoke": return(JSFactory.Identifier("BLR", "delegate_invoke")); case "BeginInvoke": return(JSFactory.Identifier("BLR", "delegate_begin_invoke")); case "EndInvoke": return(JSFactory.Identifier("BLR", "delegate_end_invoke")); case ".ctor": return(JSFactory.Identifier("BLR", "delegate_ctor")); default: return(JSFunctionDelcaration.Empty); } }
public void Run(CilMethod method) { IList <OpExpression> opAst = method.OpTree; var visitedTargets = new HashSet <OpExpression>(); var processStack = new Stack <OpExpression>(); processStack.Push(opAst.First()); while (processStack.Any()) { var op = processStack.Pop(); if (!visitedTargets.Add(op)) { continue; // visited already } foreach (var t in op.Targets) { processStack.Push(t); } if (op.PushCount == 0) { continue; } op.ResultType = InferType(method, op); foreach (var loc in op.StoreLocations) { loc.ResultType = MergeTypes(loc.ResultType, op.ResultType); } } UpdateVariables(opAst); }
public void Run(CilMethod method) { var counter = 0; foreach (var opInfo in method.OpTree) { if (opInfo.StackBefore == null) { continue; } foreach (var usage in opInfo.StackBefore.Skip(opInfo.StackBefore.Count() - opInfo.GetRealPopCount())) { usage.Variable = new VariableInfo { Name = string.Format("st_{0:X2}", counter++), ResultType = usage.Type }; foreach (var def in usage.Definitions) { if (def is OpExpression) { ((OpExpression)def).StoreLocations.Add(usage.Variable); } else if (def is ExceptionNode) { ((ExceptionNode)def).StoreLocations.Add(usage.Variable); } else { throw new NotImplementedException(); } } } } }
public static int?GetPopCount(CilMethod method, OpInstruction instruction) { if (instruction.OpCode.Name.StartsWith("leave")) { return(null); // pops all } switch (instruction.OpCode.StackBehaviourPop) { case StackBehaviour.Pop0: return(0); case StackBehaviour.Pop1: case StackBehaviour.Popi: case StackBehaviour.Popref: return(1); case StackBehaviour.Pop1_pop1: case StackBehaviour.Popi_pop1: case StackBehaviour.Popi_popi: case StackBehaviour.Popi_popi8: case StackBehaviour.Popi_popr4: case StackBehaviour.Popi_popr8: case StackBehaviour.Popref_pop1: case StackBehaviour.Popref_popi: return(2); case StackBehaviour.Popi_popi_popi: case StackBehaviour.Popref_popi_pop1: case StackBehaviour.Popref_popi_popi: case StackBehaviour.Popref_popi_popi8: case StackBehaviour.Popref_popi_popr4: case StackBehaviour.Popref_popi_popr8: case StackBehaviour.Popref_popi_popref: return(3); case StackBehaviour.Varpop: if (instruction.OpCode.Name.StartsWith("call")) { var callTarget = (MethodBase)instruction.Data; var result = callTarget.GetParameters().Count(); if (callTarget.IsStatic == false) { result++; } return(result); } else if (instruction.OpCode.Name == "newobj") { return(((ConstructorInfo)instruction.Data).GetParameters().Count()); } else if (instruction.OpCode.Name == "ret") { var mi = method.ReflectionMethod as MethodInfo; if (mi != null && mi.ReturnType.FullName != "System.Void") { return(1); } else { return(0); } } else { throw new NotImplementedException(); } default: throw new NotImplementedException(); } }
public void Run(CilMethod method) { var opInfos = CreateOpInfos(method); method.OpTree = opInfos; }
public override void VisitCallVirtualInstruction(CallVirtualInstruction instruction) { if (!instruction.CallConv.IsInstance) { throw new System.NotImplementedException(); } var methodArgs = PopMethodArgs(instruction); ControlState.EvaluationStack.PopValue(_program, instruction.TypeSpec.GetCilType(_program), out var thisVal); var callExternal = true; CilClassInstance thisClassInstance = null; CilObject thisObject = null; if (thisVal is CilValueReference thisValRef) { var thisObj = ManagedMemory.Load(thisValRef); if (thisObj is CilClassInstance) { thisClassInstance = thisObj as CilClassInstance; } else { thisObject = thisObj; callExternal = true; } } else { throw new System.NotImplementedException(); } CilMethod method = null; if (thisClassInstance != null) { var currentClass = thisClassInstance.Class; while (true) { var possibleMethod = currentClass.Methods.SingleOrDefault(m => m.Name == instruction.MethodName && AreArgumentsAssignable(instruction.SigArgs, m.Arguments)); if (possibleMethod != null) { method = possibleMethod; callExternal = false; break; } currentClass = currentClass.Extends; if (currentClass == null) { callExternal = true; break; } } } if (callExternal) { var result = CallExternalMethod(instruction, thisVal, methodArgs.ToArray(), null); if (!(instruction.ReturnType is CilTypeVoid)) { var resultVal = instruction.ReturnType.CreateValueFromRuntime(result, ManagedMemory, _program); ControlState.EvaluationStack.PushValue(resultVal); } ControlState.MoveToNextInstruction(); } else { var sigArgsWithThis = CompleteSigArgs(instruction, method); var argsWithThis = CompleteArgs(instruction, methodArgs, thisVal); var newMethodState = new CilMethodState(method, sigArgsWithThis, argsWithThis, _program); ControlState.MoveToNextInstruction(); ControlState.CallStack.Push(newMethodState); } }
public void Run(CilMethod method) { var regions = GetRegions(method); var spans = regions .SelectMany(r => r.GetSpans()) .OrderBy(s => s.From) .ThenByDescending(s => s.To); var regionQueue = new Queue <ProtectedRegionSpan>(spans); ProtectedRegionSpan awaitedRegion = null; ProtectedRegionSpan currentRegion = null; var regionStack = new Stack <ProtectedRegionSpan>(); if (regionQueue.Any()) { awaitedRegion = regionQueue.Dequeue(); } var block = new Block(BlockKind.Normal, 0, 0); block.Ast.Add(new JumpLabel(0, false)); var rootBlock = block; var blockStack = new Stack <Block>(); foreach (var op in method.OpTree) { while (currentRegion != null && false == currentRegion.Contains(op)) { // we are no longer in currentRegion, let's wrap it up! var parentBlock = blockStack.Pop(); parentBlock.Ast.Add(block); block = parentBlock; currentRegion = regionStack.Pop(); } if (op.IsLabel) { block.Ast.Add(new JumpLabel(op.Position, true)); } while (awaitedRegion != null && awaitedRegion.Contains(op)) { // we've entered awaitedRegion blockStack.Push(block); block = CreateBlock(awaitedRegion); block.Ast.Add(new JumpLabel(op.Position, false)); regionStack.Push(currentRegion); currentRegion = awaitedRegion; if (regionQueue.Any()) { awaitedRegion = regionQueue.Dequeue(); } else { awaitedRegion = null; } } block.Ast.Add(op); block.To = op.Position; } if (blockStack.Any()) { var parentBlock = blockStack.Pop(); parentBlock.Ast.Add(block); } method.Block = rootBlock; }
public JSFunctionDelcaration GetFirstCallInitializer(CilAssembly assembly, CilType type, CilMethod method) { if (type.IsIgnored) { throw new ArgumentException("cannot translate method of ignored class"); } if (!method.NeedInitializer) { throw new ArgumentException("method need no initialization"); } var functionBlock = new List <JSStatement>(); JSExpression closedMethodInitializer; JSExpression openMethodInitializer = JSFactory.Identifier("asm", GetMethodIdentifier(method.ReflectionMethod) + "_init"); if (HasGenericParameters(method)) { closedMethodInitializer = new JSCallExpression { Function = openMethodInitializer, Arguments = GetGenericParameterList(method.ReflectionMethod) .Select(t => JSFactory.Identifier(t.Name)) .ToList() }; } else { closedMethodInitializer = openMethodInitializer; } functionBlock.Add( new JSCallExpression { Function = JSFactory.Identifier(closedMethodInitializer, "apply"), Arguments = { JSFactory.Identifier("this"), JSFactory.Identifier("arguments") } }.ToStatement()); JSExpression openMethodImplementation = JSFactory.Identifier("asm", GetMethodIdentifier(method.ReflectionMethod) + "_"); JSExpression closedMethodImplementation; if (HasGenericParameters(method)) { closedMethodImplementation = new JSCallExpression { Function = openMethodImplementation, Arguments = GetGenericParameterList(method.ReflectionMethod) .Select(t => JSFactory.Identifier(t.Name)) .ToList() }; } else { closedMethodImplementation = openMethodImplementation; } functionBlock.Add( new JSReturnExpression { Expression = new JSCallExpression { Function = JSFactory.Identifier(closedMethodImplementation, "apply"), Arguments = { JSFactory.Identifier("this"), JSFactory.Identifier("arguments") } } }.ToStatement()); var ps = GetParameterCount(method); var f = new JSFunctionDelcaration { Body = functionBlock, Parameters = Enumerable.Range(0, ps).Select(i => new JSFunctionParameter { Name = "arg" + i }).ToList() }; return(HasGenericParameters(method) ? CreateGenericFunction(method, f) : f); }
public ComparisonTranslator(Context context, CilAssembly assembly, CilType type, CilMethod method, Block block) : base(context, assembly, type, method, block) { }
public void Run(CilMethod method) { ProcessBlock(method.Block); }
private static bool HasGenericParameters(CilMethod method) { return((method.ReflectionMethod.IsGenericMethodDefinition) || (method.ReflectionMethod.IsStatic && method.ReflectionMethod.DeclaringType.IsGenericType)); }
private IKVM.Reflection.Type InferType(CilMethod method, OpExpression op) { var opc = op.Instruction.OpCode.Name; var i = opc.IndexOf("."); var opc_ = i > 0 ? opc.Substring(0, i) : opc; var methodBody = method.MethodBody; switch (opc_) { case "add": case "and": return(InferBinaryArithmeticType(op)); case "box": return(types.Object); case "call": case "callvirt": { var mb = ((MethodBase)op.Instruction.Data); var mi = mb as MethodInfo; if (mi != null) { return(mi.ReturnType); } return(null); } case "castclass": return((IKVM.Reflection.Type)op.Instruction.Data); case "ceq": case "cgt": case "clt": return(types.Boolean); // err... should this be int? case "conv": var t = opc == "conv.i1" ? types.Int32 : opc == "conv.i2" ? types.Int32 : opc == "conv.i4" ? types.Int32 : opc == "conv.i8" ? types.Int64 : opc == "conv.r4" ? types.Single : opc == "conv.r8" ? types.Double : opc == "conv.u1" ? types.UInt32 : opc == "conv.u2" ? types.UInt32 : opc == "conv.u4" ? types.UInt32 : opc == "conv.u8" ? types.UInt64 : opc == "conv.i" ? types.Int32 : opc == "conv.u" ? types.Int32 : opc == "conv.r.un" ? types.Single : null; return(t); case "div": case "div.un": return(InferBinaryArithmeticType(op)); case "dup": return(op.Targeting.First().ResultType); case "endfinally": return(null); case "initobj": return((Type)op.Instruction.Data); case "isinst": return((Type)op.Instruction.Data); case "ldarg": { var id = ""; if (op.Instruction.Data != null) { id = op.Instruction.Data.ToString(); } else { id = opc.Replace(".s", ".").Replace(".", "").Substring("ldarg".Length); } var idx = int.Parse(id); if (false == method.ReflectionMethod.IsStatic) { if (idx == 0) { if (method.ReflectionMethod.DeclaringType.IsValueType) { return(types.ManagedPointer.MakeGenericType(method.ReflectionMethod.DeclaringType)); } else { return(method.ReflectionMethod.DeclaringType); } } else { idx -= 1; } } return(method.ReflectionMethod.GetParameters()[idx].ParameterType); } case "ldarga": { var idxStr = ""; if (op.Instruction.Data != null) { idxStr = op.Instruction.Data.ToString(); } idxStr = opc.Replace(".s", ".").Replace(".", "").Substring("ldarga".Length) + idxStr; var idx = int.Parse(idxStr); if (method.ReflectionMethod.IsStatic == false) { idx--; } var args = method.ReflectionMethod.GetParameters(); var type = args[idx].ParameterType; return(types.ManagedPointer.MakeGenericType(type)); } case "ldc": if (opc.StartsWith("ldc.i4")) { return(types.Int32); } else if (opc.StartsWith("ldc.i8")) { return(types.Int64); } else if (opc.StartsWith("ldc.r8")) { return(types.Double); } else { return(types.Single); } case "ldelem": switch (opc) { case "ldelem": return((Type)op.Instruction.Data); case "ldelem.ref": return(op.Arguments.First().ResultType.GetElementType()); //throw new NotImplementedException(); // array element type case "ldelem.i1": return(types.Sbyte); case "ldelem.i2": return(types.Int16); case "ldelem.i4": return(types.Int32); case "ldelem.i8": return(types.Int64); case "ldelem.u1": return(types.Byte); case "ldelem.u2": return(types.UInt16); case "ldelem.u4": return(types.UInt32); case "ldelem.u8": return(types.UInt64); case "ldelem.r4": return(types.Single); case "ldelem.r8": return(types.Double); case "ldelem.i": return(types.Int32); default: throw new NotSupportedException(); } case "ldelema": { var type = (Type)op.Instruction.Data; return(types.ManagedPointer.MakeGenericType(type)); } case "ldfld": return(((FieldInfo)op.Instruction.Data).FieldType); case "ldftn": return(types.IntPtr); case "ldlen": return(types.UInt32); case "ldloc": { var id = ""; if (op.Instruction.Data != null) { id = op.Instruction.Data.ToString(); } id = opc.Substring(5).Replace(".s", ".").Replace(".", "") + id; return(methodBody.LocalVariables[int.Parse(id)].LocalType); } case "ldloca": { var id = ""; if (op.Instruction.Data != null) { id = op.Instruction.Data.ToString(); } var idx = int.Parse(opc.Substring(5).Replace("a.", ".").Replace(".s", ".").Replace(".", "") + id); var type = methodBody.LocalVariables[idx].LocalType; return(types.ManagedPointer.MakeGenericType(type)); } case "ldnull": return(types.Null); case "ldobj": return((Type)op.Instruction.Data); case "ldsfld": return(((FieldInfo)op.Instruction.Data).FieldType); case "ldflda": { var fieldType = ((FieldInfo)op.Instruction.Data).FieldType; return(types.ManagedPointer.MakeGenericType(fieldType)); } case "ldstr": return(types.String); case "ldtoken": return(types.Object); //universe.GetType("System.Reflection.MemberInfo"); case "mul": return(InferBinaryArithmeticType(op)); case "neg": return(op.Arguments.First().ResultType); case "newarr": return(((Type)op.Instruction.Data).MakeArrayType()); case "newobj": return(((ConstructorInfo)op.Instruction.Data).DeclaringType); case "nop": return(null); case "or": return(InferBinaryArithmeticType(op)); case "pop": return(null); case "rem": case "rem.un": return(InferBinaryArithmeticType(op)); case "ret": return(null); case "shl": case "shr": case "shr.un": return(InferBinaryArithmeticType(op)); case "stelem": case "stind": case "stloc": case "stfld": case "stsfld": return(null); case "sub": return(InferBinaryArithmeticType(op)); case "throw": return(null); case "unbox": return((Type)op.Instruction.Data); default: return(null); } }
private JSFunctionDelcaration TranslateNormalMethod(CilAssembly asm, CilType type, CilMethod method) { var functionBlock = new List <JSStatement>(); if (method.Name == ".cctor") { var type_id = GetTypeIdentifier(type.ReflectionType, method.ReflectionMethod); var has_init = JSFactory.Identifier(type_id, "FieldsInitialized"); functionBlock.Add( new JSIfStatement { Condition = has_init, Statements = { new JSReturnExpression().ToStatement() } }); functionBlock.Add( JSFactory .Assignment(has_init, JSFactory.Literal(true)) .ToStatement()); } var thisScope = GetThisScope(method.ReflectionMethod, method.ReflectionMethod.DeclaringType); if (method.ReferencedTypes != null) { var tIdx = 0; var typesInScope = new List <Type>(); foreach (var t in method.ReferencedTypes) { functionBlock.Add( new JSVariableDelcaration { Name = "t" + tIdx, Value = GetTypeIdentifier(t, method.ReflectionMethod, method.ReflectionMethod.DeclaringType, thisScope, typesInScope) } .ToStatement()); typesInScope.Add(t); tIdx++; } } if (method.MethodBody.InitLocals) { var locIdx = 0; foreach (var loc in method.MethodBody.LocalVariables) { if (method.Locals[locIdx].NeedInit) { functionBlock.Add( new JSExpressionStatement { Expression = new JSVariableDelcaration { Name = "loc" + locIdx, Value = GetDefaultValue(loc.LocalType, methodScope: method.ReflectionMethod, typeScope: method.ReflectionMethod.DeclaringType, thisScope: thisScope) } }); } locIdx++; } } functionBlock.AddRange( method .Block .GetExpressions() .Where(o => o.StoreLocations != null) .SelectMany(o => o.StoreLocations) .Select(l => l.Name) .Distinct() .OrderBy(n => n) .Select( n => new JSExpressionStatement { Expression = new JSVariableDelcaration { Name = n } })); var blockTranslator = new BlockTranslator(context, asm, type, method, thisScope); functionBlock.AddRange( blockTranslator .Translate(method.Block) .Where(s => !(s is JSSwitchCase) && !((s is JSExpressionStatement) && ( ((JSExpressionStatement)s).Expression is JSBreakExpression))) .StartWith( new JSVariableDelcaration { Name = "__pos__", Value = JSFactory.Hex(0) } .ToStatement())); var ps = GetParameterCount(method); var function = new JSFunctionDelcaration { Body = functionBlock, Name = GetSimpleName(method.ReflectionMethod), Parameters = Enumerable.Range(0, ps).Select(i => new JSFunctionParameter { Name = "arg" + i }).ToList() }; return (HasGenericParameters(method) ? CreateGenericFunction(method, function) : function); }
private List <OpExpression> CreateOpInfos(CilMethod method) { var ilOps = new OpInstructionReader(method.MethodBody.GetILAsByteArray(), method.Resolver); var opInfos = new List <OpExpression>(); var prefixes = new List <OpInstruction>(); foreach (var op in ilOps.Process()) { if (op.OpCode.OpCodeType == OpCodeType.Prefix) { prefixes.Add(op); continue; } OpExpression opx; if (op.OpCode.Name.StartsWith("call")) { opx = new CallNode(op, prefixes, GetPopCount(method, op), GetPushCount(method, op), context.LookupMethod((MethodBase)op.Data)); } else if (op.OpCode.Name.StartsWith("ldftn")) { opx = new LoadFunctionNode(op, prefixes, GetPopCount(method, op), GetPushCount(method, op), context.LookupMethod((MethodBase)op.Data)); } else { opx = new OpExpression(op, prefixes, GetPopCount(method, op), GetPushCount(method, op)); } opInfos.Add(opx); prefixes = new List <OpInstruction>(); } foreach (var pairs in opInfos.Zip(opInfos.Skip(1), (current, next) => new { current, next })) { pairs.current.Next = pairs.next; } foreach (var pairs in opInfos.Zip(opInfos.Skip(1), (prev, current) => new { current, prev })) { pairs.current.Prev = pairs.prev; } var body = method.MethodBody; var handlers = body != null ? body.ExceptionHandlingClauses : new List <ExceptionHandlingClause>(); // Create targets foreach (var opInfo in opInfos) { if (opInfo.Instruction.OpCode.Name == "switch") { var i = opInfo.Instruction; var switchEndPosition = 1 + i.Position + i.Size; var target = opInfos.First(p => p.Position == switchEndPosition); opInfo.Targets.Add(target); foreach (var targetOffset in (int[])i.Data) { var targetPosition = 1 + i.Position + i.Size + targetOffset; target = opInfos.First(f2 => f2.Position == targetPosition); opInfo.Targets.Add(target); } } else if (opInfo.Instruction.OpCode.FlowControl == FlowControl.Branch) { var position = GetTargetPosition(opInfo.Instruction); opInfo.Targets = new List <OpExpression> { opInfos.First(i => i.Position == position) }; } else if (opInfo.Instruction.OpCode.FlowControl == FlowControl.Cond_Branch) { var position = GetTargetPosition(opInfo.Instruction); opInfo.Targets = new List <OpExpression> { opInfos.First(i => i.Position == position) }; if (opInfo.Next != null) { opInfo.Targets.Add(opInfo.Next); } } else if (opInfo.Instruction.OpCode.FlowControl == FlowControl.Throw) { // nothing } else { if (opInfo.Next != null) { opInfo.Targets.Add(opInfo.Next); } } if (opInfo.Next != null) { foreach (var handler in handlers.Where(t => t.TryOffset == opInfo.Next.Position)) { if (handler.Flags != ExceptionHandlingClauseOptions.Clause && handler.Flags != ExceptionHandlingClauseOptions.Finally) { continue; } var handlerStart = opInfos.First(i => i.Position == handler.HandlerOffset); opInfo.Targets.Add(handlerStart); } } foreach (var target in opInfo.Targets) { target.Targeting.Add(opInfo); } } foreach (var handler in handlers) { if (handler.Flags != ExceptionHandlingClauseOptions.Clause) { continue; } var handlerStart = opInfos.First(i => i.Position == handler.HandlerOffset); handlerStart.IsHandlerStart = true; } return(opInfos); }
public void Run(CilMethod method) { InternalProcess(method.OpTree); }
public JSFunctionDelcaration GetInitializer(CilAssembly assembly, CilType type, CilMethod method) { if (type.IsIgnored) { throw new ArgumentException("cannot translate method of ignored class"); } if (method.NeedInitializer == false) { return(null); } var functionBlock = new List <JSStatement>(); var thisScope = GetThisScope(method.ReflectionMethod, method.ReflectionMethod.DeclaringType); foreach (var t in method.ReferencedTypes) { if (t.IsGenericParameter) // types shall be initialized before they are used as generic parameters { continue; } functionBlock.Add( new JSCallExpression { Function = JSFactory.Identifier(GetTypeIdentifier(t, method.ReflectionMethod, method.ReflectionMethod.DeclaringType, thisScope), "init") } .ToStatement()); } bool mustInitialize = false; if (method.DeclaringType.ReflectionType.IsGenericTypeDefinition && method.ReflectionMethod.IsConstructor) { mustInitialize = true; } else if (HasGenericParameters(method) || type.ReflectionType.IsGenericType) { var args = GetGenericParameterList(method.ReflectionMethod) .Concat(type.ReflectionType.GetGenericArguments()) .ToList() ; mustInitialize = method .ReferencedTypes .Where(r => r.IsGenericType || r.IsArray) .Any(r => r .GetGenericArguments() .Intersect(args) .Any() || (r.IsArray && args.Contains(r.GetElementType()))); } // We need to always call the initializer for // 1. constructors of generic types, since we have no type arguments // 2. any method with generic arguments which are used in the initializer // // TODO: we should inline the initialization for those cases. if (!mustInitialize) { functionBlock.Add( JSFactory .Assignment( JSFactory.Identifier("asm", GetMethodIdentifier(method.ReflectionMethod)), JSFactory.Identifier("asm", GetMethodIdentifier(method.ReflectionMethod) + "_")) .ToStatement()); } var f = new JSFunctionDelcaration { Body = functionBlock }; return(HasGenericParameters(method) ? CreateGenericFunction(method, f) : f); }