[JSC] Shrink size of VM by lazily allocating IsoSubspaces for non-common types
[WebKit-https.git] / Source / JavaScriptCore / runtime / VM.h
index c03498e..2ea8207 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -51,6 +51,7 @@
 #include "SmallStrings.h"
 #include "Strong.h"
 #include "StructureCache.h"
+#include "SubspaceAccess.h"
 #include "VMTraps.h"
 #include "WasmContext.h"
 #include "Watchpoint.h"
@@ -63,6 +64,7 @@
 #include <wtf/Gigacage.h>
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
+#include <wtf/SetForScope.h>
 #include <wtf/StackBounds.h>
 #include <wtf/StackPointer.h>
 #include <wtf/Stopwatch.h>
@@ -128,6 +130,7 @@ class JSWebAssemblyInstance;
 class LLIntOffsetsExtractor;
 class NativeExecutable;
 class PromiseDeferredTimer;
+class RegExp;
 class RegExpCache;
 class Register;
 class RegisterAtOffsetList;
@@ -321,9 +324,8 @@ public:
     std::unique_ptr<GigacageAlignedMemoryAllocator> jsValueGigacageAllocator;
 
     std::unique_ptr<HeapCellType> auxiliaryHeapCellType;
-    std::unique_ptr<HeapCellType> cellJSValueOOBHeapCellType;
     std::unique_ptr<HeapCellType> immutableButterflyHeapCellType;
-    std::unique_ptr<HeapCellType> cellDangerousBitsHeapCellType;
+    std::unique_ptr<HeapCellType> cellHeapCellType;
     std::unique_ptr<HeapCellType> destructibleCellHeapCellType;
     std::unique_ptr<JSStringHeapCellType> stringHeapCellType;
     std::unique_ptr<JSDestructibleObjectHeapCellType> destructibleObjectHeapCellType;
@@ -345,6 +347,8 @@ public:
     ALWAYS_INLINE CompleteSubspace& gigacageAuxiliarySpace(Gigacage::Kind kind)
     {
         switch (kind) {
+        case Gigacage::ReservedForFlagsAndNotABasePtr:
+            RELEASE_ASSERT_NOT_REACHED();
         case Gigacage::Primitive:
             return primitiveGigacageAuxiliarySpace;
         case Gigacage::JSValue:
@@ -355,8 +359,7 @@ public:
     }
     
     // Whenever possible, use subspaceFor<CellType>(vm) to get one of these subspaces.
-    CompleteSubspace cellJSValueOOBSpace;
-    CompleteSubspace cellDangerousBitsSpace;
+    CompleteSubspace cellSpace;
     CompleteSubspace jsValueGigacageCellSpace; // FIXME: This space is problematic because we have things in here like DirectArguments and ScopedArguments; those should be split into JSValueOOB cells and JSValueStrict auxiliaries. https://bugs.webkit.org/show_bug.cgi?id=182858
     CompleteSubspace destructibleCellSpace;
     CompleteSubspace stringSpace;
@@ -364,142 +367,116 @@ public:
     CompleteSubspace eagerlySweptDestructibleObjectSpace;
     CompleteSubspace segmentedVariableObjectSpace;
     
-    IsoSubspace arrayBufferConstructorSpace;
-    IsoSubspace asyncFunctionSpace;
-    IsoSubspace asyncGeneratorFunctionSpace;
-    IsoSubspace boundFunctionSpace;
-    IsoSubspace callbackFunctionSpace;
-    IsoSubspace customGetterSetterFunctionSpace;
-    IsoSubspace errorConstructorSpace;
     IsoSubspace executableToCodeBlockEdgeSpace;
     IsoSubspace functionSpace;
-    IsoSubspace generatorFunctionSpace;
-    IsoSubspace inferredTypeSpace;
-    IsoSubspace inferredValueSpace;
     IsoSubspace internalFunctionSpace;
-#if ENABLE(INTL)
-    IsoSubspace intlCollatorConstructorSpace;
-    IsoSubspace intlDateTimeFormatConstructorSpace;
-    IsoSubspace intlNumberFormatConstructorSpace;
-    IsoSubspace intlPluralRulesConstructorSpace;
-#endif
-    IsoSubspace nativeErrorConstructorSpace;
     IsoSubspace nativeExecutableSpace;
-    IsoSubspace nativeStdFunctionSpace;
-#if JSC_OBJC_API_ENABLED
-    IsoSubspace objCCallbackFunctionSpace;
-#endif
     IsoSubspace propertyTableSpace;
-    IsoSubspace proxyRevokeSpace;
-    IsoSubspace regExpConstructorSpace;
-    IsoSubspace strictModeTypeErrorFunctionSpace;
     IsoSubspace structureRareDataSpace;
     IsoSubspace structureSpace;
-    IsoSubspace weakSetSpace;
-    IsoSubspace weakMapSpace;
-    IsoSubspace errorInstanceSpace;
+
+#define DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(name) \
+    template<SubspaceAccess mode> \
+    IsoSubspace* name() \
+    { \
+        if (m_##name || mode == SubspaceAccess::Concurrently) \
+            return m_##name.get(); \
+        return name##Slow(); \
+    } \
+    IsoSubspace* name##Slow(); \
+    std::unique_ptr<IsoSubspace> m_##name;
+
+
+#if JSC_OBJC_API_ENABLED
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(objCCallbackFunctionSpace)
+#endif
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(boundFunctionSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(callbackFunctionSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(customGetterSetterFunctionSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(errorInstanceSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(nativeStdFunctionSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(proxyRevokeSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(weakSetSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(weakMapSpace)
 #if ENABLE(WEBASSEMBLY)
-    IsoSubspace webAssemblyCodeBlockSpace;
-    IsoSubspace webAssemblyFunctionSpace;
-    IsoSubspace webAssemblyWrapperFunctionSpace;
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(webAssemblyCodeBlockSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(webAssemblyFunctionSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(webAssemblyWrapperFunctionSpace)
 #endif
+
+#undef DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER
     
     IsoCellSet executableToCodeBlockEdgesWithConstraints;
     IsoCellSet executableToCodeBlockEdgesWithFinalizers;
-    IsoCellSet inferredTypesWithFinalizers;
-    IsoCellSet inferredValuesWithFinalizers;
+
+#define DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(name) \
+    template<SubspaceAccess mode> \
+    IsoSubspace* name() \
+    { \
+        if (auto* spaceAndSet = m_##name.get()) \
+            return &spaceAndSet->space; \
+        if (mode == SubspaceAccess::Concurrently) \
+            return nullptr; \
+        return name##Slow(); \
+    } \
+    IsoSubspace* name##Slow(); \
+    std::unique_ptr<SpaceAndSet> m_##name;
     
-    struct SpaceAndFinalizerSet {
+    struct SpaceAndSet {
+        WTF_MAKE_STRUCT_FAST_ALLOCATED;
+
         IsoSubspace space;
-        IsoCellSet finalizerSet;
+        IsoCellSet set;
         
         template<typename... Arguments>
-        SpaceAndFinalizerSet(Arguments&&... arguments)
+        SpaceAndSet(Arguments&&... arguments)
             : space(std::forward<Arguments>(arguments)...)
-            , finalizerSet(space)
+            , set(space)
         {
         }
         
-        static IsoCellSet& finalizerSetFor(Subspace& space)
+        static IsoCellSet& setFor(Subspace& space)
         {
             return *bitwise_cast<IsoCellSet*>(
                 bitwise_cast<char*>(&space) -
-                OBJECT_OFFSETOF(SpaceAndFinalizerSet, space) +
-                OBJECT_OFFSETOF(SpaceAndFinalizerSet, finalizerSet));
+                OBJECT_OFFSETOF(SpaceAndSet, space) +
+                OBJECT_OFFSETOF(SpaceAndSet, set));
         }
     };
     
-    SpaceAndFinalizerSet evalCodeBlockSpace;
-    SpaceAndFinalizerSet functionCodeBlockSpace;
-    SpaceAndFinalizerSet moduleProgramCodeBlockSpace;
-    SpaceAndFinalizerSet programCodeBlockSpace;
+    SpaceAndSet codeBlockSpace;
+    DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(inferredValueSpace)
 
     template<typename Func>
     void forEachCodeBlockSpace(const Func& func)
     {
         // This should not include webAssemblyCodeBlockSpace because this is about subsclasses of
         // JSC::CodeBlock.
-        func(evalCodeBlockSpace);
-        func(functionCodeBlockSpace);
-        func(moduleProgramCodeBlockSpace);
-        func(programCodeBlockSpace);
+        func(codeBlockSpace);
     }
 
-    struct ScriptExecutableSpaceAndSet {
-        IsoSubspace space;
-        IsoCellSet clearableCodeSet;
-
-        template<typename... Arguments>
-        ScriptExecutableSpaceAndSet(Arguments&&... arguments)
-            : space(std::forward<Arguments>(arguments)...)
-            , clearableCodeSet(space)
-        { }
-
-        static IsoCellSet& clearableCodeSetFor(Subspace& space)
-        {
-            return *bitwise_cast<IsoCellSet*>(
-                bitwise_cast<char*>(&space) -
-                OBJECT_OFFSETOF(ScriptExecutableSpaceAndSet, space) +
-                OBJECT_OFFSETOF(ScriptExecutableSpaceAndSet, clearableCodeSet));
-        }
-    };
-
-    ScriptExecutableSpaceAndSet directEvalExecutableSpace;
-    ScriptExecutableSpaceAndSet functionExecutableSpace;
-    ScriptExecutableSpaceAndSet indirectEvalExecutableSpace;
-    ScriptExecutableSpaceAndSet moduleProgramExecutableSpace;
-    ScriptExecutableSpaceAndSet programExecutableSpace;
+    DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(directEvalExecutableSpace)
+    DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(indirectEvalExecutableSpace)
+    DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(moduleProgramExecutableSpace)
+    SpaceAndSet functionExecutableSpace;
+    SpaceAndSet programExecutableSpace;
 
     template<typename Func>
     void forEachScriptExecutableSpace(const Func& func)
     {
-        func(directEvalExecutableSpace);
+        if (m_directEvalExecutableSpace)
+            func(*m_directEvalExecutableSpace);
         func(functionExecutableSpace);
-        func(indirectEvalExecutableSpace);
-        func(moduleProgramExecutableSpace);
+        if (m_indirectEvalExecutableSpace)
+            func(*m_indirectEvalExecutableSpace);
+        if (m_moduleProgramExecutableSpace)
+            func(*m_moduleProgramExecutableSpace);
         func(programExecutableSpace);
     }
 
-    struct UnlinkedFunctionExecutableSpaceAndSet {
-        IsoSubspace space;
-        IsoCellSet clearableCodeSet;
+    SpaceAndSet unlinkedFunctionExecutableSpace;
 
-        template<typename... Arguments>
-        UnlinkedFunctionExecutableSpaceAndSet(Arguments&&... arguments)
-            : space(std::forward<Arguments>(arguments)...)
-            , clearableCodeSet(space)
-        { }
-        
-        static IsoCellSet& clearableCodeSetFor(Subspace& space)
-        {
-            return *bitwise_cast<IsoCellSet*>(
-                bitwise_cast<char*>(&space) -
-                OBJECT_OFFSETOF(UnlinkedFunctionExecutableSpaceAndSet, space) +
-                OBJECT_OFFSETOF(UnlinkedFunctionExecutableSpaceAndSet, clearableCodeSet));
-        }
-    };
-
-    UnlinkedFunctionExecutableSpaceAndSet unlinkedFunctionExecutableSpace;
+#undef DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER
 
     VMType vmType;
     ClientData* clientData;
@@ -548,8 +525,6 @@ public:
     Strong<Structure> unlinkedFunctionCodeBlockStructure;
     Strong<Structure> unlinkedModuleProgramCodeBlockStructure;
     Strong<Structure> propertyTableStructure;
-    Strong<Structure> inferredTypeStructure;
-    Strong<Structure> inferredTypeTableStructure;
     Strong<Structure> inferredValueStructure;
     Strong<Structure> functionRareDataStructure;
     Strong<Structure> exceptionStructure;
@@ -692,6 +667,10 @@ public:
     Exception* lastException() const { return m_lastException; }
     JSCell** addressOfLastException() { return reinterpret_cast<JSCell**>(&m_lastException); }
 
+    // This should only be used for test or assertion code that wants to inspect
+    // the pending exception without interfering with Throw/CatchScopes.
+    Exception* exceptionForInspection() const { return m_exception; }
+
     void setFailNextNewCodeBlock() { m_failNextNewCodeBlock = true; }
     bool getAndClearFailNextNewCodeBlock()
     {
@@ -855,6 +834,7 @@ public:
 
     void queueMicrotask(JSGlobalObject&, Ref<Microtask>&&);
     JS_EXPORT_PRIVATE void drainMicrotasks();
+    ALWAYS_INLINE void setOnEachMicrotaskTick(WTF::Function<void(VM&)>&& func) { m_onEachMicrotaskTick = WTFMove(func); }
     void setGlobalConstRedeclarationShouldThrow(bool globalConstRedeclarationThrow) { m_globalConstRedeclarationShouldThrow = globalConstRedeclarationThrow; }
     ALWAYS_INLINE bool globalConstRedeclarationShouldThrow() const { return m_globalConstRedeclarationShouldThrow; }
 
@@ -863,12 +843,13 @@ public:
 
     BytecodeIntrinsicRegistry& bytecodeIntrinsicRegistry() { return *m_bytecodeIntrinsicRegistry; }
     
-    ShadowChicken& shadowChicken() { return *m_shadowChicken; }
+    ShadowChicken* shadowChicken() { return m_shadowChicken.get(); }
+    void ensureShadowChicken();
     
     template<typename Func>
     void logEvent(CodeBlock*, const char* summary, const Func& func);
 
-    std::optional<RefPtr<Thread>> ownerThread() const { return m_apiLock->ownerThread(); }
+    Optional<RefPtr<Thread>> ownerThread() const { return m_apiLock->ownerThread(); }
 
     VMTraps& traps() { return m_traps; }
 
@@ -893,6 +874,19 @@ public:
     JS_EXPORT_PRIVATE void setRunLoop(CFRunLoopRef);
 #endif // USE(CF)
 
+    class DeferExceptionScope {
+    public:
+        DeferExceptionScope(VM& vm)
+            : m_savedException(vm.m_exception, nullptr)
+            , m_savedLastException(vm.m_lastException, nullptr)
+        {
+        }
+
+    private:
+        SetForScope<Exception*> m_savedException;
+        SetForScope<Exception*> m_savedLastException;
+    };
+
 private:
     friend class LLIntOffsetsExtractor;
 
@@ -1001,6 +995,8 @@ private:
     std::unique_ptr<ShadowChicken> m_shadowChicken;
     std::unique_ptr<BytecodeIntrinsicRegistry> m_bytecodeIntrinsicRegistry;
 
+    WTF::Function<void(VM&)> m_onEachMicrotaskTick;
+
 #if ENABLE(JIT)
 #if !ASSERT_DISABLED
     JS_EXPORT_PRIVATE static bool s_canUseJITIsSet;