public int GetConversionDistance(List <StackValue> reducedParamSVs, ProtoCore.DSASM.ClassTable classTable, bool allowArrayPromotion, RuntimeCore runtimeCore) { // If the replication strategy allows array promotion, first check for the case // where it could be disabled using the [AllowArrayPromotion(false)] attribute // and if so set it from the attribute. if (allowArrayPromotion) { var ma = procedureNode.MethodAttribute; if (ma != null) { allowArrayPromotion = ma.AllowArrayPromotion; } } int dist = ComputeTypeDistance(reducedParamSVs, classTable, runtimeCore, allowArrayPromotion); if (dist >= 0 && dist != (int)ProcedureDistance.MaxDistance) //Is it possible to convert to this type? { if (!FunctionGroup.CheckInvalidArrayCoersion(this, reducedParamSVs, classTable, runtimeCore, allowArrayPromotion)) { return(dist); } } return((int)ProcedureDistance.InvalidDistance); }
public void LogMethodResolutionWarning(FunctionGroup funcGroup, string methodName, int classScope = Constants.kGlobalScope, List <StackValue> arguments = null) { string message; string propertyName; Operator op; var qualifiedMethodName = methodName; if (classScope != Constants.kGlobalScope) { var className = runtimeCore.DSExecutable.classTable.ClassNodes[classScope].Name; var classNameSimple = className.Split('.').Last(); qualifiedMethodName = classNameSimple + "." + methodName; } if (CoreUtils.TryGetPropertyName(methodName, out propertyName)) { if (classScope != Constants.kGlobalScope) { string classname = runtimeCore.DSExecutable.classTable.ClassNodes[classScope].Name; message = string.Format(Resources.kPropertyOfClassNotFound, propertyName, classname); } else { message = string.Format(Resources.kPropertyNotFound, propertyName); } } else if (CoreUtils.TryGetOperator(methodName, out op)) { var strOp = Op.GetOpSymbol(op); message = String.Format(Resources.kMethodResolutionFailureForOperator, strOp, GetTypeName(arguments[0]), GetTypeName(arguments[1])); } else if (funcGroup.FunctionEndPoints.Count == 1) // non-overloaded case { var argsJoined = string.Join(", ", arguments.Select(GetTypeName)); var fep = funcGroup.FunctionEndPoints[0]; var formalParamsJoined = string.Join(", ", fep.FormalParams.Select(x => x.ToShortString())); message = string.Format(Resources.NonOverloadMethodResolutionError, qualifiedMethodName, formalParamsJoined, argsJoined); } else // overloaded case { var argsJoined = string.Join(", ", arguments.Select(GetTypeName)); message = string.Format(Resources.kMethodResolutionFailureWithTypes, qualifiedMethodName, argsJoined); } LogWarning(WarningID.MethodResolutionFailure, message); }
public int GetConversionDistance(List <StackValue> reducedParamSVs, ProtoCore.DSASM.ClassTable classTable, bool allowArrayPromotion, RuntimeCore runtimeCore) { int dist = ComputeTypeDistance(reducedParamSVs, classTable, runtimeCore, allowArrayPromotion); if (dist >= 0 && dist != (int)ProcedureDistance.kMaxDistance) //Is it possible to convert to this type? { if (!FunctionGroup.CheckInvalidArrayCoersion(this, reducedParamSVs, classTable, runtimeCore, allowArrayPromotion)) { return(dist); } } return((int)ProcedureDistance.kInvalidDistance); }
//Repication /// <summary> /// Excecute an arbitrary depth replication using the full slow path algorithm /// </summary> /// <param name="functionEndPoint"> </param> /// <param name="c"></param> /// <param name="formalParameters"></param> /// <param name="replicationInstructions"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <returns></returns> private StackValue ExecWithRISlowPath(List<FunctionEndPoint> functionEndPoint, ProtoCore.Runtime.Context c, List<StackValue> formalParameters, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, Core core, FunctionGroup funcGroup, SingleRunTraceData previousTraceData, SingleRunTraceData newTraceData) { if (core.Options.ExecutionMode == ExecutionMode.Parallel) throw new NotImplementedException("Parallel mode disabled: {BF417AD5-9EA9-4292-ABBC-3526FC5A149E}"); //Recursion base case if (replicationInstructions.Count == 0) return ExecWithZeroRI(functionEndPoint, c, formalParameters, stackFrame, core, funcGroup, previousTraceData, newTraceData); //Get the replication instruction that this call will deal with ReplicationInstruction ri = replicationInstructions[0]; if (ri.Zipped) { ZipAlgorithm algorithm = ri.ZipAlgorithm; //For each item in this plane, an array of the length of the minimum will be constructed //The size of the array will be the minimum size of the passed arrays List<int> repIndecies = ri.ZipIndecies; //this will hold the heap elements for all the arrays that are going to be replicated over List<StackValue[]> parameters = new List<StackValue[]>(); int retSize; switch (algorithm) { case ZipAlgorithm.Shortest: retSize = Int32.MaxValue; //Search to find the smallest break; case ZipAlgorithm.Longest: retSize = Int32.MinValue; //Search to find the largest break; default: throw new ReplicationCaseNotCurrentlySupported("Selected algorithm not supported"); } foreach (int repIndex in repIndecies) { StackValue[] subParameters = null; if (formalParameters[repIndex].IsArray) { subParameters = ArrayUtils.GetValues(formalParameters[repIndex], core); } else { subParameters = new StackValue[] { formalParameters[repIndex] }; } parameters.Add(subParameters); switch (algorithm) { case ZipAlgorithm.Shortest: retSize = Math.Min(retSize, subParameters.Length); //We need the smallest array break; case ZipAlgorithm.Longest: retSize = Math.Max(retSize, subParameters.Length); //We need the longest array break; } } StackValue[] retSVs = new StackValue[retSize]; SingleRunTraceData retTrace = newTraceData; retTrace.NestedData = new List<SingleRunTraceData>(); //this will shadow the SVs as they are created //Populate out the size of the list with default values //@TODO:Luke perf optimisation here for (int i = 0; i < retSize; i++) retTrace.NestedData.Add(new SingleRunTraceData()); for (int i = 0; i < retSize; i++) { SingleRunTraceData lastExecTrace = new SingleRunTraceData(); if (previousTraceData.HasNestedData && i < previousTraceData.NestedData.Count) { //There was previous data that needs loading into the cache lastExecTrace = previousTraceData.NestedData[i]; } else { //We're off the edge of the previous trace window //So just pass in an empty block lastExecTrace = new SingleRunTraceData(); } //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); for (int repIi = 0; repIi < repIndecies.Count; repIi++) { switch (algorithm) { case ZipAlgorithm.Shortest: //If the shortest algorithm is selected this would newFormalParams[repIndecies[repIi]] = parameters[repIi][i]; break; case ZipAlgorithm.Longest: int length = parameters[repIi].Length; if (i < length) { newFormalParams[repIndecies[repIi]] = parameters[repIi][i]; } else { newFormalParams[repIndecies[repIi]] = parameters[repIi].Last(); } break; } } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); SingleRunTraceData cleanRetTrace = new SingleRunTraceData(); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, core, funcGroup, lastExecTrace, cleanRetTrace); retTrace.NestedData[i] = cleanRetTrace; } StackValue ret = HeapUtils.StoreArray(retSVs, null, core); GCUtils.GCRetain(ret, core); return ret; } else { //With a cartesian product over an array, we are going to create an array of n //where the n is the product of the next item //We will call the subsequent reductions n times int cartIndex = ri.CartesianIndex; //this will hold the heap elements for all the arrays that are going to be replicated over bool supressArray = false; int retSize; StackValue[] parameters = null; if (formalParameters[cartIndex].IsArray) { parameters = ArrayUtils.GetValues(formalParameters[cartIndex], core); retSize = parameters.Length; } else { retSize = 1; supressArray = true; } StackValue[] retSVs = new StackValue[retSize]; SingleRunTraceData retTrace = newTraceData; retTrace.NestedData = new List<SingleRunTraceData>(); //this will shadow the SVs as they are created //Populate out the size of the list with default values //@TODO:Luke perf optimisation here for (int i = 0; i < retSize; i++) { retTrace.NestedData.Add(new SingleRunTraceData()); } if (supressArray) { List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); return ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, core, funcGroup, previousTraceData, newTraceData); } //Now iterate over each of these options for (int i = 0; i < retSize; i++) { #if __PROTOTYPE_ARRAYUPDATE_FUNCTIONCALL // Comment Jun: If the array pointer passed in was of type DS Null, // then it means this is the first time the results are being computed. bool executeAll = c.ArrayPointer.IsNull; if (executeAll || ProtoCore.AssociativeEngine.ArrayUpdate.IsIndexInElementUpdateList(i, c.IndicesIntoArgMap)) { List<List<int>> prevIndexIntoList = new List<List<int>>(); foreach (List<int> dimList in c.IndicesIntoArgMap) { prevIndexIntoList.Add(new List<int>(dimList)); } StackValue svPrevPtr = c.ArrayPointer; if (!executeAll) { c.IndicesIntoArgMap = ProtoCore.AssociativeEngine.ArrayUpdate.UpdateIndexIntoList(i, c.IndicesIntoArgMap); c.ArrayPointer = ProtoCore.Utils.ArrayUtils.GetArrayElementAt(c.ArrayPointer, i, core); } //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); if (he != null) { //It was an array pack the arg with the current value newFormalParams[cartIndex] = he.Stack[i]; } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, core, funcGroup); // Restore the context properties for arrays c.IndicesIntoArgMap = new List<List<int>>(prevIndexIntoList); c.ArrayPointer = svPrevPtr; } else { retSVs[i] = ProtoCore.Utils.ArrayUtils.GetArrayElementAt(c.ArrayPointer, i, core); } #else //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); if (parameters != null) { //It was an array pack the arg with the current value newFormalParams[cartIndex] = parameters[i]; } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); SingleRunTraceData lastExecTrace; if (previousTraceData.HasNestedData && i < previousTraceData.NestedData.Count) { //There was previous data that needs loading into the cache lastExecTrace = previousTraceData.NestedData[i]; } else if (previousTraceData.HasData && i == 0) { //We've moved up one dimension, and there was a previous run lastExecTrace = new SingleRunTraceData(); lastExecTrace.Data = previousTraceData.GetLeftMostData(); } else { //We're off the edge of the previous trace window //So just pass in an empty block lastExecTrace = new SingleRunTraceData(); } //previousTraceData = lastExecTrace; SingleRunTraceData cleanRetTrace = new SingleRunTraceData(); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, core, funcGroup, lastExecTrace, cleanRetTrace); retTrace.NestedData[i] = cleanRetTrace; // retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, core, // funcGroup, previousTraceData, newTraceData); #endif } StackValue ret = HeapUtils.StoreArray(retSVs, null, core); GCUtils.GCRetain(ret, core); return ret; } }
//Single function call /// <summary> /// Dispatch without replication /// </summary> private StackValue ExecWithZeroRI(List<FunctionEndPoint> functionEndPoint, ProtoCore.Runtime.Context c, List<StackValue> formalParameters, StackFrame stackFrame, Core core, FunctionGroup funcGroup, SingleRunTraceData previousTraceData, SingleRunTraceData newTraceData) { //@PERF: Todo add a fast path here for the case where we have a homogenious array so we can directly dispatch FunctionEndPoint finalFep = SelectFinalFep(c, functionEndPoint, formalParameters, stackFrame, core); if (functionEndPoint == null) { core.RuntimeStatus.LogWarning(ProtoCore.RuntimeData.WarningID.kMethodResolutionFailure, "Function dispatch could not be completed {2EB39E1B-557C-4819-94D8-CF7C9F933E8A}"); return StackValue.Null; } if (core.Options.IDEDebugMode && core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { DebugFrame debugFrame = core.DebugProps.DebugStackFrame.Peek(); debugFrame.FinalFepChosen = finalFep; } List<StackValue> coercedParameters = finalFep.CoerceParameters(formalParameters, core); // Correct block id where the function is defined. StackValue funcBlock = stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock); funcBlock.opdata = finalFep.BlockScope; stackFrame.SetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock, funcBlock); //TraceCache -> TLS //Extract left most high-D pack Object traceD = previousTraceData.GetLeftMostData(); if (traceD != null) { //There was data associated with the previous execution, push this into the TLS Dictionary<string, object> dataDict = new Dictionary<string, object>(); dataDict.Add(TRACE_KEY, traceD); TraceUtils.SetObjectToTLS(dataDict); } else { //There was no trace data for this run TraceUtils.ClearAllKnownTLSKeys(); } //EXECUTE StackValue ret = finalFep.Execute(c, coercedParameters, stackFrame, core); if (StackUtils.IsNull(ret)) { //wipe the trace cache TraceUtils.ClearTLSKey(TRACE_KEY); } //TLS -> TraceCache Dictionary<String, Object> traceRet = TraceUtils.GetObjectFromTLS(); if (traceRet.ContainsKey(TRACE_KEY)) { Object val = traceRet[TRACE_KEY]; newTraceData.Data = val; } // An explicit call requires return coercion at the return instruction if (ret.optype != AddressType.ExplicitCall) { ret = PerformReturnTypeCoerce(finalFep, core, ret); } return ret; }
private StackValue Execute(List<FunctionEndPoint> functionEndPoint, ProtoCore.Runtime.Context c, List<StackValue> formalParameters, List<ReplicationInstruction> replicationInstructions, DSASM.StackFrame stackFrame, Core core, FunctionGroup funcGroup) { for (int i = 0; i < formalParameters.Count; ++i) { GCUtils.GCRetain(formalParameters[i], core); } StackValue ret; if (replicationInstructions.Count == 0) { c.IsReplicating = false; SingleRunTraceData singleRunTraceData; //READ TRACE FOR NON-REPLICATED CALL //Lookup the trace data in the cache if (invokeCount < traceData.Count) { singleRunTraceData = (SingleRunTraceData) traceData[invokeCount]; } else { //We don't have any previous stored data for the previous invoke calls, so //gen an empty packet and push it through singleRunTraceData = new SingleRunTraceData(); } SingleRunTraceData newTraceData = new SingleRunTraceData(); ret = ExecWithZeroRI(functionEndPoint, c, formalParameters, stackFrame, core, funcGroup, singleRunTraceData, newTraceData); //newTraceData is update with the trace cache assocaite with the single shot executions if (invokeCount < traceData.Count) traceData[invokeCount] = newTraceData; else { traceData.Add(newTraceData); } } else //replicated call { //Extract the correct run data from the trace cache here //This is the thing that will get unpacked from the datastore SingleRunTraceData singleRunTraceData; SingleRunTraceData newTraceData = new SingleRunTraceData(); //Lookup the trace data in the cache if (invokeCount < traceData.Count) { singleRunTraceData = (SingleRunTraceData)traceData[invokeCount]; } else { //We don't have any previous stored data for the previous invoke calls, so //gen an empty packet and push it through singleRunTraceData = new SingleRunTraceData(); } c.IsReplicating = true; ret = ExecWithRISlowPath(functionEndPoint, c, formalParameters, replicationInstructions, stackFrame, core, funcGroup, singleRunTraceData, newTraceData); //Do a trace save here if (invokeCount < traceData.Count) traceData[invokeCount] = newTraceData; else { traceData.Add(newTraceData); } } // Explicit calls require the GC of arguments in the function return instruction if (!ret.IsExplicitCall) { for (int i = 0; i < formalParameters.Count; ++i) { GCUtils.GCRelease(formalParameters[i], core); } } invokeCount++; //We've completed this invocation if (ret.IsNull) return ret; //It didn't return a value return ret; }
private void EmitFunctionDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone) { bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.DSASM.AssociativeCompilePass.kGlobalFuncBody == compilePass; bool parseMemberFunctionBody = ProtoCore.DSASM.Constants.kGlobalScope != globalClassIndex && ProtoCore.DSASM.AssociativeCompilePass.kClassMemFuncBody == compilePass; FunctionDefinitionNode funcDef = node as FunctionDefinitionNode; localFunctionDefNode = funcDef; if (funcDef.IsAssocOperator) { isAssocOperator = true; } else { isAssocOperator = false; } bool hasReturnStatement = false; ProtoCore.DSASM.CodeBlockType origCodeBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingGlobalFunctionSig() || IsParsingMemberFunctionSig()) { Debug.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.name = funcDef.Name; localProcedure.pc = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.localCount = 0; // Defer till all locals are allocated localProcedure.returntype.UID = compileStateTracker.TypeSystem.GetType(funcDef.ReturnType.Name); if (localProcedure.returntype.UID == (int)PrimitiveType.kInvalidType) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kReturnTypeUndefined, funcDef.ReturnType.Name, funcDef.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kTypeUndefined, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col); localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; } localProcedure.returntype.IsIndexable = funcDef.ReturnType.IsIndexable; localProcedure.returntype.rank = funcDef.ReturnType.rank; localProcedure.isConstructor = false; localProcedure.isStatic = funcDef.IsStatic; localProcedure.runtimeIndex = codeBlock.codeBlockId; localProcedure.access = funcDef.access; localProcedure.isExternal = funcDef.IsExternLib; localProcedure.isAutoGenerated = funcDef.IsAutoGenerated; localProcedure.classScope = globalClassIndex; localProcedure.isAssocOperator = funcDef.IsAssocOperator; localProcedure.isAutoGeneratedThisProc = funcDef.IsAutoGeneratedThisProc; int peekFunctionindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { peekFunctionindex = codeBlock.procedureTable.procList.Count; } else { peekFunctionindex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count; } // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); if (null != funcDef.Singnature) { int argNumber = 0; foreach (VarDeclNode argNode in funcDef.Singnature.Arguments) { ++argNumber; IdentifierNode paramNode = null; bool aIsDefault = false; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aIsDefault = true; aDefaultExpression = bNode; //buildStatus.LogSemanticError("Defualt parameters are not supported"); //throw new BuildHaltException(); } else { Debug.Assert(false, "Check generated AST"); } ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); // We dont directly allocate arguments now argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(paramNode.Value, argType)); localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { Name = paramNode.Value, isDefault = aIsDefault, defaultExpression = aDefaultExpression }; localProcedure.argInfoList.Add(argInfo); } } if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { globalProcIndex = codeBlock.procedureTable.Append(localProcedure); } else { globalProcIndex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.Append(localProcedure); } // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != globalProcIndex) { Debug.Assert(peekFunctionindex == localProcedure.procId); argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, globalProcIndex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("B2CB2093"); } }); // TODO Jun: Remove this once agree that alltest cases assume the default assoc block is block 0 // NOTE: Only affects mirror, not actual execution if (null == codeBlock.parent && pc <= 0) { // The first node in the top level block is a function compileStateTracker.DSExecutable.isSingleAssocBlock = false; } #if ENABLE_EXCEPTION_HANDLING core.ExceptionHandlingManager.Register(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); #endif } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodAlreadyDefined, localProcedure.name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col); funcDef.skipMe = true; } } else if (parseGlobalFunctionBody || parseMemberFunctionBody) { if (compileStateTracker.Options.DisableDisposeFunctionDebug) { if (node.Name.Equals(ProtoCore.DSDefinitions.Keyword.Dispose)) { compileStateTracker.Options.EmitBreakpoints = false; } } // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Singnature) { foreach (VarDeclNode argNode in funcDef.Singnature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); argList.Add(argType); } } // Get the exisitng procedure that was added on the previous pass if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { globalProcIndex = codeBlock.procedureTable.IndexOfExact(funcDef.Name, argList); localProcedure = codeBlock.procedureTable.procList[globalProcIndex]; } else { globalProcIndex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList); localProcedure = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; } Debug.Assert(null != localProcedure); // code gen the attribute localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.pc = pc; // Copy the active function to the core so nested language blocks can refer to it compileStateTracker.ProcNode = localProcedure; ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { //Traverse default argument emitDebugInfo = false; foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList) { if (!argNode.isDefault) { continue; } BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp = nodeBuilder.BuildTempVariable(); var bNodeTemp = nodeBuilder.BuildBinaryExpression(iNodeTemp, bNode.LeftNode) as BinaryExpressionNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, AssociativeSubCompilePass.kUnboundIdentifier); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.IsAutoGenerated = true; BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, AssociativeSubCompilePass.kUnboundIdentifier); } emitDebugInfo = true; EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Singnature)); // Traverse definition foreach (AssociativeNode bnode in funcDef.FunctionBody.Body) { // // TODO Jun: Handle stand alone language blocks // Integrate the subPass into a proper pass // ProtoCore.Type itype = new ProtoCore.Type(); itype.UID = (int)PrimitiveType.kTypeVar; if (bnode is LanguageBlockNode) { // Build a binaryn node with a temporary lhs for every stand-alone language block BinaryExpressionNode langBlockNode = new BinaryExpressionNode(); langBlockNode.LeftNode = nodeBuilder.BuildIdentfier(compileStateTracker.GenerateTempLangageVar()); langBlockNode.Optr = ProtoCore.DSASM.Operator.assign; langBlockNode.RightNode = bnode; //DfsTraverse(bnode, ref itype, false, null, ProtoCore.DSASM.AssociativeSubCompilePass.kNone); DfsTraverse(langBlockNode, ref itype, false, null, subPass); } else { DfsTraverse(bnode, ref itype, false, null, subPass); } if (NodeUtils.IsReturnExpressionNode(bnode)) hasReturnStatement = true; } EmitCompileLogFunctionEnd(); // All locals have been stack allocated, update the local count of this function localProcedure.localCount = compileStateTracker.BaseOffset; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { localProcedure.localCount = compileStateTracker.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values) { if (symnode.functionIndex == localProcedure.procId && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } } else { compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[localProcedure.procId].localCount = compileStateTracker.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in compileStateTracker.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList.Values) { if (symnode.functionIndex == localProcedure.procId && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } } ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.pc; record.locals = localProcedure.localCount; record.classIndex = globalClassIndex; record.funcIndex = localProcedure.procId; fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else if (funcDef.BuiltInMethodId != ProtoCore.Lang.BuiltInMethods.MethodID.kInvalidMethodID) { fep = new ProtoCore.Lang.BuiltInFunctionEndPoint(funcDef.BuiltInMethodId); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.pc; jRecord.locals = localProcedure.localCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.procId; // TODO Jun/Luke: Wrap this into Core.Options and extend if needed /* bool isCSFFI = false; if (isCSFFI) { ProtoCore.Lang.CSFFIActivationRecord record = new ProtoCore.Lang.CSFFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = funcDef.IsDNI; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.argTypeList; fep = new ProtoCore.Lang.CSFFIFunctionEndPoint(record); } else {*/ ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = funcDef.IsDNI; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.argTypeList; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); //} } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count]; fep.BlockScope = codeBlock.codeBlockId; fep.ClassOwnerIndex = localProcedure.classScope; fep.procedureNode = localProcedure; localProcedure.argTypeList.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = globalClassIndex + 1; FunctionGroup functionGroup = compileStateTracker.FunctionTable.GetFunctionGroup(classIndexAtCallsite, funcDef.Name); if (functionGroup != null) { functionGroup.FunctionEndPoints.Add(fep); } else { // If any functions in the base class have the same name, append them here FunctionGroup basegroup = null; int ci = classIndexAtCallsite - 1; if (ci != Constants.kInvalidIndex) { ProtoCore.DSASM.ClassNode cnode = compileStateTracker.ClassTable.ClassNodes[ci]; if (cnode.baseList.Count > 0) { Validity.Assert(1 == cnode.baseList.Count, "We don't support multiple inheritance yet"); basegroup = compileStateTracker.FunctionTable.GetFunctionGroup(cnode.baseList[0] + 1, funcDef.Name); } } if (basegroup == null) { compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep); } else { // Copy all non-private feps from the basegroup into this the new group FunctionGroup newGroup = new FunctionGroup(); newGroup.CopyVisible(basegroup.FunctionEndPoints); newGroup.FunctionEndPoints.Add(fep); foreach (var newfep in newGroup.FunctionEndPoints) { compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, newfep); } } } if (!hasReturnStatement && !funcDef.IsExternLib) { if (!compileStateTracker.Options.SuppressFunctionResolutionWarning) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kFunctionNotReturnAtAllCodePaths, localProcedure.name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col); } EmitReturnNull(); } if (compileStateTracker.Options.DisableDisposeFunctionDebug) { if (node.Name.Equals(ProtoCore.DSDefinitions.Keyword.Dispose)) { compileStateTracker.Options.EmitBreakpoints = true; } } } compileStateTracker.ProcNode = localProcedure = null; codeBlock.blockType = origCodeBlockType; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; localFunctionDefNode = null; compileStateTracker.BaseOffset = 0; argOffset = 0; isAssocOperator = false; }
private void EmitFunctionDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, GraphNode graphNode = null) { bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.CompilerDefinitions.Associative.CompilePass.kGlobalFuncBody == compilePass; bool parseMemberFunctionBody = ProtoCore.DSASM.Constants.kGlobalScope != globalClassIndex && ProtoCore.CompilerDefinitions.Associative.CompilePass.kClassMemFuncBody == compilePass; FunctionDefinitionNode funcDef = node as FunctionDefinitionNode; localFunctionDefNode = funcDef; if (funcDef.IsAssocOperator) { isAssocOperator = true; } else { isAssocOperator = false; } bool hasReturnStatement = false; ProtoCore.DSASM.CodeBlockType origCodeBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingGlobalFunctionSig() || IsParsingMemberFunctionSig()) { Validity.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.Name = funcDef.Name; localProcedure.PC = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.LocalCount = 0; // Defer till all locals are allocated var uid = core.TypeSystem.GetType(funcDef.ReturnType.Name); var rank = funcDef.ReturnType.rank; var returnType = core.TypeSystem.BuildTypeObject(uid, rank); if (returnType.UID == (int)PrimitiveType.kInvalidType) { string message = String.Format(ProtoCore.Properties.Resources.kReturnTypeUndefined, funcDef.ReturnType.Name, funcDef.Name); buildStatus.LogWarning(WarningID.kTypeUndefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode); returnType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, rank); } localProcedure.ReturnType = returnType; localProcedure.IsConstructor = false; localProcedure.IsStatic = funcDef.IsStatic; localProcedure.RuntimeIndex = codeBlock.codeBlockId; localProcedure.AccessModifier = funcDef.Access; localProcedure.IsExternal = funcDef.IsExternLib; localProcedure.IsAutoGenerated = funcDef.IsAutoGenerated; localProcedure.ClassID = globalClassIndex; localProcedure.IsAssocOperator = funcDef.IsAssocOperator; localProcedure.IsAutoGeneratedThisProc = funcDef.IsAutoGeneratedThisProc; localProcedure.MethodAttribute = funcDef.MethodAttributes; int peekFunctionindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { peekFunctionindex = codeBlock.procedureTable.Procedures.Count; } else { peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures.Count; } // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); string functionDescription = localProcedure.Name; if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { var argInfo = BuildArgumentInfoFromVarDeclNode(argNode); localProcedure.ArgumentInfos.Add(argInfo); var argType = BuildArgumentTypeFromVarDeclNode(argNode, graphNode); localProcedure.ArgumentTypes.Add(argType); argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(argInfo.Name, argType)); functionDescription += argNode.ArgumentType.ToString(); } localProcedure.HashID = functionDescription.GetHashCode(); localProcedure.IsVarArg = funcDef.Signature.IsVarArg; } if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { globalProcIndex = codeBlock.procedureTable.Append(localProcedure); } else { globalProcIndex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Append(localProcedure); } // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != globalProcIndex) { argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, globalProcIndex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("B2CB2093"); } }); } else { string message = String.Format(ProtoCore.Properties.Resources.kMethodAlreadyDefined, localProcedure.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode); funcDef.skipMe = true; } } else if (parseGlobalFunctionBody || parseMemberFunctionBody) { if (CoreUtils.IsDisposeMethod(node.Name)) { core.Options.EmitBreakpoints = false; } // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, graphNode); argList.Add(argType); } } // Get the exisitng procedure that was added on the previous pass if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { var procNode = codeBlock.procedureTable.GetFunctionBySignature(funcDef.Name, argList); globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID; localProcedure = codeBlock.procedureTable.Procedures[globalProcIndex]; } else { var procNode = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.GetFunctionBySignature(funcDef.Name, argList); globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID; localProcedure = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex]; } Validity.Assert(null != localProcedure); // code gen the attribute localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.PC = pc; // Copy the active function to the core so nested language blocks can refer to it core.ProcNode = localProcedure; ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { //Traverse default argument emitDebugInfo = false; foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.ArgumentInfos) { if (!argNode.IsDefault) { continue; } BinaryExpressionNode bNode = argNode.DefaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp = AstFactory.BuildIdentifier(core.GenerateTempVar()); var bNodeTemp = AstFactory.BuildAssignment(iNodeTemp, bNode.LeftNode); bNodeTemp.IsProcedureOwned = true; EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.IsAutoGenerated = true; BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier); } emitDebugInfo = true; EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature)); ProtoCore.Type itype = new ProtoCore.Type(); hasReturnStatement = EmitCodeBlock(funcDef.FunctionBody.Body, ref itype, subPass, true); // Build dependency within the function ProtoCore.AssociativeEngine.Utils.BuildGraphNodeDependencies( codeBlock.instrStream.dependencyGraph.GetGraphNodesAtScope(globalClassIndex, globalProcIndex)); EmitCompileLogFunctionEnd(); // All locals have been stack allocated, update the local count of this function localProcedure.LocalCount = core.BaseOffset; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { localProcedure.LocalCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values) { if (symnode.functionIndex == localProcedure.ID && symnode.isArgument) { symnode.index -= localProcedure.LocalCount; } } } else { core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[localProcedure.ID].LocalCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[globalClassIndex].Symbols.symbolList.Values) { if (symnode.functionIndex == localProcedure.ID && symnode.isArgument) { symnode.index -= localProcedure.LocalCount; } } } ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.PC; record.locals = localProcedure.LocalCount; record.classIndex = globalClassIndex; record.funcIndex = localProcedure.ID; fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else if (funcDef.BuiltInMethodId != ProtoCore.Lang.BuiltInMethods.MethodID.kInvalidMethodID) { fep = new ProtoCore.Lang.BuiltInFunctionEndPoint(funcDef.BuiltInMethodId); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.PC; jRecord.locals = localProcedure.LocalCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.ID; ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = funcDef.IsDNI; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.ArgumentTypes; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.ArgumentTypes.Count]; fep.BlockScope = codeBlock.codeBlockId; fep.ClassOwnerIndex = localProcedure.ClassID; fep.procedureNode = localProcedure; localProcedure.ArgumentTypes.CopyTo(fep.FormalParams, 0); // 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables int classIndexAtCallsite = globalClassIndex + 1; core.FunctionTable.InitGlobalFunctionEntry(classIndexAtCallsite); // Get the function group of the current class and see if the current function exists Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // If any functions in the base class have the same name, append them here int ci = classIndexAtCallsite - 1; if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { ProtoCore.DSASM.ClassNode cnode = core.ClassTable.ClassNodes[ci]; if (cnode.Bases.Count > 0) { Validity.Assert(1 == cnode.Bases.Count, "We don't support multiple inheritance yet"); ci = cnode.Bases[0]; Dictionary<string, FunctionGroup> tgroup = new Dictionary<string, FunctionGroup>(); int callsiteCI = ci + 1; bool bSucceed = core.FunctionTable.GlobalFuncTable.TryGetValue(callsiteCI, out tgroup); if (bSucceed) { if (tgroup.ContainsKey(funcDef.Name)) { // Get that base group - the group of function from the baseclass FunctionGroup basegroup = new FunctionGroup(); bSucceed = tgroup.TryGetValue(funcDef.Name, out basegroup); if (bSucceed) { // Copy all non-private feps from the basegroup into this the new group FunctionGroup newGroup = new FunctionGroup(); newGroup.CopyVisible(basegroup.FunctionEndPoints); // Append the new fep newGroup.FunctionEndPoints.Add(fep); // Copy the new group to this class table core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, newGroup); } } else { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } } else { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } cnode = core.ClassTable.ClassNodes[ci]; } else { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } } else { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } if (!hasReturnStatement && !funcDef.IsExternLib) { if (!core.Options.SuppressFunctionResolutionWarning) { string message = String.Format(ProtoCore.Properties.Resources.kFunctionNotReturnAtAllCodePaths, localProcedure.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode); } EmitReturnNull(); } if (CoreUtils.IsDisposeMethod(node.Name)) { core.Options.EmitBreakpoints = true; } } core.ProcNode = localProcedure = null; codeBlock.blockType = origCodeBlockType; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; localFunctionDefNode = null; core.BaseOffset = 0; argOffset = 0; isAssocOperator = false; }
private void ComputeFeps( StringBuilder log, Context context, List<StackValue> arguments, FunctionGroup funcGroup, List<ReplicationInstruction> instructions, List<List<ReplicationGuide>> partialReplicationGuides, StackFrame stackFrame, RuntimeCore runtimeCore, out List<FunctionEndPoint> resolvesFeps, out List<ReplicationInstruction> replicationInstructions) { //With replication guides only //Exact match //Match with single elements //Match with single elements with upcast //Try replication without type cast //Match with type conversion //Match with type conversion with upcast //Try replication + type casting //Try replication + type casting + Array promotion #region First Case: Replicate only according to the replication guides { log.AppendLine("Case 1: Exact Match"); FunctionEndPoint fep = Case1GetCompleteMatchFEP(context, arguments, funcGroup, instructions, stackFrame, runtimeCore, log); if (fep != null) { if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); resolvesFeps = new List<FunctionEndPoint>() { fep }; replicationInstructions = instructions; return; } } #endregion #region Case 1a: Replicate only according to the replication guides, but with a sub-typing match { log.AppendLine("Case 1a: Replication guides + auto-replication + no cases"); List<List<StackValue>> reducedParams = Replicator.ComputeAllReducedParams(arguments, instructions, runtimeCore); int resolutionFailures; Dictionary<FunctionEndPoint, int> lookups = funcGroup.GetExactMatchStatistics( context, reducedParams, stackFrame, runtimeCore, out resolutionFailures); if (resolutionFailures == 0) { log.AppendLine("Resolution succeeded against FEP Cluster"); foreach (FunctionEndPoint fep in lookups.Keys) log.AppendLine("\t - " + fep); List<FunctionEndPoint> feps = new List<FunctionEndPoint>(); feps.AddRange(lookups.Keys); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); //Otherwise we have a cluster of FEPs that can be used to dispatch the array resolvesFeps = feps; replicationInstructions = instructions; return; } } #endregion var replicationTrials = Replicator.BuildReplicationCombinations(instructions, arguments, runtimeCore); #region Case 2: Replication with no type cast { log.AppendLine("Case 2: Beginning Auto-replication, no casts"); //Build the possible ways in which we might replicate foreach (List<ReplicationInstruction> repOption in replicationTrials) { List<List<StackValue>> reducedParams = Replicator.ComputeAllReducedParams(arguments, repOption, runtimeCore); int resolutionFailures; Dictionary<FunctionEndPoint, int> lookups = funcGroup.GetExactMatchStatistics( context, reducedParams, stackFrame, runtimeCore, out resolutionFailures); if (resolutionFailures > 0) continue; log.AppendLine("Resolution succeeded against FEP Cluster"); foreach (FunctionEndPoint fep in lookups.Keys) log.AppendLine("\t - " + fep); List<FunctionEndPoint> feps = new List<FunctionEndPoint>(); feps.AddRange(lookups.Keys); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); //Otherwise we have a cluster of FEPs that can be used to dispatch the array resolvesFeps = feps; replicationInstructions = repOption; return; } } #endregion #region Case 3: Match with type conversion, but no array promotion { log.AppendLine("Case 3: Type conversion"); FunctionEndPoint compliantTarget = GetCompliantFEP(context, arguments, funcGroup, instructions, stackFrame, runtimeCore); if (compliantTarget != null) { log.AppendLine("Resolution Succeeded: " + compliantTarget); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); resolvesFeps = new List<FunctionEndPoint>() { compliantTarget }; replicationInstructions = instructions; return; } } #endregion #region Case 4: Match with type conversion and replication log.AppendLine("Case 4: Replication + Type conversion"); { if (arguments.Any(arg => arg.IsArray)) { foreach (List<ReplicationInstruction> replicationOption in replicationTrials) { //@TODO: THis should use the proper reducer? FunctionEndPoint compliantTarget = GetCompliantFEP(context, arguments, funcGroup, replicationOption, stackFrame, runtimeCore); if (compliantTarget != null) { log.AppendLine("Resolution Succeeded: " + compliantTarget); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); resolvesFeps = new List<FunctionEndPoint>() { compliantTarget }; replicationInstructions = replicationOption; return; } } } } #endregion #region Case 5: Match with type conversion, replication and array promotion log.AppendLine("Case 5: Replication + Type conversion + Array promotion"); { //Add as a first attempt a no-replication, but allowing up-promoting replicationTrials.Insert(0, new List<ReplicationInstruction>()); foreach (List<ReplicationInstruction> replicationOption in replicationTrials) { //@TODO: THis should use the proper reducer? FunctionEndPoint compliantTarget = GetCompliantFEP(context, arguments, funcGroup, replicationOption, stackFrame, runtimeCore, true); if (compliantTarget != null) { log.AppendLine("Resolution Succeeded: " + compliantTarget); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); resolvesFeps = new List<FunctionEndPoint>() { compliantTarget }; replicationInstructions = replicationOption; return; } } } #endregion resolvesFeps = new List<FunctionEndPoint>(); replicationInstructions = instructions; }
/// <summary> /// Get complete match attempts to locate a function endpoint where 1 FEP matches all of the requirements for dispatch /// </summary> /// <param name="context"></param> /// <param name="arguments"></param> /// <param name="funcGroup"></param> /// <param name="replicationControl"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <param name="log"></param> /// <returns></returns> private FunctionEndPoint Case1GetCompleteMatchFEP(Context context, List<StackValue> arguments, FunctionGroup funcGroup, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore, StringBuilder log) { //Exact match List<FunctionEndPoint> exactTypeMatchingCandindates = funcGroup.GetExactTypeMatches(context, arguments, replicationInstructions, stackFrame, runtimeCore); FunctionEndPoint fep = null; if (exactTypeMatchingCandindates.Count > 0) { if (exactTypeMatchingCandindates.Count == 1) { //Exact match fep = exactTypeMatchingCandindates[0]; log.AppendLine("1 exact match found - FEP selected" + fep); } else { //Exact match with upcast fep = SelectFEPFromMultiple(stackFrame, runtimeCore, exactTypeMatchingCandindates, arguments); log.AppendLine(exactTypeMatchingCandindates.Count + "exact matches found - FEP selected" + fep); } } return fep; }
private StackValue Execute( List<FunctionEndPoint> functionEndPoint, Context c, List<StackValue> formalParameters, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore, FunctionGroup funcGroup) { SingleRunTraceData singleRunTraceData = (invokeCount < traceData.Count) ? traceData[invokeCount] : new SingleRunTraceData(); SingleRunTraceData newTraceData = new SingleRunTraceData(); StackValue ret; if (replicationInstructions.Count == 0) { c.IsReplicating = false; ret = ExecWithZeroRI(functionEndPoint, c, formalParameters, stackFrame, runtimeCore, funcGroup, singleRunTraceData, newTraceData); } else //replicated call { c.IsReplicating = true; ret = ExecWithRISlowPath(functionEndPoint, c, formalParameters, replicationInstructions, stackFrame, runtimeCore, funcGroup, singleRunTraceData, newTraceData); } //Do a trace save here if (invokeCount < traceData.Count) { traceData[invokeCount] = newTraceData; } else { traceData.Add(newTraceData); } invokeCount++; //We've completed this invocation return ret; }
//Single function call /// <summary> /// Dispatch without replication /// </summary> private StackValue ExecWithZeroRI(List<FunctionEndPoint> functionEndPoint, Context c, List<StackValue> formalParameters, StackFrame stackFrame, RuntimeCore runtimeCore, FunctionGroup funcGroup, SingleRunTraceData previousTraceData, SingleRunTraceData newTraceData) { if (runtimeCore.CancellationPending) { throw new ExecutionCancelledException(); } //@PERF: Todo add a fast path here for the case where we have a homogenious array so we can directly dispatch FunctionEndPoint finalFep = SelectFinalFep(c, functionEndPoint, formalParameters, stackFrame, runtimeCore); if (functionEndPoint == null) { runtimeCore.RuntimeStatus.LogWarning(WarningID.kMethodResolutionFailure, string.Format(Resources.FunctionDispatchFailed, "{2EB39E1B-557C-4819-94D8-CF7C9F933E8A}")); return StackValue.Null; } if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter) { DebugFrame debugFrame = runtimeCore.DebugProps.DebugStackFrame.Peek(); debugFrame.FinalFepChosen = finalFep; } List<StackValue> coercedParameters = finalFep.CoerceParameters(formalParameters, runtimeCore); // Correct block id where the function is defined. stackFrame.FunctionBlock = finalFep.BlockScope; //TraceCache -> TLS //Extract left most high-D pack ISerializable traceD = previousTraceData.GetLeftMostData(); if (traceD != null) { //There was data associated with the previous execution, push this into the TLS Dictionary<string, ISerializable> dataDict = new Dictionary<string, ISerializable>(); dataDict.Add(TRACE_KEY, traceD); TraceUtils.SetObjectToTLS(dataDict); } else { //There was no trace data for this run TraceUtils.ClearAllKnownTLSKeys(); } //EXECUTE StackValue ret = finalFep.Execute(c, coercedParameters, stackFrame, runtimeCore); if (ret.IsNull) { //wipe the trace cache TraceUtils.ClearTLSKey(TRACE_KEY); } //TLS -> TraceCache Dictionary<string, ISerializable> traceRet = TraceUtils.GetObjectFromTLS(); if (traceRet.ContainsKey(TRACE_KEY)) { var val = traceRet[TRACE_KEY]; newTraceData.Data = val; } // An explicit call requires return coercion at the return instruction if (!ret.IsExplicitCall) { ret = PerformReturnTypeCoerce(finalFep, runtimeCore, ret); } return ret; }
private void EmitFunctionDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone) { bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.DSASM.AssociativeCompilePass.kGlobalFuncBody == compilePass; bool parseMemberFunctionBody = ProtoCore.DSASM.Constants.kGlobalScope != globalClassIndex && ProtoCore.DSASM.AssociativeCompilePass.kClassMemFuncBody == compilePass; FunctionDefinitionNode funcDef = node as FunctionDefinitionNode; bool hasReturnStatement = false; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingGlobalFunctionSig() || IsParsingMemberFunctionSig()) { Debug.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.name = funcDef.Name; localProcedure.pc = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.localCount = 0; // Defer till all locals are allocated localProcedure.returntype.Name = funcDef.ReturnType.Name; localProcedure.returntype.UID = core.TypeSystem.GetType(funcDef.ReturnType.Name); if (localProcedure.returntype.UID == ProtoCore.DSASM.Constants.kInvalidIndex) localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; localProcedure.returntype.Name = core.TypeSystem.GetType(localProcedure.returntype.UID); localProcedure.returntype.IsIndexable = funcDef.ReturnType.IsIndexable; localProcedure.returntype.rank = funcDef.ReturnType.rank; localProcedure.isConstructor = false; localProcedure.isStatic = funcDef.IsStatic; localProcedure.runtimeIndex = codeBlock.codeBlockId; localProcedure.access = funcDef.access; localProcedure.isExternal = funcDef.IsExternLib; localProcedure.isAutoGenerated = funcDef.IsAutoGenerated; localProcedure.classScope = globalClassIndex; localProcedure.isAssocOperator = funcDef.IsAssocOperator; int peekFunctionindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { peekFunctionindex = codeBlock.procedureTable.procList.Count; } else { peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count; } if (IsParsingMemberFunctionSig() && !funcDef.IsExternLib) CodeRangeTable.AddClassBlockFunctionEntry(globalClassIndex, peekFunctionindex, funcDef.FunctionBody.line, funcDef.FunctionBody.col, funcDef.FunctionBody.endLine, funcDef.FunctionBody.endCol, core.CurrentDSFileName); else if (!funcDef.IsExternLib) CodeRangeTable.AddCodeBlockFunctionEntry(codeBlock.codeBlockId, peekFunctionindex, funcDef.FunctionBody.line, funcDef.FunctionBody.col, funcDef.FunctionBody.endLine, funcDef.FunctionBody.endCol, core.CurrentDSFileName); // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); if (null != funcDef.Singnature) { int argNumber = 0; foreach (VarDeclNode argNode in funcDef.Singnature.Arguments) { ++argNumber; IdentifierNode paramNode = null; bool aIsDefault = false; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aIsDefault = true; aDefaultExpression = bNode; //buildStatus.LogSemanticError("Defualt parameters are not supported"); //throw new BuildHaltException(); } else { Debug.Assert(false, "Check generated AST"); } ProtoCore.Type argType = new ProtoCore.Type(); argType.UID = core.TypeSystem.GetType(argNode.ArgumentType.Name); if (argType.UID == ProtoCore.DSASM.Constants.kInvalidIndex) argType.UID = (int)PrimitiveType.kTypeVar; argType.Name = core.TypeSystem.GetType(argType.UID); argType.IsIndexable = argNode.ArgumentType.IsIndexable; argType.rank = argNode.ArgumentType.rank; // We dont directly allocate arguments now argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(paramNode.Value, argType)); localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { isDefault = aIsDefault, defaultExpression = aDefaultExpression, Name = paramNode.Name }; localProcedure.argInfoList.Add(argInfo); } } if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { globalProcIndex = codeBlock.procedureTable.Append(localProcedure); } else { globalProcIndex = core.ClassTable.ClassNodes[globalClassIndex].vtable.Append(localProcedure); } // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != globalProcIndex) { Debug.Assert(peekFunctionindex == localProcedure.procId); argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, globalProcIndex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException(); } }); ExceptionRegistration registration = core.ExceptionHandlingManager.ExceptionTable.GetExceptionRegistration(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); if (registration == null) { registration = core.ExceptionHandlingManager.ExceptionTable.Register(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); Debug.Assert(registration != null); } } } else if (parseGlobalFunctionBody || parseMemberFunctionBody) { // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Singnature) { foreach (VarDeclNode argNode in funcDef.Singnature.Arguments) { int argType = core.TypeSystem.GetType(argNode.ArgumentType.Name); bool isArray = argNode.ArgumentType.IsIndexable; int rank = argNode.ArgumentType.rank; argList.Add(core.TypeSystem.BuildTypeObject(argType, isArray, rank)); } } // Get the exisitng procedure that was added on the previous pass if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { globalProcIndex = codeBlock.procedureTable.IndexOfExact(funcDef.Name, argList); localProcedure = codeBlock.procedureTable.procList[globalProcIndex]; } else { globalProcIndex = core.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList); localProcedure = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; } Debug.Assert(null != localProcedure); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); // Copy the active function to the core so nested language blocks can refer to it core.ProcNode = localProcedure; ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList) { if (!argNode.isDefault) { continue; } BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; IdentifierNode iNodeTemp = new IdentifierNode() { Value = ProtoCore.DSASM.Constants.kTempDefaultArg, Name = ProtoCore.DSASM.Constants.kTempDefaultArg, datatype = core.TypeSystem.BuildTypeObject(PrimitiveType.kTypeVar, false) }; BinaryExpressionNode bNodeTemp = new BinaryExpressionNode(); bNodeTemp.LeftNode = iNodeTemp; bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign; bNodeTemp.RightNode = bNode.LeftNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); ////duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; //InlineConditionalNode icNode = new InlineConditionalNode(); //BinaryExpressionNode cExprNode = new BinaryExpressionNode(); //cExprNode.Optr = ProtoCore.DSASM.Operator.eq; //cExprNode.LeftNode = iNodeTemp; //cExprNode.RightNode = new DefaultArgNode(); //icNode.ConditionExpression = cExprNode; //icNode.TrueExpression = bNode.RightNode; //icNode.FalseExpression = iNodeTemp; //bNodeTemp.LeftNode = bNode.LeftNode; //bNodeTemp.RightNode = icNode; //EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } // Traverse definition foreach (AssociativeNode bnode in funcDef.FunctionBody.Body) { // // TODO Jun: Handle stand alone language blocks // Integrate the subPass into a proper pass // ProtoCore.Type itype = new ProtoCore.Type(); itype.UID = (int)PrimitiveType.kTypeVar; if (bnode is LanguageBlockNode) { // Build a binaryn node with a temporary lhs for every stand-alone language block IdentifierNode iNode = new IdentifierNode() { Value = ProtoCore.DSASM.Constants.kTempLangBlock, Name = ProtoCore.DSASM.Constants.kTempLangBlock, datatype = core.TypeSystem.BuildTypeObject(PrimitiveType.kTypeVar, false) }; BinaryExpressionNode langBlockNode = new BinaryExpressionNode(); langBlockNode.LeftNode = iNode; langBlockNode.Optr = ProtoCore.DSASM.Operator.assign; langBlockNode.RightNode = bnode; //DfsTraverse(bnode, ref itype, false, null, ProtoCore.DSASM.AssociativeSubCompilePass.kNone); DfsTraverse(langBlockNode, ref itype, false, null, subPass); } else { DfsTraverse(bnode, ref itype, false, null, subPass); } BinaryExpressionNode binaryNode = bnode as BinaryExpressionNode; hasReturnStatement = hasReturnStatement || ((binaryNode != null) && (binaryNode.LeftNode.Name == ProtoCore.DSDefinitions.Kw.kw_return)); } // All locals have been stack allocated, update the local count of this function localProcedure.localCount = core.BaseOffset; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { localProcedure.localCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values) { if (symnode.functionIndex == localProcedure.procId && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } } else { core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[localProcedure.procId].localCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList.Values) { if (symnode.functionIndex == localProcedure.procId && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } } ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.pc; record.locals = localProcedure.localCount; record.classIndex = globalClassIndex; record.funcIndex = localProcedure.procId; fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.pc; jRecord.locals = localProcedure.localCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.procId; // TODO Jun/Luke: Wrap this into Core.Options and extend if needed /*bool isCSFFI = false; if (isCSFFI) { ProtoCore.Lang.CSFFIActivationRecord record = new ProtoCore.Lang.CSFFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = funcDef.IsDNI; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.argTypeList; fep = new ProtoCore.Lang.CSFFIFunctionEndPoint(record); } else {*/ ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = funcDef.IsDNI; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.argTypeList; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); //} } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count]; fep.BlockScope = this.codeBlock.codeBlockId; localProcedure.argTypeList.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = globalClassIndex + 1; if (!core.FunctionTable.GlobalFuncTable.ContainsKey(classIndexAtCallsite)) { Dictionary<string, FunctionGroup> funcList = new Dictionary<string, FunctionGroup>(); core.FunctionTable.GlobalFuncTable.Add(classIndexAtCallsite, funcList); } Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } } core.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; core.BaseOffset = 0; argOffset = 0; }
private void EmitConstructorDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone) { ConstructorDefinitionNode funcDef = node as ConstructorDefinitionNode; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingMemberFunctionSig()) { Debug.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.name = funcDef.Name; localProcedure.pc = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.localCount = 0;// Defer till all locals are allocated localProcedure.returntype.UID = core.TypeSystem.GetType(funcDef.ReturnType.Name); if (localProcedure.returntype.UID == ProtoCore.DSASM.Constants.kInvalidIndex) localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; localProcedure.returntype.Name = core.TypeSystem.GetType(localProcedure.returntype.UID); localProcedure.returntype.IsIndexable = false; localProcedure.isConstructor = true; localProcedure.runtimeIndex = 0; Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class"); localProcedure.localCount = 0; int peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count; if (!funcDef.IsExternLib) CodeRangeTable.AddClassBlockFunctionEntry(globalClassIndex, peekFunctionindex, funcDef.FunctionBody.line, funcDef.FunctionBody.col, funcDef.FunctionBody.endLine, funcDef.FunctionBody.endCol, core.CurrentDSFileName); // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); if (null != funcDef.Signature) { int argNumber = 0; foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ++argNumber; IdentifierNode paramNode = null; bool aIsDefault = false; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aIsDefault = true; aDefaultExpression = bNode; //buildStatus.LogSemanticError("Default parameters are not supported"); //throw new BuildHaltException(); } else { Debug.Assert(false, "Check generated AST"); } ProtoCore.Type argType = new ProtoCore.Type(); argType.UID = core.TypeSystem.GetType(argNode.ArgumentType.Name); if (argType.UID == ProtoCore.DSASM.Constants.kInvalidIndex) argType.UID = (int)PrimitiveType.kTypeVar; argType.Name = core.TypeSystem.GetType(argType.UID); argType.IsIndexable = argNode.ArgumentType.IsIndexable; argType.rank = argNode.ArgumentType.rank; argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(paramNode.Value, argType)); localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { isDefault = aIsDefault, defaultExpression = aDefaultExpression, Name = paramNode.Name }; localProcedure.argInfoList.Add(argInfo); } } int findex = core.ClassTable.ClassNodes[globalClassIndex].vtable.Append(localProcedure); // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != findex) { Debug.Assert(peekFunctionindex == localProcedure.procId); argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, findex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException(); } }); } } else if (IsParsingMemberFunctionBody()) { // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { int argType = core.TypeSystem.GetType(argNode.ArgumentType.Name); bool isArray = argNode.ArgumentType.IsIndexable; int rank = argNode.ArgumentType.rank; argList.Add(core.TypeSystem.BuildTypeObject(argType, isArray, rank)); } } globalProcIndex = core.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList); Debug.Assert(null == localProcedure); localProcedure = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; Debug.Assert(null != localProcedure); if (null == localProcedure) return; if (-1 == localProcedure.classScope && (localProcedure.classScope != globalClassIndex)) localProcedure.classScope = globalClassIndex; // Assign class index if it's not done. ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { // Traverse default assignment for the class foreach (BinaryExpressionNode bNode in core.ClassTable.ClassNodes[globalClassIndex].defaultArgExprList) { EmitBinaryExpressionNode(bNode, ref inferedType, false, null, subPass); UpdateType(bNode.LeftNode.Name, ProtoCore.DSASM.Constants.kInvalidIndex, inferedType); } //Traverse default argument for the constructor foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList) { if (!argNode.isDefault) { continue; } BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; IdentifierNode iNodeTemp = new IdentifierNode() { Value = ProtoCore.DSASM.Constants.kTempDefaultArg, Name = ProtoCore.DSASM.Constants.kTempDefaultArg, datatype = core.TypeSystem.BuildTypeObject(PrimitiveType.kTypeVar, false) }; BinaryExpressionNode bNodeTemp = new BinaryExpressionNode(); bNodeTemp.LeftNode = iNodeTemp; bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign; bNodeTemp.RightNode = bNode.LeftNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } // Traverse definition foreach (AssociativeNode bnode in funcDef.FunctionBody.Body) { inferedType.UID = (int)PrimitiveType.kTypeVoid; inferedType.rank = 0; DfsTraverse(bnode, ref inferedType, false, null, subPass); } // All locals have been stack allocated, update the local count of this function localProcedure.localCount = core.BaseOffset; core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex].localCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList.Values) { if (symnode.functionIndex == globalProcIndex && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } // JIL FEP ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.pc; record.locals = localProcedure.localCount; record.classIndex = globalClassIndex; record.funcIndex = globalProcIndex; // Construct the fep arguments fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.pc; jRecord.locals = localProcedure.localCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.procId; ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = false; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.argTypeList; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count]; localProcedure.argTypeList.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = globalClassIndex + 1; if (!core.FunctionTable.GlobalFuncTable.ContainsKey(classIndexAtCallsite)) { Dictionary<string, FunctionGroup> funcList = new Dictionary<string, FunctionGroup>(); core.FunctionTable.GlobalFuncTable.Add(classIndexAtCallsite, funcList); } Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } // Build and append a graphnode for this return statememt ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode(); returnNode.name = "return"; } // Constructors have no return statemetns, reset variables here core.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; core.BaseOffset = 0; argOffset = 0; classOffset = 0; codeBlock.blockType = originalBlockType; }
//Dispatch private StackValue DispatchNew( Context context, List<StackValue> arguments, List<List<ReplicationGuide>> partialReplicationGuides, DominantListStructure domintListStructure, StackFrame stackFrame, RuntimeCore runtimeCore) { // Update the CallsiteExecutionState with // TODO: Replace this with the real data UpdateCallsiteExecutionState(null, runtimeCore); Stopwatch sw = new Stopwatch(); sw.Start(); StringBuilder log = new StringBuilder(); log.AppendLine("Method name: " + methodName); #region Get Function Group //@PERF: Possible optimisation point here, to deal with static dispatches that don't need replication analysis //Handle resolution Pass 1: Name -> Method Group FunctionGroup funcGroup = GetFuncGroup(runtimeCore); if (funcGroup == null) { log.AppendLine("Function group not located"); log.AppendLine("Resolution failed in: " + sw.ElapsedMilliseconds); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); return ReportFunctionGroupNotFound(runtimeCore, arguments); } //check accesibility of function group bool methodAccessible = IsFunctionGroupAccessible(runtimeCore, ref funcGroup); if (!methodAccessible) { return ReportMethodNotAccessible(runtimeCore); } //If we got here then the function group got resolved log.AppendLine("Function group resolved: " + funcGroup); // Filter function end point List<FunctionEndPoint> candidatesFeps = new List<FunctionEndPoint>(); int argumentNumber = arguments.Count; foreach (var fep in funcGroup.FunctionEndPoints) { int defaultParamNumber = fep.procedureNode.ArgumentInfos.Count(x => x.IsDefault); int parameterNumber = fep.procedureNode.ArgumentTypes.Count; if (argumentNumber <= parameterNumber && parameterNumber - argumentNumber <= defaultParamNumber) { candidatesFeps.Add(fep); } } funcGroup = new FunctionGroup(candidatesFeps); #endregion partialReplicationGuides = PerformRepGuideDemotion(arguments, partialReplicationGuides, runtimeCore); //Replication Control is an ordered list of the elements that we have to replicate over //Ordering implies containment, so element 0 is the outer most forloop, element 1 is nested within it etc. //Take the explicit replication guides and build the replication structure //Turn the replication guides into a guide -> List args data structure var partialInstructions = Replicator.BuildPartialReplicationInstructions(partialReplicationGuides); //Get the fep that are resolved List<FunctionEndPoint> resolvesFeps; List<ReplicationInstruction> replicationInstructions; arguments = PerformRepGuideForcedPromotion(arguments, partialReplicationGuides, runtimeCore); ComputeFeps(context, arguments, funcGroup, partialInstructions, stackFrame, runtimeCore, out resolvesFeps, out replicationInstructions); if (resolvesFeps.Count == 0) { log.AppendLine("Resolution Failed"); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); return ReportMethodNotFoundForArguments(runtimeCore, arguments); } arguments.ForEach(x => runtimeCore.AddCallSiteGCRoot(CallSiteID, x)); StackValue ret = Execute(resolvesFeps, context, arguments, replicationInstructions, stackFrame, runtimeCore); if (!ret.IsExplicitCall) { ret = AtLevelHandler.RestoreDominantStructure(ret, domintListStructure, replicationInstructions, runtimeCore); } runtimeCore.RemoveCallSiteGCRoot(CallSiteID); return ret; }
/// <summary> /// Returns complete match attempts to locate a function endpoint where 1 FEP matches all of the requirements for dispatch /// </summary> /// <param name="context"></param> /// <param name="arguments"></param> /// <param name="funcGroup"></param> /// <param name="replicationControl"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <param name="log"></param> /// <returns></returns> private FunctionEndPoint GetCompleteMatchFunctionEndPoint( Context context, List<StackValue> arguments, FunctionGroup funcGroup, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore) { //Exact match var exactTypeMatchingCandindates = funcGroup.GetExactTypeMatches(context, arguments, replicationInstructions, stackFrame, runtimeCore); if (exactTypeMatchingCandindates.Count == 0) { return null; } FunctionEndPoint fep = null; if (exactTypeMatchingCandindates.Count == 1) { //Exact match fep = exactTypeMatchingCandindates[0]; } else { //Exact match with upcast fep = SelectFEPFromMultiple(stackFrame, runtimeCore, exactTypeMatchingCandindates, arguments); } return fep; }
private void ComputeFeps( Context context, List<StackValue> arguments, FunctionGroup funcGroup, List<ReplicationInstruction> instructions, StackFrame stackFrame, RuntimeCore runtimeCore, out List<FunctionEndPoint> resolvesFeps, out List<ReplicationInstruction> replicationInstructions) { #region Case 1: Replication guide with exact match { FunctionEndPoint fep = GetCompleteMatchFunctionEndPoint(context, arguments, funcGroup, instructions, stackFrame, runtimeCore); if (fep != null) { resolvesFeps = new List<FunctionEndPoint>() { fep }; replicationInstructions = instructions; return; } } #endregion var replicationTrials = Replicator.BuildReplicationCombinations(instructions, arguments, runtimeCore); #region Case 2: Replication and replication guide with exact match { //Build the possible ways in which we might replicate foreach (List<ReplicationInstruction> replicationOption in replicationTrials) { List<List<StackValue>> reducedParams = Replicator.ComputeAllReducedParams(arguments, replicationOption, runtimeCore); HashSet<FunctionEndPoint> lookups; if (funcGroup.CanGetExactMatchStatics(context, reducedParams, stackFrame, runtimeCore, out lookups)) { //Otherwise we have a cluster of FEPs that can be used to dispatch the array resolvesFeps = new List<FunctionEndPoint>(lookups); replicationInstructions = replicationOption; return; } } } #endregion #region Case 3: Replciation with type conversion { FunctionEndPoint compliantTarget = GetCompliantFEP(context, arguments, funcGroup, instructions, stackFrame, runtimeCore); if (compliantTarget != null) { resolvesFeps = new List<FunctionEndPoint>() { compliantTarget }; replicationInstructions = instructions; return; } } #endregion #region Case 4: Replication and replication guide with type conversion { if (arguments.Any(arg => arg.IsArray)) { foreach (List<ReplicationInstruction> replicationOption in replicationTrials) { FunctionEndPoint compliantTarget = GetCompliantFEP(context, arguments, funcGroup, replicationOption, stackFrame, runtimeCore); if (compliantTarget != null) { resolvesFeps = new List<FunctionEndPoint>() { compliantTarget }; replicationInstructions = replicationOption; return; } } } } #endregion #region Case 5: Replication and replciation guide with type conversion and array promotion { //Add as a first attempt a no-replication, but allowing up-promoting replicationTrials.Add(new List<ReplicationInstruction>()); foreach (List<ReplicationInstruction> replicationOption in replicationTrials) { FunctionEndPoint compliantTarget = GetCompliantFEP(context, arguments, funcGroup, replicationOption, stackFrame, runtimeCore, true); if (compliantTarget != null) { resolvesFeps = new List<FunctionEndPoint>() { compliantTarget }; replicationInstructions = replicationOption; return; } } } #endregion #region Case 6: Replication and replication guide with type conversion and array promotion, and OK if not all convertible { foreach (List<ReplicationInstruction> replicationOption in replicationTrials) { FunctionEndPoint compliantTarget = GetLooseCompliantFEP(context, arguments, funcGroup, replicationOption, stackFrame, runtimeCore); if (compliantTarget != null) { resolvesFeps = new List<FunctionEndPoint>() { compliantTarget }; replicationInstructions = replicationOption; return; } } } #endregion resolvesFeps = new List<FunctionEndPoint>(); replicationInstructions = instructions; }
/// <summary> /// Excecute an arbitrary depth replication using the full slow path algorithm /// </summary> /// <param name="functionEndPoint"> </param> /// <param name="c"></param> /// <param name="formalParameters"></param> /// <param name="replicationInstructions"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <returns></returns> private StackValue ExecWithRISlowPath( List<FunctionEndPoint> functionEndPoint, Context c, List<StackValue> formalParameters, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore, FunctionGroup funcGroup, SingleRunTraceData previousTraceData, SingleRunTraceData newTraceData) { if (runtimeCore.Options.ExecutionMode == ExecutionMode.Parallel) throw new NotImplementedException("Parallel mode disabled: {BF417AD5-9EA9-4292-ABBC-3526FC5A149E}"); //Recursion base case if (replicationInstructions.Count == 0) { return ExecWithZeroRI(functionEndPoint, c, formalParameters, stackFrame, runtimeCore, funcGroup, previousTraceData, newTraceData); } //Get the replication instruction that this call will deal with ReplicationInstruction ri = replicationInstructions[0]; if (ri.Zipped) { ZipAlgorithm algorithm = ri.ZipAlgorithm; //For each item in this plane, an array of the length of the minimum will be constructed //The size of the array will be the minimum size of the passed arrays List<int> repIndecies = ri.ZipIndecies; //this will hold the heap elements for all the arrays that are going to be replicated over List<StackValue[]> parameters = new List<StackValue[]>(); int retSize; switch (algorithm) { case ZipAlgorithm.Shortest: retSize = Int32.MaxValue; //Search to find the smallest break; case ZipAlgorithm.Longest: retSize = Int32.MinValue; //Search to find the largest break; default: throw new ReplicationCaseNotCurrentlySupported(Resources.AlgorithmNotSupported); } bool hasEmptyArg = false; foreach (int repIndex in repIndecies) { StackValue[] subParameters = null; if (formalParameters[repIndex].IsArray) { subParameters = runtimeCore.Heap.ToHeapObject<DSArray>(formalParameters[repIndex]).Values.ToArray(); } else { subParameters = new StackValue[] { formalParameters[repIndex] }; } parameters.Add(subParameters); if (subParameters.Length == 0) hasEmptyArg = true; switch (algorithm) { case ZipAlgorithm.Shortest: retSize = Math.Min(retSize, subParameters.Length); //We need the smallest array break; case ZipAlgorithm.Longest: retSize = Math.Max(retSize, subParameters.Length); //We need the longest array break; } } // If we're being asked to replicate across an empty list // then it's always going to be zero, as there will never be any // data to pass to that parameter. if (hasEmptyArg) retSize = 0; StackValue[] retSVs = new StackValue[retSize]; SingleRunTraceData retTrace = newTraceData; retTrace.NestedData = new List<SingleRunTraceData>(); //this will shadow the SVs as they are created //Populate out the size of the list with default values //@TODO:Luke perf optimisation here for (int i = 0; i < retSize; i++) retTrace.NestedData.Add(new SingleRunTraceData()); for (int i = 0; i < retSize; i++) { SingleRunTraceData lastExecTrace = new SingleRunTraceData(); if (previousTraceData.HasNestedData && i < previousTraceData.NestedData.Count) { //There was previous data that needs loading into the cache lastExecTrace = previousTraceData.NestedData[i]; } else { //We're off the edge of the previous trace window //So just pass in an empty block lastExecTrace = new SingleRunTraceData(); } //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); for (int repIi = 0; repIi < repIndecies.Count; repIi++) { switch (algorithm) { case ZipAlgorithm.Shortest: //If the shortest algorithm is selected this would newFormalParams[repIndecies[repIi]] = parameters[repIi][i]; break; case ZipAlgorithm.Longest: int length = parameters[repIi].Length; if (i < length) { newFormalParams[repIndecies[repIi]] = parameters[repIi][i]; } else { newFormalParams[repIndecies[repIi]] = parameters[repIi].Last(); } break; } } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); SingleRunTraceData cleanRetTrace = new SingleRunTraceData(); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, runtimeCore, funcGroup, lastExecTrace, cleanRetTrace); runtimeCore.AddCallSiteGCRoot(CallSiteID, retSVs[i]); retTrace.NestedData[i] = cleanRetTrace; } StackValue ret = runtimeCore.RuntimeMemory.Heap.AllocateArray(retSVs); return ret; } else { //With a cartesian product over an array, we are going to create an array of n //where the n is the product of the next item //We will call the subsequent reductions n times int cartIndex = ri.CartesianIndex; //this will hold the heap elements for all the arrays that are going to be replicated over bool supressArray = false; int retSize; StackValue[] parameters = null; if (formalParameters[cartIndex].IsArray) { DSArray array = runtimeCore.Heap.ToHeapObject<DSArray>(formalParameters[cartIndex]); parameters = array.Values.ToArray(); retSize = parameters.Length; } else { retSize = 1; supressArray = true; } StackValue[] retSVs = new StackValue[retSize]; SingleRunTraceData retTrace = newTraceData; retTrace.NestedData = new List<SingleRunTraceData>(); //this will shadow the SVs as they are created //Populate out the size of the list with default values //@TODO:Luke perf optimisation here for (int i = 0; i < retSize; i++) { retTrace.NestedData.Add(new SingleRunTraceData()); } if (supressArray) { List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); return ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, runtimeCore, funcGroup, previousTraceData, newTraceData); } //Now iterate over each of these options for (int i = 0; i < retSize; i++) { //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); if (parameters != null) { //It was an array pack the arg with the current value newFormalParams[cartIndex] = parameters[i]; } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); SingleRunTraceData lastExecTrace; if (previousTraceData.HasNestedData && i < previousTraceData.NestedData.Count) { //There was previous data that needs loading into the cache lastExecTrace = previousTraceData.NestedData[i]; } else if (previousTraceData.HasData && i == 0) { //We've moved up one dimension, and there was a previous run lastExecTrace = new SingleRunTraceData(); lastExecTrace.Data = previousTraceData.GetLeftMostData(); } else { //We're off the edge of the previous trace window //So just pass in an empty block lastExecTrace = new SingleRunTraceData(); } //previousTraceData = lastExecTrace; SingleRunTraceData cleanRetTrace = new SingleRunTraceData(); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, runtimeCore, funcGroup, lastExecTrace, cleanRetTrace); runtimeCore.AddCallSiteGCRoot(CallSiteID, retSVs[i]); retTrace.NestedData[i] = cleanRetTrace; } StackValue ret = runtimeCore.RuntimeMemory.Heap.AllocateArray(retSVs); return ret; } }
private StackValue Execute(List<FunctionEndPoint> functionEndPoint, ProtoCore.Runtime.Context c, List<StackValue> formalParameters, List<ReplicationInstruction> replicationInstructions, DSASM.StackFrame stackFrame, Core core, FunctionGroup funcGroup) { for (int i = 0; i < formalParameters.Count; ++i) { GCUtils.GCRetain(formalParameters[i], core); } StackValue ret; if (replicationInstructions.Count == 0) { c.IsReplicating = false; ret = ExecWithZeroRI(functionEndPoint, c, formalParameters, stackFrame, core, funcGroup); } else { c.IsReplicating = true; ret = ExecWithRISlowPath(functionEndPoint, c, formalParameters, replicationInstructions, stackFrame, core, funcGroup); } // Explicit calls require the GC of arguments in the function return instruction if (ret.optype != AddressType.ExplicitCall) { for (int i = 0; i < formalParameters.Count; ++i) { GCUtils.GCRelease(formalParameters[i], core); } } if (ret.optype == AddressType.Null) return ret; //It didn't return a value return ret; }
private FunctionEndPoint GetCompliantFEP( Context context, List<StackValue> arguments, FunctionGroup funcGroup, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore, bool allowArrayPromotion = false) { Dictionary<FunctionEndPoint, int> candidatesWithDistances = funcGroup.GetConversionDistances( context, arguments, replicationInstructions, runtimeCore.DSExecutable.classTable, runtimeCore, allowArrayPromotion); Dictionary<FunctionEndPoint, int> candidatesWithCastDistances = funcGroup.GetCastDistances( context, arguments, replicationInstructions, runtimeCore.DSExecutable.classTable, runtimeCore); List<FunctionEndPoint> candidateFunctions = GetCandidateFunctions(stackFrame, candidatesWithDistances); FunctionEndPoint compliantTarget = GetCompliantTarget( context, arguments, replicationInstructions, stackFrame, runtimeCore, candidatesWithCastDistances, candidateFunctions, candidatesWithDistances); return compliantTarget; }
/// <summary> /// Excecute an arbitrary depth replication using the full slow path algorithm /// </summary> /// <param name="functionEndPoint"> </param> /// <param name="c"></param> /// <param name="formalParameters"></param> /// <param name="replicationInstructions"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <returns></returns> private StackValue ExecWithRISlowPath(List<FunctionEndPoint> functionEndPoint, ProtoCore.Runtime.Context c, List<StackValue> formalParameters, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, Core core, FunctionGroup funcGroup) { //Recursion base case if (replicationInstructions.Count == 0) return ExecWithZeroRI(functionEndPoint, c, formalParameters, stackFrame, core, funcGroup); //Get the replication instruction that this call will deal with ReplicationInstruction ri = replicationInstructions[0]; if (ri.Zipped) { //For each item in this plane, an array of the length of the minimum will be constructed //The size of the array will be the minimum size of the passed arrays List<int> repIndecies = ri.ZipIndecies; //this will hold the heap elements for all the arrays that are going to be replicated over List<StackValue[]> parameters = new List<StackValue[]>(); int retSize = Int32.MaxValue; foreach (int repIndex in repIndecies) { //if (StackUtils.IsArray(formalParameters[repIndex])) // throw new NotImplementedException("Replication Case not implemented - Jagged Arrays - Slow path: {8606D4AA-9225-4F34-BE53-74270B8D0A90}"); StackValue[] subParameters = ArrayUtils.GetValues(formalParameters[repIndex], core); parameters.Add(subParameters); retSize = Math.Min(retSize, subParameters.Length); //We need the smallest array } StackValue[] retSVs = new StackValue[retSize]; if (core.Options.ExecutionMode == ExecutionMode.Parallel) throw new NotImplementedException("Parallel mode disabled: {BF417AD5-9EA9-4292-ABBC-3526FC5A149E}"); else { for (int i = 0; i < retSize; i++) { //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); for (int repIi = 0; repIi < repIndecies.Count; repIi++) { newFormalParams[repIndecies[repIi]] = parameters[repIi][i]; } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, core, funcGroup); //retSVs[i] = Execute(c, CoerceParameters(newFormalParams, core), stackFrame, core); } } StackValue ret = HeapUtils.StoreArray(retSVs, null, core); GCUtils.GCRetain(ret, core); return ret; } else { //With a cartesian product over an array, we are going to create an array of n //where the n is the product of the next item //We will call the subsequent reductions n times int cartIndex = ri.CartesianIndex; //this will hold the heap elements for all the arrays that are going to be replicated over bool supressArray = false; int retSize; StackValue[] parameters = null; if (formalParameters[cartIndex].optype == AddressType.ArrayPointer) { parameters = ArrayUtils.GetValues(formalParameters[cartIndex], core); retSize = parameters.Length; } else { retSize = 1; supressArray = true; } StackValue[] retSVs = new StackValue[retSize]; if (core.Options.ExecutionMode == ExecutionMode.Parallel) throw new NotImplementedException("Parallel mode disabled: {BF417AD5-9EA9-4292-ABBC-3526FC5A149E}"); else { if (supressArray) { List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); return ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, core, funcGroup); } //Now iterate over each of these options for (int i = 0; i < retSize; i++) { #if __PROTOTYPE_ARRAYUPDATE_FUNCTIONCALL // Comment Jun: If the array pointer passed in was of type DS Null, // then it means this is the first time the results are being computed. bool executeAll = c.ArrayPointer.optype == AddressType.Null; if (executeAll || ProtoCore.AssociativeEngine.ArrayUpdate.IsIndexInElementUpdateList(i, c.IndicesIntoArgMap)) { List<List<int>> prevIndexIntoList = new List<List<int>>(); foreach (List<int> dimList in c.IndicesIntoArgMap) { prevIndexIntoList.Add(new List<int>(dimList)); } StackValue svPrevPtr = c.ArrayPointer; if (!executeAll) { c.IndicesIntoArgMap = ProtoCore.AssociativeEngine.ArrayUpdate.UpdateIndexIntoList(i, c.IndicesIntoArgMap); c.ArrayPointer = ProtoCore.Utils.ArrayUtils.GetArrayElementAt(c.ArrayPointer, i, core); } //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); if (he != null) { //It was an array pack the arg with the current value newFormalParams[cartIndex] = he.Stack[i]; } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, core, funcGroup); // Restore the context properties for arrays c.IndicesIntoArgMap = new List<List<int>>(prevIndexIntoList); c.ArrayPointer = svPrevPtr; } else { retSVs[i] = ProtoCore.Utils.ArrayUtils.GetArrayElementAt(c.ArrayPointer, i, core); } #else //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); if (parameters != null) { //It was an array pack the arg with the current value newFormalParams[cartIndex] = parameters[i]; } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, core, funcGroup); #endif } } StackValue ret = HeapUtils.StoreArray(retSVs, null, core); GCUtils.GCRetain(ret, core); return ret; throw new ReplicationCaseNotCurrentlySupported( "Slowpath Cartesian product replication not yet implemented {33BCFC09-9A5C-4887-B44D-3584C34741F7}"); } }
private bool IsFunctionGroupAccessible(RuntimeCore runtimeCore, ref FunctionGroup funcGroup) { bool methodAccessible = true; if (classScope != Constants.kGlobalScope) { // If last stack frame is not member function, then only public // functions are acessible in this context. int callerci, callerfi; runtimeCore.CurrentExecutive.CurrentDSASMExec.GetCallerInformation(out callerci, out callerfi); if (callerci == Constants.kGlobalScope || (classScope != callerci && !runtimeCore.DSExecutable.classTable.ClassNodes[classScope].IsMyBase(callerci))) { bool hasFEP = funcGroup.FunctionEndPoints.Count > 0; FunctionGroup visibleFuncGroup = new FunctionGroup(); visibleFuncGroup.CopyPublic(funcGroup.FunctionEndPoints); funcGroup = visibleFuncGroup; if (hasFEP && funcGroup.FunctionEndPoints.Count == 0) { methodAccessible = false; } } } return methodAccessible; }
/// <summary> /// Dispatch without replication /// </summary> private StackValue ExecWithZeroRI(List<FunctionEndPoint> functionEndPoint, ProtoCore.Runtime.Context c, List<StackValue> formalParameters, StackFrame stackFrame, Core core, FunctionGroup funcGroup) { //@PERF: Todo add a fast path here for the case where we have a homogenious array so we can directly dispatch FunctionEndPoint finalFep = SelectFinalFep(c, functionEndPoint, formalParameters, stackFrame, core); /*functionEndPoint = ResolveFunctionEndPointWithoutReplication(c,funcGroup, formalParameters, stackFrame, core);*/ if (functionEndPoint == null) { core.RuntimeStatus.LogWarning(ProtoCore.RuntimeData.WarningID.kMethodResolutionFailure, "Function dispatch could not be completed {2EB39E1B-557C-4819-94D8-CF7C9F933E8A}"); return StackUtils.BuildNull(); } if (core.Options.IDEDebugMode && core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { DebugFrame debugFrame = core.DebugProps.DebugStackFrame.Peek(); debugFrame.FinalFepChosen = finalFep; } //@TODO(Luke): Should this coerce? List<StackValue> coercedParameters = finalFep.CoerceParameters(formalParameters, core); // Correct block id where the function is defined. StackValue funcBlock = stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock); funcBlock.opdata = finalFep.BlockScope; stackFrame.SetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock, funcBlock); StackValue ret = finalFep.Execute(c, coercedParameters, stackFrame, core); // An explicit call requires return coercion at the return instruction if (ret.optype != AddressType.ExplicitCall) { ret = PerformReturnTypeCoerce(finalFep, core, ret); } return ret; }
private void EmitFunctionDefinitionNode(ImperativeNode node, ref ProtoCore.Type inferedType) { bool parseGlobalFunctionSig = null == localProcedure && ProtoCore.CompilerDefinitions.Imperative.CompilePass.kGlobalFuncSig == compilePass; bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.CompilerDefinitions.Imperative.CompilePass.kGlobalFuncBody == compilePass; FunctionDefinitionNode funcDef = node as FunctionDefinitionNode; localFunctionDefNode = funcDef; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (parseGlobalFunctionSig) { Validity.Assert(null == localProcedure); // TODO jun: Add semantics for checking overloads (different parameter types) localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.name = funcDef.Name; localProcedure.pc = pc; localProcedure.localCount = funcDef.localVars; localProcedure.returntype.UID = core.TypeSystem.GetType(funcDef.ReturnType.Name); if (localProcedure.returntype.UID == (int)PrimitiveType.kInvalidType) { string message = String.Format(ProtoCore.Properties.Resources.kReturnTypeUndefined, funcDef.ReturnType.Name, funcDef.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kTypeUndefined, message, null, funcDef.line, funcDef.col, firstSSAGraphNode); localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; } localProcedure.returntype.rank = funcDef.ReturnType.rank; localProcedure.runtimeIndex = codeBlock.codeBlockId; globalProcIndex = codeBlock.procedureTable.Append(localProcedure); core.ProcNode = localProcedure; // Append arg symbols if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { IdentifierNode paramNode = null; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aDefaultExpression = bNode; } else { Validity.Assert(false, "Check generated AST"); } ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, firstSSAGraphNode); int symbolIndex = AllocateArg(paramNode.Value, localProcedure.procId, argType); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("26384684"); } localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { DefaultExpression = aDefaultExpression }; localProcedure.argInfoList.Add(argInfo); } } } else if (parseGlobalFunctionBody) { EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature)); // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, firstSSAGraphNode); argList.Add(argType); } } // Get the exisitng procedure that was added on the previous pass globalProcIndex = codeBlock.procedureTable.IndexOfExact(funcDef.Name, argList, false); localProcedure = codeBlock.procedureTable.procList[globalProcIndex]; Validity.Assert(null != localProcedure); localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.pc = pc; // Copy the active function to the core so nested language blocks can refer to it core.ProcNode = localProcedure; // Arguments have been allocated, update the baseOffset localProcedure.localCount = core.BaseOffset; ProtoCore.FunctionEndPoint fep = null; //Traverse default argument emitDebugInfo = false; foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList) { if (!argNode.IsDefault) { continue; } BinaryExpressionNode bNode = argNode.DefaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp = nodeBuilder.BuildIdentfier(Constants.kTempDefaultArg); BinaryExpressionNode bNodeTemp = nodeBuilder.BuildBinaryExpression(iNodeTemp, bNode.LeftNode) as BinaryExpressionNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.ConditionExpression = nodeBuilder.BuildBinaryExpression(iNodeTemp, new DefaultArgNode(), Operator.eq); icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } emitDebugInfo = true; // Traverse definition bool hasReturnStatement = false; foreach (ImperativeNode bnode in funcDef.FunctionBody.Body) { DfsTraverse(bnode, ref inferedType); if (ProtoCore.Utils.NodeUtils.IsReturnExpressionNode(bnode)) { hasReturnStatement = true; } if (bnode is FunctionCallNode) { EmitSetExpressionUID(core.ExpressionUID++); } } // All locals have been stack allocated, update the local count of this function localProcedure.localCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values) { if (symnode.functionIndex == localProcedure.procId && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.pc; record.locals = localProcedure.localCount; record.classIndex = ProtoCore.DSASM.Constants.kInvalidIndex; record.funcIndex = localProcedure.procId; fep = new ProtoCore.Lang.JILFunctionEndPoint(record); // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count]; fep.BlockScope = codeBlock.codeBlockId; fep.procedureNode = localProcedure; localProcedure.argTypeList.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = ProtoCore.DSASM.Constants.kInvalidIndex + 1; if (!core.FunctionTable.GlobalFuncTable.ContainsKey(classIndexAtCallsite)) { Dictionary<string, FunctionGroup> funcList = new Dictionary<string, FunctionGroup>(); core.FunctionTable.GlobalFuncTable.Add(classIndexAtCallsite, funcList); } Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } if (!hasReturnStatement) { if (!core.Options.SuppressFunctionResolutionWarning) { string message = String.Format(ProtoCore.Properties.Resources.kFunctionNotReturnAtAllCodePaths, localProcedure.name); core.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, core.CurrentDSFileName, funcDef.line, funcDef.col, firstSSAGraphNode); } EmitReturnNull(); } EmitCompileLogFunctionEnd(); //Fuqiang: return is already done in traversing the function body //// function return //EmitInstrConsole(ProtoCore.DSASM.kw.ret); //EmitReturn(); } core.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; argOffset = 0; core.BaseOffset = 0; codeBlock.blockType = originalBlockType; localFunctionDefNode = null; }
private void EmitConstructorDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone) { ConstructorDefinitionNode funcDef = node as ConstructorDefinitionNode; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingMemberFunctionSig()) { Validity.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.name = funcDef.Name; localProcedure.pc = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.localCount = 0;// Defer till all locals are allocated localProcedure.returntype.UID = globalClassIndex; localProcedure.returntype.rank = Constants.kArbitraryRank; localProcedure.isConstructor = true; localProcedure.runtimeIndex = 0; localProcedure.isExternal = funcDef.IsExternLib; Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class"); localProcedure.localCount = 0; localProcedure.classScope = globalClassIndex; localProcedure.MethodAttribute = funcDef.MethodAttributes; int peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count; // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); if (null != funcDef.Signature) { int argNumber = 0; foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ++argNumber; IdentifierNode paramNode = null; bool aIsDefault = false; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aIsDefault = true; aDefaultExpression = bNode; //buildStatus.LogSemanticError("Default parameters are not supported"); //throw new BuildHaltException(); } else { Validity.Assert(false, "Check generated AST"); } ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(paramNode.Value, argType)); localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { Name = paramNode.Value, isDefault = aIsDefault, defaultExpression = aDefaultExpression }; localProcedure.argInfoList.Add(argInfo); } localProcedure.isVarArg = funcDef.Signature.IsVarArg; } int findex = core.ClassTable.ClassNodes[globalClassIndex].vtable.Append(localProcedure); // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != findex) { Validity.Assert(peekFunctionindex == localProcedure.procId); argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, findex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("44B557F1"); } }); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodAlreadyDefined, localProcedure.name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col); funcDef.skipMe = true; } } else if (IsParsingMemberFunctionBody()) { EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature, true)); // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); argList.Add(argType); } } globalProcIndex = core.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList); Validity.Assert(null == localProcedure); localProcedure = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; Validity.Assert(null != localProcedure); localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.pc = pc; EmitInstrConsole(ProtoCore.DSASM.kw.allocc, localProcedure.name); EmitAllocc(globalClassIndex); setConstructorStartPC = true; EmitCallingForBaseConstructor(globalClassIndex, funcDef.baseConstr); ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { // Traverse default assignment for the class emitDebugInfo = false; foreach (BinaryExpressionNode bNode in core.ClassTable.ClassNodes[globalClassIndex].defaultArgExprList) { ProtoCore.AssociativeGraph.GraphNode graphNode = new ProtoCore.AssociativeGraph.GraphNode(); graphNode.exprUID = bNode.exprUID; graphNode.modBlkUID = bNode.modBlkUID; graphNode.procIndex = globalProcIndex; graphNode.classIndex = globalClassIndex; graphNode.isAutoGenerated = true; EmitBinaryExpressionNode(bNode, ref inferedType, false, graphNode, subPass); } //Traverse default argument for the constructor foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList) { if (!argNode.isDefault) { continue; } BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp = nodeBuilder.BuildIdentfier(Constants.kTempDefaultArg); BinaryExpressionNode bNodeTemp = new BinaryExpressionNode(); bNodeTemp.LeftNode = iNodeTemp; bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign; bNodeTemp.RightNode = bNode.LeftNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.IsAutoGenerated = true; BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } emitDebugInfo = true; // Traverse definition foreach (AssociativeNode bnode in funcDef.FunctionBody.Body) { inferedType.UID = (int)PrimitiveType.kTypeVoid; inferedType.rank = 0; if (bnode is LanguageBlockNode) { // Build a binaryn node with a temporary lhs for every stand-alone language block var iNode = nodeBuilder.BuildIdentfier(core.GenerateTempLangageVar()); BinaryExpressionNode langBlockNode = new BinaryExpressionNode(); langBlockNode.LeftNode = iNode; langBlockNode.Optr = ProtoCore.DSASM.Operator.assign; langBlockNode.RightNode = bnode; DfsTraverse(langBlockNode, ref inferedType, false, null, subPass); } else { DfsTraverse(bnode, ref inferedType, false, null, subPass); } } // All locals have been stack allocated, update the local count of this function localProcedure.localCount = core.BaseOffset; core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex].localCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList.Values) { if (symnode.functionIndex == globalProcIndex && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } // JIL FEP ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.pc; record.locals = localProcedure.localCount; record.classIndex = globalClassIndex; record.funcIndex = globalProcIndex; // Construct the fep arguments fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.pc; jRecord.locals = localProcedure.localCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.procId; ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = false; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.argTypeList; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count]; fep.procedureNode = localProcedure; localProcedure.argTypeList.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = globalClassIndex + 1; if (!core.FunctionTable.GlobalFuncTable.ContainsKey(classIndexAtCallsite)) { Dictionary<string, FunctionGroup> funcList = new Dictionary<string, FunctionGroup>(); core.FunctionTable.GlobalFuncTable.Add(classIndexAtCallsite, funcList); } Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } int startpc = pc; // Constructors auto return EmitInstrConsole(ProtoCore.DSASM.kw.retc); // Stepping out of a constructor body will have the execution cursor // placed right at the closing curly bracket of the constructor definition. // int closeCurlyBracketLine = 0, closeCurlyBracketColumn = -1; if (null != funcDef.FunctionBody) { closeCurlyBracketLine = funcDef.FunctionBody.endLine; closeCurlyBracketColumn = funcDef.FunctionBody.endCol; } // The execution cursor covers exactly one character -- the closing // curly bracket. Note that we decrement the start-column by one here // because end-column of "FunctionBody" here is *after* the closing // curly bracket, so we want one before that. // EmitRetc(closeCurlyBracketLine, closeCurlyBracketColumn - 1, closeCurlyBracketLine, closeCurlyBracketColumn); // Build and append a graphnode for this return statememt ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode(); returnNode.name = ProtoCore.DSDefinitions.Keyword.Return; ProtoCore.AssociativeGraph.GraphNode retNode = new ProtoCore.AssociativeGraph.GraphNode(); //retNode.symbol = returnNode; retNode.PushSymbolReference(returnNode); retNode.procIndex = globalProcIndex; retNode.classIndex = globalClassIndex; retNode.updateBlock.startpc = startpc; retNode.updateBlock.endpc = pc - 1; codeBlock.instrStream.dependencyGraph.Push(retNode); EmitCompileLogFunctionEnd(); } // Constructors have no return statemetns, reset variables here core.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; core.BaseOffset = 0; argOffset = 0; classOffset = 0; codeBlock.blockType = originalBlockType; }
private void EmitConstructorDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, GraphNode gNode = null) { ConstructorDefinitionNode funcDef = node as ConstructorDefinitionNode; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingMemberFunctionSig()) { Validity.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.Name = funcDef.Name; localProcedure.PC = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.LocalCount = 0;// Defer till all locals are allocated ProtoCore.Type returnType = localProcedure.ReturnType; if (globalClassIndex != -1) returnType.Name = core.ClassTable.ClassNodes[globalClassIndex].Name; returnType.UID = globalClassIndex; returnType.rank = 0; localProcedure.ReturnType = returnType; localProcedure.IsConstructor = true; localProcedure.RuntimeIndex = 0; localProcedure.IsExternal = funcDef.IsExternLib; Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class"); localProcedure.LocalCount = 0; localProcedure.ClassID = globalClassIndex; localProcedure.MethodAttribute = funcDef.MethodAttributes; int peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures.Count; // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { var argInfo = BuildArgumentInfoFromVarDeclNode(argNode); localProcedure.ArgumentInfos.Add(argInfo); var argType = BuildArgumentTypeFromVarDeclNode(argNode, gNode); localProcedure.ArgumentTypes.Add(argType); argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(argInfo.Name, argType)); } localProcedure.IsVarArg = funcDef.Signature.IsVarArg; } int findex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Append(localProcedure); // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != findex) { Validity.Assert(peekFunctionindex == localProcedure.ID); argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, findex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("44B557F1"); } }); } else { string message = String.Format(ProtoCore.Properties.Resources.kMethodAlreadyDefined, localProcedure.Name); buildStatus.LogWarning(WarningID.kFunctionAlreadyDefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, gNode); funcDef.skipMe = true; } } else if (IsParsingMemberFunctionBody()) { EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature, true)); // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, gNode); argList.Add(argType); } } var procNode = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.GetFunctionBySignature(funcDef.Name, argList); globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID; Validity.Assert(null == localProcedure); localProcedure = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex]; Validity.Assert(null != localProcedure); localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.PC = pc; EmitInstrConsole(ProtoCore.DSASM.kw.allocc, localProcedure.Name); EmitAllocc(globalClassIndex); setConstructorStartPC = true; EmitCallingForBaseConstructor(globalClassIndex, funcDef.BaseConstructor); ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { // Traverse default assignment for the class emitDebugInfo = false; List<AssociativeNode> defaultArgList = core.ClassTable.ClassNodes[globalClassIndex].DefaultArgExprList; defaultArgList = BuildSSA(defaultArgList, context); foreach (BinaryExpressionNode bNode in defaultArgList) { ProtoCore.AssociativeGraph.GraphNode graphNode = new ProtoCore.AssociativeGraph.GraphNode(); graphNode.exprUID = bNode.ExpressionUID; graphNode.ssaExpressionUID = bNode.SSAExpressionUID; graphNode.procIndex = globalProcIndex; graphNode.classIndex = globalClassIndex; graphNode.languageBlockId = codeBlock.codeBlockId; graphNode.isAutoGenerated = true; bNode.IsProcedureOwned = graphNode.ProcedureOwned = true; EmitBinaryExpressionNode(bNode, ref inferedType, false, graphNode, subPass); } //Traverse default argument for the constructor foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.ArgumentInfos) { if (!argNode.IsDefault) { continue; } BinaryExpressionNode bNode = argNode.DefaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp =AstFactory.BuildIdentifier(Constants.kTempDefaultArg); BinaryExpressionNode bNodeTemp = new BinaryExpressionNode(); bNodeTemp.LeftNode = iNodeTemp; bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign; bNodeTemp.RightNode = bNode.LeftNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.IsAutoGenerated = true; BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } emitDebugInfo = true; EmitCodeBlock(funcDef.FunctionBody.Body, ref inferedType, subPass, true); // Build dependency within the function ProtoCore.AssociativeEngine.Utils.BuildGraphNodeDependencies( codeBlock.instrStream.dependencyGraph.GetGraphNodesAtScope(globalClassIndex, globalProcIndex)); // All locals have been stack allocated, update the local count of this function localProcedure.LocalCount = core.BaseOffset; core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex].LocalCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[globalClassIndex].Symbols.symbolList.Values) { if (symnode.functionIndex == globalProcIndex && symnode.isArgument) { symnode.index -= localProcedure.LocalCount; } } // JIL FEP ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.PC; record.locals = localProcedure.LocalCount; record.classIndex = globalClassIndex; record.funcIndex = globalProcIndex; // Construct the fep arguments fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.PC; jRecord.locals = localProcedure.LocalCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.ID; ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = false; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.ArgumentTypes; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.ArgumentTypes.Count]; fep.procedureNode = localProcedure; localProcedure.ArgumentTypes.CopyTo(fep.FormalParams, 0); // 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables int classIndexAtCallsite = globalClassIndex + 1; core.FunctionTable.InitGlobalFunctionEntry(classIndexAtCallsite); Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } int startpc = pc; // Constructors auto return EmitInstrConsole(ProtoCore.DSASM.kw.retc); // Stepping out of a constructor body will have the execution cursor // placed right at the closing curly bracket of the constructor definition. // int closeCurlyBracketLine = 0, closeCurlyBracketColumn = -1; if (null != funcDef.FunctionBody) { closeCurlyBracketLine = funcDef.FunctionBody.endLine; closeCurlyBracketColumn = funcDef.FunctionBody.endCol; } // The execution cursor covers exactly one character -- the closing // curly bracket. Note that we decrement the start-column by one here // because end-column of "FunctionBody" here is *after* the closing // curly bracket, so we want one before that. // EmitRetc(closeCurlyBracketLine, closeCurlyBracketColumn - 1, closeCurlyBracketLine, closeCurlyBracketColumn); // Build and append a graphnode for this return statememt ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode(); returnNode.name = ProtoCore.DSDefinitions.Keyword.Return; ProtoCore.AssociativeGraph.GraphNode retNode = new ProtoCore.AssociativeGraph.GraphNode(); //retNode.symbol = returnNode; retNode.PushSymbolReference(returnNode); retNode.procIndex = globalProcIndex; retNode.classIndex = globalClassIndex; retNode.updateBlock.startpc = startpc; retNode.updateBlock.endpc = pc - 1; PushGraphNode(retNode); EmitCompileLogFunctionEnd(); } // Constructors have no return statemetns, reset variables here core.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; core.BaseOffset = 0; argOffset = 0; classOffset = 0; codeBlock.blockType = originalBlockType; }
public void LogMethodResolutionWarning(FunctionGroup funcGroup, string methodName, int classScope = Constants.kGlobalScope, List <StackValue> arguments = null) { string message; var qualifiedMethodName = methodName; var className = string.Empty; var classNameSimple = string.Empty; if (classScope != Constants.kGlobalScope) { if (methodName == nameof(DesignScript.Builtin.Get.ValueAtIndex)) { if (arguments.Count == 2 && arguments[0].IsInteger && arguments[1].IsInteger) { LogWarning(WarningID.IndexOutOfRange, Resources.IndexIntoNonArrayObject); return; } } var classNode = runtimeCore.DSExecutable.classTable.ClassNodes[classScope]; className = classNode.Name; classNameSimple = className.Split('.').Last(); qualifiedMethodName = classNameSimple + "." + methodName; } Operator op; string propertyName; if (CoreUtils.TryGetPropertyName(methodName, out propertyName)) { if (classScope != Constants.kGlobalScope) { if (arguments != null && arguments.Any()) { qualifiedMethodName = classNameSimple + "." + propertyName; // if the property is found on the class, it must be a static getter being called on // an instance argument type not matching the property message = string.Format(Resources.NonOverloadMethodResolutionError, qualifiedMethodName, className, GetTypeName(arguments[0])); } else { message = string.Format(Resources.kPropertyOfClassNotFound, propertyName, className); } } else { message = string.Format(Resources.kPropertyNotFound, propertyName); } } else if (CoreUtils.TryGetOperator(methodName, out op)) { var strOp = Op.GetOpSymbol(op); message = String.Format(Resources.kMethodResolutionFailureForOperator, strOp, GetTypeName(arguments[0]), GetTypeName(arguments[1])); } else if (funcGroup.FunctionEndPoints.Count == 1) // non-overloaded case { var argsJoined = string.Join(", ", arguments.Select(GetTypeName)); var fep = funcGroup.FunctionEndPoints[0]; var formalParamsJoined = string.Join(", ", fep.FormalParams); message = string.Format(Resources.NonOverloadMethodResolutionError, qualifiedMethodName, formalParamsJoined, argsJoined); } else // overloaded case { var argsJoined = string.Join(", ", arguments.Select(GetTypeName)); message = string.Format(Resources.kMethodResolutionFailureWithTypes, qualifiedMethodName, argsJoined); } LogWarning(WarningID.MethodResolutionFailure, message); }
private void ResolveFunctionGroups() { // foreach class in classtable foreach (ProtoCore.DSASM.ClassNode cnode in core.ClassTable.ClassNodes) { if (cnode.Bases.Count > 0) { // Get the current class functiongroup int ci = cnode.ID; Dictionary<string, FunctionGroup> groupList = new Dictionary<string, FunctionGroup>(); if (!core.FunctionTable.GlobalFuncTable.TryGetValue(ci + 1, out groupList)) { continue; } // If it has a baseclass, get its function group 'basegroup' int baseCI = cnode.Bases[0]; Dictionary<string, FunctionGroup> baseGroupList = new Dictionary<string, FunctionGroup>(); bool groupListExists = core.FunctionTable.GlobalFuncTable.TryGetValue(baseCI + 1, out baseGroupList); if (groupListExists) { // If it has a baseclass, get its list of function group 'basegrouplist' // for every group, check if this already exisits in the current class foreach (KeyValuePair<string, FunctionGroup> baseGroup in baseGroupList) { if (groupList.ContainsKey(baseGroup.Key)) { // If this class has this function group, append the visible feps from the basegoup FunctionGroup currentGroup = new FunctionGroup(); if (groupList.TryGetValue(baseGroup.Key, out currentGroup)) { // currentGroup is this class's current function group given the current name currentGroup.CopyVisible(baseGroup.Value.FunctionEndPoints); } } else { // If this class doesnt have basegroup, create a new group and append the visible feps from the basegoup FunctionGroup newGroup = new FunctionGroup(); newGroup.CopyVisible(baseGroup.Value.FunctionEndPoints); if (newGroup.FunctionEndPoints.Count > 0) { groupList.Add(baseGroup.Key, newGroup); } } } } } } }
private void EmitFunctionDefinitionNode(ImperativeNode node, ref ProtoCore.Type inferedType) { bool parseGlobalFunctionSig = null == localProcedure && ProtoCore.DSASM.ImperativeCompilePass.kGlobalFuncSig == compilePass; bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.DSASM.ImperativeCompilePass.kGlobalFuncBody == compilePass; FunctionDefinitionNode funcDef = node as FunctionDefinitionNode; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (parseGlobalFunctionSig) { Debug.Assert(null == localProcedure); // TODO jun: Add semantics for checking overloads (different parameter types) localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.name = funcDef.Name; localProcedure.localCount = funcDef.localVars; localProcedure.returntype.UID = core.TypeSystem.GetType(funcDef.ReturnType.Name); if (localProcedure.returntype.UID == ProtoCore.DSASM.Constants.kInvalidIndex) localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; localProcedure.returntype.Name = core.TypeSystem.GetType(localProcedure.returntype.UID); localProcedure.returntype.IsIndexable = funcDef.ReturnType.IsIndexable; localProcedure.returntype.rank = funcDef.ReturnType.rank; localProcedure.runtimeIndex = codeBlock.codeBlockId; globalProcIndex = codeBlock.procedureTable.Append(localProcedure); core.ProcNode = localProcedure; CodeRangeTable.AddCodeBlockFunctionEntry(codeBlock.codeBlockId, globalProcIndex, funcDef.FunctionBody.line, funcDef.FunctionBody.col, funcDef.FunctionBody.endLine, funcDef.FunctionBody.endCol, core.CurrentDSFileName); // Append arg symbols if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { IdentifierNode paramNode = null; bool aIsDefault = false; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aIsDefault = true; aDefaultExpression = bNode; //buildStatus.LogSemanticError("Defualt parameters are not supported"); //throw new BuildHaltException(); } else { Debug.Assert(false, "Check generated AST"); } ProtoCore.Type argType = new ProtoCore.Type(); argType.UID = core.TypeSystem.GetType(argNode.ArgumentType.Name); if (argType.UID == ProtoCore.DSASM.Constants.kInvalidIndex) argType.UID = (int)PrimitiveType.kTypeVar; argType.Name = core.TypeSystem.GetType(argType.UID); argType.IsIndexable = argNode.ArgumentType.IsIndexable; argType.rank = argNode.ArgumentType.rank; int symbolIndex = AllocateArg(paramNode.Value, localProcedure.procId, argType); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException(); } localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { isDefault = aIsDefault, defaultExpression = aDefaultExpression, Name = paramNode.Name }; localProcedure.argInfoList.Add(argInfo); } } ExceptionRegistration registration = core.ExceptionHandlingManager.ExceptionTable.GetExceptionRegistration(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); if (registration == null) { registration = core.ExceptionHandlingManager.ExceptionTable.Register(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); Debug.Assert(registration != null); } } else if (parseGlobalFunctionBody) { // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { int argType = core.TypeSystem.GetType(argNode.ArgumentType.Name); bool isArray = argNode.ArgumentType.IsIndexable; int rank = argNode.ArgumentType.rank; argList.Add(core.TypeSystem.BuildTypeObject(argType, isArray, rank)); } } // Get the exisitng procedure that was added on the previous pass globalProcIndex = codeBlock.procedureTable.IndexOfExact(funcDef.Name, argList); localProcedure = codeBlock.procedureTable.procList[globalProcIndex]; Debug.Assert(null != localProcedure); // Copy the active function to the core so nested language blocks can refer to it core.ProcNode = localProcedure; // Arguments have been allocated, update the baseOffset localProcedure.localCount = core.BaseOffset; ProtoCore.FunctionEndPoint fep = null; //Traverse default argument foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList) { if (!argNode.isDefault) { continue; } BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; IdentifierNode iNodeTemp = new IdentifierNode() { Value = ProtoCore.DSASM.Constants.kTempDefaultArg, Name = ProtoCore.DSASM.Constants.kTempDefaultArg, datatype = core.TypeSystem.BuildTypeObject(PrimitiveType.kTypeVar, false) }; BinaryExpressionNode bNodeTemp = new BinaryExpressionNode(); bNodeTemp.LeftNode = iNodeTemp; bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign; bNodeTemp.RightNode = bNode.LeftNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); ////duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; //InlineConditionalNode icNode = new InlineConditionalNode(); //BinaryExpressionNode cExprNode = new BinaryExpressionNode(); //cExprNode.Optr = ProtoCore.DSASM.Operator.eq; //cExprNode.LeftNode = iNodeTemp; //cExprNode.RightNode = new DefaultArgNode(); //icNode.ConditionExpression = cExprNode; //icNode.TrueExpression = bNode.RightNode; //icNode.FalseExpression = iNodeTemp; //bNodeTemp.LeftNode = bNode.LeftNode; //bNodeTemp.RightNode = icNode; //EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } // Traverse definition bool hasReturnStatement = false; foreach (ImperativeNode bnode in funcDef.FunctionBody.Body) { DfsTraverse(bnode, ref inferedType); BinaryExpressionNode binaryNode = bnode as BinaryExpressionNode; hasReturnStatement = hasReturnStatement || ((binaryNode != null) && (binaryNode.LeftNode.Name == ProtoCore.DSDefinitions.Kw.kw_return)); } // All locals have been stack allocated, update the local count of this function localProcedure.localCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values) { if (symnode.functionIndex == localProcedure.procId && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.pc; record.locals = localProcedure.localCount; record.classIndex = ProtoCore.DSASM.Constants.kInvalidIndex; record.funcIndex = localProcedure.procId; fep = new ProtoCore.Lang.JILFunctionEndPoint(record); // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count]; fep.BlockScope = this.codeBlock.codeBlockId; localProcedure.argTypeList.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = ProtoCore.DSASM.Constants.kInvalidIndex + 1; if (!core.FunctionTable.GlobalFuncTable.ContainsKey(classIndexAtCallsite)) { Dictionary<string, FunctionGroup> funcList = new Dictionary<string, FunctionGroup>(); core.FunctionTable.GlobalFuncTable.Add(classIndexAtCallsite, funcList); } Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } //Fuqiang: return is already done in traversing the function body //// function return //EmitInstrConsole(ProtoCore.DSASM.kw.ret); //EmitReturn(); } core.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; argOffset = 0; core.BaseOffset = 0; codeBlock.blockType = originalBlockType; }