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