protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { //Jumps need special treatment for label resolution if (Instruction.Arguments == -1) { switch (Instruction.OpCode) { case OpCode.jump: target.EmitJump(Position, Instruction.Id); break; case OpCode.jump_t: target.EmitJumpIfTrue(Position, Instruction.Id); break; case OpCode.jump_f: target.EmitJumpIfFalse(Position, Instruction.Id); break; case OpCode.leave: target.EmitLeave(Position, Instruction.Id); break; default: goto emitNormally; } } else goto emitNormally; return; emitNormally: target.Emit(Position, Instruction); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if(stackSemantics == StackSemantics.Value) throw new NotSupportedException("Try-catch-finally blocks cannot be used with value stack semantics (They don't produce values)"); var prefix = "try\\" + Guid.NewGuid().ToString("N") + "\\"; var beginTryLabel = prefix + "beginTry"; var beginFinallyLabel = prefix + "beginFinally"; var beginCatchLabel = prefix + "beginCatch"; var endTry = prefix + "endTry"; if (TryBlock.IsEmpty) if (FinallyBlock.IsEmpty) return; else { //The finally block is not protected // A trycatchfinally with just a finally block is equivalent to the contents of the finally block // " try {} finally { $code } " => " $code " FinallyBlock.EmitEffectCode(target); return; } //Emit try block target.EmitLabel(Position, beginTryLabel); target.Emit(Position,OpCode.@try); TryBlock.EmitEffectCode(target); //Emit finally block target.EmitLabel(FinallyBlock.Position, beginFinallyLabel); var beforeEmit = target.Code.Count; FinallyBlock.EmitEffectCode(target); if (FinallyBlock.Count > 0 && target.Code.Count == beforeEmit) target.Emit(FinallyBlock.Position, OpCode.nop); target.EmitLeave(FinallyBlock.Position, endTry); //Emit catch block target.EmitLabel(CatchBlock.Position, beginCatchLabel); var usesException = ExceptionVar != null; var justRethrow = CatchBlock.IsEmpty && !usesException; if (usesException) { //Assign exception ExceptionVar = _GetOptimizedNode(target, ExceptionVar) as AstGetSet ?? ExceptionVar; ExceptionVar.Arguments.Add(new AstGetException(File, Line, Column)); ExceptionVar.Call = PCall.Set; ExceptionVar.EmitEffectCode(target); } if (!justRethrow) { //Exception handled CatchBlock.EmitEffectCode(target); } else { //Exception not handled => rethrow. // * Rethrow is implemented in the runtime * //AstThrow th = new AstThrow(File, Line, Column); //th.Expression = new AstGetException(File, Line, Column); //th.EmitCode(target); } target.EmitLabel(Position, endTry); target.Emit(Position,OpCode.nop); var block = new TryCatchFinallyBlock( _getAddress(target, beginTryLabel), _getAddress(target, endTry)) { BeginFinally = (!FinallyBlock.IsEmpty ? _getAddress(target, beginFinallyLabel) : -1), BeginCatch = (!justRethrow ? _getAddress(target, beginCatchLabel) : -1), UsesException = usesException }; //Register try-catch-finally block target.Function.Meta.AddTo(TryCatchFinallyBlock.MetaKey, block); target.Function.InvalidateTryCatchFinallyBlocks(); }