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