Bug 1155946 part 1 - Add a mayResolve class hook to optimize objects with resolve hooks better. r=bhackett

This commit is contained in:
Jan de Mooij 2015-04-23 15:51:28 +02:00
parent 2f41005dd9
commit bfb27c97d1
65 changed files with 207 additions and 84 deletions

View File

@ -476,6 +476,7 @@ class CGDOMJSClass(CGThing):
nullptr, /* setProperty */
${enumerate}, /* enumerate */
${resolve}, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
${finalize}, /* finalize */
${call}, /* call */
@ -616,6 +617,7 @@ class CGPrototypeJSClass(CGThing):
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */
@ -709,6 +711,7 @@ class CGInterfaceObjectJSClass(CGThing):
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
${ctorname}, /* call */

View File

@ -20125,6 +20125,7 @@ const JSClass CreateIndexOp::ThreadLocalJSRuntime::kGlobalClass = {
/* setProperty */ nullptr,
/* enumerate */ nullptr,
/* resolve */ nullptr,
/* mayResolve */ nullptr,
/* convert */ nullptr,
/* finalize */ nullptr,
/* call */ nullptr,

View File

@ -213,6 +213,7 @@ const static js::Class sNPObjectJSWrapperClass =
NPObjWrapper_SetProperty,
nullptr,
NPObjWrapper_Resolve,
nullptr, /* mayResolve */
NPObjWrapper_Convert,
NPObjWrapper_Finalize,
NPObjWrapper_Call,
@ -265,7 +266,7 @@ static const JSClass sNPObjectMemberClass =
{
"NPObject Ambiguous Member class", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, NPObjectMember_Convert,
nullptr, nullptr, nullptr, NPObjectMember_Convert,
NPObjectMember_Finalize, NPObjectMember_Call,
nullptr, nullptr, NPObjectMember_Trace
};

View File

@ -599,6 +599,7 @@ const js::Class workerdebuggersandbox_class = {
nullptr,
workerdebuggersandbox_enumerate,
workerdebuggersandbox_resolve,
nullptr, /* mayResolve */
workerdebuggersandbox_convert,
workerdebuggersandbox_finalize,
nullptr,

View File

@ -93,7 +93,7 @@ static const JSClass gPrototypeJSClass = {
// Our one reserved slot holds the relevant nsXBLPrototypeBinding
JSCLASS_HAS_RESERVED_SLOTS(1),
nullptr, nullptr, nullptr, nullptr,
XBLEnumerate, nullptr,
XBLEnumerate, nullptr, nullptr,
nullptr, XBLFinalize,
nullptr, nullptr, nullptr, nullptr
};

View File

@ -24,6 +24,7 @@
* object behavior and, e.g., allows custom slow layout.
*/
struct JSAtomState;
struct JSFreeOp;
struct JSFunctionSpec;
@ -281,6 +282,18 @@ typedef bool
(* JSResolveOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
bool* resolvedp);
// A class with a resolve hook can optionally have a mayResolve hook. This hook
// must have no side effects and must return true for a given id if the resolve
// hook may resolve this id. This is useful when we're doing a "pure" lookup: if
// mayResolve returns false, we know we don't have to call the effectful resolve
// hook.
//
// maybeObj, if non-null, is the object on which we're doing the lookup. This
// can be nullptr: during JIT compilation we sometimes know the Class but not
// the object.
typedef bool
(* JSMayResolveOp)(const JSAtomState& names, jsid id, JSObject* maybeObj);
// Convert obj to the given type, returning true with the resulting value in
// *vp on success, and returning false on error or exception.
typedef bool
@ -420,6 +433,7 @@ typedef void
JSSetterOp setProperty; \
JSEnumerateOp enumerate; \
JSResolveOp resolve; \
JSMayResolveOp mayResolve; \
JSConvertOp convert; \
FinalizeOpType finalize; \
JSNative call; \
@ -688,6 +702,8 @@ static_assert(offsetof(JSClass, enumerate) == offsetof(Class, enumerate),
"Class and JSClass must be consistent");
static_assert(offsetof(JSClass, resolve) == offsetof(Class, resolve),
"Class and JSClass must be consistent");
static_assert(offsetof(JSClass, mayResolve) == offsetof(Class, mayResolve),
"Class and JSClass must be consistent");
static_assert(offsetof(JSClass, convert) == offsetof(Class, convert),
"Class and JSClass must be consistent");
static_assert(offsetof(JSClass, finalize) == offsetof(Class, finalize),

View File

@ -998,6 +998,7 @@ const Class AsmJSModuleObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
AsmJSModuleObject_finalize,
nullptr, /* call */

View File

@ -565,6 +565,7 @@ static const Class CollatorClass = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
collator_finalize
};
@ -1057,6 +1058,7 @@ static const Class NumberFormatClass = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
numberFormat_finalize
};
@ -1516,6 +1518,7 @@ static const Class DateTimeFormatClass = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
dateTimeFormat_finalize
};

View File

@ -880,6 +880,7 @@ const Class MapIteratorObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
MapIteratorObject::finalize
};
@ -1024,6 +1025,7 @@ const Class MapObject::class_ = {
nullptr, // setProperty
nullptr, // enumerate
nullptr, // resolve
nullptr, // mayResolve
nullptr, // convert
finalize,
nullptr, // call
@ -1616,6 +1618,7 @@ const Class SetIteratorObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
SetIteratorObject::finalize
};
@ -1756,6 +1759,7 @@ const Class SetObject::class_ = {
nullptr, // setProperty
nullptr, // enumerate
nullptr, // resolve
nullptr, // mayResolve
nullptr, // convert
finalize,
nullptr, // call

View File

@ -1189,6 +1189,7 @@ const Class PlainObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */

View File

@ -180,6 +180,7 @@ const Class SimdTypeDescr::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
TypeDescr::finalize,
call

View File

@ -25,6 +25,7 @@ const Class SymbolObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
convert
};

View File

@ -1154,6 +1154,7 @@ static const JSClass FinalizeCounterClass = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
finalize_counter_finalize
};
@ -1835,6 +1836,7 @@ const Class CloneBufferObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
Finalize
};

View File

@ -224,6 +224,7 @@ const Class js::ScalarTypeDescr::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
TypeDescr::finalize,
ScalarTypeDescr::call
@ -321,6 +322,7 @@ const Class js::ReferenceTypeDescr::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
TypeDescr::finalize,
ReferenceTypeDescr::call
@ -500,6 +502,7 @@ const Class ArrayTypeDescr::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
TypeDescr::finalize,
nullptr, /* call */
@ -727,6 +730,7 @@ const Class StructTypeDescr::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
TypeDescr::finalize,
nullptr, /* call */
@ -2246,6 +2250,7 @@ OutlineTransparentTypedObject::getOrCreateBuffer(JSContext* cx)
nullptr, /* setProperty */ \
nullptr, /* enumerate */ \
nullptr, /* resolve */ \
nullptr, /* mayResolve */ \
nullptr, /* convert */ \
nullptr, /* finalize */ \
nullptr, /* call */ \

View File

@ -533,7 +533,7 @@ static const JSClass sCABIClass = {
static const JSClass sCTypeProtoClass = {
"CType",
JSCLASS_HAS_RESERVED_SLOTS(CTYPEPROTO_SLOTS),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
ConstructAbstract, nullptr, ConstructAbstract
};
@ -548,7 +548,7 @@ static const JSClass sCDataProtoClass = {
static const JSClass sCTypeClass = {
"CType",
JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, CType::Finalize,
CType::ConstructData, CType::HasInstance, CType::ConstructData,
CType::Trace
@ -558,14 +558,14 @@ static const JSClass sCDataClass = {
"CData",
JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS),
nullptr, nullptr, ArrayType::Getter, ArrayType::Setter,
nullptr, nullptr, nullptr, CData::Finalize,
nullptr, nullptr, nullptr, nullptr, CData::Finalize,
FunctionType::Call, nullptr, FunctionType::Call
};
static const JSClass sCClosureClass = {
"CClosure",
JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, CClosure::Finalize,
nullptr, nullptr, nullptr, CClosure::Trace
};
@ -587,7 +587,7 @@ static const JSClass sCDataFinalizerProtoClass = {
static const JSClass sCDataFinalizerClass = {
"CDataFinalizer",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(CDATAFINALIZER_SLOTS),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, CDataFinalizer::Finalize
};
@ -773,14 +773,14 @@ static const JSClass sUInt64ProtoClass = {
static const JSClass sInt64Class = {
"Int64",
JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, Int64Base::Finalize
};
static const JSClass sUInt64Class = {
"UInt64",
JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, Int64Base::Finalize
};

View File

@ -35,7 +35,7 @@ typedef Rooted<JSFlatString*> RootedFlatString;
static const JSClass sLibraryClass = {
"Library",
JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, Library::Finalize
};

View File

@ -17,7 +17,7 @@ const JSClass global_class = {
"global", JSCLASS_GLOBAL_FLAGS,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};

View File

@ -7102,18 +7102,8 @@ ObjectHasExtraOwnProperty(CompileCompartment* comp, TypeSet::ObjectKey* object,
return name == comp->runtime()->names().length;
// Resolve hooks can install new properties on objects on demand.
if (!clasp->resolve)
return false;
if (clasp->resolve == str_resolve) {
// str_resolve only resolves integers, not names.
return false;
}
if (clasp->resolve == fun_resolve)
return FunctionHasResolveHook(comp->runtime()->names(), NameToId(name));
return true;
JSObject* singleton = object->isSingleton() ? object->singleton() : nullptr;
return ClassMayResolveId(comp->runtime()->names(), clasp, NameToId(name), singleton);
}
void

View File

@ -22,6 +22,7 @@ static const JSClass global_class = {
nullptr,
nullptr,
nullptr,
nullptr,
JS_GlobalObjectTraceHook
};

View File

@ -25,7 +25,7 @@ BEGIN_TEST(testRedefineGlobalEval)
"global", JSCLASS_GLOBAL_FLAGS,
nullptr, nullptr, nullptr, nullptr,
GlobalEnumerate, GlobalResolve, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};

View File

@ -27,6 +27,7 @@ static const js::Class TenuredClass = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* ??? */
_finalize,
nullptr, /* call */
@ -47,6 +48,7 @@ static const js::Class NurseryClass = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* ??? */
_finalize,
nullptr, /* call */

View File

@ -98,7 +98,7 @@ BEGIN_TEST(testNewObject_1)
0,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, constructHook
nullptr, nullptr, nullptr, constructHook
};
JS::RootedObject ctor(cx, JS_NewObject(cx, &cls));
CHECK(ctor);

View File

@ -23,7 +23,7 @@ static const JSClass myClass = {
"MyClass",
0,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, my_convert
nullptr, nullptr, nullptr, my_convert
};
static bool

View File

@ -29,6 +29,7 @@ const JSClass BarkWhenTracedClass::class_ = {
nullptr,
nullptr,
nullptr,
nullptr,
finalize,
nullptr,
nullptr,

View File

@ -148,6 +148,7 @@ JSObject* newKey()
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */
@ -204,6 +205,7 @@ JSObject* newDelegate()
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */

View File

@ -230,7 +230,7 @@ class JSAPITest
"global", JSCLASS_GLOBAL_FLAGS,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};
return &c;

View File

@ -1138,13 +1138,12 @@ typedef struct JSStdName {
} JSStdName;
static const JSStdName*
LookupStdName(JSRuntime* rt, HandleString name, const JSStdName* table)
LookupStdName(const JSAtomState& names, JSAtom* name, const JSStdName* table)
{
MOZ_ASSERT(name->isAtom());
for (unsigned i = 0; !table[i].isSentinel(); i++) {
if (table[i].isDummy())
continue;
JSAtom* atom = AtomStateOffsetToName(*rt->commonNames, table[i].atomOffset);
JSAtom* atom = AtomStateOffsetToName(names, table[i].atomOffset);
MOZ_ASSERT(atom);
if (name == atom)
return &table[i];
@ -1220,11 +1219,10 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso
if (!rt->hasContexts() || !JSID_IS_ATOM(id))
return true;
RootedString idstr(cx, JSID_TO_STRING(id));
/* Check whether we're resolving 'undefined', and define it if so. */
JSAtom* idAtom = JSID_TO_ATOM(id);
JSAtom* undefinedAtom = cx->names().undefined;
if (idstr == undefinedAtom) {
if (idAtom == undefinedAtom) {
*resolved = true;
return DefineProperty(cx, obj, undefinedAtom->asPropertyName(),
UndefinedHandleValue, nullptr, nullptr,
@ -1232,11 +1230,11 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso
}
/* Try for class constructors/prototypes named by well-known atoms. */
stdnm = LookupStdName(rt, idstr, standard_class_names);
stdnm = LookupStdName(cx->names(), idAtom, standard_class_names);
/* Try less frequently used top-level functions and constants. */
if (!stdnm)
stdnm = LookupStdName(rt, idstr, builtin_property_names);
stdnm = LookupStdName(cx->names(), idAtom, builtin_property_names);
// If this class is anonymous, then it doesn't exist as a global
// property, so we won't resolve anything.
@ -1260,6 +1258,27 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso
return true;
}
JS_PUBLIC_API(bool)
JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj)
{
MOZ_ASSERT_IF(maybeObj, maybeObj->is<GlobalObject>());
// The global object's resolve hook is special: JS_ResolveStandardClass
// initializes the prototype chain lazily. Only attempt to optimize here
// if we know the prototype chain has been initialized.
if (!maybeObj || !maybeObj->getProto())
return true;
if (!JSID_IS_ATOM(id))
return false;
JSAtom* atom = JSID_TO_ATOM(id);
return atom == names.undefined ||
LookupStdName(names, atom, standard_class_names) ||
LookupStdName(names, atom, builtin_property_names);
}
JS_PUBLIC_API(bool)
JS_EnumerateStandardClasses(JSContext* cx, HandleObject obj)
{
@ -1305,8 +1324,9 @@ JS_IdToProtoKey(JSContext* cx, HandleId id)
if (!JSID_IS_ATOM(id))
return JSProto_Null;
RootedString idstr(cx, JSID_TO_STRING(id));
const JSStdName* stdnm = LookupStdName(cx->runtime(), idstr, standard_class_names);
JSAtom* atom = JSID_TO_ATOM(id);
const JSStdName* stdnm = LookupStdName(cx->names(), atom, standard_class_names);
if (!stdnm)
return JSProto_Null;

View File

@ -1506,6 +1506,9 @@ JS_InitStandardClasses(JSContext* cx, JS::Handle<JSObject*> obj);
extern JS_PUBLIC_API(bool)
JS_ResolveStandardClass(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved);
extern JS_PUBLIC_API(bool)
JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj);
extern JS_PUBLIC_API(bool)
JS_EnumerateStandardClasses(JSContext* cx, JS::HandleObject obj);

View File

@ -3249,6 +3249,7 @@ const Class ArrayObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */

View File

@ -3044,6 +3044,7 @@ const Class DateObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
date_convert,
nullptr, /* finalize */
nullptr, /* call */

View File

@ -77,6 +77,7 @@ static const JSFunctionSpec exception_methods[] = {
nullptr, /* setProperty */ \
nullptr, /* enumerate */ \
nullptr, /* resolve */ \
nullptr, /* mayResolve */ \
nullptr, /* convert */ \
exn_finalize, \
nullptr, /* call */ \
@ -108,6 +109,7 @@ ErrorObject::classes[JSEXN_LIMIT] = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
exn_finalize,
nullptr, /* call */

View File

@ -319,6 +319,7 @@ namespace js {
nullptr, /* setProperty */ \
nullptr, /* enumerate */ \
nullptr, /* resolve */ \
nullptr, /* mayResolve */ \
js::proxy_Convert, \
js::proxy_Finalize, /* finalize */ \
nullptr, /* call */ \

View File

@ -419,18 +419,18 @@ ResolveInterpretedFunctionPrototype(JSContext* cx, HandleObject obj)
return proto;
}
bool
js::FunctionHasResolveHook(const JSAtomState& atomState, jsid id)
static bool
fun_mayResolve(const JSAtomState& names, jsid id, JSObject*)
{
if (!JSID_IS_ATOM(id))
return false;
JSAtom* atom = JSID_TO_ATOM(id);
return atom == atomState.prototype || atom == atomState.length || atom == atomState.name;
return atom == names.prototype || atom == names.length || atom == names.name;
}
bool
js::fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
static bool
fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
{
if (!JSID_IS_ATOM(id))
return true;
@ -891,7 +891,8 @@ const Class JSFunction::class_ = {
nullptr, /* getProperty */
nullptr, /* setProperty */
fun_enumerate,
js::fun_resolve,
fun_resolve,
fun_mayResolve,
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */

View File

@ -53,8 +53,8 @@ class JSFunction : public js::NativeObject
must be constructible but not decompilable. */
HAS_REST = 0x0200, /* function has a rest (...) parameter */
INTERPRETED_LAZY = 0x0400, /* function is interpreted but doesn't have a script yet */
RESOLVED_LENGTH = 0x0800, /* f.length has been resolved (see js::fun_resolve). */
RESOLVED_NAME = 0x1000, /* f.name has been resolved (see js::fun_resolve). */
RESOLVED_LENGTH = 0x0800, /* f.length has been resolved (see fun_resolve). */
RESOLVED_NAME = 0x1000, /* f.name has been resolved (see fun_resolve). */
FUNCTION_KIND_SHIFT = 13,
FUNCTION_KIND_MASK = 0x3 << FUNCTION_KIND_SHIFT,
@ -568,9 +568,6 @@ DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native,
bool
FunctionHasResolveHook(const JSAtomState& atomState, jsid id);
extern bool
fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp);
extern bool
fun_toString(JSContext* cx, unsigned argc, Value* vp);

View File

@ -988,6 +988,7 @@ const Class PropertyIteratorObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
finalize,
nullptr, /* call */
@ -1375,6 +1376,7 @@ const Class StopIterationObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */

View File

@ -2784,19 +2784,10 @@ js::LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject**
return true;
}
// Fail if there's a resolve hook. We allow the JSFunction resolve hook
// if we know it will never add a property with this name or str_resolve
// with a non-integer property.
do {
const Class* clasp = obj->getClass();
if (!clasp->resolve)
break;
if (clasp->resolve == fun_resolve && !FunctionHasResolveHook(cx->names(), id))
break;
if (clasp->resolve == str_resolve && !JSID_IS_INT(id))
break;
// Fail if there's a resolve hook, unless the mayResolve hook tells
// us the resolve hook won't define a property with this id.
if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj))
return false;
} while (0);
} else if (obj->is<UnboxedPlainObject>()) {
if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
*objp = obj;

View File

@ -1361,6 +1361,7 @@ const Class ScriptSourceObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
finalize,
nullptr, /* call */

View File

@ -394,8 +394,15 @@ str_enumerate(JSContext* cx, HandleObject obj)
return true;
}
bool
js::str_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
static bool
str_mayResolve(const JSAtomState&, jsid id, JSObject*)
{
// str_resolve ignores non-integer ids.
return JSID_IS_INT(id);
}
static bool
str_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
{
if (!JSID_IS_INT(id))
return true;
@ -424,7 +431,8 @@ const Class StringObject::class_ = {
nullptr, /* getProperty */
nullptr, /* setProperty */
str_enumerate,
str_resolve
str_resolve,
str_mayResolve
};
/*

View File

@ -408,9 +408,6 @@ str_split(JSContext* cx, unsigned argc, Value* vp);
JSObject*
str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep);
bool
str_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp);
bool
str_replace_regexp_raw(JSContext* cx, HandleString string, HandleObject regexp,
HandleString replacement, MutableHandleValue rval);

View File

@ -616,6 +616,7 @@ const Class WeakMapObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
WeakMap_finalize,
nullptr, /* call */

View File

@ -163,7 +163,7 @@ static void pm_finalize(JSFreeOp* fop, JSObject* obj);
static const JSClass pm_class = {
"PerfMeasurement", JSCLASS_HAS_PRIVATE,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, pm_finalize
};

View File

@ -2660,7 +2660,7 @@ static const JSClass sandbox_class = {
JSCLASS_GLOBAL_FLAGS,
nullptr, nullptr, nullptr, nullptr,
sandbox_enumerate, sandbox_resolve,
nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};
@ -5119,10 +5119,16 @@ global_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
return true;
}
static bool
global_mayResolve(const JSAtomState& names, jsid id, JSObject* maybeObj)
{
return JS_MayResolveStandardClass(names, id, maybeObj);
}
static const JSClass global_class = {
"global", JSCLASS_GLOBAL_FLAGS,
nullptr, nullptr, nullptr, nullptr,
global_enumerate, global_resolve,
global_enumerate, global_resolve, global_mayResolve,
nullptr, nullptr,
nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook

View File

@ -560,6 +560,7 @@ const Class NormalArgumentsObject::class_ = {
nullptr, /* setProperty */
args_enumerate,
args_resolve,
nullptr, /* mayResolve */
nullptr, /* convert */
ArgumentsObject::finalize,
nullptr, /* call */
@ -584,6 +585,7 @@ const Class StrictArgumentsObject::class_ = {
nullptr, /* setProperty */
strictargs_enumerate,
strictargs_resolve,
nullptr, /* mayResolve */
nullptr, /* convert */
ArgumentsObject::finalize,
nullptr, /* call */

View File

@ -108,6 +108,7 @@ const Class ArrayBufferObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
ArrayBufferObject::finalize,
nullptr, /* call */

View File

@ -2405,7 +2405,7 @@ const Class Debugger::jsclass = {
"Debugger",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUG_COUNT),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, Debugger::finalize,
nullptr, /* call */
nullptr, /* hasInstance */
@ -4204,7 +4204,7 @@ const Class DebuggerScript_class = {
"Script",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSCRIPT_COUNT),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, /* call */
nullptr, /* hasInstance */
@ -5225,7 +5225,7 @@ const Class DebuggerSource_class = {
"Source",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSOURCE_COUNT),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, /* call */
nullptr, /* hasInstance */
@ -5580,7 +5580,7 @@ DebuggerFrame_finalize(FreeOp* fop, JSObject* obj)
const Class DebuggerFrame_class = {
"Frame", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGFRAME_COUNT),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, DebuggerFrame_finalize
};
@ -6342,7 +6342,7 @@ const Class DebuggerObject_class = {
"Object",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGOBJECT_COUNT),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, /* call */
nullptr, /* hasInstance */
@ -7252,7 +7252,7 @@ const Class DebuggerEnv_class = {
"Environment",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGENV_COUNT),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, /* call */
nullptr, /* hasInstance */

View File

@ -506,7 +506,7 @@ GlobalDebuggees_finalize(FreeOp* fop, JSObject* obj)
static const Class
GlobalDebuggees_class = {
"GlobalDebuggee", JSCLASS_HAS_PRIVATE,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, GlobalDebuggees_finalize
};

View File

@ -192,7 +192,7 @@ static const JSClass parseTaskGlobalClass = {
"internal-parse-task-global", JSCLASS_GLOBAL_FLAGS,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};

View File

@ -414,6 +414,11 @@ CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleS
if (!resolved)
return true;
// Assert the mayResolve hook, if there is one, returns true for this
// property.
MOZ_ASSERT_IF(obj->getClass()->mayResolve,
obj->getClass()->mayResolve(cx->names(), id, obj));
if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
MarkDenseOrTypedArrayElementFound<CanGC>(propp);
return true;
@ -425,6 +430,28 @@ CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleS
return true;
}
static MOZ_ALWAYS_INLINE bool
ClassMayResolveId(const JSAtomState& names, const Class* clasp, jsid id, JSObject* maybeObj)
{
MOZ_ASSERT_IF(maybeObj, maybeObj->getClass() == clasp);
if (!clasp->resolve) {
// Sanity check: we should only have a mayResolve hook if we have a
// resolve hook.
MOZ_ASSERT(!clasp->mayResolve, "Class with mayResolve hook but no resolve hook");
return false;
}
if (clasp->mayResolve) {
// Tell the analysis our mayResolve hooks won't trigger GC.
JS::AutoSuppressGCAnalysis nogc;
if (!clasp->mayResolve(names, id, maybeObj))
return false;
}
return true;
}
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE bool
LookupOwnPropertyInline(ExclusiveContext* cx,

View File

@ -296,7 +296,7 @@ ForOfPIC_traceObject(JSTracer* trc, JSObject* obj)
const Class ForOfPIC::jsclass = {
"ForOfPIC", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, ForOfPIC_finalize,
nullptr, /* call */
nullptr, /* hasInstance */

View File

@ -269,6 +269,7 @@ const Class RegExpObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */

View File

@ -44,6 +44,7 @@ const Class RegExpStaticsObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
resc_finalize,
nullptr, /* call */

View File

@ -185,6 +185,7 @@ SavedFrame::finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject
nullptr, // setProperty
nullptr, // enumerate
nullptr, // resolve
nullptr, // mayResolve
nullptr, // convert
SavedFrame::finalize, // finalize
nullptr, // call

View File

@ -540,6 +540,7 @@ const Class DynamicWithObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */
@ -977,6 +978,7 @@ const Class UninitializedLexicalObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */

View File

@ -1542,7 +1542,7 @@ JSRuntime::createSelfHostingGlobal(JSContext* cx)
"self-hosting-global", JSCLASS_GLOBAL_FLAGS,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};

View File

@ -313,6 +313,7 @@ const Class SharedArrayBufferObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
SharedArrayBufferObject::Finalize,
nullptr, /* call */

View File

@ -711,6 +711,7 @@ IMPL_SHARED_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
nullptr, /* setProperty */ \
nullptr, /* enumerate */ \
nullptr, /* resolve */ \
nullptr, /* mayResolve */ \
nullptr, /* convert */ \
nullptr, /* finalize */ \
nullptr, /* call */ \
@ -732,6 +733,7 @@ IMPL_SHARED_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
nullptr, /* setProperty */ \
nullptr, /* enumerate */ \
nullptr, /* resolve */ \
nullptr, /* mayResolve */ \
nullptr, /* convert */ \
nullptr, /* finalize */ \
nullptr, /* call */ \

View File

@ -839,6 +839,7 @@ TypedArrayObject::sharedTypedArrayPrototypeClass = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */
@ -1801,6 +1802,7 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
nullptr, /* setProperty */ \
nullptr, /* enumerate */ \
nullptr, /* resolve */ \
nullptr, /* mayResolve */ \
nullptr, /* convert */ \
nullptr, /* finalize */ \
nullptr, /* call */ \
@ -1846,6 +1848,7 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
nullptr, /* setProperty */ \
nullptr, /* enumerate */ \
nullptr, /* resolve */ \
nullptr, /* mayResolve */ \
nullptr, /* convert */ \
nullptr, /* finalize */ \
nullptr, /* call */ \
@ -1901,6 +1904,7 @@ const Class DataViewObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */

View File

@ -893,6 +893,7 @@ const Class UnboxedPlainObject::class_ = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
nullptr, /* finalize */
nullptr, /* call */

View File

@ -468,7 +468,9 @@ static const js::Class SandboxClass = {
"Sandbox",
XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
nullptr, nullptr, nullptr, nullptr,
sandbox_enumerate, sandbox_resolve, sandbox_convert, sandbox_finalize,
sandbox_enumerate, sandbox_resolve,
nullptr, /* mayResolve */
sandbox_convert, sandbox_finalize,
nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook,
JS_NULL_CLASS_SPEC,
{
@ -487,7 +489,9 @@ static const js::Class SandboxWriteToProtoClass = {
"Sandbox",
XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
sandbox_addProperty, nullptr, nullptr, nullptr,
sandbox_enumerate, sandbox_resolve, sandbox_convert, sandbox_finalize,
sandbox_enumerate, sandbox_resolve,
nullptr, /* mayResolve */
sandbox_convert, sandbox_finalize,
nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook,
JS_NULL_CLASS_SPEC,
{

View File

@ -1456,6 +1456,7 @@ static const JSClass XPCOutParamClass = {
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* convert */
FinalizeStub,
nullptr, /* call */

View File

@ -648,6 +648,7 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = {
XPC_WN_Shared_Enumerate, // enumerate
XPC_WN_NoHelper_Resolve, // resolve
nullptr, // mayResolve
XPC_WN_Shared_Convert, // convert
XPC_WN_NoHelper_Finalize, // finalize
@ -1288,6 +1289,7 @@ const js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = {
nullptr, // setProperty;
XPC_WN_Shared_Proto_Enumerate, // enumerate;
XPC_WN_ModsAllowed_Proto_Resolve, // resolve;
nullptr, // mayResolve;
nullptr, // convert;
XPC_WN_Shared_Proto_Finalize, // finalize;
@ -1313,6 +1315,7 @@ const js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass = {
nullptr, // setProperty;
XPC_WN_Shared_Proto_Enumerate, // enumerate;
XPC_WN_ModsAllowed_Proto_Resolve, // resolve;
nullptr, // mayResolve;
nullptr, // convert;
XPC_WN_Shared_Proto_Finalize, // finalize;
@ -1391,6 +1394,7 @@ const js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = {
nullptr, // setProperty;
XPC_WN_Shared_Proto_Enumerate, // enumerate;
XPC_WN_NoMods_Proto_Resolve, // resolve;
nullptr, // mayResolve;
nullptr, // convert;
XPC_WN_Shared_Proto_Finalize, // finalize;
@ -1416,6 +1420,7 @@ const js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = {
nullptr, // setProperty;
XPC_WN_Shared_Proto_Enumerate, // enumerate;
XPC_WN_NoMods_Proto_Resolve, // resolve;
nullptr, // mayResolve;
nullptr, // convert;
XPC_WN_Shared_Proto_Finalize, // finalize;
@ -1511,6 +1516,7 @@ const js::Class XPC_WN_Tearoff_JSClass = {
nullptr, // setProperty;
XPC_WN_TearOff_Enumerate, // enumerate;
XPC_WN_TearOff_Resolve, // resolve;
nullptr, // mayResolve;
XPC_WN_Shared_Convert, // convert;
XPC_WN_TearOff_Finalize, // finalize;

View File

@ -887,7 +887,7 @@ ExpandoObjectFinalize(JSFreeOp* fop, JSObject* obj)
const JSClass ExpandoObjectClass = {
"XrayExpandoObject",
JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_EXPANDO_COUNT),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, ExpandoObjectFinalize
};

View File

@ -669,7 +669,7 @@ const JSClass JSRuntimeWrapper::sGlobalClass = {
"PACResolutionThreadGlobal",
JSCLASS_GLOBAL_FLAGS,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};

View File

@ -120,6 +120,7 @@ static const JSClass sWitnessClass = {
nullptr /* setProperty */,
nullptr /* enumerate */,
nullptr /* resolve */,
nullptr /* mayResolve */,
nullptr /* convert */,
Finalize /* finalize */
};

View File

@ -88,7 +88,7 @@ CreateGlobalAndRunTest(JSRuntime* rt, JSContext* cx)
"global", JSCLASS_GLOBAL_FLAGS,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};