зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1499813 - Part 2: JSObject::unwrapAs<T>() and canUnwrapAs<T>() methods. r=tcampbell
Depends on D9834 Differential Revision: https://phabricator.services.mozilla.com/D9835 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
6ff7b405ea
Коммит
cc2589c333
|
@ -957,13 +957,6 @@ const JSPropertySpec DataViewObject::properties[] = {
|
|||
JS_PS_END
|
||||
};
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
JS_IsDataViewObject(JSObject* obj)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
return obj ? obj->is<DataViewObject>() : false;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteOffset(JSObject* obj)
|
||||
{
|
||||
|
|
|
@ -170,18 +170,7 @@ template<class T>
|
|||
bool
|
||||
IsMaybeWrapped(const HandleValue v)
|
||||
{
|
||||
if (!v.isObject()) {
|
||||
return false;
|
||||
}
|
||||
JSObject* obj = &v.toObject();
|
||||
if (obj->is<T>()) {
|
||||
return true;
|
||||
}
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
return obj->is<T>();
|
||||
return v.isObject() && v.toObject().canUnwrapAs<T>();
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
|
@ -2742,7 +2731,7 @@ static MOZ_MUST_USE bool
|
|||
ReadableStreamDefaultController_close_impl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
Rooted<ReadableStreamDefaultController*> controller(cx);
|
||||
controller = &UncheckedUnwrap(&args.thisv().toObject())->as<ReadableStreamDefaultController>();
|
||||
controller = &args.thisv().toObject().unwrapAs<ReadableStreamDefaultController>();
|
||||
|
||||
// Steps 2-3.
|
||||
if (!VerifyControllerStateForClosing(cx, controller)) {
|
||||
|
@ -2773,7 +2762,7 @@ static MOZ_MUST_USE bool
|
|||
ReadableStreamDefaultController_enqueue_impl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
Rooted<ReadableStreamDefaultController*> controller(cx);
|
||||
controller = &UncheckedUnwrap(&args.thisv().toObject())->as<ReadableStreamDefaultController>();
|
||||
controller = &args.thisv().toObject().unwrapAs<ReadableStreamDefaultController>();
|
||||
|
||||
// Step 2: If this.[[closeRequested]] is true, throw a TypeError exception.
|
||||
if (ControllerFlags(controller) & ControllerFlag_CloseRequested) {
|
||||
|
@ -2819,7 +2808,7 @@ static MOZ_MUST_USE bool
|
|||
ReadableStreamDefaultController_error_impl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
Rooted<ReadableStreamDefaultController*> controller(cx);
|
||||
controller = &UncheckedUnwrap(&args.thisv().toObject())->as<ReadableStreamDefaultController>();
|
||||
controller = &args.thisv().toObject().unwrapAs<ReadableStreamDefaultController>();
|
||||
|
||||
// Step 2: Let stream be this.[[controlledReadableStream]].
|
||||
// Step 3: If stream.[[state]] is not "readable", throw a TypeError exception.
|
||||
|
|
|
@ -4719,28 +4719,19 @@ JS::NewReadableExternalSourceStreamObject(JSContext* cx, void* underlyingSource,
|
|||
JS_PUBLIC_API(bool)
|
||||
JS::IsReadableStream(JSObject* obj)
|
||||
{
|
||||
if (IsWrapper(obj)) {
|
||||
obj = CheckedUnwrap(obj);
|
||||
}
|
||||
return obj && obj->is<ReadableStream>();
|
||||
return obj->canUnwrapAs<ReadableStream>();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::IsReadableStreamReader(JSObject* obj)
|
||||
{
|
||||
if (IsWrapper(obj)) {
|
||||
obj = CheckedUnwrap(obj);
|
||||
}
|
||||
return obj && obj->is<ReadableStreamDefaultReader>();
|
||||
return obj->canUnwrapAs<ReadableStreamDefaultReader>();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::IsReadableStreamDefaultReader(JSObject* obj)
|
||||
{
|
||||
if (IsWrapper(obj)) {
|
||||
obj = CheckedUnwrap(obj);
|
||||
}
|
||||
return obj && obj->is<ReadableStreamDefaultReader>();
|
||||
return obj->canUnwrapAs<ReadableStreamDefaultReader>();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
|
|
@ -2068,12 +2068,6 @@ JS_DetachArrayBuffer(JSContext* cx, JS::HandleObject obj);
|
|||
extern JS_FRIEND_API(bool)
|
||||
JS_IsDetachedArrayBufferObject(JSObject* obj);
|
||||
|
||||
/**
|
||||
* Check whether obj supports JS_GetDataView* APIs.
|
||||
*/
|
||||
JS_FRIEND_API(bool)
|
||||
JS_IsDataViewObject(JSObject* obj);
|
||||
|
||||
/**
|
||||
* Create a new DataView using the given buffer for storage. The given buffer
|
||||
* must be an ArrayBuffer or SharedArrayBuffer (or a cross-compartment wrapper
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "js/Conversions.h"
|
||||
#include "js/GCVector.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "vm/Printer.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "vm/StringType.h"
|
||||
|
@ -535,6 +536,27 @@ class JSObject : public js::gc::Cell
|
|||
return *static_cast<const T*>(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* True if either this or CheckedUnwrap(this) is an object of class T.
|
||||
* (Only two objects are checked, regardless of how many wrappers there
|
||||
* are.)
|
||||
*
|
||||
* /!\ Note: This can be true at one point, but false later for the same
|
||||
* object, thanks to js::NukeCrossCompartmentWrapper and friends.
|
||||
*/
|
||||
template <class T>
|
||||
bool canUnwrapAs();
|
||||
|
||||
/*
|
||||
* Unwrap and downcast to class T.
|
||||
*
|
||||
* Precondition: `this->canUnwrapAs<T>()`. Note that it's not enough to
|
||||
* have checked this at some point in the past; if there's any doubt as to
|
||||
* whether js::Nuke* could have been called in the meantime, check again.
|
||||
*/
|
||||
template <class T>
|
||||
T& unwrapAs();
|
||||
|
||||
#if defined(DEBUG) || defined(JS_JITSPEW)
|
||||
void dump(js::GenericPrinter& fp) const;
|
||||
void dump() const;
|
||||
|
@ -590,6 +612,39 @@ js::HandleBase<JSObject*, Wrapper>::as() const
|
|||
return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
JSObject::canUnwrapAs()
|
||||
{
|
||||
static_assert(!std::is_convertible<T*, js::Wrapper*>::value,
|
||||
"T can't be a Wrapper type; this function discards wrappers");
|
||||
|
||||
if (is<T>()) {
|
||||
return true;
|
||||
}
|
||||
JSObject* obj = js::CheckedUnwrap(this);
|
||||
return obj && obj->is<T>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T&
|
||||
JSObject::unwrapAs()
|
||||
{
|
||||
static_assert(!std::is_convertible<T*, js::Wrapper*>::value,
|
||||
"T can't be a Wrapper type; this function discards wrappers");
|
||||
|
||||
if (is<T>()) {
|
||||
return as<T>();
|
||||
}
|
||||
|
||||
// Since the caller just called canUnwrapAs<T>(), which does a
|
||||
// CheckedUnwrap, this does not need to repeat the security check.
|
||||
JSObject* unwrapped = js::UncheckedUnwrap(this);
|
||||
MOZ_ASSERT(js::CheckedUnwrap(this) == unwrapped,
|
||||
"check that the security check we skipped really is redundant");
|
||||
return unwrapped->as<T>();
|
||||
}
|
||||
|
||||
/*
|
||||
* The only sensible way to compare JSObject with == is by identity. We use
|
||||
* const& instead of * as a syntactic way to assert non-null. This leads to an
|
||||
|
|
|
@ -97,14 +97,6 @@ class SavedFrame : public NativeObject {
|
|||
RootedIterator end() { return RootedIterator(); }
|
||||
};
|
||||
|
||||
static bool isSavedFrameOrWrapper(JSObject& obj) {
|
||||
auto unwrapped = CheckedUnwrap(&obj);
|
||||
if (!unwrapped) {
|
||||
return false;
|
||||
}
|
||||
return unwrapped->is<SavedFrame>();
|
||||
}
|
||||
|
||||
struct Lookup;
|
||||
struct HashPolicy;
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ inline void
|
|||
js::AssertObjectIsSavedFrameOrWrapper(JSContext* cx, HandleObject stack)
|
||||
{
|
||||
if (stack) {
|
||||
MOZ_RELEASE_ASSERT(js::SavedFrame::isSavedFrameOrWrapper(*stack));
|
||||
MOZ_RELEASE_ASSERT(stack->canUnwrapAs<SavedFrame>());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1132,7 +1132,7 @@ JS_PUBLIC_API(bool)
|
|||
IsMaybeWrappedSavedFrame(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(obj);
|
||||
return js::SavedFrame::isSavedFrameOrWrapper(*obj);
|
||||
return obj->canUnwrapAs<js::SavedFrame>();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
|
|
|
@ -1827,16 +1827,16 @@ JSStructuredCloneWriter::startWrite(HandleValue v)
|
|||
break;
|
||||
|
||||
case ESClass::Other: {
|
||||
if (JS_IsTypedArrayObject(obj)) {
|
||||
if (obj->canUnwrapAs<TypedArrayObject>()) {
|
||||
return writeTypedArray(obj);
|
||||
}
|
||||
if (JS_IsDataViewObject(obj)) {
|
||||
if (obj->canUnwrapAs<DataViewObject>()) {
|
||||
return writeDataView(obj);
|
||||
}
|
||||
if (wasm::IsSharedWasmMemoryObject(obj)) {
|
||||
return writeSharedWasmMemory(obj);
|
||||
}
|
||||
if (SavedFrame::isSavedFrameOrWrapper(*obj)) {
|
||||
if (obj->canUnwrapAs<SavedFrame>()) {
|
||||
return traverseSavedFrame(obj);
|
||||
}
|
||||
break;
|
||||
|
@ -2072,7 +2072,7 @@ JSStructuredCloneWriter::write(HandleValue v)
|
|||
if (!startWrite(key) || !startWrite(val)) {
|
||||
return false;
|
||||
}
|
||||
} else if (cls == ESClass::Set || SavedFrame::isSavedFrameOrWrapper(*obj)) {
|
||||
} else if (cls == ESClass::Set || obj->canUnwrapAs<SavedFrame>()) {
|
||||
key = otherEntries.popCopy();
|
||||
checkStack();
|
||||
|
||||
|
|
|
@ -2269,8 +2269,7 @@ js::DefineTypedArrayElement(JSContext* cx, HandleObject obj, uint64_t index,
|
|||
JS_FRIEND_API(bool)
|
||||
JS_IsTypedArrayObject(JSObject* obj)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
return obj ? obj->is<TypedArrayObject>() : false;
|
||||
return obj->canUnwrapAs<TypedArrayObject>();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
|
|
Загрузка…
Ссылка в новой задаче