Example #1
0
        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);
        }
Example #2
0
        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);
        }
Example #4
0
        //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;

            }
        }
Example #5
0
        //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;
        }
Example #6
0
        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;
        }
Example #7
0
        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;
        }
Example #8
0
        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;
        }
Example #9
0
        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;
        }
Example #10
0
        /// <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;
        }
Example #11
0
        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;
        }
Example #12
0
        //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;
        }
Example #15
0
        //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;
        }
Example #16
0
        /// <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;
        }
Example #17
0
        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;
        }
Example #18
0
        /// <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;
            }
        }
Example #19
0
        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;
        }
Example #20
0
        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;
        }
Example #21
0
        /// <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}");
            }
        }
Example #22
0
        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;
        }
Example #23
0
        /// <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;
        }
Example #24
0
        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;
        }
Example #25
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())
            {
                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;
        }
Example #26
0
        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;
        }
Example #27
0
        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);
        }
Example #28
0
        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);
                               }
                           }
                        }
                    }
                }
            }
        }
Example #29
0
        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;
        }