Commit b361ed51 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[bigint] Expose BigInt on the global object

Along with BigInt.prototype. Their functions only have skeleton
implementations. The purpose of this change is to make it easier
to gradually increase test coverage (e.g. for toString(radix)).

Of course this is still behind the --harmony-bigint flag.

Bug: v8:6791
Change-Id: Ic307fd9165c56ac782fba18d648ce893daaa718f
Reviewed-on: https://chromium-review.googlesource.com/671209
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48094}
parent ce76dd60
...@@ -1234,6 +1234,7 @@ v8_source_set("v8_base") { ...@@ -1234,6 +1234,7 @@ v8_source_set("v8_base") {
"src/builtins/builtins-api.cc", "src/builtins/builtins-api.cc",
"src/builtins/builtins-array.cc", "src/builtins/builtins-array.cc",
"src/builtins/builtins-arraybuffer.cc", "src/builtins/builtins-arraybuffer.cc",
"src/builtins/builtins-bigint.cc",
"src/builtins/builtins-boolean.cc", "src/builtins/builtins-boolean.cc",
"src/builtins/builtins-call.cc", "src/builtins/builtins-call.cc",
"src/builtins/builtins-callsite.cc", "src/builtins/builtins-callsite.cc",
......
...@@ -4220,7 +4220,6 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_dynamic_import) ...@@ -4220,7 +4220,6 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_dynamic_import)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_template_escapes) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_template_escapes)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrict_constructor_return) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrict_constructor_return)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_strict_legacy_accessor_builtins) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_strict_legacy_accessor_builtins)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_bigint)
void InstallPublicSymbol(Factory* factory, Handle<Context> native_context, void InstallPublicSymbol(Factory* factory, Handle<Context> native_context,
const char* name, Handle<Symbol> value) { const char* name, Handle<Symbol> value) {
...@@ -4345,6 +4344,50 @@ void Genesis::InitializeGlobal_harmony_regexp_dotall() { ...@@ -4345,6 +4344,50 @@ void Genesis::InitializeGlobal_harmony_regexp_dotall() {
native_context()->set_regexp_prototype_map(*prototype_map); native_context()->set_regexp_prototype_map(*prototype_map);
} }
void Genesis::InitializeGlobal_harmony_bigint() {
if (!FLAG_harmony_bigint) return;
Handle<JSGlobalObject> global(native_context()->global_object());
Handle<JSFunction> bigint_fun = InstallFunction(
global, "BigInt", JS_VALUE_TYPE, JSValue::kSize,
isolate()->factory()->the_hole_value(), Builtins::kBigIntConstructor);
bigint_fun->shared()->DontAdaptArguments();
bigint_fun->shared()->SetConstructStub(
*BUILTIN_CODE(isolate(), BigIntConstructor_ConstructStub));
bigint_fun->shared()->set_length(1);
InstallWithIntrinsicDefaultProto(isolate(), bigint_fun,
Context::BIGINT_FUNCTION_INDEX);
heap()->bigint_map()->SetConstructorFunctionIndex(
Context::BIGINT_FUNCTION_INDEX);
// Install the properties of the BigInt constructor.
// parseInt(string, radix)
SimpleInstallFunction(bigint_fun, "parseInt", Builtins::kBigIntParseInt, 2,
false);
// asUintN(bits, bigint)
SimpleInstallFunction(bigint_fun, "asUintN", Builtins::kBigIntAsUintN, 2,
false);
// asIntN(bits, bigint)
SimpleInstallFunction(bigint_fun, "asIntN", Builtins::kBigIntAsIntN, 2,
false);
// Set up the %BigIntPrototype%.
Handle<JSObject> prototype(JSObject::cast(bigint_fun->instance_prototype()));
JSFunction::SetPrototype(bigint_fun, prototype);
// Install the properties of the BigInt.prototype.
// "constructor" is created implicitly by InstallFunction() above.
// toLocaleString([reserved1 [, reserved2]])
SimpleInstallFunction(prototype, "toLocaleString",
Builtins::kBigIntPrototypeToLocaleString, 0, false);
// toString([radix])
SimpleInstallFunction(prototype, "toString",
Builtins::kBigIntPrototypeToString, 0, false);
// valueOf()
SimpleInstallFunction(prototype, "valueOf", Builtins::kBigIntPrototypeValueOf,
0, false);
}
#ifdef V8_INTL_SUPPORT #ifdef V8_INTL_SUPPORT
void Genesis::InitializeGlobal_harmony_number_format_to_parts() { void Genesis::InitializeGlobal_harmony_number_format_to_parts() {
......
// 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.h"
#include "src/builtins/builtins.h"
#include "src/counters.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
BUILTIN(BigIntConstructor) {
HandleScope scope(isolate);
Handle<Object> value = args.atOrUndefined(isolate, 1);
// TODO(jkummerow): Implement properly.
// Dummy implementation only takes Smi args.
if (!value->IsSmi()) return isolate->heap()->undefined_value();
int num = Smi::ToInt(*value);
if (num == 0) return *isolate->factory()->NewBigInt(0);
Handle<BigInt> result = isolate->factory()->NewBigIntRaw(1);
result->set_value(num);
return *result;
}
BUILTIN(BigIntConstructor_ConstructStub) {
HandleScope scope(isolate);
Handle<Object> value = args.atOrUndefined(isolate, 1);
Handle<JSFunction> target = args.target();
Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
DCHECK(*target == target->native_context()->bigint_function());
Handle<JSObject> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
JSObject::New(target, new_target));
// TODO(jkummerow): Implement.
USE(value);
USE(result);
UNIMPLEMENTED();
}
BUILTIN(BigIntParseInt) {
HandleScope scope(isolate);
Handle<Object> string_obj = args.atOrUndefined(isolate, 1);
Handle<Object> radix_obj = args.atOrUndefined(isolate, 2);
// TODO(jkummerow): Implement.
USE(string_obj);
USE(radix_obj);
UNIMPLEMENTED();
}
BUILTIN(BigIntAsUintN) {
HandleScope scope(isolate);
Handle<Object> bits_obj = args.atOrUndefined(isolate, 1);
Handle<Object> bigint_obj = args.atOrUndefined(isolate, 2);
// TODO(jkummerow): Implement.
USE(bits_obj);
USE(bigint_obj);
UNIMPLEMENTED();
}
BUILTIN(BigIntAsIntN) {
HandleScope scope(isolate);
Handle<Object> bits_obj = args.atOrUndefined(isolate, 1);
Handle<Object> bigint_obj = args.atOrUndefined(isolate, 2);
// TODO(jkummerow): Implement.
USE(bits_obj);
USE(bigint_obj);
UNIMPLEMENTED();
}
BUILTIN(BigIntPrototypeToLocaleString) {
HandleScope scope(isolate);
// TODO(jkummerow): Implement.
UNIMPLEMENTED();
}
namespace {
MaybeHandle<BigInt> ThisBigIntValue(Isolate* isolate, Handle<Object> value,
const char* caller) {
// 1. If Type(value) is BigInt, return value.
if (value->IsBigInt()) return Handle<BigInt>::cast(value);
// 2. If Type(value) is Object and value has a [[BigIntData]] internal slot:
if (value->IsJSValue()) {
// 2a. Assert: value.[[BigIntData]] is a BigInt value.
// 2b. Return value.[[BigIntData]].
Object* data = JSValue::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);
}
} // namespace
BUILTIN(BigIntPrototypeToString) {
HandleScope scope(isolate);
// 1. Let x be ? thisBigIntValue(this value).
Handle<BigInt> x;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, x,
ThisBigIntValue(isolate, args.receiver(), "BigInt.prototype.toString"));
// 2. If radix is not present, let radixNumber be 10.
// 3. Else if radix is undefined, let radixNumber be 10.
Handle<Object> radix = args.atOrUndefined(isolate, 1);
int radix_number;
if (radix->IsUndefined(isolate)) {
radix_number = 10;
} else {
// 4. Else, let radixNumber be ? ToInteger(radix).
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix,
Object::ToInteger(isolate, radix));
radix_number = static_cast<int>(radix->Number());
}
// 5. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
if (radix_number < 2 || radix_number > 36) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kToRadixFormatRange));
}
// Return the String representation of this Number value using the radix
// specified by radixNumber.
RETURN_RESULT_OR_FAILURE(isolate, BigInt::ToString(x, radix_number));
}
BUILTIN(BigIntPrototypeValueOf) {
HandleScope scope(isolate);
RETURN_RESULT_OR_FAILURE(
isolate,
ThisBigIntValue(isolate, args.receiver(), "BigInt.prototype.valueOf"));
}
} // namespace internal
} // namespace v8
...@@ -328,6 +328,16 @@ namespace internal { ...@@ -328,6 +328,16 @@ namespace internal {
TFJ(AsyncFunctionPromiseCreate, 0) \ TFJ(AsyncFunctionPromiseCreate, 0) \
TFJ(AsyncFunctionPromiseRelease, 1, kPromise) \ TFJ(AsyncFunctionPromiseRelease, 1, kPromise) \
\ \
/* BigInt */ \
CPP(BigIntConstructor) \
CPP(BigIntConstructor_ConstructStub) \
CPP(BigIntParseInt) \
CPP(BigIntAsUintN) \
CPP(BigIntAsIntN) \
CPP(BigIntPrototypeToLocaleString) \
CPP(BigIntPrototypeToString) \
CPP(BigIntPrototypeValueOf) \
\
/* Boolean */ \ /* Boolean */ \
CPP(BooleanConstructor) \ CPP(BooleanConstructor) \
CPP(BooleanConstructor_ConstructStub) \ CPP(BooleanConstructor_ConstructStub) \
......
...@@ -226,6 +226,7 @@ enum ContextLookupFlags { ...@@ -226,6 +226,7 @@ enum ContextLookupFlags {
V(ASYNC_GENERATOR_RETURN_CLOSED_REJECT_SHARED_FUN, SharedFunctionInfo, \ V(ASYNC_GENERATOR_RETURN_CLOSED_REJECT_SHARED_FUN, SharedFunctionInfo, \
async_generator_return_closed_reject_shared_fun) \ async_generator_return_closed_reject_shared_fun) \
V(ATOMICS_OBJECT, JSObject, atomics_object) \ V(ATOMICS_OBJECT, JSObject, atomics_object) \
V(BIGINT_FUNCTION_INDEX, JSFunction, bigint_function) \
V(BOOLEAN_FUNCTION_INDEX, JSFunction, boolean_function) \ V(BOOLEAN_FUNCTION_INDEX, JSFunction, boolean_function) \
V(BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX, Map, \ V(BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX, Map, \
bound_function_with_constructor_map) \ bound_function_with_constructor_map) \
......
...@@ -123,7 +123,7 @@ Handle<BigInt> BigInt::BitwiseOr(Handle<BigInt> x, Handle<BigInt> y) { ...@@ -123,7 +123,7 @@ Handle<BigInt> BigInt::BitwiseOr(Handle<BigInt> x, Handle<BigInt> y) {
UNIMPLEMENTED(); // TODO(jkummerow): Implement. UNIMPLEMENTED(); // TODO(jkummerow): Implement.
} }
Handle<String> BigInt::ToString(Handle<BigInt> bigint, int radix) { MaybeHandle<String> BigInt::ToString(Handle<BigInt> bigint, int radix) {
// TODO(jkummerow): Support non-power-of-two radixes. // TODO(jkummerow): Support non-power-of-two radixes.
if (!base::bits::IsPowerOfTwo(radix)) radix = 16; if (!base::bits::IsPowerOfTwo(radix)) radix = 16;
return ToStringBasePowerOfTwo(bigint, radix); return ToStringBasePowerOfTwo(bigint, radix);
...@@ -248,9 +248,10 @@ void BigInt::RightTrim() { ...@@ -248,9 +248,10 @@ void BigInt::RightTrim() {
static const char kConversionChars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; static const char kConversionChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
// TODO(jkummerow): Add more tests for this when it is exposed on // TODO(jkummerow): Add more tests for this when we have a way to construct
// BigInt.prototype. // multi-digit BigInts.
Handle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x, int radix) { MaybeHandle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x,
int radix) {
STATIC_ASSERT(base::bits::IsPowerOfTwo(kDigitBits)); STATIC_ASSERT(base::bits::IsPowerOfTwo(kDigitBits));
DCHECK(base::bits::IsPowerOfTwo(radix)); DCHECK(base::bits::IsPowerOfTwo(radix));
DCHECK(radix >= 2 && radix <= 32); DCHECK(radix >= 2 && radix <= 32);
......
...@@ -60,7 +60,7 @@ class BigInt : public HeapObject { ...@@ -60,7 +60,7 @@ class BigInt : public HeapObject {
} }
void Initialize(int length, bool zero_initialize); void Initialize(int length, bool zero_initialize);
static Handle<String> ToString(Handle<BigInt> bigint, int radix); static MaybeHandle<String> ToString(Handle<BigInt> bigint, int radix);
// Temporarily exposed helper, pending proper initialization. // Temporarily exposed helper, pending proper initialization.
void set_value(int value) { void set_value(int value) {
...@@ -100,7 +100,8 @@ class BigInt : public HeapObject { ...@@ -100,7 +100,8 @@ class BigInt : public HeapObject {
// abs(x) < abs(y), or zero if abs(x) == abs(y). // abs(x) < abs(y), or zero if abs(x) == abs(y).
static int AbsoluteCompare(Handle<BigInt> x, Handle<BigInt> y); static int AbsoluteCompare(Handle<BigInt> x, Handle<BigInt> y);
static Handle<String> ToStringBasePowerOfTwo(Handle<BigInt> x, int radix); static MaybeHandle<String> ToStringBasePowerOfTwo(Handle<BigInt> x,
int radix);
// Digit arithmetic helpers. // Digit arithmetic helpers.
static inline digit_t digit_add(digit_t a, digit_t b, digit_t* carry); static inline digit_t digit_add(digit_t a, digit_t b, digit_t* carry);
......
...@@ -12,28 +12,6 @@ ...@@ -12,28 +12,6 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
RUNTIME_FUNCTION(Runtime_BigInt) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_SMI_ARG_CHECKED(value, 0);
// For the moment, this is the only way to create a BigInt.
// Since we currently don't want ClusterFuzz to generate BigInts, we always
// throw here if the --harmony-bigint flag is disabled. (All --harmony-* flags
// are blacklisted for ClusterFuzz.)
if (!FLAG_harmony_bigint) {
THROW_NEW_ERROR_RETURN_FAILURE(isolate,
NewTypeError(MessageTemplate::kUnsupported));
}
if (value == 0) return *isolate->factory()->NewBigInt(0);
Handle<BigInt> result = isolate->factory()->NewBigInt(1);
result->set_value(value);
return *result;
}
RUNTIME_FUNCTION(Runtime_BigIntEqual) { RUNTIME_FUNCTION(Runtime_BigIntEqual) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());
......
...@@ -69,7 +69,6 @@ namespace internal { ...@@ -69,7 +69,6 @@ namespace internal {
F(SetAllowAtomicsWait, 1, 1) F(SetAllowAtomicsWait, 1, 1)
#define FOR_EACH_INTRINSIC_BIGINT(F) \ #define FOR_EACH_INTRINSIC_BIGINT(F) \
F(BigInt, 1, 1) \
F(BigIntEqual, 2, 1) \ F(BigIntEqual, 2, 1) \
F(BigIntToBoolean, 1, 1) F(BigIntToBoolean, 1, 1)
......
...@@ -622,6 +622,7 @@ ...@@ -622,6 +622,7 @@
'builtins/builtins-api.cc', 'builtins/builtins-api.cc',
'builtins/builtins-arraybuffer.cc', 'builtins/builtins-arraybuffer.cc',
'builtins/builtins-array.cc', 'builtins/builtins-array.cc',
'builtins/builtins-bigint.cc',
'builtins/builtins-boolean.cc', 'builtins/builtins-boolean.cc',
'builtins/builtins-call.cc', 'builtins/builtins-call.cc',
'builtins/builtins-callsite.cc', 'builtins/builtins-callsite.cc',
......
...@@ -6,10 +6,15 @@ ...@@ -6,10 +6,15 @@
'use strict' 'use strict'
const zero = %BigInt(0); const zero = BigInt(0);
const another_zero = %BigInt(0); const another_zero = BigInt(0);
const one = %BigInt(1); const one = BigInt(1);
const another_one = %BigInt(1); const another_one = BigInt(1);
// BigInt
{
assertSame(BigInt, BigInt.prototype.constructor)
}
// typeof // typeof
{ {
...@@ -32,6 +37,31 @@ const another_one = %BigInt(1); ...@@ -32,6 +37,31 @@ const another_one = %BigInt(1);
assertEquals(String(one), "1"); assertEquals(String(one), "1");
} }
// .toString(radix)
{
// assertEquals(expected, BigInt(input).toString(n)) is generated by:
// input = $(python -c "print(int('expected', n))")
assertEquals("hello", BigInt(18306744).toString(32));
assertEquals("-hello", BigInt(-18306744).toString(32));
assertEquals("abcde", BigInt(0xabcde).toString(16));
assertEquals("-abcde", BigInt(-0xabcde).toString(16));
assertEquals("1234567", BigInt(342391).toString(8));
assertEquals("-1234567", BigInt(-342391).toString(8));
assertEquals("1230123", BigInt(6939).toString(4));
assertEquals("-1230123", BigInt(-6939).toString(4));
assertEquals("1011001110001", BigInt(5745).toString(2));
assertEquals("-1011001110001", BigInt(-5745).toString(2));
}
// .valueOf
{
assertEquals(Object(zero).valueOf(), another_zero);
assertThrows(() => { return BigInt.prototype.valueOf.call("string"); },
TypeError);
// TODO(jkummerow): Add tests for (new BigInt(...)).valueOf() when we
// can construct BigInt wrappers.
}
// ToBoolean // ToBoolean
{ {
assertTrue(!zero); assertTrue(!zero);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment