Bug 1744975 - Change type signatures of TupleObject::unbox(), TupleObject::maybeUnbox() r=jandem

* unbox() now returns a TupleType&
   * maybeUnbox() now returns a Maybe<TupleType&>; in both cases, callers are responsible for rooting
   * IsTuple() now takes a Value& rather than a HandleValue
   * ThisTupleValue() now takes a Value& and returns a TupleType&

   These changes are meant to minimize assumptions made by TupleObject and TupleType methods about their inputs, and shift responsibility for rooting onto the callers.

Differential Revision: https://phabricator.services.mozilla.com/D135016
This commit is contained in:
Tim Chevalier 2022-01-31 08:56:40 +00:00
parent dee7ad83fa
commit 88d0d93b46
9 changed files with 43 additions and 35 deletions

View File

@ -1438,7 +1438,7 @@ static bool TryEnumerableOwnPropertiesNative(JSContext* cx, HandleObject obj,
#ifdef ENABLE_RECORD_TUPLE
if (obj->is<TupleObject>()) {
Rooted<TupleType*> tup(cx, obj->as<TupleObject>().unbox());
Rooted<TupleType*> tup(cx, &obj->as<TupleObject>().unbox());
return TryEnumerableOwnPropertiesNative<kind>(cx, tup, rval, optimized);
} else if (obj->is<RecordObject>()) {
Rooted<RecordType*> tup(cx, obj->as<RecordObject>().unbox());

View File

@ -30,22 +30,20 @@ TupleObject* TupleObject::create(JSContext* cx, Handle<TupleType*> tuple) {
return tup;
}
TupleType* TupleObject::unbox() const {
return &getFixedSlot(PrimitiveValueSlot)
.toExtendedPrimitive()
.as<TupleType>();
// Caller is responsible for rooting the result
TupleType& TupleObject::unbox() const {
return getFixedSlot(PrimitiveValueSlot).toExtendedPrimitive().as<TupleType>();
}
bool TupleObject::maybeUnbox(JSObject* obj, MutableHandle<TupleType*> tupp) {
// Caller is responsible for rooting the result
mozilla::Maybe<TupleType&> TupleObject::maybeUnbox(JSObject* obj) {
Maybe<TupleType&> result = mozilla::Nothing();
if (obj->is<TupleType>()) {
tupp.set(&obj->as<TupleType>());
return true;
result.emplace(obj->as<TupleType>());
} else if (obj->is<TupleObject>()) {
result.emplace(obj->as<TupleObject>().unbox());
}
if (obj->is<TupleObject>()) {
tupp.set(obj->as<TupleObject>().unbox());
return true;
}
return false;
return result;
}
bool tup_mayResolve(const JSAtomState&, jsid id, JSObject*) {
@ -56,7 +54,7 @@ bool tup_mayResolve(const JSAtomState&, jsid id, JSObject*) {
bool tup_resolve(JSContext* cx, HandleObject obj, HandleId id,
bool* resolvedp) {
RootedValue value(cx);
*resolvedp = obj->as<TupleObject>().unbox()->getOwnProperty(id, &value);
*resolvedp = obj->as<TupleObject>().unbox().getOwnProperty(id, &value);
if (*resolvedp) {
static const unsigned TUPLE_ELEMENT_ATTRS =

View File

@ -20,9 +20,9 @@ class TupleObject : public NativeObject {
static TupleObject* create(JSContext* cx, Handle<TupleType*> record);
JS::TupleType* unbox() const;
JS::TupleType& unbox() const;
static bool maybeUnbox(JSObject* obj, MutableHandle<TupleType*> tupp);
static mozilla::Maybe<TupleType&> maybeUnbox(JSObject* obj);
};
} // namespace js

View File

@ -273,11 +273,12 @@ static bool EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj,
return true;
} else {
Rooted<TupleType*> tup(cx);
if (TupleObject::maybeUnbox(pobj, &tup)) {
mozilla::Maybe<TupleType&> tup = TupleObject::maybeUnbox(pobj);
if (tup) {
uint32_t len = (*tup).length();
RootedId id(cx);
for (size_t i = 0; i < tup->length(); i++) {
for (size_t i = 0; i < len; i++) {
if (!JS_IndexToId(cx, i, &id)) {
return false;
}

View File

@ -3492,7 +3492,7 @@ bool js::Unbox(JSContext* cx, HandleObject obj, MutableHandleValue vp) {
} else if (obj->is<RecordObject>()) {
vp.setExtendedPrimitive(*obj->as<RecordObject>().unbox());
} else if (obj->is<TupleObject>()) {
vp.setExtendedPrimitive(*obj->as<TupleObject>().unbox());
vp.setExtendedPrimitive(obj->as<TupleObject>().unbox());
#endif
} else {
vp.setUndefined();

View File

@ -2212,9 +2212,13 @@ JSString* js::ToStringSlow(
}
#ifdef ENABLE_RECORD_TUPLE
else if (arg.isExtendedPrimitive()) {
if (!allowGC) {
return nullptr;
}
JSObject& obj = arg.toExtendedPrimitive();
if (obj.is<js::TupleType>()) {
str = js::TupleToSource(cx, &obj.as<js::TupleType>());
Rooted<TupleType*> tup(cx, &obj.as<js::TupleType>());
str = js::TupleToSource(cx, tup);
} else if (obj.is<js::RecordType>()) {
str = js::RecordToSource(cx, &obj.as<js::RecordType>());
} else {

View File

@ -170,7 +170,8 @@ JSString* js::ValueToSource(JSContext* cx, HandleValue v) {
case ValueType::ExtendedPrimitive: {
RootedObject obj(cx, &v.toExtendedPrimitive());
if (obj->is<TupleType>()) {
return TupleToSource(cx, &obj->as<TupleType>());
Rooted<TupleType*> tup(cx, &obj->as<TupleType>());
return TupleToSource(cx, tup);
}
if (obj->is<RecordType>()) {
return RecordToSource(cx, obj.as<RecordType>());

View File

@ -235,7 +235,7 @@ bool TupleType::sameValueWith(JSContext* cx, TupleType* lhs, TupleType* rhs,
return true;
}
JSString* js::TupleToSource(JSContext* cx, TupleType* tup) {
JSString* js::TupleToSource(JSContext* cx, Handle<TupleType*> tup) {
JSStringBuilder sb(cx);
if (!sb.append("#[")) {
@ -297,30 +297,33 @@ bool TupleConstructor(JSContext* cx, unsigned argc, Value* vp) {
BEGIN: Tuple.prototype methods
\*===========================================================================*/
bool IsTuple(HandleValue v) {
bool IsTuple(const Value& v) {
if (v.isExtendedPrimitive()) return v.toExtendedPrimitive().is<TupleType>();
if (v.isObject()) return v.toObject().is<TupleObject>();
return false;
};
static MOZ_ALWAYS_INLINE TupleType* ThisTupleValue(HandleValue val) {
MOZ_ASSERT(IsTuple(val));
return val.isExtendedPrimitive() ? &val.toExtendedPrimitive().as<TupleType>()
: val.toObject().as<TupleObject>().unbox();
}
// Caller is responsible for rooting the result
TupleType& ThisTupleValue(const Value& val) {
MOZ_ASSERT(IsTuple(val));
return (val.isExtendedPrimitive() ? val.toExtendedPrimitive().as<TupleType>()
: val.toObject().as<TupleObject>().unbox());
}
bool HandleIsTuple(HandleValue v) { return IsTuple(v.get()); }
// 8.2.3.2 get Tuple.prototype.length
bool lengthAccessor_impl(JSContext* cx, const CallArgs& args) {
// Step 1.
TupleType* tuple = ThisTupleValue(args.thisv());
TupleType& tuple = ThisTupleValue(args.thisv().get());
// Step 2.
args.rval().setInt32(tuple->length());
args.rval().setInt32(tuple.length());
return true;
}
bool TupleType::lengthAccessor(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsTuple, lengthAccessor_impl>(cx, args);
return CallNonGenericMethod<HandleIsTuple, lengthAccessor_impl>(cx, args);
}
/*===========================================================================*\

View File

@ -60,7 +60,8 @@ class TupleType final : public js::NativeObject {
namespace js {
extern JSString* TupleToSource(JSContext* cx, TupleType* tup);
}
extern JSString* TupleToSource(JSContext* cx, Handle<TupleType*> tup);
} // namespace js
#endif