/ runtime / FinalizationRegistryPrototype.cpp
FinalizationRegistryPrototype.cpp
  1  /*
  2   * Copyright (C) 2020 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 "FinalizationRegistryPrototype.h"
 28  
 29  #include "Error.h"
 30  #include "JSCInlines.h"
 31  #include "JSFinalizationRegistry.h"
 32  
 33  namespace JSC {
 34  
 35  const ClassInfo FinalizationRegistryPrototype::s_info = { "FinalizationRegistry", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(FinalizationRegistryPrototype) };
 36  
 37  static JSC_DECLARE_HOST_FUNCTION(protoFuncFinalizationRegistryRegister);
 38  static JSC_DECLARE_HOST_FUNCTION(protoFuncFinalizationRegistryUnregister);
 39  
 40  void FinalizationRegistryPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
 41  {
 42      Base::finishCreation(vm);
 43      ASSERT(inherits(vm, info()));
 44  
 45      // We can't make this a property name because it's a resevered word in C++...
 46      JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(Identifier::fromString(vm, "register"), protoFuncFinalizationRegistryRegister, static_cast<unsigned>(PropertyAttribute::DontEnum), 2);
 47      JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(Identifier::fromString(vm, "unregister"), protoFuncFinalizationRegistryUnregister, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
 48      JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
 49  }
 50  
 51  ALWAYS_INLINE static JSFinalizationRegistry* getFinalizationRegistry(VM& vm, JSGlobalObject* globalObject, JSValue value)
 52  {
 53      auto scope = DECLARE_THROW_SCOPE(vm);
 54  
 55      if (UNLIKELY(!value.isObject())) {
 56          throwTypeError(globalObject, scope, "Called FinalizationRegistry function on non-object"_s);
 57          return nullptr;
 58      }
 59  
 60      auto* group = jsDynamicCast<JSFinalizationRegistry*>(vm, asObject(value));
 61      if (LIKELY(group))
 62          return group;
 63  
 64      throwTypeError(globalObject, scope, "Called FinalizationRegistry function on a non-FinalizationRegistry object"_s);
 65      return nullptr;
 66  }
 67  
 68  JSC_DEFINE_HOST_FUNCTION(protoFuncFinalizationRegistryRegister, (JSGlobalObject* globalObject, CallFrame* callFrame))
 69  {
 70      VM& vm = globalObject->vm();
 71      auto scope = DECLARE_THROW_SCOPE(vm);
 72  
 73      auto* group = getFinalizationRegistry(vm, globalObject, callFrame->thisValue());
 74      RETURN_IF_EXCEPTION(scope, { });
 75  
 76      JSValue target = callFrame->argument(0);
 77      if (!target.isObject())
 78          return throwVMTypeError(globalObject, scope, "register requires an object as the target"_s);
 79  
 80      JSValue holdings = callFrame->argument(1);
 81      if (sameValue(globalObject, target, holdings))
 82          return throwVMTypeError(globalObject, scope, "register expects the target object and the holdings parameter are not the same. Otherwise, the target can never be collected"_s);
 83  
 84      JSValue unregisterToken = callFrame->argument(2);
 85      if (!unregisterToken.isUndefined() && !unregisterToken.isObject())
 86          return throwVMTypeError(globalObject, scope, "register requires an object as the unregistration token"_s);
 87  
 88      group->registerTarget(vm, target.getObject(), holdings, unregisterToken);
 89      return encodedJSUndefined();
 90  }
 91  
 92  JSC_DEFINE_HOST_FUNCTION(protoFuncFinalizationRegistryUnregister, (JSGlobalObject* globalObject, CallFrame* callFrame))
 93  {
 94      VM& vm = globalObject->vm();
 95      auto scope = DECLARE_THROW_SCOPE(vm);
 96  
 97      auto* group = getFinalizationRegistry(vm, globalObject, callFrame->thisValue());
 98      RETURN_IF_EXCEPTION(scope, { });
 99  
100      if (auto* token = jsDynamicCast<JSObject*>(vm, callFrame->argument(0))) {
101          bool result = group->unregister(vm, token);
102          return JSValue::encode(jsBoolean(result));
103      }
104  
105      return throwVMTypeError(globalObject, scope, "unregister requires an object is the unregistration token"_s);
106  }
107  
108  }
109