public void AddMethodInfo(Program prog, ClassDecl c, ArmadaSymbolTable symbols, Method meth, bool fromStructsModule, ArmadaStructs structs) { bool isExternal = (meth.Body is null || Attributes.Contains(meth.Attributes, "extern")); var smst = new ArmadaSingleMethodSymbolTable(meth, isExternal, fromStructsModule); foreach (var formal in meth.Ins) { var v = new MethodStackFrameUnaddressableLocalArmadaVariable(formal.Name, formal.Type, null, ArmadaVarType.Input, meth.Name); smst.AddVariable(prog, v); } foreach (var formal in meth.Outs) { var v = new MethodStackFrameUnaddressableLocalArmadaVariable(formal.Name, formal.Type, null, ArmadaVarType.Output, meth.Name); smst.AddVariable(prog, v); } ExtractLocalVariables(prog, meth.Body, meth.Name, smst, structs); if (isExternal && meth.Reads.Expressions != null) { var reads = meth.Reads.Expressions; for (int i = 0; i < reads.Count; ++i) { Expression read_expr = reads.ElementAt(i); var varName = $"Armada_Extern{i}"; var v = new MethodStackFrameUnaddressableLocalArmadaVariable(varName, read_expr.Type, null, ArmadaVarType.ExternRead, meth.Name); smst.AddVariable(prog, v); } } if (methodTable.ContainsKey(meth.Name)) { AH.PrintError(prog, $"Method {meth.Name} already defined"); } else { methodTable[meth.Name] = smst; } if (isExternal && meth.Body == null) { ExtractOldVariablesForBodylessMethod(prog, symbols, meth, smst); } }
protected override bool CheckVariableNameListEquivalence(IEnumerable <string> varNames_l, IEnumerable <string> varNames_h, ArmadaSingleMethodSymbolTable s_l, ArmadaSingleMethodSymbolTable s_h, string methodName, string descriptor) { var vars_l = varNames_l.ToArray(); string[] vars_h; if (methodName == strategy.MethodName) { vars_h = varNames_h.Where(v => v != strategy.VariableName).ToArray(); } else { vars_h = varNames_h.ToArray(); } if (vars_l.Length != vars_h.Length) { AH.PrintError(pgp.prog, $"Method {methodName} has {vars_l.Length} {descriptor} variables in level {pgp.mLow.Name} but {vars_h.Length} of them in level {pgp.mHigh.Name}"); return(false); } for (int i = 0; i < vars_l.Length; ++i) { var name_l = vars_l[i]; var name_h = vars_h[i]; if (name_l != name_h) { AH.PrintError(pgp.prog, $"In method {methodName}, {descriptor} non-introduced variable number {i+1} is named {name_l} in level {pgp.mLow.Name} but named {name_h} in level {pgp.mHigh.Name}"); return(false); } var v_l = s_l.LookupVariable(name_l); var v_h = s_h.LookupVariable(name_h); if (!AH.TypesMatch(v_l.ty, v_h.ty)) { AH.PrintError(pgp.prog, $"In method {methodName}, the {descriptor} variable named {name_l} has type {v_l.ty} in level {pgp.mLow.Name} but type {v_h.ty} in level {pgp.mHigh.Name}"); return(false); } } return(true); }
private void ExtractOldVariablesForBodylessMethod(Program prog, ArmadaSymbolTable symbols, Method meth, ArmadaSingleMethodSymbolTable smst) { if (meth.Ens == null) { return; } if (!meth.Ens.Any()) { return; } var s = AH.MakeNameSegment("s", "Armada_TotalState"); var tid = AH.MakeNameSegment("tid", "Armada_ThreadHandle"); var failureCollector = new SimpleFailureReporter(prog); var ensContext = new BodylessMethodSnapshotResolutionContext(s, tid, meth.Name, symbols, failureCollector); foreach (var ens in meth.Ens) { var ensResolvedJustToGetOldValues = ensContext.ResolveAsRValue(ens.E); } int whichOldValue = 0; foreach (var oldValue in ensContext.OldValues) { var varName = $"Armada_Old{whichOldValue}"; var v = new MethodStackFrameUnaddressableLocalArmadaVariable(varName, oldValue.Type, oldValue, ArmadaVarType.ExternOld, meth.Name); ++whichOldValue; smst.AddVariable(prog, v); } }
private void ExtractLocalVariables(Program prog, Statement stmt, string methodName, ArmadaSingleMethodSymbolTable smst) { if (stmt is BlockStmt) { var s = (BlockStmt)stmt; foreach (var substmt in s.Body) { ExtractLocalVariables(prog, substmt, methodName, smst); } } else if (stmt is IfStmt) { var s = (IfStmt)stmt; ExtractLocalVariables(prog, s.Thn, methodName, smst); ExtractLocalVariables(prog, s.Els, methodName, smst); } else if (stmt is WhileStmt) { var s = (WhileStmt)stmt; ExtractLocalVariables(prog, s.Body, methodName, smst); } else if (stmt is VarDeclStmt) { var s = (VarDeclStmt)stmt; UpdateStmt update = null; if (s.Update != null) { if (!(s.Update is UpdateStmt)) { AH.PrintError(prog, stmt.Tok, "Armada only supports *concrete* assignment of local variables during assignment."); return; } else { update = (UpdateStmt)s.Update; if (s.Locals.Count != update.Rhss.Count) { AH.PrintError(prog, s.Tok, $"Number of left-hand sides for assignment ({s.Locals.Count}) statement doesn't match number of right-hand sides ({update.Rhss.Count})."); return; } } } for (int i = 0; i < s.Locals.Count; ++i) { var local = s.Locals[i]; if (local.OptionalType is InferredTypeProxy) { AH.PrintError(prog, local.EndTok, "Local variables in Armada layer methods must be given explicit types."); continue; } Expression initialValue = null; if (update != null) { var rhs = update.Rhss[i]; if (rhs is HavocRhs) { // No need to do anything special here because in the absence of an initializer we already havoc } else if (rhs is ExprRhs) { var erhs = (ExprRhs)rhs; initialValue = erhs.Expr; } else if (rhs is CreateThreadRhs) { AH.PrintError(prog, rhs.Tok, "Create-thread can't be done in a variable-declaration statement"); continue; } else if (rhs is MallocRhs || rhs is CallocRhs) { AH.PrintError(prog, rhs.Tok, "Allocation can't be done in a variable-declaration statement"); continue; } else { AH.PrintError(prog, rhs.Tok, "Right-hand side of variable-declaration isn't a valid rvalue"); continue; } } ArmadaVariable v; if (local.IsNoAddr) { v = new MethodStackFrameUnaddressableLocalArmadaVariable(local.Name, local.OptionalType, initialValue, ArmadaVarType.Local, methodName); } else { v = new MethodStackFrameAddressableLocalArmadaVariable(local.Name, local.OptionalType, initialValue, s.BypassStoreBuffers, methodName); } smst.AddVariable(prog, v); } } }