Meghana Gupta 7 lat temu
rodzic
commit
3bee8f018e

+ 4 - 0
lib/Runtime/Language/InterpreterStackFrame.cpp

@@ -6727,6 +6727,10 @@ skipThunk:
             // Finally exited with LeaveNull, We don't throw for early returns
             if (finallyEndOffset == 0 && exceptionObj)
             {
+                if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
+                {
+                    JavascriptExceptionOperators::WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
+                }
                 JavascriptExceptionOperators::DoThrow(const_cast<Js::JavascriptExceptionObject *>(exceptionObj), scriptContext);
             }
             if (finallyEndOffset != 0)

+ 166 - 138
lib/Runtime/Language/JavascriptExceptionOperators.cpp

@@ -190,19 +190,23 @@ namespace Js
     {
         void                      *tryContinuation     = nullptr;
         JavascriptExceptionObject *exception           = nullptr;
+        void                      *tryHandlerAddrOfReturnAddr = nullptr;
 
         Js::JavascriptExceptionOperators::HasBailedOutPtrStack hasBailedOutPtrStack(scriptContext, (bool*)((char*)frame + hasBailedOutOffset));
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + spillSize + argsSize);
-
-        try
-        {
-            tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize);
-        }
-        catch (const Js::JavascriptException& err)
         {
-            exception = err.GetAndClear();
+            void * addrOfReturnAddr = (void*)((char*)frame + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+            try
+            {
+                tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize);
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                exception = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-
         if (exception)
         {
             // Clone static exception object early in case finally block overwrites it
@@ -212,19 +216,9 @@ namespace Js
         if (exception)
         {
 #if ENABLE_NATIVE_CODEGEN
-            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
-            {
-                if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
-                {
-                    WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
-                }
-            }
-            else
+            if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
             {
-                if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
-                {
-                     WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, frame);
-                }
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
             }
 #endif
             bool hasBailedOut = *(bool*)((char*)frame + hasBailedOutOffset); // stack offsets are negative
@@ -251,21 +245,31 @@ namespace Js
         void                      *tryContinuation = nullptr;
         void                      *finallyContinuation = nullptr;
         JavascriptExceptionObject *exception           = nullptr;
+        void                      *tryHandlerAddrOfReturnAddr = nullptr;
 
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + spillSize + argsSize);
-        try
-        {
-            tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize);
-        }
-        catch (const Js::JavascriptException& err)
         {
-            exception = err.GetAndClear();
+            void * addrOfReturnAddr = (void*)((char*)frame + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+            try
+            {
+                tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize);
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                exception = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-
         if (exception)
         {
             // Clone static exception object early in case finally block overwrites it
             exception = exception->CloneIfStaticExceptionObject(scriptContext);
+
+            if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
+            }
         }
 
         finallyContinuation = amd64_CallWithFakeFrame(finallyAddr, frame, spillSize, argsSize);
@@ -276,6 +280,10 @@ namespace Js
 
         if (exception)
         {
+            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
+            }
             JavascriptExceptionOperators::DoThrow(exception, scriptContext);
         }
 
@@ -365,44 +373,40 @@ namespace Js
         int hasBailedOutOffset,
         ScriptContext *scriptContext)
     {
-        void                      *tryContinuation     = nullptr;
-        JavascriptExceptionObject *exception           = nullptr;
+        void                      *tryContinuation            = nullptr;
+        JavascriptExceptionObject *exception                  = nullptr;
+        void                      *tryHandlerAddrOfReturnAddr = nullptr;
+
         Js::JavascriptExceptionOperators::HasBailedOutPtrStack hasBailedOutPtrStack(scriptContext, (bool*)((char*)localsPtr + hasBailedOutOffset));
 
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + argsSize);
-        try
         {
+            void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+            try
+            {
 #if defined(_M_ARM)
             tryContinuation = arm_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
 #elif defined(_M_ARM64)
             tryContinuation = arm64_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
 #endif
-        }
-        catch (const Js::JavascriptException& err)
-        {
-            exception = err.GetAndClear();
-        }
-
-        if (exception)
-        {
-#if ENABLE_NATIVE_CODEGEN
-            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
-            {
-                if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
-                {
-                    WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
-                }
             }
-            else
+            catch (const Js::JavascriptException& err)
             {
-                if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
-                {
-                    WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, framePtr);
-                }
+                exception = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
             }
-#endif
+        }
+        if (exception)
+        {
             // Clone static exception object early in case finally block overwrites it
             exception = exception->CloneIfStaticExceptionObject(scriptContext);
+
+            if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
+            }
+
             bool hasBailedOut = *(bool*)((char*)localsPtr + hasBailedOutOffset); // stack offsets are sp relative
             if (hasBailedOut)
             {
@@ -437,26 +441,36 @@ namespace Js
         void                      *tryContinuation = nullptr;
         void                      *finallyContinuation = nullptr;
         JavascriptExceptionObject *exception = nullptr;
+        void                      *tryHandlerAddrOfReturnAddr = nullptr;
 
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + argsSize);
-
-        try
         {
+            void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+
+            try
+            {
 #if defined(_M_ARM)
-            tryContinuation = arm_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
+                tryContinuation = arm_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
 #elif defined(_M_ARM64)
-            tryContinuation = arm64_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
+                tryContinuation = arm64_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
 #endif
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                exception = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-        catch (const Js::JavascriptException& err)
-        {
-            exception = err.GetAndClear();
-        }
-
         if (exception)
         {
             // Clone static exception object early in case finally block overwrites it
             exception = exception->CloneIfStaticExceptionObject(scriptContext);
+
+            if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
+            }
         }
 
 #if defined(_M_ARM)
@@ -472,6 +486,10 @@ namespace Js
 
         if (exception)
         {
+            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
+            }
             JavascriptExceptionOperators::DoThrow(exception, scriptContext);
         }
 
@@ -647,21 +665,24 @@ namespace Js
     {
         Js::JavascriptExceptionObject* pExceptionObject = NULL;
         void* continuationAddr = NULL;
+        void* tryHandlerAddrOfReturnAddr = nullptr;
 
         Js::JavascriptExceptionOperators::HasBailedOutPtrStack hasBailedOutPtrStack(scriptContext, (bool*)((char*)framePtr + hasBailedOutOffset));
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout);
-
-        try
         {
-            // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function
-            // that may throw. The current workaround is to add the following dummy throw to prevent this optimization.
-            // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below).
-            // In order to circumvent that we are throwing OutOfMemory.
-            if (!tryAddr)
+            void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+            try
             {
-                Assert(false);
-                ThrowOutOfMemory(scriptContext);
-            }
+                // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function
+                // that may throw. The current workaround is to add the following dummy throw to prevent this optimization.
+                // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below).
+                // In order to circumvent that we are throwing OutOfMemory.
+                if (!tryAddr)
+                {
+                    Assert(false);
+                    ThrowOutOfMemory(scriptContext);
+                }
 
 #ifdef _M_IX86
             void *savedEsp;
@@ -711,28 +732,19 @@ namespace Js
 #else
             AssertMsg(FALSE, "Unsupported native try-finally handler");
 #endif
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                pExceptionObject = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-        catch(const Js::JavascriptException& err)
-        {
-            pExceptionObject = err.GetAndClear();
-        }
-
         if (pExceptionObject)
         {
 #if ENABLE_NATIVE_CODEGEN
-            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
-            {
-                if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction())
-                {
-                    WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
-                }
-            }
-            else
+            if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction())
             {
-                if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction())
-                {
-                    WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, framePtr);
-                }
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
             }
 #endif
             // Clone static exception object early in case finally block overwrites it
@@ -817,79 +829,91 @@ namespace Js
     {
         Js::JavascriptExceptionObject* pExceptionObject = NULL;
         void* continuationAddr = NULL;
+        void * tryHandlerAddrOfReturnAddr = nullptr;
 
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout);
-
-        try
         {
-            // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function
-            // that may throw. The current workaround is to add the following dummy throw to prevent this optimization.
-            // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below).
-            // In order to circumvent that we are throwing OutOfMemory.
-            if (!tryAddr)
+            void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+
+            try
             {
-                Assert(false);
-                ThrowOutOfMemory(scriptContext);
-            }
+                // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function
+                // that may throw. The current workaround is to add the following dummy throw to prevent this optimization.
+                // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below).
+                // In order to circumvent that we are throwing OutOfMemory.
+                if (!tryAddr)
+                {
+                    Assert(false);
+                    ThrowOutOfMemory(scriptContext);
+                }
 
 #ifdef _M_IX86
-            void *savedEsp;
-            __asm
-            {
-                // Save and restore the callee-saved registers around the call.
-                // TODO: track register kills by region and generate per-region prologs and epilogs
-                push esi
-                push edi
-                push ebx
+                void *savedEsp;
+                __asm
+                {
+                    // Save and restore the callee-saved registers around the call.
+                    // TODO: track register kills by region and generate per-region prologs and epilogs
+                    push esi
+                    push edi
+                    push ebx
 
-                // 8-byte align frame to improve floating point perf of our JIT'd code.
-                // Save ESP
-                mov ecx, esp
-                mov savedEsp, ecx
-                and esp, -8
+                    // 8-byte align frame to improve floating point perf of our JIT'd code.
+                    // Save ESP
+                    mov ecx, esp
+                    mov savedEsp, ecx
+                    and esp, -8
 
-                // Set up the call target, save the current frame ptr, and adjust the frame to access
-                // locals in native code.
-                mov eax, tryAddr
+                    // Set up the call target, save the current frame ptr, and adjust the frame to access
+                    // locals in native code.
+                    mov eax, tryAddr
 
 #if 0 && defined(_CONTROL_FLOW_GUARD)
-                // verify that the call target is valid
-                mov  ebx, eax; save call target
-                mov  ecx, eax
-                call[__guard_check_icall_fptr]
-                mov  eax, ebx; restore call target
+                    // verify that the call target is valid
+                    mov  ebx, eax; save call target
+                    mov  ecx, eax
+                    call[__guard_check_icall_fptr]
+                    mov  eax, ebx; restore call target
 #endif
 
-                push ebp
-                mov ebp, framePtr
-                call eax
-                pop ebp
+                    push ebp
+                    mov ebp, framePtr
+                    call eax
+                    pop ebp
 
-                // The native code gives us the address where execution should continue on exit
-                // from the region.
-                mov continuationAddr, eax
+                    // The native code gives us the address where execution should continue on exit
+                    // from the region.
+                    mov continuationAddr, eax
 
-                // Restore ESP
-                mov ecx, savedEsp
-                mov esp, ecx
+                    // Restore ESP
+                    mov ecx, savedEsp
+                    mov esp, ecx
 
-                pop ebx
-                pop edi
-                pop esi
-            }
+                    pop ebx
+                    pop edi
+                    pop esi
+                }
 #else
-            AssertMsg(FALSE, "Unsupported native try-finally handler");
+                AssertMsg(FALSE, "Unsupported native try-finally handler");
 #endif
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                pExceptionObject = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-        catch (const Js::JavascriptException& err)
-        {
-            pExceptionObject = err.GetAndClear();
-        }
-
         if (pExceptionObject)
         {
             // Clone static exception object early in case finally block overwrites it
             pExceptionObject = pExceptionObject->CloneIfStaticExceptionObject(scriptContext);
+
+#if ENABLE_NATIVE_CODEGEN
+            if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction())
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
+            }
+#endif
         }
 
         void* newContinuationAddr = NULL;
@@ -952,6 +976,10 @@ namespace Js
 
         if (pExceptionObject)
         {
+            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
+            }
             JavascriptExceptionOperators::DoThrow(pExceptionObject, scriptContext);
         }