public ClassNode(ClassNode rhs) { IsImportedClass = rhs.IsImportedClass; name = rhs.name; size = rhs.size; hasCachedDisposeMethod = rhs.hasCachedDisposeMethod; disposeMethod = rhs.disposeMethod; rank = rhs.rank; symbols = new SymbolTable("classscope", 0); if (rhs.symbols != null) { symbols = new SymbolTable(rhs.symbols.ScopeName, rhs.symbols.RuntimeIndex); } defaultArgExprList = new List<AST.AssociativeAST.AssociativeNode>(); classId = rhs.classId; int classRuntimProc = ProtoCore.DSASM.Constants.kInvalidIndex; vtable = new ProcedureTable(classRuntimProc); if (rhs.vtable != null) { vtable = new ProcedureTable(rhs.vtable); } baseList = new List<int>(rhs.baseList); ExternLib = rhs.ExternLib; typeSystem = rhs.typeSystem; coerceTypes = new Dictionary<int, int>(rhs.coerceTypes); }
public static ProcedureNode GetClassAndProcFromGlobalInstance(ProcedureNode procNode, Core core, out int classIndex, List <Type> argTypeList) { string className = ProtoCore.Utils.CoreUtils.GetClassDeclarationName(procNode, core); classIndex = core.ClassTable.IndexOf(className); int removelength = 0; if (ProtoCore.Utils.CoreUtils.IsGlobalInstanceGetterSetter(procNode.name)) { if (ProtoCore.Utils.CoreUtils.IsGlobalInstanceSetter(procNode.name)) { removelength = procNode.name.IndexOf(ProtoCore.DSASM.Constants.kSetterPrefix); } else { removelength = procNode.name.IndexOf(ProtoCore.DSASM.Constants.kGetterPrefix); } } else { removelength = procNode.name.IndexOf(ProtoCore.DSASM.Constants.kGlobalInstanceFunctionPrefix); removelength += ProtoCore.DSASM.Constants.kGlobalInstanceFunctionPrefix.Length; } string functionName = procNode.name.Remove(0, removelength); //ProtoCore.DSASM.ProcedureNode tmpProcNode = core.ClassTable.list[classIndex].GetFirstMemberFunction(functionName, procNode.argTypeList.Count - 1); int functionIndex = core.ClassTable.ClassNodes[classIndex].vtable.IndexOfExact(functionName, argTypeList, procNode.isAutoGeneratedThisProc); ProtoCore.DSASM.ProcedureNode tmpProcNode = core.ClassTable.ClassNodes[classIndex].vtable.procList[functionIndex]; return(tmpProcNode); }
public ClassNode(ClassNode rhs) { IsImportedClass = rhs.IsImportedClass; Name = rhs.Name; Size = rhs.Size; hasCachedDisposeMethod = rhs.hasCachedDisposeMethod; disposeMethod = rhs.disposeMethod; Rank = rhs.Rank; Symbols = new SymbolTable("classscope", 0); if (rhs.Symbols != null) { Symbols = new SymbolTable(rhs.Symbols.ScopeName, rhs.Symbols.RuntimeIndex); } DefaultArgExprList = new List<AST.AssociativeAST.AssociativeNode>(); ID = rhs.ID; int classRuntimProc = ProtoCore.DSASM.Constants.kInvalidIndex; ProcTable = new ProcedureTable(classRuntimProc); if (rhs.ProcTable != null) { ProcTable = new ProcedureTable(rhs.ProcTable); } Bases = new List<int>(rhs.Bases); ExternLib = rhs.ExternLib; TypeSystem = rhs.TypeSystem; CoerceTypes = new Dictionary<int, int>(rhs.CoerceTypes); }
public DSFunction(ProcedureNode dsProcedure) { procedure = dsProcedure; foreach (var arg in procedure.argInfoList) { InPortData.Add(new PortData(arg.Name, "parameter", typeof(object))); } OutPortData.Add(new PortData("", "Object inspected", typeof(object))); RegisterAllPorts(); NickName = procedure.name; }
public void PushProcReference(ProtoCore.DSASM.ProcedureNode proc) { Debug.Assert(null != proc); Debug.Assert(null != updateNodeRefList); UpdateNode updateNode = new UpdateNode(); updateNode.procNode = proc; updateNode.nodeType = UpdateNodeType.kMethod; UpdateNodeRef nodeRef = new UpdateNodeRef(); nodeRef.PushUpdateNode(updateNode); updateNodeRefList.Add(nodeRef); }
public FunctionPointerEvaluator(StackValue pointer, Interpreter dsi) { Validity.Assert(pointer.optype == AddressType.FunctionPointer); mRunTime = dsi; Core core = dsi.runtime.Core; int fptr = (int)pointer.opdata; ProtoCore.DSASM.FunctionPointerNode fptrNode; if (core.FunctionPointerTable.functionPointerDictionary.TryGetByFirst(fptr, out fptrNode)) { int blockId = fptrNode.blockId; int procId = fptrNode.procId; mProcNode = dsi.runtime.exe.procedureTable[blockId].procList[procId]; } mCallSite = new ProtoCore.CallSite(ProtoCore.DSASM.Constants.kGlobalScope, Name, core.FunctionTable, core.Options.ExecutionMode); }
public FunctionPointerEvaluator(StackValue pointer, Interpreter dsi) { Validity.Assert(pointer.IsFunctionPointer); interpreter = dsi; RuntimeCore runtimeCore = dsi.runtime.RuntimeCore; int fptr = (int)pointer.opdata; FunctionPointerNode fptrNode; int classScope = Constants.kGlobalScope; if (runtimeCore.DSExecutable.FuncPointerTable.functionPointerDictionary.TryGetByFirst(fptr, out fptrNode)) { int blockId = fptrNode.blockId; int procId = fptrNode.procId; classScope = fptrNode.classScope; procNode = dsi.runtime.GetProcedureNode(blockId, classScope, procId); } callsite = new ProtoCore.CallSite(classScope, Name, interpreter.runtime.exe.FunctionTable, runtimeCore.Options.ExecutionMode); }
public ProcedureNode GetFirstStaticFunctionBy(string procName, int argCount) { if (ProcTable == null) { return(null); } ProcedureNode procNode = ProcTable.GetFunctionsByNameAndArgumentNumber(procName, argCount) .Where(p => p.IsStatic) .FirstOrDefault(); if (procNode != null) { return(procNode); } if (Base != Constants.kInvalidIndex) { var baseClass = TypeSystem.classTable.ClassNodes[Base]; procNode = baseClass.GetFirstStaticFunctionBy(procName, argCount); } return(procNode); }
public ProcedureNode GetDisposeMethod() { if (!hasCachedDisposeMethod) { hasCachedDisposeMethod = true; if (ProcTable == null) { disposeMethod = null; } else { foreach (ProcedureNode procNode in ProcTable.Procedures) { if (CoreUtils.IsDisposeMethod(procNode.Name) && procNode.ArgumentInfos.Count == 0) { disposeMethod = procNode; break; } } } } return(disposeMethod); }
public ProcedureNode GetDisposeMethod() { if (!hasCachedDisposeMethod) { hasCachedDisposeMethod = true; if (vtable == null) { disposeMethod = null; } else { foreach (ProcedureNode procNode in vtable.procList) { if (procNode.name == ProtoCore.DSDefinitions.Kw.kw_Dispose && procNode.argInfoList.Count == 0) { disposeMethod = procNode; break; } } } } return(disposeMethod); }
public ClassNode() { IsImportedClass = false; Name = null; Size = 0; hasCachedDisposeMethod = false; disposeMethod = null; Rank = ProtoCore.DSASM.Constants.kDefaultClassRank; Symbols = new SymbolTable("classscope", 0); ID = (int)PrimitiveType.InvalidType; // Jun TODO: how significant is runtime index for class procedures? int classRuntimProc = ProtoCore.DSASM.Constants.kInvalidIndex; ProcTable = new ProcedureTable(classRuntimProc); Base = Constants.kInvalidIndex; ExternLib = string.Empty; // Set default allowed coerce types CoerceTypes = new Dictionary<int, int>(); CoerceTypes.Add((int)ProtoCore.PrimitiveType.Var, (int)ProtoCore.DSASM.ProcedureDistance.CoerceScore); CoerceTypes.Add((int)ProtoCore.PrimitiveType.Array, (int)ProtoCore.DSASM.ProcedureDistance.CoerceScore); CoerceTypes.Add((int)ProtoCore.PrimitiveType.Null, (int)ProtoCore.DSASM.ProcedureDistance.CoerceScore); }
public ProcedureNode GetDisposeMethod() { if (!hasCachedDisposeMethod) { hasCachedDisposeMethod = true; if (vtable == null) { disposeMethod = null; } else { foreach (ProcedureNode procNode in vtable.procList) { if (CoreUtils.IsDisposeMethod(procNode.name) && procNode.argInfoList.Count == 0) { disposeMethod = procNode; break; } } } } return(disposeMethod); }
public ClassNode() { IsImportedClass = false; name = null; size = 0; hasCachedDisposeMethod = false; disposeMethod = null; rank = ProtoCore.DSASM.Constants.kDefaultClassRank; symbols = new SymbolTable("classscope", 0); defaultArgExprList = new List<AST.AssociativeAST.BinaryExpressionNode>(); classId = (int)PrimitiveType.kInvalidType; // Jun TODO: how significant is runtime index for class procedures? int classRuntimProc = ProtoCore.DSASM.Constants.kInvalidIndex; vtable = new ProcedureTable(classRuntimProc); baseList = new List<int>(); ExternLib = string.Empty; // Set default allowed coerce types coerceTypes = new Dictionary<int, int>(); coerceTypes.Add((int)ProtoCore.PrimitiveType.kTypeVar, (int)ProtoCore.DSASM.ProcedureDistance.kCoerceScore); coerceTypes.Add((int)ProtoCore.PrimitiveType.kTypeArray, (int)ProtoCore.DSASM.ProcedureDistance.kCoerceScore); coerceTypes.Add((int)ProtoCore.PrimitiveType.kTypeNull, (int)ProtoCore.DSASM.ProcedureDistance.kCoerceScore); }
public ClassNode() { IsImportedClass = false; Name = null; Size = 0; hasCachedDisposeMethod = false; disposeMethod = null; Rank = ProtoCore.DSASM.Constants.kDefaultClassRank; Symbols = new SymbolTable("classscope", 0); ID = (int)PrimitiveType.InvalidType; // Jun TODO: how significant is runtime index for class procedures? int classRuntimProc = ProtoCore.DSASM.Constants.kInvalidIndex; ProcTable = new ProcedureTable(classRuntimProc); Base = Constants.kInvalidIndex; ExternLib = string.Empty; // Set default allowed coerce types CoerceTypes = new Dictionary <int, int>(); CoerceTypes.Add((int)ProtoCore.PrimitiveType.Var, (int)ProtoCore.DSASM.ProcedureDistance.CoerceScore); CoerceTypes.Add((int)ProtoCore.PrimitiveType.Array, (int)ProtoCore.DSASM.ProcedureDistance.CoerceScore); CoerceTypes.Add((int)ProtoCore.PrimitiveType.Null, (int)ProtoCore.DSASM.ProcedureDistance.CoerceScore); }
public ProcedureNode GetFirstMemberFunctionBy(string procName, int argCount) { if (ProcTable == null) { return(null); } ProcedureNode procNode = ProcTable.GetFunctionsBy(procName, argCount).FirstOrDefault(); if (procNode != null) { return(procNode); } foreach (int baseClassIndex in Bases) { var baseClass = TypeSystem.classTable.ClassNodes[baseClassIndex]; procNode = baseClass.GetFirstMemberFunctionBy(procName, argCount); if (null != procNode) { break; } } return(procNode); }
/// <summary> /// Try to get the original procedure node that the function pointer /// points to. /// </summary> /// <param name="functionPointer">Function pointer</param> /// <param name="core">Core</param> /// <param name="procNode">Procedure node</param> /// <returns></returns> public bool TryGetFunction(StackValue functionPointer, RuntimeCore runtimeCore, out ProcedureNode procNode) { procNode = null; int index = functionPointer.FunctionPointer; FunctionPointerNode fptrNode; if (functionPointerDictionary.TryGetByFirst(index, out fptrNode)) { var blockId = fptrNode.blockId; var classScope = fptrNode.classScope; var functionIndex = fptrNode.procId; if (classScope != Constants.kGlobalScope) { procNode = runtimeCore.DSExecutable.classTable.ClassNodes[classScope].ProcTable.Procedures[functionIndex]; } else { bool found = runtimeCore.DSExecutable.CompleteCodeBlockDict.TryGetValue(blockId, out CodeBlock codeBlock); Validity.Assert(found, $"Could find code block with codeBlockId {blockId}"); procNode = codeBlock.procedureTable.Procedures[functionIndex]; } return(true); } return(false); }
private void ReturnToCallSiteForReplication(ProcedureNode procNode, int ci, int fi) { // Jump back to Callr to call ResolveForReplication and recompute fep with next argument // Need to push new arguments, then cache block, dim and type, push them before calling callr - pratapa // This functionality has to be common for both Serial mode execution and the debugger - pratap List<StackValue> nextArgs = core.ContinuationStruct.NextDispatchArgs; foreach (var arg in nextArgs) { rmem.Push(arg); } // TODO: Currently functions can be defined only in the global and level 1 blocks (BlockIndex = 0 or 1) // Ideally the procNode.runtimeIndex should capture this information but this needs to be tested - pratapa //rmem.Push(StackValue.BuildNode(AddressType.BlockIndex, core.DebugProps.CurrentBlockId)); rmem.Push(StackValue.BuildBlockIndex(procNode.runtimeIndex)); // The function call dimension for the subsequent feps are assumed to be 0 for now // This is not being used currently except for stack alignment - pratapa rmem.Push(StackValue.BuildArrayDimension(0)); // This is unused in Callr() but needed for stack alignment rmem.Push(StackValue.BuildStaticType((int)PrimitiveType.kTypeVar)); bool explicitCall = true; Callr(fi, ci, core.ContinuationStruct.InitialDepth, ref explicitCall); }
private void SerialReplication(ProcedureNode procNode, ref int exeblock, int ci, int fi, DebugFrame debugFrame = null) { // TODO: Decide where to insert this common code block for Serial mode and Debugging - pratapa if (core.Options.ExecutionMode == ProtoCore.ExecutionMode.Serial || core.Options.IDEDebugMode) { RX = CallSite.PerformReturnTypeCoerce(procNode, core, RX); core.ContinuationStruct.RunningResult.Add(RX); core.ContinuationStruct.Result = RX; pc = core.ContinuationStruct.InitialPC; if (core.ContinuationStruct.Done) { RX = HeapUtils.StoreArray(core.ContinuationStruct.RunningResult.ToArray(), null, core); GCUtils.GCRetain(RX, core); core.ContinuationStruct.RunningResult.Clear(); core.ContinuationStruct.IsFirstCall = true; if (core.Options.IDEDebugMode) { // If stepping over function call in debug mode if (core.DebugProps.RunMode == Runmode.StepNext) { // if stepping over outermost function call if (!core.DebugProps.DebugStackFrameContains(DebugProperties.StackFrameFlagOptions.IsFunctionStepOver)) { core.DebugProps.SetUpStepOverFunctionCalls(core, procNode, debugFrame.ExecutingGraphNode, debugFrame.HasDebugInfo); } } // The DebugFrame passed here is the previous one that was popped off before this call // In the case of Dot call the debugFrame obtained here is the one for the member function // for both Break and non Break cases - pratapa DebugPerformCoercionAndGC(debugFrame); // If call returns to Dot Call, restore debug props for Dot call debugFrame = core.DebugProps.DebugStackFrame.Peek(); if (debugFrame.IsDotCall) { List<Instruction> instructions = istream.instrList; bool wasPopped = RestoreDebugPropsOnReturnFromBuiltIns(ref exeblock, ref instructions); if (wasPopped) { executingBlock = exeblock; core.DebugProps.CurrentBlockId = exeblock; } else { core.DebugProps.RestoreCallrForNoBreak(core, procNode, false); } DebugPerformCoercionAndGC(debugFrame); } //core.DebugProps.DebugEntryPC = currentPC; } // Perform return type coercion, GC and/or GC for Dot methods for Non-debug, Serial mode replication case else { // If member function // 1. Release array arguments to Member function // 2. Release this pointer bool isBaseCall = false; StackValue? thisPtr = null; if (thisPtr != null) { // Replicating member function PerformCoercionAndGC(null, false, thisPtr, core.ContinuationStruct.InitialArguments, core.ContinuationStruct.InitialDotCallDimensions); // Perform coercion and GC for Dot call ProcedureNode dotCallprocNode = null; List<StackValue> dotCallArgs = new List<StackValue>(); List<StackValue> dotCallDimensions = new List<StackValue>(); PerformCoercionAndGC(dotCallprocNode, false, null, dotCallArgs, dotCallDimensions); } else { PerformCoercionAndGC(procNode, isBaseCall, null, core.ContinuationStruct.InitialArguments, core.ContinuationStruct.InitialDotCallDimensions); } } pc++; return; } else { // Jump back to Callr to call ResolveForReplication and recompute fep with next argument core.ContinuationStruct.IsFirstCall = false; ReturnToCallSiteForReplication(procNode, ci, fi); return; } } }
private void EmitFunctionCall(int depth, int type, List<ProtoCore.Type> arglist, ProcedureNode procNode, FunctionCallNode funcCall, bool isGetter = false, BinaryExpressionNode parentExpression = null) { int blockId = procNode.RuntimeIndex; //push value-not-provided default argument for (int i = arglist.Count; i < procNode.ArgumentInfos.Count; i++) { EmitDefaultArgNode(); } // Push the function declaration block and indexed array // Jun TODO: Implementeation of indexing into a function call: // x = f()[0][1] int dimensions = 0; EmitPushVarData(dimensions); // Emit depth EmitInstrConsole(kw.push, depth + "[depth]"); EmitPush(StackValue.BuildInt(depth)); // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, procNode.Name); if (isGetter) { EmitCall(procNode.ID, blockId, type, Constants.kInvalidIndex, Constants.kInvalidIndex, Constants.kInvalidIndex, Constants.kInvalidIndex, procNode.PC); } // Break at function call inside dynamic lang block created for a 'true' or 'false' expression inside an inline conditional else if (core.DebuggerProperties.breakOptions.HasFlag(DebugProperties.BreakpointOptions.EmitInlineConditionalBreakpoint)) { ProtoCore.CodeModel.CodePoint startInclusive = core.DebuggerProperties.highlightRange.StartInclusive; ProtoCore.CodeModel.CodePoint endExclusive = core.DebuggerProperties.highlightRange.EndExclusive; EmitCall(procNode.ID, blockId, type, startInclusive.LineNo, startInclusive.CharNo, endExclusive.LineNo, endExclusive.CharNo, procNode.PC); } else if (parentExpression != null) { EmitCall(procNode.ID, blockId, type, parentExpression.line, parentExpression.col, parentExpression.endLine, parentExpression.endCol, procNode.PC); } else { EmitCall(procNode.ID, blockId, type, funcCall.line, funcCall.col, funcCall.endLine, funcCall.endCol, procNode.PC); } // The function return value EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); StackValue opReturn = StackValue.BuildRegister(Registers.RX); EmitPush(opReturn); }
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; }
// Comment Jun: // Instead of this method, consider storing the name mangled methods original class name and varname public static string GetClassDeclarationName(ProcedureNode procNode, Core core) { string mangledName = procNode.name; mangledName = mangledName.Remove(0, ProtoCore.DSASM.Constants.kGlobalInstanceNamePrefix.Length); int start = mangledName.IndexOf(ProtoCore.DSASM.Constants.kGlobalInstanceFunctionPrefix); mangledName = mangledName.Remove(start); return mangledName; if (ProtoCore.DSASM.Constants.kInvalidIndex == procNode.classScope) { return string.Empty; } Validity.Assert(core.ClassTable.ClassNodes.Count > procNode.classScope); return core.ClassTable.ClassNodes[procNode.classScope].name; }
public bool IsEqual(ProcedureNode rhs) { return(procId == rhs.procId && classScope == rhs.classScope && localCount == rhs.localCount && name == rhs.name); }
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; var returnType = new ProtoCore.Type(); returnType.UID = core.TypeSystem.GetType(funcDef.ReturnType.Name); if (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); returnType.UID = (int)PrimitiveType.kTypeVar; } returnType.rank = funcDef.ReturnType.rank; localProcedure.ReturnType = returnType; 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.ID, argType); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("26384684"); } localProcedure.ArgumentTypes.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { DefaultExpression = aDefaultExpression }; localProcedure.ArgumentInfos.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.ArgumentInfos) { 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.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 = ProtoCore.DSASM.Constants.kInvalidIndex; record.funcIndex = localProcedure.ID; fep = new ProtoCore.Lang.JILFunctionEndPoint(record); // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.ArgumentTypes.Count]; fep.BlockScope = codeBlock.codeBlockId; fep.procedureNode = localProcedure; localProcedure.ArgumentTypes.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; }
public ProcedureNode GetDisposeMethod() { if (!hasCachedDisposeMethod) { hasCachedDisposeMethod = true; if (ProcTable == null) { disposeMethod = null; } else { foreach (ProcedureNode procNode in ProcTable.Procedures) { if (CoreUtils.IsDisposeMethod(procNode.Name) && procNode.ArgumentInfos.Count == 0) { disposeMethod = procNode; break; } } } } return disposeMethod; }
public CodeGen(Core coreObj, ProtoCore.DSASM.CodeBlock parentBlock = null) { Validity.Assert(coreObj != null); core = coreObj; buildStatus = core.BuildStatus; isEntrySet = false; emitReplicationGuide = false; dumpByteCode = core.Options.DumpByteCode; isAssocOperator = false; pc = 0; argOffset = 0; globalClassIndex = core.ClassIndex; context = new ProtoCore.CompileTime.Context(); targetLangBlock = ProtoCore.DSASM.Constants.kInvalidIndex; enforceTypeCheck = true; localProcedure = core.ProcNode; globalProcIndex = null != localProcedure ? localProcedure.ID : ProtoCore.DSASM.Constants.kGlobalScope; tryLevel = 0; functionCallStack = new List<DSASM.ProcedureNode>(); IsAssociativeArrayIndexing = false; if (core.AsmOutput == null) { if (core.Options.CompileToLib) { string path = ""; if (core.Options.LibPath == null) { path += core.Options.RootModulePathName + "ASM"; } else { path = Path.Combine(core.Options.LibPath, Path.GetFileNameWithoutExtension(core.Options.RootModulePathName) + ".dsASM"); } core.AsmOutput = new StreamWriter(File.Open(path, FileMode.Create)); } else { core.AsmOutput = Console.Out; } } ssaPointerStack = new Stack<List<AST.AssociativeAST.AssociativeNode>>(); }
// Deperecate this function after further regression testing and just use DFSGetSymbolList public void DFSGetSymbolList_Simple(Node pNode, ref ProtoCore.Type lefttype, ref int functionindex, ProtoCore.AssociativeGraph.UpdateNodeRef nodeRef) { dynamic node = pNode; if (node is ProtoCore.AST.ImperativeAST.IdentifierListNode || node is ProtoCore.AST.AssociativeAST.IdentifierListNode) { dynamic bnode = node; DFSGetSymbolList_Simple(bnode.LeftNode, ref lefttype, ref functionindex, nodeRef); node = bnode.RightNode; } if (node is ProtoCore.AST.ImperativeAST.IdentifierNode || node is ProtoCore.AST.AssociativeAST.IdentifierNode) { dynamic identnode = node; ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool isAllocated = VerifyAllocation(identnode.Value, lefttype.UID, functionindex, out symbolnode, out isAccessible); if (isAllocated) { if (null == symbolnode) { // It is inaccessible from here due to access modifier. // Just attempt to retrieve the symbol int symindex = core.ClassTable.ClassNodes[lefttype.UID].GetFirstVisibleSymbolNoAccessCheck(identnode.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex != symindex) { symbolnode = core.ClassTable.ClassNodes[lefttype.UID].Symbols.symbolList[symindex]; } } // Since the variable was found, all succeeding nodes in the ident list are class members // Class members have a function scope of kGlobalScope as they are only local to the class, not with any member function functionindex = ProtoCore.DSASM.Constants.kGlobalScope; lefttype = symbolnode.datatype; ProtoCore.AssociativeGraph.UpdateNode updateNode = new AssociativeGraph.UpdateNode(); updateNode.symbol = symbolnode; updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol; nodeRef.PushUpdateNode(updateNode); } else { // Is it a class? int ci = core.ClassTable.IndexOf(identnode.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { lefttype.UID = ci; // Comment Jun: // Create a symbol node that contains information about the class type that contains static properties ProtoCore.DSASM.SymbolNode classSymbol = new DSASM.SymbolNode(); classSymbol.memregion = DSASM.MemoryRegion.kMemStatic; classSymbol.name = identnode.Value; classSymbol.classScope = ci; ProtoCore.AssociativeGraph.UpdateNode updateNode = new AssociativeGraph.UpdateNode(); updateNode.symbol = classSymbol; updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol; nodeRef.PushUpdateNode(updateNode); } else { // In this case, the lhs type is undefined // Just attempt to create a symbol node string ident = identnode.Value; if (0 != ident.CompareTo(ProtoCore.DSDefinitions.Keyword.This)) { symbolnode = new SymbolNode(); symbolnode.name = identnode.Value; ProtoCore.AssociativeGraph.UpdateNode updateNode = new AssociativeGraph.UpdateNode(); updateNode.symbol = symbolnode; updateNode.nodeType = AssociativeGraph.UpdateNodeType.kSymbol; nodeRef.PushUpdateNode(updateNode); } } } } else if (node is ProtoCore.AST.ImperativeAST.FunctionCallNode || node is ProtoCore.AST.AssociativeAST.FunctionCallNode) { string functionName = node.Function.Value; if (ProtoCore.Utils.CoreUtils.IsGetterSetter(functionName)) { string property; if (CoreUtils.TryGetPropertyName(functionName, out property)) { functionName = property; } ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool isAllocated = VerifyAllocation(functionName, lefttype.UID, globalProcIndex, out symbolnode, out isAccessible); if (isAllocated) { if (null == symbolnode) { // It is inaccessible from here due to access modifier. // Just attempt to retrieve the symbol int symindex = core.ClassTable.ClassNodes[lefttype.UID].GetFirstVisibleSymbolNoAccessCheck(functionName); if (ProtoCore.DSASM.Constants.kInvalidIndex != symindex) { symbolnode = core.ClassTable.ClassNodes[lefttype.UID].Symbols.symbolList[symindex]; } } lefttype = symbolnode.datatype; ProtoCore.AssociativeGraph.UpdateNode updateNode = new AssociativeGraph.UpdateNode(); updateNode.symbol = symbolnode; updateNode.nodeType = AssociativeGraph.UpdateNodeType.kSymbol; nodeRef.PushUpdateNode(updateNode); } } else { ProtoCore.AssociativeGraph.UpdateNode updateNode = new AssociativeGraph.UpdateNode(); ProtoCore.DSASM.ProcedureNode procNodeDummy = new DSASM.ProcedureNode(); procNodeDummy.Name = functionName; updateNode.procNode = procNodeDummy; updateNode.nodeType = AssociativeGraph.UpdateNodeType.kMethod; nodeRef.PushUpdateNode(updateNode); } } }
/// <summary> /// Get function by its signature. /// </summary> /// <param name="opts">Matching options</param> /// <param name="outputProcNode">Output procedure node. Null if nothing is found</param> /// <returns>Index of the ProcedureNode in the Procedures list. Returns -1 If nothing is found</returns> internal int GetFunctionBySignature(ProcedureMatchOptions opts, out ProcedureNode outputProcNode) { int outputProcNodeIndex = Constants.kInvalidIndex; outputProcNode = null; // how many default parameters are used int smallestDefaultArgNum = int.MaxValue; for (int ii = 0; ii < Procedures.Count; ++ii) { var f = Procedures[ii]; if (opts.FilterCallback(f) == false) { continue; } if ((opts.FunctionName != f.Name) || (opts.ExcludeAutoGeneratedThisProc && f.IsAutoGeneratedThisProc) || (opts.IsStatic != null) && (opts.IsStatic != f.IsStatic) || (opts.IsConstructor != null) && (opts.IsConstructor != f.IsConstructor)) { goto NotMatch; } if (!f.IsActive) { goto NotMatch; } if (opts.ParameterTypes != null) { var argNum = f.ArgumentTypes.Count; var paramNum = opts.ParameterTypes.Count; if (opts.ExactMatchWithNumArgs && (argNum != paramNum)) { goto NotMatch; } if (opts.ExactMatchWithArgTypes) { for (int k = 0; k < paramNum; k++) { if (f.ArgumentTypes[k].Name != opts.ParameterTypes[k].Name || f.ArgumentTypes[k].UID != opts.ParameterTypes[k].UID) { goto NotMatch; } } } int defaultArgs = f.ArgumentInfos.Count(X => X.DefaultExpression != null); if ((argNum < paramNum) || (defaultArgs < argNum - paramNum)) { // The current procedure has either: // too less arguments that we are looking for. // or // too many arguments(even with defaults) than we are looking for goto NotMatch; } // Look for the function with the least amount of default arguments var num = argNum - paramNum; if (num <= smallestDefaultArgNum) { smallestDefaultArgNum = num; outputProcNodeIndex = ii; outputProcNode = Procedures[ii]; } if (smallestDefaultArgNum == 0) { break; } } else { outputProcNodeIndex = ii; outputProcNode = Procedures[ii]; break; } NotMatch: ; } return(outputProcNodeIndex); }
public ProtoCore.DSASM.ProcedureNode TraverseDotFunctionCall(ProtoCore.AST.Node node, ProtoCore.AST.Node parentNode, int lefttype, int depth, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, ProtoCore.AST.AssociativeAST.BinaryExpressionNode bnode = null) { FunctionCallNode funcCall = null; ProtoCore.DSASM.ProcedureNode procCallNode = null; ProtoCore.DSASM.ProcedureNode procDotCallNode = null; string procName = null; List<ProtoCore.Type> arglist = new List<ProtoCore.Type>(); ProtoCore.Type dotCallType = new ProtoCore.Type(); dotCallType.UID = (int)PrimitiveType.kTypeVar; dotCallType.IsIndexable = false; bool isConstructor = false; bool isStaticCall = false; bool isStaticCallAllowed = false; bool isUnresolvedDot = false; bool isUnresolvedMethod = false; int classIndex = ProtoCore.DSASM.Constants.kInvalidIndex; string className = string.Empty; ProtoCore.AST.AssociativeAST.FunctionDotCallNode dotCall = node as ProtoCore.AST.AssociativeAST.FunctionDotCallNode; funcCall = dotCall.DotCall; procName = dotCall.FunctionCall.Function.Name; List<AssociativeNode> replicationGuide = (dotCall.FunctionCall.Function as IdentifierNode).ReplicationGuides; var dotCallFirstArgument = dotCall.DotCall.FormalArguments[0]; if (dotCallFirstArgument is FunctionDotCallNode) { isUnresolvedDot = true; } else if (dotCallFirstArgument is IdentifierNode || dotCallFirstArgument is ThisPointerNode) { // Check if the lhs identifer is a class name string lhsName = ""; int ci = Constants.kInvalidIndex; if (dotCallFirstArgument is IdentifierNode) { lhsName = (dotCallFirstArgument as IdentifierNode).Name; ci = compileStateTracker.ClassTable.IndexOf(lhsName); classIndex = ci; className = lhsName; // As a class name can be used as property name, we need to // check if this identifier is a property or a class name. // if (ci != Constants.kInvalidIndex && globalClassIndex != Constants.kInvalidIndex) { ProtoCore.DSASM.SymbolNode symbolnode; bool isAccessbile = false; bool hasAllocated = VerifyAllocation(lhsName, globalClassIndex, globalProcIndex, out symbolnode, out isAccessbile); // Well, found a property whose name is class name. Now // we need to check if the RHS function call is // constructor or not. if (hasAllocated && isAccessbile && symbolnode.functionIndex == ProtoCore.DSASM.Constants.kInvalidIndex) { var procnode = GetProcedureFromInstance(ci, dotCall.FunctionCall); if (procnode != null && !procnode.isConstructor) { ci = Constants.kInvalidIndex; lhsName = ""; } } } } if (ci != ProtoCore.DSASM.Constants.kInvalidIndex) { // It is a class name dotCall.DotCall.FormalArguments[0] = new IntNode { value = ci.ToString() }; dotCallFirstArgument = dotCall.DotCall.FormalArguments[0]; inferedType.UID = dotCallType.UID = ci; string rhsName = dotCall.FunctionCall.Function.Name; procCallNode = GetProcedureFromInstance(ci, dotCall.FunctionCall, graphNode); if (null != procCallNode) { isConstructor = procCallNode.isConstructor; // It's a static call if its not a constructor isStaticCall = !procCallNode.isConstructor; // If this is a static call and the first method found was not static // Look further if (isStaticCall && !procCallNode.isStatic) { ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.ClassTable.ClassNodes[ci].GetFirstStaticMemberFunction(procName); if (null != staticProcCallNode) { procCallNode = staticProcCallNode; } } isStaticCallAllowed = procCallNode.isStatic && isStaticCall; } else { ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.ClassTable.ClassNodes[ci].GetFirstStaticMemberFunction(procName); string functionName = dotCall.FunctionCall.Function.Name; string property; if (null != staticProcCallNode) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodHasInvalidArguments, functionName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else if (CoreUtils.TryGetPropertyName(functionName, out property)) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticProperty, lhsName, property); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticMethod, lhsName, functionName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } } } if (dotCall.DotCall.FormalArguments.Count == ProtoCore.DSASM.Constants.kDotCallArgCount) { if (dotCallFirstArgument is IdentifierNode) { ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool isAllocated = VerifyAllocation((dotCallFirstArgument as IdentifierNode).Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); if (isAllocated && symbolnode.datatype.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = symbolnode.datatype.UID; if (ProtoCore.DSASM.Constants.kInvalidIndex != inferedType.UID) { procCallNode = GetProcedureFromInstance(symbolnode.datatype.UID, dotCall.FunctionCall); } if (null != procCallNode) { if (procCallNode.isConstructor) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { // A constructor cannot be called from an instance string message = String.Format(ProtoCore.BuildData.WarningMessage.KCallingConstructorOnInstance, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingConstructorOnInstance, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } isUnresolvedDot = true; isUnresolvedMethod = true; } else { isAccessible = procCallNode.access == ProtoCore.DSASM.AccessSpecifier.kPublic || (procCallNode.access == ProtoCore.DSASM.AccessSpecifier.kPrivate && procCallNode.classScope == globalClassIndex); if (!isAccessible) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } } if (null != procCallNode) { int dynamicRhsIndex = int.Parse((dotCall.DotCall.FormalArguments[1] as IntNode).value); compileStateTracker.DynamicFunctionTable.functionTable[dynamicRhsIndex].classIndex = procCallNode.classScope; compileStateTracker.DynamicFunctionTable.functionTable[dynamicRhsIndex].procedureIndex = procCallNode.procId; compileStateTracker.DynamicFunctionTable.functionTable[dynamicRhsIndex].pc = procCallNode.pc; } } } } else { isUnresolvedDot = true; } } else if (dotCallFirstArgument is ThisPointerNode) { if (globalClassIndex != Constants.kInvalidIndex) { procCallNode = GetProcedureFromInstance(globalClassIndex, dotCall.FunctionCall); if (null != procCallNode && procCallNode.isConstructor) { dotCall.DotCall.FormalArguments[0] = new IntNode { value = globalClassIndex.ToString() }; dotCallFirstArgument = dotCall.DotCall.FormalArguments[0]; inferedType.UID = dotCallType.UID = ci; } } } } } else if (funcCall.FormalArguments[0] is IntNode) { inferedType.UID = dotCallType.UID = int.Parse((funcCall.FormalArguments[0] as IntNode).value); classIndex = inferedType.UID; procCallNode = GetProcedureFromInstance(dotCallType.UID, dotCall.FunctionCall, graphNode); if (null != procCallNode) { // It's a static call if its not a constructor isConstructor = procCallNode.isConstructor; isStaticCall = !procCallNode.isConstructor; // If this is a static call and the first method found was not static // Look further if (isStaticCall && !procCallNode.isStatic) { ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetFirstStaticMemberFunction(procName); if (null != staticProcCallNode) { procCallNode = staticProcCallNode; } } isStaticCallAllowed = procCallNode.isStatic && isStaticCall; className = compileStateTracker.ClassTable.ClassNodes[dotCallType.UID].name; if (isStaticCall && !isStaticCallAllowed) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { string property; className = compileStateTracker.ClassTable.ClassNodes[dotCallType.UID].name; ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetFirstStaticMemberFunction(procName); if (null != staticProcCallNode) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodHasInvalidArguments, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else if (CoreUtils.TryGetPropertyName(procName, out property)) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticProperty, property, className); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticMethod, procName, className); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } } isUnresolvedMethod = true; } else { inferedType = procCallNode.returntype; } } } // Its an accceptable method at this point if (!isUnresolvedMethod) { int funtionArgCount = 0; //foreach (AssociativeNode paramNode in funcCall.FormalArguments) for (int n = 0; n < funcCall.FormalArguments.Count; ++n) { AssociativeNode paramNode = funcCall.FormalArguments[n]; ProtoCore.Type paramType = new ProtoCore.Type(); paramType.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; paramType.IsIndexable = false; emitReplicationGuide = false; // If it's a binary node then continue type check, otherwise disable type check and just take the type of paramNode itself // f(1+2.0) -> type check enabled - param is typed as double // f(2) -> type check disabled - param is typed as int enforceTypeCheck = !(paramNode is BinaryExpressionNode); // TODO Jun: Cleansify me // What im doing is just taking the second parameter of the dot op (The method call) // ...and adding it to the graph node dependencies if (ProtoCore.DSASM.Constants.kDotArgIndexDynTableIndex == n) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { if (!isConstructor) { if (null != procCallNode) { if (graphNode.dependentList.Count > 0) { ProtoCore.AssociativeGraph.UpdateNodeRef nodeRef = new ProtoCore.AssociativeGraph.UpdateNodeRef(); ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode(); ProtoCore.DSASM.ProcedureNode procNodeDummy = new ProtoCore.DSASM.ProcedureNode(); if (procCallNode.isAutoGenerated) { ProtoCore.DSASM.SymbolNode sym = new ProtoCore.DSASM.SymbolNode(); sym.name = procName.Remove(0, ProtoCore.DSASM.Constants.kSetterPrefix.Length); updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol; updateNode.symbol = sym; } else { procNodeDummy.name = procName; updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kMethod; updateNode.procNode = procNodeDummy; } graphNode.dependentList[0].updateNodeRefList[0].nodeList.Add(updateNode); } } else { // comment Jun: // This is dotarg whos first argument is also a dotarg // dotarg(dorarg...)...) if (graphNode.dependentList.Count > 0) { if (ProtoCore.Utils.CoreUtils.IsGetterSetter(procName)) { ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode(); ProtoCore.DSASM.SymbolNode sym = new ProtoCore.DSASM.SymbolNode(); sym.name = procName.Remove(0, ProtoCore.DSASM.Constants.kSetterPrefix.Length); updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol; updateNode.symbol = sym; graphNode.dependentList[0].updateNodeRefList[0].nodeList.Add(updateNode); } } } } } } // Traversing the first arg (the LHS pointer/Static instanct/Constructor if (ProtoCore.DSASM.Constants.kDotArgIndexPtr == n) { // Comment Jun: // Allow guides only on 'this' pointers for non getter/setter methods // No guides for 'this' pointers in constructors calls (There is no this pointer yet) // /* class C { def f(a : int) { return = 10; } } p = {C.C(), C.C()}; x = p<1>.f({1,2}<2>); // guides allowed on the pointer 'p' class A { x : var[]; constructor A() { x = {1,2}; } } a = A.A(); b = A.A(); c = a<1>.x<2>; // guides not allowed on getter */ if (!ProtoCore.Utils.CoreUtils.IsGetterSetter(procName) && !isConstructor) { emitReplicationGuide = true; } DfsTraverse(paramNode, ref paramType, false, graphNode, subPass, bnode); if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { if (isStaticCall && isStaticCallAllowed) { Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != classIndex); Validity.Assert(string.Empty != className); SymbolNode classSymbol = new SymbolNode(); classSymbol.name = className; classSymbol.classScope = classIndex; ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(classSymbol, ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol); graphNode.PushDependent(dependentNode); } } } // Traversing the actual arguments passed into the function (not the dot function) else if (ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs == n) { int defaultAdded = 0; // If its null this is the second call in a chained dot if (null != procCallNode) { // Check how many args were passed in.... against what is expected defaultAdded = procCallNode.argInfoList.Count - dotCall.FunctionCall.FormalArguments.Count; } // Enable graphnode dependencies if its a setter method bool allowDependentState = null != graphNode ? graphNode.allowDependents : false; if (ProtoCore.Utils.CoreUtils.IsSetter(procName)) { // If the arguments are not temporaries ProtoCore.AST.AssociativeAST.ExprListNode exprList = paramNode as ExprListNode; Validity.Assert(1 == exprList.list.Count); string varname = string.Empty; if (exprList.list[0] is IdentifierNode) { varname = (exprList.list[0] as IdentifierNode).Name; // Only allow the acutal function variables and SSA temp vars // TODO Jun: determine what temp could be passed in that is autodegenerated and non-SSA if (!ProtoCore.Utils.CoreUtils.IsAutoGeneratedVar(varname) || ProtoCore.Utils.CoreUtils.IsSSATemp(varname)) { graphNode.allowDependents = true; } } else { graphNode.allowDependents = true; } } emitReplicationGuide = true; if (defaultAdded > 0) { ProtoCore.AST.AssociativeAST.ExprListNode exprList = paramNode as ExprListNode; if (subPass != AssociativeSubCompilePass.kUnboundIdentifier) { for (int i = 0; i < defaultAdded; i++) { exprList.list.Add(new DefaultArgNode()); } } DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); funtionArgCount = exprList.list.Count; } else { Validity.Assert(paramNode is ProtoCore.AST.AssociativeAST.ExprListNode); ProtoCore.AST.AssociativeAST.ExprListNode exprList = paramNode as ProtoCore.AST.AssociativeAST.ExprListNode; // Comment Jun: This is a getter/setter or a an auto-generated thisarg function... // ...add the dynamic sv that will be resolved as a pointer at runtime if (!isStaticCall && !isConstructor) { //if (null != procCallNode && ProtoCore.Utils.CoreUtils.IsGetterSetter(procCallNode.name) && AssociativeSubCompilePass.kNone == subPass) // TODO Jun: pls get rid of subPass checking outside the core travesal if (ProtoCore.DSASM.AssociativeSubCompilePass.kNone == subPass) { exprList.list.Insert(0, new DynamicNode()); } } if (exprList.list.Count > 0) { foreach (ProtoCore.AST.AssociativeAST.AssociativeNode exprListNode in exprList.list) { bool repGuideState = emitReplicationGuide; if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { if (exprListNode is ProtoCore.AST.AssociativeAST.ExprListNode || exprListNode is ProtoCore.AST.AssociativeAST.GroupExpressionNode) { if (compileStateTracker.Options.TempReplicationGuideEmptyFlag) { // Emit the replication guide for the exprlist List<ProtoCore.AST.AssociativeAST.AssociativeNode> repGuideList = GetReplicationGuides(exprListNode); EmitReplicationGuides(repGuideList, true); emitReplicationGuide = false; // Pop off the guide if the current element was an array if (null != repGuideList) { EmitInstrConsole(ProtoCore.DSASM.kw.popg); EmitPopGuide(); } } } } else { emitReplicationGuide = false; } DfsTraverse(exprListNode, ref paramType, false, graphNode, subPass, bnode); emitReplicationGuide = repGuideState; } if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { EmitInstrConsole(ProtoCore.DSASM.kw.alloca, exprList.list.Count.ToString()); EmitPopArray(exprList.list.Count); if (exprList.ArrayDimensions != null) { int dimensions = DfsEmitArrayIndexHeap(exprList.ArrayDimensions, graphNode); EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, dimensions.ToString() + "[dim]"); EmitPushArrayIndex(dimensions); } } } else { if (exprList != null) { bool emitReplicationGuideState = emitReplicationGuide; emitReplicationGuide = false; DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); emitReplicationGuide = emitReplicationGuideState; } else { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); } } funtionArgCount = exprList.list.Count; } emitReplicationGuide = false; // Restore the state only if it is a setter method if (ProtoCore.Utils.CoreUtils.IsSetter(procName)) { graphNode.allowDependents = allowDependentState; } } else if (ProtoCore.DSASM.Constants.kDotArgIndexArgCount == n) { ProtoCore.AST.AssociativeAST.IntNode argNumNode = new ProtoCore.AST.AssociativeAST.IntNode() { value = funtionArgCount.ToString() }; DfsTraverse(argNumNode, ref paramType, false, graphNode, subPass); } else { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); } emitReplicationGuide = false; enforceTypeCheck = true; arglist.Add(paramType); } } if (subPass == ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { return null; } // Comment Jun: Append the lhs pointer as an argument to the overloaded function if (!isConstructor && !isStaticCall) { Validity.Assert(dotCall.DotCall.FormalArguments[ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs] is ExprListNode); ExprListNode functionArgs = dotCall.DotCall.FormalArguments[ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs] as ExprListNode; functionArgs.list.Insert(0, dotCall.DotCall.FormalArguments[ProtoCore.DSASM.Constants.kDotArgIndexPtr]); } if (isUnresolvedMethod) { EmitNullNode(new NullNode(), ref inferedType); return null; } procDotCallNode = compileStateTracker.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotArgMethodName, arglist, codeBlock); // From here on, handle the actual procedure call int type = ProtoCore.DSASM.Constants.kInvalidIndex; int refClassIndex = ProtoCore.DSASM.Constants.kInvalidIndex; if (parentNode != null && parentNode is ProtoCore.AST.AssociativeAST.IdentifierListNode) { ProtoCore.AST.Node leftnode = (parentNode as ProtoCore.AST.AssociativeAST.IdentifierListNode).LeftNode; if (leftnode != null && leftnode is ProtoCore.AST.AssociativeAST.IdentifierNode) { refClassIndex = compileStateTracker.ClassTable.IndexOf(leftnode.Name); } } if (dotCallFirstArgument is FunctionCallNode || dotCallFirstArgument is FunctionDotCallNode || dotCallFirstArgument is ExprListNode) { inferedType.UID = arglist[0].UID; } // If lefttype is a valid class then check if calling a constructor if ((int)ProtoCore.PrimitiveType.kInvalidType != inferedType.UID && (int)ProtoCore.PrimitiveType.kTypeVoid != inferedType.UID && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex; procCallNode = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetFirstMemberFunction(procName); } // Try function pointer firstly if ((procCallNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)) { bool isAccessibleFp; ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAllocated = VerifyAllocation(procName, globalClassIndex, globalProcIndex, out symbolnode, out isAccessibleFp); if (isAllocated) // not checking the type against function pointer, as the type could be var { procName = ProtoCore.DSASM.Constants.kFunctionPointerCall; // The graph node always depends on this function pointer if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } } } // Always try global function firstly. Because we dont have syntax // support for calling global function (say, ::foo()), if we try // member function firstly, there is no way to call a global function // For member function, we can use this.foo() to distinguish it from // global function. if ((procCallNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)) { procCallNode = compileStateTracker.GetFirstVisibleProcedure(procName, arglist, codeBlock); if (null != procCallNode) { type = ProtoCore.DSASM.Constants.kGlobalScope; if (compileStateTracker.TypeSystem.IsHigherRank(procCallNode.returntype.UID, inferedType.UID)) { inferedType = procCallNode.returntype; } } } // Try member functions in global class scope if ((procCallNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) && (parentNode == null)) { if (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) { int realType; bool isAccessible; bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex; ProtoCore.DSASM.ProcedureNode memProcNode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (memProcNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); procCallNode = memProcNode; inferedType = procCallNode.returntype; type = realType; if (!isAccessible) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procCallNode; } } } } if (isUnresolvedDot) { // Get the dot call procedure ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode; if (!isConstructor && !isStaticCall) { procNode = compileStateTracker.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotMethodName, null, codeBlock); } if(CoreUtils.IsGetter(procName)) { EmitFunctionCall(depth, type, arglist, procNode, funcCall, true); } else EmitFunctionCall(depth, type, arglist, procNode, funcCall, false, bnode); if (dotCallType.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = dotCallType.UID; } return procCallNode; } if (null != procCallNode) { if (procCallNode.isConstructor && (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && (globalProcIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && (globalClassIndex == inferedType.UID)) { ProtoCore.DSASM.ProcedureNode contextProcNode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; if (contextProcNode.isConstructor && string.Equals(contextProcNode.name, procCallNode.name) && contextProcNode.runtimeIndex == procCallNode.runtimeIndex) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingConstructorInConstructor, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingConstructorInConstructor, message, compileStateTracker.CurrentDSFileName, node.line, node.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procCallNode; } } inferedType = procCallNode.returntype; //if call is replication call if (procCallNode.isThisCallReplication) { inferedType.IsIndexable = true; inferedType.rank++; } // Get the dot call procedure ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode; if (!isConstructor && !isStaticCall) { procNode = compileStateTracker.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotMethodName, null, codeBlock); } if (CoreUtils.IsSetter(procName)) { EmitFunctionCall(depth, type, arglist, procNode, funcCall); } // Do not emit breakpoint at getters only - pratapa else if (CoreUtils.IsGetter(procName)) { EmitFunctionCall(depth, type, arglist, procNode, funcCall, true); } else { EmitFunctionCall(depth, type, arglist, procNode, funcCall, false, bnode); } if (dotCallType.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = dotCallType.UID; } if (isConstructor) { foreach (AssociativeNode paramNode in dotCall.FunctionCall.FormalArguments) { // Get the lhs symbol list ProtoCore.Type ltype = new ProtoCore.Type(); ltype.UID = globalClassIndex; ProtoCore.AssociativeGraph.UpdateNodeRef argNodeRef = new ProtoCore.AssociativeGraph.UpdateNodeRef(); DFSGetSymbolList(paramNode, ref ltype, argNodeRef); if (null != graphNode) { graphNode.updatedArguments.Add(argNodeRef); } } graphNode.firstProc = procCallNode; } return procCallNode; } else { // Function does not exist at this point but we try to reolve at runtime if (depth <= 0 && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { if (inferedType.UID != (int)PrimitiveType.kTypeVar) { if (!compileStateTracker.Options.SuppressFunctionResolutionWarning) { string property; if (CoreUtils.TryGetPropertyName(procName, out property)) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kPropertyNotFound, property); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kPropertyNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodNotFound, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } } inferedType.UID = (int)PrimitiveType.kTypeNull; } // Get the dot call procedure ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode; if (!isConstructor && !isStaticCall) { procNode = compileStateTracker.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotMethodName, null, codeBlock); } if (CoreUtils.IsGetter(procName)) { EmitFunctionCall(depth, type, arglist, procNode, funcCall, true); } else EmitFunctionCall(depth, type, arglist, procNode, funcCall, false, bnode); if (dotCallType.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = dotCallType.UID; } } else { if (procName == ProtoCore.DSASM.Constants.kFunctionPointerCall && depth == 0) { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(procName, arglist, lefttype); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); var iNode = nodeBuilder.BuildIdentfier(funcCall.Function.Name); EmitIdentifierNode(iNode, ref inferedType); } else { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(funcCall.Function.Name, arglist, lefttype); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); } // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, funcCall.Function.Name + "[dynamic]"); EmitDynamicCall(compileStateTracker.DynamicFunctionTable.functionTable.Count - 1, globalClassIndex, depth, funcCall.line, funcCall.col, funcCall.endLine, funcCall.endCol); // The function return value EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); if (compileStateTracker.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide) { int guides = EmitReplicationGuides(replicationGuide); EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, guides + "[guide]"); EmitPushReplicationGuide(guides); } //assign inferedType to var inferedType.UID = (int)PrimitiveType.kTypeVar; } } return procDotCallNode; }
internal MethodMirror(ProcedureNode procNode) { MethodName = procNode.Name; this.Name = MethodName; IsConstructor = procNode.IsConstructor; IsStatic = procNode.IsStatic; this.procNode = procNode; }
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 = globalClassIndex; localProcedure.returntype.IsIndexable = false; localProcedure.isConstructor = true; localProcedure.runtimeIndex = 0; localProcedure.isExternal = funcDef.IsExternLib; Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class"); localProcedure.localCount = 0; localProcedure.classScope = globalClassIndex; int 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.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 = 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); } } int findex = 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 != 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("44B557F1"); } }); } 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 (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 = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList); Debug.Assert(null == localProcedure); localProcedure = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; Debug.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 //Debug.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 compileStateTracker.ClassTable.ClassNodes[globalClassIndex].defaultArgExprList) { ProtoCore.AssociativeGraph.GraphNode graphNode = new ProtoCore.AssociativeGraph.GraphNode(); graphNode.isParent = true; 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(compileStateTracker.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 = compileStateTracker.BaseOffset; compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex].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 == 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; compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, 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 compileStateTracker.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; compileStateTracker.BaseOffset = 0; argOffset = 0; classOffset = 0; codeBlock.blockType = originalBlockType; }
private void EmitConstructorDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, GraphNode gNode = null) { ConstructorDefinitionNode funcDef = node as ConstructorDefinitionNode; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingMemberFunctionSig()) { Validity.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.Name = funcDef.Name; localProcedure.PC = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.LocalCount = 0;// Defer till all locals are allocated ProtoCore.Type returnType = localProcedure.ReturnType; if (globalClassIndex != -1) returnType.Name = core.ClassTable.ClassNodes[globalClassIndex].Name; returnType.UID = globalClassIndex; returnType.rank = 0; localProcedure.ReturnType = returnType; localProcedure.IsConstructor = true; localProcedure.RuntimeIndex = 0; localProcedure.IsExternal = funcDef.IsExternLib; Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class"); localProcedure.LocalCount = 0; localProcedure.ClassID = globalClassIndex; localProcedure.MethodAttribute = funcDef.MethodAttributes; int peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures.Count; // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { var argInfo = BuildArgumentInfoFromVarDeclNode(argNode); localProcedure.ArgumentInfos.Add(argInfo); var argType = BuildArgumentTypeFromVarDeclNode(argNode, gNode); localProcedure.ArgumentTypes.Add(argType); argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(argInfo.Name, argType)); } localProcedure.IsVarArg = funcDef.Signature.IsVarArg; } int findex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Append(localProcedure); // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != findex) { Validity.Assert(peekFunctionindex == localProcedure.ID); argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, findex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("44B557F1"); } }); } else { string message = String.Format(ProtoCore.Properties.Resources.kMethodAlreadyDefined, localProcedure.Name); buildStatus.LogWarning(WarningID.kFunctionAlreadyDefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, gNode); funcDef.skipMe = true; } } else if (IsParsingMemberFunctionBody()) { EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature, true)); // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, gNode); argList.Add(argType); } } var procNode = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.GetFunctionBySignature(funcDef.Name, argList); globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID; Validity.Assert(null == localProcedure); localProcedure = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex]; Validity.Assert(null != localProcedure); localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.PC = pc; EmitInstrConsole(ProtoCore.DSASM.kw.allocc, localProcedure.Name); EmitAllocc(globalClassIndex); setConstructorStartPC = true; EmitCallingForBaseConstructor(globalClassIndex, funcDef.BaseConstructor); ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { // Traverse default assignment for the class emitDebugInfo = false; List<AssociativeNode> defaultArgList = core.ClassTable.ClassNodes[globalClassIndex].DefaultArgExprList; defaultArgList = BuildSSA(defaultArgList, context); foreach (BinaryExpressionNode bNode in defaultArgList) { ProtoCore.AssociativeGraph.GraphNode graphNode = new ProtoCore.AssociativeGraph.GraphNode(); graphNode.exprUID = bNode.ExpressionUID; graphNode.ssaExpressionUID = bNode.SSAExpressionUID; graphNode.procIndex = globalProcIndex; graphNode.classIndex = globalClassIndex; graphNode.languageBlockId = codeBlock.codeBlockId; graphNode.isAutoGenerated = true; bNode.IsProcedureOwned = graphNode.ProcedureOwned = true; EmitBinaryExpressionNode(bNode, ref inferedType, false, graphNode, subPass); } //Traverse default argument for the constructor foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.ArgumentInfos) { if (!argNode.IsDefault) { continue; } BinaryExpressionNode bNode = argNode.DefaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp =AstFactory.BuildIdentifier(Constants.kTempDefaultArg); BinaryExpressionNode bNodeTemp = new BinaryExpressionNode(); bNodeTemp.LeftNode = iNodeTemp; bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign; bNodeTemp.RightNode = bNode.LeftNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.IsAutoGenerated = true; BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } emitDebugInfo = true; EmitCodeBlock(funcDef.FunctionBody.Body, ref inferedType, subPass, true); // Build dependency within the function ProtoCore.AssociativeEngine.Utils.BuildGraphNodeDependencies( codeBlock.instrStream.dependencyGraph.GetGraphNodesAtScope(globalClassIndex, globalProcIndex)); // All locals have been stack allocated, update the local count of this function localProcedure.LocalCount = core.BaseOffset; core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex].LocalCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[globalClassIndex].Symbols.symbolList.Values) { if (symnode.functionIndex == globalProcIndex && symnode.isArgument) { symnode.index -= localProcedure.LocalCount; } } // JIL FEP ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.PC; record.locals = localProcedure.LocalCount; record.classIndex = globalClassIndex; record.funcIndex = globalProcIndex; // Construct the fep arguments fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.PC; jRecord.locals = localProcedure.LocalCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.ID; ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = false; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.ArgumentTypes; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.ArgumentTypes.Count]; fep.procedureNode = localProcedure; localProcedure.ArgumentTypes.CopyTo(fep.FormalParams, 0); // 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables int classIndexAtCallsite = globalClassIndex + 1; core.FunctionTable.InitGlobalFunctionEntry(classIndexAtCallsite); Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } int startpc = pc; // Constructors auto return EmitInstrConsole(ProtoCore.DSASM.kw.retc); // Stepping out of a constructor body will have the execution cursor // placed right at the closing curly bracket of the constructor definition. // int closeCurlyBracketLine = 0, closeCurlyBracketColumn = -1; if (null != funcDef.FunctionBody) { closeCurlyBracketLine = funcDef.FunctionBody.endLine; closeCurlyBracketColumn = funcDef.FunctionBody.endCol; } // The execution cursor covers exactly one character -- the closing // curly bracket. Note that we decrement the start-column by one here // because end-column of "FunctionBody" here is *after* the closing // curly bracket, so we want one before that. // EmitRetc(closeCurlyBracketLine, closeCurlyBracketColumn - 1, closeCurlyBracketLine, closeCurlyBracketColumn); // Build and append a graphnode for this return statememt ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode(); returnNode.name = ProtoCore.DSDefinitions.Keyword.Return; ProtoCore.AssociativeGraph.GraphNode retNode = new ProtoCore.AssociativeGraph.GraphNode(); //retNode.symbol = returnNode; retNode.PushSymbolReference(returnNode); retNode.procIndex = globalProcIndex; retNode.classIndex = globalClassIndex; retNode.updateBlock.startpc = startpc; retNode.updateBlock.endpc = pc - 1; PushGraphNode(retNode); EmitCompileLogFunctionEnd(); } // Constructors have no return statemetns, reset variables here core.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; core.BaseOffset = 0; argOffset = 0; classOffset = 0; codeBlock.blockType = originalBlockType; }
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; localFunctionDefNode = funcDef; 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.pc = pc; localProcedure.localCount = funcDef.localVars; 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, null, funcDef.line, funcDef.col); localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; } localProcedure.returntype.IsIndexable = funcDef.ReturnType.IsIndexable; localProcedure.returntype.rank = funcDef.ReturnType.rank; localProcedure.runtimeIndex = codeBlock.codeBlockId; globalProcIndex = codeBlock.procedureTable.Append(localProcedure); compileStateTracker.ProcNode = localProcedure; // 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 = BuildArgumentTypeFromVarDeclNode(argNode); 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 { isDefault = aIsDefault, defaultExpression = aDefaultExpression }; localProcedure.argInfoList.Add(argInfo); } } // 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 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); argList.Add(argType); } } // 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); 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; // Arguments have been allocated, update the baseOffset localProcedure.localCount = compileStateTracker.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(compileStateTracker.ExpressionUID++); } } // All locals have been stack allocated, update the local count of this function 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; } } 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; compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep); if (!hasReturnStatement) { if (!compileStateTracker.Options.SuppressFunctionResolutionWarning) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kFunctionNotReturnAtAllCodePaths, localProcedure.name); compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col); } EmitReturnNull(); } EmitCompileLogFunctionEnd(); //Fuqiang: return is already done in traversing the function body //// function return //EmitInstrConsole(ProtoCore.DSASM.kw.ret); //EmitReturn(); } compileStateTracker.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; argOffset = 0; compileStateTracker.BaseOffset = 0; codeBlock.blockType = originalBlockType; localFunctionDefNode = null; }
public FunctionPointerNode(ProcedureNode procNode) { this.procId = procNode.procId; this.classScope = procNode.classScope; this.blockId = procNode.runtimeIndex; }
/// <summary> /// Try to get the original procedure node that the function pointer /// points to. /// </summary> /// <param name="functionPointer">Function pointer</param> /// <param name="core">Core</param> /// <param name="procNode">Procedure node</param> /// <returns></returns> public bool TryGetFunction(StackValue functionPointer, RuntimeCore runtimeCore, out ProcedureNode procNode) { procNode = null; int index = (int)functionPointer.RawIntValue; FunctionPointerNode fptrNode; if (functionPointerDictionary.TryGetByFirst(index, out fptrNode)) { var blockId = fptrNode.blockId; var classScope = fptrNode.classScope; var functionIndex = fptrNode.procId; if (classScope != Constants.kGlobalScope) { procNode = runtimeCore.DSExecutable.classTable.ClassNodes[classScope].vtable.procList[functionIndex]; } else { procNode = runtimeCore.DSExecutable.CompleteCodeBlocks[blockId].procedureTable.procList[functionIndex]; } return(true); } return(false); }
private bool DebugReturn(ProcedureNode procNode, int currentPC) { // // TODO: Aparajit, Jun - Determine an alternative to the waspopped flag // bool waspopped = false; bool isReplicating; int exeblock = Constants.kInvalidIndex; int ci; int fi; DebugFrame debugFrame = null; if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter) { waspopped = DebugReturnFromFunctionCall(currentPC, ref exeblock, out ci, out fi, out isReplicating, out debugFrame); if (!waspopped) { runtimeCore.DebugProps.RestoreCallrForNoBreak(runtimeCore, procNode, isReplicating); } } return waspopped; }
internal PropertyMirror(ProcedureNode procNode, bool isSetter = false) { this.procNode = procNode; string getterPrefix = ProtoCore.DSASM.Constants.kGetterPrefix; int prefixLength = getterPrefix.Length; PropertyName = procNode.Name.Substring(prefixLength); this.Name = PropertyName; this.isSetter = isSetter; }
private void RestoreGraphNodeExecutionStates(ProcedureNode procNode, List<bool> execStateRestore) { if (execStateRestore.Count > 0 ) { Validity.Assert(execStateRestore.Count == procNode.GraphNodeList.Count); for (int n = 0; n < execStateRestore.Count; ++n) { procNode.GraphNodeList[n].isDirty = execStateRestore[n]; } } }
private void EmitFunctionDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, GraphNode graphNode = null) { bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.CompilerDefinitions.Associative.CompilePass.kGlobalFuncBody == compilePass; bool parseMemberFunctionBody = ProtoCore.DSASM.Constants.kGlobalScope != globalClassIndex && ProtoCore.CompilerDefinitions.Associative.CompilePass.kClassMemFuncBody == compilePass; FunctionDefinitionNode funcDef = node as FunctionDefinitionNode; localFunctionDefNode = funcDef; if (funcDef.IsAssocOperator) { isAssocOperator = true; } else { isAssocOperator = false; } bool hasReturnStatement = false; ProtoCore.DSASM.CodeBlockType origCodeBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingGlobalFunctionSig() || IsParsingMemberFunctionSig()) { Validity.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.Name = funcDef.Name; localProcedure.PC = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.LocalCount = 0; // Defer till all locals are allocated var uid = core.TypeSystem.GetType(funcDef.ReturnType.Name); var rank = funcDef.ReturnType.rank; var returnType = core.TypeSystem.BuildTypeObject(uid, rank); if (returnType.UID == (int)PrimitiveType.kInvalidType) { string message = String.Format(ProtoCore.Properties.Resources.kReturnTypeUndefined, funcDef.ReturnType.Name, funcDef.Name); buildStatus.LogWarning(WarningID.kTypeUndefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode); returnType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, rank); } localProcedure.ReturnType = returnType; localProcedure.IsConstructor = false; localProcedure.IsStatic = funcDef.IsStatic; localProcedure.RuntimeIndex = codeBlock.codeBlockId; localProcedure.AccessModifier = funcDef.Access; localProcedure.IsExternal = funcDef.IsExternLib; localProcedure.IsAutoGenerated = funcDef.IsAutoGenerated; localProcedure.ClassID = globalClassIndex; localProcedure.IsAssocOperator = funcDef.IsAssocOperator; localProcedure.IsAutoGeneratedThisProc = funcDef.IsAutoGeneratedThisProc; localProcedure.MethodAttribute = funcDef.MethodAttributes; int peekFunctionindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { peekFunctionindex = codeBlock.procedureTable.Procedures.Count; } else { peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures.Count; } // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); string functionDescription = localProcedure.Name; if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { var argInfo = BuildArgumentInfoFromVarDeclNode(argNode); localProcedure.ArgumentInfos.Add(argInfo); var argType = BuildArgumentTypeFromVarDeclNode(argNode, graphNode); localProcedure.ArgumentTypes.Add(argType); argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(argInfo.Name, argType)); functionDescription += argNode.ArgumentType.ToString(); } localProcedure.HashID = functionDescription.GetHashCode(); localProcedure.IsVarArg = funcDef.Signature.IsVarArg; } if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { globalProcIndex = codeBlock.procedureTable.Append(localProcedure); } else { globalProcIndex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Append(localProcedure); } // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != globalProcIndex) { argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, globalProcIndex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("B2CB2093"); } }); } else { string message = String.Format(ProtoCore.Properties.Resources.kMethodAlreadyDefined, localProcedure.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode); funcDef.skipMe = true; } } else if (parseGlobalFunctionBody || parseMemberFunctionBody) { if (CoreUtils.IsDisposeMethod(node.Name)) { core.Options.EmitBreakpoints = false; } // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, graphNode); argList.Add(argType); } } // Get the exisitng procedure that was added on the previous pass if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { var procNode = codeBlock.procedureTable.GetFunctionBySignature(funcDef.Name, argList); globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID; localProcedure = codeBlock.procedureTable.Procedures[globalProcIndex]; } else { var procNode = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.GetFunctionBySignature(funcDef.Name, argList); globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID; localProcedure = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex]; } Validity.Assert(null != localProcedure); // code gen the attribute localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.PC = pc; // Copy the active function to the core so nested language blocks can refer to it core.ProcNode = localProcedure; ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { //Traverse default argument emitDebugInfo = false; foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.ArgumentInfos) { if (!argNode.IsDefault) { continue; } BinaryExpressionNode bNode = argNode.DefaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp = AstFactory.BuildIdentifier(core.GenerateTempVar()); var bNodeTemp = AstFactory.BuildAssignment(iNodeTemp, bNode.LeftNode); bNodeTemp.IsProcedureOwned = true; EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.IsAutoGenerated = true; BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier); } emitDebugInfo = true; EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature)); ProtoCore.Type itype = new ProtoCore.Type(); hasReturnStatement = EmitCodeBlock(funcDef.FunctionBody.Body, ref itype, subPass, true); // Build dependency within the function ProtoCore.AssociativeEngine.Utils.BuildGraphNodeDependencies( codeBlock.instrStream.dependencyGraph.GetGraphNodesAtScope(globalClassIndex, globalProcIndex)); EmitCompileLogFunctionEnd(); // All locals have been stack allocated, update the local count of this function localProcedure.LocalCount = core.BaseOffset; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { localProcedure.LocalCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values) { if (symnode.functionIndex == localProcedure.ID && symnode.isArgument) { symnode.index -= localProcedure.LocalCount; } } } else { core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[localProcedure.ID].LocalCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[globalClassIndex].Symbols.symbolList.Values) { if (symnode.functionIndex == localProcedure.ID && symnode.isArgument) { symnode.index -= localProcedure.LocalCount; } } } ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.PC; record.locals = localProcedure.LocalCount; record.classIndex = globalClassIndex; record.funcIndex = localProcedure.ID; fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else if (funcDef.BuiltInMethodId != ProtoCore.Lang.BuiltInMethods.MethodID.kInvalidMethodID) { fep = new ProtoCore.Lang.BuiltInFunctionEndPoint(funcDef.BuiltInMethodId); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.PC; jRecord.locals = localProcedure.LocalCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.ID; ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = funcDef.IsDNI; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.ArgumentTypes; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.ArgumentTypes.Count]; fep.BlockScope = codeBlock.codeBlockId; fep.ClassOwnerIndex = localProcedure.ClassID; fep.procedureNode = localProcedure; localProcedure.ArgumentTypes.CopyTo(fep.FormalParams, 0); // 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables int classIndexAtCallsite = globalClassIndex + 1; core.FunctionTable.InitGlobalFunctionEntry(classIndexAtCallsite); // Get the function group of the current class and see if the current function exists Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // If any functions in the base class have the same name, append them here int ci = classIndexAtCallsite - 1; if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { ProtoCore.DSASM.ClassNode cnode = core.ClassTable.ClassNodes[ci]; if (cnode.Bases.Count > 0) { Validity.Assert(1 == cnode.Bases.Count, "We don't support multiple inheritance yet"); ci = cnode.Bases[0]; Dictionary<string, FunctionGroup> tgroup = new Dictionary<string, FunctionGroup>(); int callsiteCI = ci + 1; bool bSucceed = core.FunctionTable.GlobalFuncTable.TryGetValue(callsiteCI, out tgroup); if (bSucceed) { if (tgroup.ContainsKey(funcDef.Name)) { // Get that base group - the group of function from the baseclass FunctionGroup basegroup = new FunctionGroup(); bSucceed = tgroup.TryGetValue(funcDef.Name, out basegroup); if (bSucceed) { // Copy all non-private feps from the basegroup into this the new group FunctionGroup newGroup = new FunctionGroup(); newGroup.CopyVisible(basegroup.FunctionEndPoints); // Append the new fep newGroup.FunctionEndPoints.Add(fep); // Copy the new group to this class table core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, newGroup); } } else { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } } else { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } cnode = core.ClassTable.ClassNodes[ci]; } else { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } } else { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } if (!hasReturnStatement && !funcDef.IsExternLib) { if (!core.Options.SuppressFunctionResolutionWarning) { string message = String.Format(ProtoCore.Properties.Resources.kFunctionNotReturnAtAllCodePaths, localProcedure.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode); } EmitReturnNull(); } if (CoreUtils.IsDisposeMethod(node.Name)) { core.Options.EmitBreakpoints = true; } } core.ProcNode = localProcedure = null; codeBlock.blockType = origCodeBlockType; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; localFunctionDefNode = null; core.BaseOffset = 0; argOffset = 0; isAssocOperator = false; }
private void PerformCoercionAndGC(ProcedureNode procNode, bool isBaseCall, StackValue? thisPtr, List<StackValue> Arguments, List<StackValue> DotCallDimensions) { // finalFep is forced to be null for base class constructor calls // and for such calls 'PerformReturnTypeCoerce' is not called if (!isBaseCall) { RX = ProtoCore.CallSite.PerformReturnTypeCoerce(procNode, core, RX); for (int i = 0; i < Arguments.Count; ++i) { GCUtils.GCRelease(Arguments[i], core); } if (thisPtr != null) { GCRelease((StackValue)thisPtr); } else { //if (debugFrame.IsDotArgCall || debugFrame.IsDotCall) { StackValue sv = RX; GCDotMethods(procNode.name, ref sv, DotCallDimensions, Arguments); RX = sv; } DecRefCounter(RX); isGlobScope = true; } } }
private void TraverseDotCallArguments(FunctionCallNode funcCall, FunctionDotCallNode dotCall, ProcedureNode procCallNode, List<ProtoCore.Type> arglist, string procName, int classIndex, string className, bool isStaticCall, bool isConstructor, GraphNode graphNode, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass, BinaryExpressionNode bnode) { // Update graph dependencies if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier && graphNode != null) { if (isStaticCall) { Validity.Assert(classIndex != Constants.kInvalidIndex); Validity.Assert(!string.IsNullOrEmpty(className)); SymbolNode classSymbol = new SymbolNode(); classSymbol.name = className; classSymbol.classScope = classIndex; PushSymbolAsDependent(classSymbol, graphNode); } } int funtionArgCount = 0; for (int n = 0; n < funcCall.FormalArguments.Count; ++n) { if (isStaticCall || isConstructor) { if (n != Constants.kDotArgIndexArrayArgs) { continue; } } AssociativeNode paramNode = funcCall.FormalArguments[n]; ProtoCore.Type paramType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0); emitReplicationGuide = false; // If it's a binary node then continue type check, otherwise // disable type check and just take the type of paramNode itself enforceTypeCheck = !(paramNode is BinaryExpressionNode); if (ProtoCore.DSASM.Constants.kDotArgIndexPtr == n) { // Traversing the first arg (the LHS pointer/Static instanct/Constructor // Replication guides only allowed on method, e.g., // // x = p<1>.f({1,2}<2>); // // But not on getter, e.g., // // c = a<1>.x<2>; if (!CoreUtils.IsGetterSetter(procName) && !isConstructor) { emitReplicationGuide = true; } DfsTraverse(paramNode, ref paramType, false, graphNode, subPass, bnode); } else if (ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs == n) { // Traversing the actual arguments passed into the function // (not the dot function) int defaultArgNumber = 0; // If its null this is the second call in a chained dot if (null != procCallNode) { defaultArgNumber = procCallNode.ArgumentInfos.Count - dotCall.FunctionCall.FormalArguments.Count; } // Enable graphnode dependencies if its a setter method bool allowDependentState = null != graphNode ? graphNode.allowDependents : false; if (CoreUtils.IsSetter(procName)) { // If the arguments are not temporaries ExprListNode exprList = paramNode as ExprListNode; Validity.Assert(1 == exprList.Exprs.Count); string varname = string.Empty; if (exprList.Exprs[0] is IdentifierNode) { varname = (exprList.Exprs[0] as IdentifierNode).Name; if (!CoreUtils.IsAutoGeneratedVar(varname)) { graphNode.allowDependents = true; } else if (CoreUtils.IsSSATemp(varname) && core.Options.GenerateSSA) { graphNode.allowDependents = true; } } else { graphNode.allowDependents = true; } } emitReplicationGuide = true; if (defaultArgNumber > 0) { ExprListNode exprList = paramNode as ExprListNode; if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { for (int i = 0; i < defaultArgNumber; i++) { exprList.Exprs.Add(new DefaultArgNode()); } } if (!isStaticCall && !isConstructor) { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); funtionArgCount = exprList.Exprs.Count; } else { foreach (AssociativeNode exprListNode in exprList.Exprs) { bool repGuideState = emitReplicationGuide; if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { emitReplicationGuide = false; } DfsTraverse(exprListNode, ref paramType, false, graphNode, subPass, bnode); emitReplicationGuide = repGuideState; arglist.Add(paramType); } } } else { ExprListNode exprList = paramNode as ExprListNode; // Comment Jun: This is a getter/setter or a an auto-generated thisarg function... // ...add the dynamic sv that will be resolved as a pointer at runtime if (!isStaticCall && !isConstructor) { // TODO Jun: pls get rid of subPass checking outside the core travesal if (ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone == subPass) { exprList.Exprs.Insert(0, new DynamicNode()); } } if (exprList.Exprs.Count > 0) { foreach (AssociativeNode exprListNode in exprList.Exprs) { bool repGuideState = emitReplicationGuide; if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { emitReplicationGuide = false; } DfsTraverse(exprListNode, ref paramType, false, graphNode, subPass, bnode); emitReplicationGuide = repGuideState; arglist.Add(paramType); } if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier && !isStaticCall && !isConstructor) { EmitInstrConsole(ProtoCore.DSASM.kw.alloca, exprList.Exprs.Count.ToString()); EmitPopArray(exprList.Exprs.Count); if (exprList.ArrayDimensions != null) { int dimensions = DfsEmitArrayIndexHeap(exprList.ArrayDimensions, graphNode); EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, dimensions.ToString() + "[dim]"); EmitPushArrayIndex(dimensions); } } } else { if (!isStaticCall && !isConstructor) { if (exprList != null) { bool emitReplicationGuideState = emitReplicationGuide; emitReplicationGuide = false; DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); emitReplicationGuide = emitReplicationGuideState; } else { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); } } } funtionArgCount = exprList.Exprs.Count; } emitReplicationGuide = false; // Restore the state only if it is a setter method if (ProtoCore.Utils.CoreUtils.IsSetter(procName)) { graphNode.allowDependents = allowDependentState; } } else if (ProtoCore.DSASM.Constants.kDotArgIndexArgCount == n) { IntNode argNumNode = new IntNode(funtionArgCount); DfsTraverse(argNumNode, ref paramType, false, graphNode, subPass); } else { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); } emitReplicationGuide = false; enforceTypeCheck = true; if (!isStaticCall || !isConstructor) { arglist.Add(paramType); } } }
private bool DebugReturn(ProcedureNode procNode, int currentPC) { // // TODO: Aparajit, Jun - Determine an alternative to the waspopped flag // bool waspopped = false; bool isReplicating = false; int exeblock = ProtoCore.DSASM.Constants.kInvalidIndex; int ci = ProtoCore.DSASM.Constants.kInvalidIndex; int fi = ProtoCore.DSASM.Constants.kInvalidIndex; DebugFrame debugFrame = null; if (core.Options.IDEDebugMode && core.ExecMode != InterpreterMode.kExpressionInterpreter) { waspopped = DebugReturnFromFunctionCall(currentPC, ref exeblock, out ci, out fi, out isReplicating, out debugFrame); if (!waspopped) { core.DebugProps.RestoreCallrForNoBreak(core, procNode, isReplicating); } } // TODO: This call is common to both Debug as well as Serial mode of execution. Currently this will work only in Debug mode - pratapa #if __DEBUG_REPLICATE if (isReplicating) { SerialReplication(procNode, ref exeblock, ci, fi, debugFrame); waspopped = true; } #endif return waspopped; }
public static ProcedureNode GetClassAndProcFromGlobalInstance(ProcedureNode procNode, Core core, out int classIndex, List<Type> argTypeList) { string className = ProtoCore.Utils.CoreUtils.GetClassDeclarationName(procNode, core); classIndex = core.ClassTable.IndexOf(className); int removelength = 0; if (ProtoCore.Utils.CoreUtils.IsGlobalInstanceGetterSetter(procNode.name)) { if (ProtoCore.Utils.CoreUtils.IsGlobalInstanceSetter(procNode.name)) { removelength = procNode.name.IndexOf(ProtoCore.DSASM.Constants.kSetterPrefix); } else { removelength = procNode.name.IndexOf(ProtoCore.DSASM.Constants.kGetterPrefix); } } else { removelength = procNode.name.IndexOf(ProtoCore.DSASM.Constants.kGlobalInstanceFunctionPrefix); removelength += ProtoCore.DSASM.Constants.kGlobalInstanceFunctionPrefix.Length; } string functionName = procNode.name.Remove(0, removelength); //ProtoCore.DSASM.ProcedureNode tmpProcNode = core.ClassTable.list[classIndex].GetFirstMemberFunction(functionName, procNode.argTypeList.Count - 1); int functionIndex = core.ClassTable.ClassNodes[classIndex].vtable.IndexOfExact(functionName, argTypeList, procNode.isAutoGeneratedThisProc); ProtoCore.DSASM.ProcedureNode tmpProcNode = core.ClassTable.ClassNodes[classIndex].vtable.procList[functionIndex]; return tmpProcNode; }
private void PerformCoercionAndGC(ProcedureNode procNode, bool isBaseCall, StackValue? thisPtr, List<StackValue> Arguments, List<StackValue> DotCallDimensions) { // finalFep is forced to be null for base class constructor calls // and for such calls 'PerformReturnTypeCoerce' is not called if (!isBaseCall) { RX = CallSite.PerformReturnTypeCoerce(procNode, runtimeCore, RX); if (thisPtr == null) { StackValue sv = RX; GCDotMethods(procNode.Name, ref sv, DotCallDimensions, Arguments); RX = sv; } } }