mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-26 00:57:30 +09:00
Issue #1240 - Part 2 - Define the BigIntObject class for BigInt wrapper objects. Based on https://bugzilla.mozilla.org/show_bug.cgi?id=1366287 Part 3. In our Part 3 we will fast forward to the V8 implementation skipping GMP.
This commit is contained in:
parent
f041afc61d
commit
13ac0d6483
15 changed files with 338 additions and 9 deletions
|
|
@ -1100,6 +1100,7 @@ enum class ESClass {
|
|||
SetIterator,
|
||||
Arguments,
|
||||
Error,
|
||||
BigInt,
|
||||
|
||||
/** None of the above. */
|
||||
Other
|
||||
|
|
|
|||
184
js/src/builtin/BigInt.cpp
Normal file
184
js/src/builtin/BigInt.cpp
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "builtin/BigInt.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "builtin/TypedObject.h"
|
||||
#include "gc/Tracer.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "vm/ArrayBufferObject.h"
|
||||
#include "vm/BigIntType.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
#include "vm/TaggedProto.h"
|
||||
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
IsBigInt(HandleValue v)
|
||||
{
|
||||
return v.isBigInt() || (v.isObject() && v.toObject().is<BigIntObject>());
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
CreateBigIntPrototype(JSContext* cx, JSProtoKey key)
|
||||
{
|
||||
return GlobalObject::createBlankPrototype<PlainObject>(cx, cx->global());
|
||||
}
|
||||
|
||||
// BigInt proposal section 5.1.3
|
||||
static bool
|
||||
BigIntConstructor(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Step 1.
|
||||
if (args.isConstructing()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_CONSTRUCTOR, "BigInt");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 2.
|
||||
RootedValue v(cx, args.get(0));
|
||||
if (!ToPrimitive(cx, JSTYPE_NUMBER, &v))
|
||||
return false;
|
||||
|
||||
// Steps 3-4.
|
||||
BigInt* bi = v.isNumber()
|
||||
? NumberToBigInt(cx, v.toNumber())
|
||||
: ToBigInt(cx, v);
|
||||
if (!bi)
|
||||
return false;
|
||||
|
||||
args.rval().setBigInt(bi);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
BigIntObject::create(JSContext* cx, HandleBigInt bigInt)
|
||||
{
|
||||
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
BigIntObject& bn = obj->as<BigIntObject>();
|
||||
bn.setFixedSlot(PRIMITIVE_VALUE_SLOT, BigIntValue(bigInt));
|
||||
return &bn;
|
||||
}
|
||||
|
||||
BigInt*
|
||||
BigIntObject::unbox() const
|
||||
{
|
||||
return getFixedSlot(PRIMITIVE_VALUE_SLOT).toBigInt();
|
||||
}
|
||||
|
||||
bool
|
||||
js::intrinsic_ToBigInt(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
|
||||
BigInt* result = ToBigInt(cx, args[0]);
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
args.rval().setBigInt(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// BigInt proposal section 5.3.4
|
||||
bool
|
||||
BigIntObject::valueOf_impl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
// Step 1.
|
||||
HandleValue thisv = args.thisv();
|
||||
MOZ_ASSERT(IsBigInt(thisv));
|
||||
RootedBigInt bi(cx, thisv.isBigInt()
|
||||
? thisv.toBigInt()
|
||||
: thisv.toObject().as<BigIntObject>().unbox());
|
||||
|
||||
args.rval().setBigInt(bi);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BigIntObject::valueOf(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsBigInt, valueOf_impl>(cx, args);
|
||||
}
|
||||
|
||||
// BigInt proposal section 5.3.3
|
||||
bool
|
||||
BigIntObject::toString_impl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
// Step 1.
|
||||
HandleValue thisv = args.thisv();
|
||||
MOZ_ASSERT(IsBigInt(thisv));
|
||||
RootedBigInt bi(cx, thisv.isBigInt()
|
||||
? thisv.toBigInt()
|
||||
: thisv.toObject().as<BigIntObject>().unbox());
|
||||
|
||||
// Steps 2-3.
|
||||
uint8_t radix = 10;
|
||||
|
||||
// Steps 4-5.
|
||||
if (args.hasDefined(0)) {
|
||||
double d;
|
||||
if (!ToInteger(cx, args[0], &d))
|
||||
return false;
|
||||
if (d < 2 || d > 36) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_RADIX);
|
||||
return false;
|
||||
}
|
||||
radix = d;
|
||||
}
|
||||
|
||||
// Steps 6-7.
|
||||
JSLinearString* str = BigInt::toString(cx, bi, radix);
|
||||
if (!str)
|
||||
return false;
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BigIntObject::toString(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsBigInt, toString_impl>(cx, args);
|
||||
}
|
||||
|
||||
const ClassSpec BigIntObject::classSpec_ = {
|
||||
GenericCreateConstructor<BigIntConstructor, 1, gc::AllocKind::FUNCTION>,
|
||||
CreateBigIntPrototype,
|
||||
nullptr,
|
||||
nullptr,
|
||||
BigIntObject::methods,
|
||||
BigIntObject::properties
|
||||
};
|
||||
|
||||
const Class BigIntObject::class_ = {
|
||||
"BigInt",
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt) |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
|
||||
JS_NULL_CLASS_OPS,
|
||||
&BigIntObject::classSpec_
|
||||
};
|
||||
|
||||
const JSPropertySpec BigIntObject::properties[] = {
|
||||
// BigInt proposal section 5.3.5
|
||||
JS_STRING_SYM_PS(toStringTag, "BigInt", JSPROP_READONLY),
|
||||
JS_PS_END
|
||||
};
|
||||
|
||||
const JSFunctionSpec BigIntObject::methods[] = {
|
||||
JS_FN("valueOf", valueOf, 0, 0),
|
||||
JS_FN("toString", toString, 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
51
js/src/builtin/BigInt.h
Normal file
51
js/src/builtin/BigInt.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef builtin_BigInt_h
|
||||
#define builtin_BigInt_h
|
||||
|
||||
#include "js/Class.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "vm/BigIntType.h"
|
||||
#include "vm/NativeObject.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
class BigIntObject : public NativeObject
|
||||
{
|
||||
static const unsigned PRIMITIVE_VALUE_SLOT = 0;
|
||||
static const unsigned RESERVED_SLOTS = 1;
|
||||
|
||||
public:
|
||||
static const ClassSpec classSpec_;
|
||||
static const Class class_;
|
||||
|
||||
static JSObject* create(JSContext* cx, JS::Handle<JS::BigInt*> bi);
|
||||
|
||||
// Methods defined on BigInt.prototype.
|
||||
static bool valueOf_impl(JSContext* cx, const CallArgs& args);
|
||||
static bool valueOf(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
static bool toString_impl(JSContext* cx, const CallArgs& args);
|
||||
static bool toString(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
JS::BigInt* unbox() const;
|
||||
|
||||
private:
|
||||
static const JSPropertySpec properties[];
|
||||
static const JSFunctionSpec methods[];
|
||||
};
|
||||
|
||||
extern JSObject*
|
||||
InitBigIntClass(JSContext* cx, Handle<GlobalObject*> global);
|
||||
|
||||
extern bool
|
||||
intrinsic_ToBigInt(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif
|
||||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "builtin/BigInt.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jsstr.h"
|
||||
|
||||
|
|
@ -471,6 +473,9 @@ js::obj_toString(JSContext* cx, unsigned argc, Value* vp)
|
|||
case ESClass::RegExp:
|
||||
builtinTag = cx->names().objectRegExp;
|
||||
break;
|
||||
case ESClass::BigInt:
|
||||
builtinTag = cx->names().objectBigInt;
|
||||
break;
|
||||
default:
|
||||
if (obj->isCallable()) {
|
||||
// Non-standard: Prevent <object> from showing up as Function.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "builtin/BigInt.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jscompartment.h"
|
||||
#include "jsgc.h"
|
||||
|
|
@ -299,6 +301,8 @@ js::GetBuiltinClass(JSContext* cx, HandleObject obj, ESClass* cls)
|
|||
*cls = ESClass::Arguments;
|
||||
else if (obj->is<ErrorObject>())
|
||||
*cls = ESClass::Error;
|
||||
else if (obj->is<BigIntObject>())
|
||||
*cls = ESClass::BigInt;
|
||||
else
|
||||
*cls = ESClass::Other;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "jswin.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
#include "builtin/BigInt.h"
|
||||
#include "builtin/Eval.h"
|
||||
#include "builtin/Object.h"
|
||||
#include "builtin/SymbolObject.h"
|
||||
|
|
@ -3110,8 +3111,7 @@ js::PrimitiveToObject(JSContext* cx, const Value& v)
|
|||
}
|
||||
MOZ_ASSERT(v.isBigInt());
|
||||
RootedBigInt bigInt(cx, v.toBigInt());
|
||||
// Return nullptr because BigIntObject has not been defined yet.
|
||||
return nullptr;
|
||||
return BigIntObject::create(cx, bigInt);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
#include "mozilla/Range.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
||||
#include "builtin/BigInt.h"
|
||||
|
||||
#include "jsarray.h"
|
||||
#include "jsatom.h"
|
||||
#include "jscntxt.h"
|
||||
|
|
@ -328,6 +330,8 @@ PreprocessValue(JSContext* cx, HandleObject holder, KeyType key, MutableHandleVa
|
|||
} else if (cls == ESClass::Boolean) {
|
||||
if (!Unbox(cx, obj, vp))
|
||||
return false;
|
||||
} else if (cls == ESClass::BigInt) {
|
||||
vp.setBigInt(obj->as<BigIntObject>().unbox());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -626,6 +630,7 @@ Str(JSContext* cx, const Value& v, StringifyContext* scx)
|
|||
return NumberValueToStringBuffer(cx, v, scx->sb);
|
||||
}
|
||||
|
||||
/* Step 10 in the BigInt proposal. */
|
||||
if (v.isBigInt()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BIGINT_NOT_SERIALIZABLE);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@
|
|||
real(Float32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \
|
||||
real(Float64Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \
|
||||
real(Uint8ClampedArray, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \
|
||||
real(BigInt, InitViaClassSpec, OCLASP(BigInt)) \
|
||||
real(Proxy, InitProxyClass, js::ProxyClassPtr) \
|
||||
real(WeakMap, InitWeakMapClass, OCLASP(WeakMap)) \
|
||||
real(Map, InitMapClass, OCLASP(Map)) \
|
||||
|
|
|
|||
|
|
@ -3737,7 +3737,7 @@ js::ToStringSlow(ExclusiveContext* cx, typename MaybeRooted<Value, allowGC>::Han
|
|||
} else if (v.isBigInt()) {
|
||||
if (!allowGC)
|
||||
return nullptr;
|
||||
str = BigInt::toString(cx, v.toBigInt());
|
||||
str = BigInt::toString(cx, v.toBigInt(), 10);
|
||||
} else {
|
||||
MOZ_ASSERT(v.isUndefined());
|
||||
str = cx->names().undefined;
|
||||
|
|
|
|||
|
|
@ -384,6 +384,7 @@ main_deunified_sources = [
|
|||
# instantiations may or may not be needed depending on what it gets bundled
|
||||
# with.
|
||||
SOURCES += [
|
||||
'builtin/BigInt.cpp',
|
||||
'builtin/RegExp.cpp',
|
||||
'frontend/Parser.cpp',
|
||||
'gc/StoreBuffer.cpp',
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "builtin/BigInt.h"
|
||||
#include "gc/Allocator.h"
|
||||
#include "gc/Tracer.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
|
|
@ -18,7 +19,7 @@
|
|||
using namespace js;
|
||||
|
||||
BigInt*
|
||||
BigInt::create(js::ExclusiveContext* cx)
|
||||
BigInt::create(ExclusiveContext* cx)
|
||||
{
|
||||
BigInt* x = Allocate<BigInt>(cx);
|
||||
if (!x)
|
||||
|
|
@ -27,7 +28,51 @@ BigInt::create(js::ExclusiveContext* cx)
|
|||
}
|
||||
|
||||
BigInt*
|
||||
BigInt::copy(js::ExclusiveContext* cx, HandleBigInt x)
|
||||
BigInt::create(ExclusiveContext* cx, double d)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// BigInt proposal section 5.1.1
|
||||
static bool
|
||||
IsInteger(double d)
|
||||
{
|
||||
// Step 1 is an assertion checked by the caller.
|
||||
// Step 2.
|
||||
if (!mozilla::IsFinite(d))
|
||||
return false;
|
||||
|
||||
// Step 3.
|
||||
double i = JS::ToInteger(d);
|
||||
|
||||
// Step 4.
|
||||
if (i != d)
|
||||
return false;
|
||||
|
||||
// Step 5.
|
||||
return true;
|
||||
}
|
||||
|
||||
// BigInt proposal section 5.1.2
|
||||
BigInt*
|
||||
js::NumberToBigInt(ExclusiveContext* cx, double d)
|
||||
{
|
||||
// Step 1 is an assertion checked by the caller.
|
||||
// Step 2.
|
||||
if (!IsInteger(d)) {
|
||||
if(cx->isJSContext()) {
|
||||
JS_ReportErrorNumberASCII(cx->asJSContext(), GetErrorMessage, nullptr,
|
||||
JSMSG_NUMBER_TO_BIGINT);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Step 3.
|
||||
return BigInt::create(cx, d);
|
||||
}
|
||||
|
||||
BigInt*
|
||||
BigInt::copy(ExclusiveContext* cx, HandleBigInt x)
|
||||
{
|
||||
BigInt* bi = create(cx);
|
||||
if (!bi)
|
||||
|
|
@ -35,8 +80,29 @@ BigInt::copy(js::ExclusiveContext* cx, HandleBigInt x)
|
|||
return bi;
|
||||
}
|
||||
|
||||
// BigInt proposal section 7.3
|
||||
BigInt*
|
||||
js::ToBigInt(ExclusiveContext* cx, HandleValue val)
|
||||
{
|
||||
RootedValue v(cx, val);
|
||||
|
||||
if(cx->isJSContext()) {
|
||||
// Step 1.
|
||||
if (!ToPrimitive(cx->asJSContext(), JSTYPE_NUMBER, &v))
|
||||
return nullptr;
|
||||
|
||||
// Step 2.
|
||||
// Boolean and string conversions are not yet supported.
|
||||
if (v.isBigInt())
|
||||
return v.toBigInt();
|
||||
|
||||
JS_ReportErrorNumberASCII(cx->asJSContext(), GetErrorMessage, nullptr, JSMSG_NOT_BIGINT);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSLinearString*
|
||||
BigInt::toString(ExclusiveContext* cx, BigInt* x)
|
||||
BigInt::toString(ExclusiveContext* cx, BigInt* x, uint8_t radix)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -50,7 +116,7 @@ BigInt::finalize(js::FreeOp* fop)
|
|||
JSAtom*
|
||||
js::BigIntToAtom(ExclusiveContext* cx, BigInt* bi)
|
||||
{
|
||||
JSString* str = BigInt::toString(cx, bi);
|
||||
JSString* str = BigInt::toString(cx, bi, 10);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
return AtomizeString(cx, str);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ class BigInt final : public js::gc::TenuredCell
|
|||
// Allocate and initialize a BigInt value
|
||||
static BigInt* create(js::ExclusiveContext* cx);
|
||||
|
||||
static BigInt* create(js::ExclusiveContext* cx, double d);
|
||||
|
||||
static const JS::TraceKind TraceKind = JS::TraceKind::BigInt;
|
||||
|
||||
void traceChildren(JSTracer* trc);
|
||||
|
|
@ -37,10 +39,12 @@ class BigInt final : public js::gc::TenuredCell
|
|||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
static JSLinearString* toString(js::ExclusiveContext* cx, BigInt* x);
|
||||
bool toBoolean();
|
||||
|
||||
static BigInt* copy(js::ExclusiveContext* cx, Handle<BigInt*> x);
|
||||
|
||||
static JSLinearString* toString(js::ExclusiveContext* cx, BigInt* x, uint8_t radix);
|
||||
|
||||
};
|
||||
|
||||
static_assert(sizeof(BigInt) >= js::gc::CellSize,
|
||||
|
|
@ -53,6 +57,11 @@ namespace js {
|
|||
extern JSAtom*
|
||||
BigIntToAtom(ExclusiveContext* cx, JS::BigInt* bi);
|
||||
|
||||
extern JS::BigInt*
|
||||
NumberToBigInt(ExclusiveContext* cx, double d);
|
||||
|
||||
extern JS::BigInt*
|
||||
ToBigInt(ExclusiveContext* cx, JS::Handle<JS::Value> v);
|
||||
} // namespace js
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@
|
|||
macro(objectArguments, objectArguments, "[object Arguments]") \
|
||||
macro(objectArray, objectArray, "[object Array]") \
|
||||
macro(objectBoolean, objectBoolean, "[object Boolean]") \
|
||||
macro(objectBigInt, objectBigInt, "[object BigInt]") \
|
||||
macro(objectDate, objectDate, "[object Date]") \
|
||||
macro(objectError, objectError, "[object Error]") \
|
||||
macro(objectFunction, objectFunction, "[object Function]") \
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "jsweakmap.h"
|
||||
|
||||
#include "builtin/AtomicsObject.h"
|
||||
#include "builtin/BigInt.h"
|
||||
#include "builtin/Eval.h"
|
||||
#include "builtin/MapObject.h"
|
||||
#include "builtin/ModuleObject.h"
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ js::ValueToStringBufferSlow(JSContext* cx, const Value& arg, StringBuffer& sb)
|
|||
return false;
|
||||
}
|
||||
if (v.isBigInt()) {
|
||||
JSString* str = BigInt::toString(cx, v.toBigInt());
|
||||
JSLinearString* str = BigInt::toString(cx, v.toBigInt(), 10);
|
||||
if (!str)
|
||||
return false;
|
||||
return sb.append(str);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue