// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/builtins/builtins-utils-inl.h" #include "src/builtins/builtins.h" #include "src/logging/counters.h" #include "src/numbers/conversions.h" #include "src/objects/objects-inl.h" #ifdef V8_INTL_SUPPORT #include "src/objects/intl-objects.h" #endif namespace v8 { namespace internal { BUILTIN(BigIntConstructor) { HandleScope scope(isolate); if (!args.new_target()->IsUndefined(isolate)) { // [[Construct]] THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kNotConstructor, isolate->factory()->BigInt_string())); } // [[Call]] Handle value = args.atOrUndefined(isolate, 1); if (value->IsJSReceiver()) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, value, JSReceiver::ToPrimitive(Handle::cast(value), ToPrimitiveHint::kNumber)); } if (value->IsNumber()) { RETURN_RESULT_OR_FAILURE(isolate, BigInt::FromNumber(isolate, value)); } else { RETURN_RESULT_OR_FAILURE(isolate, BigInt::FromObject(isolate, value)); } } BUILTIN(BigIntAsUintN) { HandleScope scope(isolate); Handle bits_obj = args.atOrUndefined(isolate, 1); Handle bigint_obj = args.atOrUndefined(isolate, 2); Handle bits; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, bits, Object::ToIndex(isolate, bits_obj, MessageTemplate::kInvalidIndex)); Handle bigint; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint, BigInt::FromObject(isolate, bigint_obj)); RETURN_RESULT_OR_FAILURE(isolate, BigInt::AsUintN(isolate, bits->Number(), bigint)); } BUILTIN(BigIntAsIntN) { HandleScope scope(isolate); Handle bits_obj = args.atOrUndefined(isolate, 1); Handle bigint_obj = args.atOrUndefined(isolate, 2); Handle bits; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, bits, Object::ToIndex(isolate, bits_obj, MessageTemplate::kInvalidIndex)); Handle bigint; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint, BigInt::FromObject(isolate, bigint_obj)); return *BigInt::AsIntN(isolate, bits->Number(), bigint); } namespace { MaybeHandle ThisBigIntValue(Isolate* isolate, Handle value, const char* caller) { // 1. If Type(value) is BigInt, return value. if (value->IsBigInt()) return Handle::cast(value); // 2. If Type(value) is Object and value has a [[BigIntData]] internal slot: if (value->IsJSPrimitiveWrapper()) { // 2a. Assert: value.[[BigIntData]] is a BigInt value. // 2b. Return value.[[BigIntData]]. Object data = JSPrimitiveWrapper::cast(*value).value(); if (data.IsBigInt()) return handle(BigInt::cast(data), isolate); } // 3. Throw a TypeError exception. THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kNotGeneric, isolate->factory()->NewStringFromAsciiChecked(caller), isolate->factory()->NewStringFromStaticChars("BigInt")), BigInt); } Object BigIntToStringImpl(Handle receiver, Handle radix, Isolate* isolate, const char* builtin_name) { // 1. Let x be ? thisBigIntValue(this value). Handle x; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, x, ThisBigIntValue(isolate, receiver, builtin_name)); // 2. If radix is not present, let radixNumber be 10. // 3. Else if radix is undefined, let radixNumber be 10. int radix_number = 10; if (!radix->IsUndefined(isolate)) { // 4. Else, let radixNumber be ? ToInteger(radix). ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix, Object::ToInteger(isolate, radix)); double radix_double = radix->Number(); // 5. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception. if (radix_double < 2 || radix_double > 36) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewRangeError(MessageTemplate::kToRadixFormatRange)); } radix_number = static_cast(radix_double); } // Return the String representation of this Number value using the radix // specified by radixNumber. RETURN_RESULT_OR_FAILURE(isolate, BigInt::ToString(isolate, x, radix_number)); } } // namespace BUILTIN(BigIntPrototypeToLocaleString) { HandleScope scope(isolate); #ifdef V8_INTL_SUPPORT if (FLAG_harmony_intl_bigint) { // 1. Let x be ? thisBigIntValue(this value). Handle x; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, x, ThisBigIntValue(isolate, args.receiver(), "BigInt.prototype.toLocaleString")); RETURN_RESULT_OR_FAILURE( isolate, Intl::NumberToLocaleString(isolate, x, args.atOrUndefined(isolate, 1), args.atOrUndefined(isolate, 2))); } // Fallbacks to old toString implemention if flag is off or no // V8_INTL_SUPPORT #endif // V8_INTL_SUPPORT Handle radix = isolate->factory()->undefined_value(); return BigIntToStringImpl(args.receiver(), radix, isolate, "BigInt.prototype.toLocaleString"); } BUILTIN(BigIntPrototypeToString) { HandleScope scope(isolate); Handle radix = args.atOrUndefined(isolate, 1); return BigIntToStringImpl(args.receiver(), radix, isolate, "BigInt.prototype.toString"); } BUILTIN(BigIntPrototypeValueOf) { HandleScope scope(isolate); RETURN_RESULT_OR_FAILURE( isolate, ThisBigIntValue(isolate, args.receiver(), "BigInt.prototype.valueOf")); } } // namespace internal } // namespace v8