private IEnumerable <JSStatement> CreateJsFinallyBlock(FinallyBlock finallyBlock, int p) { yield return(new JSFinallyBlock { Statements = CreateJsBlock(finallyBlock, p).Build().ToList() }); }
/// <summary> /// Appends the script to represent this object to the StringBuilder. /// </summary> /// <param name="builder">The StringBuilder to which the Javascript is appended.</param> /// <param name="options">The options to use when appending JavaScript</param> /// <param name="allowReservedWords"></param> internal protected override void AppendScript(StringBuilder builder, ScriptOptions options, bool allowReservedWords) { if (builder == null) { throw new ArgumentNullException("builder"); } if (_tryBlock == null) { throw new InvalidOperationException(); } builder.Append("try"); _tryBlock.AppendScript(builder, options, allowReservedWords); if (CatchBlock != null) { if (CatchVariable == null) { throw new InvalidOperationException(); } builder.Append("catch("); CatchVariable.AppendScript(builder, options, allowReservedWords); builder.Append(")"); CatchBlock.AppendScript(builder, options, allowReservedWords); } if (FinallyBlock != null) { builder.Append("finally"); FinallyBlock.AppendScript(builder, options, allowReservedWords); } }
public FinallyBlock Build() { var finallyBlock = new FinallyBlock(_block); finallyBlock.Body = new OrderedBlockBuilder(_reader, "finally", finallyBlock).Build(); return(finallyBlock); }
public override void Clone(JsNode node) { base.Clone(node); var node2 = (JsTryStatement)node; node2.TryBlock = TryBlock.Clone(); node2.CatchClause = CatchClause.Clone(); node2.FinallyBlock = FinallyBlock.Clone(); }
internal TryStmt ParseTryStmt() { Token t = RequireAndGet(TokenType.TRY); Require(TokenType.EOS); var s = ParseStatementBlock(); var cb = new List <CatchBlock>(); while (La() == TokenType.CATCH) { cb.Add(ParseCatchBlock()); } FinallyBlock fb = null; if (La() == TokenType.FINALLY) { var ft = ConsumeAndGet(); Require(TokenType.EOS); fb = new FinallyBlock(ft, ParseStatementBlock()); } Require(TokenType.END); Expect(TokenType.TRY); Require(TokenType.EOS); return(new TryStmt(t, s, cb.ToArray(), fb)); CatchBlock ParseCatchBlock() { Token ct = RequireAndGet(TokenType.CATCH); Expect(TokenType.TO); Token n = ParseVarIdName(); TypeExpr type = null; if (Expect(TokenType.AS)) { Require(type = ParseType(), ErrorCode.Expected, "type"); } Expr when = null; if (Expect(TokenType.WHEN)) { when = RequireExpression(); } Expect(TokenType.EOS); var cs = ParseStatementBlock(); return(new CatchBlock(ct, n, type, when, cs)); } }
protected internal override void VisitFinallyBlock(FinallyBlock node, object data) { StackTypes stack = data as StackTypes; if (stack.Count != 0) { throw new VerifierException(); } AddTask(node.Next, stack); }
void beginNumericUpDown_ValueChanged(object sender, EventArgs e) { if (!beginChanging) { using (FinallyBlock.Create(beginChanging = true, _ => beginChanging = false)) { this.BeginValue = sender == beginNumericUpDown ? (float)beginNumericUpDown.Value : beginTrackBar.Value / 100f; if (BeginValueChanged != null) { BeginValueChanged(this, EventArgs.Empty); } } } }
void endNumericUpDown_ValueChanged(object sender, EventArgs e) { if (!endChanging) { using (FinallyBlock.Create(endChanging = true, _ => endChanging = false)) { this.EndValue = sender == endNumericUpDown ? (float)endNumericUpDown.Value : endTrackBar.Value / 100f; if (EndValueChanged != null) { EndValueChanged(this, EventArgs.Empty); } } } }
public IDisposable SusupendNotification(bool notifyReset, bool checkRealChanges) { var cache = checkRealChanges ? this.ToArray() : null; return(FinallyBlock.Create(this.NotifyChanges = false, _ => { this.NotifyChanges = true; if (notifyReset && (!checkRealChanges || !this.SequenceEqual(cache))) { dispatcher.Invoke((Action <NotifyCollectionChangedEventArgs>)OnCollectionChanged, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } })); }
//----------------------------------------------------------------------------------------------------------------------------------------------------- public override void AcceptVisitor(StatementVisitor visitor) { visitor.VisitTryStatement(this); TryBlock.AcceptVisitor(visitor); foreach (var catchBlock in CatchBlocks) { catchBlock.AcceptVisitor(visitor); } if (FinallyBlock != null) { FinallyBlock.AcceptVisitor(visitor); } }
void UpdateUIValues() { if (activePanel.Enabled = this.Caption != null) { beginLabel.Text = this.Caption.StartFrame.ToString("0.00"); endLabel.Text = (this.Caption.StartFrame + this.Caption.DurationFrame).ToString("0.00"); timelineControl.CurrentAmount = (float)((this.CurrentFrame - this.Caption.StartFrame) / this.Caption.DurationFrame); } if (updates != null) { updates(); } updates = null; if (this.AnimationData != null) { timelineControl.Amounts = this.AnimationData.X.Frames.Select(_ => _.FrameAmount).ToArray(); } else { timelineControl.Amounts = null; } timelineControl.TryUpdate(); if (parametersPanel.Enabled = this.Caption != null && this.AnimationData != null && this.IsAnimationEnabled) { if (!changing) { using (FinallyBlock.Create(changing = true, _ => changing = false)) { GetValueSet(xEntry, this.AnimationData.X); GetValueSet(yEntry, this.AnimationData.Y); GetValueSet(alphaEntry, this.AnimationData.Alpha); GetValueSet(rotationEntry, this.AnimationData.Rotation); GetValueSet(fontSizeEntry, this.AnimationData.FontSize); GetValueSet(lineSpacingEntry, this.AnimationData.LineSpacing); GetValueSet(letterSpacingEntry, this.AnimationData.LetterSpacing); GetValueSet(shadowDistanceEntry, this.AnimationData.ShadowDistance); } } } }
public void SetNewValues() { if (!changing) { using (FinallyBlock.Create(changing = true, _ => changing = false)) if (this.Caption != null && this.AnimationData != null) { SetValueSet(xEntry, this.AnimationData.X); SetValueSet(yEntry, this.AnimationData.Y); SetValueSet(alphaEntry, this.AnimationData.Alpha); SetValueSet(rotationEntry, this.AnimationData.Rotation); SetValueSet(fontSizeEntry, this.AnimationData.FontSize); SetValueSet(lineSpacingEntry, this.AnimationData.LineSpacing); SetValueSet(letterSpacingEntry, this.AnimationData.LetterSpacing); SetValueSet(shadowDistanceEntry, this.AnimationData.ShadowDistance); } } }
protected override void VisitFinallyBlock(FinallyBlock node, object data) { throw new NodeNotSupportedException(node); }
protected internal virtual void VisitFinallyBlock(FinallyBlock node, object data) { throw new NodeNotSupportedException(node); }
protected static IDisposable AcquireUpgradableReaderLock(ReaderWriterLockSlim self) { return(FinallyBlock.Create(() => self.EnterUpgradeableReadLock(), () => self.ExitUpgradeableReadLock())); }
public static MethodBodyBlock Convert(MethodEx method) { if (!method.IsVerified) { throw new ConvertionException(); } MethodInfoExtention _method_ = new MethodInfoExtention(method.Method); MethodBodyBlock mainBlock = new MethodBodyBlock(_method_.GetReturnType().type); mainBlock.Options["StackTypes"] = new StackTypes(); Block currentBlock = mainBlock; Node[] heads = new Node[method.Count]; Node[] tails = new Node[method.Count]; Node head = null; Node tail = null; Node firstBlock = null; Node lastBlock = null; int iNum, iNumNext; Variable[] locals = new Variable[method.Locals.Count]; Variable[] args = new Variable[_method_.ArgCount]; VariablesList methodVarList = mainBlock.Variables; for (int i = 0; i < args.Length; i++) { args[i] = methodVarList.CreateVar(_method_.GetArgType(i).type, VariableKind.Parameter); args[i].Name = "Arg" + i; // methodVarList.Add(args[i]); } for (int i = 0; i < locals.Length; i++) { locals[i] = methodVarList.CreateVar(method.Locals[i], VariableKind.Local); locals[i].Name = "Loc" + i; // methodVarList.Add(locals[i]); } BlockType nextBlockType; int nextBlockStart = -1; int nextBlockEnd = 1 << 30; int nextBlockIndex; Type nextCatchBlockType; Hashtable tryBlocks = new Hashtable(); Hashtable filterBlocks = new Hashtable(); Stack blockEnds = new Stack(); blockEnds.Push(method.Count); FindNextBlockStart(method.EHClauses, out nextBlockType, ref nextBlockStart, ref nextBlockEnd, out nextCatchBlockType, out nextBlockIndex); //Nodes and blocks creation, blocks linkage for (iNum = 0; iNum < method.Count; iNum++) { while (iNum == (int)blockEnds.Peek()) { currentBlock = currentBlock.Parent; blockEnds.Pop(); } firstBlock = null; lastBlock = null; Node thisBlock = null; while (iNum == nextBlockStart) { Block currentBlockOld = currentBlock; switch (nextBlockType) { case BlockType.Try: currentBlock = new ProtectedBlock(); break; case BlockType.Catch: currentBlock = new CatchBlock(nextCatchBlockType); break; case BlockType.Finally: currentBlock = new FinallyBlock(false); break; case BlockType.Filter: currentBlock = new FilterBlock(); break; case BlockType.FilteredCatch: currentBlock = new UserFilteredBlock(); break; } currentBlock.setParent(currentBlockOld); blockEnds.Push(nextBlockEnd); if (thisBlock == null) { thisBlock = firstBlock = currentBlock; } else { thisBlock.Next = currentBlock; thisBlock = currentBlock; } switch (nextBlockType) { case BlockType.Try: tryBlocks.Add(new Segment(nextBlockStart, nextBlockEnd), thisBlock); break; case BlockType.Filter: filterBlocks.Add(new Segment(nextBlockStart, nextBlockEnd), thisBlock); break; case BlockType.Finally: case BlockType.Catch: { Segment tryBlockKey = FindProtectedBlock(method.EHClauses, nextBlockIndex); ProtectedBlock tryBlock = tryBlocks[tryBlockKey] as ProtectedBlock; tryBlock.AddHandler(thisBlock as EHBlock); } break; case BlockType.FilteredCatch: { Segment tryBlockKey = FindProtectedBlock(method.EHClauses, nextBlockIndex); ProtectedBlock tryBlock = tryBlocks[tryBlockKey] as ProtectedBlock; tryBlock.AddHandler(thisBlock as EHBlock); Segment filterKey = FindFilterBlock(method.EHClauses, nextBlockIndex); FilterBlock filterBlock = filterBlocks[filterKey] as FilterBlock; (thisBlock as UserFilteredBlock).Filter = filterBlock; } break; } FindNextBlockStart(method.EHClauses, out nextBlockType, ref nextBlockStart, ref nextBlockEnd, out nextCatchBlockType, out nextBlockIndex); } lastBlock = thisBlock; Instruction i = method[iNum]; switch (i.Code) { case InstructionCode.NEG: case InstructionCode.NOT: { head = tail = new UnaryOp(UnaryOpFromCode(i.Code)); /*!*/ head.setParent(currentBlock); } break; case InstructionCode.ADD: case InstructionCode.AND: case InstructionCode.CEQ: case InstructionCode.CGT: case InstructionCode.CLT: case InstructionCode.DIV: case InstructionCode.MUL: case InstructionCode.OR: case InstructionCode.REM: case InstructionCode.SHL: case InstructionCode.SHR: case InstructionCode.SUB: case InstructionCode.XOR: { head = tail = new BinaryOp(BinaryOpFromCode(i.Code), i.OverflowFlag, i.UnsignedFlag); /*!*/ head.setParent(currentBlock); } break; case InstructionCode.LDC: head = tail = new LoadConst(i.Param); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDARG: head = tail = new LoadVar(args[(int)(i.Param)]); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDLOC: head = tail = new LoadVar(locals[(int)(i.Param)]); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDARGA: head = tail = new LoadVarAddr(args[(int)(i.Param)]); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDLOCA: head = tail = new LoadVarAddr(locals[(int)(i.Param)]); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDIND: head = tail = new LoadIndirect(i.TypeBySuffixOrParam()); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDFLD: { FieldInfo field = i.Param as FieldInfo; if (field.IsStatic) { head = new RemoveStackTop(); /*!*/ head.setParent(currentBlock); //remove the object instance when accessing the static field with LDFLD tail = new LoadField(field); /*!*/ tail.setParent(currentBlock); head.Next = tail; } else { head = tail = new LoadField(field); /*!*/ head.setParent(currentBlock); } } break; case InstructionCode.LDFLDA: { FieldInfo field = i.Param as FieldInfo; if (field.IsStatic) { head = new RemoveStackTop(); /*!*/ head.setParent(currentBlock); tail = new LoadFieldAddr(field); /*!*/ tail.setParent(currentBlock); head.Next = tail; } else { head = tail = new LoadFieldAddr(field); /*!*/ head.setParent(currentBlock); } } break; case InstructionCode.LDSFLD: head = tail = new LoadField(i.Param as FieldInfo); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDSFLDA: head = tail = new LoadFieldAddr(i.Param as FieldInfo); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDELEM: head = tail = new LoadElement(i.TypeBySuffixOrParam()); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDELEMA: head = tail = new LoadElementAddr(i.TypeBySuffixOrParam()); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDOBJ: head = tail = new LoadIndirect(i.Param as Type); /*!*/ head.setParent(currentBlock); break; case InstructionCode.SIZEOF: head = tail = new LoadSizeOfValue(i.Param as Type); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDLEN: head = tail = new LoadLength(); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDTOKEN: if (i.Param is Type) { head = tail = new LoadConst((i.Param as Type).TypeHandle); } else if (i.Param is MethodBase) { head = tail = new LoadConst((i.Param as MethodBase).MethodHandle); } else if (i.Param is FieldInfo) { head = tail = new LoadConst((i.Param as FieldInfo).FieldHandle); } else { throw new ConvertionException(); } /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDNULL: head = tail = new LoadConst(null); /*!*/ head.setParent(currentBlock); break; case InstructionCode.LDSTR: head = tail = new LoadConst(i.Param); /*!*/ head.setParent(currentBlock); break; case InstructionCode.STARG: head = tail = new StoreVar(args[(int)(i.Param)]); /*!*/ head.setParent(currentBlock); break; case InstructionCode.STLOC: head = tail = new StoreVar(locals[(int)(i.Param)]); /*!*/ head.setParent(currentBlock); break; case InstructionCode.STIND: head = tail = new StoreIndirect(i.TypeBySuffixOrParam()); /*!*/ head.setParent(currentBlock); break; case InstructionCode.STFLD: { FieldInfo field = i.Param as FieldInfo; if (field.IsStatic) { head = new StoreField(field); /*!*/ head.setParent(currentBlock); tail = new RemoveStackTop(); /*!*/ tail.setParent(currentBlock); head.Next = tail; } else { head = tail = new StoreField(i.Param as FieldInfo); /*!*/ head.setParent(currentBlock); } } break; case InstructionCode.STSFLD: head = tail = new StoreField(i.Param as FieldInfo); /*!*/ head.setParent(currentBlock); break; case InstructionCode.STELEM: head = tail = new StoreElement(i.TypeBySuffixOrParam()); /*!*/ head.setParent(currentBlock); break; case InstructionCode.STOBJ: head = tail = new StoreIndirect(i.Param as Type); /*!*/ head.setParent(currentBlock); break; case InstructionCode.CPOBJ: head = new LoadIndirect(i.Param as Type); /*!*/ head.setParent(currentBlock); tail = new StoreIndirect(i.Param as Type); /*!*/ tail.setParent(currentBlock); head.Next = tail; break; case InstructionCode.DUP: head = tail = new DuplicateStackTop(); /*!*/ head.setParent(currentBlock); break; case InstructionCode.CALL: head = tail = new CallMethod(i.Param as MethodBase, false, i.HasTail); /*!*/ head.setParent(currentBlock); break; case InstructionCode.CALLVIRT: MethodInfo callee = i.Param as MethodInfo; head = tail = new CallMethod(callee, callee.IsVirtual, i.HasTail); /*!*/ head.setParent(currentBlock); break; case InstructionCode.NEWOBJ: { ConstructorInfo ctor = i.Param as ConstructorInfo; if (Verifier.IsDelegate(ctor.DeclaringType)) { if (Verifier.IsInstanceDispatch(method, iNum)) { heads[iNum - 1] = tails[iNum - 1] = null; head = tail = new CreateDelegate(ctor, method[iNum - 1].Param as MethodInfo, false); } else if (Verifier.IsVirtualDispatch(method, iNum)) { heads[iNum - 2] = tails[iNum - 2] = null; heads[iNum - 1] = tails[iNum - 1] = null; head = tail = new CreateDelegate(ctor, method[iNum - 1].Param as MethodInfo, true); } } else { head = tail = new NewObject(ctor); } /*!*/ head.setParent(currentBlock); } break; case InstructionCode.NEWARR: head = tail = new NewArray(i.Param as Type); /*!*/ head.setParent(currentBlock); break; case InstructionCode.INITOBJ: head = tail = new InitValue(i.Param as Type); /*!*/ head.setParent(currentBlock); break; case InstructionCode.ISINST: head = tail = new CastClass(i.Param as Type, false); /*!*/ head.setParent(currentBlock); break; case InstructionCode.CASTCLASS: head = tail = new CastClass(i.Param as Type, true); /*!*/ head.setParent(currentBlock); break; case InstructionCode.BOX: head = tail = new BoxValue(i.Param as Type); /*!*/ head.setParent(currentBlock); break; case InstructionCode.UNBOX: head = tail = new UnboxValue(i.Param as Type); /*!*/ head.setParent(currentBlock); break; case InstructionCode.CONV: head = tail = new ConvertValue(i.TypeBySuffixOrParam(), i.OverflowFlag, i.UnsignedFlag); /*!*/ head.setParent(currentBlock); break; case InstructionCode.POP: head = tail = new RemoveStackTop(); /*!*/ head.setParent(currentBlock); break; case InstructionCode.BEQ: head = new BinaryOp(BinaryOp.ArithOp.CEQ, false, false); /*!*/ head.setParent(currentBlock); tail = new Branch(); /*!*/ tail.setParent(currentBlock); head.Next = tail; break; case InstructionCode.BNE: head = new BinaryOp(BinaryOp.ArithOp.CEQ, false, false); /*!*/ head.setParent(currentBlock); tail = new Branch(); /*!*/ tail.setParent(currentBlock); head.Next = tail; break; case InstructionCode.BGE: if (TypeFixer.IsFloatOrCompatible(i.Stack.Top())) { head = new BinaryOp(BinaryOp.ArithOp.CLT, false, !i.UnsignedFlag); } else { head = new BinaryOp(BinaryOp.ArithOp.CLT, false, i.UnsignedFlag); } tail = new Branch(); /*!*/ head.setParent(currentBlock); /*!*/ tail.setParent(currentBlock); head.Next = tail; break; case InstructionCode.BGT: head = new BinaryOp(BinaryOp.ArithOp.CGT, false, i.UnsignedFlag); tail = new Branch(); /*!*/ head.setParent(currentBlock); /*!*/ tail.setParent(currentBlock); head.Next = tail; break; case InstructionCode.BLE: if (TypeFixer.IsFloatOrCompatible(i.Stack.Top())) { head = new BinaryOp(BinaryOp.ArithOp.CGT, false, !i.UnsignedFlag); } else { head = new BinaryOp(BinaryOp.ArithOp.CGT, false, i.UnsignedFlag); } tail = new Branch(); /*!*/ head.setParent(currentBlock); /*!*/ tail.setParent(currentBlock); head.Next = tail; break; case InstructionCode.BLT: head = new BinaryOp(BinaryOp.ArithOp.CLT, false, i.UnsignedFlag); tail = new Branch(); /*!*/ head.setParent(currentBlock); /*!*/ tail.setParent(currentBlock); head.Next = tail; break; case InstructionCode.BRTRUE: head = tail = new Branch(); /*!*/ head.setParent(currentBlock); break; case InstructionCode.BRFALSE: head = tail = new Branch(); /*!*/ head.setParent(currentBlock); break; case InstructionCode.SWITCH: head = tail = new Switch((i.Param as int[]).Length); /*!*/ head.setParent(currentBlock); break; case InstructionCode.BR: case InstructionCode.NOP: case InstructionCode.BREAK: case InstructionCode.LDFTN: // Expecting further delegate construction... case InstructionCode.LDVIRTFTN: // head = tail = new DummyNode(); /*!*/ head.setParent(currentBlock); break; case InstructionCode.THROW: head = tail = new ThrowException(); /*!*/ head.setParent(currentBlock); break; case InstructionCode.RET: case InstructionCode.ENDFINALLY: case InstructionCode.ENDFILTER: case InstructionCode.LEAVE: head = tail = new Leave(); /*!*/ head.setParent(currentBlock); break; default: throw new ConvertionException(); } if (head != null) { head.Options["StackTypes"] = i.Stack.Clone() as StackTypes; } if (head != tail) //=> head :: BinaryOp, tail :: Branch //|| head :: LoadIndirect, tail :: StoreIndirect { if (head is BinaryOp && tail is Branch) { StackTypes stack = i.Stack.Clone() as StackTypes; stack.Pop(); stack.Pop(); stack.Push(typeof(int)); tail.Options["StackTypes"] = stack; } else if (head is LoadIndirect && tail is StoreIndirect) { StackTypes stack = i.Stack.Clone() as StackTypes; TypeEx type = stack.Pop(); //type == S& stack.Push(type.type.GetElementType()); tail.Options["StackTypes"] = stack; } } if (firstBlock != null) { lastBlock.Next = head; for (Node n = firstBlock; n != head; n = n.Next) { n.Options["StackTypes"] = i.Stack.Clone() as StackTypes; } head = firstBlock; if (tail == null) { tail = lastBlock; //This may occure what the NOP instruction starts some block } } heads[iNum] = head; tails[iNum] = tail; } //for mainBlock.Next = heads[0]; //Control flow linkage for (iNum = 0; iNum < method.Count; iNum++) { if (heads[iNum] == null) { throw new ConvertionException(); //impossible :) } Instruction i = method[iNum]; switch (i.Code) { case InstructionCode.BR: case InstructionCode.LEAVE: tails[iNum].Next = heads[(int)i.Param]; break; case InstructionCode.RET: case InstructionCode.ENDFINALLY: case InstructionCode.ENDFILTER: case InstructionCode.THROW: case InstructionCode.RETHROW: break; case InstructionCode.BRFALSE: //false case InstructionCode.BGE: //false case InstructionCode.BLE: //false case InstructionCode.BNE: //false tails[iNum].Next = heads[(int)i.Param]; (tails[iNum] as Branch).Alt = heads[iNum + 1]; break; case InstructionCode.BRTRUE: //true case InstructionCode.BEQ: //true case InstructionCode.BGT: //true case InstructionCode.BLT: //true tails[iNum].Next = heads[iNum + 1]; (tails[iNum] as Branch).Alt = heads[(int)i.Param]; break; case InstructionCode.SWITCH: tails[iNum].Next = heads[iNum + 1]; Switch node = tails[iNum] as Switch; int[] alt = i.Param as int[]; for (int j = 0; j < node.Count; j++) { node[j] = heads[alt[j]]; } break; default: tails[iNum].Next = heads[iNum + 1]; break; } } //Removing DummyNodes for (iNum = 0; iNum < method.Count; iNum++) { if (heads[iNum] is DummyNode) { Node dummy = heads[iNum]; Node[] prev = new Node[dummy.PrevArray.Count]; for (int j = 0; j < prev.Length; j++) { prev[j] = dummy.PrevArray[j]; } for (int j = 0; j < prev.Length; j++) { prev[j].NextArray[prev[j].NextArray.IndexOf(dummy)] = dummy.Next; } dummy.RemoveFromGraph(); } } return(mainBlock); }
protected override void VisitFinallyBlock(FinallyBlock node, object data) { result = false; }
/// <summary> /// Begins a finally block on the given exception block. /// /// Only one finally block can be defined per exception block, and the block cannot appear within a catch block. /// /// The given exception block must still be open. /// </summary> public Emit BeginFinallyBlock(ExceptionBlock forTry, out FinallyBlock forFinally) { InnerEmit.BeginFinallyBlock(forTry, out forFinally); return(this); }
/// <summary cref="M:Sigil.Emit.NonGeneric.Emit`1.BeginFinallyBlock(Sigil.ExceptionBlock)" /> public EmitShorthand BeginFinallyBlock(ExceptionBlock forTry, out FinallyBlock forFinally) { forFinally = BeginFinallyBlock(forTry); return(this); }
/// <summary cref="M:Sigil.Emit.NonGeneric.Emit`1.EndFinallyBlock(Sigil.FinallyBlock)" /> public EmitShorthand EndFinallyBlock(FinallyBlock forFinally) { InnerEmit.EndFinallyBlock(forFinally); return(this); }
public override string ToCode(ToCodeFormat format) { StringBuilder sb = new StringBuilder(); // passing a "T" format means nested try's don't actually nest -- they // just add the catch clauses to the end if (format != ToCodeFormat.NestedTry) { sb.Append("try"); if (TryBlock == null) { // empty body sb.Append("{}"); } else { sb.Append(TryBlock.ToCode(ToCodeFormat.NestedTry)); } } else { sb.Append(TryBlock.ToCode(ToCodeFormat.NestedTry)); } // handle the catch clause (if any) // catch should always have braces around it string catchString = ( CatchBlock == null ? string.Empty : CatchBlock.Count == 0 ? "{}" : CatchBlock.ToCode(ToCodeFormat.AlwaysBraces) ); if (catchString.Length > 0) { Parser.Settings.NewLine(sb); sb.Append("catch("); if (m_catchVariable != null) { sb.Append(m_catchVariable.ToString()); } else if (m_catchVarName != null) { sb.Append(m_catchVarName); } sb.Append(')'); sb.Append(catchString); } // handle the finally, if any // finally should always have braces around it string finallyString = ( FinallyBlock == null ? string.Empty : FinallyBlock.ToCode(ToCodeFormat.AlwaysBraces) ); if (finallyString.Length > 0) { Parser.Settings.NewLine(sb); sb.Append("finally"); sb.Append(finallyString); } return(sb.ToString()); }
/// <summary> /// Process an unplugged method. /// </summary> /// <param name="aMethod">The method to process.</param> /// <param name="staticConstructorDependencyRoot">Null if method scanning is not a static constructor. Otherwise, the root node that represents the static constructor being scanned.</param> /// <returns>A new ILChunk with ILOpInfos and common attribites loaded. Null if any errors occur.</returns> /// <exception cref="System.Exception"> /// Thrown when an unrecognised operand type is read. Can occur if MSBuild has been /// updated/extended from when the kernel compiler was last updated. /// </exception> public ILChunk ProcessUnpluggedMethod(MethodBase aMethod, StaticConstructorDependency staticConstructorDependencyRoot = null) { ILChunk result = new ILChunk() { Plugged = false, Method = aMethod }; //Pre-process common method attributes so we get information such as //whether to apply GC or not etc. ProcessCommonMethodAttributes(aMethod, result); //Get the method body which can then be used to get locals info and //IL bytes that are the IL code. MethodBody theMethodBody = aMethod.GetMethodBody(); //Method body for something like [DelegateType].Invoke() // is null if (theMethodBody == null) { //Just return empty method return result; } //For each local variable in this method foreach (LocalVariableInfo aLocal in theMethodBody.LocalVariables) { //Add it to our list of locals with some common information pre-worked out LocalVariable localItem = new LocalVariable() { sizeOnStackInBytes = Utils.GetNumBytesForType(aLocal.LocalType), isFloat = Utils.IsFloat(aLocal.LocalType), TheType = aLocal.LocalType, isGCManaged = Utils.IsGCManaged(aLocal.LocalType) }; result.LocalVariables.Add(localItem); } //Used later to store location and length of the cleanup try-finally block int CleanUpBlock_TryOffset = 0; int CleanUpBlock_TryLength = 0; int CleanUpBlock_FinallyOffset = 0; int CleanUpBlock_FinallyLength = 0; //The "cleanup" block is the finally handler created by the IL reader that //calls GC.DecrementRefCount of locals and arguments as-required so that //memory managed by the GC through objects gets freed correctly. //The try-section of the cleanup block surrounds all of the main code of the method //excluding the final "ret" instruction. In this way, even if an exception occurs, //locals and args still get "cleaned up". //The IL bytes are the IL code. byte[] ILBytes = theMethodBody.GetILAsByteArray(); //Note: IL offsets are usually calculated as the number of bytes offset from the // start of the method. //Note: IL line numbers are IL offsets. //The current position in the IL bytes. //This will change throughout the loop below so it always points past //all the bytes processed so far. int ILBytesPos = 0; //The previous position in the IL bytes. //This will only change in the loop below after a new IL op is created. In this way, //it actually points to the IL bytes position just before the new op is created. //That is to say, it points to the IL bytes pos of the start of the new op. int PrevILBytesPos = 0; //The previous IL op info that was created. //This is the latest one that was created as opposed the the one before that. //I.e. this is the last ILOpInfo added to the final list of IL op infos. ILOpInfo prevInfo = null; //Loop through all the IL bytes for this method... while (ILBytesPos < ILBytes.Length) { //The current System.Reflection.Emit.OpCode being processed OpCode currOpCode; //The unique number that identifies the op code. //This number is also deliberately equivalent to Kernel.Compiler.ILOps.IlOp.OpCodes! ushort currOpCodeID = 0; //MSIL is saved such that OpIds that only require 1 byte, only use 1 byte! //ILBytes encoded as big-endian(?) so high bytes of the op code value (ID) come first //So if high byte is set to 0xFE then we need to load the next byte as low byte if (ILBytes[ILBytesPos] == 0xFE) { currOpCodeID = (ushort)(0xFE00 + (short)ILBytes[ILBytesPos + 1]); ILBytesPos += 2; } else { currOpCodeID = (ushort)ILBytes[ILBytesPos]; ILBytesPos++; } //Load the op code from our pre-constructed list of all op codes currOpCode = AllOpCodes[currOpCodeID]; int operandSize = 0; //Operand type tells us the operand size //We must: // a) Skip over the operand bytes so that we read the next IL op correctly // b) Store the operand bytes in the ILOpInfo for later use switch(currOpCode.OperandType) { case OperandType.InlineBrTarget: operandSize = 4; break; case OperandType.InlineField: operandSize = 4; break; case OperandType.InlineI: operandSize = 4; break; case OperandType.InlineI8: operandSize = 8; break; case OperandType.InlineMethod: operandSize = 4; break; case OperandType.InlineNone: //No operands = no op size break; case OperandType.InlineR: operandSize = 8; break; case OperandType.InlineSig: operandSize = 4; break; case OperandType.InlineString: operandSize = 4; break; case OperandType.InlineSwitch: { int count = Utils.ReadInt32(ILBytes, ILBytesPos); ILBytesPos += 4; operandSize = count * 4; } break; case OperandType.InlineTok: operandSize = 4; break; case OperandType.InlineType: operandSize = 4; break; case OperandType.InlineVar: operandSize = 2; break; case OperandType.ShortInlineBrTarget: operandSize = 1; break; case OperandType.ShortInlineI: operandSize = 1; break; case OperandType.ShortInlineR: operandSize = 4; break; case OperandType.ShortInlineVar: operandSize = 1; break; default: throw new Exception("Unrecognised operand type!"); } //Update the previous op with next position now that we // know what that is... if (prevInfo != null) { prevInfo.NextPosition = PrevILBytesPos; } //The IL reader pre-loads any methods that should be called by, for example, a call op //This was added so that the MethodToCall could be set by the IL reader to inject call ops // - It was going to be a lot harder to try and get the "metadata token bytes" for the // method to call than to simply "pre-load" the method to call. MethodBase methodToCall = null; //Value bytes generally contain a constant value to be loaded or the bytes of a metadata token. //Metadata tokens can be used to retrieve information such as string literals or method infos //from the calling assembly. byte[] valueBytes = new byte[operandSize]; //Don't bother copying 0 bytes... if (operandSize > 0) { //Copy the bytes... Array.Copy(ILBytes, ILBytesPos, valueBytes, 0, operandSize); //If the op is one where the valueBytes are a metadata token pointing to a method: if ((ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Call || (ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Calli || (ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Callvirt || (ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Ldftn || (ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Newobj) { //Pre-load the method for reasons described above. //The metadata token that identifies the method to call in the DLL //It is used to retrieve more information about the method from the DLL int MethodMetadataToken = Utils.ReadInt32(valueBytes, 0); //The method to call retrieved using the metasdata token methodToCall = aMethod.Module.ResolveMethod(MethodMetadataToken); } } //If the op being processed is a Return op and this method has GC applied: if ((ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Ret && result.ApplyGC) { //We must insert the cleanup block code. //Insert try-finally block around the entire method but just before Ret //The finally block can then do clean-up of local variables and args //1. Insert IL ops for doing locals / args cleanup //2. Add the try/finally block (or just finally block if try block already exists) //We must also consider the fact that just before a "ret" op, the return value is loaded. //Since this cleanup block will wrap that load op, we must add code to store the return value //at the end of the try block and then re-load the return value after the finally block (but //before the ret op.) //Get a list of all the params to the current method List<Type> allParams = result.Method.GetParameters() .Select(x => x.ParameterType) .ToList(); //If it isn't a static method: if (!result.Method.IsStatic) { //The first param is the current instance reference. allParams.Insert(0, result.Method.DeclaringType); } //Only insert the cleanup block if there are some params or locals to clean up. //This is the first of two checks of this condition. if (result.LocalVariables.Count > 0 || allParams.Count > 0) { //As per above we need to check for return value LocalVariable returnValVariable = null; //Return type of constructor is void, so only check proper methods if(result.Method is MethodInfo) { Type returnType = ((MethodInfo)result.Method).ReturnType; //Void return type = no return value if(returnType != typeof(void)) { //Add a new local variable for storing the return value returnValVariable = new LocalVariable() { isFloat = Utils.IsFloat(returnType), sizeOnStackInBytes = Utils.GetNumBytesForType(returnType), TheType = returnType, isGCManaged = Utils.IsGCManaged(returnType) }; result.LocalVariables.Add(returnValVariable); //This will become the penultimate IL op of the try-block //It will immediately follow the op just before ret which // will have loaded the return value or, at the very least, // the top-most item on the stack is the return value //This op stores that return value in our new local variable // for reload after the finally block has completed. result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Stloc, Position = PrevILBytesPos++, NextPosition = PrevILBytesPos, ValueBytes = BitConverter.GetBytes(result.LocalVariables.IndexOf(returnValVariable)) }); } } //This becomes the last op of the try-block (and is required to be // the last op of a try block) result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Leave_S, Position = PrevILBytesPos++, NextPosition = PrevILBytesPos, ValueBytes = new byte[4] }); //Try block length is now the length in IL bytes from start // (i.e. offset) to start of the current IL op. See above for // why we use PrevIlBytesPos. CleanUpBlock_TryLength = PrevILBytesPos - CleanUpBlock_TryOffset; //Finally offset is offset to first op of finally block i.e. // current IL op position. CleanUpBlock_FinallyOffset = PrevILBytesPos; //Finally length is currently 0 - gets increased later. CleanUpBlock_FinallyLength = 0; //Add cleanup code for each local for (int i = 0; i < result.LocalVariables.Count; i++) { //Clean-up local variables //If the local variable is GC handled: //1. Load the the local //2. Call GC Dec Ref count LocalVariable aVar = result.LocalVariables[i]; //Only add cleanup code if the local is actually GC managed. if (Utils.IsGCManaged(aVar.TheType)) { if (prevInfo != null) { prevInfo.NextPosition = PrevILBytesPos; } //Load the local result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Ldloc, Position = PrevILBytesPos++, NextPosition = -1, ValueBytes = BitConverter.GetBytes(i) }); prevInfo.NextPosition = PrevILBytesPos; //Decrement the ref count of the local result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Call, Position = PrevILBytesPos++, NextPosition = -1, SetToGCDecRefCountMethod = true }); CleanUpBlock_FinallyLength += 2; } } //Add cleanup code for each arg //Dec ref count of all args passed to the method for (int i = 0; i < allParams.Count; i++) { Type aVarType = allParams[i]; //Only add cleanup code if the arg is actually GC managed. if (Utils.IsGCManaged(aVarType)) { if (prevInfo != null) { prevInfo.NextPosition = PrevILBytesPos; } result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Ldarg, Position = PrevILBytesPos++, NextPosition = -1, ValueBytes = BitConverter.GetBytes(i) }); prevInfo.NextPosition = PrevILBytesPos; result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Call, Position = PrevILBytesPos++, NextPosition = -1, SetToGCDecRefCountMethod = true }); CleanUpBlock_FinallyLength += 2; } } //Locals and args not necessarily of GC managed type // so we could potentially have cleaned up nothing //This is the second of the two checks to make sure we // only add cleanup code if there is something to cleanup if (CleanUpBlock_FinallyLength > 0) { //If there is cleanup code, add the end of the finally block and // reload the return value if necessary. prevInfo.NextPosition = PrevILBytesPos; result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Endfinally, Position = PrevILBytesPos++, NextPosition = -1 }); CleanUpBlock_FinallyLength += 1; if (returnValVariable != null) { result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Ldloc, Position = PrevILBytesPos++, NextPosition = PrevILBytesPos, ValueBytes = BitConverter.GetBytes(result.LocalVariables.IndexOf(returnValVariable)) }); } } else { //If there was nothing to cleanup, we need to remove // the ops and locals etc. that got added earlier. result.ILOpInfos.RemoveAt(result.ILOpInfos.Count - 1); PrevILBytesPos--; if(returnValVariable != null) { result.LocalVariables.Remove(returnValVariable); result.ILOpInfos.RemoveAt(result.ILOpInfos.Count - 1); PrevILBytesPos--; } } } } if (staticConstructorDependencyRoot != null) { //Create our static constructor dependency tree //Each of these ops could try to access a static method or field switch((ILOps.ILOp.OpCodes)currOpCode.Value) { case ILOps.ILOp.OpCodes.Call: //Check if the method to call is static and not a constructor itself //If so, we must add the declaring type's static constructors to the tree { int metadataToken = Utils.ReadInt32(valueBytes, 0); MethodBase methodBaseInf = aMethod.Module.ResolveMethod(metadataToken); if(!(methodBaseInf.IsConstructor || methodBaseInf is ConstructorInfo)) { MethodInfo methodInf = (MethodInfo)methodBaseInf; ConstructorInfo[] staticConstructors = methodInf.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.Public) .Concat(methodInf.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)) .ToArray(); if (staticConstructors.Length > 0) { ConstructorInfo TheConstructor = staticConstructors[0]; if (staticConstructorDependencyRoot[TheConstructor] == null) { staticConstructorDependencyRoot.Children.Add(new StaticConstructorDependency() { TheConstructor = TheConstructor }); } } } } break; case ILOps.ILOp.OpCodes.Ldsfld: case ILOps.ILOp.OpCodes.Ldsflda: case ILOps.ILOp.OpCodes.Stsfld: { int metadataToken = Utils.ReadInt32(valueBytes, 0); FieldInfo fieldInf = aMethod.Module.ResolveField(metadataToken); ConstructorInfo[] staticConstructors = fieldInf.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.Public) .Concat(fieldInf.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)) .ToArray(); if(staticConstructors.Length > 0) { ConstructorInfo TheConstructor = staticConstructors[0]; if (staticConstructorDependencyRoot[TheConstructor] == null) { staticConstructorDependencyRoot.Children.Add(new StaticConstructorDependency() { TheConstructor = TheConstructor }); } } } break; } } //Add the IL op result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = currOpCode, Position = PrevILBytesPos, // Next position set to -1 indicates no next op NextPosition = -1, ValueBytes = valueBytes, MethodToCall = methodToCall }); ILBytesPos += operandSize; PrevILBytesPos = ILBytesPos; } prevInfo.NextPosition = PrevILBytesPos; //Add the exception handlers (excluding Cleanup try-finally block - see below) foreach (ExceptionHandlingClause aClause in theMethodBody.ExceptionHandlingClauses) { ExceptionHandledBlock exBlock = result.GetExactExceptionHandledBlock(aClause.TryOffset); if (exBlock == null) { exBlock = new ExceptionHandledBlock(); exBlock.Offset = aClause.TryOffset; exBlock.Length = aClause.TryLength; result.ExceptionHandledBlocks.Add(exBlock); } switch (aClause.Flags) { case ExceptionHandlingClauseOptions.Fault: case ExceptionHandlingClauseOptions.Clause: { CatchBlock catchBlock = new CatchBlock() { Offset = aClause.HandlerOffset, Length = aClause.HandlerLength, //Though not used, we may as well set it anyway FilterType = aClause.CatchType }; exBlock.CatchBlocks.Add(catchBlock); } break; case ExceptionHandlingClauseOptions.Finally: { FinallyBlock finallyBlock = new FinallyBlock() { Offset = aClause.HandlerOffset, Length = aClause.HandlerLength }; exBlock.FinallyBlocks.Add(finallyBlock); } break; default: OutputError(new NotSupportedException("Exception handling clause not supported! Type: " + aClause.Flags.ToString())); break; } } //Add the cleanup try-finally block //Only add the block if try-section has non-zero length and // if the finally block has more than just the endfinally op if (CleanUpBlock_TryLength != 0 && CleanUpBlock_FinallyLength > 1) { ExceptionHandledBlock cleanUpTryBlock = new ExceptionHandledBlock() { Offset = CleanUpBlock_TryOffset, Length = CleanUpBlock_TryLength }; FinallyBlock cleanupFinallyBlock = new FinallyBlock() { Offset = CleanUpBlock_FinallyOffset, Length = CleanUpBlock_FinallyLength, }; cleanUpTryBlock.FinallyBlocks.Add(cleanupFinallyBlock); result.ExceptionHandledBlocks.Add(cleanUpTryBlock); } return result; }