[JSC] Add LazyClassStructure::getInitializedOnMainThread
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Feb 2019 22:58:46 +0000 (22:58 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Feb 2019 22:58:46 +0000 (22:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194784
<rdar://problem/48154820>

Reviewed by Mark Lam.

JSTests:

* stress/lazy-initialization-done-a-priori-if-jit-enabled.js: Added.
(getProperties):
(getRandomProperty):
(i.catch):

Source/JavaScriptCore:

LazyClassStructure::get and LazyProperty::get functions do not allow compiler threads to call them. But for booleanPrototype, numberPrototype and symbolPrototype cases,
we would like to call them from compiler threads. We eagerly initialize them if VM::canUseJIT() is true, so that compiler threads can safely call LazyClassStructure::get
and LazyProperty::get for booleanPrototype, numberPrototype and symbolPrototype. But still assertion hits because the assertion requires that these functions need to be
called in non compiler threads. Calling `getConcurrently()` is not possible since symbolPrototype() function is called from both the main thread and compiler threads,
and we would like to lazily initialize SymbolPrototype object if it is called from the main thread, which can happen with non-JIT configuration.

This patch adds `getInitializedOnMainThread()`. Compiler threads can call it only when we know that the value is already initialized on the main thread. The main thread
can call it at anytime and this function lazily initializes the value. This is useful to make some of prototypes lazy with non-JIT configuration: With non-JIT configuration,
this function is always called from the main thread and it initializes the value lazily. Non-JIT configuration does not care about compiler threads since they do not exist.
With JIT configuration, we eagerly initialize them in JSGlobalObject::init so that `getInitializedOnMainThread()` always succeeds.

Basically, `getInitializedOnMainThread()` is `get` with different assertion location: While `get` always crashes if it is called from compiler threads, `getInitializedOnMainThread()`
crashes only when actual initialization happens on compiler threads. We do not merge them since `get` is still useful to find accidental initialization from compiler threads.

* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::booleanPrototype const):
(JSC::JSGlobalObject::numberPrototype const):
(JSC::JSGlobalObject::symbolPrototype const):
* runtime/LazyClassStructure.h:
(JSC::LazyClassStructure::getInitializedOnMainThread const):
(JSC::LazyClassStructure::prototypeInitializedOnMainThread const):
(JSC::LazyClassStructure::constructorInitializedOnMainThread const):
* runtime/LazyProperty.h:
(JSC::LazyProperty::get const):
(JSC::LazyProperty::getInitializedOnMainThread const):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@241741 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/stress/lazy-initialization-done-a-priori-if-jit-enabled.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/LazyClassStructure.h
Source/JavaScriptCore/runtime/LazyProperty.h

index b073979..40e6e8d 100644 (file)
@@ -1,3 +1,16 @@
+2019-02-18  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Add LazyClassStructure::getInitializedOnMainThread
+        https://bugs.webkit.org/show_bug.cgi?id=194784
+        <rdar://problem/48154820>
+
+        Reviewed by Mark Lam.
+
+        * stress/lazy-initialization-done-a-priori-if-jit-enabled.js: Added.
+        (getProperties):
+        (getRandomProperty):
+        (i.catch):
+
 2019-02-18  Dominik Infuehr  <dinfuehr@igalia.com>
 
         [ARM] Test gardening: Test running out of executable memory
diff --git a/JSTests/stress/lazy-initialization-done-a-priori-if-jit-enabled.js b/JSTests/stress/lazy-initialization-done-a-priori-if-jit-enabled.js
new file mode 100644 (file)
index 0000000..ddba417
--- /dev/null
@@ -0,0 +1,14 @@
+function getProperties(obj) {
+    let proto = Object.getPrototypeOf(obj);
+}
+function getRandomProperty(obj) {
+    let properties = getProperties(obj);
+}
+var number = 981428;
+getRandomProperty(number);
+for (var i = 0; i < 100000; ++i) {
+    try {
+        undef, void false;
+    } catch (e) {
+    }
+}
index 74065de..0f05acb 100644 (file)
@@ -1,3 +1,37 @@
+2019-02-18  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Add LazyClassStructure::getInitializedOnMainThread
+        https://bugs.webkit.org/show_bug.cgi?id=194784
+        <rdar://problem/48154820>
+
+        Reviewed by Mark Lam.
+
+        LazyClassStructure::get and LazyProperty::get functions do not allow compiler threads to call them. But for booleanPrototype, numberPrototype and symbolPrototype cases,
+        we would like to call them from compiler threads. We eagerly initialize them if VM::canUseJIT() is true, so that compiler threads can safely call LazyClassStructure::get
+        and LazyProperty::get for booleanPrototype, numberPrototype and symbolPrototype. But still assertion hits because the assertion requires that these functions need to be
+        called in non compiler threads. Calling `getConcurrently()` is not possible since symbolPrototype() function is called from both the main thread and compiler threads,
+        and we would like to lazily initialize SymbolPrototype object if it is called from the main thread, which can happen with non-JIT configuration.
+
+        This patch adds `getInitializedOnMainThread()`. Compiler threads can call it only when we know that the value is already initialized on the main thread. The main thread
+        can call it at anytime and this function lazily initializes the value. This is useful to make some of prototypes lazy with non-JIT configuration: With non-JIT configuration,
+        this function is always called from the main thread and it initializes the value lazily. Non-JIT configuration does not care about compiler threads since they do not exist.
+        With JIT configuration, we eagerly initialize them in JSGlobalObject::init so that `getInitializedOnMainThread()` always succeeds.
+
+        Basically, `getInitializedOnMainThread()` is `get` with different assertion location: While `get` always crashes if it is called from compiler threads, `getInitializedOnMainThread()`
+        crashes only when actual initialization happens on compiler threads. We do not merge them since `get` is still useful to find accidental initialization from compiler threads.
+
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::booleanPrototype const):
+        (JSC::JSGlobalObject::numberPrototype const):
+        (JSC::JSGlobalObject::symbolPrototype const):
+        * runtime/LazyClassStructure.h:
+        (JSC::LazyClassStructure::getInitializedOnMainThread const):
+        (JSC::LazyClassStructure::prototypeInitializedOnMainThread const):
+        (JSC::LazyClassStructure::constructorInitializedOnMainThread const):
+        * runtime/LazyProperty.h:
+        (JSC::LazyProperty::get const):
+        (JSC::LazyProperty::getInitializedOnMainThread const):
+
 2019-02-18  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Better categorize CPU usage per-thread / worker
index 06e0093..befbd22 100644 (file)
@@ -622,12 +622,12 @@ public:
     ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); }
     FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); }
     ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); }
-    JSObject* booleanPrototype() const { return m_booleanObjectStructure.prototype(this); }
+    JSObject* booleanPrototype() const { return m_booleanObjectStructure.prototypeInitializedOnMainThread(this); }
     StringPrototype* stringPrototype() const { return m_stringPrototype.get(); }
-    JSObject* numberPrototype() const { return m_numberObjectStructure.prototype(this); }
+    JSObject* numberPrototype() const { return m_numberObjectStructure.prototypeInitializedOnMainThread(this); }
     BigIntPrototype* bigIntPrototype() const { return m_bigIntPrototype.get(); }
     JSObject* datePrototype() const { return m_dateStructure.prototype(this); }
-    JSObject* symbolPrototype() const { return m_symbolObjectStructure.prototype(this); }
+    JSObject* symbolPrototype() const { return m_symbolObjectStructure.prototypeInitializedOnMainThread(this); }
     RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
     ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); }
     IteratorPrototype* iteratorPrototype() const { return m_iteratorPrototype.get(); }
index 66d44c9..164a998 100644 (file)
@@ -105,6 +105,23 @@ public:
     {
         return m_constructor.get();
     }
+
+    // Call this "InitializedOnMainThread" function if we would like to (1) get a value from a compiler thread which must be initialized on the main thread and (2) initialize a value if we are on the main thread.
+    Structure* getInitializedOnMainThread(const JSGlobalObject* global) const
+    {
+        return m_structure.getInitializedOnMainThread(global);
+    }
+
+    JSObject* prototypeInitializedOnMainThread(const JSGlobalObject* global) const
+    {
+        return getInitializedOnMainThread(global)->storedPrototypeObject();
+    }
+
+    JSObject* constructorInitializedOnMainThread(const JSGlobalObject* global) const
+    {
+        m_structure.getInitializedOnMainThread(global);
+        return m_constructor.get();
+    }
     
     void visit(SlotVisitor&);
     
index 169f202..ff0ac16 100644 (file)
@@ -79,11 +79,7 @@ public:
     ElementType* get(const OwnerType* owner) const
     {
         ASSERT(!isCompilationThread());
-        if (UNLIKELY(m_pointer & lazyTag)) {
-            FuncType func = *bitwise_cast<FuncType*>(m_pointer & ~(lazyTag | initializingTag));
-            return func(Initializer(const_cast<OwnerType*>(owner), *const_cast<LazyProperty*>(this)));
-        }
-        return bitwise_cast<ElementType*>(m_pointer);
+        return getInitializedOnMainThread(owner);
     }
     
     ElementType* getConcurrently() const
@@ -93,6 +89,16 @@ public:
             return nullptr;
         return bitwise_cast<ElementType*>(pointer);
     }
+
+    ElementType* getInitializedOnMainThread(const OwnerType* owner) const
+    {
+        if (UNLIKELY(m_pointer & lazyTag)) {
+            ASSERT(!isCompilationThread());
+            FuncType func = *bitwise_cast<FuncType*>(m_pointer & ~(lazyTag | initializingTag));
+            return func(Initializer(const_cast<OwnerType*>(owner), *const_cast<LazyProperty*>(this)));
+        }
+        return bitwise_cast<ElementType*>(m_pointer);
+    }
     
     void setMayBeNull(VM&, const OwnerType* owner, ElementType*);
     void set(VM&, const OwnerType* owner, ElementType*);