mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1097267 - Change to the simpler enumerate hook in the js engine. r=jorendorff
This commit is contained in:
parent
728bcc87a1
commit
1f02c25c20
@ -41,6 +41,12 @@ extern JS_FRIEND_DATA(const js::Class* const) FunctionClassPtr;
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
class AutoIdVector;
|
||||
|
||||
}
|
||||
|
||||
// JSClass operation signatures.
|
||||
|
||||
// Add or get a property named by id in obj. Note the jsid id type -- id may
|
||||
@ -76,39 +82,19 @@ typedef bool
|
||||
(* JSDeletePropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
|
||||
bool *succeeded);
|
||||
|
||||
// This function type is used for callbacks that enumerate the properties of
|
||||
// a JSObject. The behavior depends on the value of enum_op:
|
||||
// The type of ObjectOps::enumerate. This callback overrides a portion of SpiderMonkey's default
|
||||
// [[Enumerate]] internal method. When an ordinary object is enumerated, that object and each object
|
||||
// on its prototype chain is tested for an enumerate op, and those ops are called in order.
|
||||
// The properties each op adds to the 'properties' vector are added to the set of values the
|
||||
// for-in loop will iterate over. All of this is nonstandard.
|
||||
//
|
||||
// JSENUMERATE_INIT
|
||||
// A new, opaque iterator state should be allocated and stored in *statep.
|
||||
// (You can use PRIVATE_TO_JSVAL() to tag the pointer to be stored).
|
||||
// An object is "enumerated" when it's the target of a for-in loop or JS_Enumerate().
|
||||
// All other property inspection, including Object.keys(obj), goes through [[OwnKeys]].
|
||||
//
|
||||
// The number of properties that will be enumerated should be returned as
|
||||
// an integer jsval in *idp, if idp is non-null, and provided the number of
|
||||
// enumerable properties is known. If idp is non-null and the number of
|
||||
// enumerable properties can't be computed in advance, *idp should be set
|
||||
// to JSVAL_ZERO.
|
||||
//
|
||||
// JSENUMERATE_INIT_ALL
|
||||
// Used identically to JSENUMERATE_INIT, but exposes all properties of the
|
||||
// object regardless of enumerability.
|
||||
//
|
||||
// JSENUMERATE_NEXT
|
||||
// A previously allocated opaque iterator state is passed in via statep.
|
||||
// Return the next jsid in the iteration using *idp. The opaque iterator
|
||||
// state pointed at by statep is destroyed and *statep is set to JSVAL_NULL
|
||||
// if there are no properties left to enumerate.
|
||||
//
|
||||
// JSENUMERATE_DESTROY
|
||||
// Destroy the opaque iterator state previously allocated in *statep by a
|
||||
// call to this function when enum_op was JSENUMERATE_INIT or
|
||||
// JSENUMERATE_INIT_ALL.
|
||||
//
|
||||
// The return value is used to indicate success, with a value of false
|
||||
// indicating failure.
|
||||
// The callback's job is to populate 'properties' with all property keys that the for-in loop
|
||||
// should visit.
|
||||
typedef bool
|
||||
(* JSNewEnumerateOp)(JSContext *cx, JS::HandleObject obj, JSIterateOp enum_op,
|
||||
JS::MutableHandleValue statep, JS::MutableHandleId idp);
|
||||
(* JSNewEnumerateOp)(JSContext *cx, JS::HandleObject obj, JS::AutoIdVector &properties);
|
||||
|
||||
// The old-style JSClass.enumerate op should define all lazy properties not
|
||||
// yet reflected in obj.
|
||||
@ -421,7 +407,6 @@ struct JSClass {
|
||||
};
|
||||
|
||||
#define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot
|
||||
#define JSCLASS_NEW_ENUMERATE (1<<1) // has JSNewEnumerateOp hook
|
||||
#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports *)
|
||||
#define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM
|
||||
#define JSCLASS_IMPLEMENTS_BARRIERS (1<<5) // Correctly implements GC read
|
||||
|
@ -238,9 +238,6 @@ typedef uint64_t JSValueShiftedTag;
|
||||
typedef enum JSWhyMagic
|
||||
{
|
||||
JS_ELEMENTS_HOLE, /* a hole in a native object's elements */
|
||||
JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded
|
||||
* to JS_EnumerateState, which really means the object can be
|
||||
* enumerated like a native object. */
|
||||
JS_NO_ITER_VALUE, /* there is not a pending iterator value */
|
||||
JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */
|
||||
JS_NO_CONSTANT, /* compiler sentinel value */
|
||||
|
@ -2120,84 +2120,44 @@ TypedObject::obj_deleteGeneric(JSContext *cx, HandleObject obj, HandleId id, boo
|
||||
}
|
||||
|
||||
bool
|
||||
TypedObject::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
|
||||
MutableHandleValue statep, MutableHandleId idp)
|
||||
TypedObject::obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties)
|
||||
{
|
||||
int32_t index;
|
||||
|
||||
MOZ_ASSERT(obj->is<TypedObject>());
|
||||
Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
|
||||
Rooted<TypeDescr *> descr(cx, &typedObj->typeDescr());
|
||||
|
||||
RootedId id(cx);
|
||||
switch (descr->kind()) {
|
||||
case type::Scalar:
|
||||
case type::Reference:
|
||||
case type::Simd:
|
||||
switch (enum_op) {
|
||||
case JSENUMERATE_INIT_ALL:
|
||||
case JSENUMERATE_INIT:
|
||||
statep.setInt32(0);
|
||||
idp.set(INT_TO_JSID(0));
|
||||
|
||||
case JSENUMERATE_NEXT:
|
||||
case JSENUMERATE_DESTROY:
|
||||
statep.setNull();
|
||||
case type::Simd: {
|
||||
// Nothing to enumerate.
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case type::Array:
|
||||
switch (enum_op) {
|
||||
case JSENUMERATE_INIT_ALL:
|
||||
case JSENUMERATE_INIT:
|
||||
statep.setInt32(0);
|
||||
idp.set(INT_TO_JSID(typedObj->length()));
|
||||
break;
|
||||
case type::Array: {
|
||||
if (!properties.reserve(typedObj->length()))
|
||||
return false;
|
||||
|
||||
case JSENUMERATE_NEXT:
|
||||
index = statep.toInt32();
|
||||
|
||||
if (index < typedObj->length()) {
|
||||
idp.set(INT_TO_JSID(index));
|
||||
statep.setInt32(index + 1);
|
||||
} else {
|
||||
MOZ_ASSERT(index == typedObj->length());
|
||||
statep.setNull();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case JSENUMERATE_DESTROY:
|
||||
statep.setNull();
|
||||
break;
|
||||
for (int32_t index = 0; index < typedObj->length(); index++) {
|
||||
id.set(INT_TO_JSID(index));
|
||||
properties.infallibleAppend(id);
|
||||
}
|
||||
break;
|
||||
|
||||
case type::Struct:
|
||||
switch (enum_op) {
|
||||
case JSENUMERATE_INIT_ALL:
|
||||
case JSENUMERATE_INIT:
|
||||
statep.setInt32(0);
|
||||
idp.set(INT_TO_JSID(descr->as<StructTypeDescr>().fieldCount()));
|
||||
break;
|
||||
|
||||
case JSENUMERATE_NEXT:
|
||||
index = static_cast<uint32_t>(statep.toInt32());
|
||||
|
||||
if ((size_t) index < descr->as<StructTypeDescr>().fieldCount()) {
|
||||
idp.set(AtomToId(&descr->as<StructTypeDescr>().fieldName(index)));
|
||||
statep.setInt32(index + 1);
|
||||
} else {
|
||||
statep.setNull();
|
||||
}
|
||||
|
||||
break;
|
||||
case type::Struct: {
|
||||
size_t fieldCount = descr->as<StructTypeDescr>().fieldCount();
|
||||
if (!properties.reserve(fieldCount))
|
||||
return false;
|
||||
|
||||
case JSENUMERATE_DESTROY:
|
||||
statep.setNull();
|
||||
break;
|
||||
for (size_t index = 0; index < fieldCount; index++) {
|
||||
id.set(AtomToId(&descr->as<StructTypeDescr>().fieldName(index)));
|
||||
properties.infallibleAppend(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -581,8 +581,7 @@ class TypedObject : public JSObject
|
||||
|
||||
static bool obj_deleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded);
|
||||
|
||||
static bool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
|
||||
MutableHandleValue statep, MutableHandleId idp);
|
||||
static bool obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties);
|
||||
|
||||
public:
|
||||
TypedProto &typedProto() const {
|
||||
|
@ -232,10 +232,6 @@ JS_CopyPropertyFrom(JSContext *cx, JS::HandleId id, JS::HandleObject target,
|
||||
extern JS_FRIEND_API(bool)
|
||||
JS_WrapPropertyDescriptor(JSContext *cx, JS::MutableHandle<JSPropertyDescriptor> desc);
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
JS_EnumerateState(JSContext *cx, JS::HandleObject obj, JSIterateOp enum_op,
|
||||
JS::MutableHandleValue statep, JS::MutableHandleId idp);
|
||||
|
||||
struct JSFunctionSpecWithHelp {
|
||||
const char *name;
|
||||
JSNative call;
|
||||
|
@ -281,19 +281,30 @@ Snapshot(JSContext *cx, HandleObject pobj_, unsigned flags, AutoIdVector *props)
|
||||
RootedObject pobj(cx, pobj_);
|
||||
|
||||
do {
|
||||
const Class *clasp = pobj->getClass();
|
||||
if (pobj->isNative() &&
|
||||
!pobj->getOps()->enumerate &&
|
||||
!(clasp->flags & JSCLASS_NEW_ENUMERATE))
|
||||
{
|
||||
if (JSEnumerateOp enumerate = clasp->enumerate) {
|
||||
if (JSNewEnumerateOp enumerate = pobj->getOps()->enumerate) {
|
||||
// This hook has the full control over what gets enumerated.
|
||||
AutoIdVector properties(cx);
|
||||
if (!enumerate(cx, pobj, properties))
|
||||
return false;
|
||||
|
||||
for (size_t n = 0; n < properties.length(); n++) {
|
||||
if (!Enumerate(cx, pobj, properties[n], true, flags, ht, props))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pobj->isNative()) {
|
||||
if (!EnumerateNativeProperties(cx, pobj.as<NativeObject>(), flags, ht, props))
|
||||
return false;
|
||||
}
|
||||
} else if (pobj->isNative()) {
|
||||
// Give the object a chance to resolve all lazy properties
|
||||
if (JSEnumerateOp enumerate = pobj->getClass()->enumerate) {
|
||||
if (!enumerate(cx, pobj.as<NativeObject>()))
|
||||
return false;
|
||||
}
|
||||
if (!EnumerateNativeProperties(cx, pobj.as<NativeObject>(), flags, ht, props))
|
||||
return false;
|
||||
} else {
|
||||
if (pobj->is<ProxyObject>()) {
|
||||
} else if (pobj->is<ProxyObject>()) {
|
||||
AutoIdVector proxyProps(cx);
|
||||
if (flags & JSITER_OWNONLY) {
|
||||
if (flags & JSITER_HIDDEN) {
|
||||
@ -319,26 +330,8 @@ Snapshot(JSContext *cx, HandleObject pobj_, unsigned flags, AutoIdVector *props)
|
||||
// Proxy objects enumerate the prototype on their own, so we're
|
||||
// done here.
|
||||
break;
|
||||
}
|
||||
RootedValue state(cx);
|
||||
RootedId id(cx);
|
||||
JSIterateOp op = (flags & JSITER_HIDDEN) ? JSENUMERATE_INIT_ALL : JSENUMERATE_INIT;
|
||||
if (!JSObject::enumerate(cx, pobj, op, &state, &id))
|
||||
return false;
|
||||
if (state.isMagic(JS_NATIVE_ENUMERATE)) {
|
||||
if (!EnumerateNativeProperties(cx, pobj.as<NativeObject>(), flags, ht, props))
|
||||
return false;
|
||||
} else {
|
||||
while (true) {
|
||||
RootedId id(cx);
|
||||
if (!JSObject::enumerate(cx, pobj, JSENUMERATE_NEXT, &state, &id))
|
||||
return false;
|
||||
if (state.isNull())
|
||||
break;
|
||||
if (!Enumerate(cx, pobj, id, true, flags, ht, props))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("non-native objects must have an enumerate op");
|
||||
}
|
||||
|
||||
if (flags & JSITER_OWNONLY)
|
||||
|
@ -3523,27 +3523,6 @@ js::DefaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValu
|
||||
return false;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
JS_EnumerateState(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
|
||||
MutableHandleValue statep, JS::MutableHandleId idp)
|
||||
{
|
||||
/* If the class has a custom JSCLASS_NEW_ENUMERATE hook, call it. */
|
||||
const Class *clasp = obj->getClass();
|
||||
JSEnumerateOp enumerate = clasp->enumerate;
|
||||
if (enumerate) {
|
||||
if (clasp->flags & JSCLASS_NEW_ENUMERATE)
|
||||
return ((JSNewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp);
|
||||
|
||||
if (!enumerate(cx, obj))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Tell InitNativeIterator to treat us like a native object. */
|
||||
MOZ_ASSERT(enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL);
|
||||
statep.setMagic(JS_NATIVE_ENUMERATE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::IsDelegate(JSContext *cx, HandleObject obj, const js::Value &v, bool *result)
|
||||
{
|
||||
@ -3791,7 +3770,6 @@ dumpValue(const Value &v)
|
||||
#ifdef DEBUG
|
||||
switch (v.whyMagic()) {
|
||||
case JS_ELEMENTS_HOLE: fprintf(stderr, " elements hole"); break;
|
||||
case JS_NATIVE_ENUMERATE: fprintf(stderr, " native enumeration"); break;
|
||||
case JS_NO_ITER_VALUE: fprintf(stderr, " no iter value"); break;
|
||||
case JS_GENERATOR_CLOSING: fprintf(stderr, " generator closing"); break;
|
||||
case JS_OPTIMIZED_OUT: fprintf(stderr, " optimized out"); break;
|
||||
|
@ -674,13 +674,6 @@ class JSObject : public js::gc::Cell
|
||||
JS::HandleObject callable);
|
||||
static inline bool unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
|
||||
|
||||
static bool enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp iterop,
|
||||
JS::MutableHandleValue statep, JS::MutableHandleId idp)
|
||||
{
|
||||
JSNewEnumerateOp op = obj->getOps()->enumerate;
|
||||
return (op ? op : JS_EnumerateState)(cx, obj, iterop, statep, idp);
|
||||
}
|
||||
|
||||
static bool defaultValue(JSContext *cx, js::HandleObject obj, JSType hint,
|
||||
js::MutableHandleValue vp)
|
||||
{
|
||||
|
@ -84,24 +84,6 @@ enum JSProtoKey {
|
||||
JSProto_LIMIT
|
||||
};
|
||||
|
||||
/*
|
||||
* This enum type is used to control the behavior of a JSObject property
|
||||
* iterator function that has type JSNewEnumerate.
|
||||
*/
|
||||
enum JSIterateOp {
|
||||
/* Create new iterator state over enumerable properties. */
|
||||
JSENUMERATE_INIT,
|
||||
|
||||
/* Create new iterator state over all properties. */
|
||||
JSENUMERATE_INIT_ALL,
|
||||
|
||||
/* Iterate once. */
|
||||
JSENUMERATE_NEXT,
|
||||
|
||||
/* Destroy iterator state. */
|
||||
JSENUMERATE_DESTROY
|
||||
};
|
||||
|
||||
/* Struct forward declarations. */
|
||||
struct JSClass;
|
||||
struct JSCompartment;
|
||||
|
Loading…
Reference in New Issue
Block a user