Skip to content

Commit

Permalink
Merge pull request #139 from kpreisser/changeExceptionType
Browse files Browse the repository at this point in the history
Pass through third-party exceptions, even if they don't derive from Exception.
  • Loading branch information
paulbartrum authored Jan 8, 2019
2 parents b32a840 + c09d794 commit e8ade10
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 16 deletions.
2 changes: 1 addition & 1 deletion Jurassic/Compiler/Emit/ReflectionHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ static ReflectionHelpers()
ScriptEngine_RegExp = GetInstanceMethod(typeof(ScriptEngine), "get_RegExp");
ScriptEngine_Array = GetInstanceMethod(typeof(ScriptEngine), "get_Array");
ScriptEngine_Object = GetInstanceMethod(typeof(ScriptEngine), "get_Object");
ScriptEngine_CanCatchException = GetInstanceMethod(typeof(ScriptEngine), "CanCatchException", typeof(Exception));
ScriptEngine_CanCatchException = GetInstanceMethod(typeof(ScriptEngine), "CanCatchException", typeof(object));
Global_Eval = GetStaticMethod(typeof(GlobalObject), "Eval", typeof(ScriptEngine), typeof(object), typeof(Scope), typeof(object), typeof(bool));

String_Constructor_Char_Int = GetConstructor(typeof(string), typeof(char), typeof(int));
Expand Down
29 changes: 19 additions & 10 deletions Jurassic/Compiler/Statements/TryCatchFinallyStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,30 +86,39 @@ public override void GenerateCode(ILGenerator generator, OptimizationInfo optimi
var previousInsideTryCatchOrFinally = optimizationInfo.InsideTryCatchOrFinally;
optimizationInfo.InsideTryCatchOrFinally = true;

// Finally requires two exception nested blocks.
// When we have a finally block, use a temporary variable that stores if the
// finally block should be skipped. This will be set to true when an exception was
// caught but ScriptEngine.CanCatchException() returns false.
// returns true.
ILLocalVariable skipFinallyBlock = null;
if (this.FinallyBlock != null)
{
// Finally requires two exception nested blocks.
generator.BeginExceptionBlock();

skipFinallyBlock = generator.CreateTemporaryVariable(typeof(bool));
generator.LoadBoolean(false);
generator.StoreVariable(skipFinallyBlock);
}

// Begin the exception block.
generator.BeginExceptionBlock();

// Generate code for the try block.
this.TryBlock.GenerateCode(generator, optimizationInfo);

// Generate code for the catch block.
ILLocalVariable skipFinallyBlock = null;

// Generate code for the catch block.

// Begin a catch block. The exception is on the top of the stack.
generator.BeginCatchBlock(typeof(Exception));
generator.BeginCatchBlock(typeof(object));

// Check the exception is catchable by calling CanCatchException(ex).
// We need to handle the case where JS code calls into .NET code which then throws
// a JavaScriptException from a different ScriptEngine.
// If CatchBlock is null, we need to rethrow the exception in every case.
var endOfIfLabel = generator.CreateLabel();
generator.Duplicate(); // ex
var exceptionTemporary = generator.CreateTemporaryVariable(typeof(Exception));
var exceptionTemporary = generator.CreateTemporaryVariable(typeof(object));
generator.StoreVariable(exceptionTemporary);
EmitHelpers.LoadScriptEngine(generator);
generator.LoadVariable(exceptionTemporary);
Expand All @@ -119,7 +128,6 @@ public override void GenerateCode(ILGenerator generator, OptimizationInfo optimi
if (this.FinallyBlock != null)
{
generator.LoadBoolean(true);
skipFinallyBlock = generator.DeclareVariable(typeof(bool), "skipFinallyBlock");
generator.StoreVariable(skipFinallyBlock);
}
if (this.CatchBlock == null)
Expand Down Expand Up @@ -154,11 +162,12 @@ public override void GenerateCode(ILGenerator generator, OptimizationInfo optimi
{
generator.BeginFinallyBlock();

// If an exception was thrown that wasn't handled by the catch block, then don't
// run the finally block either. This prevents user code from being run when a
// ThreadAbortException is thrown.
// If an exception was thrown that isn't determined as catchable by the ScriptEngine,
// then don't run the finally block either. This prevents user code from being run
// when a non-JavaScriptException is thrown (e.g. to cancel script execution).
var endOfFinallyBlock = generator.CreateLabel();
generator.LoadVariable(skipFinallyBlock);
generator.ReleaseTemporaryVariable(skipFinallyBlock);
generator.BranchIfTrue(endOfFinallyBlock);

var branches = new List<ILLabel>();
Expand Down
10 changes: 5 additions & 5 deletions Jurassic/Core/ScriptEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1326,16 +1326,16 @@ internal void PopStackFrame()
}

/// <summary>
/// Checks if the given <see cref="Exception"/> is catchable by JavaScript code with a
/// Checks if the given <paramref name="exception"/> is catchable by JavaScript code with a
/// <c>catch</c> clause.
/// Note: This property is public for technical reasons only and should not be used by user code.
/// Note: This method is public for technical reasons only and should not be used by user code.
/// </summary>
/// <param name="ex"> The exception to check. </param>
/// <param name="exception"> The exception to check. </param>
/// <returns><c>true</c> if the <see cref="Exception"/> is catchable, <c>false otherwise</c></returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool CanCatchException(Exception ex)
public bool CanCatchException(object exception)
{
var jsException = ex as JavaScriptException;
var jsException = exception as JavaScriptException;
if (jsException == null)
return false;
return jsException.Engine == this || jsException.Engine == null;
Expand Down

0 comments on commit e8ade10

Please sign in to comment.