/ bytecode / CallVariant.cpp
CallVariant.cpp
  1  /*
  2   * Copyright (C) 2014-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 "CallVariant.h"
 28  
 29  #include "JSCInlines.h"
 30  #include <wtf/ListDump.h>
 31  
 32  namespace JSC {
 33  
 34  bool CallVariant::finalize(VM& vm)
 35  {
 36      if (m_callee && !vm.heap.isMarked(m_callee))
 37          return false;
 38      return true;
 39  }
 40  
 41  bool CallVariant::merge(const CallVariant& other)
 42  {
 43      if (*this == other)
 44          return true;
 45      if (executable() == other.executable()) {
 46          *this = despecifiedClosure();
 47          return true;
 48      }
 49      return false;
 50  }
 51  
 52  void CallVariant::filter(VM& vm, JSValue value)
 53  {
 54      if (!*this)
 55          return;
 56      
 57      if (!isClosureCall()) {
 58          if (nonExecutableCallee() != value)
 59              *this = CallVariant();
 60          return;
 61      }
 62      
 63      if (JSFunction* function = jsDynamicCast<JSFunction*>(vm, value)) {
 64          if (function->executable() == executable())
 65              *this = CallVariant(function);
 66          else
 67              *this = CallVariant();
 68          return;
 69      }
 70      
 71      *this = CallVariant();
 72  }
 73  
 74  void CallVariant::dump(PrintStream& out) const
 75  {
 76      if (!*this) {
 77          out.print("null");
 78          return;
 79      }
 80      
 81      if (InternalFunction* internalFunction = this->internalFunction()) {
 82          out.print("InternalFunction: ", JSValue(internalFunction));
 83          return;
 84      }
 85      
 86      if (JSFunction* function = this->function()) {
 87          out.print("(Function: ", JSValue(function), "; Executable: ", *executable(), ")");
 88          return;
 89      }
 90      
 91      if (ExecutableBase* executable = this->executable()) {
 92          out.print("(Executable: ", *executable, ")");
 93          return;
 94      }
 95  
 96      out.print("Non-executable callee: ", *nonExecutableCallee());
 97  }
 98  
 99  CallVariantList variantListWithVariant(const CallVariantList& list, CallVariant variantToAdd)
100  {
101      ASSERT(variantToAdd);
102      CallVariantList result;
103      for (CallVariant variant : list) {
104          ASSERT(variant);
105          if (!!variantToAdd) {
106              if (variant == variantToAdd)
107                  variantToAdd = CallVariant();
108              else if (variant.despecifiedClosure() == variantToAdd.despecifiedClosure()) {
109                  variant = variant.despecifiedClosure();
110                  variantToAdd = CallVariant();
111              }
112          }
113          result.append(variant);
114      }
115      if (!!variantToAdd)
116          result.append(variantToAdd);
117      
118      if (ASSERT_ENABLED) {
119          for (unsigned i = 0; i < result.size(); ++i) {
120              for (unsigned j = i + 1; j < result.size(); ++j) {
121                  if (result[i] != result[j])
122                      continue;
123                  
124                  dataLog("variantListWithVariant(", listDump(list), ", ", variantToAdd, ") failed: got duplicates in result: ", listDump(result), "\n");
125                  RELEASE_ASSERT_NOT_REACHED();
126              }
127          }
128      }
129      
130      return result;
131  }
132  
133  CallVariantList despecifiedVariantList(const CallVariantList& list)
134  {
135      CallVariantList result;
136      for (CallVariant variant : list)
137          result = variantListWithVariant(result, variant.despecifiedClosure());
138      return result;
139  }
140  
141  } // namespace JSC
142