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