Bug 1370608 part 2 - Add JS_NewEnumerateStandardClasses and use it in js/src. r=evilpie

This commit is contained in:
Jan de Mooij 2017-06-14 10:39:07 +02:00
Родитель 83f290de99
Коммит 1a863117ff
5 изменённых файлов: 89 добавлений и 17 удалений

Просмотреть файл

@ -7,12 +7,6 @@
#include "jsapi-tests/tests.h" #include "jsapi-tests/tests.h"
static bool
GlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj)
{
return JS_EnumerateStandardClasses(cx, obj);
}
static bool static bool
GlobalResolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp) GlobalResolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp)
{ {
@ -23,7 +17,7 @@ BEGIN_TEST(testRedefineGlobalEval)
{ {
static const JSClassOps clsOps = { static const JSClassOps clsOps = {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
GlobalEnumerate, nullptr, GlobalResolve, nullptr, nullptr, nullptr, JS_NewEnumerateStandardClasses, GlobalResolve, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook JS_GlobalObjectTraceHook
}; };

Просмотреть файл

@ -1117,6 +1117,63 @@ JS_EnumerateStandardClasses(JSContext* cx, HandleObject obj)
return GlobalObject::initStandardClasses(cx, global); return GlobalObject::initStandardClasses(cx, global);
} }
static bool
EnumerateUnresolvedStandardClasses(JSContext* cx, Handle<GlobalObject*> global,
AutoIdVector& properties, const JSStdName* table)
{
for (unsigned i = 0; !table[i].isSentinel(); i++) {
if (table[i].isDummy())
continue;
JSProtoKey key = table[i].key;
// If the standard class has been resolved, the properties have been
// defined on the global so we don't need to add them here.
if (global->isStandardClassResolved(key))
continue;
if (GlobalObject::skipDeselectedConstructor(cx, key))
continue;
if (const Class* clasp = ProtoKeyToClass(key)) {
if (clasp->flags & JSCLASS_IS_ANONYMOUS)
continue;
if (!clasp->specShouldDefineConstructor())
continue;
}
jsid id = NameToId(AtomStateOffsetToName(cx->names(), table[i].atomOffset));
if (!properties.append(id))
return false;
}
return true;
}
JS_PUBLIC_API(bool)
JS_NewEnumerateStandardClasses(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
bool enumerableOnly)
{
if (enumerableOnly) {
// There are no enumerable lazy properties.
return true;
}
Handle<GlobalObject*> global = obj.as<GlobalObject>();
// It's fine to always append |undefined| here, it's non-configurable and
// the enumeration code filters duplicates.
if (!properties.append(NameToId(cx->names().undefined)))
return false;
if (!EnumerateUnresolvedStandardClasses(cx, global, properties, standard_class_names))
return false;
if (!EnumerateUnresolvedStandardClasses(cx, global, properties, builtin_property_names))
return false;
return true;
}
JS_PUBLIC_API(bool) JS_PUBLIC_API(bool)
JS_GetClassObject(JSContext* cx, JSProtoKey key, MutableHandleObject objp) JS_GetClassObject(JSContext* cx, JSProtoKey key, MutableHandleObject objp)
{ {

Просмотреть файл

@ -1494,9 +1494,10 @@ JS_InitStandardClasses(JSContext* cx, JS::Handle<JSObject*> obj);
* as usual for bool result-typed API entry points. * as usual for bool result-typed API entry points.
* *
* This API can be called directly from a global object class's resolve op, * This API can be called directly from a global object class's resolve op,
* to define standard classes lazily. The class's enumerate op should call * to define standard classes lazily. The class should either have an enumerate
* JS_EnumerateStandardClasses(cx, obj), to define eagerly during for..in * hook that calls JS_EnumerateStandardClasses, or a newEnumerate hook that
* loops any classes not yet resolved lazily. * calls JS_NewEnumerateStandardClasses. newEnumerate is preferred because it's
* faster (does not define all standard classes).
*/ */
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(bool)
JS_ResolveStandardClass(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved); JS_ResolveStandardClass(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved);
@ -1507,6 +1508,10 @@ JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(bool)
JS_EnumerateStandardClasses(JSContext* cx, JS::HandleObject obj); JS_EnumerateStandardClasses(JSContext* cx, JS::HandleObject obj);
extern JS_PUBLIC_API(bool)
JS_NewEnumerateStandardClasses(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
bool enumerableOnly);
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(bool)
JS_GetClassObject(JSContext* cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp); JS_GetClassObject(JSContext* cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp);

Просмотреть файл

@ -2769,10 +2769,24 @@ js::PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result, I
// Force lazy properties to be resolved. // Force lazy properties to be resolved.
if (obj->isNative()) { if (obj->isNative()) {
if (JSEnumerateOp enumerate = obj->getClass()->getEnumerate()) { const Class* clasp = obj->getClass();
if (JSEnumerateOp enumerate = clasp->getEnumerate()) {
if (!enumerate(cx, obj.as<NativeObject>())) if (!enumerate(cx, obj.as<NativeObject>()))
return false; return false;
} }
if (clasp->getNewEnumerate() && clasp->getResolve()) {
AutoIdVector properties(cx);
if (!clasp->getNewEnumerate()(cx, obj, properties, /* enumerableOnly = */ false))
return false;
RootedId id(cx);
for (size_t i = 0; i < properties.length(); i++) {
id = properties[i];
bool found;
if (!HasOwnProperty(cx, obj, id, &found))
return false;
}
}
} }
// Sparsify dense elements, to make sure no element can be added without a // Sparsify dense elements, to make sure no element can be added without a

Просмотреть файл

@ -3068,7 +3068,8 @@ typedef struct ComplexObject {
} ComplexObject; } ComplexObject;
static bool static bool
sandbox_enumerate(JSContext* cx, HandleObject obj) sandbox_enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
bool enumerableOnly)
{ {
RootedValue v(cx); RootedValue v(cx);
@ -3078,7 +3079,7 @@ sandbox_enumerate(JSContext* cx, HandleObject obj)
if (!ToBoolean(v)) if (!ToBoolean(v))
return true; return true;
return JS_EnumerateStandardClasses(cx, obj); return JS_NewEnumerateStandardClasses(cx, obj, properties, enumerableOnly);
} }
static bool static bool
@ -3095,7 +3096,7 @@ sandbox_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
static const JSClassOps sandbox_classOps = { static const JSClassOps sandbox_classOps = {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
sandbox_enumerate, nullptr, sandbox_resolve, nullptr, sandbox_enumerate, sandbox_resolve,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook JS_GlobalObjectTraceHook
@ -7016,10 +7017,11 @@ js::shell::WarningReporter(JSContext* cx, JSErrorReport* report)
} }
static bool static bool
global_enumerate(JSContext* cx, HandleObject obj) global_enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
bool enumerableOnly)
{ {
#ifdef LAZY_STANDARD_CLASSES #ifdef LAZY_STANDARD_CLASSES
return JS_EnumerateStandardClasses(cx, obj); return JS_NewEnumerateStandardClasses(cx, obj, properties, enumerableOnly);
#else #else
return true; return true;
#endif #endif
@ -7043,7 +7045,7 @@ global_mayResolve(const JSAtomState& names, jsid id, JSObject* maybeObj)
static const JSClassOps global_classOps = { static const JSClassOps global_classOps = {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
global_enumerate, nullptr, global_resolve, global_mayResolve, nullptr, global_enumerate, global_resolve, global_mayResolve,
nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook JS_GlobalObjectTraceHook