Exits from exceptions shouldn't jettison code
https://bugs.webkit.org/show_bug.cgi?id=153564

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

We create two new exit kinds for exception-handling
OSRExits:
- ExceptionCheck: an exception check after a C call.
- GenericUnwind: an OSR exit executes because it's jumped to from genericUnwind machinery.

Having these two new exit kinds allows us to remove fields from
various OSRExit variants that store booleans indicating
if the exit is an exception handler, and if so, what kind
of exception handler. Most of this patch is just removing
those old fields and adding new equivalent functions.

This patch also implements the policy that we should never consider jettisoning
code from exits that happen from an exception check to an op_catch (it might be worth
considering a similar policy for 'throw'). We're choosing this policy because
it will almost never be more expensive, in total, to execute the OSR exit than
to execute the baseline variant of the code. When an exception is thrown, we do
really expensive work, like call through to genericUnwind, and also create an error
object with a stack trace. The cost of OSR exiting here is small in comparison to
those other operations. And penalizing a CodeBlock for OSR exiting from an exception
is silly because the basis of our implementation of exception handling in the
upper tiers is to OSR exit on a caught exception. So we used to penalize
ourselves for having an implementation that is correct w.r.t our design goals.

I've verified this hypothesis with on v8-raytrace by adding a new 
benchmark that throws with very high frequency. Implementing
this policy on that benchmark results in about a 4-5% speed up.

* bytecode/ExitKind.cpp:
(JSC::exitKindToString):
(JSC::exitKindMayJettison):
(JSC::exitKindIsCountable): Deleted.
* bytecode/ExitKind.h:
* dfg/DFGJITCode.cpp:
(JSC::DFG::JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::noticeOSREntry):
(JSC::DFG::JITCompiler::appendExceptionHandlingOSRExit):
(JSC::DFG::JITCompiler::exceptionCheck):
(JSC::DFG::JITCompiler::recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded):
* dfg/DFGJITCompiler.h:
* dfg/DFGOSRExit.cpp:
(JSC::DFG::OSRExit::OSRExit):
* dfg/DFGOSRExit.h:
(JSC::DFG::OSRExit::considerAddingAsFrequentExitSite):
* dfg/DFGOSRExitBase.h:
(JSC::DFG::OSRExitBase::OSRExitBase):
(JSC::DFG::OSRExitBase::isExceptionHandler):
(JSC::DFG::OSRExitBase::isGenericUnwindHandler):
(JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSite):
* dfg/DFGOSRExitCompiler.cpp:
* dfg/DFGOSRExitCompiler32_64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGOSRExitCompiler64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGOSRExitCompilerCommon.cpp:
(JSC::DFG::handleExitCounts):
(JSC::DFG::osrWriteBarrier):
(JSC::DFG::adjustAndJumpToTarget):
* dfg/DFGOSRExitCompilerCommon.h:
(JSC::DFG::adjustFrameAndStackInOSRExitCompilerThunk):
* ftl/FTLCompile.cpp:
(JSC::FTL::mmAllocateDataSection):
* ftl/FTLExitThunkGenerator.cpp:
(JSC::FTL::ExitThunkGenerator::emitThunk):
* ftl/FTLJITCode.cpp:
(JSC::FTL::JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::callCheck):
(JSC::FTL::DFG::LowerDFGToLLVM::appendOSRExitArgumentsForPatchpointIfWillCatchException):
(JSC::FTL::DFG::LowerDFGToLLVM::appendOSRExit):
(JSC::FTL::DFG::LowerDFGToLLVM::blessSpeculation):
* ftl/FTLOSRExit.cpp:
(JSC::FTL::OSRExitDescriptor::emitOSRExit):
(JSC::FTL::OSRExitDescriptor::emitOSRExitLater):
(JSC::FTL::OSRExitDescriptor::prepareOSRExitHandle):
(JSC::FTL::OSRExit::OSRExit):
(JSC::FTL::OSRExit::spillRegistersToSpillSlot):
(JSC::FTL::OSRExit::recoverRegistersFromSpillSlot):
(JSC::FTL::OSRExit::willArriveAtExitFromIndirectExceptionCheck):
(JSC::FTL::OSRExit::willArriveAtOSRExitFromCallOperation):
(JSC::FTL::exceptionTypeWillArriveAtOSRExitFromGenericUnwind): Deleted.
(JSC::FTL::OSRExit::willArriveAtOSRExitFromGenericUnwind): Deleted.
* ftl/FTLOSRExit.h:
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStub):
(JSC::FTL::compileFTLOSRExit):
* ftl/FTLPatchpointExceptionHandle.cpp:
(JSC::FTL::PatchpointExceptionHandle::scheduleExitCreation):
(JSC::FTL::PatchpointExceptionHandle::scheduleExitCreationForUnwind):
(JSC::FTL::PatchpointExceptionHandle::PatchpointExceptionHandle):
(JSC::FTL::PatchpointExceptionHandle::createHandle):
* ftl/FTLPatchpointExceptionHandle.h:

LayoutTests:

* js/regress/script-tests/v8-raytrace-with-try-catch-high-frequency-throws.js: Added.
(randomException):
(Class.create):
(Object.extend):
(Flog.RayTracer.Color.prototype.initialize):
(Flog.RayTracer.Color.prototype.add):
(Flog.RayTracer.Color.prototype.addScalar):
(Flog.RayTracer.Color.prototype.subtract):
(Flog.RayTracer.Color.prototype.multiply):
(Flog.RayTracer.Color.prototype.multiplyScalar):
(Flog.RayTracer.Color.prototype.divideFactor):
(Flog.RayTracer.Color.prototype.limit):
(Flog.RayTracer.Color.prototype.distance):
(Flog.RayTracer.Color.prototype.blend):
(Flog.RayTracer.Color.prototype.brightness):
(Flog.RayTracer.Color.prototype.toString):
(Flog.RayTracer.Light.prototype.initialize):
(Flog.RayTracer.Light.prototype.toString):
(Flog.RayTracer.Vector.prototype.initialize):
(Flog.RayTracer.Vector.prototype.copy):
(Flog.RayTracer.Vector.prototype.normalize):
(Flog.RayTracer.Vector.prototype.magnitude):
(Flog.RayTracer.Vector.prototype.cross):
(Flog.RayTracer.Vector.prototype.dot):
(Flog.RayTracer.Vector.prototype.add):
(Flog.RayTracer.Vector.prototype.subtract):
(Flog.RayTracer.Vector.prototype.multiplyVector):
(Flog.RayTracer.Vector.prototype.multiplyScalar):
(Flog.RayTracer.Vector.prototype.toString):
(Flog.RayTracer.Ray.prototype.initialize):
(Flog.RayTracer.Ray.prototype.toString):
(Flog.RayTracer.Scene.prototype.initialize):
(Flog.RayTracer.Material.BaseMaterial.prototype.initialize):
(Flog.RayTracer.Material.BaseMaterial.prototype.getColor):
(Flog.RayTracer.Material.BaseMaterial.prototype.wrapUp):
(Flog.RayTracer.Material.BaseMaterial.prototype.toString):
(Flog.RayTracer.Material.Solid.prototype.Object.extend.new.Flog.RayTracer.Material.BaseMaterial.initialize):
(Flog.RayTracer.Material.Solid.prototype.Object.extend.new.Flog.RayTracer.Material.BaseMaterial.getColor):
(Flog.RayTracer.Material.Solid.prototype.Object.extend.new.Flog.RayTracer.Material.BaseMaterial.toString):
(Flog.RayTracer.Material.Solid.prototype.Object.extend.new.Flog.RayTracer.Material.BaseMaterial):
(Flog.RayTracer.Material.Chessboard.prototype.Object.extend.new.Flog.RayTracer.Material.BaseMaterial.initialize):
(Flog.RayTracer.Material.Chessboard.prototype.Object.extend.new.Flog.RayTracer.Material.BaseMaterial.getColor):
(Flog.RayTracer.Material.Chessboard.prototype.Object.extend.new.Flog.RayTracer.Material.BaseMaterial.toString):
(Flog.RayTracer.Material.Chessboard.prototype.Object.extend.new.Flog.RayTracer.Material.BaseMaterial):
(Flog.RayTracer.Shape.Sphere.prototype.initialize):
(Flog.RayTracer.Shape.Sphere.prototype.intersect):
(Flog.RayTracer.Shape.Sphere.prototype.toString):
(Flog.RayTracer.Shape.Plane.prototype.initialize):
(Flog.RayTracer.Shape.Plane.prototype.intersect):
(Flog.RayTracer.Shape.Plane.prototype.toString):
(Flog.RayTracer.IntersectionInfo.prototype.initialize):
(Flog.RayTracer.IntersectionInfo.prototype.toString):
(Flog.RayTracer.Camera.prototype.initialize):
(Flog.RayTracer.Camera.prototype.getRay):
(Flog.RayTracer.Camera.prototype.toString):
(Flog.RayTracer.Background.prototype.initialize):
(Flog.RayTracer.Engine.prototype.initialize):
(Flog.RayTracer.Engine.prototype.setPixel):
(Flog.RayTracer.Engine.prototype.renderScene):
(Flog.RayTracer.Engine.prototype.getPixelColor):
(Flog.RayTracer.Engine.prototype.testIntersection):
(Flog.RayTracer.Engine.prototype.getReflectionRay):
(Flog.RayTracer.Engine.prototype.rayTrace):
(renderScene):
* js/regress/v8-raytrace-with-try-catch-high-frequency-throws-expected.txt: Added.
* js/regress/v8-raytrace-with-try-catch-high-frequency-throws.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@195831 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ftl/FTLOSRExit.cpp b/Source/JavaScriptCore/ftl/FTLOSRExit.cpp
index 59e1f44..ffbb637 100644
--- a/Source/JavaScriptCore/ftl/FTLOSRExit.cpp
+++ b/Source/JavaScriptCore/ftl/FTLOSRExit.cpp
@@ -69,20 +69,20 @@
 #if FTL_USES_B3
 RefPtr<OSRExitHandle> OSRExitDescriptor::emitOSRExit(
     State& state, ExitKind exitKind, const NodeOrigin& nodeOrigin, CCallHelpers& jit,
-    const StackmapGenerationParams& params, unsigned offset, bool isExceptionHandler)
+    const StackmapGenerationParams& params, unsigned offset)
 {
     RefPtr<OSRExitHandle> handle =
-        prepareOSRExitHandle(state, exitKind, nodeOrigin, params, offset, isExceptionHandler);
+        prepareOSRExitHandle(state, exitKind, nodeOrigin, params, offset);
     handle->emitExitThunk(state, jit);
     return handle;
 }
 
 RefPtr<OSRExitHandle> OSRExitDescriptor::emitOSRExitLater(
     State& state, ExitKind exitKind, const NodeOrigin& nodeOrigin,
-    const StackmapGenerationParams& params, unsigned offset, bool isExceptionHandler)
+    const StackmapGenerationParams& params, unsigned offset)
 {
     RefPtr<OSRExitHandle> handle =
-        prepareOSRExitHandle(state, exitKind, nodeOrigin, params, offset, isExceptionHandler);
+        prepareOSRExitHandle(state, exitKind, nodeOrigin, params, offset);
     params.addLatePath(
         [handle, &state] (CCallHelpers& jit) {
             handle->emitExitThunk(state, jit);
@@ -92,11 +92,11 @@
 
 RefPtr<OSRExitHandle> OSRExitDescriptor::prepareOSRExitHandle(
     State& state, ExitKind exitKind, const NodeOrigin& nodeOrigin,
-    const StackmapGenerationParams& params, unsigned offset, bool isExceptionHandler)
+    const StackmapGenerationParams& params, unsigned offset)
 {
     unsigned index = state.jitCode->osrExit.size();
     OSRExit& exit = state.jitCode->osrExit.alloc(
-        this, exitKind, nodeOrigin.forExit, nodeOrigin.semantic, isExceptionHandler);
+        this, exitKind, nodeOrigin.forExit, nodeOrigin.semantic);
     RefPtr<OSRExitHandle> handle = adoptRef(new OSRExitHandle(index, exit));
     for (unsigned i = offset; i < params.size(); ++i)
         exit.m_valueReps.append(params[i]);
@@ -108,23 +108,20 @@
 #if FTL_USES_B3
 OSRExit::OSRExit(
     OSRExitDescriptor* descriptor,
-    ExitKind exitKind, CodeOrigin codeOrigin, CodeOrigin codeOriginForExitProfile,
-    bool isExceptionHandler)
+    ExitKind exitKind, CodeOrigin codeOrigin, CodeOrigin codeOriginForExitProfile)
     : OSRExitBase(exitKind, codeOrigin, codeOriginForExitProfile)
     , m_descriptor(descriptor)
 {
-    m_isExceptionHandler = isExceptionHandler;
 }
 #else // FTL_USES_B3
 OSRExit::OSRExit(
-    OSRExitDescriptor* descriptor, OSRExitDescriptorImpl& exitDescriptorImpl,
+    OSRExitDescriptor* descriptor, ExitKind exitKind, OSRExitDescriptorImpl& exitDescriptorImpl,
     uint32_t stackmapRecordIndex)
-    : OSRExitBase(exitDescriptorImpl.m_kind, exitDescriptorImpl.m_codeOrigin, exitDescriptorImpl.m_codeOriginForExitProfile)
+    : OSRExitBase(exitKind, exitDescriptorImpl.m_codeOrigin, exitDescriptorImpl.m_codeOriginForExitProfile)
     , m_descriptor(descriptor)
     , m_stackmapRecordIndex(stackmapRecordIndex)
     , m_exceptionType(exitDescriptorImpl.m_exceptionType)
 {
-    m_isExceptionHandler = exitDescriptorImpl.m_exceptionType != ExceptionType::None;
 }
 #endif // FTL_USES_B3
 
@@ -178,7 +175,7 @@
 
 void OSRExit::spillRegistersToSpillSlot(CCallHelpers& jit, int32_t stackSpillSlot)
 {
-    RELEASE_ASSERT(willArriveAtOSRExitFromGenericUnwind() || willArriveAtOSRExitFromCallOperation());
+    RELEASE_ASSERT(isGenericUnwindHandler() || willArriveAtOSRExitFromCallOperation());
     unsigned count = 0;
     for (GPRReg reg = MacroAssembler::firstRegister(); reg <= MacroAssembler::lastRegister(); reg = MacroAssembler::nextRegister(reg)) {
         if (registersToPreserveForCallThatMightThrow.get(reg)) {
@@ -196,7 +193,7 @@
 
 void OSRExit::recoverRegistersFromSpillSlot(CCallHelpers& jit, int32_t stackSpillSlot)
 {
-    RELEASE_ASSERT(willArriveAtOSRExitFromGenericUnwind() || willArriveAtOSRExitFromCallOperation());
+    RELEASE_ASSERT(isGenericUnwindHandler() || willArriveAtOSRExitFromCallOperation());
     unsigned count = 0;
     for (GPRReg reg = MacroAssembler::firstRegister(); reg <= MacroAssembler::lastRegister(); reg = MacroAssembler::nextRegister(reg)) {
         if (registersToPreserveForCallThatMightThrow.get(reg)) {
@@ -229,24 +226,6 @@
     RELEASE_ASSERT_NOT_REACHED();
 }
 
-bool exceptionTypeWillArriveAtOSRExitFromGenericUnwind(ExceptionType exceptionType)
-{
-    switch (exceptionType) {
-    case ExceptionType::JSCall:
-    case ExceptionType::GetById:
-    case ExceptionType::PutById:
-        return true;
-    default:
-        return false;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-}
-
-bool OSRExit::willArriveAtOSRExitFromGenericUnwind() const
-{
-    return exceptionTypeWillArriveAtOSRExitFromGenericUnwind(m_exceptionType);
-}
-
 bool OSRExit::willArriveAtOSRExitFromCallOperation() const
 {
     switch (m_exceptionType) {