We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / bytecode / GetByIdStatus.cpp
index 972d5de..b0946c4 100644 (file)
@@ -51,16 +51,6 @@ bool GetByIdStatus::appendVariant(const GetByIdVariant& variant)
     return appendICStatusVariant(m_variants, variant);
 }
 
-#if ENABLE(DFG_JIT)
-bool GetByIdStatus::hasExitSite(CodeBlock* profiledBlock, unsigned bytecodeIndex)
-{
-    UnlinkedCodeBlock* unlinkedCodeBlock = profiledBlock->unlinkedCodeBlock();
-    ConcurrentJSLocker locker(unlinkedCodeBlock->m_lock);
-    return unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache))
-        || unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadConstantCache));
-}
-#endif
-
 GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex, UniquedStringImpl* uid)
 {
     VM& vm = *profiledBlock->vm();
@@ -105,7 +95,7 @@ GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned
     }
 }
 
-GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid)
+GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, ICStatusMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid, ExitFlag didExit, CallLinkStatus::ExitSiteData callExitSiteData)
 {
     ConcurrentJSLocker locker(profiledBlock->m_lock);
 
@@ -113,12 +103,11 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& m
 
 #if ENABLE(DFG_JIT)
     result = computeForStubInfoWithoutExitSiteFeedback(
-        locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)), uid,
-        CallLinkStatus::computeExitSiteData(profiledBlock, bytecodeIndex));
+        locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)).stubInfo, uid,
+        callExitSiteData);
     
-    if (!result.takesSlowPath()
-        && hasExitSite(profiledBlock, bytecodeIndex))
-        return GetByIdStatus(result.makesCalls() ? MakesCalls : TakesSlowPath, true);
+    if (didExit)
+        return result.slowVersion();
 #else
     UNUSED_PARAM(map);
 #endif
@@ -136,8 +125,8 @@ GetByIdStatus GetByIdStatus::computeForStubInfo(const ConcurrentJSLocker& locker
         locker, profiledBlock, stubInfo, uid,
         CallLinkStatus::computeExitSiteData(profiledBlock, codeOrigin.bytecodeIndex));
 
-    if (!result.takesSlowPath() && GetByIdStatus::hasExitSite(profiledBlock, codeOrigin.bytecodeIndex))
-        return GetByIdStatus(result.makesCalls() ? GetByIdStatus::MakesCalls : GetByIdStatus::TakesSlowPath, true);
+    if (!result.takesSlowPath() && hasBadCacheExitSite(profiledBlock, codeOrigin.bytecodeIndex))
+        return result.slowVersion();
     return result;
 }
 #endif // ENABLE(DFG_JIT)
@@ -156,22 +145,9 @@ GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
     const ConcurrentJSLocker& locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, UniquedStringImpl* uid,
     CallLinkStatus::ExitSiteData callExitSiteData)
 {
-    if (!stubInfo || !stubInfo->everConsidered)
-        return GetByIdStatus(NoInformation);
-
-    PolymorphicAccess* list = 0;
-    State slowPathState = TakesSlowPath;
-    if (stubInfo->cacheType == CacheType::Stub) {
-        list = stubInfo->u.stub;
-        for (unsigned i = 0; i < list->size(); ++i) {
-            const AccessCase& access = list->at(i);
-            if (access.doesCalls())
-                slowPathState = MakesCalls;
-        }
-    }
-    
-    if (stubInfo->tookSlowPath)
-        return GetByIdStatus(slowPathState);
+    StubInfoSummary summary = StructureStubInfo::summary(stubInfo);
+    if (!isInlineable(summary))
+        return GetByIdStatus(summary);
     
     // Finally figure out if we can derive an access strategy.
     GetByIdStatus result;
@@ -184,14 +160,14 @@ GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
     case CacheType::GetByIdSelf: {
         Structure* structure = stubInfo->u.byIdSelf.baseObjectStructure.get();
         if (structure->takesSlowPathInDFGForImpureProperty())
-            return GetByIdStatus(slowPathState, true);
+            return GetByIdStatus(JSC::slowVersion(summary));
         unsigned attributes;
         GetByIdVariant variant;
         variant.m_offset = structure->getConcurrently(uid, attributes);
         if (!isValidOffset(variant.m_offset))
-            return GetByIdStatus(slowPathState, true);
+            return GetByIdStatus(JSC::slowVersion(summary));
         if (attributes & PropertyAttribute::CustomAccessor)
-            return GetByIdStatus(slowPathState, true);
+            return GetByIdStatus(JSC::slowVersion(summary));
         
         variant.m_structureSet.add(structure);
         bool didAppend = result.appendVariant(variant);
@@ -200,6 +176,7 @@ GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
     }
         
     case CacheType::Stub: {
+        PolymorphicAccess* list = stubInfo->u.stub;
         if (list->size() == 1) {
             const AccessCase& access = list->at(0);
             switch (access.type()) {
@@ -213,10 +190,10 @@ GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
         for (unsigned listIndex = 0; listIndex < list->size(); ++listIndex) {
             const AccessCase& access = list->at(listIndex);
             if (access.viaProxy())
-                return GetByIdStatus(slowPathState, true);
+                return GetByIdStatus(JSC::slowVersion(summary));
 
             if (access.usesPolyProto())
-                return GetByIdStatus(slowPathState, true);
+                return GetByIdStatus(JSC::slowVersion(summary));
             
             Structure* structure = access.structure();
             if (!structure) {
@@ -226,7 +203,7 @@ GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
                 // shouldn't have to use value profiling to discover something that the AccessCase
                 // could have told us. But, it works well enough. So, our only concern here is to not
                 // crash on null structure.
-                return GetByIdStatus(slowPathState, true);
+                return GetByIdStatus(JSC::slowVersion(summary));
             }
             
             ComplexGetStatus complexGetStatus = ComplexGetStatus::computeFor(
@@ -237,7 +214,7 @@ GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
                 continue;
                  
             case ComplexGetStatus::TakesSlowPath:
-                return GetByIdStatus(slowPathState, true);
+                return GetByIdStatus(JSC::slowVersion(summary));
                  
             case ComplexGetStatus::Inlineable: {
                 std::unique_ptr<CallLinkStatus> callLinkStatus;
@@ -267,14 +244,14 @@ GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
                     customAccessorGetter = access.as<GetterSetterAccessCase>().customAccessor();
                     domAttribute = access.as<GetterSetterAccessCase>().domAttribute();
                     if (!domAttribute)
-                        return GetByIdStatus(slowPathState, true);
+                        return GetByIdStatus(JSC::slowVersion(summary));
                     result.m_state = Custom;
                     break;
                 }
                 default: {
                     // FIXME: It would be totally sweet to support more of these at some point in the
                     // future. https://bugs.webkit.org/show_bug.cgi?id=133052
-                    return GetByIdStatus(slowPathState, true);
+                    return GetByIdStatus(JSC::slowVersion(summary));
                 } }
 
                 ASSERT((AccessCase::Miss == access.type()) == (access.offset() == invalidOffset));
@@ -286,16 +263,16 @@ GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
                     domAttribute);
 
                 if (!result.appendVariant(variant))
-                    return GetByIdStatus(slowPathState, true);
+                    return GetByIdStatus(JSC::slowVersion(summary));
 
                 if (domAttribute) {
                     // Give up when cutom accesses are not merged into one.
                     if (result.numVariants() != 1)
-                        return GetByIdStatus(slowPathState, true);
+                        return GetByIdStatus(JSC::slowVersion(summary));
                 } else {
                     // Give up when custom access and simple access are mixed.
                     if (result.m_state == Custom)
-                        return GetByIdStatus(slowPathState, true);
+                        return GetByIdStatus(JSC::slowVersion(summary));
                 }
                 break;
             } }
@@ -305,7 +282,7 @@ GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
     }
         
     default:
-        return GetByIdStatus(slowPathState, true);
+        return GetByIdStatus(JSC::slowVersion(summary));
     }
     
     RELEASE_ASSERT_NOT_REACHED();
@@ -314,40 +291,47 @@ GetByIdStatus GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback(
 #endif // ENABLE(JIT)
 
 GetByIdStatus GetByIdStatus::computeFor(
-    CodeBlock* profiledBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap,
-    StubInfoMap& dfgMap, CodeOrigin codeOrigin, UniquedStringImpl* uid)
+    CodeBlock* profiledBlock, ICStatusMap& baselineMap,
+    ICStatusContextStack& icContextStack, CodeOrigin codeOrigin, UniquedStringImpl* uid)
 {
-#if ENABLE(DFG_JIT)
-    if (dfgBlock) {
-        CallLinkStatus::ExitSiteData exitSiteData;
-        {
-            ConcurrentJSLocker locker(profiledBlock->m_lock);
-            exitSiteData = CallLinkStatus::computeExitSiteData(
-                profiledBlock, codeOrigin.bytecodeIndex);
-        }
-        
-        GetByIdStatus result;
-        {
-            ConcurrentJSLocker locker(dfgBlock->m_lock);
-            result = computeForStubInfoWithoutExitSiteFeedback(
-                locker, dfgBlock, dfgMap.get(codeOrigin), uid, exitSiteData);
-        }
-
-        if (result.takesSlowPath())
-            return result;
+    CallLinkStatus::ExitSiteData callExitSiteData =
+        CallLinkStatus::computeExitSiteData(profiledBlock, codeOrigin.bytecodeIndex);
+    ExitFlag didExit = hasBadCacheExitSite(profiledBlock, codeOrigin.bytecodeIndex);
     
-        if (hasExitSite(profiledBlock, codeOrigin.bytecodeIndex))
-            return GetByIdStatus(TakesSlowPath, true);
+    for (ICStatusContext* context : icContextStack) {
+        ICStatus status = context->get(codeOrigin);
         
-        if (result.isSet())
+        auto bless = [&] (const GetByIdStatus& result) -> GetByIdStatus {
+            if (!context->isInlined(codeOrigin)) {
+                // Merge with baseline result, which also happens to contain exit data for both
+                // inlined and not-inlined.
+                GetByIdStatus baselineResult = computeFor(
+                    profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid, didExit,
+                    callExitSiteData);
+                baselineResult.merge(result);
+                return baselineResult;
+            }
+            if (didExit.isSet(ExitFromInlined))
+                return result.slowVersion();
             return result;
+        };
+        
+        if (status.stubInfo) {
+            GetByIdStatus result;
+            {
+                ConcurrentJSLocker locker(context->optimizedCodeBlock->m_lock);
+                result = computeForStubInfoWithoutExitSiteFeedback(
+                    locker, context->optimizedCodeBlock, status.stubInfo, uid, callExitSiteData);
+            }
+            if (result.isSet())
+                return bless(result);
+        }
+        
+        if (status.getStatus)
+            return bless(*status.getStatus);
     }
-#else
-    UNUSED_PARAM(dfgBlock);
-    UNUSED_PARAM(dfgMap);
-#endif
-
-    return computeFor(profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid);
+    
+    return computeFor(profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid, didExit, callExitSiteData);
 }
 
 GetByIdStatus GetByIdStatus::computeFor(const StructureSet& set, UniquedStringImpl* uid)
@@ -414,6 +398,59 @@ bool GetByIdStatus::makesCalls() const
     return false;
 }
 
+GetByIdStatus GetByIdStatus::slowVersion() const
+{
+    return GetByIdStatus(makesCalls() ? MakesCalls : TakesSlowPath, wasSeenInJIT());
+}
+
+void GetByIdStatus::merge(const GetByIdStatus& other)
+{
+    if (other.m_state == NoInformation)
+        return;
+    
+    auto mergeSlow = [&] () {
+        *this = GetByIdStatus((makesCalls() || other.makesCalls()) ? MakesCalls : TakesSlowPath);
+    };
+    
+    switch (m_state) {
+    case NoInformation:
+        *this = other;
+        return;
+        
+    case Simple:
+    case Custom:
+        if (m_state != other.m_state)
+            return mergeSlow();
+        
+        for (const GetByIdVariant& otherVariant : other.m_variants) {
+            if (!appendVariant(otherVariant))
+                return mergeSlow();
+        }
+        return;
+        
+    case ModuleNamespace:
+        if (other.m_state != ModuleNamespace)
+            return mergeSlow();
+        
+        if (m_moduleNamespaceObject != other.m_moduleNamespaceObject)
+            return mergeSlow();
+        
+        if (m_moduleEnvironment != other.m_moduleEnvironment)
+            return mergeSlow();
+        
+        if (m_scopeOffset != other.m_scopeOffset)
+            return mergeSlow();
+        
+        return;
+        
+    case TakesSlowPath:
+    case MakesCalls:
+        return mergeSlow();
+    }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
 void GetByIdStatus::filter(const StructureSet& set)
 {
     if (m_state != Simple)
@@ -423,6 +460,25 @@ void GetByIdStatus::filter(const StructureSet& set)
         m_state = NoInformation;
 }
 
+void GetByIdStatus::markIfCheap(SlotVisitor& visitor)
+{
+    for (GetByIdVariant& variant : m_variants)
+        variant.markIfCheap(visitor);
+}
+
+bool GetByIdStatus::finalize()
+{
+    for (GetByIdVariant& variant : m_variants) {
+        if (!variant.finalize())
+            return false;
+    }
+    if (m_moduleNamespaceObject && !Heap::isMarked(m_moduleNamespaceObject))
+        return false;
+    if (m_moduleEnvironment && !Heap::isMarked(m_moduleEnvironment))
+        return false;
+    return true;
+}
+
 void GetByIdStatus::dump(PrintStream& out) const
 {
     out.print("(");