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") {
"src/builtins/builtins-api.cc",
"src/builtins/builtins-array.cc",
"src/builtins/builtins-arraybuffer.cc",
"src/builtins/builtins-bigint.cc",
"src/builtins/builtins-boolean.cc",
"src/builtins/builtins-call.cc",
"src/builtins/builtins-callsite.cc",
......
......@@ -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_restrict_constructor_return)
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,
const char* name, Handle<Symbol> value) {
......@@ -4345,6 +4344,50 @@ void Genesis::InitializeGlobal_harmony_regexp_dotall() {
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
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 {
TFJ(AsyncFunctionPromiseCreate, 0) \
TFJ(AsyncFunctionPromiseRelease, 1, kPromise) \
\
/* BigInt */ \
CPP(BigIntConstructor) \
CPP(BigIntConstructor_ConstructStub) \
CPP(BigIntParseInt) \
CPP(BigIntAsUintN) \
CPP(BigIntAsIntN) \
CPP(BigIntPrototypeToLocaleString) \
CPP(BigIntPrototypeToString) \
CPP(BigIntPrototypeValueOf) \
\
/* Boolean */ \
CPP(BooleanConstructor) \
CPP(BooleanConstructor_ConstructStub) \
......
......@@ -226,6 +226,7 @@ enum ContextLookupFlags {
V(ASYNC_GENERATOR_RETURN_CLOSED_REJECT_SHARED_FUN, SharedFunctionInfo, \
async_generator_return_closed_reject_shared_fun) \
V(ATOMICS_OBJECT, JSObject, atomics_object) \
V(BIGINT_FUNCTION_INDEX, JSFunction, bigint_function) \
V(BOOLEAN_FUNCTION_INDEX, JSFunction, boolean_function) \
V(BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX, Map, \
bound_function_with_constructor_map) \
......
......@@ -123,7 +123,7 @@ Handle<BigInt> BigInt::BitwiseOr(Handle<BigInt> x, Handle<BigInt> y) {
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.
if (!base::bits::IsPowerOfTwo(radix)) radix = 16;
return ToStringBasePowerOfTwo(bigint, radix);
......@@ -248,9 +248,10 @@ void BigInt::RightTrim() {
static const char kConversionChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
// TODO(jkummerow): Add more tests for this when it is exposed on
// BigInt.prototype.
Handle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x, int radix) {
// TODO(jkummerow): Add more tests for this when we have a way to construct
// multi-digit BigInts.
MaybeHandle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x,
int radix) {
STATIC_ASSERT(base::bits::IsPowerOfTwo(kDigitBits));
DCHECK(base::bits::IsPowerOfTwo(radix));
DCHECK(radix >= 2 && radix <= 32);
......
......@@ -60,7 +60,7 @@ class BigInt : public HeapObject {
}
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.
void set_value(int value) {
......@@ -100,7 +100,8 @@ class BigInt : public HeapObject {
// abs(x) < abs(y), or zero if abs(x) == abs(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.
static inline digit_t digit_add(digit_t a, digit_t b, digit_t* carry);
......
......@@ -12,28 +12,6 @@
namespace v8 {
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) {
SealHandleScope shs(isolate);
DCHECK_EQ(2, args.length());
......
......@@ -69,7 +69,6 @@ namespace internal {
F(SetAllowAtomicsWait, 1, 1)
#define FOR_EACH_INTRINSIC_BIGINT(F) \
F(BigInt, 1, 1) \
F(BigIntEqual, 2, 1) \
F(BigIntToBoolean, 1, 1)
......
......@@ -622,6 +622,7 @@
'builtins/builtins-api.cc',
'builtins/builtins-arraybuffer.cc',
'builtins/builtins-array.cc',
'builtins/builtins-bigint.cc',
'builtins/builtins-boolean.cc',
'builtins/builtins-call.cc',
'builtins/builtins-callsite.cc',
......
......@@ -6,10 +6,15 @@
'use strict'
const zero = %BigInt(0);
const another_zero = %BigInt(0);
const one = %BigInt(1);
const another_one = %BigInt(1);
const zero = BigInt(0);
const another_zero = BigInt(0);
const one = BigInt(1);
const another_one = BigInt(1);
// BigInt
{
assertSame(BigInt, BigInt.prototype.constructor)
}
// typeof
{
......@@ -32,6 +37,31 @@ const another_one = %BigInt(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
{
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