/ runtime / SetConstructor.cpp
SetConstructor.cpp
  1  /*
  2   * Copyright (C) 2013-2017 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 "SetConstructor.h"
 28  
 29  #include "IteratorOperations.h"
 30  #include "JSCInlines.h"
 31  #include "JSSet.h"
 32  #include "SetPrototype.h"
 33  
 34  namespace JSC {
 35  
 36  const ClassInfo SetConstructor::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(SetConstructor) };
 37  
 38  void SetConstructor::finishCreation(VM& vm, SetPrototype* setPrototype, GetterSetter* speciesSymbol)
 39  {
 40      Base::finishCreation(vm, 0, vm.propertyNames->Set.string(), PropertyAdditionMode::WithoutStructureTransition);
 41      putDirectWithoutTransition(vm, vm.propertyNames->prototype, setPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
 42      putDirectNonIndexAccessorWithoutTransition(vm, vm.propertyNames->speciesSymbol, speciesSymbol, PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
 43  }
 44  
 45  static JSC_DECLARE_HOST_FUNCTION(callSet);
 46  static JSC_DECLARE_HOST_FUNCTION(constructSet);
 47  
 48  SetConstructor::SetConstructor(VM& vm, Structure* structure)
 49      : Base(vm, structure, callSet, constructSet)
 50  {
 51  }
 52  
 53  JSC_DEFINE_HOST_FUNCTION(callSet, (JSGlobalObject* globalObject, CallFrame*))
 54  {
 55      VM& vm = globalObject->vm();
 56      auto scope = DECLARE_THROW_SCOPE(vm);
 57      return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(globalObject, scope, "Set"));
 58  }
 59  
 60  JSC_DEFINE_HOST_FUNCTION(constructSet, (JSGlobalObject* globalObject, CallFrame* callFrame))
 61  {
 62      VM& vm = globalObject->vm();
 63      auto scope = DECLARE_THROW_SCOPE(vm);
 64  
 65      JSObject* newTarget = asObject(callFrame->newTarget());
 66      Structure* setStructure = newTarget == callFrame->jsCallee()
 67          ? globalObject->setStructure()
 68          : InternalFunction::createSubclassStructure(globalObject, newTarget, getFunctionRealm(vm, newTarget)->setStructure());
 69      RETURN_IF_EXCEPTION(scope, { });
 70  
 71      JSValue iterable = callFrame->argument(0);
 72      if (iterable.isUndefinedOrNull()) 
 73          RELEASE_AND_RETURN(scope, JSValue::encode(JSSet::create(globalObject, vm, setStructure)));
 74  
 75      if (auto* iterableSet = jsDynamicCast<JSSet*>(vm, iterable)) {
 76          if (iterableSet->canCloneFastAndNonObservable(setStructure)) 
 77              RELEASE_AND_RETURN(scope, JSValue::encode(iterableSet->clone(globalObject, vm, setStructure)));
 78      }
 79  
 80      JSSet* set = JSSet::create(globalObject, vm, setStructure);
 81      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 82  
 83      JSValue adderFunction = set->JSObject::get(globalObject, vm.propertyNames->add);
 84      RETURN_IF_EXCEPTION(scope, encodedJSValue());
 85  
 86      auto adderFunctionCallData = getCallData(vm, adderFunction);
 87      if (UNLIKELY(adderFunctionCallData.type == CallData::Type::None))
 88          return JSValue::encode(throwTypeError(globalObject, scope));
 89  
 90      scope.release();
 91      forEachInIterable(globalObject, iterable, [&](VM&, JSGlobalObject* globalObject, JSValue nextValue) {
 92          MarkedArgumentBuffer arguments;
 93          arguments.append(nextValue);
 94          ASSERT(!arguments.hasOverflowed());
 95          call(globalObject, adderFunction, adderFunctionCallData, set, arguments);
 96      });
 97  
 98      return JSValue::encode(set);
 99  }
100  
101  JSC_DEFINE_HOST_FUNCTION(setPrivateFuncSetBucketHead, (JSGlobalObject* globalObject, CallFrame* callFrame))
102  {
103      ASSERT_UNUSED(globalObject, jsDynamicCast<JSSet*>(globalObject->vm(), callFrame->argument(0)));
104      JSSet* set = jsCast<JSSet*>(callFrame->uncheckedArgument(0));
105      auto* head = set->head();
106      ASSERT(head);
107      return JSValue::encode(head);
108  }
109  
110  JSC_DEFINE_HOST_FUNCTION(setPrivateFuncSetBucketNext, (JSGlobalObject* globalObject, CallFrame* callFrame))
111  {
112      ASSERT(jsDynamicCast<JSSet::BucketType*>(globalObject->vm(), callFrame->argument(0)));
113      auto* bucket = jsCast<JSSet::BucketType*>(callFrame->uncheckedArgument(0));
114      ASSERT(bucket);
115      bucket = bucket->next();
116      while (bucket) {
117          if (!bucket->deleted())
118              return JSValue::encode(bucket);
119          bucket = bucket->next();
120      }
121      return JSValue::encode(globalObject->vm().sentinelSetBucket());
122  }
123  
124  JSC_DEFINE_HOST_FUNCTION(setPrivateFuncSetBucketKey, (JSGlobalObject* globalObject, CallFrame* callFrame))
125  {
126      ASSERT_UNUSED(globalObject, jsDynamicCast<JSSet::BucketType*>(globalObject->vm(), callFrame->argument(0)));
127      auto* bucket = jsCast<JSSet::BucketType*>(callFrame->uncheckedArgument(0));
128      ASSERT(bucket);
129      return JSValue::encode(bucket->key());
130  }
131  
132  }