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