• 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_bigint.h"
19 #include "ecmascript/js_primitive_ref.h"
20 #ifdef ARK_SUPPORT_INTL
21 #include "ecmascript/js_number_format.h"
22 #else
23 #ifndef ARK_NOT_SUPPORT_INTL_GLOBAL
24 #include "ecmascript/intl/global_intl_helper.h"
25 #endif
26 #endif
27 
28 namespace panda::ecmascript::builtins {
BigIntConstructor(EcmaRuntimeCallInfo * argv)29 JSTaggedValue BuiltinsBigInt::BigIntConstructor(EcmaRuntimeCallInfo *argv)
30 {
31     ASSERT(argv);
32     JSThread *thread = argv->GetThread();
33     BUILTINS_API_TRACE(thread, BigInt, Constructor);
34     [[maybe_unused]] EcmaHandleScope handleScope(thread);
35     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
36     // 1. If NewTarget is not undefined, throw a TypeError exception.
37     if (!newTarget->IsUndefined()) {
38         THROW_TYPE_ERROR_AND_RETURN(thread, "BigInt is not a constructor", JSTaggedValue::Exception());
39     }
40     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
41     // 2. Let prim be ? ToPrimitive(value).
42     JSHandle<JSTaggedValue> Primitive(thread, JSTaggedValue::ToPrimitive(thread, value));
43     // 3. If Type(prim) is Number, return ? NumberToBigInt(prim).
44     if (Primitive->IsNumber()) {
45         return BigInt::NumberToBigInt(thread, Primitive);
46     }
47     // 4. Otherwise, return ? ToBigInt(value).
48     return JSTaggedValue::ToBigInt(thread, value);
49 }
50 
AsUintN(EcmaRuntimeCallInfo * argv)51 JSTaggedValue BuiltinsBigInt::AsUintN(EcmaRuntimeCallInfo *argv)
52 {
53     ASSERT(argv);
54     JSThread *thread = argv->GetThread();
55     BUILTINS_API_TRACE(thread, BigInt, AsUintN);
56     [[maybe_unused]] EcmaHandleScope handleScope(thread);
57     JSHandle<JSTaggedValue> bits = GetCallArg(argv, 0);
58     JSHandle<JSTaggedValue> bigint = GetCallArg(argv, 1);
59     // 1. Let bits be ? ToIndex(bits).
60     JSTaggedNumber index = JSTaggedValue::ToIndex(thread, bits);
61     // 2. Let bigint be ? ToBigInt(bigint).
62     JSTaggedValue jsBigint = JSTaggedValue::ToBigInt(thread, bigint);
63     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
64     JSHandle<BigInt> jsBigintVal(thread, jsBigint);
65     // 3. Return a BigInt representing bigint modulo 2bits.
66     return BigInt::AsUintN(thread, index, jsBigintVal);
67 }
68 
AsIntN(EcmaRuntimeCallInfo * argv)69 JSTaggedValue BuiltinsBigInt::AsIntN(EcmaRuntimeCallInfo *argv)
70 {
71     ASSERT(argv);
72     JSThread *thread = argv->GetThread();
73     BUILTINS_API_TRACE(thread, BigInt, AsIntN);
74     [[maybe_unused]] EcmaHandleScope handleScope(thread);
75     JSHandle<JSTaggedValue> bits = GetCallArg(argv, 0);
76     JSHandle<JSTaggedValue> bigint = GetCallArg(argv, 1);
77     // 1. Let bits be ? ToIndex(bits).
78     JSTaggedNumber index = JSTaggedValue::ToIndex(thread, bits);
79     // 2. Let bigint be ? ToBigInt(bigint).
80     JSTaggedValue jsBigint = JSTaggedValue::ToBigInt(thread, bigint);
81     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
82     JSHandle<BigInt> jsBigintVal(thread, jsBigint);
83     // 3. Let mod be ℝ(bigint) modulo 2bits.
84     // 4. If mod ≥ 2bits - 1, return ℤ(mod - 2bits); otherwise, return ℤ(mod).
85     return BigInt::AsintN(thread, index, jsBigintVal);
86 }
87 
ToLocaleString(EcmaRuntimeCallInfo * argv)88 JSTaggedValue BuiltinsBigInt::ToLocaleString(EcmaRuntimeCallInfo *argv)
89 {
90     ASSERT(argv);
91     JSThread *thread = argv->GetThread();
92     BUILTINS_API_TRACE(thread, BigInt, ToLocaleString);
93     [[maybe_unused]] EcmaHandleScope handleScope(thread);
94     // 1. Let x be ? ThisBigIntValue(this value).
95     JSTaggedValue value = ThisBigIntValue(argv);
96     [[maybe_unused]] JSHandle<JSTaggedValue> x(thread, value);
97     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
98 
99     JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
100     JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
101     [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined();
102 #ifdef ARK_SUPPORT_INTL
103     if (cacheable) {
104         auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales);
105         if (numberFormatter != nullptr) {
106             JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue());
107             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
108             return result.GetTaggedValue();
109         }
110     }
111     // 2. Let numberFormat be ? Construct(%NumberFormat%, « locales, options »).
112     EcmaVM *ecmaVm = thread->GetEcmaVM();
113     JSHandle<JSFunction> ctor(ecmaVm->GetGlobalEnv()->GetNumberFormatFunction());
114     ObjectFactory *factory = ecmaVm->GetFactory();
115     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor);
116     JSHandle<JSNumberFormat> numberFormat = JSHandle<JSNumberFormat>::Cast(obj);
117     JSNumberFormat::InitializeNumberFormat(thread, numberFormat, locales, options, cacheable);
118     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
119     if (cacheable) {
120         auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales);
121         ASSERT(numberFormatter != nullptr);
122         JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue());
123         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
124         return result.GetTaggedValue();
125     }
126 
127     // Return ? FormatNumeric(numberFormat, x).
128     JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormat, x.GetTaggedValue());
129     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
130     return result.GetTaggedValue();
131 #else
132 #ifdef ARK_NOT_SUPPORT_INTL_GLOBAL
133     ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "LocaleCompare");
134 #else
135     intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::NumberFormatter);
136     auto numberFormatter = gh.GetGlobalObject<intl::GlobalNumberFormat>(thread,
137         locales, options, intl::GlobalFormatterType::NumberFormatter, cacheable);
138     if (numberFormatter == nullptr) {
139         LOG_ECMA(ERROR) << "BuiltinsBigInt:numberFormatter is nullptr";
140     }
141     ASSERT(numberFormatter != nullptr);
142     std::string result = numberFormatter->Format(x->GetDouble());
143     EcmaVM *ecmaVm = thread->GetEcmaVM();
144     ObjectFactory *factory = ecmaVm->GetFactory();
145     JSHandle returnValue = factory->NewFromStdString(result);
146     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
147     return returnValue.GetTaggedValue();
148 #endif
149 #endif
150 }
151 
ToString(EcmaRuntimeCallInfo * argv)152 JSTaggedValue BuiltinsBigInt::ToString(EcmaRuntimeCallInfo *argv)
153 {
154     ASSERT(argv);
155     JSThread *thread = argv->GetThread();
156     BUILTINS_API_TRACE(thread, BigInt, ToString);
157     [[maybe_unused]] EcmaHandleScope handleScope(thread);
158 
159     // 1. Let x be ? thisBigIntValue(this value).
160     JSTaggedValue value = ThisBigIntValue(argv);
161     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
162     JSHandle<BigInt> thisBigint(thread, value);
163     // 2. If radix is not present, let radixNumber be 10
164     double radix = base::DECIMAL;
165     JSHandle<JSTaggedValue> radixValue = GetCallArg(argv, 0);
166     // 3. Else, let radixNumber be ? ToIntegerOrInfinity(radix).
167     if (!radixValue->IsUndefined()) {
168         JSTaggedNumber radixNumber = JSTaggedValue::ToInteger(thread, radixValue);
169         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
170         radix = radixNumber.GetNumber();
171     }
172     // 4. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
173     if (radix < base::MIN_RADIX || radix > base::MAX_RADIX) {
174         THROW_RANGE_ERROR_AND_RETURN(thread, "toString() radix argument must be between 2 and 36",
175                                      JSTaggedValue::Exception());
176     }
177     // 5. If radixNumber = 10, return ToString(x).
178     if (radix == base::DECIMAL) {
179         return BigInt::ToString(thread, thisBigint).GetTaggedValue();
180     }
181     // 6. Return the String representation of this BigInt value using the radix specified by radixNumber
182     return BigInt::ToString(thread, thisBigint, static_cast<int>(radix)).GetTaggedValue();
183 }
184 
ValueOf(EcmaRuntimeCallInfo * argv)185 JSTaggedValue BuiltinsBigInt::ValueOf(EcmaRuntimeCallInfo *argv)
186 {
187     ASSERT(argv);
188     JSThread *thread = argv->GetThread();
189     BUILTINS_API_TRACE(thread, BigInt, ValueOf);
190     [[maybe_unused]] EcmaHandleScope handleScope(thread);
191     // 1. Let x be ? thisBigIntValue(this value).
192     return ThisBigIntValue(argv);
193 }
194 
ThisBigIntValue(EcmaRuntimeCallInfo * argv)195 JSTaggedValue BuiltinsBigInt::ThisBigIntValue(EcmaRuntimeCallInfo *argv)
196 {
197     ASSERT(argv);
198     JSThread *thread = argv->GetThread();
199     BUILTINS_API_TRACE(thread, BigInt, ThisBigIntValue);
200     JSHandle<JSTaggedValue> value = GetThis(argv);
201     // 1. If Type(value) is BigInt, return value.
202     if (value->IsBigInt()) {
203         return value.GetTaggedValue();
204     }
205     // 2. If Type(value) is Object and value has a [[BigIntData]] internal slot, then
206     if (value->IsJSPrimitiveRef()) {
207         JSTaggedValue primitive = JSPrimitiveRef::Cast(value->GetTaggedObject())->GetValue();
208         // a. Assert: Type(value.[[BigIntData]]) is BigInt.
209         if (primitive.IsBigInt()) {
210             // b. Return value.[[BigIntData]].
211             return primitive;
212         }
213     }
214     // 3. Throw a TypeError exception.
215     THROW_TYPE_ERROR_AND_RETURN(thread, "not BigInt type", JSTaggedValue::Exception());
216 }
217 }  // namespace panda::ecmascript::builtins