/ bytecode / InstanceOfStatus.cpp
InstanceOfStatus.cpp
  1  /*
  2   * Copyright (C) 2018 Apple Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without
  5   * modification, are permitted provided that the following conditions
  6   * are met:
  7   * 1. Redistributions of source code must retain the above copyright
  8   *    notice, this list of conditions and the following disclaimer.
  9   * 2. Redistributions in binary form must reproduce the above copyright
 10   *    notice, this list of conditions and the following disclaimer in the
 11   *    documentation and/or other materials provided with the distribution.
 12   *
 13   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 17   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 24   */
 25  
 26  #include "config.h"
 27  #include "InstanceOfStatus.h"
 28  
 29  #include "ICStatusUtils.h"
 30  #include "InstanceOfAccessCase.h"
 31  #include "JSCellInlines.h"
 32  #include "PolymorphicAccess.h"
 33  #include "StructureStubInfo.h"
 34  
 35  namespace JSC {
 36  
 37  void InstanceOfStatus::appendVariant(const InstanceOfVariant& variant)
 38  {
 39      appendICStatusVariant(m_variants, variant);
 40  }
 41  
 42  InstanceOfStatus InstanceOfStatus::computeFor(
 43      CodeBlock* codeBlock, ICStatusMap& infoMap, BytecodeIndex bytecodeIndex)
 44  {
 45      ConcurrentJSLocker locker(codeBlock->m_lock);
 46      
 47      InstanceOfStatus result;
 48  #if ENABLE(DFG_JIT)
 49      result = computeForStubInfo(locker, codeBlock->vm(), infoMap.get(CodeOrigin(bytecodeIndex)).stubInfo);
 50  
 51      if (!result.takesSlowPath()) {
 52          UnlinkedCodeBlock* unlinkedCodeBlock = codeBlock->unlinkedCodeBlock();
 53          ConcurrentJSLocker locker(unlinkedCodeBlock->m_lock);
 54          // We also check for BadType here in case this is "primitive instanceof Foo".
 55          if (unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache))
 56              || unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadConstantCache))
 57              || unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadType)))
 58              return TakesSlowPath;
 59      }
 60  #else
 61      UNUSED_PARAM(infoMap);
 62      UNUSED_PARAM(bytecodeIndex);
 63  #endif
 64      
 65      return result;
 66  }
 67  
 68  #if ENABLE(DFG_JIT)
 69  InstanceOfStatus InstanceOfStatus::computeForStubInfo(const ConcurrentJSLocker&, VM& vm, StructureStubInfo* stubInfo)
 70  {
 71      // FIXME: We wouldn't have to bail for nonCell if we taught MatchStructure how to handle non
 72      // cells. If we fixed that then we wouldn't be able to use summary();
 73      // https://bugs.webkit.org/show_bug.cgi?id=185784
 74      StubInfoSummary summary = StructureStubInfo::summary(vm, stubInfo);
 75      if (!isInlineable(summary))
 76          return InstanceOfStatus(summary);
 77      
 78      if (stubInfo->cacheType() != CacheType::Stub)
 79          return TakesSlowPath; // This is conservative. It could be that we have no information.
 80      
 81      PolymorphicAccess* list = stubInfo->u.stub;
 82      InstanceOfStatus result;
 83      for (unsigned listIndex = 0; listIndex < list->size(); ++listIndex) {
 84          const AccessCase& access = list->at(listIndex);
 85          
 86          if (access.type() == AccessCase::InstanceOfGeneric)
 87              return TakesSlowPath;
 88          
 89          if (!access.conditionSet().structuresEnsureValidity())
 90              return TakesSlowPath;
 91          
 92          result.appendVariant(InstanceOfVariant(
 93              access.structure(),
 94              access.conditionSet(),
 95              access.as<InstanceOfAccessCase>().prototype(),
 96              access.type() == AccessCase::InstanceOfHit));
 97      }
 98      
 99      return result;
100  }
101  #endif // ENABLE(DFG_JIT)
102  
103  JSObject* InstanceOfStatus::commonPrototype() const
104  {
105      JSObject* prototype = nullptr;
106      for (const InstanceOfVariant& variant : m_variants) {
107          if (!prototype) {
108              prototype = variant.prototype();
109              continue;
110          }
111          if (prototype != variant.prototype())
112              return nullptr;
113      }
114      return prototype;
115  }
116  
117  void InstanceOfStatus::filter(const StructureSet& structureSet)
118  {
119      if (m_state != Simple)
120          return;
121      filterICStatusVariants(m_variants, structureSet);
122      if (m_variants.isEmpty())
123          m_state = NoInformation;
124  }
125  
126  } // namespace JSC
127