public static void Run() { AbstractEnvironment env1 = new AbstractEnvironment(); env1.SetValue("A", new int[] {0,0,0}); env1.SetValue("B", false); env1.SetValue("I", 32); AbstractEnvironment env2 = new AbstractEnvironment(); env2.SetValue("A", new int[] {0,0,0}); env2.SetValue("B", false); env2.SetValue("I", 32); SDDebug.Assert(env1.Equals(env2)); env2.SetValue("A", new int[] {0,0,1}); SDDebug.Assert(env1.Equals(env2) == false); }
private static void SpecializeFunctionCall(ILFunction context, ILExpression fcall, string resultVar, StringBuilder source, AbstractEnvironment env, List<FunctionCallContainer> calls) { var f = fcall.Function; //Stdlib function if (f.EmbeddedBody != null) { if (f.CanBeCalculatedWithoutRun && !fcall.VAList.Any(pexpr => env.IsDynamic(pexpr.Const.ToString()))) { var args = fcall.VAList.Select(ilexpr => ilexpr.Eval(env)) .Select(o => (o is Int32) ? o : ( (o is Boolean) ? o : L1Runtime.L1Runtime.GetArrayFromObjectArray((object[])o))).ToArray(); var result = f.EmbeddedBody.Invoke(null, args); if (env.IsDynamic(resultVar)) { source.Append("\t"); source.Append(resultVar); source.Append(" := "); RenderConst(result); source.Append(");"); source.Append(System.Environment.NewLine); } else { if (result is L1Runtime.L1Array<int>) { var l1arr = result as L1Runtime.L1Array<int>; var a = new object[l1arr.GetLength()]; for (int i = 0; i < a.Length; ++i) { a[i] = l1arr.GetValue(i); } result = a; } env.SetValue(resultVar, result); } } else { source.Append("\t"); source.Append(resultVar); source.Append(" := "); source.Append(f.Name); source.Append("("); for (int i = 0; i < fcall.VAList.Count; ++i) { var p = fcall.VAList[i].Const.ToString(); if (env.IsDynamic(p)) { source.Append(p); } else { source.Append(RenderConst(env.GetValue(p))); } if (i != fcall.VAList.Count - 1) source.Append(", "); } source.Append(");"); source.Append(System.Environment.NewLine); } } else { if (f.CanBeCalculatedWithoutRun && !fcall.VAList.Any(pexpr => env.IsDynamic(pexpr.Const.ToString()))) { var args = fcall.VAList.Select(ilexpr => ilexpr.Eval(env)).ToArray(); var res = f.Call(args); if (env.IsDynamic(resultVar)) { source.Append("\t").Append(resultVar).Append(" := ").Append(RenderConst(res)).Append(";").AppendLine(); } else { env.SetValue(resultVar, res); } } else { var functionCallRef = new FunctionCallContainer { Function = fcall.Function, SourceFunction = context, ResultVariable = resultVar, Parameters = fcall.VAList.Select(ilexpr => env.IsDynamic(ilexpr.Const.ToString()) ? ilexpr.Const.ToString() : env.GetValue(ilexpr.Const.ToString())).ToList() }; calls.Add(functionCallRef); source.Append("\t").Append(functionCallRef.ToString()).AppendLine(); } } }
private static FunctionSpecializationResult SpecializeFunction( ILFunction function, Dictionary<string, object> pars, List<string> forceDynamic) { var source = new StringBuilder(1024 * 1024); int LabelId = 1; var visited = new SpecPointContainer(); var q = new Queue<SpecPoint>(); var initEnv = new AbstractEnvironment(); foreach (var kvp in pars) { initEnv.SetValue(kvp.Key, kvp.Value); } foreach (var kvp in function.LocalTypes) { if (pars.ContainsKey(kvp.Key)) continue; object val = null; if (kvp.Value.TypeEnum == L1Runtime.SyntaxTree.VariableTypeEnum.Integer) val = 0; if (kvp.Value.TypeEnum == L1Runtime.SyntaxTree.VariableTypeEnum.Bool) val = false; if (kvp.Value.TypeEnum == L1Runtime.SyntaxTree.VariableTypeEnum.Char) val = (char)0; initEnv.SetValue(kvp.Key, val); } foreach (var d in forceDynamic) { initEnv.SetValue(d, Dynamic.Value); } initEnv = _bindTimeAnalyze(function, initEnv); initEnv.Trace(); Dictionary<VariableType, List<string>> localVarsInfo = new Dictionary<VariableType, List<string>>(); foreach (var kvp in function.LocalTypes) { if (initEnv.IsDynamic(kvp.Key) && !function.Parameters.Contains(kvp.Key)) { if (localVarsInfo.ContainsKey(kvp.Value) == false) { localVarsInfo.Add(kvp.Value, new List<string>()); } localVarsInfo[kvp.Value].Add(kvp.Key); } } foreach (var kvp in localVarsInfo) { source.Append("\t"); source.Append(kvp.Key.ToCompileableString()); source.Append(" "); for (int i = 0; i < kvp.Value.Count; ++i) { source.Append(kvp.Value[i]); if (i != kvp.Value.Count - 1) source.Append(", "); } source.Append(";"); source.Append(System.Environment.NewLine); } foreach (var kvp in pars) { if (kvp.Value != Dynamic.Value && initEnv.IsDynamic(kvp.Key)) { source.Append("\t"); source.Append(function.LocalTypes[kvp.Key].ToCompileableString()); source.Append(" "); source.Append(kvp.Key); source.Append(" := "); source.Append(RenderConst(kvp.Value)); source.Append(";"); source.AppendLine(); } } source.Append("* Begin of function specialized body"); source.Append(System.Environment.NewLine); var initialSp = new SpecPoint { Env = initEnv, P = 1, L = LabelId++ } ; q.Enqueue(initialSp); initialSp.Env.Freeze(); visited.AddSpecPoint(initialSp); int operations = 0; var calls = new List<FunctionCallContainer>(); while (q.Count != 0) { operations++; var sp = q.Dequeue(); var env = sp.Env.Clone(); source.Append("L_"); source.Append(sp.L); source.Append(":"); source.Append(System.Environment.NewLine); bool stopped = false; int p = sp.P; while (!stopped) { var instr = function.Body[p - 1]; if (instr is ILExpression) { var expr = instr as ILExpression; stopped = SpecializeExpression(function, expr, env, source, calls); p++; } else if (instr is ILBranch) { var br = (instr as ILBranch); var condVar = br.Condition.Const.ToString(); if (env.IsDynamic(condVar)) { env.Freeze(); var succSp = visited.GetSpecPoint(br.SuccessJump, env); var failSp = visited.GetSpecPoint(br.FailJump, env); if (succSp == null) { succSp = new SpecPoint { Env = env, P = br.SuccessJump, L = LabelId++ }; q.Enqueue(succSp); visited.AddSpecPoint(succSp); } if (failSp == null) { failSp = new SpecPoint { Env = env, P = br.FailJump, L = LabelId++ }; q.Enqueue(failSp); visited.AddSpecPoint(failSp); } source.Append("\tif "); source.Append(condVar); source.Append(" then "); source.Append("goto "); source.Append("L_"); source.Append(succSp.L); source.Append(" else "); source.Append("goto "); source.Append("L_"); source.Append(failSp.L); source.Append(" end;"); source.Append(System.Environment.NewLine); stopped = true; } else { var cond = (bool)env.GetValue(condVar); if (cond) p = br.SuccessJump; else p = br.FailJump; } } else if (instr is ILGoto) { p = (instr as ILGoto).GoTo; } else if (instr is ILReturn) { var ret = (instr as ILReturn); if (ret.Return == null) { source.Append("\treturn;"); source.Append(System.Environment.NewLine); } else { source.Append("\treturn "); var retVar = ret.Return.Const.ToString(); if (env.IsDynamic(retVar)) { source.Append(retVar); } else { m_renderConst(source, env.GetValue(retVar)); } source.Append(";"); source.Append(System.Environment.NewLine); } stopped = true; } } //TODO: Stop if too big query and try with more dynamic variables if (operations >= MaximimOperations) { var ch = visited.GetMostChangeableVariables(); forceDynamic = forceDynamic.Union(ch).ToList(); var res1 = SpecializeFunction(function, pars, forceDynamic); return res1; } } source.Append("0").AppendLine(); //System.Console.WriteLine(source.ToString()); var r = new FunctionSpecializationResult { FunctionCallsNeedToResolve = calls, Source = source, Function = function, SpecializationRules = pars }; return r; }
private static bool SpecializeExpression(ILFunction f, ILExpression expr, AbstractEnvironment env, StringBuilder source, List<FunctionCallContainer> calls) { if (expr.Type == ILExpressionType.Assign) { var left = expr.LeftNode; var right = expr.RightNode; if (left.Type == ILExpressionType.VariableAccess) { var varName = left.Const.ToString(); try { var rightRed = right.AbstactReduce(varName, env, f.LocalTypes); if (rightRed is ILExpression) { var fcall = rightRed as ILExpression; SpecializeFunctionCall(f, fcall, varName, source, env, calls); //source.Append("<<FUNCTION_CALL>>"); } else if (env.IsDynamic(varName)) { //source.Append(varName); source.Append(" := "); if (rightRed is string) { source.Append("\t"); source.Append(varName); source.Append(" := "); source.Append((string)rightRed); source.Append(";"); source.Append(System.Environment.NewLine); } else { source.Append("\t"); source.Append(varName); source.Append(" := "); source.Append(RenderConst(rightRed)); source.Append(";"); source.Append(System.Environment.NewLine); } } else { object val = rightRed; System.Diagnostics.Debug.Assert(val is string == false); System.Diagnostics.Debug.Assert(val is ILExpression == false); env.SetValue(varName, val); } } catch (NullReferenceException) { source.Append("\t__spec_raise_null_ref_exception();"); source.Append(System.Environment.NewLine); } catch (IndexOutOfRangeException) { source.Append("\t__spec_raise_index_out_of_range_exception();"); source.Append(System.Environment.NewLine); } } else { System.Diagnostics.Debug.Assert(left.Type == ILExpressionType.ArrayAccess); try { var arrayName = left.LeftNode.Const.ToString(); object index = null; if (env.IsDynamic(left.RightNode.Const.ToString())) { index = left.RightNode.Const.ToString(); } else { index = env.GetValue(left.RightNode.Const.ToString()); } object rightVar = null; if (env.IsDynamic(right.Const.ToString())) { rightVar = right.Const.ToString(); } else { rightVar = env.GetValue(right.Const.ToString()); } if (env.IsDynamic(arrayName)) { source.Append("\t"); source.Append(arrayName); source.Append("["); source.Append(index); source.Append("] := "); source.Append(rightVar); source.Append(";"); source.Append(System.Environment.NewLine); } else { object[] a = (object[])env.GetValue(arrayName); a[Convert.ToInt32(index)] = rightVar; } } catch (NullReferenceException) { source.Append("\t__spec_raise_null_ref_exception();"); source.Append(System.Environment.NewLine); } catch (IndexOutOfRangeException) { source.Append("\t__spec_raise_index_out_of_range_exception();"); source.Append(System.Environment.NewLine); } } } else if (expr.Type == ILExpressionType.FunctionCall) { source.Append("\t"); source.Append(expr.Const.ToString()); source.Append("("); for (int i = 0; i < expr.VAList.Count; ++i) { string p = null; if (env.IsDynamic(expr.VAList[i].Const.ToString())) { p = expr.VAList[i].Const.ToString(); } else { p = RenderConst(env.GetValue(expr.VAList[i].Const.ToString())); } source.Append(p); if (i != expr.VAList.Count - 1) source.Append(", "); } source.Append(");"); source.Append(System.Environment.NewLine); } return false; }
public object Eval(AbstractEnvironment state) { #region +, -, *, /, mod, pow if (Type == ILExpressionType.Plus) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left + (int)right; else return Dynamic.Value; } if (Type == ILExpressionType.Minus) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left - (int)right; else return Dynamic.Value; } if (Type == ILExpressionType.Mul) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left * (int)right; else return Dynamic.Value; } if (Type == ILExpressionType.Div) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left / (int)right; else return Dynamic.Value; } if (Type == ILExpressionType.Mod) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left % (int)right; else return Dynamic.Value; } if (Type == ILExpressionType.Pow) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return L1Runtime.L1Runtime.Deg((int)left, (int)right); else return Dynamic.Value; } #endregion #region [] if (Type == ILExpressionType.ArrayAccess) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return ((Array)left).GetValue((int)right); else return Dynamic.Value; } #endregion #region >, >=, <, <=, =, <> if (Type == ILExpressionType.Gr) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left > (int)right; else return Dynamic.Value; } if (Type == ILExpressionType.Greq) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left >= (int)right; else return Dynamic.Value; } if (Type == ILExpressionType.Le) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left < (int)right; else return Dynamic.Value; } if (Type == ILExpressionType.Leeq) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left <= (int)right; else return Dynamic.Value; } if (Type == ILExpressionType.Eq) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left == (int)right; else return Dynamic.Value; } if (Type == ILExpressionType.NotEq) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (int)left != (int)right; else return Dynamic.Value; } #endregion #region Uminus, Unot if (Type == ILExpressionType.Uminus) { object left = LeftNode.Eval(state); if (left != Dynamic.Value) return - (int)left; else return Dynamic.Value; } if (Type == ILExpressionType.Unot) { object left = LeftNode.Eval(state); if (left != Dynamic.Value) return !(bool)left; else return Dynamic.Value; } #endregion #region And, Or, Xor if (Type == ILExpressionType.And) { throw new InvalidOperationException("And operator is not allowed in IL!"); } if (Type == ILExpressionType.Or) { throw new InvalidOperationException("Or operator is not allowed in IL!"); } if (Type == ILExpressionType.Xor) { object left = LeftNode.Eval(state); object right = RightNode.Eval(state); if (left != Dynamic.Value && right != Dynamic.Value) return (bool)left ^ (bool)right; else return Dynamic.Value; } #endregion #region Alloc, ArrayLength, VariableAccess, Const if (Type == ILExpressionType.Alloc) { object left = LeftNode.Eval(state); if (left != Dynamic.Value) { int size = (int)left; object[] r = new object[size]; if (OriginalType.NestedType == VariableType.IntType) { for (int i = 0; i < size; ++i) { r[i] = 0; } } if (OriginalType.NestedType == VariableType.BoolType) { for (int i = 0; i < size; ++i) { r[i] = false; } } return r; } else return Dynamic.Value; } if (Type == ILExpressionType.ArrayLength) { object left = LeftNode.Eval(state); if (left != Dynamic.Value) return ((Array)left).GetLength(0); else return Dynamic.Value; } if (Type == ILExpressionType.VariableAccess) { return state.GetValue((string)Const); } if (Type == ILExpressionType.Const) { if (Const is string) { var s = (string)Const; var a = new object[s.Length]; for (int i = 0; i < s.Length; ++i) { a[i] = (int)s[i]; } return a; } return Const; } #endregion #region Assign if (Type == ILExpressionType.Assign) { object right = RightNode.Eval(state); if (LeftNode.Type == ILExpressionType.VariableAccess) { state.SetValue((string)LeftNode.Const, right); return right; } else if (LeftNode.Type == ILExpressionType.ArrayAccess) { object array = LeftNode.LeftNode.Eval(state); object index = LeftNode.RightNode.Eval(state); if (array == Dynamic.Value) { return right; } else { if (index == Dynamic.Value) { //Set whole array as Dynamic state.SetArrayAsDynamic(array); } else { ((Array)array).SetValue(right, (int)index); } return right; } } else { throw new InvalidOperationException("Bad assign construction!"); } } #endregion #region FunctionCall if (Type == ILExpressionType.FunctionCall) { string functionName = (string)Const; var args = new List<object>(); bool isDynamic = false; foreach (ILExpression expr in VAList) { object arg = expr.Eval(state); args.Add(arg); if (arg == Dynamic.Value) isDynamic = true; } if (isDynamic) return Dynamic.Value; else return Function.Call(args.ToArray());; } #endregion throw new InvalidOperationException("Bad interpreter error! =("); }
public virtual object Call(object[] arguments) { if (arguments.Length != Parameters.Count) { throw new InvalidOperationException("Interpreter bad error: function call with bad number of arguments =("); } AbstractEnvironment env = new AbstractEnvironment(); for (int i = 0; i < Parameters.Count; ++i) { env.SetValue(Parameters[i], arguments[i]); } int PC = 1; var curr = Body[0]; while (curr is ILReturn == false) { curr = Body[PC - 1]; if (curr is ILExpression) { object r = (curr as ILExpression).Eval(env); if (r == Dynamic.Value) throw new InvalidOperationException("Interpreter bad error: try to calculate dynamic function"); PC++; } else if (curr is ILBranch) { object r = (curr as ILBranch).Condition.Eval(env); if (r == Dynamic.Value) throw new InvalidOperationException("Interpreter bad error: try to calculate dynamic function"); bool br = (bool)r; if (br) PC = (curr as ILBranch).SuccessJump; else PC = (curr as ILBranch).FailJump; } else if (curr is ILGoto) { PC = (curr as ILGoto).GoTo; } } object result = (curr as ILReturn).Return.Eval(env); if (result == Dynamic.Value) throw new InvalidOperationException("Interpreter bad error: try to calculate dynamic function"); return result; }