/ runtime / BigIntPrototype.cpp
BigIntPrototype.cpp
  1  /*
  2   * Copyright (C) 2017 Caio Lima <ticaiolima@gmail.com>.
  3   * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
  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. AND ITS CONTRIBUTORS ``AS IS''
 15   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 16   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 17   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 18   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 19   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 20   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 21   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 22   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 24   * THE POSSIBILITY OF SUCH DAMAGE.
 25   */
 26  
 27  #include "config.h"
 28  #include "BigIntPrototype.h"
 29  
 30  #include "BigIntObject.h"
 31  #include "IntegrityInlines.h"
 32  #include "IntlNumberFormat.h"
 33  #include "JSBigInt.h"
 34  #include "JSCInlines.h"
 35  #include "JSCast.h"
 36  #include "NumberPrototype.h"
 37  #include <wtf/Assertions.h>
 38  
 39  namespace JSC {
 40  
 41  static JSC_DECLARE_HOST_FUNCTION(bigIntProtoFuncToString);
 42  static JSC_DECLARE_HOST_FUNCTION(bigIntProtoFuncToLocaleString);
 43  static JSC_DECLARE_HOST_FUNCTION(bigIntProtoFuncValueOf);
 44  
 45  }
 46  
 47  #include "BigIntPrototype.lut.h"
 48  
 49  namespace JSC {
 50  
 51  const ClassInfo BigIntPrototype::s_info = { "BigInt", &Base::s_info, &bigIntPrototypeTable, nullptr, CREATE_METHOD_TABLE(BigIntPrototype) };
 52  
 53  /* Source for BigIntPrototype.lut.h
 54  @begin bigIntPrototypeTable
 55    toString          bigIntProtoFuncToString         DontEnum|Function 0
 56    toLocaleString    bigIntProtoFuncToLocaleString   DontEnum|Function 0
 57    valueOf           bigIntProtoFuncValueOf          DontEnum|Function 0
 58  @end
 59  */
 60  
 61  STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(BigIntPrototype);
 62  
 63  BigIntPrototype::BigIntPrototype(VM& vm, Structure* structure)
 64      : JSNonFinalObject(vm, structure)
 65  {
 66  }
 67  
 68  void BigIntPrototype::finishCreation(VM& vm, JSGlobalObject*)
 69  {
 70      Base::finishCreation(vm);
 71      ASSERT(inherits(vm, info()));
 72      JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
 73  }
 74  
 75  // ------------------------------ Functions ---------------------------
 76  
 77  static ALWAYS_INLINE JSBigInt* toThisBigIntValue(JSGlobalObject* globalObject, JSValue thisValue)
 78  {
 79      VM& vm = globalObject->vm();
 80      auto scope = DECLARE_THROW_SCOPE(vm);
 81  
 82  #if USE(BIGINT32)
 83      // FIXME: heap-allocating all big ints is inneficient, but re-implementing toString for small BigInts is enough work that I'm deferring it to a later patch.
 84      if (thisValue.isBigInt32())
 85          RELEASE_AND_RETURN(scope, JSBigInt::createFrom(globalObject, thisValue.bigInt32AsInt32()));
 86  #endif
 87  
 88      if (thisValue.isCell()) {
 89          if (JSBigInt* bigInt = jsDynamicCast<JSBigInt*>(vm, thisValue.asCell()))
 90              return bigInt;
 91  
 92          if (BigIntObject* bigIntObject = jsDynamicCast<BigIntObject*>(vm, thisValue.asCell())) {
 93              JSValue bigInt = bigIntObject->internalValue();
 94  #if USE(BIGINT32)
 95              if (bigInt.isBigInt32())
 96                  RELEASE_AND_RETURN(scope, JSBigInt::createFrom(globalObject, bigInt.bigInt32AsInt32()));
 97  #endif
 98              return bigInt.asHeapBigInt();
 99          }
100      }
101  
102      throwTypeError(globalObject, scope, "'this' value must be a BigInt or BigIntObject"_s);
103      return nullptr;
104  }
105  
106  JSC_DEFINE_HOST_FUNCTION(bigIntProtoFuncToString, (JSGlobalObject* globalObject, CallFrame* callFrame))
107  {
108      VM& vm = globalObject->vm();
109      auto scope = DECLARE_THROW_SCOPE(vm);
110  
111      JSBigInt* value = toThisBigIntValue(globalObject, callFrame->thisValue());
112      RETURN_IF_EXCEPTION(scope, { });
113  
114      ASSERT(value);
115  
116      Integrity::auditStructureID(vm, value->structureID());
117      int32_t radix = extractToStringRadixArgument(globalObject, callFrame->argument(0), scope);
118      RETURN_IF_EXCEPTION(scope, { });
119  
120      String resultString = value->toString(globalObject, radix);
121      RETURN_IF_EXCEPTION(scope, { });
122      scope.release();
123      if (resultString.length() == 1)
124          return JSValue::encode(vm.smallStrings.singleCharacterString(resultString[0]));
125  
126      return JSValue::encode(jsNontrivialString(vm, resultString));
127  }
128  
129  // FIXME: this function should introduce the right separators for thousands and similar things.
130  JSC_DEFINE_HOST_FUNCTION(bigIntProtoFuncToLocaleString, (JSGlobalObject* globalObject, CallFrame* callFrame))
131  {
132      VM& vm = globalObject->vm();
133      auto scope = DECLARE_THROW_SCOPE(vm);
134  
135      JSBigInt* value = toThisBigIntValue(globalObject, callFrame->thisValue());
136      RETURN_IF_EXCEPTION(scope, { });
137  
138      auto* numberFormat = IntlNumberFormat::create(vm, globalObject->numberFormatStructure());
139      numberFormat->initializeNumberFormat(globalObject, callFrame->argument(0), callFrame->argument(1));
140      RETURN_IF_EXCEPTION(scope, encodedJSValue());
141      RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->format(globalObject, value)));
142  }
143  
144  JSC_DEFINE_HOST_FUNCTION(bigIntProtoFuncValueOf, (JSGlobalObject* globalObject, CallFrame* callFrame))
145  {
146      VM& vm = globalObject->vm();
147      auto scope = DECLARE_THROW_SCOPE(vm);
148  
149      JSBigInt* value = toThisBigIntValue(globalObject, callFrame->thisValue());
150      RETURN_IF_EXCEPTION(scope, { });
151  
152      Integrity::auditStructureID(vm, value->structureID());
153      return JSValue::encode(value);
154  }
155  
156  } // namespace JSC