• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/builtins/builtins_bigint.h"
17 
18 #include "ecmascript/js_number_format.h"
19 #include "ecmascript/js_primitive_ref.h"
20 #include "ecmascript/js_bigint.h"
21 
22 namespace panda::ecmascript::builtins {
BigIntConstructor(EcmaRuntimeCallInfo * argv)23 JSTaggedValue BuiltinsBigInt::BigIntConstructor(EcmaRuntimeCallInfo *argv)
24 {
25     ASSERT(argv);
26     JSThread *thread = argv->GetThread();
27     BUILTINS_API_TRACE(thread, BigInt, Constructor);
28     [[maybe_unused]] EcmaHandleScope handleScope(thread);
29     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
30     // 1. If NewTarget is not undefined, throw a TypeError exception.
31     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
32     if (!newTarget->IsUndefined()) {
33         THROW_TYPE_ERROR_AND_RETURN(thread, "BigInt is not a constructor", JSTaggedValue::Exception());
34     }
35     // 2. Let prim be ? ToPrimitive(value).
36     JSHandle<JSTaggedValue> Primitive(thread, JSTaggedValue::ToPrimitive(thread, value));
37     // 3. If Type(prim) is Number, return ? NumberToBigInt(prim).
38     if (Primitive->IsNumber()) {
39         return BigInt::NumberToBigInt(thread, Primitive);
40     }
41     // 4. Otherwise, return ? ToBigInt(value).
42     return JSTaggedValue::ToBigInt(thread, value);
43 }
44 
AsUintN(EcmaRuntimeCallInfo * argv)45 JSTaggedValue BuiltinsBigInt::AsUintN(EcmaRuntimeCallInfo *argv)
46 {
47     ASSERT(argv);
48     JSThread *thread = argv->GetThread();
49     BUILTINS_API_TRACE(thread, BigInt, AsUintN);
50     [[maybe_unused]] EcmaHandleScope handleScope(thread);
51     JSHandle<JSTaggedValue> bits = GetCallArg(argv, 0);
52     JSHandle<JSTaggedValue> bigint = GetCallArg(argv, 1);
53     // 1. Let bits be ? ToIndex(bits).
54     JSTaggedNumber index = JSTaggedValue::ToIndex(thread, bits);
55     // 2. Let bigint be ? ToBigInt(bigint).
56     JSTaggedValue jsBigint = JSTaggedValue::ToBigInt(thread, bigint);
57     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
58     JSHandle<BigInt> jsBigintVal(thread, jsBigint);
59     // 3. Return a BigInt representing bigint modulo 2bits.
60     return BigInt::AsUintN(thread, index, jsBigintVal);
61 }
62 
AsIntN(EcmaRuntimeCallInfo * argv)63 JSTaggedValue BuiltinsBigInt::AsIntN(EcmaRuntimeCallInfo *argv)
64 {
65     ASSERT(argv);
66     JSThread *thread = argv->GetThread();
67     BUILTINS_API_TRACE(thread, BigInt, AsIntN);
68     [[maybe_unused]] EcmaHandleScope handleScope(thread);
69     JSHandle<JSTaggedValue> bits = GetCallArg(argv, 0);
70     JSHandle<JSTaggedValue> bigint = GetCallArg(argv, 1);
71     // 1. Let bits be ? ToIndex(bits).
72     JSTaggedNumber index = JSTaggedValue::ToIndex(thread, bits);
73     // 2. Let bigint be ? ToBigInt(bigint).
74     JSTaggedValue jsBigint = JSTaggedValue::ToBigInt(thread, bigint);
75     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
76     JSHandle<BigInt> jsBigintVal(thread, jsBigint);
77     // 3. Let mod be ℝ(bigint) modulo 2bits.
78     // 4. If mod ≥ 2bits - 1, return ℤ(mod - 2bits); otherwise, return ℤ(mod).
79     return BigInt::AsintN(thread, index, jsBigintVal);
80 }
81 
ToLocaleString(EcmaRuntimeCallInfo * argv)82 JSTaggedValue BuiltinsBigInt::ToLocaleString(EcmaRuntimeCallInfo *argv)
83 {
84     ASSERT(argv);
85     JSThread *thread = argv->GetThread();
86     BUILTINS_API_TRACE(thread, BigInt, ToLocaleString);
87     [[maybe_unused]] EcmaHandleScope handleScope(thread);
88     // 1. Let x be ? ThisBigIntValue(this value).
89     JSTaggedValue value = ThisBigIntValue(argv);
90     JSHandle<JSTaggedValue> x(thread, value);
91     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
92 
93     // 2. Let numberFormat be ? Construct(%NumberFormat%, « locales, options »).
94     EcmaVM *ecmaVm = thread->GetEcmaVM();
95     JSHandle<JSFunction> ctor(ecmaVm->GetGlobalEnv()->GetNumberFormatFunction());
96     ObjectFactory *factory = ecmaVm->GetFactory();
97     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor);
98     JSHandle<JSNumberFormat> numberFormat = JSHandle<JSNumberFormat>::Cast(obj);
99     JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
100     JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
101     bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined();
102     if (cacheable) {
103         auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales);
104         if (numberFormatter != nullptr) {
105             JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue());
106             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
107             return result.GetTaggedValue();
108         }
109     }
110     JSNumberFormat::InitializeNumberFormat(thread, numberFormat, locales, options, cacheable);
111     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
112     if (cacheable) {
113         auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales);
114         ASSERT(numberFormatter != nullptr);
115         JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue());
116         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
117         return result.GetTaggedValue();
118     }
119 
120     // Return ? FormatNumeric(numberFormat, x).
121     JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormat, x.GetTaggedValue());
122     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
123     return result.GetTaggedValue();
124 }
125 
ToString(EcmaRuntimeCallInfo * argv)126 JSTaggedValue BuiltinsBigInt::ToString(EcmaRuntimeCallInfo *argv)
127 {
128     ASSERT(argv);
129     JSThread *thread = argv->GetThread();
130     BUILTINS_API_TRACE(thread, BigInt, ToString);
131     [[maybe_unused]] EcmaHandleScope handleScope(thread);
132 
133     // 1. Let x be ? thisBigIntValue(this value).
134     JSTaggedValue value = ThisBigIntValue(argv);
135     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
136     JSHandle<BigInt> thisBigint(thread, value);
137     // 2. If radix is not present, let radixNumber be 10
138     double radix = base::DECIMAL;
139     JSHandle<JSTaggedValue> radixValue = GetCallArg(argv, 0);
140     // 3. Else, let radixNumber be ? ToIntegerOrInfinity(radix).
141     if (!radixValue->IsUndefined()) {
142         JSTaggedNumber radixNumber = JSTaggedValue::ToInteger(thread, radixValue);
143         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
144         radix = radixNumber.GetNumber();
145     }
146     // 4. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
147     if (radix < base::MIN_RADIX || radix > base::MAX_RADIX) {
148         THROW_RANGE_ERROR_AND_RETURN(thread, "toString() radix argument must be between 2 and 36",
149                                      JSTaggedValue::Exception());
150     }
151     // 5. If radixNumber = 10, return ToString(x).
152     if (radix == base::DECIMAL) {
153         return BigInt::ToString(thread, thisBigint).GetTaggedValue();
154     }
155     // 6. Return the String representation of this BigInt value using the radix specified by radixNumber
156     return BigInt::ToString(thread, thisBigint, static_cast<int>(radix)).GetTaggedValue();
157 }
158 
ValueOf(EcmaRuntimeCallInfo * argv)159 JSTaggedValue BuiltinsBigInt::ValueOf(EcmaRuntimeCallInfo *argv)
160 {
161     ASSERT(argv);
162     JSThread *thread = argv->GetThread();
163     BUILTINS_API_TRACE(thread, BigInt, ValueOf);
164     [[maybe_unused]] EcmaHandleScope handleScope(thread);
165     // 1. Let x be ? thisBigIntValue(this value).
166     return ThisBigIntValue(argv);
167 }
168 
ThisBigIntValue(EcmaRuntimeCallInfo * argv)169 JSTaggedValue BuiltinsBigInt::ThisBigIntValue(EcmaRuntimeCallInfo *argv)
170 {
171     ASSERT(argv);
172     JSThread *thread = argv->GetThread();
173     BUILTINS_API_TRACE(thread, BigInt, ThisBigIntValue);
174     JSHandle<JSTaggedValue> value = GetThis(argv);
175     // 1. If Type(value) is BigInt, return value.
176     if (value->IsBigInt()) {
177         return value.GetTaggedValue();
178     }
179     // 2. If Type(value) is Object and value has a [[BigIntData]] internal slot, then
180     if (value->IsJSPrimitiveRef()) {
181         JSTaggedValue primitive = JSPrimitiveRef::Cast(value->GetTaggedObject())->GetValue();
182         // a. Assert: Type(value.[[BigIntData]]) is BigInt.
183         if (primitive.IsBigInt()) {
184             // b. Return value.[[BigIntData]].
185             return primitive;
186         }
187     }
188     // 3. Throw a TypeError exception.
189     THROW_TYPE_ERROR_AND_RETURN(thread, "not BigInt type", JSTaggedValue::Exception());
190 }
191 }  // namespace panda::ecmascript::builtins