BytecodeGenerator needs to be re-entrant to support miranda functions
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Mar 2015 18:19:43 +0000 (18:19 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Mar 2015 18:19:43 +0000 (18:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142627

Reviewed by Filip Pizlo.

Made CodeCache::getGlobalCodeBlock and CodeCache::getFunctionExecutableFromGlobalCode re-entrant
by not keeping AddResult while invoking BytecodeGenerator::generate.

This is needed to support Miranda functions since they need to be lazily initialized.

* runtime/CodeCache.cpp:
(JSC::CodeCache::getGlobalCodeBlock):
(JSC::CodeCache::getFunctionExecutableFromGlobalCode):
* runtime/CodeCache.h:
(JSC::CodeCacheMap::findCacheAndUpdateAge): Extracted from add.
(JSC::CodeCacheMap::addCache): Extracted from add.
(JSC::CodeCacheMap::add): Deleted.

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/CodeCache.cpp
Source/JavaScriptCore/runtime/CodeCache.h

index 3eec3629a388d6e35a6b0d7bc6859a497d75387d..ac834702fc81590cd38015b5f3dd07c9497b73b3 100644 (file)
@@ -1,3 +1,23 @@
+2015-03-13  Ryosuke Niwa  <rniwa@webkit.org>
+
+        BytecodeGenerator needs to be re-entrant to support miranda functions
+        https://bugs.webkit.org/show_bug.cgi?id=142627
+
+        Reviewed by Filip Pizlo.
+
+        Made CodeCache::getGlobalCodeBlock and CodeCache::getFunctionExecutableFromGlobalCode re-entrant
+        by not keeping AddResult while invoking BytecodeGenerator::generate.
+
+        This is needed to support Miranda functions since they need to be lazily initialized.
+
+        * runtime/CodeCache.cpp:
+        (JSC::CodeCache::getGlobalCodeBlock):
+        (JSC::CodeCache::getFunctionExecutableFromGlobalCode):
+        * runtime/CodeCache.h:
+        (JSC::CodeCacheMap::findCacheAndUpdateAge): Extracted from add.
+        (JSC::CodeCacheMap::addCache): Extracted from add.
+        (JSC::CodeCacheMap::add): Deleted.
+
 2015-03-13  Mark Lam  <mark.lam@apple.com>
 
         Introduce WTF::Atomic to wrap std::atomic for a friendlier CAS.
 2015-03-13  Mark Lam  <mark.lam@apple.com>
 
         Introduce WTF::Atomic to wrap std::atomic for a friendlier CAS.
index 505231122dbae69b2f0b80fa2afb241134b7a249..6c626100431b98c313489de2390b43172b189e89 100644 (file)
@@ -78,10 +78,10 @@ template <class UnlinkedCodeBlockType, class ExecutableType>
 UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
 {
     SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictness);
 UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
 {
     SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictness);
-    CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue());
+    SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key);
     bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff && !vm.typeProfiler() && !vm.controlFlowProfiler();
     bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff && !vm.typeProfiler() && !vm.controlFlowProfiler();
-    if (!addResult.isNewEntry && canCache) {
-        UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast<UnlinkedCodeBlockType*>(addResult.iterator->value.cell.get());
+    if (cache && canCache) {
+        UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast<UnlinkedCodeBlockType*>(cache->cell.get());
         unsigned firstLine = source.firstLine() + unlinkedCodeBlock->firstLine();
         unsigned lineCount = unlinkedCodeBlock->lineCount();
         unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn();
         unsigned firstLine = source.firstLine() + unlinkedCodeBlock->firstLine();
         unsigned lineCount = unlinkedCodeBlock->lineCount();
         unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn();
@@ -93,10 +93,9 @@ UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* exe
 
     typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
     std::unique_ptr<RootNode> rootNode = parse<RootNode>(&vm, source, 0, Identifier(), strictness, JSParseProgramCode, error);
 
     typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
     std::unique_ptr<RootNode> rootNode = parse<RootNode>(&vm, source, 0, Identifier(), strictness, JSParseProgramCode, error);
-    if (!rootNode) {
-        m_sourceCode.remove(addResult.iterator);
-        return 0;
-    }
+    if (!rootNode)
+        return nullptr;
+
     unsigned lineCount = rootNode->lastLine() - rootNode->lineNo();
     unsigned startColumn = rootNode->startColumn() + 1;
     bool endColumnIsOnStartLine = !lineCount;
     unsigned lineCount = rootNode->lastLine() - rootNode->lineNo();
     unsigned startColumn = rootNode->startColumn() + 1;
     bool endColumnIsOnStartLine = !lineCount;
@@ -109,17 +108,13 @@ UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* exe
 
     auto generator = std::make_unique<BytecodeGenerator>(vm, rootNode.get(), unlinkedCodeBlock, debuggerMode, profilerMode);
     error = generator->generate();
 
     auto generator = std::make_unique<BytecodeGenerator>(vm, rootNode.get(), unlinkedCodeBlock, debuggerMode, profilerMode);
     error = generator->generate();
-    if (error.isValid()) {
-        m_sourceCode.remove(addResult.iterator);
+    if (error.isValid())
         return nullptr;
         return nullptr;
-    }
 
 
-    if (!canCache) {
-        m_sourceCode.remove(addResult.iterator);
+    if (!canCache)
         return unlinkedCodeBlock;
         return unlinkedCodeBlock;
-    }
 
 
-    addResult.iterator->value = SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age());
+    m_sourceCode.addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age()));
     return unlinkedCodeBlock;
 }
 
     return unlinkedCodeBlock;
 }
 
@@ -136,15 +131,14 @@ UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* execu
 UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error)
 {
     SourceCodeKey key = SourceCodeKey(source, name.string(), SourceCodeKey::FunctionType, JSParseNormal);
 UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error)
 {
     SourceCodeKey key = SourceCodeKey(source, name.string(), SourceCodeKey::FunctionType, JSParseNormal);
-    CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue());
-    if (!addResult.isNewEntry)
-        return jsCast<UnlinkedFunctionExecutable*>(addResult.iterator->value.cell.get());
+    SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key);
+    if (cache)
+        return jsCast<UnlinkedFunctionExecutable*>(cache->cell.get());
 
     JSTextPosition positionBeforeLastNewline;
     std::unique_ptr<ProgramNode> program = parse<ProgramNode>(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error, &positionBeforeLastNewline);
     if (!program) {
         RELEASE_ASSERT(error.isValid());
 
     JSTextPosition positionBeforeLastNewline;
     std::unique_ptr<ProgramNode> program = parse<ProgramNode>(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error, &positionBeforeLastNewline);
     if (!program) {
         RELEASE_ASSERT(error.isValid());
-        m_sourceCode.remove(addResult.iterator);
         return nullptr;
     }
 
         return nullptr;
     }
 
@@ -165,7 +159,7 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& v
     UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body, UnlinkedNormalFunction);
     functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string()));
 
     UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body, UnlinkedNormalFunction);
     functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string()));
 
-    addResult.iterator->value = SourceCodeValue(vm, functionExecutable, m_sourceCode.age());
+    m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age()));
     return functionExecutable;
 }
 
     return functionExecutable;
 }
 
index fe07d19c69d44a48c0d020d58338a80e43aa6dd6..118af109d505da3f3c84bed3b8d2ee96862f0c66 100644 (file)
@@ -144,18 +144,15 @@ public:
     {
     }
 
     {
     }
 
-    AddResult add(const SourceCodeKey& key, const SourceCodeValue& value)
+    SourceCodeValue* findCacheAndUpdateAge(const SourceCodeKey& key)
     {
         prune();
 
     {
         prune();
 
-        AddResult addResult = m_map.add(key, value);
-        if (addResult.isNewEntry) {
-            m_size += key.length();
-            m_age += key.length();
-            return addResult;
-        }
+        iterator findResult = m_map.find(key);
+        if (findResult == m_map.end())
+            return nullptr;
 
 
-        int64_t age = m_age - addResult.iterator->value.age;
+        int64_t age = m_age - findResult->value.age;
         if (age > m_capacity) {
             // A requested object is older than the cache's capacity. We can
             // infer that requested objects are subject to high eviction probability,
         if (age > m_capacity) {
             // A requested object is older than the cache's capacity. We can
             // infer that requested objects are subject to high eviction probability,
@@ -170,7 +167,20 @@ public:
                 m_capacity = m_minCapacity;
         }
 
                 m_capacity = m_minCapacity;
         }
 
-        addResult.iterator->value.age = m_age;
+        findResult->value.age = m_age;
+        m_age += key.length();
+
+        return &findResult->value;
+    }
+
+    AddResult addCache(const SourceCodeKey& key, const SourceCodeValue& value)
+    {
+        prune();
+
+        AddResult addResult = m_map.add(key, value);
+        ASSERT(addResult.isNewEntry);
+
+        m_size += key.length();
         m_age += key.length();
         return addResult;
     }
         m_age += key.length();
         return addResult;
     }