/// <summary> /// This function sets the modified temp graphnodes to the last graphnode in a statement /// </summary> /// <param name="graphnode"></param> public static void SetFinalGraphNodeRuntimeDependents(AssociativeGraph.GraphNode graphnode) { if (null != graphnode && graphnode.IsSSANode()) { if (null != graphnode.lastGraphNode) { graphnode.lastGraphNode.symbolListWithinExpression.Add(graphnode.updateNodeRefList[0].nodeList[0].symbol); } } }
public void LogSemanticError(string msg, string fileName = null, int line = -1, int col = -1, AssociativeGraph.GraphNode graphNode = null) { /*if (fileName == null) { fileName = "N.A."; }*/ if (logErrors) { System.Console.WriteLine("{0}({1},{2}) Error:{3}", fileName, line, col, msg); } if (compileState.Options.IsDeltaExecution) { compileState.LogErrorInGlobalMap(ProtoLanguage.CompileStateTracker.ErrorType.Error, msg, fileName, line, col); } BuildData.ErrorEntry errorEntry = new BuildData.ErrorEntry { FileName = fileName, Message = msg, Line = line, Col = col }; errors.Add(errorEntry); // Comment: This is true for example in Graph Execution mode /*if (errorAsWarning) { if (graphNode != null) { graphNode.isDirty = false; return; } }*/ OutputMessage outputmessage = new OutputMessage(OutputMessage.MessageType.Error, msg.Trim(), fileName, line, col); if (MessageHandler != null) { MessageHandler.Write(outputmessage); if (WebMsgHandler != null) { OutputMessage webOutputMsg = new OutputMessage(OutputMessage.MessageType.Error, msg.Trim(), "", line, col); WebMsgHandler.Write(webOutputMsg); } if (!outputmessage.Continue) throw new BuildHaltException(msg); } throw new BuildHaltException(msg); }
/// <summary> /// Check if an update is triggered; /// Find all graph nodes whos dependents contain this symbol; /// Mark those nodes as dirty /// </summary> public int UpdateDependencyGraph( int exprUID, int modBlkId, bool isSSAAssign, AssociativeGraph.GraphNode executingGraphNode, bool propertyChanged = false) { int nodesMarkedDirty = 0; if (executingGraphNode == null) { return nodesMarkedDirty; } int classIndex = executingGraphNode.classIndex; int procIndex = executingGraphNode.procIndex; var graph = istream.dependencyGraph; var graphNodes = graph.GetGraphNodesAtScope(classIndex, procIndex); if (graphNodes == null) { return nodesMarkedDirty; } //foreach (var graphNode in graphNodes) for (int i = 0; i < graphNodes.Count; ++i) { var graphNode = graphNodes[i]; // If the graphnode is inactive then it is no longer executed if (!graphNode.isActive) { continue; } // // Comment Jun: // This is clarifying the intention that if the graphnode is within the same SSA expression, we still allow update // bool allowUpdateWithinSSA = false; if (core.Options.ExecuteSSA) { allowUpdateWithinSSA = true; isSSAAssign = false; // Remove references to this when ssa flag is removed // Do not update if its a property change and the current graphnode is the same expression if (propertyChanged && graphNode.exprUID == Properties.executingGraphNode.exprUID) { continue; } } else { // TODO Jun: Remove this code immediatley after enabling SSA bool withinSSAStatement = graphNode.UID == executingGraphNode.UID; allowUpdateWithinSSA = !withinSSAStatement; } if (!allowUpdateWithinSSA || (propertyChanged && graphNode == Properties.executingGraphNode)) { continue; } foreach (var noderef in executingGraphNode.updateNodeRefList) { ProtoCore.AssociativeGraph.GraphNode matchingNode = null; if (!graphNode.DependsOn(noderef, ref matchingNode)) { continue; } // Jun: only allow update to other expr id's (other statements) if this is the final SSA assignment if (core.Options.ExecuteSSA && !propertyChanged) { if (null != Properties.executingGraphNode && Properties.executingGraphNode.IsSSANode()) { // This is still an SSA statement, if a node of another statement depends on it, ignore it if (graphNode.exprUID != Properties.executingGraphNode.exprUID) { // Defer this update until the final non-ssa node deferedGraphNodes.Add(graphNode); continue; } } } // @keyu: if we are modifying an object's property, e.g., // // foo.id = 42; // // both dependent list and update list of the corresponding // graph node contains "foo" and "id", so if property "id" // is changed, this graph node will be re-executed and the // value of "id" is incorrectly set back to old value. if (propertyChanged) { var depUpdateNodeRef = graphNode.dependentList[0].updateNodeRefList[0]; if (graphNode.updateNodeRefList.Count == 1) { var updateNodeRef = graphNode.updateNodeRefList[0]; if (depUpdateNodeRef.IsEqual(updateNodeRef)) { continue; } } } // // Comment Jun: We dont want to cycle between such statements: // // a1.a = 1; // a1.a = 10; // Validity.Assert(null != matchingNode); bool isLHSModification = matchingNode.isLHSNode; bool isUpdateable = matchingNode.IsUpdateableBy(noderef); // isSSAAssign means this is the graphnode of the final SSA assignment // Overrride this if allowing within SSA update // TODO Jun: Remove this code when SSA is completely enabled bool allowSSADownstream = false; if (core.Options.ExecuteSSA) { // Check if we allow downstream update if (exprUID == graphNode.exprUID) { allowSSADownstream = graphNode.AstID > executingGraphNode.AstID; } } // Comment Jun: // If the triggered dependent graphnode is LHS // and... // the triggering node (executing graphnode) if (isLHSModification && !isUpdateable) { break; } // TODO Jun: Optimization - Reimplement update delta evaluation using registers //if (IsNodeModified(EX, FX)) bool isLastSSAAssignment = (exprUID == graphNode.exprUID) && graphNode.IsLastNodeInSSA && !graphNode.isReturn; if (exprUID != graphNode.exprUID && modBlkId != graphNode.modBlkUID) { UpdateModifierBlockDependencyGraph(graphNode); } else if (allowSSADownstream || isSSAAssign || isLastSSAAssignment || (exprUID != graphNode.exprUID && modBlkId == Constants.kInvalidIndex && graphNode.modBlkUID == Constants.kInvalidIndex) ) { if (graphNode.isCyclic) { // If the graphnode is cyclic, mark it as not dirst so it wont get executed // Sets its cyclePoint graphnode to be not dirty so it also doesnt execute. // The cyclepoint is the other graphNode that the current node cycles with graphNode.isDirty = false; if (null != graphNode.cyclePoint) { graphNode.cyclePoint.isDirty = false; graphNode.cyclePoint.isCyclic = true; } } else if (!graphNode.isDirty) { // If the graphnode is not cyclic, then it can be safely marked as dirty, in preparation of its execution if (core.Options.EnableVariableAccumulator && !isSSAAssign && graphNode.IsSSANode()) { // // Comment Jun: Backtrack and firt the first graphnode of this SSA transform and mark it dirty. // We want to execute the entire statement, not just the partial SSA nodes // // TODO Jun: Optimization - Statically determine the index of the starting graphnode of this SSA expression // Looks we should partially execuate graph // nodes otherwise we will get accumulative // update. - Yu Ke /* int graphNodeIndex = 0; for (; graphNodeIndex < graph.GraphList.Count; graphNodeIndex++) { if (graph.GraphList[graphNodeIndex].UID == graphNode.UID) break; } var firstGraphNode = GetFirstSSAGraphnode(graphNodeIndex - 1, graphNode.exprUID); firstGraphNode.isDirty = true; */ } if (core.Options.ElementBasedArrayUpdate) { UpdateDimensionsForGraphNode(graphNode, matchingNode, executingGraphNode); } graphNode.isDirty = true; graphNode.forPropertyChanged = propertyChanged; nodesMarkedDirty++; // On debug mode: // we want to mark all ssa statements dirty for an if the lhs pointer is a new instance. // In this case, the entire line must be re-executed // // Given: // x = 1 // p = p.f(x) // x = 2 // // To SSA: // // x = 1 // t0 = p -> we want to execute from here of member function 'f' returned a new instance of 'p' // t1 = x // t2 = t0.f(t1) // p = t2 // x = 2 if (null != executingGraphNode.lastGraphNode && executingGraphNode.lastGraphNode.reExecuteExpression) { executingGraphNode.lastGraphNode.reExecuteExpression = false; //if (core.Options.GCTempVarsOnDebug && core.Options.IDEDebugMode) { var firstGraphNode = GetFirstSSAGraphnode(i - 1, graphNode.exprUID); firstGraphNode.isDirty = true; } } } } } } return nodesMarkedDirty; }
private void SetGraphNodeStackValueNull(AssociativeGraph.GraphNode graphNode) { StackValue svNull = StackValue.Null; SetGraphNodeStackValue(graphNode, svNull); }
private bool HasCyclicDependency(AssociativeGraph.GraphNode node) { return node.counter > runtimeCore.Options.kDynamicCycleThreshold; }
protected void BuildRealDependencyForIdentList(AssociativeGraph.GraphNode graphNode) { if (ssaPointerStack.Count == 0) { return; } // Push all dependent pointers ProtoCore.AST.AssociativeAST.IdentifierListNode identList = BuildIdentifierList(ssaPointerStack.Peek()); // Comment Jun: perhaps this can be an assert? if (null != identList) { ProtoCore.Type type = new ProtoCore.Type(); type.UID = globalClassIndex; ProtoCore.AssociativeGraph.UpdateNodeRef nodeRef = new AssociativeGraph.UpdateNodeRef(); int functionIndex = globalProcIndex; DFSGetSymbolList_Simple(identList, ref type, ref functionIndex, nodeRef); if (null != graphNode && nodeRef.nodeList.Count > 0) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.updateNodeRefList.Add(nodeRef); graphNode.PushDependent(dependentNode); // If the pointerList is a setter, then it should also be in the lhs of a graphNode // Given: // a.x = 1 // Which was converted to: // tvar = a.set_x(1) // Set a.x as lhs of the graphnode. // This means that statement that depends on a.x can re-execute, such as: // p = a.x; // List<ProtoCore.AST.AssociativeAST.AssociativeNode> topList = ssaPointerStack.Peek(); string propertyName = topList[topList.Count - 1].Name; bool isSetter = propertyName.StartsWith(Constants.kSetterPrefix); if (isSetter) { graphNode.updateNodeRefList.Add(nodeRef); graphNode.IsLHSIdentList = true; AutoGenerateUpdateArgumentReference(nodeRef, graphNode); } } } }
protected void EmitStringNode( Node node, ref Type inferedType, AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone) { if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { return; } dynamic sNode = node; if (!enforceTypeCheck || core.TypeSystem.IsHigherRank((int)PrimitiveType.kTypeString, inferedType.UID)) { inferedType.UID = (int)PrimitiveType.kTypeString; } if (core.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide) { EmitInstrConsole(ProtoCore.DSASM.kw.push, 0 + "[guide]"); StackValue opNumGuides = StackValue.BuildReplicationGuide(0); EmitPush(opNumGuides); } string value = (string)sNode.Value; StackValue svString = core.Heap.AllocateFixedString(value); if (core.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide) { EmitInstrConsole(kw.pushg, "\"" + value + "\""); EmitPushG(svString, node.line, node.col); } else { EmitInstrConsole(kw.push, "\"" + value + "\""); EmitPush(svString, node.line, node.col); } if (IsAssociativeArrayIndexing && graphNode != null && graphNode.isIndexingLHS) { SymbolNode literalSymbol = new SymbolNode(); literalSymbol.name = value; var dimNode = new AssociativeGraph.UpdateNode(); dimNode.symbol = literalSymbol; dimNode.nodeType = AssociativeGraph.UpdateNodeType.kLiteral; graphNode.dimensionNodeList.Add(dimNode); } }
/// <summary> /// Append the graphnode to the instruction stream and procedure nodes /// </summary> /// <param name="graphnode"></param> protected void PushGraphNode(AssociativeGraph.GraphNode graphnode) { codeBlock.instrStream.dependencyGraph.Push(graphnode); if (globalProcIndex != Constants.kGlobalScope) { localProcedure.GraphNodeList.Add(graphnode); } }
// // Comment Jun: Revised // // proc UpdateGraphNodeDependency(execnode) // foreach node in graphnodelist // if execnode.lhs is equal to node.lhs // if execnode.HasDependents() // if execnode.Dependents() is not equal to node.Dependents() // node.RemoveDependents() // end // end // end // end // end // private void UpdateGraphNodeDependency(AssociativeGraph.GraphNode gnode, AssociativeGraph.GraphNode executingNode) { if (gnode.UID >= executingNode.UID // for previous graphnodes || gnode.updateNodeRefList.Count == 0 || gnode.updateNodeRefList.Count != executingNode.updateNodeRefList.Count || gnode.isAutoGenerated) { return; } for (int n = 0; n < executingNode.updateNodeRefList.Count; ++n) { if (!gnode.updateNodeRefList[n].IsEqual(executingNode.updateNodeRefList[n])) { return; } } //if (executingNode.dependentList.Count > 0) { // if execnode.Dependents() is not equal to node.Dependents() // TODO Jun: Extend this check bool areDependentsEqual = false; if (!areDependentsEqual) { gnode.dependentList.Clear(); } } }
private void SetGraphNodeStackValueNull(AssociativeGraph.GraphNode graphNode) { StackValue svNull = StackUtils.BuildNull(); SetGraphNodeStackValue(graphNode, svNull); }
public void SetUpStepOverFunctionCalls(ProtoCore.Core core, ProcedureNode fNode, AssociativeGraph.GraphNode graphNode, bool hasDebugInfo) { int tempPC = DebugEntryPC; int limit = 0; // end pc of current expression InstructionStream istream; int pc = tempPC; if (core.DebugProps.InlineConditionOptions.isInlineConditional == true) { tempPC = InlineConditionOptions.startPc; limit = InlineConditionOptions.endPc; istream = core.DSExecutable.instrStreamList[InlineConditionOptions.instructionStream]; } else { pc = tempPC; istream = core.DSExecutable.instrStreamList[core.RunningBlock]; if (istream.language == Language.kAssociative) { limit = FindEndPCForAssocGraphNode(pc, istream, fNode, graphNode, core.Options.ExecuteSSA); //Validity.Assert(limit != ProtoCore.DSASM.Constants.kInvalidIndex); } else if (istream.language == Language.kImperative) { // Check for 'SETEXPUID' instruction to check for end of expression while (++pc < istream.instrList.Count) { Instruction instr = istream.instrList[pc]; if (instr.opCode == OpCode.SETEXPUID) { limit = pc; break; } } } } // Determine if this is outermost CALLR in the expression // until then do not restore any breakpoints // If outermost CALLR, restore breakpoints after end of expression pc = tempPC; int numNestedFunctionCalls = 0; while (++pc <= limit) { Instruction instr = istream.instrList[pc]; if (instr.opCode == OpCode.CALLR && instr.debug != null) { numNestedFunctionCalls++; } } if (numNestedFunctionCalls == 0) { // If this is the outermost function call core.Breakpoints.Clear(); core.Breakpoints.AddRange(AllbreakPoints); pc = tempPC; while (++pc <= limit) { Instruction instr = istream.instrList[pc]; // We still want to break at the closing brace of a function or ctor call or language block if (instr.debug != null && instr.opCode != OpCode.RETC && instr.opCode != OpCode.RETURN && (instr.opCode != OpCode.RETB)) { if (core.Breakpoints.Contains(instr)) core.Breakpoints.Remove(instr); } } } }
private int FindEndPCForAssocGraphNode(int tempPC, InstructionStream istream, ProcedureNode fNode, AssociativeGraph.GraphNode graphNode, bool handleSSATemps) { int limit = Constants.kInvalidIndex; //AssociativeGraph.GraphNode currentGraphNode = executingGraphNode; AssociativeGraph.GraphNode currentGraphNode = graphNode; //Validity.Assert(currentGraphNode != null); if (currentGraphNode != null) { if (tempPC < currentGraphNode.updateBlock.startpc || tempPC > currentGraphNode.updateBlock.endpc) { // return false; return Constants.kInvalidIndex; } int i = currentGraphNode.dependencyGraphListID; AssociativeGraph.GraphNode nextGraphNode = currentGraphNode; while (currentGraphNode.exprUID != ProtoCore.DSASM.Constants.kInvalidIndex && currentGraphNode.exprUID == nextGraphNode.exprUID) { limit = nextGraphNode.updateBlock.endpc; if (++i < istream.dependencyGraph.GraphList.Count) { nextGraphNode = istream.dependencyGraph.GraphList[i]; } else { break; } // Is it the next statement // This check will be deprecated on full SSA if (handleSSATemps) { if (!nextGraphNode.IsSSANode()) { // The next graphnode is nolonger part of the current statement // This is the end pc needed to run until nextGraphNode = istream.dependencyGraph.GraphList[i]; limit = nextGraphNode.updateBlock.endpc; break; } } } } // If graph node is null in associative lang block, it either is the very first property declaration or // it is the very first or only function call statement ("return = f();") inside the calling function // Here there's most likely a DEP or RETURN respectively after the function call // in which case, search for the instruction and set that as the new pc limit else if (!fNode.name.Contains(Constants.kSetterPrefix)) { while (++tempPC < istream.instrList.Count) { Instruction instr = istream.instrList[tempPC]; if (instr.opCode == OpCode.DEP || instr.opCode == OpCode.RETURN) { limit = tempPC; break; } } } return limit; }
/// <summary> /// Check if an update is triggered; /// Find all graph nodes whos dependents contain this symbol; /// Mark those nodes as dirty /// </summary> public int UpdateDependencyGraph( int exprUID, int modBlkId, bool isSSAAssign, AssociativeGraph.GraphNode executingGraphNode, bool propertyChanged = false) { int nodesMarkedDirty = 0; if (executingGraphNode == null) { return nodesMarkedDirty; } int classIndex = executingGraphNode.classIndex; int procIndex = executingGraphNode.procIndex; var graph = istream.dependencyGraph; var graphNodes = graph.GetGraphNodesAtScope(classIndex, procIndex); if (graphNodes == null) { return nodesMarkedDirty; } foreach (var graphNode in graphNodes) { // // Comment Jun: // This is clarifying the intention that if the graphnode is within the same SSA expression, we still allow update // bool allowUpdateWithinSSA = true; if (!allowUpdateWithinSSA || (propertyChanged && graphNode == Properties.executingGraphNode)) { continue; } foreach (var noderef in executingGraphNode.updateNodeRefList) { ProtoCore.AssociativeGraph.GraphNode matchingNode = null; if (!graphNode.DependsOn(noderef, ref matchingNode)) { continue; } // @keyu: if we are modifying an object's property, e.g., // // foo.id = 42; // // both dependent list and update list of the corresponding // graph node contains "foo" and "id", so if property "id" // is changed, this graph node will be re-executed and the // value of "id" is incorrectly set back to old value. if (propertyChanged) { var depUpdateNodeRef = graphNode.dependentList[0].updateNodeRefList[0]; if (graphNode.updateNodeRefList.Count == 1) { var updateNodeRef = graphNode.updateNodeRefList[0]; if (depUpdateNodeRef.IsEqual(updateNodeRef)) { continue; } } } // // Comment Jun: We dont want to cycle between such statements: // // a1.a = 1; // a1.a = 10; // Validity.Assert(null != matchingNode); bool isLHSModification = matchingNode.isLHSNode; bool isUpdateable = matchingNode.IsUpdateableBy(noderef); // isSSAAssign means this is the graphnode of the final SSA assignment // Overrride this if allowing within SSA update // TODO Jun: Remove this code when SSA is completely enabled bool allowSSADownstream = graphNode.UID > executingGraphNode.UID; // Comment Jun: // If the triggered dependent graphnode is LHS // and... // the triggering node (executing graphnode) if (isLHSModification && !isUpdateable) { break; } // TODO Jun: Optimization - Reimplement update delta evaluation using registers //if (IsNodeModified(EX, FX)) if (exprUID != graphNode.exprUID && modBlkId != graphNode.modBlkUID) { UpdateModifierBlockDependencyGraph(graphNode); } else if (allowSSADownstream || isSSAAssign || (exprUID != graphNode.exprUID && modBlkId == Constants.kInvalidIndex && graphNode.modBlkUID == Constants.kInvalidIndex) ) { if (graphNode.isCyclic) { // If the graphnode is cyclic, mark it as not dirst so it wont get executed // Sets its cyclePoint graphnode to be not dirty so it also doesnt execute. // The cyclepoint is the other graphNode that the current node cycles with graphNode.isDirty = false; if (null != graphNode.cyclePoint) { graphNode.cyclePoint.isDirty = false; graphNode.cyclePoint.isCyclic = true; } } else if (!graphNode.isDirty) { if (core.Options.ElementBasedArrayUpdate) { UpdateDimensionsForGraphNode(graphNode, matchingNode, executingGraphNode); } graphNode.isDirty = true; graphNode.forPropertyChanged = propertyChanged; nodesMarkedDirty++; } } } } return nodesMarkedDirty; }
protected int DfsEmitArrayIndexHeap(Node node, AssociativeGraph.GraphNode graphNode = null, ProtoCore.AST.Node parentNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone) { int indexCnt = 0; Debug.Assert(node is ProtoCore.AST.AssociativeAST.ArrayNode || node is ProtoCore.AST.ImperativeAST.ArrayNode); IsAssociativeArrayIndexing = true; dynamic arrayNode = node; while (arrayNode is ProtoCore.AST.AssociativeAST.ArrayNode || arrayNode is ProtoCore.AST.ImperativeAST.ArrayNode) { ++indexCnt; dynamic array = arrayNode; ProtoCore.Type lastType = new ProtoCore.Type(); lastType.UID = (int)PrimitiveType.kTypeVoid; lastType.IsIndexable = false; DfsTraverse(array.Expr, ref lastType, false, graphNode, subPass, parentNode); arrayNode = array.Type; } IsAssociativeArrayIndexing = false; return indexCnt; }
protected void EmitStringNode( Node node, ref Type inferedType, AssociativeGraph.GraphNode graphNode = null, AssociativeSubCompilePass subPass = AssociativeSubCompilePass.kNone) { if (subPass == AssociativeSubCompilePass.kUnboundIdentifier) { return; } dynamic sNode = node; if (!enforceTypeCheck || core.TypeSystem.IsHigherRank((int)PrimitiveType.kTypeString, inferedType.UID)) { inferedType.UID = (int)PrimitiveType.kTypeString; } Byte[] utf8bytes = EncodingUtils.UTF8StringToUTF8Bytes((String)sNode.value); String value = Encoding.UTF8.GetString(utf8bytes); foreach (char ch in value) { String strValue = "'" + ch + "'"; EmitInstrConsole(kw.push, strValue); StackValue op = StackValue.BuildChar(ch); EmitPush(op, node.line, node.col); } if (IsAssociativeArrayIndexing && graphNode != null && graphNode.isIndexingLHS) { SymbolNode literalSymbol = new SymbolNode(); literalSymbol.name = value; var dimNode = new AssociativeGraph.UpdateNode(); dimNode.symbol = literalSymbol; dimNode.nodeType = AssociativeGraph.UpdateNodeType.kLiteral; graphNode.dimensionNodeList.Add(dimNode); } EmitInstrConsole(kw.alloca, value.Length.ToString()); EmitPopString(value.Length); }
private void SetGraphNodeStackValue(AssociativeGraph.GraphNode graphNode, StackValue sv) { Validity.Assert(!graphNode.isReturn); // TODO Jun: Expand me to handle complex ident lists SymbolNode symbol = graphNode.updateNodeRefList[0].nodeList[0].symbol; Validity.Assert(null != symbol); rmem.SetSymbolValue(symbol, sv); }
protected int DfsEmitArrayIndexHeap(Node node, AssociativeGraph.GraphNode graphNode = null, ProtoCore.AST.Node parentNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone) { int indexCnt = 0; Validity.Assert(node is ProtoCore.AST.AssociativeAST.ArrayNode || node is ProtoCore.AST.ImperativeAST.ArrayNode); IsAssociativeArrayIndexing = true; dynamic arrayNode = node; while (arrayNode is ProtoCore.AST.AssociativeAST.ArrayNode || arrayNode is ProtoCore.AST.ImperativeAST.ArrayNode) { ++indexCnt; dynamic array = arrayNode; ProtoCore.Type lastType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0); DfsTraverse(array.Expr, ref lastType, false, graphNode, subPass, parentNode); arrayNode = array.Type; } IsAssociativeArrayIndexing = false; return indexCnt; }
/// <summary> /// Logs the unbound variable warning and sets the unbound symbol /// </summary> /// <param name="unboundSymbol"></param> /// <param name="message"></param> /// <param name="fileName"></param> /// <param name="line"></param> /// <param name="col"></param> /// <param name="graphNode"></param> public void LogUnboundVariableWarning( SymbolNode unboundSymbol, string message, string fileName = null, int line = -1, int col = -1, AssociativeGraph.GraphNode graphNode = null) { LogWarning(BuildData.WarningID.IdUnboundIdentifier, message, core.CurrentDSFileName, line, col, graphNode, unboundSymbol); }
/// <summary> /// Generates unique identifier for the callsite associated with the graphnode /// </summary> /// <param name="graphNode"></param> /// <param name="procNode"></param> protected void GenerateCallsiteIdentifierForGraphNode(AssociativeGraph.GraphNode graphNode, string procName) { // This instance count in which the function appears lexically in the current guid // This must be stored and incremented int functionCallInstance = 0; // Cache this function call instance count // This is the count of the number of times in which this callsite appears in the program int callInstance = 0; if (!core.CallsiteGuidMap.TryGetValue(graphNode.guid, out callInstance)) { // The guid doesnt exist yet core.CallsiteGuidMap.Add(graphNode.guid, 0); } else { // Increment the current count core.CallsiteGuidMap[graphNode.guid]++; functionCallInstance = core.CallsiteGuidMap[graphNode.guid]; } // Build the unique ID for a callsite string callsiteIdentifier = procName + "_InClassDecl" + globalClassIndex + "_InFunctionScope" + globalProcIndex + "_Instance" + functionCallInstance.ToString() + "_" + graphNode.guid.ToString(); // TODO Jun: Address this in MAGN-3774 // The current limitation is retrieving the cached trace data for multiple callsites in a single CBN // after modifying the lines of code. graphNode.CallsiteIdentifier = callsiteIdentifier; }
protected void BuildRealDependencyForIdentList(AssociativeGraph.GraphNode graphNode) { // Push all dependent pointers ProtoCore.AST.AssociativeAST.IdentifierListNode identList = BuildIdentifierList(ssaPointerList); // Comment Jun: perhaps this can be an assert? if (null != identList) { ProtoCore.Type type = new ProtoCore.Type(); type.UID = globalClassIndex; ProtoCore.AssociativeGraph.UpdateNodeRef nodeRef = new AssociativeGraph.UpdateNodeRef(); int functionIndex = globalProcIndex; DFSGetSymbolList_Simple(identList, ref type, ref functionIndex, nodeRef); if (null != graphNode && nodeRef.nodeList.Count > 0) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.updateNodeRefList.Add(nodeRef); graphNode.PushDependent(dependentNode); } } }
private void BuildSSADependency(Node node, AssociativeGraph.GraphNode graphNode) { // Jun Comment: set the graphNode dependent as this identifier list ProtoCore.Type type = new ProtoCore.Type(); type.UID = globalClassIndex; ProtoCore.AssociativeGraph.UpdateNodeRef nodeRef = new AssociativeGraph.UpdateNodeRef(); DFSGetSymbolList(node, ref type, nodeRef); if (null != graphNode && nodeRef.nodeList.Count > 0) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.updateNodeRefList.Add(nodeRef); graphNode.PushDependent(dependentNode); } }
public void LogSemanticError(string msg, string fileName = null, int line = -1, int col = -1, AssociativeGraph.GraphNode graphNode = null) { if (logErrors) { System.Console.WriteLine("{0}({1},{2}) Error:{3}", fileName, line, col, msg); } if (core.Options.IsDeltaExecution) { } BuildData.ErrorEntry errorEntry = new BuildData.ErrorEntry { FileName = fileName, Message = msg, Line = line, Column = col }; errors.Add(errorEntry); OutputMessage outputmessage = new OutputMessage(OutputMessage.MessageType.Error, msg.Trim(), fileName, line, col); if (MessageHandler != null) { MessageHandler.Write(outputmessage); if (WebMsgHandler != null) { OutputMessage webOutputMsg = new OutputMessage(OutputMessage.MessageType.Error, msg.Trim(), "", line, col); WebMsgHandler.Write(webOutputMsg); } if (!outputmessage.Continue) throw new BuildHaltException(msg); } throw new BuildHaltException(msg); }
/// <summary> /// Audits the class table for multiple symbol definition. /// </summary> /// <param name="status">BuildStatus to log the warnings if /// multiple symbol found.</param> /// /// <param name="guid">Guid of node to which warning corresponds</param> public void AuditMultipleDefinition(BuildStatus status, AssociativeGraph.GraphNode graphNode) { var names = symbolTable.GetAllSymbolNames(); if (names.Count == symbolTable.GetSymbolCount()) return; foreach (var name in names) { var symbols = symbolTable.GetAllSymbols(name); if (symbols.Count > 1) { string message = string.Format(Resources.kMultipleSymbolFound, name, ""); foreach (var symbol in symbols) { message += ", " + symbol.FullName; } status.LogWarning(BuildData.WarningID.MultipleSymbolFound, message, graphNode: graphNode); } } }
public void LogWarning(BuildData.WarningID warningID, string message, string fileName = null, int line = -1, int col = -1, AssociativeGraph.GraphNode graphNode = null) { var entry = new BuildData.WarningEntry { ID = warningID, Message = message, Line = line, Column = col, GraphNodeGuid = graphNode == null ? default(Guid) : graphNode.guid, AstID = graphNode == null? DSASM.Constants.kInvalidIndex : graphNode.OriginalAstID, FileName = fileName }; warnings.Add(entry); if (core.Options.IsDeltaExecution) { } if (LogWarnings) { System.Console.WriteLine("{0}({1},{2}) Warning:{3}", fileName, line, col, message); OutputMessage outputmessage = new OutputMessage(OutputMessage.MessageType.Warning, message.Trim(), fileName, line, col); if (MessageHandler != null) { MessageHandler.Write(outputmessage); if (WebMsgHandler != null) { OutputMessage webOutputMsg = new OutputMessage(OutputMessage.MessageType.Warning, message.Trim(), "", line, col); WebMsgHandler.Write(webOutputMsg); } if (!outputmessage.Continue) throw new BuildHaltException(message); } } }
private void SetGraphNodeStackValue(AssociativeGraph.GraphNode graphNode, StackValue sv) { Validity.Assert(!graphNode.isReturn); // TODO Jun: Expand me to handle complex ident lists ProtoCore.DSASM.SymbolNode symbol = graphNode.updateNodeRefList[0].nodeList[0].symbol; Validity.Assert(null != symbol); rmem.SetStackData(symbol.runtimeTableIndex, symbol.symbolTableIndex, symbol.classScope, sv); }
private bool HasCyclicDependency(AssociativeGraph.GraphNode node) { return IsExecutedTooManyTimes(node, runtimeCore.Options.kDynamicCycleThreshold); }
/// <summary> /// To implement element based update: when an element in an array is /// updated, only updates the corresponding element in its updatee. /// /// For example: /// /// a = b; // b = {1, 2, 3}; /// b[0] = 0; // should only update a[0]. /// /// The basic idea is checking the dimension node in the executing /// graph node (i.e., [0] in the executing graph node b[0] = 0), and /// apply thsi dimension to the dirty graph node (i.e., a = b), so when /// executing that dirty graph node, [0] will be applied to all POP and /// PUSH instructions. So for statement a = b; essentially the VM /// will do /// /// push b[0]; /// pop to a[0]; /// /// Now this function only considers about the simpliest case, i.e., /// only variable is on the RHS of expression because a function may /// involve array promotion, type conversion, replication guide and so /// on. -- Yu Ke /// </summary> /// <param name="graphNode">The graph node that is to be update</param> /// <param name="matchingNode">Matching node</param> /// <param name="executingGraphNode">The executing graph node</param> private void UpdateDimensionsForGraphNode( AssociativeGraph.GraphNode graphNode, AssociativeGraph.GraphNode matchingNode, AssociativeGraph.GraphNode executingGraphNode) { Validity.Assert(graphNode != null && executingGraphNode != null); graphNode.updateDimensions.Clear(); var updateDimNodes = executingGraphNode.dimensionNodeList; if (updateDimNodes == null) { return; } // We may take replication control into account in the future. // But right now let's just skip it. var rcInstructions = executingGraphNode.replicationControl.Instructions; // Update node list can be a, b, c for the case like: // a.b.c[0] = ... // // Let's only support the simplest case now: // // a[0] = ... Validity.Assert(matchingNode.updateNodeRefList != null && matchingNode.updateNodeRefList.Count > 0); var depNodes = matchingNode.updateNodeRefList[0].nodeList; if (depNodes == null || depNodes.Count != 1) { return; } if (graphNode.firstProc != null && graphNode.firstProc.argTypeList.Count != 0) { // Skip the case that function on RHS takes over 1 parameters -- // there is potential replication guide which hasn't been supported // yet right now. // // x = foo(a, b); // a[0] = ... // if (graphNode.firstProc.argTypeList.Count > 1) { return; } // Not support function parameter whose rank >= 1 // // def foo(a:int[]) // { // ... // } // a = {1, 2, 3}; // b = a; // a[0] = 0; // b[0] = foo(a[0]) doesn't work! // if (graphNode.firstProc.argTypeList[0].rank >= 1) { return; } } var depDimNodes = depNodes.Last().dimensionNodeList; int dimIndex = 0; if (depDimNodes != null) { // Try to match all dependent dimensions. For example: // // ... = a[0][i]; // a[0][j] = ...; // // Here [i], [j] doesn't match, even they may have same value. // Or, // // ... = a[0][1][2]; // a[0][1] = ...; // // where [2] hasn't been matched yet. // // For these cases, right now just do full update. if (depDimNodes.Count > updateDimNodes.Count) { return; } // For the case: // // x = a[0]; // a[0] = 1; // // We don't want to apply array indexing [0] to a[0] again. But we // do want to apply array indexing [1] for the following case: // // x = a[0]; // a[0][1] = 1; --> x[1] = a[0][1] // // So basically we should eliminate the common part. for (; dimIndex < depDimNodes.Count; ++dimIndex) { var dimSymbol1 = depDimNodes[dimIndex].symbol; var dimSymbol2 = updateDimNodes[dimIndex].symbol; if (!dimSymbol1.IsEqualAtScope(dimSymbol2)) { return; } } } for (; dimIndex < updateDimNodes.Count; ++dimIndex) { var dimNode = updateDimNodes[dimIndex]; var dimSymbol = dimNode.symbol; switch (dimNode.nodeType) { case AssociativeGraph.UpdateNodeType.kSymbol: { var opSymbol = StackValue.Null; if (dimSymbol.classScope != Constants.kInvalidIndex && dimSymbol.functionIndex == Constants.kInvalidIndex) { opSymbol = StackValue.BuildMemVarIndex(dimSymbol.symbolTableIndex); } else { opSymbol = StackValue.BuildVarIndex(dimSymbol.symbolTableIndex); } var dimValue = GetOperandData(dimSymbol.codeBlockId, opSymbol, StackValue.BuildInt(dimSymbol.classScope)); graphNode.updateDimensions.Add(dimValue); break; } case AssociativeGraph.UpdateNodeType.kLiteral: { int dimValue = Constants.kInvalidIndex; if (Int32.TryParse(dimSymbol.name, out dimValue)) { graphNode.updateDimensions.Add(StackValue.BuildInt(dimValue)); } else { // No idea for this dimension, just terminate. return; } break; } default: // No idea to how to handle method and other node types, // just stop here at least we can get partial element // based array update. return; } } }
private bool IsExecutedTooManyTimes(AssociativeGraph.GraphNode node, int limit) { Validity.Assert(null != node); return (node.counter > limit); }
// // Comment Jun: Revised // // proc UpdateGraphNodeDependency(execnode) // foreach node in graphnodelist // if execnode.lhs is equal to node.lhs // if execnode.HasDependents() // if execnode.Dependents() is not equal to node.Dependents() // node.RemoveDependents() // end // end // end // end // end // private void UpdateGraphNodeDependency(AssociativeGraph.GraphNode gnode, AssociativeGraph.GraphNode executingNode) { if (gnode.UID >= executingNode.UID // for previous graphnodes || gnode.updateNodeRefList.Count == 0 || gnode.updateNodeRefList.Count != executingNode.updateNodeRefList.Count || gnode.isAutoGenerated) { return; } for (int n = 0; n < executingNode.updateNodeRefList.Count; ++n) { if (!gnode.updateNodeRefList[n].IsEqual(executingNode.updateNodeRefList[n])) { return; } if (gnode.guid == executingNode.guid && gnode.ssaExprID == executingNode.ssaExprID) //if (gnode.exprUID == executingNode.exprUID) { // These nodes are within the same expression, no redifinition can occur return; } } //if (executingNode.dependentList.Count > 0) { // if execnode.Dependents() is not equal to node.Dependents() // TODO Jun: Extend this check bool areDependentsEqual = false; if (!areDependentsEqual) { gnode.dependentList.Clear(); // GC all the temporaries associated with the redefined variable // Given: // a = A.A() // a = 10 // // Transforms to: // // t0 = A.A() // a = t0 // a = 10 // Redefinition of 'a' will GC 't0' // // Another example // Given: // a = {A.A()} // a = 10 // // Transforms to: // // t0 = A.A() // t1 = {t0} // a = t1 // a = 10 // Redefinition of 'a' will GC t0 and t1 // GCAnonymousSymbols(gnode.symbolListWithinExpression); gnode.symbolListWithinExpression.Clear(); } } }
protected void EmitStringNode( Node node, ref Type inferedType, AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone) { if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { return; } dynamic sNode = node; if (!enforceTypeCheck || core.TypeSystem.IsHigherRank((int)PrimitiveType.kTypeString, inferedType.UID)) { inferedType.UID = (int)PrimitiveType.kTypeString; } string value = (string)sNode.Value; StackValue svString = core.Heap.AllocateFixedString(value); EmitOpWithEmptyReplicationGuide(emitReplicationGuide, svString, "\"" + value + "\"", node); if (IsAssociativeArrayIndexing && graphNode != null && graphNode.isIndexingLHS) { SymbolNode literalSymbol = new SymbolNode(); literalSymbol.name = value; var dimNode = new AssociativeGraph.UpdateNode(); dimNode.symbol = literalSymbol; dimNode.nodeType = AssociativeGraph.UpdateNodeType.kLiteral; graphNode.dimensionNodeList.Add(dimNode); } }