mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 896116 - Morph the dependent-JSProtoKey system to explicitly store a JSProtoKey, rather than relying on a system where a single class represents the parent and dependent both. Also convert error objects (Error, RangeError, &c.) to be represented by multiple classes, not a single one. r=bholley, r=till
--HG-- extra : rebase_source : 1d1913c49ae58be86e991077bda96684c6afb941
This commit is contained in:
parent
053427c423
commit
f5477c2a39
@ -286,6 +286,8 @@ typedef JSObject *(*ClassObjectCreationOp)(JSContext *cx, JSProtoKey key);
|
||||
typedef bool (*FinishClassInitOp)(JSContext *cx, JS::HandleObject ctor,
|
||||
JS::HandleObject proto);
|
||||
|
||||
const size_t JSCLASS_CACHED_PROTO_WIDTH = 6;
|
||||
|
||||
struct ClassSpec
|
||||
{
|
||||
ClassObjectCreationOp createConstructor;
|
||||
@ -294,7 +296,29 @@ struct ClassSpec
|
||||
const JSFunctionSpec *prototypeFunctions;
|
||||
const JSPropertySpec *prototypeProperties;
|
||||
FinishClassInitOp finishInit;
|
||||
uintptr_t flags;
|
||||
|
||||
static const size_t ParentKeyWidth = JSCLASS_CACHED_PROTO_WIDTH;
|
||||
|
||||
static const uintptr_t ParentKeyMask = (1 << ParentKeyWidth) - 1;
|
||||
static const uintptr_t DontDefineConstructor = 1 << ParentKeyWidth;
|
||||
|
||||
bool defined() const { return !!createConstructor; }
|
||||
|
||||
bool dependent() const {
|
||||
MOZ_ASSERT(defined());
|
||||
return (flags & ParentKeyMask);
|
||||
}
|
||||
|
||||
JSProtoKey parentKey() const {
|
||||
static_assert(JSProto_Null == 0, "zeroed key must be null");
|
||||
return JSProtoKey(flags & ParentKeyMask);
|
||||
}
|
||||
|
||||
bool shouldDefineConstructor() const {
|
||||
MOZ_ASSERT(defined());
|
||||
return !(flags & DontDefineConstructor);
|
||||
}
|
||||
};
|
||||
|
||||
struct ClassExtension
|
||||
@ -373,7 +397,7 @@ typedef void (*JSClassInternal)();
|
||||
struct JSClass {
|
||||
JS_CLASS_MEMBERS(JSFinalizeOp);
|
||||
|
||||
void *reserved[32];
|
||||
void *reserved[33];
|
||||
};
|
||||
|
||||
#define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot
|
||||
@ -446,7 +470,6 @@ struct JSClass {
|
||||
|
||||
// Fast access to the original value of each standard class's prototype.
|
||||
#define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 10)
|
||||
#define JSCLASS_CACHED_PROTO_WIDTH 6
|
||||
#define JSCLASS_CACHED_PROTO_MASK JS_BITMASK(JSCLASS_CACHED_PROTO_WIDTH)
|
||||
#define JSCLASS_HAS_CACHED_PROTO(key) (uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT)
|
||||
#define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey) \
|
||||
|
@ -3032,7 +3032,7 @@ const Class DateObject::class_ = {
|
||||
nullptr, /* trace */
|
||||
{
|
||||
GenericCreateConstructor<js_Date, MAXARGS, JSFunction::FinalizeKind>,
|
||||
GenericCreatePrototype<&DateObject::class_>,
|
||||
GenericCreatePrototype,
|
||||
date_static_methods,
|
||||
date_methods,
|
||||
nullptr,
|
||||
|
@ -59,30 +59,69 @@ static const JSFunctionSpec exception_methods[] = {
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
||||
const Class ErrorObject::class_ = {
|
||||
js_Error_str,
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Error) |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
exn_finalize,
|
||||
nullptr, /* call */
|
||||
nullptr, /* hasInstance */
|
||||
nullptr, /* construct */
|
||||
nullptr, /* trace */
|
||||
{
|
||||
ErrorObject::createConstructor,
|
||||
ErrorObject::createProto,
|
||||
nullptr,
|
||||
exception_methods
|
||||
#define IMPLEMENT_ERROR_SUBCLASS(name) \
|
||||
{ \
|
||||
js_Error_str, /* yes, really */ \
|
||||
JSCLASS_IMPLEMENTS_BARRIERS | \
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS), \
|
||||
JS_PropertyStub, /* addProperty */ \
|
||||
JS_DeletePropertyStub, /* delProperty */ \
|
||||
JS_PropertyStub, /* getProperty */ \
|
||||
JS_StrictPropertyStub, /* setProperty */ \
|
||||
JS_EnumerateStub, \
|
||||
JS_ResolveStub, \
|
||||
JS_ConvertStub, \
|
||||
exn_finalize, \
|
||||
nullptr, /* call */ \
|
||||
nullptr, /* hasInstance */ \
|
||||
nullptr, /* construct */ \
|
||||
nullptr, /* trace */ \
|
||||
{ \
|
||||
ErrorObject::createConstructor, \
|
||||
ErrorObject::createProto, \
|
||||
nullptr, \
|
||||
exception_methods, \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
JSProto_Error \
|
||||
} \
|
||||
}
|
||||
|
||||
const Class
|
||||
ErrorObject::classes[JSEXN_LIMIT] = {
|
||||
{
|
||||
js_Error_str,
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Error) |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
exn_finalize,
|
||||
nullptr, /* call */
|
||||
nullptr, /* hasInstance */
|
||||
nullptr, /* construct */
|
||||
nullptr, /* trace */
|
||||
{
|
||||
ErrorObject::createConstructor,
|
||||
ErrorObject::createProto,
|
||||
nullptr,
|
||||
exception_methods,
|
||||
0
|
||||
}
|
||||
},
|
||||
IMPLEMENT_ERROR_SUBCLASS(InternalError),
|
||||
IMPLEMENT_ERROR_SUBCLASS(EvalError),
|
||||
IMPLEMENT_ERROR_SUBCLASS(RangeError),
|
||||
IMPLEMENT_ERROR_SUBCLASS(ReferenceError),
|
||||
IMPLEMENT_ERROR_SUBCLASS(SyntaxError),
|
||||
IMPLEMENT_ERROR_SUBCLASS(TypeError),
|
||||
IMPLEMENT_ERROR_SUBCLASS(URIError)
|
||||
};
|
||||
|
||||
JSErrorReport *
|
||||
@ -465,7 +504,7 @@ JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR == JSProto_URIError);
|
||||
/* static */ JSObject *
|
||||
ErrorObject::createProto(JSContext *cx, JSProtoKey key)
|
||||
{
|
||||
RootedObject errorProto(cx, GenericCreatePrototype<&ErrorObject::class_>(cx, key));
|
||||
RootedObject errorProto(cx, GenericCreatePrototype(cx, key));
|
||||
if (!errorProto)
|
||||
return nullptr;
|
||||
|
||||
|
@ -659,17 +659,14 @@ JS_FRIEND_API(const Class *)
|
||||
ProtoKeyToClass(JSProtoKey key);
|
||||
|
||||
// Returns true if the standard class identified by |key| inherits from
|
||||
// another standard class with the same js::Class. This basically means
|
||||
// that the various properties described by our js::Class are intended
|
||||
// to live higher up on the proto chain.
|
||||
// another standard class (in addition to Object) along its proto chain.
|
||||
//
|
||||
// In practice, this only returns true for Error subtypes.
|
||||
inline bool
|
||||
StandardClassIsDependent(JSProtoKey key)
|
||||
{
|
||||
JSProtoKey keyFromClass = JSCLASS_CACHED_PROTO_KEY(ProtoKeyToClass(key));
|
||||
MOZ_ASSERT(keyFromClass);
|
||||
return key != keyFromClass;
|
||||
const Class *clasp = ProtoKeyToClass(key);
|
||||
return clasp->spec.defined() && clasp->spec.dependent();
|
||||
}
|
||||
|
||||
// Returns the key for the class inherited by a given standard class (that
|
||||
@ -686,10 +683,9 @@ ParentKeyForStandardClass(JSProtoKey key)
|
||||
if (key == JSProto_Object)
|
||||
return JSProto_Null;
|
||||
|
||||
// If we're dependent (i.e. an Error subtype), return the key of the class
|
||||
// we depend on.
|
||||
// If we're dependent, return the key of the class we depend on.
|
||||
if (StandardClassIsDependent(key))
|
||||
return JSCLASS_CACHED_PROTO_KEY(ProtoKeyToClass(key));
|
||||
return ProtoKeyToClass(key)->spec.parentKey();
|
||||
|
||||
// Otherwise, we inherit [Object].
|
||||
return JSProto_Object;
|
||||
|
@ -35,6 +35,7 @@
|
||||
#define CLASP(name) (&name##Class)
|
||||
#define OCLASP(name) (&name##Object::class_)
|
||||
#define TYPED_ARRAY_CLASP(type) (&TypedArrayObject::classes[Scalar::type])
|
||||
#define ERROR_CLASP(type) (&ErrorObject::classes[type])
|
||||
#define SHARED_TYPED_ARRAY_CLASP(type) (&SharedTypedArrayObject::classes[Scalar::type])
|
||||
|
||||
#ifdef ENABLE_PARALLEL_JS
|
||||
@ -79,14 +80,14 @@
|
||||
real(Number, 8, js_InitNumberClass, OCLASP(Number)) \
|
||||
real(String, 9, js_InitStringClass, OCLASP(String)) \
|
||||
real(RegExp, 10, js_InitRegExpClass, OCLASP(RegExp)) \
|
||||
real(Error, 11, js_InitViaClassSpec, OCLASP(Error)) \
|
||||
real(InternalError, 12, js_InitViaClassSpec, OCLASP(Error)) \
|
||||
real(EvalError, 13, js_InitViaClassSpec, OCLASP(Error)) \
|
||||
real(RangeError, 14, js_InitViaClassSpec, OCLASP(Error)) \
|
||||
real(ReferenceError, 15, js_InitViaClassSpec, OCLASP(Error)) \
|
||||
real(SyntaxError, 16, js_InitViaClassSpec, OCLASP(Error)) \
|
||||
real(TypeError, 17, js_InitViaClassSpec, OCLASP(Error)) \
|
||||
real(URIError, 18, js_InitViaClassSpec, OCLASP(Error)) \
|
||||
real(Error, 11, js_InitViaClassSpec, ERROR_CLASP(JSEXN_ERR)) \
|
||||
real(InternalError, 12, js_InitViaClassSpec, ERROR_CLASP(JSEXN_INTERNALERR)) \
|
||||
real(EvalError, 13, js_InitViaClassSpec, ERROR_CLASP(JSEXN_EVALERR)) \
|
||||
real(RangeError, 14, js_InitViaClassSpec, ERROR_CLASP(JSEXN_RANGEERR)) \
|
||||
real(ReferenceError, 15, js_InitViaClassSpec, ERROR_CLASP(JSEXN_REFERENCEERR)) \
|
||||
real(SyntaxError, 16, js_InitViaClassSpec, ERROR_CLASP(JSEXN_SYNTAXERR)) \
|
||||
real(TypeError, 17, js_InitViaClassSpec, ERROR_CLASP(JSEXN_TYPEERR)) \
|
||||
real(URIError, 18, js_InitViaClassSpec, ERROR_CLASP(JSEXN_URIERR)) \
|
||||
real(Iterator, 19, js_InitIteratorClasses, OCLASP(PropertyIterator)) \
|
||||
real(StopIteration, 20, js_InitIteratorClasses, OCLASP(StopIteration)) \
|
||||
real(ArrayBuffer, 21, js_InitArrayBufferClass, &js::ArrayBufferObject::protoClass) \
|
||||
|
@ -93,7 +93,8 @@ js::ErrorObject::create(JSContext *cx, JSExnType errorType, HandleString stack,
|
||||
|
||||
Rooted<ErrorObject*> errObject(cx);
|
||||
{
|
||||
JSObject* obj = NewObjectWithGivenProto(cx, &ErrorObject::class_, proto, nullptr);
|
||||
const Class *clasp = ErrorObject::classForType(errorType);
|
||||
JSObject* obj = NewObjectWithGivenProto(cx, clasp, proto, nullptr);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
errObject = &obj->as<ErrorObject>();
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef vm_ErrorObject_h_
|
||||
#define vm_ErrorObject_h_
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "vm/Shape.h"
|
||||
@ -63,7 +65,17 @@ class ErrorObject : public JSObject
|
||||
static const uint32_t RESERVED_SLOTS = MESSAGE_SLOT + 1;
|
||||
|
||||
public:
|
||||
static const Class class_;
|
||||
static const Class classes[JSEXN_LIMIT];
|
||||
|
||||
static const Class * classForType(JSExnType type) {
|
||||
MOZ_ASSERT(type != JSEXN_NONE);
|
||||
MOZ_ASSERT(type < JSEXN_LIMIT);
|
||||
return &classes[type];
|
||||
}
|
||||
|
||||
static bool isErrorClass(const Class *clasp) {
|
||||
return &classes[0] <= clasp && clasp < &classes[0] + mozilla::ArrayLength(classes);
|
||||
}
|
||||
|
||||
// Create an error of the given type corresponding to the provided location
|
||||
// info. If |message| is non-null, then the error will have a .message
|
||||
@ -100,4 +112,11 @@ class ErrorObject : public JSObject
|
||||
|
||||
} // namespace js
|
||||
|
||||
template<>
|
||||
inline bool
|
||||
JSObject::is<js::ErrorObject>() const
|
||||
{
|
||||
return js::ErrorObject::isErrorClass(getClass());
|
||||
}
|
||||
|
||||
#endif // vm_ErrorObject_h_
|
||||
|
@ -161,8 +161,10 @@ GlobalObject::resolveConstructor(JSContext *cx, Handle<GlobalObject*> global, JS
|
||||
return false;
|
||||
|
||||
RootedId id(cx, NameToId(ClassName(key, cx)));
|
||||
if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
|
||||
return false;
|
||||
if (clasp->spec.shouldDefineConstructor()) {
|
||||
if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
|
||||
return false;
|
||||
}
|
||||
|
||||
global->setConstructor(key, ObjectValue(*ctor));
|
||||
global->setConstructorPropertySlot(key, ObjectValue(*ctor));
|
||||
@ -192,9 +194,11 @@ GlobalObject::resolveConstructor(JSContext *cx, Handle<GlobalObject*> global, JS
|
||||
if (clasp->spec.finishInit && !clasp->spec.finishInit(cx, ctor, proto))
|
||||
return false;
|
||||
|
||||
// Stash type information, so that what we do here is equivalent to
|
||||
// initBuiltinConstructor.
|
||||
types::AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
|
||||
if (clasp->spec.shouldDefineConstructor()) {
|
||||
// Stash type information, so that what we do here is equivalent to
|
||||
// initBuiltinConstructor.
|
||||
types::AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -795,11 +795,11 @@ GenericCreateConstructor(JSContext *cx, JSProtoKey key)
|
||||
return cx->global()->createConstructor(cx, ctor, name, length, kind);
|
||||
}
|
||||
|
||||
template<const Class *clasp>
|
||||
JSObject *
|
||||
inline JSObject *
|
||||
GenericCreatePrototype(JSContext *cx, JSProtoKey key)
|
||||
{
|
||||
MOZ_ASSERT(key != JSProto_Object);
|
||||
const Class *clasp = ProtoKeyToClass(key);
|
||||
JSProtoKey parentKey = ParentKeyForStandardClass(key);
|
||||
if (!GlobalObject::ensureConstructor(cx, cx->global(), parentKey))
|
||||
return nullptr;
|
||||
|
@ -421,17 +421,12 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
|
||||
const js::Class *clasp = js::GetObjectClass(target);
|
||||
MOZ_ASSERT(clasp->spec.defined());
|
||||
JSProtoKey protoKey = getProtoKey(holder);
|
||||
|
||||
// Handle the 'constructor' property.
|
||||
if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR)) {
|
||||
RootedObject constructor(cx);
|
||||
{
|
||||
JSAutoCompartment ac(cx, target);
|
||||
if (!JS_GetClassObject(cx, protoKey, &constructor))
|
||||
if (!JS_GetClassObject(cx, key, &constructor))
|
||||
return false;
|
||||
}
|
||||
if (!JS_WrapObject(cx, &constructor))
|
||||
@ -452,11 +447,6 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper,
|
||||
return JS_IdToValue(cx, className, desc.value());
|
||||
}
|
||||
|
||||
// Bail out for dependent classes, since all the rest of the properties we'll
|
||||
// resolve here will live on the parent prototype.
|
||||
if (js::StandardClassIsDependent(protoKey))
|
||||
return true;
|
||||
|
||||
// Compute the property name we're looking for. Indexed array properties
|
||||
// are handled above. We'll handle well-known symbols when we start
|
||||
// supporting Symbol.iterator in bug 918828.
|
||||
@ -464,6 +454,10 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper,
|
||||
return true;
|
||||
Rooted<JSFlatString*> str(cx, JSID_TO_FLAT_STRING(id));
|
||||
|
||||
// Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
|
||||
const js::Class *clasp = js::GetObjectClass(target);
|
||||
MOZ_ASSERT(clasp->spec.defined());
|
||||
|
||||
// Scan through the functions.
|
||||
const JSFunctionSpec *fsMatch = nullptr;
|
||||
for (const JSFunctionSpec *fs = clasp->spec.prototypeFunctions; fs && fs->name; ++fs) {
|
||||
@ -694,11 +688,6 @@ JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags
|
||||
return true;
|
||||
}
|
||||
|
||||
// Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
|
||||
const js::Class *clasp = js::GetObjectClass(target);
|
||||
MOZ_ASSERT(clasp->spec.defined());
|
||||
JSProtoKey protoKey = getProtoKey(holder);
|
||||
|
||||
// Add the 'constructor' property.
|
||||
if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR)))
|
||||
return false;
|
||||
@ -707,10 +696,9 @@ JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags
|
||||
if (IsErrorObjectKey(key) && !props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_NAME)))
|
||||
return false;
|
||||
|
||||
// Bail out for dependent classes, since all the rest of the properties we'll
|
||||
// resolve here will live on the parent prototype.
|
||||
if (js::StandardClassIsDependent(protoKey))
|
||||
return true;
|
||||
// Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
|
||||
const js::Class *clasp = js::GetObjectClass(target);
|
||||
MOZ_ASSERT(clasp->spec.defined());
|
||||
|
||||
// Intern all the strings, and pass theme to the caller.
|
||||
for (const JSFunctionSpec *fs = clasp->spec.prototypeFunctions; fs && fs->name; ++fs) {
|
||||
|
Loading…
Reference in New Issue
Block a user