1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/builtins/builtins-utils-inl.h"
6 #include "src/builtins/builtins.h"
7 #include "src/logging/counters.h"
8 #include "src/numbers/conversions.h"
9 #include "src/objects/objects-inl.h"
10 #ifdef V8_INTL_SUPPORT
11 #include "src/objects/intl-objects.h"
12 #endif
13
14 namespace v8 {
15 namespace internal {
16
BUILTIN(BigIntConstructor)17 BUILTIN(BigIntConstructor) {
18 HandleScope scope(isolate);
19 if (!args.new_target()->IsUndefined(isolate)) { // [[Construct]]
20 THROW_NEW_ERROR_RETURN_FAILURE(
21 isolate, NewTypeError(MessageTemplate::kNotConstructor,
22 isolate->factory()->BigInt_string()));
23 }
24 // [[Call]]
25 Handle<Object> value = args.atOrUndefined(isolate, 1);
26
27 if (value->IsJSReceiver()) {
28 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
29 isolate, value,
30 JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(value),
31 ToPrimitiveHint::kNumber));
32 }
33
34 if (value->IsNumber()) {
35 RETURN_RESULT_OR_FAILURE(isolate, BigInt::FromNumber(isolate, value));
36 } else {
37 RETURN_RESULT_OR_FAILURE(isolate, BigInt::FromObject(isolate, value));
38 }
39 }
40
BUILTIN(BigIntAsUintN)41 BUILTIN(BigIntAsUintN) {
42 HandleScope scope(isolate);
43 Handle<Object> bits_obj = args.atOrUndefined(isolate, 1);
44 Handle<Object> bigint_obj = args.atOrUndefined(isolate, 2);
45
46 Handle<Object> bits;
47 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
48 isolate, bits,
49 Object::ToIndex(isolate, bits_obj, MessageTemplate::kInvalidIndex));
50
51 Handle<BigInt> bigint;
52 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint,
53 BigInt::FromObject(isolate, bigint_obj));
54
55 RETURN_RESULT_OR_FAILURE(isolate,
56 BigInt::AsUintN(isolate, bits->Number(), bigint));
57 }
58
BUILTIN(BigIntAsIntN)59 BUILTIN(BigIntAsIntN) {
60 HandleScope scope(isolate);
61 Handle<Object> bits_obj = args.atOrUndefined(isolate, 1);
62 Handle<Object> bigint_obj = args.atOrUndefined(isolate, 2);
63
64 Handle<Object> bits;
65 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
66 isolate, bits,
67 Object::ToIndex(isolate, bits_obj, MessageTemplate::kInvalidIndex));
68
69 Handle<BigInt> bigint;
70 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint,
71 BigInt::FromObject(isolate, bigint_obj));
72
73 return *BigInt::AsIntN(isolate, bits->Number(), bigint);
74 }
75
76 namespace {
77
ThisBigIntValue(Isolate * isolate,Handle<Object> value,const char * caller)78 MaybeHandle<BigInt> ThisBigIntValue(Isolate* isolate, Handle<Object> value,
79 const char* caller) {
80 // 1. If Type(value) is BigInt, return value.
81 if (value->IsBigInt()) return Handle<BigInt>::cast(value);
82 // 2. If Type(value) is Object and value has a [[BigIntData]] internal slot:
83 if (value->IsJSPrimitiveWrapper()) {
84 // 2a. Assert: value.[[BigIntData]] is a BigInt value.
85 // 2b. Return value.[[BigIntData]].
86 Object data = JSPrimitiveWrapper::cast(*value).value();
87 if (data.IsBigInt()) return handle(BigInt::cast(data), isolate);
88 }
89 // 3. Throw a TypeError exception.
90 THROW_NEW_ERROR(
91 isolate,
92 NewTypeError(MessageTemplate::kNotGeneric,
93 isolate->factory()->NewStringFromAsciiChecked(caller),
94 isolate->factory()->BigInt_string()),
95 BigInt);
96 }
97
BigIntToStringImpl(Handle<Object> receiver,Handle<Object> radix,Isolate * isolate,const char * builtin_name)98 Object BigIntToStringImpl(Handle<Object> receiver, Handle<Object> radix,
99 Isolate* isolate, const char* builtin_name) {
100 // 1. Let x be ? thisBigIntValue(this value).
101 Handle<BigInt> x;
102 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
103 isolate, x, ThisBigIntValue(isolate, receiver, builtin_name));
104 // 2. If radix is not present, let radixNumber be 10.
105 // 3. Else if radix is undefined, let radixNumber be 10.
106 int radix_number = 10;
107 if (!radix->IsUndefined(isolate)) {
108 // 4. Else, let radixNumber be ? ToInteger(radix).
109 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix,
110 Object::ToInteger(isolate, radix));
111 double radix_double = radix->Number();
112 // 5. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
113 if (radix_double < 2 || radix_double > 36) {
114 THROW_NEW_ERROR_RETURN_FAILURE(
115 isolate, NewRangeError(MessageTemplate::kToRadixFormatRange));
116 }
117 radix_number = static_cast<int>(radix_double);
118 }
119 // Return the String representation of this Number value using the radix
120 // specified by radixNumber.
121 RETURN_RESULT_OR_FAILURE(isolate, BigInt::ToString(isolate, x, radix_number));
122 }
123
124 } // namespace
125
BUILTIN(BigIntPrototypeToLocaleString)126 BUILTIN(BigIntPrototypeToLocaleString) {
127 HandleScope scope(isolate);
128 const char* method_name = "BigInt.prototype.toLocaleString";
129 #ifdef V8_INTL_SUPPORT
130 // 1. Let x be ? thisBigIntValue(this value).
131 Handle<BigInt> x;
132 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
133 isolate, x, ThisBigIntValue(isolate, args.receiver(), method_name));
134
135 RETURN_RESULT_OR_FAILURE(
136 isolate,
137 Intl::NumberToLocaleString(isolate, x, args.atOrUndefined(isolate, 1),
138 args.atOrUndefined(isolate, 2), method_name));
139 // Fallbacks to old toString implemention if no V8_INTL_SUPPORT
140 #endif // V8_INTL_SUPPORT
141 Handle<Object> radix = isolate->factory()->undefined_value();
142 return BigIntToStringImpl(args.receiver(), radix, isolate, method_name);
143 }
144
BUILTIN(BigIntPrototypeToString)145 BUILTIN(BigIntPrototypeToString) {
146 HandleScope scope(isolate);
147 Handle<Object> radix = args.atOrUndefined(isolate, 1);
148 return BigIntToStringImpl(args.receiver(), radix, isolate,
149 "BigInt.prototype.toString");
150 }
151
BUILTIN(BigIntPrototypeValueOf)152 BUILTIN(BigIntPrototypeValueOf) {
153 HandleScope scope(isolate);
154 RETURN_RESULT_OR_FAILURE(
155 isolate,
156 ThisBigIntValue(isolate, args.receiver(), "BigInt.prototype.valueOf"));
157 }
158
159 } // namespace internal
160 } // namespace v8
161