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

[bigint] Expose BigInt on the API

Bug: v8:6791, v8:7486
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I733d0fb886c42928816fe570712ed23f41c8e751
Reviewed-on: https://chromium-review.googlesource.com/938945Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51664}
parent 40a3e6dc
......@@ -66,6 +66,8 @@ namespace v8 {
class AccessorSignature;
class Array;
class ArrayBuffer;
class BigInt;
class BigIntObject;
class Boolean;
class BooleanObject;
class Context;
......@@ -2151,6 +2153,11 @@ class V8_EXPORT Value : public Data {
*/
bool IsObject() const;
/**
* Returns true if this value is a bigint.
*/
bool IsBigInt() const;
/**
* Returns true if this value is boolean.
*/
......@@ -2186,6 +2193,11 @@ class V8_EXPORT Value : public Data {
*/
bool IsArgumentsObject() const;
/**
* Returns true if this value is a BigInt object.
*/
bool IsBigIntObject() const;
/**
* Returns true if this value is a Boolean object.
*/
......@@ -2354,6 +2366,8 @@ class V8_EXPORT Value : public Data {
bool IsWebAssemblyCompiledModule() const;
V8_WARN_UNUSED_RESULT MaybeLocal<BigInt> ToBigInt(
Local<Context> context) const;
V8_WARN_UNUSED_RESULT MaybeLocal<Boolean> ToBoolean(
Local<Context> context) const;
V8_WARN_UNUSED_RESULT MaybeLocal<Number> ToNumber(
......@@ -3005,6 +3019,19 @@ class V8_EXPORT Uint32 : public Integer {
static void CheckCast(v8::Value* obj);
};
/**
* A JavaScript BigInt value (https://tc39.github.io/proposal-bigint)
*/
class V8_EXPORT BigInt : public Primitive {
public:
static Local<BigInt> New(Isolate* isolate, int64_t value);
V8_INLINE static BigInt* Cast(v8::Value* obj);
private:
BigInt();
static void CheckCast(v8::Value* obj);
};
/**
* PropertyAttribute.
*/
......@@ -4874,6 +4901,20 @@ class V8_EXPORT NumberObject : public Object {
static void CheckCast(Value* obj);
};
/**
* A BigInt object (https://tc39.github.io/proposal-bigint)
*/
class V8_EXPORT BigIntObject : public Object {
public:
static Local<Value> New(Isolate* isolate, int64_t value);
Local<BigInt> ValueOf() const;
V8_INLINE static BigIntObject* Cast(Value* obj);
private:
static void CheckCast(Value* obj);
};
/**
* A Boolean object (ECMA-262, 4.3.15).
......@@ -9848,6 +9889,12 @@ Uint32* Uint32::Cast(v8::Value* value) {
return static_cast<Uint32*>(value);
}
BigInt* BigInt::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<BigInt*>(value);
}
Date* Date::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
......@@ -9880,6 +9927,12 @@ NumberObject* NumberObject::Cast(v8::Value* value) {
return static_cast<NumberObject*>(value);
}
BigIntObject* BigIntObject::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<BigIntObject*>(value);
}
BooleanObject* BooleanObject::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
......
......@@ -3478,6 +3478,7 @@ bool Value::IsNumber() const {
return Utils::OpenHandle(this)->IsNumber();
}
bool Value::IsBigInt() const { return Utils::OpenHandle(this)->IsBigInt(); }
bool Value::IsProxy() const { return Utils::OpenHandle(this)->IsJSProxy(); }
......@@ -3496,6 +3497,7 @@ bool Value::IsWebAssemblyCompiledModule() const {
}
VALUE_IS_SPECIFIC_TYPE(ArgumentsObject, JSArgumentsObject)
VALUE_IS_SPECIFIC_TYPE(BigIntObject, BigIntWrapper)
VALUE_IS_SPECIFIC_TYPE(BooleanObject, BooleanWrapper)
VALUE_IS_SPECIFIC_TYPE(NumberObject, NumberWrapper)
VALUE_IS_SPECIFIC_TYPE(StringObject, StringWrapper)
......@@ -3628,6 +3630,16 @@ Local<v8::Object> Value::ToObject(Isolate* isolate) const {
RETURN_TO_LOCAL_UNCHECKED(ToObject(isolate->GetCurrentContext()), Object);
}
MaybeLocal<BigInt> Value::ToBigInt(Local<Context> context) const {
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsBigInt()) return ToApiHandle<BigInt>(obj);
PREPARE_FOR_EXECUTION(context, Object, ToBigInt, BigInt);
Local<BigInt> result;
has_pending_exception =
!ToLocal<BigInt>(i::BigInt::FromObject(isolate, obj), &result);
RETURN_ON_FAILED_EXECUTION(BigInt);
RETURN_ESCAPED(result);
}
MaybeLocal<Boolean> Value::ToBoolean(Local<Context> context) const {
auto obj = Utils::OpenHandle(this);
......@@ -3795,6 +3807,10 @@ void v8::Uint32::CheckCast(v8::Value* that) {
"Could not convert to 32-bit unsigned integer");
}
void v8::BigInt::CheckCast(v8::Value* that) {
Utils::ApiCheck(that->IsBigInt(), "v8::BigInt::Cast",
"Could not convert to BigInt");
}
void v8::Array::CheckCast(Value* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
......@@ -3921,6 +3937,11 @@ void v8::NumberObject::CheckCast(v8::Value* that) {
"Could not convert to NumberObject");
}
void v8::BigIntObject::CheckCast(v8::Value* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
Utils::ApiCheck(obj->IsBigIntWrapper(), "v8::BigIntObject::Cast()",
"Could not convert to BigIntObject");
}
void v8::BooleanObject::CheckCast(v8::Value* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
......@@ -6875,6 +6896,25 @@ double v8::NumberObject::ValueOf() const {
return jsvalue->value()->Number();
}
Local<v8::Value> v8::BigIntObject::New(Isolate* isolate, int64_t value) {
CHECK(i::FLAG_harmony_bigint);
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, BigIntObject, New);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
i::Handle<i::Object> bigint = i::BigInt::FromInt64(i_isolate, value);
i::Handle<i::Object> obj =
i::Object::ToObject(i_isolate, bigint).ToHandleChecked();
return Utils::ToLocal(obj);
}
Local<v8::BigInt> v8::BigIntObject::ValueOf() const {
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
i::Isolate* isolate = jsvalue->GetIsolate();
LOG_API(isolate, BigIntObject, BigIntValue);
return Utils::ToLocal(
i::Handle<i::BigInt>(i::BigInt::cast(jsvalue->value())));
}
Local<v8::Value> v8::BooleanObject::New(Isolate* isolate, bool value) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
......@@ -8049,6 +8089,13 @@ Local<Integer> v8::Integer::NewFromUnsigned(Isolate* isolate, uint32_t value) {
return Utils::IntegerToLocal(result);
}
Local<BigInt> v8::BigInt::New(Isolate* isolate, int64_t value) {
CHECK(i::FLAG_harmony_bigint);
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(internal_isolate);
i::Handle<i::BigInt> result = i::BigInt::FromInt64(internal_isolate, value);
return Utils::ToLocal(result);
}
void Isolate::ReportExternalAllocationLimitReached() {
i::Heap* heap = reinterpret_cast<i::Isolate*>(this)->heap();
......
......@@ -202,6 +202,8 @@ class Utils {
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<Uint32> Uint32ToLocal(
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<BigInt> ToLocal(
v8::internal::Handle<v8::internal::BigInt> obj);
static inline Local<FunctionTemplate> ToLocal(
v8::internal::Handle<v8::internal::FunctionTemplateInfo> obj);
static inline Local<ObjectTemplate> ToLocal(
......@@ -333,6 +335,7 @@ MAKE_TO_LOCAL(StackFrameToLocal, StackFrameInfo, StackFrame)
MAKE_TO_LOCAL(NumberToLocal, Object, Number)
MAKE_TO_LOCAL(IntegerToLocal, Object, Integer)
MAKE_TO_LOCAL(Uint32ToLocal, Object, Uint32)
MAKE_TO_LOCAL(ToLocal, BigInt, BigInt);
MAKE_TO_LOCAL(ExternalToLocal, JSObject, External)
MAKE_TO_LOCAL(CallableToLocal, JSReceiver, Function)
MAKE_TO_LOCAL(ToLocalPrimitive, Object, Primitive)
......
......@@ -201,6 +201,7 @@ enum class ObjectType {
#undef ENUM_STRUCT_ELEMENT
class AccessCheckNeeded;
class BigIntWrapper;
class ClassBoilerplate;
class BooleanWrapper;
class CompilationCacheTable;
......
......@@ -694,6 +694,8 @@ class RuntimeCallTimer final {
V(Array_New) \
V(BigInt64Array_New) \
V(BigUint64Array_New) \
V(BigIntObject_New) \
V(BigIntObject_BigIntValue) \
V(BooleanObject_BooleanValue) \
V(BooleanObject_New) \
V(Context_New) \
......@@ -767,6 +769,7 @@ class RuntimeCallTimer final {
V(ObjectTemplate_New) \
V(ObjectTemplate_NewInstance) \
V(Object_ToArrayIndex) \
V(Object_ToBigInt) \
V(Object_ToDetailString) \
V(Object_ToInt32) \
V(Object_ToInteger) \
......
......@@ -429,6 +429,10 @@ bool HeapObject::IsNumberWrapper() const {
return IsJSValue() && JSValue::cast(this)->value()->IsNumber();
}
bool HeapObject::IsBigIntWrapper() const {
return IsJSValue() && JSValue::cast(this)->value()->IsBigInt();
}
bool HeapObject::IsSymbolWrapper() const {
return IsJSValue() && JSValue::cast(this)->value()->IsSymbol();
}
......
......@@ -997,6 +997,7 @@ template <class C> inline bool Is(Object* obj);
V(AccessCheckNeeded) \
V(ArrayList) \
V(BigInt) \
V(BigIntWrapper) \
V(BoilerplateDescription) \
V(Boolean) \
V(BooleanWrapper) \
......
......@@ -15,6 +15,8 @@
namespace v8 {
namespace internal {
class BigInt;
// BigIntBase is just the raw data object underlying a BigInt. Use with care!
// Most code should be using BigInts instead.
class BigIntBase : public HeapObject {
......@@ -38,7 +40,7 @@ class BigIntBase : public HeapObject {
static const int kHeaderSize = kDigitsOffset;
private:
friend class BigInt;
friend class ::v8::internal::BigInt; // MSVC wants full namespace.
friend class MutableBigInt;
typedef uintptr_t digit_t;
......
......@@ -1769,6 +1769,36 @@ THREADED_TEST(NumberObject) {
CHECK_EQ(43.0, the_number);
}
THREADED_TEST(BigIntObject) {
v8::internal::FLAG_harmony_bigint = true;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context(env.local());
v8::Local<Value> boxed_bigint = CompileRun("new Object(42n)");
CHECK(!boxed_bigint->IsBigInt());
CHECK(boxed_bigint->IsBigIntObject());
v8::Local<Value> unboxed_bigint = CompileRun("42n");
CHECK(unboxed_bigint->IsBigInt());
CHECK(!unboxed_bigint->IsBigIntObject());
v8::Local<v8::BigIntObject> as_boxed = boxed_bigint.As<v8::BigIntObject>();
CHECK(!as_boxed.IsEmpty());
v8::Local<v8::BigInt> unpacked = as_boxed->ValueOf();
CHECK(!unpacked.IsEmpty());
v8::Local<v8::Value> new_boxed_bigint = v8::BigIntObject::New(isolate, 43);
CHECK(new_boxed_bigint->IsBigIntObject());
v8::Local<v8::Value> new_unboxed_bigint = v8::BigInt::New(isolate, 44);
CHECK(new_unboxed_bigint->IsBigInt());
// Test functionality inherited from v8::Value.
CHECK(unboxed_bigint->BooleanValue(context).ToChecked());
v8::Local<v8::String> string =
unboxed_bigint->ToString(context).ToLocalChecked();
CHECK_EQ(0, strcmp("42", *v8::String::Utf8Value(isolate, string)));
// IntegerValue throws.
CHECK(unboxed_bigint->IntegerValue(context).IsNothing());
}
THREADED_TEST(BooleanObject) {
LocalContext env;
......
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