/ API / JSCallbackObject.h
JSCallbackObject.h
  1  /*
  2   * Copyright (C) 2006-2020 Apple Inc. All rights reserved.
  3   * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
  4   *
  5   * Redistribution and use in source and binary forms, with or without
  6   * modification, are permitted provided that the following conditions
  7   * are met:
  8   * 1. Redistributions of source code must retain the above copyright
  9   *    notice, this list of conditions and the following disclaimer.
 10   * 2. Redistributions in binary form must reproduce the above copyright
 11   *    notice, this list of conditions and the following disclaimer in the
 12   *    documentation and/or other materials provided with the distribution.
 13   *
 14   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 15   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 16   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 17   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 18   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 19   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 20   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 21   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 22   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 23   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 24   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 25   */
 26  
 27  #ifndef JSCallbackObject_h
 28  #define JSCallbackObject_h
 29  
 30  #include "JSObjectRef.h"
 31  #include "JSValueRef.h"
 32  #include "JSObject.h"
 33  
 34  namespace JSC {
 35  
 36  struct JSCallbackObjectData {
 37      WTF_MAKE_FAST_ALLOCATED;
 38  public:
 39      JSCallbackObjectData(void* privateData, JSClassRef jsClass)
 40          : privateData(privateData)
 41          , jsClass(jsClass)
 42      {
 43          JSClassRetain(jsClass);
 44      }
 45      
 46      ~JSCallbackObjectData()
 47      {
 48          JSClassRelease(jsClass);
 49      }
 50      
 51      JSValue getPrivateProperty(const Identifier& propertyName) const
 52      {
 53          if (!m_privateProperties)
 54              return JSValue();
 55          return m_privateProperties->getPrivateProperty(propertyName);
 56      }
 57      
 58      void setPrivateProperty(VM& vm, JSCell* owner, const Identifier& propertyName, JSValue value)
 59      {
 60          if (!m_privateProperties)
 61              m_privateProperties = makeUnique<JSPrivatePropertyMap>();
 62          m_privateProperties->setPrivateProperty(vm, owner, propertyName, value);
 63      }
 64      
 65      void deletePrivateProperty(const Identifier& propertyName)
 66      {
 67          if (!m_privateProperties)
 68              return;
 69          m_privateProperties->deletePrivateProperty(propertyName);
 70      }
 71  
 72      void visitChildren(SlotVisitor& visitor)
 73      {
 74          JSPrivatePropertyMap* properties = m_privateProperties.get();
 75          if (!properties)
 76              return;
 77          properties->visitChildren(visitor);
 78      }
 79  
 80      void* privateData;
 81      JSClassRef jsClass;
 82      struct JSPrivatePropertyMap {
 83          WTF_MAKE_FAST_ALLOCATED;
 84      public:
 85          JSValue getPrivateProperty(const Identifier& propertyName) const
 86          {
 87              PrivatePropertyMap::const_iterator location = m_propertyMap.find(propertyName.impl());
 88              if (location == m_propertyMap.end())
 89                  return JSValue();
 90              return location->value.get();
 91          }
 92          
 93          void setPrivateProperty(VM& vm, JSCell* owner, const Identifier& propertyName, JSValue value)
 94          {
 95              LockHolder locker(m_lock);
 96              WriteBarrier<Unknown> empty;
 97              m_propertyMap.add(propertyName.impl(), empty).iterator->value.set(vm, owner, value);
 98          }
 99          
100          void deletePrivateProperty(const Identifier& propertyName)
101          {
102              LockHolder locker(m_lock);
103              m_propertyMap.remove(propertyName.impl());
104          }
105  
106          void visitChildren(SlotVisitor& visitor)
107          {
108              LockHolder locker(m_lock);
109              for (auto& pair : m_propertyMap) {
110                  if (pair.value)
111                      visitor.append(pair.value);
112              }
113          }
114  
115      private:
116          typedef HashMap<RefPtr<UniquedStringImpl>, WriteBarrier<Unknown>, IdentifierRepHash> PrivatePropertyMap;
117          PrivatePropertyMap m_propertyMap;
118          Lock m_lock;
119      };
120      std::unique_ptr<JSPrivatePropertyMap> m_privateProperties;
121  };
122  
123      
124  template <class Parent>
125  class JSCallbackObject final : public Parent {
126  public:
127      using Base = Parent;
128      static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | ProhibitsPropertyCaching | GetOwnPropertySlotMayBeWrongAboutDontEnum;
129      static_assert(!(StructureFlags & ImplementsDefaultHasInstance), "using customHasInstance");
130  
131      ~JSCallbackObject();
132  
133      static JSCallbackObject* create(JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, void* data)
134      {
135          VM& vm = getVM(globalObject);
136          ASSERT_UNUSED(globalObject, !structure->globalObject() || structure->globalObject() == globalObject);
137          JSCallbackObject* callbackObject = new (NotNull, allocateCell<JSCallbackObject>(vm.heap)) JSCallbackObject(globalObject, structure, classRef, data);
138          callbackObject->finishCreation(globalObject);
139          return callbackObject;
140      }
141      static JSCallbackObject<Parent>* create(VM&, JSClassRef, Structure*);
142  
143      static const bool needsDestruction;
144      static void destroy(JSCell* cell)
145      {
146          static_cast<JSCallbackObject*>(cell)->JSCallbackObject::~JSCallbackObject();
147      }
148  
149      template<typename CellType, SubspaceAccess mode>
150      static IsoSubspace* subspaceFor(VM& vm)
151      {
152          return subspaceForImpl(vm, mode);
153      }
154  
155      void setPrivate(void* data);
156      void* getPrivate();
157  
158      // FIXME: We should fix the warnings for extern-template in JSObject template classes: https://bugs.webkit.org/show_bug.cgi?id=161979
159      IGNORE_CLANG_WARNINGS_BEGIN("undefined-var-template")
160      DECLARE_INFO;
161      IGNORE_CLANG_WARNINGS_END
162  
163      JSClassRef classRef() const { return m_callbackObjectData->jsClass; }
164      bool inherits(JSClassRef) const;
165  
166      static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
167      
168      JSValue getPrivateProperty(const Identifier& propertyName) const
169      {
170          return m_callbackObjectData->getPrivateProperty(propertyName);
171      }
172      
173      void setPrivateProperty(VM& vm, const Identifier& propertyName, JSValue value)
174      {
175          m_callbackObjectData->setPrivateProperty(vm, this, propertyName, value);
176      }
177      
178      void deletePrivateProperty(const Identifier& propertyName)
179      {
180          m_callbackObjectData->deletePrivateProperty(propertyName);
181      }
182  
183      using Parent::methodTable;
184  
185      static EncodedJSValue callImpl(JSGlobalObject*, CallFrame*);
186      static EncodedJSValue constructImpl(JSGlobalObject*, CallFrame*);
187      static EncodedJSValue staticFunctionGetterImpl(JSGlobalObject*, EncodedJSValue, PropertyName);
188      static EncodedJSValue callbackGetterImpl(JSGlobalObject*, EncodedJSValue, PropertyName);
189     
190  private:
191      JSCallbackObject(JSGlobalObject*, Structure*, JSClassRef, void* data);
192      JSCallbackObject(VM&, JSClassRef, Structure*);
193  
194      void finishCreation(JSGlobalObject*);
195      void finishCreation(VM&);
196  
197      static IsoSubspace* subspaceForImpl(VM&, SubspaceAccess);
198      static String className(const JSObject*, VM&);
199      static String toStringName(const JSObject*, JSGlobalObject*);
200  
201      static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
202  
203      static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
204      static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&);
205      
206      static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
207      static bool putByIndex(JSCell*, JSGlobalObject*, unsigned, JSValue, bool shouldThrow);
208  
209      static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
210      static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned);
211  
212      static bool customHasInstance(JSObject*, JSGlobalObject*, JSValue);
213  
214      static void getOwnSpecialPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, DontEnumPropertiesMode);
215  
216      static CallData getConstructData(JSCell*);
217      static CallData getCallData(JSCell*);
218  
219      static void visitChildren(JSCell* cell, SlotVisitor& visitor)
220      {
221          JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell);
222          ASSERT_GC_OBJECT_INHERITS((static_cast<Parent*>(thisObject)), JSCallbackObject<Parent>::info());
223          Parent::visitChildren(thisObject, visitor);
224          thisObject->m_callbackObjectData->visitChildren(visitor);
225      }
226  
227      void init(JSGlobalObject*);
228   
229      static JSCallbackObject* asCallbackObject(JSValue);
230      static JSCallbackObject* asCallbackObject(EncodedJSValue);
231  
232      using RawNativeFunction = EncodedJSValue(JSC_HOST_CALL_ATTRIBUTES*)(JSGlobalObject*, CallFrame*);
233  
234      static RawNativeFunction getCallFunction();
235      static RawNativeFunction getConstructFunction();
236  
237      using GetValueFunc = EncodedJSValue(JIT_OPERATION_ATTRIBUTES*)(JSGlobalObject*, EncodedJSValue, PropertyName);
238  
239      static GetValueFunc getStaticFunctionGetter();
240      static GetValueFunc getCallbackGetter();
241   
242      JSValue getStaticValue(JSGlobalObject*, PropertyName);
243  
244      std::unique_ptr<JSCallbackObjectData> m_callbackObjectData;
245      const ClassInfo* m_classInfo { nullptr };
246  };
247  
248  } // namespace JSC
249  
250  // include the actual template class implementation
251  #include "JSCallbackObjectFunctions.h"
252  
253  #endif // JSCallbackObject_h