diff --git a/deps/chakrashim/core/lib/Backend/BailOut.cpp b/deps/chakrashim/core/lib/Backend/BailOut.cpp
index 50c28e157a1..35ee85856f4 100644
--- a/deps/chakrashim/core/lib/Backend/BailOut.cpp
+++ b/deps/chakrashim/core/lib/Backend/BailOut.cpp
@@ -1217,6 +1217,12 @@ BailOutRecord::BailOutInlinedCommon(Js::JavascriptCallStackLayout * layout, Bail
BailOutReturnValue bailOutReturnValue;
Js::ScriptFunction * innerMostInlinee = nullptr;
BailOutInlinedHelper(layout, currentBailOutRecord, bailOutOffset, returnAddress, bailOutKind, registerSaves, &bailOutReturnValue, &innerMostInlinee, false, branchValue);
+
+ bool * hasBailOutBit = layout->functionObject->GetScriptContext()->GetThreadContext()->GetHasBailedOutBitPtr();
+ if (hasBailOutBit != nullptr && bailOutRecord->ehBailoutData)
+ {
+ *hasBailOutBit = true;
+ }
Js::Var result = BailOutCommonNoCodeGen(layout, currentBailOutRecord, currentBailOutRecord->bailOutOffset, returnAddress, bailOutKind, branchValue,
registerSaves, &bailOutReturnValue);
ScheduleFunctionCodeGen(Js::ScriptFunction::FromVar(layout->functionObject), innerMostInlinee, currentBailOutRecord, bailOutKind, bailOutOffset, savedImplicitCallFlags, returnAddress);
@@ -1255,6 +1261,11 @@ BailOutRecord::BailOutFromLoopBodyInlinedCommon(Js::JavascriptCallStackLayout *
BailOutReturnValue bailOutReturnValue;
Js::ScriptFunction * innerMostInlinee = nullptr;
BailOutInlinedHelper(layout, currentBailOutRecord, bailOutOffset, returnAddress, bailOutKind, registerSaves, &bailOutReturnValue, &innerMostInlinee, true, branchValue);
+ bool * hasBailOutBit = layout->functionObject->GetScriptContext()->GetThreadContext()->GetHasBailedOutBitPtr();
+ if (hasBailOutBit != nullptr && bailOutRecord->ehBailoutData)
+ {
+ *hasBailOutBit = true;
+ }
uint32 result = BailOutFromLoopBodyHelper(layout, currentBailOutRecord, currentBailOutRecord->bailOutOffset,
bailOutKind, nullptr, registerSaves, &bailOutReturnValue);
ScheduleLoopBodyCodeGen(Js::ScriptFunction::FromVar(layout->functionObject), innerMostInlinee, currentBailOutRecord, bailOutKind);
diff --git a/deps/chakrashim/core/lib/Runtime/Base/ThreadContext.cpp b/deps/chakrashim/core/lib/Runtime/Base/ThreadContext.cpp
index 9cec9aa0b35..40413025d4a 100644
--- a/deps/chakrashim/core/lib/Runtime/Base/ThreadContext.cpp
+++ b/deps/chakrashim/core/lib/Runtime/Base/ThreadContext.cpp
@@ -93,6 +93,7 @@ ThreadContext::ThreadContext(AllocationPolicyManager * allocationPolicyManager,
stackProber(nullptr),
isThreadBound(false),
hasThrownPendingException(false),
+ hasBailedOutBitPtr(nullptr),
pendingFinallyException(nullptr),
noScriptScope(false),
heapEnum(nullptr),
diff --git a/deps/chakrashim/core/lib/Runtime/Base/ThreadContext.h b/deps/chakrashim/core/lib/Runtime/Base/ThreadContext.h
index 668b141efa8..79ead8092d5 100644
--- a/deps/chakrashim/core/lib/Runtime/Base/ThreadContext.h
+++ b/deps/chakrashim/core/lib/Runtime/Base/ThreadContext.h
@@ -638,6 +638,7 @@ class ThreadContext sealed :
StackProber * stackProber;
bool isThreadBound;
bool hasThrownPendingException;
+ bool * hasBailedOutBitPtr;
bool callDispose;
#if ENABLE_JS_REENTRANCY_CHECK
bool noJsReentrancy;
@@ -1531,6 +1532,16 @@ class ThreadContext sealed :
this->hasThrownPendingException = true;
}
+ bool * GetHasBailedOutBitPtr()
+ {
+ return this->hasBailedOutBitPtr;
+ }
+
+ void SetHasBailedOutBitPtr(bool *setValue)
+ {
+ this->hasBailedOutBitPtr = setValue;
+ }
+
void SetRecordedException(Js::JavascriptExceptionObject* exceptionObject, bool propagateToDebugger = false)
{
this->recyclableData->exceptionObject = exceptionObject;
diff --git a/deps/chakrashim/core/lib/Runtime/Language/JavascriptExceptionOperators.cpp b/deps/chakrashim/core/lib/Runtime/Language/JavascriptExceptionOperators.cpp
index a850feea9c1..452bd169686 100644
--- a/deps/chakrashim/core/lib/Runtime/Language/JavascriptExceptionOperators.cpp
+++ b/deps/chakrashim/core/lib/Runtime/Language/JavascriptExceptionOperators.cpp
@@ -94,10 +94,11 @@ namespace Js
void *continuation = nullptr;
JavascriptExceptionObject *exception = nullptr;
void *tryCatchFrameAddr = nullptr;
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr((bool*)((char*)frame + hasBailedOutOffset));
+
PROBE_STACK(scriptContext, Constants::MinStackDefault + spillSize + argsSize);
{
Js::JavascriptExceptionOperators::TryCatchFrameAddrStack tryCatchFrameAddrStack(scriptContext, frame);
-
try
{
Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
@@ -129,18 +130,22 @@ namespace Js
exception = exception->CloneIfStaticExceptionObject(scriptContext);
bool hasBailedOut = *(bool*)((char*)frame + hasBailedOutOffset); // stack offsets are negative
+ // If an inlinee bailed out due to some reason, the execution of the current function enclosing the try catch will also continue in the interpreter
+ // During execution in the interpreter, if we throw outside the region enclosed in try/catch, this catch ends up catching that exception because its present on the call stack
if (hasBailedOut)
{
// If we have bailed out, this exception is coming from the interpreter. It should not have been caught;
// it so happens that this catch was on the stack and caught the exception.
// Re-throw!
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
JavascriptExceptionOperators::DoThrow(exception, scriptContext);
- }
+ }
+
Var exceptionObject = exception->GetThrownObject(scriptContext);
AssertMsg(exceptionObject, "Caught object is null.");
continuation = amd64_CallWithFakeFrame(catchAddr, frame, spillSize, argsSize, exceptionObject);
}
-
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
return continuation;
}
@@ -154,6 +159,7 @@ namespace Js
{
void *tryContinuation = nullptr;
JavascriptExceptionObject *exception = nullptr;
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr((bool*)((char*)frame + hasBailedOutOffset));
PROBE_STACK(scriptContext, Constants::MinStackDefault + spillSize + argsSize);
@@ -189,6 +195,7 @@ namespace Js
// If we have bailed out, this exception is coming from the interpreter. It should not have been caught;
// it so happens that this catch was on the stack and caught the exception.
// Re-throw!
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
JavascriptExceptionOperators::DoThrow(exception, scriptContext);
}
@@ -197,6 +204,7 @@ namespace Js
return continuation;
}
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
return tryContinuation;
}
@@ -250,6 +258,7 @@ namespace Js
void *continuation = nullptr;
JavascriptExceptionObject *exception = nullptr;
void * tryCatchFrameAddr = nullptr;
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr((bool*)((char*)localsPtr + hasBailedOutOffset));
PROBE_STACK(scriptContext, Constants::MinStackDefault + argsSize);
{
@@ -295,8 +304,10 @@ namespace Js
// If we have bailed out, this exception is coming from the interpreter. It should not have been caught;
// it so happens that this catch was on the stack and caught the exception.
// Re-throw!
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
JavascriptExceptionOperators::DoThrow(exception, scriptContext);
}
+
Var exceptionObject = exception->GetThrownObject(scriptContext);
AssertMsg(exceptionObject, "Caught object is null.");
#if defined(_M_ARM)
@@ -306,6 +317,7 @@ namespace Js
#endif
}
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
return continuation;
}
@@ -320,9 +332,9 @@ namespace Js
{
void *tryContinuation = nullptr;
JavascriptExceptionObject *exception = nullptr;
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr((bool*)((char*)localsPtr + hasBailedOutOffset));
PROBE_STACK(scriptContext, Constants::MinStackDefault + argsSize);
-
try
{
#if defined(_M_ARM)
@@ -355,8 +367,10 @@ namespace Js
// If we have bailed out, this exception is coming from the interpreter. It should not have been caught;
// it so happens that this catch was on the stack and caught the exception.
// Re-throw!
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
JavascriptExceptionOperators::DoThrow(exception, scriptContext);
}
+
scriptContext->GetThreadContext()->SetPendingFinallyException(exception);
#if defined(_M_ARM)
void * finallyContinuation = arm_CallEhFrame(finallyAddr, framePtr, localsPtr, argsSize);
@@ -366,6 +380,7 @@ namespace Js
return finallyContinuation;
}
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
return tryContinuation;
}
@@ -429,6 +444,7 @@ namespace Js
void* continuationAddr = NULL;
Js::JavascriptExceptionObject* pExceptionObject = NULL;
void *tryCatchFrameAddr = nullptr;
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr((bool*)((char*)framePtr + hasBailedOutOffset));
PROBE_STACK(scriptContext, Constants::MinStackDefault);
{
@@ -526,8 +542,10 @@ namespace Js
// If we have bailed out, this exception is coming from the interpreter. It should not have been caught;
// it so happens that this catch was on the stack and caught the exception.
// Re-throw!
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
JavascriptExceptionOperators::DoThrow(pExceptionObject, scriptContext);
}
+
Var catchObject = pExceptionObject->GetThrownObject(scriptContext);
AssertMsg(catchObject, "Caught object is NULL");
#ifdef _M_IX86
@@ -581,6 +599,7 @@ namespace Js
#endif
}
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
return continuationAddr;
}
@@ -588,7 +607,7 @@ namespace Js
{
Js::JavascriptExceptionObject* pExceptionObject = NULL;
void* continuationAddr = NULL;
-
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr((bool*)((char*)framePtr + hasBailedOutOffset));
PROBE_STACK(scriptContext, Constants::MinStackDefault);
try
@@ -676,8 +695,10 @@ namespace Js
// If we have bailed out, this exception is coming from the interpreter. It should not have been caught;
// it so happens that this catch was on the stack and caught the exception.
// Re-throw!
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
JavascriptExceptionOperators::DoThrow(pExceptionObject, scriptContext);
}
+
scriptContext->GetThreadContext()->SetPendingFinallyException(pExceptionObject);
void* newContinuationAddr = NULL;
@@ -733,6 +754,8 @@ namespace Js
#endif
return newContinuationAddr;
}
+
+ scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
return continuationAddr;
}
diff --git a/deps/chakrashim/core/test/EH/hasBailedOutBug.baseline b/deps/chakrashim/core/test/EH/hasBailedOutBug.baseline
new file mode 100644
index 00000000000..3a45d1d2cc9
--- /dev/null
+++ b/deps/chakrashim/core/test/EH/hasBailedOutBug.baseline
@@ -0,0 +1 @@
+TypeError: Assignment to read-only properties is not allowed in strict mode
diff --git a/deps/chakrashim/core/test/EH/hasBailedOutBug.js b/deps/chakrashim/core/test/EH/hasBailedOutBug.js
new file mode 100644
index 00000000000..611118be580
--- /dev/null
+++ b/deps/chakrashim/core/test/EH/hasBailedOutBug.js
@@ -0,0 +1,48 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+var shouldBailout = false;
+function test0() {
+ var obj0 = {};
+ var func0 = function () {
+ };
+ var func1 = function () {
+ (function () {
+ 'use strict';
+ try {
+ function func8() {
+ obj0.prop2;
+ }
+ var uniqobj4 = func8();
+ } catch (ex) {
+ return 'somestring';
+ } finally {
+ }
+ func0(ary.push(ary.unshift(Object.prototype.length = protoObj0)));
+ }(shouldBailout ? (Object.defineProperty(Object.prototype, 'length', {
+ get: function () {
+ }
+ })) : arguments));
+ };
+ var ary = Array();
+ var protoObj0 = Object();
+ ({
+ prop7: shouldBailout ? (Object.defineProperty(obj0, 'prop2', {
+ set: function () {
+ }
+ })) : Object
+ });
+ for (; func1(); ) {
+ }
+}
+test0();
+test0();
+shouldBailout = true;
+try {
+ test0();
+}
+catch(ex) {
+ print(ex);
+}
diff --git a/deps/chakrashim/core/test/EH/rlexe.xml b/deps/chakrashim/core/test/EH/rlexe.xml
index af75ca7873e..41009e625de 100644
--- a/deps/chakrashim/core/test/EH/rlexe.xml
+++ b/deps/chakrashim/core/test/EH/rlexe.xml
@@ -176,4 +176,10 @@
-force:inline
+
+
+ hasBailedOutBug.js
+ hasBailedOutBug.baseline
+
+