1/*
2 * Copyright (C) 2017 Caio Lima <[email protected]>
3 * Copyright (C) 2017 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. ``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#include "config.h"
28#include "BigIntConstructor.h"
29
30#include "BigIntPrototype.h"
31#include "JSBigInt.h"
32#include "JSCInlines.h"
33#include "JSGlobalObjectFunctions.h"
34#include "Lookup.h"
35#include "ParseInt.h"
36#include "StructureInlines.h"
37
38namespace JSC {
39
40static EncodedJSValue JSC_HOST_CALL bigIntConstructorFuncAsUintN(ExecState*);
41static EncodedJSValue JSC_HOST_CALL bigIntConstructorFuncAsIntN(ExecState*);
42
43} // namespace JSC
44
45#include "BigIntConstructor.lut.h"
46
47namespace JSC {
48
49STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(BigIntConstructor);
50
51const ClassInfo BigIntConstructor::s_info = { "Function", &Base::s_info, &bigIntConstructorTable, nullptr, CREATE_METHOD_TABLE(BigIntConstructor) };
52
53/* Source for BigIntConstructor.lut.h
54@begin bigIntConstructorTable
55 asUintN bigIntConstructorFuncAsUintN DontEnum|Function 2
56 asIntN bigIntConstructorFuncAsIntN DontEnum|Function 2
57@end
58*/
59
60static EncodedJSValue JSC_HOST_CALL callBigIntConstructor(ExecState*);
61
62BigIntConstructor::BigIntConstructor(VM& vm, Structure* structure)
63 : InternalFunction(vm, structure, callBigIntConstructor, nullptr)
64{
65}
66
67void BigIntConstructor::finishCreation(VM& vm, BigIntPrototype* bigIntPrototype)
68{
69 Base::finishCreation(vm, "BigInt"_s, NameVisibility::Visible, NameAdditionMode::WithoutStructureTransition);
70 ASSERT(inherits(vm, info()));
71
72 putDirectWithoutTransition(vm, vm.propertyNames->prototype, bigIntPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
73 putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
74}
75
76// ------------------------------ Functions ---------------------------
77
78static bool isSafeInteger(JSValue argument)
79{
80 if (argument.isInt32())
81 return true;
82
83 if (!argument.isDouble())
84 return false;
85
86 double number = argument.asDouble();
87 return trunc(number) == number && std::abs(number) <= maxSafeInteger();
88}
89
90static EncodedJSValue toBigInt(ExecState& state, JSValue argument)
91{
92 ASSERT(argument.isPrimitive());
93 VM& vm = state.vm();
94
95 if (argument.isBigInt())
96 return JSValue::encode(argument);
97
98 auto scope = DECLARE_THROW_SCOPE(vm);
99
100 if (argument.isBoolean())
101 RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::createFrom(vm, argument.asBoolean())));
102
103 if (argument.isUndefinedOrNull() || argument.isNumber() || argument.isSymbol())
104 return throwVMTypeError(&state, scope, "Invalid argument type in ToBigInt operation"_s);
105
106 ASSERT(argument.isString());
107
108 RELEASE_AND_RETURN(scope, toStringView(&state, argument, [&] (StringView view) {
109 return JSValue::encode(JSBigInt::parseInt(&state, view));
110 }));
111}
112
113static EncodedJSValue JSC_HOST_CALL callBigIntConstructor(ExecState* state)
114{
115 VM& vm = state->vm();
116 auto scope = DECLARE_THROW_SCOPE(vm);
117
118 JSValue value = state->argument(0);
119 JSValue primitive = value.toPrimitive(state);
120 RETURN_IF_EXCEPTION(scope, encodedJSValue());
121
122 if (primitive.isNumber()) {
123 if (!isSafeInteger(primitive))
124 return throwVMError(state, scope, createRangeError(state, "Not safe integer"_s));
125
126 scope.release();
127 if (primitive.isInt32())
128 return JSValue::encode(JSBigInt::createFrom(vm, primitive.asInt32()));
129
130 if (primitive.isUInt32())
131 return JSValue::encode(JSBigInt::createFrom(vm, primitive.asUInt32()));
132
133 return JSValue::encode(JSBigInt::createFrom(vm, static_cast<int64_t>(primitive.asDouble())));
134 }
135
136 EncodedJSValue result = toBigInt(*state, primitive);
137 RETURN_IF_EXCEPTION(scope, encodedJSValue());
138 return result;
139}
140
141EncodedJSValue JSC_HOST_CALL bigIntConstructorFuncAsUintN(ExecState*)
142{
143 // FIXME: [ESNext][BigInt] Implement BigInt.asIntN and BigInt.asUintN
144 // https://bugs.webkit.org/show_bug.cgi?id=181144
145 CRASH();
146 return JSValue::encode(JSValue());
147}
148
149EncodedJSValue JSC_HOST_CALL bigIntConstructorFuncAsIntN(ExecState*)
150{
151 // FIXME: [ESNext][BigInt] Implement BigInt.asIntN and BigInt.asUintN
152 // https://bugs.webkit.org/show_bug.cgi?id=181144
153 CRASH();
154 return JSValue::encode(JSValue());
155}
156
157} // namespace JSC
158