Bug 1730843 - Part 1 - Add support for empty R&T based on objects r=jandem

This is an alternative implementation to D87232. I didn't implement
object wrappers for these new primitive-like-objects yet, so
`typeof Object(rec)` is currently `"record"` and not `"object"`.

Differential Revision: https://phabricator.services.mozilla.com/D125644
This commit is contained in:
Nicolò Ribaudo 2021-12-20 15:17:16 +00:00
parent 7a7e49b72a
commit ded6c32e63
38 changed files with 598 additions and 12 deletions

View File

@ -133,10 +133,30 @@ def static_js(value):
set_define("MOZ_STATIC_JS", static_js)
# Enable records and tuples
# ===================================================
option(
"--enable-record-tuple",
default=False,
help="Enable records and tuples (and disables JIT)",
)
@depends("--enable-record-tuple")
def enable_record_tuple(value):
if value:
return True
set_config("ENABLE_RECORD_TUPLE", enable_record_tuple)
set_define("ENABLE_RECORD_TUPLE", enable_record_tuple)
# JIT support
# =======================================================
@depends(target)
def jit_default(target):
@depends(target, "--enable-record-tuple")
def jit_default(target, enable_record_tuple):
if enable_record_tuple:
return False
if target.cpu in ("x86", "x86_64", "arm", "aarch64", "mips32", "mips64"):
return True
return False

View File

@ -814,6 +814,11 @@ enum class ESClass {
BigInt,
Function, // Note: Only JSFunction objects.
#ifdef ENABLE_RECORD_TUPLE
Record,
Tuple,
#endif
/** None of the above. */
Other
};

View File

@ -133,7 +133,9 @@
REAL(FinalizationRegistry, OCLASP(FinalizationRegistry)) \
REAL(WeakRef, OCLASP(WeakRef)) \
REAL(Iterator, OCLASP(Iterator)) \
REAL(AsyncIterator, OCLASP(AsyncIterator))
REAL(AsyncIterator, OCLASP(AsyncIterator)) \
IF_RECORD_TUPLE(REAL(Record, (&RecordType::class_))) \
IF_RECORD_TUPLE(REAL(Tuple, (&TupleType::class_)))
#define JS_FOR_PROTOTYPES(REAL, IMAGINARY) \
JS_FOR_PROTOTYPES_(REAL, IMAGINARY, IF_INTL(REAL, IMAGINARY), \

View File

@ -48,6 +48,10 @@ typedef unsigned char Latin1Char;
class JS_PUBLIC_API Symbol;
class JS_PUBLIC_API BigInt;
#ifdef ENABLE_RECORD_TUPLE
class JS_PUBLIC_API RecordType;
class JS_PUBLIC_API TupleType;
#endif
class JS_PUBLIC_API Value;
class JS_PUBLIC_API Compartment;
@ -127,4 +131,15 @@ using MutableHandleVector = MutableHandle<StackGCVector<T>>;
using jsid = JS::PropertyKey;
#ifdef ENABLE_RECORD_TUPLE
// This takes 1 or 2 parameters. ... is just used so that
// it's possible to omit the comma when passing a single
// param:
// IF_RECORD_TUPLE(doThis)
// IF_RECORD_TUPLE(doThis, elseThis)
# define IF_RECORD_TUPLE(x, ...) x
#else
# define IF_RECORD_TUPLE(x, ...) __VA_ARGS__
#endif
#endif /* js_TypeDecls_h */

View File

@ -52,6 +52,9 @@ enum JSValueType : uint8_t {
JSVAL_TYPE_SYMBOL = 0x07,
JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
JSVAL_TYPE_BIGINT = 0x09,
#ifdef ENABLE_RECORD_TUPLE
JSVAL_TYPE_EXTENDED_PRIMITIVE = 0x0b,
#endif
JSVAL_TYPE_OBJECT = 0x0c,
// This type never appears in a Value; it's only an out-of-band value.
@ -70,9 +73,12 @@ enum class ValueType : uint8_t {
Symbol = JSVAL_TYPE_SYMBOL,
PrivateGCThing = JSVAL_TYPE_PRIVATE_GCTHING,
BigInt = JSVAL_TYPE_BIGINT,
#ifdef ENABLE_RECORD_TUPLE
ExtendedPrimitive = JSVAL_TYPE_EXTENDED_PRIMITIVE,
#endif
Object = JSVAL_TYPE_OBJECT,
};
}
} // namespace JS
static_assert(sizeof(JSValueType) == 1,
"compiler typed enum support is apparently buggy");
@ -90,6 +96,10 @@ enum JSValueTag : uint32_t {
JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING,
JSVAL_TAG_BIGINT = JSVAL_TAG_CLEAR | JSVAL_TYPE_BIGINT,
# ifdef ENABLE_RECORD_TUPLE
JSVAL_TAG_EXTENDED_PRIMITIVE =
JSVAL_TAG_CLEAR | JSVAL_TYPE_EXTENDED_PRIMITIVE,
# endif
JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
};
@ -109,6 +119,10 @@ enum JSValueTag : uint32_t {
JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING,
JSVAL_TAG_BIGINT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT,
# ifdef ENABLE_RECORD_TUPLE
JSVAL_TAG_EXTENDED_PRIMITIVE =
JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_EXTENDED_PRIMITIVE,
# endif
JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
};
@ -130,6 +144,10 @@ enum JSValueShiftedTag : uint64_t {
JSVAL_SHIFTED_TAG_PRIVATE_GCTHING =
(uint64_t(JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_BIGINT = (uint64_t(JSVAL_TAG_BIGINT) << JSVAL_TAG_SHIFT),
# ifdef ENABLE_RECORD_TUPLE
JSVAL_SHIFTED_TAG_EXTENDED_PRIMITIVE =
(uint64_t(JSVAL_TYPE_EXTENDED_PRIMITIVE) << JSVAL_TAG_SHIFT),
# endif
JSVAL_SHIFTED_TAG_OBJECT = (uint64_t(JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
};
@ -273,6 +291,7 @@ enum JSWhyMagic {
namespace js {
static inline JS::Value PoisonedObjectValue(uintptr_t poison);
extern bool IsExtendedPrimitive(JSObject& obj);
} // namespace js
namespace JS {
@ -488,10 +507,23 @@ class alignas(8) Value {
void setObject(JSObject& obj) {
MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
#ifdef ENABLE_RECORD_TUPLE
MOZ_ASSERT(!js::IsExtendedPrimitive(obj));
#endif
setObjectNoCheck(&obj);
MOZ_ASSERT(&toObject() == &obj);
}
#ifdef ENABLE_RECORD_TUPLE
void setExtendedPrimitive(JSObject& obj) {
MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
MOZ_ASSERT(js::IsExtendedPrimitive(obj));
asBits_ =
bitsFromTagAndPayload(JSVAL_TAG_EXTENDED_PRIMITIVE, PayloadType(&obj));
MOZ_ASSERT(&toExtendedPrimitive() == &obj);
}
#endif
private:
void setObjectNoCheck(JSObject* obj) {
asBits_ = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj));
@ -668,6 +700,16 @@ class alignas(8) Value {
#endif
}
#ifdef ENABLE_RECORD_TUPLE
bool isExtendedPrimitive() const {
return toTag() == JSVAL_TAG_EXTENDED_PRIMITIVE;
}
#endif
bool hasObjectPayload() const {
return isObject() || IF_RECORD_TUPLE(isExtendedPrimitive(), false);
}
bool isPrimitive() const {
#if defined(JS_NUNBOX32)
return uint32_t(toTag()) < uint32_t(detail::ValueUpperExclPrimitiveTag);
@ -797,6 +839,24 @@ class alignas(8) Value {
#endif
}
#ifdef ENABLE_RECORD_TUPLE
JSObject& toExtendedPrimitive() const {
MOZ_ASSERT(isExtendedPrimitive());
# if defined(JS_PUNBOX64)
MOZ_ASSERT((asBits_ & detail::ValueGCThingPayloadMask) != 0);
# endif
return *unboxGCPointer<JSObject, JSVAL_TAG_EXTENDED_PRIMITIVE>();
}
#endif
JSObject& getObjectPayload() const {
#ifdef ENABLE_RECORD_TUPLE
return isExtendedPrimitive() ? toExtendedPrimitive() : toObject();
#else
return toObject();
#endif
}
js::gc::Cell* toGCThing() const {
MOZ_ASSERT(isGCThing());
#if defined(JS_NUNBOX32)
@ -1005,6 +1065,14 @@ static inline Value ObjectValue(JSObject& obj) {
return v;
}
#ifdef ENABLE_RECORD_TUPLE
static inline Value ExtendedPrimitiveValue(JSObject& obj) {
Value v;
v.setExtendedPrimitive(obj);
return v;
}
#endif
static inline Value MagicValue(JSWhyMagic why) {
Value v;
v.setMagic(why);
@ -1143,6 +1211,10 @@ class WrappedPtrOperations<JS::Value, Wrapper> {
bool isSymbol() const { return value().isSymbol(); }
bool isBigInt() const { return value().isBigInt(); }
bool isObject() const { return value().isObject(); }
#ifdef ENABLE_RECORD_TUPLE
bool isExtendedPrimitive() const { return value().isExtendedPrimitive(); }
#endif
bool hasObjectPayload() const { return value().hasObjectPayload(); }
bool isMagic() const { return value().isMagic(); }
bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
bool isGCThing() const { return value().isGCThing(); }
@ -1162,6 +1234,12 @@ class WrappedPtrOperations<JS::Value, Wrapper> {
JS::BigInt* toBigInt() const { return value().toBigInt(); }
JSObject& toObject() const { return value().toObject(); }
JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
#ifdef ENABLE_RECORD_TUPLE
JSObject& toExtendedPrimitive() const {
return value().toExtendedPrimitive();
}
#endif
JSObject& getObjectPayload() const { return value().getObjectPayload(); }
JS::GCCellPtr toGCCellPtr() const { return value().toGCCellPtr(); }
gc::Cell* toGCThing() const { return value().toGCThing(); }
JS::TraceKind traceKind() const { return value().traceKind(); }
@ -1211,6 +1289,11 @@ class MutableWrappedPtrOperations<JS::Value, Wrapper>
void setBigInt(JS::BigInt* bi) { set(JS::BigIntValue(bi)); }
void setObject(JSObject& obj) { set(JS::ObjectValue(obj)); }
void setObjectOrNull(JSObject* arg) { set(JS::ObjectOrNullValue(arg)); }
#ifdef ENABLE_RECORD_TUPLE
void setExtendedPrimitive(JSObject& obj) {
return set(JS::ExtendedPrimitiveValue(obj));
}
#endif
void setPrivate(void* ptr) { set(JS::PrivateValue(ptr)); }
void setPrivateUint32(uint32_t ui) { set(JS::PrivateUint32Value(ui)); }
void setPrivateGCThing(js::gc::Cell* cell) {
@ -1239,8 +1322,11 @@ auto MapGCThingTyped(const JS::Value& val, F&& f) {
MOZ_ASSERT(gc::IsCellPointerValid(str));
return mozilla::Some(f(str));
}
#ifdef ENABLE_RECORD_TUPLE
case JS::ValueType::ExtendedPrimitive:
#endif
case JS::ValueType::Object: {
JSObject* obj = &val.toObject();
JSObject* obj = &val.getObjectPayload();
MOZ_ASSERT(gc::IsCellPointerValid(obj));
return mozilla::Some(f(obj));
}

View File

@ -50,6 +50,9 @@ using JS::NullValue;
using JS::NumberValue;
using JS::ObjectOrNullValue;
using JS::ObjectValue;
#ifdef ENABLE_RECORD_TUPLE
using JS::ExtendedPrimitiveValue;
#endif
using JS::PrivateGCThingValue;
using JS::PrivateUint32Value;
using JS::PrivateValue;
@ -148,6 +151,11 @@ using JS::Zone;
using JS::BigInt;
#ifdef ENABLE_RECORD_TUPLE
using JS::RecordType;
using JS::TupleType;
#endif
} /* namespace js */
#endif /* NamespaceImports_h */

View File

@ -265,7 +265,7 @@ bool AtomMarkingRuntime::valueIsMarked(Zone* zone, const Value& value) {
return atomIsMarked(zone, value.toSymbol());
}
MOZ_ASSERT_IF(value.isGCThing(), value.isObject() ||
MOZ_ASSERT_IF(value.isGCThing(), value.hasObjectPayload() ||
value.isPrivateGCThing() ||
value.isBigInt());
return true;

View File

@ -2139,6 +2139,9 @@ AttachDecision GetPropIRGenerator::tryAttachPrimitive(ValOperandId valId,
case ValueType::Undefined:
case ValueType::Magic:
return AttachDecision::NoAction;
#ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
#endif
case ValueType::Object:
case ValueType::PrivateGCThing:
MOZ_CRASH("unexpected type");
@ -7836,6 +7839,9 @@ AttachDecision CallIRGenerator::tryAttachObjectIs(HandleFunction callee) {
break;
}
#ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
#endif
case JS::ValueType::Double:
case JS::ValueType::Magic:
case JS::ValueType::PrivateGCThing:
@ -8049,6 +8055,9 @@ AttachDecision CallIRGenerator::tryAttachSetHas(HandleFunction callee) {
break;
}
# ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
# endif
case ValueType::Magic:
case ValueType::PrivateGCThing:
MOZ_CRASH("Unexpected type");
@ -8133,6 +8142,9 @@ AttachDecision CallIRGenerator::tryAttachMapHas(HandleFunction callee) {
break;
}
# ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
# endif
case ValueType::Magic:
case ValueType::PrivateGCThing:
MOZ_CRASH("Unexpected type");
@ -8217,6 +8229,9 @@ AttachDecision CallIRGenerator::tryAttachMapGet(HandleFunction callee) {
break;
}
# ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
# endif
case ValueType::Magic:
case ValueType::PrivateGCThing:
MOZ_CRASH("Unexpected type");

View File

@ -1908,6 +1908,9 @@ bool CacheIRCompiler::emitGuardNonDoubleType(ValOperandId inputId,
case ValueType::Magic:
case ValueType::PrivateGCThing:
case ValueType::Object:
#ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
#endif
MOZ_CRASH("unexpected type");
}

View File

@ -13056,6 +13056,10 @@ void CodeGenerator::emitTypeOfIsObject(MTypeOfIs* mir, Register obj,
case JSTYPE_BOOLEAN:
case JSTYPE_SYMBOL:
case JSTYPE_BIGINT:
#ifdef ENABLE_RECORD_TUPLE
case JSTYPE_RECORD:
case JSTYPE_TUPLE:
#endif
case JSTYPE_LIMIT:
MOZ_CRASH("Primitive type");
}
@ -13114,6 +13118,10 @@ void CodeGenerator::visitTypeOfIsNonPrimitiveV(LTypeOfIsNonPrimitiveV* lir) {
case JSTYPE_BOOLEAN:
case JSTYPE_SYMBOL:
case JSTYPE_BIGINT:
#ifdef ENABLE_RECORD_TUPLE
case JSTYPE_RECORD:
case JSTYPE_TUPLE:
#endif
case JSTYPE_LIMIT:
MOZ_CRASH("Primitive type");
}
@ -13167,6 +13175,10 @@ void CodeGenerator::visitTypeOfIsPrimitive(LTypeOfIsPrimitive* lir) {
case JSTYPE_UNDEFINED:
case JSTYPE_OBJECT:
case JSTYPE_FUNCTION:
#ifdef ENABLE_RECORD_TUPLE
case JSTYPE_RECORD:
case JSTYPE_TUPLE:
#endif
case JSTYPE_LIMIT:
MOZ_CRASH("Non-primitive type");
}

View File

@ -1330,6 +1330,10 @@ void LIRGenerator::visitTypeOfIs(MTypeOfIs* ins) {
return;
}
#ifdef ENABLE_RECORD_TUPLE
case JSTYPE_RECORD:
case JSTYPE_TUPLE:
#endif
case JSTYPE_LIMIT:
break;
}

View File

@ -1342,6 +1342,10 @@ void MTypeOfIs::printOpcode(GenericPrinter& out) const {
case JSTYPE_BIGINT:
name = "bigint";
break;
# ifdef ENABLE_RECORD_TUPLE
case JSTYPE_RECORD:
case JSTYPE_TUPLE:
# endif
case JSTYPE_LIMIT:
MOZ_CRASH("Unexpected type");
}
@ -3832,6 +3836,9 @@ static JSType TypeOfName(JSLinearString* str) {
static constexpr std::array types = {
JSTYPE_UNDEFINED, JSTYPE_OBJECT, JSTYPE_FUNCTION, JSTYPE_STRING,
JSTYPE_NUMBER, JSTYPE_BOOLEAN, JSTYPE_SYMBOL, JSTYPE_BIGINT,
#ifdef ENABLE_RECORD_TUPLE
JSTYPE_RECORD, JSTYPE_TUPLE,
#endif
};
static_assert(types.size() == JSTYPE_LIMIT);
@ -3941,6 +3948,11 @@ bool MCompare::tryFoldTypeOf(bool* result) {
case JSTYPE_LIMIT:
*result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
return true;
#ifdef ENABLE_RECORD_TUPLE
case JSTYPE_RECORD:
case JSTYPE_TUPLE:
MOZ_CRASH("Records and Tuples are not supported yet.");
#endif
}
return false;

View File

@ -1037,6 +1037,9 @@ bool WarpCacheIRTranspiler::emitGuardNonDoubleType(ValOperandId inputId,
case ValueType::Magic:
case ValueType::PrivateGCThing:
case ValueType::Object:
#ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
#endif
break;
}

View File

@ -778,8 +778,8 @@ const char* js::ValueToSourceForError(JSContext* cx, HandleValue val,
}
JSStringBuilder sb(cx);
if (val.isObject()) {
RootedObject valObj(cx, val.toObjectOrNull());
if (val.hasObjectPayload()) {
RootedObject valObj(cx, &val.getObjectPayload());
ESClass cls;
if (!JS::GetBuiltinClass(cx, valObj, &cls)) {
return "<<error determining class of value>>";
@ -791,6 +791,12 @@ const char* js::ValueToSourceForError(JSContext* cx, HandleValue val,
s = "the array buffer ";
} else if (JS_IsArrayBufferViewObject(valObj)) {
s = "the typed array ";
#ifdef ENABLE_RECORD_TUPLE
} else if (cls == ESClass::Record) {
s = "the record ";
} else if (cls == ESClass::Tuple) {
s = "the tuple ";
#endif
} else {
s = "the object ";
}

View File

@ -42,6 +42,10 @@
#include "vm/Realm.h"
#include "vm/StringObject.h"
#include "vm/WrapperObject.h"
#ifdef ENABLE_RECORD_TUPLE
# include "vm/RecordType.h"
# include "vm/TupleType.h"
#endif
#include "vm/Compartment-inl.h" // JS::Compartment::wrap
#include "vm/JSObject-inl.h"
@ -259,6 +263,12 @@ JS_PUBLIC_API bool JS::GetBuiltinClass(JSContext* cx, HandleObject obj,
*cls = ESClass::Error;
} else if (obj->is<BigIntObject>()) {
*cls = ESClass::BigInt;
#ifdef ENABLE_RECORD_TUPLE
} else if (obj->is<RecordType>()) {
*cls = ESClass::Record;
} else if (obj->is<TupleType>()) {
*cls = ESClass::Tuple;
#endif
} else if (obj->is<JSFunction>()) {
*cls = ESClass::Function;
} else {

View File

@ -40,6 +40,10 @@ enum JSType {
JSTYPE_BOOLEAN, /* boolean */
JSTYPE_SYMBOL, /* symbol */
JSTYPE_BIGINT, /* BigInt */
#ifdef ENABLE_RECORD_TUPLE
JSTYPE_RECORD, /* record */
JSTYPE_TUPLE, /* tuple */
#endif
JSTYPE_LIMIT
};

View File

@ -470,6 +470,13 @@ SOURCES += [
"vm/ProfilingStack.cpp",
]
if CONFIG["ENABLE_RECORD_TUPLE"]:
UNIFIED_SOURCES += [
"vm/RecordTupleBoxShared.cpp",
"vm/RecordType.cpp",
"vm/TupleType.cpp",
]
if CONFIG["JS_HAS_INTL_API"]:
UNIFIED_SOURCES += [
"builtin/intl/Collator.cpp",

View File

View File

@ -0,0 +1,14 @@
// |reftest| skip-if(!this.hasOwnProperty("Record"))
assertThrowsInstanceOf(
() => new Record(),
TypeError,
"Record is not a constructor"
);
assertEq(typeof Record(), "record");
//assertEq(typeof Object(Record()), "record");
assertEq(Record() instanceof Record, false);
//assertThrowsInstanceOf(() => Object(Record()) instanceof Record, TypeError);
if (typeof reportCompare === "function") reportCompare(0, 0);

View File

View File

View File

@ -0,0 +1,14 @@
// |reftest| skip-if(!this.hasOwnProperty("Tuple"))
assertThrowsInstanceOf(
() => new Tuple(),
TypeError,
"Tuple is not a constructor"
);
assertEq(typeof Tuple(), "tuple");
//assertEq(typeof Object(Tuple()), "tuple");
assertEq(Tuple() instanceof Tuple, false);
//assertEq(Object(Tuple()) instanceof Tuple, true);
if (typeof reportCompare === "function") reportCompare(0, 0);

View File

View File

@ -363,10 +363,12 @@
MACRO_(objectNull, objectNull, "[object Null]") \
MACRO_(objectNumber, objectNumber, "[object Number]") \
MACRO_(objectObject, objectObject, "[object Object]") \
IF_RECORD_TUPLE(MACRO_(objectRecord, objectRecord, "[object Record]")) \
MACRO_(objectRegExp, objectRegExp, "[object RegExp]") \
MACRO_(objects, objects, "objects") \
MACRO_(objectString, objectString, "[object String]") \
MACRO_(objectSymbol, objectSymbol, "[object Symbol]") \
IF_RECORD_TUPLE(MACRO_(objectTuple, objectTuple, "[object Tuple]")) \
MACRO_(objectUndefined, objectUndefined, "[object Undefined]") \
MACRO_(Object_valueOf, Object_valueOf, "Object_valueOf") \
MACRO2(of, of, "of") \
@ -568,7 +570,9 @@
MACRO_(number, number, "number") \
MACRO_(boolean, boolean, "boolean") \
MACRO_(symbol, symbol, "symbol") \
MACRO_(bigint, bigint, "bigint")
MACRO_(bigint, bigint, "bigint") \
IF_RECORD_TUPLE(MACRO_(record, record, "record")) \
IF_RECORD_TUPLE(MACRO_(tuple, tuple, "tuple"))
#define PROPERTY_NAME_IGNORE(IDPART, ID, TEXT)

View File

@ -65,6 +65,10 @@
#include "vm/SelfHosting.h"
#include "vm/StringObject.h"
#include "wasm/WasmJS.h"
#ifdef ENABLE_RECORD_TUPLE
# include "vm/RecordType.h"
# include "vm/TupleType.h"
#endif
#include "gc/FreeOp-inl.h"
#include "vm/JSObject-inl.h"
@ -150,6 +154,10 @@ bool GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key) {
case JSProto_AsyncFunction:
case JSProto_GeneratorFunction:
case JSProto_AsyncGeneratorFunction:
#ifdef ENABLE_RECORD_TUPLE
case JSProto_Record:
case JSProto_Tuple:
#endif
return false;
case JSProto_WebAssembly:

View File

@ -543,6 +543,24 @@ class GlobalObject : public NativeObject {
return &global->getPrototype(JSProto_BigInt);
}
#ifdef ENABLE_RECORD_TUPLE
static JSObject* getOrCreateRecordPrototype(JSContext* cx,
Handle<GlobalObject*> global) {
if (!ensureConstructor(cx, global, JSProto_Record)) {
return nullptr;
}
return &global->getPrototype(JSProto_Record);
}
static JSObject* getOrCreateTuplePrototype(JSContext* cx,
Handle<GlobalObject*> global) {
if (!ensureConstructor(cx, global, JSProto_Tuple)) {
return nullptr;
}
return &global->getPrototype(JSProto_Tuple);
}
#endif
static JSObject* getOrCreatePromisePrototype(JSContext* cx,
Handle<GlobalObject*> global) {
if (!ensureConstructor(cx, global, JSProto_Promise)) {

View File

@ -63,6 +63,10 @@
#include "vm/StringType.h"
#include "vm/ThrowMsgKind.h" // ThrowMsgKind
#include "vm/TraceLogging.h"
#ifdef ENABLE_RECORD_TUPLE
# include "vm/RecordType.h"
# include "vm/TupleType.h"
#endif
#include "builtin/Boolean-inl.h"
#include "debugger/DebugAPI-inl.h"
@ -811,6 +815,10 @@ bool js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) {
}
JSType js::TypeOfObject(JSObject* obj) {
#ifdef ENABLE_RECORD_TUPLE
MOZ_ASSERT(!js::IsExtendedPrimitive(*obj));
#endif
AutoUnsafeCallWithABI unsafe;
if (EmulatesUndefined(obj)) {
return JSTYPE_UNDEFINED;
@ -821,6 +829,20 @@ JSType js::TypeOfObject(JSObject* obj) {
return JSTYPE_OBJECT;
}
#ifdef ENABLE_RECORD_TUPLE
JSType TypeOfExtendedPrimitive(JSObject* obj) {
MOZ_ASSERT(js::IsExtendedPrimitive(*obj));
if (obj->is<RecordType>()) {
return JSTYPE_RECORD;
}
if (obj->is<TupleType>()) {
return JSTYPE_TUPLE;
}
MOZ_CRASH("Unknown ExtendedPrimitive");
}
#endif
JSType js::TypeOfValue(const Value& v) {
switch (v.type()) {
case ValueType::Double:
@ -834,6 +856,10 @@ JSType js::TypeOfValue(const Value& v) {
return JSTYPE_UNDEFINED;
case ValueType::Object:
return TypeOfObject(&v.toObject());
#ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
return TypeOfExtendedPrimitive(&v.toExtendedPrimitive());
#endif
case ValueType::Boolean:
return JSTYPE_BOOLEAN;
case ValueType::BigInt:
@ -1252,6 +1278,13 @@ again:
REGS.sp++->setObjectOrNull(obj); \
cx->debugOnlyCheck(REGS.sp[-1]); \
} while (0)
#ifdef ENABLE_RECORD_TUPLE
# define PUSH_EXTENDED_PRIMITIVE(obj) \
do { \
REGS.sp++->setExtendedPrimitive(obj); \
cx->debugOnlyCheck(REGS.sp[-1]); \
} while (0)
#endif
#define PUSH_MAGIC(magic) REGS.sp++->setMagic(magic)
#define POP_COPY_TO(v) (v) = *--REGS.sp
#define POP_RETURN_VALUE() REGS.fp()->setReturnValue(*--REGS.sp)
@ -4505,7 +4538,8 @@ bool js::GetProperty(JSContext* cx, HandleValue v, HandlePropertyName name,
// Optimize common cases like (2).toString() or "foo".valueOf() to not
// create a wrapper object.
if (v.isPrimitive() && !v.isNullOrUndefined()) {
if (v.isPrimitive() && !v.isNullOrUndefined() &&
IF_RECORD_TUPLE(!v.isExtendedPrimitive(), true)) {
JSObject* proto;
switch (v.type()) {
@ -4525,6 +4559,9 @@ bool js::GetProperty(JSContext* cx, HandleValue v, HandlePropertyName name,
case ValueType::BigInt:
proto = GlobalObject::getOrCreateBigIntPrototype(cx, cx->global());
break;
#ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
#endif
case ValueType::Undefined:
case ValueType::Null:
case ValueType::Magic:

View File

@ -66,6 +66,10 @@
#include "vm/WellKnownAtom.h" // js_*_str
#include "vm/WrapperObject.h"
#include "wasm/AsmJS.h"
#ifdef ENABLE_RECORD_TUPLE
# include "vm/RecordType.h"
# include "vm/TupleType.h"
#endif
#include "debugger/DebugAPI-inl.h"
#include "vm/FrameIter-inl.h" // js::FrameIter::unaliasedForEachActual
@ -2216,6 +2220,11 @@ void js::ReportIncompatibleMethod(JSContext* cx, const CallArgs& args,
!thisv.toObject().staticPrototype() ||
thisv.toObject().staticPrototype()->getClass() != clasp);
break;
# ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
MOZ_CRASH("ExtendedPrimitive is not supported yet");
break;
# endif
case ValueType::String:
MOZ_ASSERT(clasp != &StringObject::class_);
break;

View File

@ -63,6 +63,10 @@
#include "vm/Shape.h"
#include "vm/TypedArrayObject.h"
#include "vm/WellKnownAtom.h" // js_*_str
#ifdef ENABLE_RECORD_TUPLE
# include "vm/RecordType.h"
# include "vm/TupleType.h"
#endif
#include "builtin/Boolean-inl.h"
#include "gc/Marking-inl.h"
@ -131,7 +135,10 @@ JS_PUBLIC_API const char* JS::InformalValueTypeName(const Value& v) {
case ValueType::BigInt:
return "bigint";
case ValueType::Object:
return v.toObject().getClass()->name;
#ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
#endif
return v.getObjectPayload().getClass()->name;
case ValueType::Magic:
return "magic";
case ValueType::PrivateGCThing:
@ -2442,6 +2449,11 @@ JSObject* js::PrimitiveToObject(JSContext* cx, const Value& v) {
RootedBigInt bigInt(cx, v.toBigInt());
return BigIntObject::create(cx, bigInt);
}
#ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive: {
MOZ_CRASH("ExtendedPrimitive is not supported yet");
}
#endif
case ValueType::Undefined:
case ValueType::Null:
case ValueType::Magic:
@ -2470,6 +2482,16 @@ JSProtoKey js::PrimitiveToProtoKey(JSContext* cx, const Value& v) {
return JSProto_Symbol;
case ValueType::BigInt:
return JSProto_BigInt;
#ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive:
if (v.toExtendedPrimitive().is<TupleType>()) {
return JSProto_Tuple;
}
if (v.toExtendedPrimitive().is<RecordType>()) {
return JSProto_Null;
}
MOZ_CRASH("Unsupported ExtendedPrimitive");
#endif
case ValueType::Undefined:
case ValueType::Null:
case ValueType::Magic:
@ -2710,6 +2732,13 @@ static void dumpValue(const Value& v, js::GenericPrinter& out) {
(void*)obj);
}
break;
# ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive: {
JSObject* obj = &v.toExtendedPrimitive();
out.printf("<%s at %p>", obj->getClass()->name, (void*)obj);
break;
}
# endif
case ValueType::Boolean:
if (v.toBoolean()) {
out.put("true");

View File

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* 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 vm_RecordTupleBoxShared_h
#define vm_RecordTupleBoxShared_h
#include "vm/RecordTupleBoxShared.h"
#include "vm/RecordType.h"
#include "vm/TupleType.h"
namespace js {
bool IsExtendedPrimitive(JSObject& obj) {
return obj.is<RecordType>() || obj.is<TupleType>();
}
} // namespace js
#endif

View File

@ -0,0 +1,19 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* 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 vm_RecordTupleBoxShared_h
#define vm_RecordTupleBoxShared_h
#include "js/ErrorReport.h"
#include "js/TypeDecls.h"
namespace js {
bool IsExtendedPrimitive(JSObject& obj);
} // namespace js
#endif

55
js/src/vm/RecordType.cpp Normal file
View File

@ -0,0 +1,55 @@
/* -*- 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 "vm/RecordType.h"
#include "vm/JSContext.h"
#include "vm/JSObject-inl.h"
using namespace js;
static bool RecordConstructor(JSContext* cx, unsigned argc, Value* vp);
const JSClass RecordType::class_ = {"record", 0, JS_NULL_CLASS_OPS,
&RecordType::classSpec_};
const ClassSpec RecordType::classSpec_ = {
GenericCreateConstructor<RecordConstructor, 1, gc::AllocKind::FUNCTION>,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr};
RecordType* RecordType::create(JSContext* cx) {
Rooted<TaggedProto> proto(cx, TaggedProto(nullptr));
return NewObjectWithGivenTaggedProto<RecordType>(cx, proto);
}
// Record and Record proposal section 9.2.1
static bool RecordConstructor(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
if (args.isConstructing()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_NOT_CONSTRUCTOR, "Record");
return false;
}
if (args.length() > 0) {
MOZ_CRASH("Only empty records are supoprted.");
return false;
}
RecordType* rec = RecordType::create(cx);
if (!rec) {
return false;
}
args.rval().setExtendedPrimitive(*rec);
return true;
}

24
js/src/vm/RecordType.h Normal file
View File

@ -0,0 +1,24 @@
/* -*- 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 vm_RecordType_h
#define vm_RecordType_h
#include "vm/NativeObject.h"
namespace JS {
class RecordType final : public js::NativeObject {
public:
static const js::ClassSpec classSpec_;
static const JSClass class_;
static RecordType* create(JSContext* cx);
};
} // namespace JS
#endif

View File

@ -45,6 +45,10 @@
#include "vm/JSContext-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/Realm-inl.h"
#ifdef ENABLE_RECORD_TUPLE
# include "vm/RecordType.h"
# include "vm/TupleType.h"
#endif
using namespace js;
@ -2109,7 +2113,13 @@ JSString* js::ToStringSlow(
}
RootedBigInt i(cx, v.toBigInt());
str = BigInt::toString<CanGC>(cx, i, 10);
} else {
}
#ifdef ENABLE_RECORD_TUPLE
else if (arg.isExtendedPrimitive()) {
MOZ_CRASH("Records and Tuples are not supported yet.");
}
#endif
else {
MOZ_ASSERT(v.isUndefined());
str = cx->names().undefined;
}

View File

@ -1846,6 +1846,12 @@ bool JSStructuredCloneWriter::startWrite(HandleValue v) {
case ESClass::Function:
break;
#ifdef ENABLE_RECORD_TUPLE
case ESClass::Record:
case ESClass::Tuple:
MOZ_CRASH("Record and Tuple are not supported");
#endif
case ESClass::Other: {
if (obj->canUnwrapAs<TypedArrayObject>()) {
return writeTypedArray(obj);

View File

@ -36,6 +36,10 @@
#include "vm/StaticStrings.h" // StaticStrings
#include "vm/StringType.h" // NewStringCopy{N,Z}, ToString
#include "vm/SymbolType.h" // Symbol
#ifdef ENABLE_RECORD_TUPLE
# include "vm/RecordType.h"
# include "vm/TupleType.h"
#endif
#include "vm/JSContext-inl.h" // JSContext::check
#include "vm/JSObject-inl.h" // IsCallable
@ -162,6 +166,12 @@ JSString* js::ValueToSource(JSContext* cx, HandleValue v) {
return ConcatStrings<CanGC>(cx, str, n);
}
#ifdef ENABLE_RECORD_TUPLE
case ValueType::ExtendedPrimitive: {
MOZ_CRASH("ExtendedPrimitive is not supported yet");
}
#endif
case JS::ValueType::Object: {
RootedValue fval(cx);
RootedObject obj(cx, &v.toObject());

69
js/src/vm/TupleType.cpp Normal file
View File

@ -0,0 +1,69 @@
/* -*- 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 "vm/TupleType.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/HashFunctions.h"
#include "jsapi.h"
#include "gc/Allocator.h"
#include "gc/Tracer.h"
#include "vm/JSContext.h"
#include "vm/SelfHosting.h"
#include "vm/JSObject-inl.h"
using namespace js;
static bool TupleConstructor(JSContext* cx, unsigned argc, Value* vp);
const JSClass TupleType::class_ = {"tuple", 0, JS_NULL_CLASS_OPS,
&TupleType::classSpec_};
const JSClass TupleType::protoClass_ = {
"Tuple.prototype", JSCLASS_HAS_CACHED_PROTO(JSProto_Tuple),
JS_NULL_CLASS_OPS, &TupleType::classSpec_};
const ClassSpec TupleType::classSpec_ = {
GenericCreateConstructor<TupleConstructor, 1, gc::AllocKind::FUNCTION>,
GenericCreatePrototype<TupleType>,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr};
TupleType* TupleType::create(JSContext* cx) {
Rooted<TaggedProto> proto(cx, TaggedProto(nullptr));
return NewObjectWithGivenTaggedProto<TupleType>(cx, proto);
}
// Record and Tuple proposal section 9.2.1
static bool TupleConstructor(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
if (args.isConstructing()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_NOT_CONSTRUCTOR, "Tuple");
return false;
}
if (args.length() > 0) {
MOZ_CRASH("Only empty tuples are supported");
return false;
}
TupleType* tup = TupleType::create(cx);
if (!tup) {
return false;
}
args.rval().setExtendedPrimitive(*tup);
return true;
}

25
js/src/vm/TupleType.h Normal file
View File

@ -0,0 +1,25 @@
/* -*- 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 vm_TupleType_h
#define vm_TupleType_h
#include "vm/NativeObject.h"
namespace JS {
class TupleType final : public js::NativeObject {
public:
static const js::ClassSpec classSpec_;
static const JSClass class_;
static const JSClass protoClass_;
static TupleType* create(JSContext* cx);
};
} // namespace JS
#endif