Title: [282624] trunk/Source/_javascript_Core
Revision
282624
Author
[email protected]
Date
2021-09-16 18:04:59 -0700 (Thu, 16 Sep 2021)

Log Message

Don't throw an exception in the middle of linking a CodeBlock
https://bugs.webkit.org/show_bug.cgi?id=230367

Reviewed by Yusuke Suzuki.

It's cleaner, and probably more correct, to wait until we're done linking
the instruction stream before throwing any exceptions from CodeBlock::finishCreation.
This guarantees, for example, that all metadata structs are initialized.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::setConstantRegisters):
(JSC::CodeBlock::initializeTemplateObjects):
* bytecode/CodeBlock.h:
* runtime/JSScope.cpp:
(JSC::abstractAccess):
(JSC::JSScope::abstractResolve):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (282623 => 282624)


--- trunk/Source/_javascript_Core/ChangeLog	2021-09-17 00:53:50 UTC (rev 282623)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-09-17 01:04:59 UTC (rev 282624)
@@ -1,5 +1,25 @@
 2021-09-16  Saam Barati  <[email protected]>
 
+        Don't throw an exception in the middle of linking a CodeBlock
+        https://bugs.webkit.org/show_bug.cgi?id=230367
+
+        Reviewed by Yusuke Suzuki.
+
+        It's cleaner, and probably more correct, to wait until we're done linking
+        the instruction stream before throwing any exceptions from CodeBlock::finishCreation.
+        This guarantees, for example, that all metadata structs are initialized.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::finishCreation):
+        (JSC::CodeBlock::setConstantRegisters):
+        (JSC::CodeBlock::initializeTemplateObjects):
+        * bytecode/CodeBlock.h:
+        * runtime/JSScope.cpp:
+        (JSC::abstractAccess):
+        (JSC::JSScope::abstractResolve):
+
+2021-09-16  Saam Barati  <[email protected]>
+
         Move some profiling to UnlinkedCodeBlock
         https://bugs.webkit.org/show_bug.cgi?id=230078
         <rdar://problem/82947571>

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (282623 => 282624)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2021-09-17 00:53:50 UTC (rev 282623)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2021-09-17 01:04:59 UTC (rev 282624)
@@ -377,6 +377,8 @@
     Base::finishCreation(vm);
     finishCreationCommon(vm);
 
+    ASSERT(vm.heap.isDeferred());
+
     auto throwScope = DECLARE_THROW_SCOPE(vm);
 
     if (m_unlinkedCode->wasCompiledWithTypeProfilerOpcodes() || m_unlinkedCode->wasCompiledWithControlFlowProfilerOpcodes())
@@ -383,8 +385,10 @@
         vm.functionHasExecutedCache()->removeUnexecutedRange(ownerExecutable->sourceID(), ownerExecutable->typeProfilingStartOffset(vm), ownerExecutable->typeProfilingEndOffset(vm));
 
     ScriptExecutable* topLevelExecutable = ownerExecutable->topLevelExecutable();
-    setConstantRegisters(unlinkedCodeBlock->constantRegisters(), unlinkedCodeBlock->constantsSourceCodeRepresentation(), topLevelExecutable);
-    RETURN_IF_EXCEPTION(throwScope, false);
+    // We wait to initialize template objects until the end of finishCreation beecause it can
+    // throw. We rely on linking to put the CodeBlock into a coherent state, so we can't throw
+    // until we're all done linking.
+    Vector<unsigned> templateObjectIndices = setConstantRegisters(unlinkedCodeBlock->constantRegisters(), unlinkedCodeBlock->constantsSourceCodeRepresentation());
 
     // We already have the cloned symbol table for the module environment since we need to instantiate
     // the module environments before linking the code block. We replace the stored symbol table with the already cloned one.
@@ -435,7 +439,8 @@
     // Bookkeep the strongly referenced module environments.
     HashSet<JSModuleEnvironment*> stronglyReferencedModuleEnvironments;
 
-    auto link_profile = [&](const auto& /*instruction*/, auto /*bytecode*/, auto& /*metadata*/) {
+    auto link_profile = [&](const auto& /*instruction*/, auto /*bytecode*/, auto& metadata) {
+        static_assert(std::is_same_v<ValueProfile, decltype(metadata.m_profile)>);
         m_numberOfNonArgumentValueProfiles++;
     };
 
@@ -499,9 +504,9 @@
 
         LINK(OpGetById, profile)
 
-        LINK(OpEnumeratorNext, profile)
-        LINK(OpEnumeratorInByVal, profile)
-        LINK(OpEnumeratorHasOwnProperty, profile)
+        LINK(OpEnumeratorNext)
+        LINK(OpEnumeratorInByVal)
+        LINK(OpEnumeratorHasOwnProperty)
         LINK(OpEnumeratorGetByVal, profile)
 
         LINK(OpCall, profile)
@@ -563,7 +568,6 @@
             RELEASE_ASSERT(bytecode.m_resolveType != ResolvedClosureVar);
 
             ResolveOp op = JSScope::abstractResolve(m_globalObject.get(), bytecode.m_localScopeDepth, scope, ident, Get, bytecode.m_resolveType, InitializationMode::NotInitialization);
-            RETURN_IF_EXCEPTION(throwScope, false);
 
             metadata.m_resolveType = op.type;
             metadata.m_localScopeDepth = op.depth;
@@ -598,7 +602,6 @@
 
             const Identifier& ident = identifier(bytecode.m_var);
             ResolveOp op = JSScope::abstractResolve(m_globalObject.get(), bytecode.m_localScopeDepth, scope, ident, Get, bytecode.m_getPutInfo.resolveType(), InitializationMode::NotInitialization);
-            RETURN_IF_EXCEPTION(throwScope, false);
 
             metadata.m_getPutInfo = GetPutInfo(bytecode.m_getPutInfo.resolveMode(), op.type, bytecode.m_getPutInfo.initializationMode(), bytecode.m_getPutInfo.ecmaMode());
             if (op.type == ModuleVar)
@@ -632,7 +635,6 @@
             const Identifier& ident = identifier(bytecode.m_var);
             metadata.m_watchpointSet = nullptr;
             ResolveOp op = JSScope::abstractResolve(m_globalObject.get(), bytecode.m_symbolTableOrScopeDepth.scopeDepth(), scope, ident, Put, bytecode.m_getPutInfo.resolveType(), bytecode.m_getPutInfo.initializationMode());
-            RETURN_IF_EXCEPTION(throwScope, false);
 
             metadata.m_getPutInfo = GetPutInfo(bytecode.m_getPutInfo.resolveMode(), op.type, bytecode.m_getPutInfo.initializationMode(), bytecode.m_getPutInfo.ecmaMode());
             if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks || op.type == GlobalLexicalVar || op.type == GlobalLexicalVarWithVarInjectionChecks)
@@ -665,7 +667,6 @@
                 // Even though type profiling may be profiling either a Get or a Put, we can always claim a Get because
                 // we're abstractly "read"ing from a JSScope.
                 ResolveOp op = JSScope::abstractResolve(m_globalObject.get(), localScopeDepth, scope, ident, Get, bytecode.m_resolveType, InitializationMode::NotInitialization);
-                RETURN_IF_EXCEPTION(throwScope, false);
 
                 if (op.type == ClosureVar || op.type == ModuleVar)
                     symbolTable = op.lexicalEnvironment->symbolTable();
@@ -781,6 +782,9 @@
     if (m_metadata)
         vm.heap.reportExtraMemoryAllocated(m_metadata->sizeInBytes());
 
+    initializeTemplateObjects(topLevelExecutable, templateObjectIndices);
+    RETURN_IF_EXCEPTION(throwScope, false);
+
     return true;
 }
 
@@ -869,12 +873,13 @@
 #endif // ENABLE(JIT)
 }
 
-void CodeBlock::setConstantRegisters(const FixedVector<WriteBarrier<Unknown>>& constants, const FixedVector<SourceCodeRepresentation>& constantsSourceCodeRepresentation, ScriptExecutable* topLevelExecutable)
+Vector<unsigned> CodeBlock::setConstantRegisters(const FixedVector<WriteBarrier<Unknown>>& constants, const FixedVector<SourceCodeRepresentation>& constantsSourceCodeRepresentation)
 {
     VM& vm = *m_vm;
-    auto scope = DECLARE_THROW_SCOPE(vm);
     JSGlobalObject* globalObject = m_globalObject.get();
 
+    Vector<unsigned> templateObjectIndices;
+
     ASSERT(constants.size() == constantsSourceCodeRepresentation.size());
     size_t count = constants.size();
     {
@@ -905,11 +910,8 @@
                             clone->setRareDataCodeBlock(this);
 
                         constant = clone;
-                    } else if (auto* descriptor = jsDynamicCast<JSTemplateObjectDescriptor*>(vm, cell)) {
-                        auto* templateObject = topLevelExecutable->createTemplateObject(globalObject, descriptor);
-                        RETURN_IF_EXCEPTION(scope, void());
-                        constant = templateObject;
-                    }
+                    } else if (jsDynamicCast<JSTemplateObjectDescriptor*>(vm, cell))
+                        templateObjectIndices.append(i);
                 }
             }
             break;
@@ -916,8 +918,21 @@
         }
         m_constantRegisters[i].set(vm, this, constant);
     }
+
+    return templateObjectIndices;
 }
 
+void CodeBlock::initializeTemplateObjects(ScriptExecutable* topLevelExecutable, const Vector<unsigned>& templateObjectIndices)
+{
+    auto scope = DECLARE_THROW_SCOPE(vm());
+    for (unsigned i : templateObjectIndices) {
+        auto* descriptor = jsCast<JSTemplateObjectDescriptor*>(m_constantRegisters[i].get());
+        auto* templateObject = topLevelExecutable->createTemplateObject(globalObject(), descriptor);
+        RETURN_IF_EXCEPTION(scope, void());
+        m_constantRegisters[i].set(vm(), this, templateObject);
+    }
+}
+
 void CodeBlock::setAlternative(VM& vm, CodeBlock* alternative)
 {
     RELEASE_ASSERT(alternative);

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.h (282623 => 282624)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2021-09-17 00:53:50 UTC (rev 282623)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2021-09-17 01:04:59 UTC (rev 282624)
@@ -940,7 +940,8 @@
 
     void updateAllValueProfilePredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles);
 
-    void setConstantRegisters(const FixedVector<WriteBarrier<Unknown>>& constants, const FixedVector<SourceCodeRepresentation>& constantsSourceCodeRepresentation, ScriptExecutable* topLevelExecutable);
+    Vector<unsigned> setConstantRegisters(const FixedVector<WriteBarrier<Unknown>>& constants, const FixedVector<SourceCodeRepresentation>& constantsSourceCodeRepresentation);
+    void initializeTemplateObjects(ScriptExecutable* topLevelExecutable, const Vector<unsigned>& templateObjectIndices);
 
     void replaceConstant(VirtualRegister reg, JSValue value)
     {

Modified: trunk/Source/_javascript_Core/runtime/JSScope.cpp (282623 => 282624)


--- trunk/Source/_javascript_Core/runtime/JSScope.cpp	2021-09-17 00:53:50 UTC (rev 282623)
+++ trunk/Source/_javascript_Core/runtime/JSScope.cpp	2021-09-17 01:04:59 UTC (rev 282624)
@@ -27,10 +27,12 @@
 #include "JSScope.h"
 
 #include "AbstractModuleRecord.h"
+#include "DeferTermination.h"
 #include "JSCInlines.h"
 #include "JSLexicalEnvironment.h"
 #include "JSModuleEnvironment.h"
 #include "JSWithScope.h"
+#include "VMTrapsInlines.h"
 #include "VariableEnvironment.h"
 
 namespace JSC {
@@ -54,7 +56,7 @@
 static inline bool abstractAccess(JSGlobalObject* globalObject, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op, InitializationMode initializationMode)
 {
     VM& vm = globalObject->vm();
-    auto throwScope = DECLARE_THROW_SCOPE(vm);
+    DeferTerminationForAWhile deferScope(vm);
 
     if (scope->isJSLexicalEnvironment()) {
         JSLexicalEnvironment* lexicalEnvironment = jsCast<JSLexicalEnvironment*>(scope);
@@ -80,8 +82,9 @@
         if (scope->type() == ModuleEnvironmentType) {
             JSModuleEnvironment* moduleEnvironment = jsCast<JSModuleEnvironment*>(scope);
             AbstractModuleRecord* moduleRecord = moduleEnvironment->moduleRecord();
+            auto catchScope = DECLARE_CATCH_SCOPE(vm);
             AbstractModuleRecord::Resolution resolution = moduleRecord->resolveImport(globalObject, ident);
-            RETURN_IF_EXCEPTION(throwScope, false);
+            catchScope.releaseAssertNoException();
             if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) {
                 AbstractModuleRecord* importedRecord = resolution.moduleRecord;
                 JSModuleEnvironment* importedEnvironment = importedRecord->moduleEnvironment();
@@ -304,9 +307,6 @@
 
 ResolveOp JSScope::abstractResolve(JSGlobalObject* globalObject, size_t depthOffset, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, ResolveType unlinkedType, InitializationMode initializationMode)
 {
-    VM& vm = globalObject->vm();
-    auto throwScope = DECLARE_THROW_SCOPE(vm);
-
     ResolveOp op(Dynamic, 0, nullptr, nullptr, nullptr, 0);
     if (unlinkedType == Dynamic)
         return op;
@@ -315,7 +315,6 @@
     size_t depth = depthOffset;
     for (; scope; scope = scope->next()) {
         bool success = abstractAccess(globalObject, scope, ident, getOrPut, depth, needsVarInjectionChecks, op, initializationMode);
-        RETURN_IF_EXCEPTION(throwScope, ResolveOp(Dynamic, 0, nullptr, nullptr, nullptr, 0));
         if (success)
             break;
         ++depth;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to