public CaseLabel(Expression constant, AstNode children, TokenPosition position) : base(position) { this.constant = constant; this.children = children; this.block = null; }
public FunctionGenerator() { this.currentFunction = null; this.currentBreak = null; this.currentContinue = null; this.currentExceptionContext = null; this.builder = new BlockBuilder(); }
public void AddSuccessor(BasicBlock successor) { if(successors == null) successors = new List<BasicBlock> (); successors.Add(successor); successor.AddPredecesor(this); }
public ExceptionContext(ExceptionContext parentContext) { // Store parent-child relation. this.parentContext = parentContext; this.parentFunction = parentContext.parentFunction; parentContext.children.Add(this); module = parentFunction.GetModule(); // Initialize more variables. this.children = new List<ExceptionContext> (); this.blocks = new List<BasicBlock> (); this.handlers = new List<Handler> (); this.cleanup = null; }
public void AddCatch(Structure exception, BasicBlock block) { foreach(Handler h in handlers) { if(h.exception == exception) throw new ModuleException("Exception is already handled."); } // Store. Handler ha = new Handler(); ha.exception = exception; ha.handler = block; handlers.Add(ha); }
public ExceptionContext(Function parentFunction) { // Store parent-child relation. this.parentContext = null; this.parentFunction = parentFunction; module = parentFunction.GetModule(); if(parentFunction.exceptionContext != null) throw new ModuleException("A function only can have one (toplevel) exception context."); parentFunction.exceptionContext = this; // Initialize more variables. this.children = new List<ExceptionContext> (); this.blocks = new List<BasicBlock> (); this.handlers = new List<Handler> (); this.cleanup = null; }
protected Function(ChelaModule module) : base(module) { this.name = string.Empty; this.flags = MemberFlags.Default; this.parentScope = null; this.basicBlocks = new List<BasicBlock> (); this.lexicalScopes = new List<LexicalScope>(); this.locals = new List<LocalVariable> (); this.position = null; this.exceptionContext = null; this.returnBlock = null; this.returningVar = null; this.returnValueVar = null; this.genericPrototype = GenericPrototype.Empty; this.arguments = null; }
public override AstNode Visit(SwitchStatement node) { // Begin the node. builder.BeginNode(node); // Process the switch expression. Expression switchExpr = node.GetConstant(); switchExpr.Accept(this); // Perform coercion. IChelaType switchType = switchExpr.GetNodeType(); IChelaType coercionType = node.GetCoercionType(); if(switchType != coercionType) Cast(node, switchExpr.GetNodeValue(), switchType, coercionType); // Create the merge block. BasicBlock merge = CreateBasicBlock(); merge.SetName("smerge"); // Store the old break. BasicBlock oldBreak = currentBreak; currentBreak = merge; // Initialize the default block to the merge. BasicBlock defaultBlock = merge; // Get the cases dictionary. IDictionary<ConstantValue, CaseLabel> caseDictionary = node.CaseDictionary; // Create the jump table. int tableSize = caseDictionary.Count + 1; int[] constants = new int[tableSize]; BasicBlock[] blocks = new BasicBlock[tableSize]; // The first element is always the default block. int i = 0; constants[i] = -1; blocks[i] = defaultBlock; ++i; // Add the other elements. BasicBlock caseBlock = null; CaseLabel label = (CaseLabel)node.GetCases(); while(label != null) { // Create the label block. if(caseBlock == null) { caseBlock = CreateBasicBlock(); caseBlock.SetName("caseBlock"); } // Set the label block. label.SetBlock(caseBlock); // Store the default block. if(label.GetConstant() == null) { defaultBlock = caseBlock; blocks[0] = caseBlock; } else { // Append it to the jump table. Expression caseExpr = label.GetConstant(); ConstantValue caseConstant = (ConstantValue)caseExpr.GetNodeValue(); constants[i] = caseConstant.GetIntValue(); blocks[i] = caseBlock; ++i; } // Create a new block if the last case wasn't empty. if(label.GetChildren() != null) caseBlock = null; // Process the next label. label = (CaseLabel)label.GetNext(); } // Perform the switch. BasicBlock switchBlock = builder.GetBlock(); builder.CreateSwitch(constants, blocks); // Generate the cases blocks. VisitList(node.GetCases()); // Continue with the normal flow. currentBreak = oldBreak; // Remove the merge block if its unreachable. if(merge.GetPredsCount() == 0) { builder.SetBlock(switchBlock); merge.Destroy(); if(node.GetNext() != null) Warning(node.GetNext(), "detected unreachable code."); node.SetNext(null); } else { builder.SetBlock(merge); } return builder.EndNode(); }
private Method CreateTrivialConstructor(Structure building, Structure buildingInstance) { // Create the constructor function type. FunctionType type = FunctionType.Create(ChelaType.GetVoidType(), new IChelaType[]{ReferenceType.Create(buildingInstance)}, false); // Create the constructor. Method ctor = new Method(".ctor", MemberFlags.Public | MemberFlags.Constructor, building); ctor.SetFunctionType(type); building.AddFunction(".ctor", ctor); // Create the constructor block. BasicBlock top = new BasicBlock(ctor); top.SetName("top"); top.Append(new Instruction(OpCode.RetVoid, null)); return ctor; }
private void PrepareReturning(AstNode where, Function function, LexicalScope scope) { // Get the definition node and check for generator. FunctionDefinition defNode = function.DefinitionNode; bool isGenerator = false; if(defNode != null) isGenerator = defNode.IsGenerator; // Use standard return. if(function.GetExceptionContext() == null && !isGenerator) return; // Create the return block. BasicBlock returnBlock = new BasicBlock(function); returnBlock.SetName("retBlock"); function.ReturnBlock = returnBlock; // Create the return value local. FunctionType functionType = function.GetFunctionType(); IChelaType retType = functionType.GetReturnType(); if(retType != ChelaType.GetVoidType() && !isGenerator) function.ReturnValueVar = new LocalVariable(GenSym() + "_retval", scope, retType); // Create the is returning flag. function.ReturningVar = new LocalVariable(GenSym() + "_isret", scope, ChelaType.GetBoolType(), isGenerator); function.ReturningVar.Type = LocalType.Return; // Create the field for generators. if(isGenerator) { FieldVariable returningField = new FieldVariable("returning", MemberFlags.Private, ChelaType.GetBoolType(), defNode.GeneratorClass); defNode.GeneratorClass.AddField(returningField); function.ReturningVar.ActualVariable = returningField; } // Initializer the returning flag to false. builder.CreateLoadBool(false); PerformAssignment(where, function.ReturningVar); }
private void CreateGenerator_Reset(FunctionDefinition node) { // Get the generator class. Class genClass = node.GeneratorClass; // Create the function type. FunctionType functionType = FunctionType.Create(ChelaType.GetVoidType(), new IChelaType[]{ReferenceType.Create(node.GeneratorClassInstance)}, false); // Create the method. Method method = new Method("Reset", MemberFlags.Public, genClass); method.SetFunctionType(functionType); genClass.AddFunction("Reset", method); // Create the top block. BasicBlock top = new BasicBlock(method); builder.SetBlock(top); // Throw an exception. Class excpt = (Class)ExtractClass(node, currentModule.GetLangMember("InvalidOperationException")); builder.CreateLoadString("IEnumerator.Reset cannot be called in generators."); builder.CreateNewObject(excpt, GetExceptionCtor(node, excpt), 1); builder.CreateThrow(); }
private void CreateStaticConstructor(AstNode node, Namespace space) { // Check for a previous definition. if(space.GetStaticConstructor() != null || space.GetGlobalInitializations() == null) return; // Get the static initialization fields. List<FieldDeclaration> staticInitedField = new List<FieldDeclaration> (); bool isUnsafe = false; foreach(FieldDeclaration decl in space.GetGlobalInitializations()) { Variable variable = decl.GetVariable(); if(variable.IsStatic()) { staticInitedField.Add(decl); if(variable.IsUnsafe()) isUnsafe = true; } } // If there aren't field to initialize, don't create the static constructor. if(staticInitedField.Count == 0) return; // Create the static constructor function type. FunctionType ctorType = FunctionType.Create(ChelaType.GetVoidType()); // Create the constructor method. MemberFlags flags = MemberFlags.StaticConstructor; if(isUnsafe) flags |= MemberFlags.Unsafe; Function constructor = new Function("<sctor>", flags, space); constructor.SetFunctionType(ctorType); // Store it. space.AddMember(constructor); // Create the constructor scope. LexicalScope ctorScope = CreateLexicalScope(node, constructor); PushScope(ctorScope); // Create the top basic block. BasicBlock topBlock = new BasicBlock(constructor); builder.SetBlock(topBlock); // Initialize the static fields. GenerateStaticFieldInitializations(null, staticInitedField); // Restore the scope. PopScope(); // Return void. builder.CreateRetVoid(); }
public void SetBlock(BasicBlock block) { this.block = block; }
public void SetCleanup(BasicBlock block) { this.cleanup = block; }
private void AddPredecesor(BasicBlock pred) { if(preds == null) preds = new List<BasicBlock> (); preds.Add(pred); }
public void SetBlock(BasicBlock block) { // Set the block. this.currentBlock = block; }
private void CreateDefaultConstructor(StructDefinition node) { // Get the structure, and the default constructor. Structure building = node.GetStructure(); Method constructor = node.GetDefaultConstructor(); // Ignore structures without a default constructor. if(constructor == null) return; // Crete the self scope. LexicalScope selfScope = CreateLexicalScope(node, constructor); new ArgumentVariable(0, "this", selfScope, ReferenceType.Create(building)); PushScope(selfScope); // Create the top basic block. BasicBlock topBlock = new BasicBlock(constructor); builder.SetBlock(topBlock); // Add implicit construction expressions. CreateImplicitBaseConstructor(node, constructor); // Initialize some field. GenerateFieldInitializations(node, building); // Restore the scope. PopScope(); // Return void. builder.CreateRetVoid(); }
internal int AddBlock(BasicBlock block) { int ret = this.basicBlocks.Count; this.basicBlocks.Add(block); return ret; }
private BasicBlock CreateBasicBlock() { BasicBlock ret = new BasicBlock(currentFunction); ret.IsUnsafe = IsUnsafe; if(currentExceptionContext != null) currentExceptionContext.AddBlock(ret); return ret; }
public void RemoveBlock(BasicBlock block) { // Remove it from my blocks. for(int i = 0; i < blocks.Count; ++i) { if(blocks[i] == block) { blocks.RemoveAt(i); break; } } // Remove it from my handlers. for(int i = 0; i < handlers.Count; ++i) { Handler h = (Handler)handlers[i]; if(h.handler == block) { handlers.RemoveAt(i); break; } } // Remove it from my cleanup. if(cleanup == block) cleanup = null; // Remove it from my children. foreach(ExceptionContext child in children) child.RemoveBlock(block); }
public override AstNode Visit(ForStatement node) { // Begin the node. builder.BeginNode(node); // Get the for elements. AstNode decl = node.GetDecls(); AstNode cond = node.GetCondition(); AstNode incr = node.GetIncr(); // Write the declaration. if(decl != null) decl.Accept(this); // Create the basics blocks. BasicBlock forStart = CreateBasicBlock(); BasicBlock forEnd = CreateBasicBlock(); BasicBlock forBreak = CreateBasicBlock(); BasicBlock forCond = forStart; // Set the blocks names. forStart.SetName("for_start"); forEnd.SetName("for_end"); forBreak.SetName("for_break"); // Store and update the break and continue points. BasicBlock oldBreak = currentBreak; BasicBlock oldContinue = currentContinue; currentBreak = forBreak; currentContinue = forEnd; // Write the condition. if(cond != null) { // Create the condition block. forCond = CreateBasicBlock(); forCond.SetName("for_cond"); // Jump into the condition. builder.CreateJmp(forCond); builder.SetBlock(forCond); // Write the condition. cond.Accept(this); // Cast the condition. IChelaType condType = cond.GetNodeType(); if(condType != ChelaType.GetBoolType()) Cast(node, cond.GetNodeValue(), condType, ChelaType.GetBoolType()); // Perform the conditional branch. builder.CreateBr(forStart, forBreak); } else { // Jump into the beginning of the loop. builder.CreateJmp(forStart); } // Write the loop content. builder.SetBlock(forStart); VisitList(node.GetChildren()); // Branch into the loop end. if(!builder.IsLastTerminator()) builder.CreateJmp(forEnd); // Write the for end. builder.SetBlock(forEnd); // Write the increment. if(incr != null) incr.Accept(this); // Branch into the condition. if(!builder.IsLastTerminator()) builder.CreateJmp(forCond); // Continue with the rest of the program. builder.SetBlock(forBreak); // Restore the break and continue point. currentBreak = oldBreak; currentContinue = oldContinue; return builder.EndNode(); }
public override AstNode Visit(DoWhileStatement node) { // Begin the node. builder.BeginNode(node); // Get the condition and the job. Expression cond = node.GetCondition(); AstNode job = node.GetJob(); // Create the basic blocks. BasicBlock condBlock = CreateBasicBlock(); BasicBlock contentBlock = CreateBasicBlock(); BasicBlock endBlock = CreateBasicBlock(); // Set the blocks names. condBlock.SetName("cond"); contentBlock.SetName("content"); endBlock.SetName("end"); // Store the old break and continue. BasicBlock oldBreak = currentBreak; BasicBlock oldContinue = currentContinue; // Set the new break and continue. currentBreak = endBlock; currentContinue = condBlock; // Branch into the content. builder.CreateJmp(contentBlock); // Write the content. builder.SetBlock(contentBlock); job.Accept(this); // Branch into the condition. if(!builder.IsLastTerminator()) builder.CreateJmp(condBlock); // Write the condition. builder.SetBlock(condBlock); cond.Accept(this); // Cast the condition. IChelaType condType = cond.GetNodeType(); if(condType != ChelaType.GetBoolType()) Cast(node, cond.GetNodeValue(), condType, ChelaType.GetBoolType()); // Close the loop. builder.CreateBr(contentBlock, endBlock); // Continue with the normal flow. builder.SetBlock(endBlock); // Restore the break and continue blocks. currentBreak = oldBreak; currentContinue = oldContinue; return builder.EndNode(); }
private void CreateGenerator_GetEnumerator(FunctionDefinition node, Structure enumeratorType, bool generic) { // Get the generator class. Class genClass = node.GeneratorClass; // Use the GetEnumerator name for the most specific version. string name = "GetEnumerator"; Function contract = null; if(!generic && node.IsGenericIterator) { name = GenSym(); contract = FindFirstConstract(currentModule.GetEnumerableIface(), "GetEnumerator"); } // Create the function type. FunctionType functionType = FunctionType.Create(ReferenceType.Create(enumeratorType), new IChelaType[]{ReferenceType.Create(node.GeneratorClassInstance)}, false); // Create the method. Method method = new Method(name, MemberFlags.Public, genClass); method.SetFunctionType(functionType); genClass.AddFunction(name, method); // Set the explicit contract. if(contract != null) method.SetExplicitContract(contract); // Create the method block. BasicBlock block = new BasicBlock(method); block.SetName("top"); // Return this. builder.SetBlock(block); builder.CreateLoadArg(0); builder.CreateRet(); }
public void CreateBr(BasicBlock trueDest, BasicBlock falseDest) { AppendInst2(OpCode.Br, trueDest, falseDest); currentBlock.AddSuccessor(trueDest); currentBlock.AddSuccessor(falseDest); }
private Function CreateGenerator_MoveNext(FunctionDefinition node) { // Get the generator class. Class genClass = node.GeneratorClass; // Create the function type. FunctionType functionType = FunctionType.Create(ChelaType.GetBoolType(), new IChelaType[]{ReferenceType.Create(node.GeneratorClassInstance)}, false); // Create the method. Method method = new Method("MoveNext", MemberFlags.Public, genClass); method.SetFunctionType(functionType); method.DefinitionNode = node; genClass.AddFunction("MoveNext", method); // Swap the exception contexts. method.SwapExceptionContexts(currentFunction); // Store the old function. Function oldFunction = currentFunction; currentFunction = method; // Create the jump table block. BasicBlock jmpBlock = CreateBasicBlock(); jmpBlock.SetName("jmp"); // Generate the main code. BasicBlock topBlock = CreateBasicBlock(); topBlock.SetName("top"); builder.SetBlock(topBlock); // Prepare returning. LexicalScope topScope = (LexicalScope) node.GetScope(); PrepareReturning(node, currentFunction, topScope); // Create the function body. VisitList(node.GetChildren()); // Finish returning. FinishReturn(node, currentFunction); // Create the state jump table. builder.SetBlock(jmpBlock); // Load the current state. builder.CreateLoadArg(0); builder.CreateLoadField(node.GeneratorState); // Build the jump table. int numstates = node.Yields.Count*2+3; int[] stateConstants = new int[numstates]; BasicBlock[] stateEntries = new BasicBlock[numstates]; // The default case is return. stateConstants[0] = -1; stateEntries[0] = currentFunction.ReturnBlock; // The first state is the top block. stateConstants[1] = 0; stateEntries[1] = topBlock; // The second state is the return block. stateConstants[2] = 1; stateEntries[2] = currentFunction.ReturnBlock; // The next states are the yield merges followed by yield disposes. for(int i = 0; i < node.Yields.Count; ++i) { ReturnStatement yieldStmnt = node.Yields[i]; // Emit the merge state. int stateId = i*2+2; int entryIndex = stateId+1; stateConstants[entryIndex] = stateId; stateEntries[entryIndex] = yieldStmnt.MergeBlock; // Emit the dispose state. stateConstants[entryIndex+1] = stateId+1; stateEntries[entryIndex+1] = yieldStmnt.DisposeBlock; } builder.CreateSwitch(stateConstants, stateEntries); // Restore the old function. currentFunction = oldFunction; return method; }
private void CreateDefaultStaticConstructor(StructDefinition node) { // Get the structure. Structure building = node.GetStructure(); // Check for an user defined constructor. if(building.GetStaticConstructor() != null) return; // Get the static initialization fields. List<FieldDeclaration> staticInitedField = new List<FieldDeclaration> (); bool isUnsafe = false; foreach(FieldDeclaration decl in building.GetFieldInitializations()) { Variable variable = decl.GetVariable(); if(variable.IsStatic()) { staticInitedField.Add(decl); if(variable.IsUnsafe()) isUnsafe = true; } } // If there aren't field to initialize, don't create the static constructor. if(staticInitedField.Count == 0) return; // Begin the node. builder.BeginNode(node); // Create the static constructor function type. FunctionType ctorType = FunctionType.Create(ChelaType.GetVoidType()); // Create the constructor method. MemberFlags flags = MemberFlags.StaticConstructor; if(isUnsafe) flags |= MemberFlags.Unsafe; Method constructor = new Method("<sctor>", flags, building); constructor.SetFunctionType(ctorType); // Store it. building.AddFunction("<sctor>", constructor); // Create the constructor scope. LexicalScope ctorScope = CreateLexicalScope(node, constructor); PushScope(ctorScope); // Create the top basic block. BasicBlock topBlock = new BasicBlock(constructor); builder.SetBlock(topBlock); // Initialize the static fields. GenerateStaticFieldInitializations(node, staticInitedField); // Restore the scope. PopScope(); // Return void. builder.CreateRetVoid(); // End the node. builder.EndNode(); }
public void AddBlock(BasicBlock block) { blocks.Add(block); }
internal void RemoveBasicBlock(BasicBlock block) { // Displace the upper blocks. int numblocks = basicBlocks.Count; for(int i = block.blockIndex; i < numblocks-1; ++i) { BasicBlock next = (BasicBlock)basicBlocks[i+1]; next.blockIndex = i; basicBlocks[i] = next; } // Remove the last block. basicBlocks.RemoveAt(numblocks-1); // Remove the block from the exception contexts if(exceptionContext != null) exceptionContext.RemoveBlock(block); }
private void CreateGenerator_Current(FunctionDefinition node, bool generic) { // Get the generator class. Class genClass = node.GeneratorClass; // Use the get_Current name for the most specific version. string name = "get_Current"; Function contract = null; if(!generic && node.IsGenericIterator) { name = GenSym(); contract = FindFirstConstract(currentModule.GetEnumeratorIface(), "get_Current"); } // Select the current type. IChelaType currentType = node.YieldType; if(!generic) currentType = ReferenceType.Create(currentModule.GetObjectClass()); // Create the function type. FunctionType functionType = FunctionType.Create(currentType, new IChelaType[]{ReferenceType.Create(node.GeneratorClassInstance)}, false); // Create the method. Method method = new Method(name, MemberFlags.Public, genClass); method.SetFunctionType(functionType); genClass.AddFunction(name, method); // Set the explicit contract. if(contract != null) method.SetExplicitContract(contract); // Create the method block. BasicBlock block = new BasicBlock(method); block.SetName("top"); // Create the return and error blocks. BasicBlock retBlock = new BasicBlock(method); retBlock.SetName("ret"); BasicBlock errorBlock = new BasicBlock(method); errorBlock.SetName("error"); // Make sure reset was called before the first Current. builder.SetBlock(block); builder.CreateLoadArg(0); builder.CreateLoadField(node.GeneratorState); builder.CreateLoadInt32(0); builder.CreateCmpEQ(); builder.CreateBr(errorBlock, retBlock); // Raise an error if reset wasn't called. builder.SetBlock(errorBlock); Class excpt = (Class)ExtractClass(node, currentModule.GetLangMember("InvalidOperationException")); builder.CreateLoadString("IEnumerator.MoveNext must be called before than IEnumerator.Current."); builder.CreateNewObject(excpt, GetExceptionCtor(node, excpt), 1); builder.CreateThrow(); // Load the yielded value. builder.SetBlock(retBlock); builder.CreateLoadArg(0); builder.CreateLoadField(node.YieldedValue); // Cast the yielded value. Cast(node, null, node.YieldType, currentType); // Return. builder.CreateRet(); }
private void CreateGenerator_Dispose(FunctionDefinition node, Function moveNext) { // Get the generator class. Class genClass = node.GeneratorClass; // Create the function type. FunctionType functionType = FunctionType.Create(ChelaType.GetVoidType(), new IChelaType[]{ReferenceType.Create(node.GeneratorClassInstance)}, false); // Create the method. Method method = new Method("Dispose", MemberFlags.Public, genClass); method.SetFunctionType(functionType); genClass.AddFunction("Dispose", method); // Create the top block. BasicBlock top = new BasicBlock(method); builder.SetBlock(top); // Create the return and dispose blocks. BasicBlock justReturn = new BasicBlock(method); BasicBlock disposeAndReturn = new BasicBlock(method); // Load the current state. builder.CreateLoadArg(0); builder.CreateDup1(); builder.CreateDup1(); builder.CreateLoadField(node.GeneratorState); builder.CreateDup1(); builder.CreateLoadInt32(1); builder.CreateCmpEQ(); builder.CreateBr(justReturn, disposeAndReturn); // Dispose and return implementation. builder.SetBlock(disposeAndReturn); // Increase the state. builder.CreateLoadInt32(1); builder.CreateAdd(); builder.CreateStoreField(node.GeneratorState); // Call move next. builder.CreateCall(moveNext, 1); builder.CreateRetVoid(); // Just return implementation. builder.SetBlock(justReturn); builder.CreateRetVoid(); }
private void EmitBasicBlockDebugInfo(ModuleWriter writer, BasicBlock block) { // Compute instructions subblocks. List <SubBlock> subBlocks = new List <SubBlock> (); TokenPosition position = NullPosition; int start = 0; int index = 0; foreach (Instruction inst in block.GetInstructions()) { // Get the instruction position. TokenPosition instPos = inst.GetPosition(); if (instPos == null) { instPos = NullPosition; } if (instPos != position) { // Create a sub block for the previous set. if (index != 0) { SubBlock subBlock = new SubBlock(); subBlock.Position = position; subBlock.Start = (ushort)start; subBlock.End = (ushort)(index - 1); // Store the sub block. subBlocks.Add(subBlock); } // Store the start of the next subblock. start = index; position = instPos; } // Increase the index. ++index; } // Create the last sub block. SubBlock lastSubBlock = new SubBlock(); lastSubBlock.Position = position; lastSubBlock.Start = (ushort)(start); lastSubBlock.End = (ushort)(index - 1); // Store the sub block. subBlocks.Add(lastSubBlock); // Emit all of the sub blocks. ushort numSubs = (ushort)subBlocks.Count; writer.Write(numSubs); foreach (SubBlock subBlock in subBlocks) { writer.Write(subBlock.Start); writer.Write(subBlock.End); EmitPosition(writer, subBlock.Position); } }