[JSC] Do not use InferredValue in non-JIT configuration
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 31 Jan 2019 19:13:20 +0000 (19:13 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 31 Jan 2019 19:13:20 +0000 (19:13 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194084

Reviewed by Saam Barati.

InferredValue is not meaningful if our VM is non-JIT configuration. InferredValue is used to watch the instantiation of the  FunctionExecutable's
JSFunction and SymbolTable's JSScope to explore the chance of folding them into constants in DFG and FTL. If it is instantiated only once, we can
put a watchpoint and fold it into this constant. But if JIT is disabled, we do not need to care it.
Even in non-JIT configuration, we still use InferredValue for FunctionExecutable to determine whether the given FunctionExecutable is preferable
target for poly proto. If JSFunction for the FunctionExecutable is used as a constructor and instantiated more than once, poly proto Structure
seems appropriate for objects created by this JSFunction. But at that time, only thing we would like to know is that whether JSFunction for this
FunctionExecutable is instantiated multiple times. This does not require the full feature of InferredValue, WatchpointState is enough.
To summarize, since nobody uses InferredValue feature in non-JIT configuration, we should not create it.

* bytecode/ObjectAllocationProfileInlines.h:
(JSC::ObjectAllocationProfile::initializeProfile):
* runtime/FunctionExecutable.cpp:
(JSC::FunctionExecutable::finishCreation):
(JSC::FunctionExecutable::visitChildren):
* runtime/FunctionExecutable.h:
* runtime/InferredValue.cpp:
(JSC::InferredValue::create):
* runtime/JSAsyncFunction.cpp:
(JSC::JSAsyncFunction::create):
* runtime/JSAsyncGeneratorFunction.cpp:
(JSC::JSAsyncGeneratorFunction::create):
* runtime/JSFunction.cpp:
(JSC::JSFunction::create):
* runtime/JSFunctionInlines.h:
(JSC::JSFunction::createWithInvalidatedReallocationWatchpoint):
* runtime/JSGeneratorFunction.cpp:
(JSC::JSGeneratorFunction::create):
* runtime/JSSymbolTableObject.h:
(JSC::JSSymbolTableObject::setSymbolTable):
* runtime/SymbolTable.cpp:
(JSC::SymbolTable::finishCreation):
* runtime/VM.cpp:
(JSC::VM::VM):

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

13 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/ObjectAllocationProfileInlines.h
Source/JavaScriptCore/runtime/FunctionExecutable.cpp
Source/JavaScriptCore/runtime/FunctionExecutable.h
Source/JavaScriptCore/runtime/InferredValue.cpp
Source/JavaScriptCore/runtime/JSAsyncFunction.cpp
Source/JavaScriptCore/runtime/JSAsyncGeneratorFunction.cpp
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSFunctionInlines.h
Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp
Source/JavaScriptCore/runtime/JSSymbolTableObject.h
Source/JavaScriptCore/runtime/SymbolTable.cpp
Source/JavaScriptCore/runtime/VM.cpp

index 9596453..22d1bc8 100644 (file)
@@ -1,3 +1,44 @@
+2019-01-31  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Do not use InferredValue in non-JIT configuration
+        https://bugs.webkit.org/show_bug.cgi?id=194084
+
+        Reviewed by Saam Barati.
+
+        InferredValue is not meaningful if our VM is non-JIT configuration. InferredValue is used to watch the instantiation of the  FunctionExecutable's
+        JSFunction and SymbolTable's JSScope to explore the chance of folding them into constants in DFG and FTL. If it is instantiated only once, we can
+        put a watchpoint and fold it into this constant. But if JIT is disabled, we do not need to care it.
+        Even in non-JIT configuration, we still use InferredValue for FunctionExecutable to determine whether the given FunctionExecutable is preferable
+        target for poly proto. If JSFunction for the FunctionExecutable is used as a constructor and instantiated more than once, poly proto Structure
+        seems appropriate for objects created by this JSFunction. But at that time, only thing we would like to know is that whether JSFunction for this
+        FunctionExecutable is instantiated multiple times. This does not require the full feature of InferredValue, WatchpointState is enough.
+        To summarize, since nobody uses InferredValue feature in non-JIT configuration, we should not create it.
+
+        * bytecode/ObjectAllocationProfileInlines.h:
+        (JSC::ObjectAllocationProfile::initializeProfile):
+        * runtime/FunctionExecutable.cpp:
+        (JSC::FunctionExecutable::finishCreation):
+        (JSC::FunctionExecutable::visitChildren):
+        * runtime/FunctionExecutable.h:
+        * runtime/InferredValue.cpp:
+        (JSC::InferredValue::create):
+        * runtime/JSAsyncFunction.cpp:
+        (JSC::JSAsyncFunction::create):
+        * runtime/JSAsyncGeneratorFunction.cpp:
+        (JSC::JSAsyncGeneratorFunction::create):
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::create):
+        * runtime/JSFunctionInlines.h:
+        (JSC::JSFunction::createWithInvalidatedReallocationWatchpoint):
+        * runtime/JSGeneratorFunction.cpp:
+        (JSC::JSGeneratorFunction::create):
+        * runtime/JSSymbolTableObject.h:
+        (JSC::JSSymbolTableObject::setSymbolTable):
+        * runtime/SymbolTable.cpp:
+        (JSC::SymbolTable::finishCreation):
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+
 2019-01-31  Fujii Hironori  <Hironori.Fujii@sony.com>
 
         [CMake][JSC] Changing ud_opcode.py should trigger invoking ud_opcode.py
index 7021947..4999121 100644 (file)
@@ -65,7 +65,7 @@ ALWAYS_INLINE void ObjectAllocationProfile::initializeProfile(VM& vm, JSGlobalOb
         if (Options::forcePolyProto())
             isPolyProto = true;
         else
-            isPolyProto = executable->ensurePolyProtoWatchpoint().hasBeenInvalidated() && executable->singletonFunction()->hasBeenInvalidated();
+            isPolyProto = executable->ensurePolyProtoWatchpoint().hasBeenInvalidated() && executable->singletonFunctionHasBeenInvalidated();
     }
 
     unsigned inlineCapacity = 0;
index 79780db..f8065d0 100644 (file)
@@ -58,7 +58,10 @@ FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, Unlinke
 void FunctionExecutable::finishCreation(VM& vm)
 {
     Base::finishCreation(vm);
-    m_singletonFunction.set(vm, this, InferredValue::create(vm));
+    if (VM::canUseJIT())
+        m_singletonFunction.set(vm, this, InferredValue::create(vm));
+    else
+        m_singletonFunctionState = ClearWatchpoint;
 }
 
 void FunctionExecutable::destroy(JSCell* cell)
@@ -88,7 +91,8 @@ void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(thisObject->m_codeBlockForCall);
     visitor.append(thisObject->m_codeBlockForConstruct);
     visitor.append(thisObject->m_unlinkedExecutable);
-    visitor.append(thisObject->m_singletonFunction);
+    if (VM::canUseJIT())
+        visitor.append(thisObject->m_singletonFunction);
     visitor.append(thisObject->m_cachedPolyProtoStructure);
 }
 
index 1baaa85..5b14e2b 100644 (file)
@@ -183,7 +183,38 @@ public:
 
     DECLARE_INFO;
 
-    InferredValue* singletonFunction() { return m_singletonFunction.get(); }
+    InferredValue* singletonFunction()
+    {
+        if (VM::canUseJIT())
+            return m_singletonFunction.get();
+        return nullptr;
+    }
+
+    void notifyCreation(VM& vm, JSValue value, const char* reason)
+    {
+        if (VM::canUseJIT()) {
+            singletonFunction()->notifyWrite(vm, value, reason);
+            return;
+        }
+        switch (m_singletonFunctionState) {
+        case ClearWatchpoint:
+            m_singletonFunctionState = IsWatched;
+            return;
+        case IsWatched:
+            m_singletonFunctionState = IsInvalidated;
+            return;
+        case IsInvalidated:
+            return;
+        }
+    }
+
+    bool singletonFunctionHasBeenInvalidated()
+    {
+        if (VM::canUseJIT())
+            return singletonFunction()->hasBeenInvalidated();
+        return m_singletonFunctionState == IsInvalidated;
+    }
+
     // Cached poly proto structure for the result of constructing this executable.
     Structure* cachedPolyProtoStructure() { return m_cachedPolyProtoStructure.get(); }
     void setCachedPolyProtoStructure(VM& vm, Structure* structure) { m_cachedPolyProtoStructure.set(vm, this, structure); }
@@ -212,7 +243,10 @@ private:
     WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForCall;
     WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForConstruct;
     RefPtr<TypeSet> m_returnStatementTypeSet;
-    WriteBarrier<InferredValue> m_singletonFunction;
+    union {
+        WriteBarrier<InferredValue> m_singletonFunction;
+        WatchpointState m_singletonFunctionState;
+    };
     WriteBarrier<Structure> m_cachedPolyProtoStructure;
     Box<InlineWatchpointSet> m_polyProtoWatchpoint;
 };
index 69de0fb..989479e 100644 (file)
@@ -35,6 +35,7 @@ const ClassInfo InferredValue::s_info = { "InferredValue", nullptr, nullptr, nul
 
 InferredValue* InferredValue::create(VM& vm)
 {
+    ASSERT(VM::canUseJIT());
     InferredValue* result = new (NotNull, allocateCell<InferredValue>(vm.heap)) InferredValue(vm);
     result->finishCreation(vm);
     return result;
index c89d032..0792b21 100644 (file)
@@ -55,14 +55,14 @@ JSAsyncFunction* JSAsyncFunction::createImpl(VM& vm, FunctionExecutable* executa
 JSAsyncFunction* JSAsyncFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
 {
     JSAsyncFunction* asyncFunction = createImpl(vm, executable, scope, scope->globalObject(vm)->asyncFunctionStructure());
-    executable->singletonFunction()->notifyWrite(vm, asyncFunction, "Allocating an async function");
+    executable->notifyCreation(vm, asyncFunction, "Allocating an async function");
     return asyncFunction;
 }
 
 JSAsyncFunction* JSAsyncFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
 {
     JSAsyncFunction* asyncFunction = createImpl(vm, executable, scope, structure);
-    executable->singletonFunction()->notifyWrite(vm, asyncFunction, "Allocating an async function");
+    executable->notifyCreation(vm, asyncFunction, "Allocating an async function");
     return asyncFunction;
 }
 
index 87f9583..09fac05 100644 (file)
@@ -55,14 +55,14 @@ JSAsyncGeneratorFunction* JSAsyncGeneratorFunction::createImpl(VM& vm, FunctionE
 JSAsyncGeneratorFunction* JSAsyncGeneratorFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
 {
     JSAsyncGeneratorFunction* asyncGenerator = createImpl(vm, executable, scope, scope->globalObject(vm)->asyncGeneratorFunctionStructure());
-    executable->singletonFunction()->notifyWrite(vm, asyncGenerator, "Allocating an async generator");
+    executable->notifyCreation(vm, asyncGenerator, "Allocating an async generator");
     return asyncGenerator;
 }
 
 JSAsyncGeneratorFunction* JSAsyncGeneratorFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
 {
     JSAsyncGeneratorFunction* asyncGenerator = createImpl(vm, executable, scope, structure);
-    executable->singletonFunction()->notifyWrite(vm, asyncGenerator, "Allocating an async generator");
+    executable->notifyCreation(vm, asyncGenerator, "Allocating an async generator");
     return asyncGenerator;
 }
 
index 50568e8..83100c9 100644 (file)
@@ -84,7 +84,7 @@ JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope*
 JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
 {
     JSFunction* result = createImpl(vm, executable, scope, structure);
-    executable->singletonFunction()->notifyWrite(vm, result, "Allocating a function");
+    executable->notifyCreation(vm, result, "Allocating a function");
     return result;
 }
 
index 1f302da..189021a 100644 (file)
@@ -34,7 +34,7 @@ namespace JSC {
 inline JSFunction* JSFunction::createWithInvalidatedReallocationWatchpoint(
     VM& vm, FunctionExecutable* executable, JSScope* scope)
 {
-    ASSERT(executable->singletonFunction()->hasBeenInvalidated());
+    ASSERT(executable->singletonFunctionHasBeenInvalidated());
     return createImpl(vm, executable, scope, selectStructureForNewFuncExp(scope->globalObject(vm), executable));
 }
 
index 05b3604..5a11e01 100644 (file)
@@ -60,7 +60,7 @@ JSGeneratorFunction* JSGeneratorFunction::create(VM& vm, FunctionExecutable* exe
 JSGeneratorFunction* JSGeneratorFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
 {
     JSGeneratorFunction* generatorFunction = createImpl(vm, executable, scope, structure);
-    executable->singletonFunction()->notifyWrite(vm, generatorFunction, "Allocating a generator function");
+    executable->notifyCreation(vm, generatorFunction, "Allocating a generator function");
     return generatorFunction;
 }
 
index 0e8644e..5aa6d49 100644 (file)
@@ -66,7 +66,8 @@ protected:
     void setSymbolTable(VM& vm, SymbolTable* symbolTable)
     {
         ASSERT(!m_symbolTable);
-        symbolTable->singletonScope()->notifyWrite(vm, this, "Allocated a scope");
+        if (auto* singletonScope = symbolTable->singletonScope())
+            singletonScope->notifyWrite(vm, this, "Allocated a scope");
         m_symbolTable.set(vm, this, symbolTable);
     }
     
index 6b95a0e..25a2a73 100644 (file)
@@ -95,7 +95,8 @@ SymbolTable::~SymbolTable() { }
 void SymbolTable::finishCreation(VM& vm)
 {
     Base::finishCreation(vm);
-    m_singletonScope.set(vm, this, InferredValue::create(vm));
+    if (VM::canUseJIT())
+        m_singletonScope.set(vm, this, InferredValue::create(vm));
 }
 
 void SymbolTable::visitChildren(JSCell* thisCell, SlotVisitor& visitor)
index 9b954c2..d91b3b8 100644 (file)
@@ -409,7 +409,8 @@ VM::VM(VMType vmType, HeapType heapType)
     unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull()));
     unlinkedModuleProgramCodeBlockStructure.set(*this, UnlinkedModuleProgramCodeBlock::createStructure(*this, 0, jsNull()));
     propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull()));
-    inferredValueStructure.set(*this, InferredValue::createStructure(*this, 0, jsNull()));
+    if (VM::canUseJIT())
+        inferredValueStructure.set(*this, InferredValue::createStructure(*this, 0, jsNull()));
     functionRareDataStructure.set(*this, FunctionRareData::createStructure(*this, 0, jsNull()));
     exceptionStructure.set(*this, Exception::createStructure(*this, 0, jsNull()));
     promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull()));