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