Teach Call ICs how to call Wasm
[WebKit-https.git] / Source / JavaScriptCore / jit / RegisterSet.h
index 5f0499c..ae42323 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
-#ifndef RegisterSet_h
-#define RegisterSet_h
+#pragma once
 
-#include <wtf/Platform.h>
+#if !ENABLE(C_LOOP)
 
-#if ENABLE(JIT)
-
-#include "FPRInfo.h"
 #include "GPRInfo.h"
+#include "MacroAssembler.h"
+#include "Reg.h"
+#include "TempRegisterSet.h"
 #include <wtf/Bitmap.h>
 
 namespace JSC {
 
-static const unsigned totalNumberOfRegisters =
-    GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters;
-
-static const unsigned numberOfBytesInRegisterSet =
-    (totalNumberOfRegisters + 7) >> 3;
-
-typedef uint8_t RegisterSetPOD[numberOfBytesInRegisterSet];
+typedef Bitmap<MacroAssembler::numGPRs + MacroAssembler::numFPRs + 1> RegisterBitmap;
+class RegisterAtOffsetList;
 
 class RegisterSet {
 public:
-    RegisterSet()
-    {
-        for (unsigned i = numberOfBytesInRegisterSet; i--;)
-            m_set[i] = 0;
-    }
-    
-    RegisterSet(const RegisterSetPOD& other)
+    constexpr RegisterSet() { }
+
+    template<typename... Regs>
+    constexpr explicit RegisterSet(Regs... regs)
     {
-        for (unsigned i = numberOfBytesInRegisterSet; i--;)
-            m_set[i] = other[i];
+        setMany(regs...);
     }
     
-    const RegisterSetPOD& asPOD() const { return m_set; }
+    JS_EXPORT_PRIVATE static RegisterSet stackRegisters();
+    JS_EXPORT_PRIVATE static RegisterSet reservedHardwareRegisters();
+    static RegisterSet runtimeTagRegisters();
+    static RegisterSet specialRegisters(); // The union of stack, reserved hardware, and runtime registers.
+    JS_EXPORT_PRIVATE static RegisterSet calleeSaveRegisters();
+    static RegisterSet vmCalleeSaveRegisters(); // Callee save registers that might be saved and used by any tier.
+    static RegisterAtOffsetList* vmCalleeSaveRegisterOffsets();
+    static RegisterSet llintBaselineCalleeSaveRegisters(); // Registers saved and used by the LLInt.
+    static RegisterSet dfgCalleeSaveRegisters(); // Registers saved and used by the DFG JIT.
+    static RegisterSet ftlCalleeSaveRegisters(); // Registers that might be saved and used by the FTL JIT.
+#if ENABLE(WEBASSEMBLY)
+    static RegisterSet webAssemblyCalleeSaveRegisters(); // Registers saved and used by the WebAssembly JIT.
+#endif
+    static RegisterSet volatileRegistersForJSCall();
+    static RegisterSet stubUnavailableRegisters(); // The union of callee saves and special registers.
+    JS_EXPORT_PRIVATE static RegisterSet macroScratchRegisters();
+    JS_EXPORT_PRIVATE static RegisterSet allGPRs();
+    JS_EXPORT_PRIVATE static RegisterSet allFPRs();
+    static RegisterSet allRegisters();
+    JS_EXPORT_PRIVATE static RegisterSet argumentGPRS();
+
+    static RegisterSet registersToNotSaveForJSCall();
+    static RegisterSet registersToNotSaveForCCall();
     
-    void copyInfo(RegisterSetPOD& other) const
+    void set(Reg reg, bool value = true)
     {
-        for (unsigned i = numberOfBytesInRegisterSet; i--;)
-            other[i] = m_set[i];
+        ASSERT(!!reg);
+        m_bits.set(reg.index(), value);
     }
     
-    void set(GPRReg reg)
+    void set(JSValueRegs regs, bool value = true)
     {
-        setBit(GPRInfo::toIndex(reg));
+        if (regs.tagGPR() != InvalidGPRReg)
+            set(regs.tagGPR(), value);
+        set(regs.payloadGPR(), value);
     }
     
-    void setGPRByIndex(unsigned index)
+    void clear(Reg reg)
     {
-        ASSERT(index < GPRInfo::numberOfRegisters);
-        setBit(index);
+        ASSERT(!!reg);
+        set(reg, false);
     }
     
-    void clear(GPRReg reg)
+    bool get(Reg reg) const
     {
-        clearBit(GPRInfo::toIndex(reg));
+        ASSERT(!!reg);
+        return m_bits.get(reg.index());
     }
     
-    bool get(GPRReg reg) const
+    template<typename Iterable>
+    void setAll(const Iterable& iterable)
     {
-        return getBit(GPRInfo::toIndex(reg));
+        for (Reg reg : iterable)
+            set(reg);
     }
     
-    bool getGPRByIndex(unsigned index) const
+    // Also allow add/remove/contains terminology, which means the same thing as set/clear/get.
+    bool add(Reg reg)
     {
-        ASSERT(index < GPRInfo::numberOfRegisters);
-        return getBit(index);
+        ASSERT(!!reg);
+        return !m_bits.testAndSet(reg.index());
     }
-    
-    // Return the index'th free GPR.
-    GPRReg getFreeGPR(unsigned index = 0) const
+    bool remove(Reg reg)
     {
-        for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
-            if (!getGPRByIndex(i) && !index--)
-                return GPRInfo::toRegister(i);
-        }
-        return InvalidGPRReg;
+        ASSERT(!!reg);
+        return m_bits.testAndClear(reg.index());
     }
+    bool contains(Reg reg) const { return get(reg); }
     
-    void set(FPRReg reg)
-    {
-        setBit(GPRInfo::numberOfRegisters + FPRInfo::toIndex(reg));
-    }
+    void merge(const RegisterSet& other) { m_bits.merge(other.m_bits); }
+    void filter(const RegisterSet& other) { m_bits.filter(other.m_bits); }
+    void exclude(const RegisterSet& other) { m_bits.exclude(other.m_bits); }
     
-    void setFPRByIndex(unsigned index)
-    {
-        ASSERT(index < FPRInfo::numberOfRegisters);
-        setBit(GPRInfo::numberOfRegisters + index);
-    }
+    bool subsumes(const RegisterSet& other) const { return m_bits.subsumes(other.m_bits); }
     
-    void clear(FPRReg reg)
-    {
-        clearBit(GPRInfo::numberOfRegisters + FPRInfo::toIndex(reg));
-    }
+    size_t numberOfSetGPRs() const;
+    size_t numberOfSetFPRs() const;
+    size_t numberOfSetRegisters() const { return m_bits.count(); }
     
-    bool get(FPRReg reg) const
-    {
-        return getBit(GPRInfo::numberOfRegisters + FPRInfo::toIndex(reg));
-    }
+    bool isEmpty() const { return m_bits.isEmpty(); }
     
-    bool getFPRByIndex(unsigned index) const
-    {
-        ASSERT(index < FPRInfo::numberOfRegisters);
-        return getBit(GPRInfo::numberOfRegisters + index);
-    }
+    JS_EXPORT_PRIVATE void dump(PrintStream&) const;
     
-    template<typename BankInfo>
-    void setByIndex(unsigned index)
-    {
-        set(BankInfo::toRegister(index));
-    }
+    enum EmptyValueTag { EmptyValue };
+    enum DeletedValueTag { DeletedValue };
     
-    template<typename BankInfo>
-    bool getByIndex(unsigned index)
+    RegisterSet(EmptyValueTag)
     {
-        return get(BankInfo::toRegister(index));
+        m_bits.set(hashSpecialBitIndex);
     }
     
-    unsigned numberOfSetGPRs() const
+    RegisterSet(DeletedValueTag)
     {
-        unsigned result = 0;
-        for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
-            if (!getBit(i))
-                continue;
-            result++;
-        }
-        return result;
+        m_bits.set(hashSpecialBitIndex);
+        m_bits.set(deletedBitIndex);
     }
     
-    unsigned numberOfSetFPRs() const
+    bool isEmptyValue() const
     {
-        unsigned result = 0;
-        for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
-            if (!getBit(GPRInfo::numberOfRegisters + i))
-                continue;
-            result++;
-        }
-        return result;
+        return m_bits.get(hashSpecialBitIndex) && !m_bits.get(deletedBitIndex);
     }
     
-    unsigned numberOfSetRegisters() const
+    bool isDeletedValue() const
     {
-        unsigned result = 0;
-        for (unsigned i = totalNumberOfRegisters; i--;) {
-            if (!getBit(i))
-                continue;
-            result++;
-        }
-        return result;
+        return m_bits.get(hashSpecialBitIndex) && m_bits.get(deletedBitIndex);
     }
     
-private:
-    void setBit(unsigned i)
-    {
-        ASSERT(i < totalNumberOfRegisters);
-        m_set[i >> 3] |= (1 << (i & 7));
-    }
+    bool operator==(const RegisterSet& other) const { return m_bits == other.m_bits; }
+    bool operator!=(const RegisterSet& other) const { return m_bits != other.m_bits; }
+    
+    unsigned hash() const { return m_bits.hash(); }
     
-    void clearBit(unsigned i)
+    template<typename Func>
+    void forEach(const Func& func) const
     {
-        ASSERT(i < totalNumberOfRegisters);
-        m_set[i >> 3] &= ~(1 << (i & 7));
+        m_bits.forEachSetBit(
+            [&] (size_t index) {
+                func(Reg::fromIndex(index));
+            });
     }
     
-    bool getBit(unsigned i) const
+    class iterator {
+    public:
+        iterator()
+        {
+        }
+        
+        iterator(const RegisterBitmap::iterator& iter)
+            : m_iter(iter)
+        {
+        }
+        
+        Reg operator*() const { return Reg::fromIndex(*m_iter); }
+        
+        iterator& operator++()
+        {
+            ++m_iter;
+            return *this;
+        }
+        
+        bool operator==(const iterator& other)
+        {
+            return m_iter == other.m_iter;
+        }
+        
+        bool operator!=(const iterator& other)
+        {
+            return !(*this == other);
+        }
+        
+    private:
+        RegisterBitmap::iterator m_iter;
+    };
+    
+    iterator begin() const { return iterator(m_bits.begin()); }
+    iterator end() const { return iterator(m_bits.end()); }
+    
+private:
+    void setAny(Reg reg) { set(reg); }
+    void setAny(JSValueRegs regs) { set(regs); }
+    void setAny(const RegisterSet& set) { merge(set); }
+    void setMany() { }
+    template<typename RegType, typename... Regs>
+    void setMany(RegType reg, Regs... regs)
     {
-        ASSERT(i < totalNumberOfRegisters);
-        return !!(m_set[i >> 3] & (1 << (i & 7)));
+        setAny(reg);
+        setMany(regs...);
     }
+
+    // These offsets mirror the logic in Reg.h.
+    static const unsigned gprOffset = 0;
+    static const unsigned fprOffset = gprOffset + MacroAssembler::numGPRs;
+    static const unsigned hashSpecialBitIndex = fprOffset + MacroAssembler::numFPRs;
+    static const unsigned deletedBitIndex = 0;
     
-    RegisterSetPOD m_set;
+    RegisterBitmap m_bits;
 };
 
-} // namespace JSC
-
-#else // ENABLE(JIT) -> so if JIT is disabled
-
-namespace JSC {
+struct RegisterSetHash {
+    static unsigned hash(const RegisterSet& set) { return set.hash(); }
+    static bool equal(const RegisterSet& a, const RegisterSet& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = false;
+};
 
-// Define RegisterSetPOD to something that is a POD, but is otherwise useless,
-// to make it easier to refer to this type in code that may be compiled when
-// the DFG is disabled.
+} // namespace JSC
 
-struct RegisterSetPOD { };
+namespace WTF {
 
-} // namespace JSC
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::RegisterSet> {
+    typedef JSC::RegisterSetHash Hash;
+};
 
-#endif // ENABLE(JIT)
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::RegisterSet> : public CustomHashTraits<JSC::RegisterSet> { };
 
-#endif // RegisterSet_h
+} // namespace WTF
 
+#endif // !ENABLE(C_LOOP)