FTL lazy slow paths should work with B3
https://bugs.webkit.org/show_bug.cgi?id=151667

Reviewed by Geoffrey Garen.

This adds all of the glue necessary to make FTL::LazySlowPath work with B3. The B3 approach
allows us to put all of the code in FTL::LowerDFGToLLVM, instead of having supporting data
structures on the side and a bunch of complex code in FTLCompile.cpp.

* b3/B3CheckSpecial.cpp:
(JSC::B3::CheckSpecial::generate):
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::run):
* b3/B3PatchpointSpecial.cpp:
(JSC::B3::PatchpointSpecial::generate):
* b3/B3StackmapValue.h:
* ftl/FTLJSTailCall.cpp:
(JSC::FTL::DFG::recoveryFor):
(JSC::FTL::JSTailCall::emit):
* ftl/FTLLazySlowPath.cpp:
(JSC::FTL::LazySlowPath::LazySlowPath):
(JSC::FTL::LazySlowPath::generate):
* ftl/FTLLazySlowPath.h:
(JSC::FTL::LazySlowPath::createGenerator):
(JSC::FTL::LazySlowPath::patchableJump):
(JSC::FTL::LazySlowPath::done):
(JSC::FTL::LazySlowPath::patchpoint):
(JSC::FTL::LazySlowPath::usedRegisters):
(JSC::FTL::LazySlowPath::callSiteIndex):
(JSC::FTL::LazySlowPath::stub):
* ftl/FTLLocation.cpp:
(JSC::FTL::Location::forValueRep):
(JSC::FTL::Location::forStackmaps):
(JSC::FTL::Location::dump):
(JSC::FTL::Location::isGPR):
(JSC::FTL::Location::gpr):
(JSC::FTL::Location::isFPR):
(JSC::FTL::Location::fpr):
(JSC::FTL::Location::restoreInto):
* ftl/FTLLocation.h:
(JSC::FTL::Location::Location):
(JSC::FTL::Location::forRegister):
(JSC::FTL::Location::forIndirect):
(JSC::FTL::Location::forConstant):
(JSC::FTL::Location::kind):
(JSC::FTL::Location::hasReg):
(JSC::FTL::Location::reg):
(JSC::FTL::Location::hasOffset):
(JSC::FTL::Location::offset):
(JSC::FTL::Location::hash):
(JSC::FTL::Location::hasDwarfRegNum): Deleted.
(JSC::FTL::Location::dwarfRegNum): Deleted.
(JSC::FTL::Location::hasDwarfReg): Deleted.
(JSC::FTL::Location::dwarfReg): Deleted.
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::LowerDFGToLLVM):
(JSC::FTL::DFG::LowerDFGToLLVM::lazySlowPath):
* jit/RegisterSet.cpp:
(JSC::RegisterSet::stubUnavailableRegisters):
(JSC::RegisterSet::macroScratchRegisters):
(JSC::RegisterSet::calleeSaveRegisters):
* jit/RegisterSet.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@192856 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index 3ef2c55..4adc1aa 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -28,6 +28,8 @@
 
 #if ENABLE(FTL_JIT)
 
+#include "AirGenerationContext.h"
+#include "AllowMacroScratchRegisterUsage.h"
 #include "CodeBlockWithJITType.h"
 #include "DFGAbstractInterpreterInlines.h"
 #include "DFGDominators.h"
@@ -100,6 +102,7 @@
     } while (false)
 
 class LowerDFGToLLVM {
+    WTF_MAKE_NONCOPYABLE(LowerDFGToLLVM);
 public:
     LowerDFGToLLVM(State& state)
         : m_graph(state.graph)
@@ -7835,14 +7838,78 @@
     LValue lazySlowPath(const Functor& functor, const Vector<LValue>& userArguments)
     {
 #if FTL_USES_B3
-        UNUSED_PARAM(functor);
-
+        CodeOrigin origin = m_node->origin.semantic;
+        
         B3::PatchpointValue* result = m_out.patchpoint(B3::Int64);
         for (LValue arg : userArguments)
-            result->append(ConstrainedValue(arg, ValueRep::SomeRegister));
+            result->append(ConstrainedValue(arg, B3::ValueRep::SomeRegister));
+
+        // FIXME: As part of handling exceptions, we need to append OSR exit state here.
+        
+        result->clobber(RegisterSet::macroScratchRegisters());
+        State* state = &m_ftlState;
+
         result->setGenerator(
-            [&] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
-                jit.oops();
+            [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                Vector<Location> locations;
+                for (const B3::ValueRep& rep : params.reps)
+                    locations.append(Location::forValueRep(rep));
+
+                RefPtr<LazySlowPath::Generator> generator = functor(locations);
+                
+                CCallHelpers::PatchableJump patchableJump = jit.patchableJump();
+                CCallHelpers::Label done = jit.label();
+
+                RegisterSet usedRegisters = params.usedRegisters;
+
+                // FIXME: As part of handling exceptions, we need to create a concrete OSRExit here.
+                // Doing so should automagically register late paths that emit exit thunks.
+                
+                params.context->latePaths.append(
+                    createSharedTask<Air::GenerationContext::LatePathFunction>(
+                        [=] (CCallHelpers& jit, Air::GenerationContext&) {
+                            AllowMacroScratchRegisterUsage allowScratch(jit);
+                            patchableJump.m_jump.link(&jit);
+                            unsigned index = state->jitCode->lazySlowPaths.size();
+                            state->jitCode->lazySlowPaths.append(nullptr);
+                            jit.pushToSaveImmediateWithoutTouchingRegisters(
+                                CCallHelpers::TrustedImm32(index));
+                            CCallHelpers::Jump generatorJump = jit.jump();
+
+                            // Note that so long as we're here, we don't really know if our late path
+                            // runs before or after any other late paths that we might depend on, like
+                            // the exception thunk.
+
+                            RefPtr<JITCode> jitCode = state->jitCode;
+                            VM* vm = &state->graph.m_vm;
+
+                            jit.addLinkTask(
+                                [=] (LinkBuffer& linkBuffer) {
+                                    linkBuffer.link(
+                                        generatorJump, CodeLocationLabel(
+                                            vm->getCTIStub(
+                                                lazySlowPathGenerationThunkGenerator).code()));
+                                    
+                                    CodeLocationJump linkedPatchableJump = CodeLocationJump(
+                                        linkBuffer.locationOf(patchableJump));
+                                    CodeLocationLabel linkedDone = linkBuffer.locationOf(done);
+
+                                    // FIXME: Need a story for exceptions in FTL-B3. That basically means
+                                    // doing a lookup of the exception entrypoint here. We will have an
+                                    // OSR exit data structure of some sort.
+                                    // https://bugs.webkit.org/show_bug.cgi?id=151686
+                                    CodeLocationLabel exceptionTarget;
+                                    CallSiteIndex callSiteIndex =
+                                        jitCode->common.addUniqueCallSiteIndex(origin);
+                                    
+                                    std::unique_ptr<LazySlowPath> lazySlowPath =
+                                        std::make_unique<LazySlowPath>(
+                                            linkedPatchableJump, linkedDone, exceptionTarget,
+                                            usedRegisters, callSiteIndex, generator);
+                                    
+                                    jitCode->lazySlowPaths[index] = WTF::move(lazySlowPath);
+                                });
+                        }));
             });
         return result;
 #else