Bug 846111 - Part 1: Pure paths for looking up native slot properties. (r=bhackett)

This commit is contained in:
Shu-yu Guo 2013-04-10 11:04:23 -07:00
parent 0639dc9cba
commit 9d891a80ae
6 changed files with 189 additions and 1 deletions

View File

@ -3854,6 +3854,109 @@ baseops::GetPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, jsid
return GetPropertyHelperInline<NoGC>(cx, obj, receiver, id, 0, vp);
}
static JS_ALWAYS_INLINE bool
LookupPropertyPureInline(JSObject *obj, jsid id, JSObject **objp, Shape **propp)
{
if (!obj->isNative())
return false;
JSObject *current = obj;
while (true) {
/* Search for a native dense element or property. */
{
if (JSID_IS_INT(id) && current->containsDenseElement(JSID_TO_INT(id))) {
*objp = current;
MarkDenseElementFound<NoGC>(propp);
return true;
}
if (Shape *shape = current->nativeLookupPure(id)) {
*objp = current;
*propp = shape;
return true;
}
}
/* Fail if there's a resolve hook. */
if (current->getClass()->resolve != JS_ResolveStub)
return false;
JSObject *proto = current->getProto();
if (!proto)
break;
if (!proto->isNative())
return false;
current = proto;
}
*objp = NULL;
*propp = NULL;
return true;
}
static JS_ALWAYS_INLINE bool
NativeGetPureInline(JSObject *pobj, Shape *shape, Value *vp)
{
JS_ASSERT(pobj->isNative());
if (shape->hasSlot()) {
*vp = pobj->nativeGetSlot(shape->slot());
JS_ASSERT(!vp->isMagic());
} else {
vp->setUndefined();
}
/* Fail if we have a custom getter. */
return shape->hasDefaultGetter();
}
bool
js::LookupPropertyPure(JSObject *obj, jsid id, JSObject **objp, Shape **propp)
{
return LookupPropertyPureInline(obj, id, objp, propp);
}
/*
* A pure version of GetPropertyHelper that can be called from parallel code
* without locking. This code path cannot GC. This variant returns false
* whenever a side-effect might have occured in the effectful version. This
* includes, but is not limited to:
*
* - Any object in the lookup chain has a non-stub resolve hook.
* - Any object in the lookup chain is non-native.
* - Hashification of a shape tree into a shape table.
* - The property has a getter.
*/
bool
js::GetPropertyPure(JSObject *obj, jsid id, Value *vp)
{
JSObject *obj2;
Shape *shape;
if (!LookupPropertyPureInline(obj, id, &obj2, &shape))
return false;
/*
* If we couldn't find the property, fail if any of the following edge
* cases appear.
*/
if (!shape) {
/* Do we have a non-stub class op hook? */
if (obj->getClass()->getProperty && obj->getClass()->getProperty != JS_PropertyStub)
return false;
vp->setUndefined();
return true;
}
if (IsImplicitDenseElement(shape)) {
*vp = obj2->getDenseElement(JSID_TO_INT(id));
return true;
}
return NativeGetPureInline(obj2, shape, vp);
}
JSBool
baseops::GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp)
@ -5059,7 +5162,6 @@ js_DumpBacktrace(JSContext *cx)
}
fprintf(stdout, "%s", sprinter.string());
}
void
JSObject::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, JS::ObjectsExtraSizes *sizes)
{

View File

@ -1339,6 +1339,18 @@ GetPropertyHelper(JSContext *cx, HandleObject obj, PropertyName *name, uint32_t
return GetPropertyHelper(cx, obj, id, getHow, vp);
}
bool
LookupPropertyPure(JSObject *obj, jsid id, JSObject **objp, Shape **propp);
bool
GetPropertyPure(JSObject *obj, jsid id, Value *vp);
inline bool
GetPropertyPure(JSObject *obj, PropertyName *name, Value *vp)
{
return GetPropertyPure(obj, NameToId(name), vp);
}
bool
GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, PropertyDescriptor *desc);

View File

@ -83,6 +83,36 @@ js::ObjectImpl::nativeContains(JSContext *cx, Shape *shape)
return nativeLookup(cx, shape->propid()) == shape;
}
inline js::Shape *
js::ObjectImpl::nativeLookupPure(PropertyId pid)
{
return nativeLookupPure(pid.asId());
}
inline js::Shape *
js::ObjectImpl::nativeLookupPure(PropertyName *name)
{
return nativeLookupPure(NameToId(name));
}
inline bool
js::ObjectImpl::nativeContainsPure(jsid id)
{
return nativeLookupPure(id) != NULL;
}
inline bool
js::ObjectImpl::nativeContainsPure(PropertyName *name)
{
return nativeContainsPure(NameToId(name));
}
inline bool
js::ObjectImpl::nativeContainsPure(Shape *shape)
{
return nativeLookupPure(shape->propid()) == shape;
}
inline bool
js::ObjectImpl::isExtensible() const
{

View File

@ -307,6 +307,13 @@ js::ObjectImpl::nativeLookup(JSContext *cx, jsid id)
# pragma optimize("", on)
#endif
Shape *
js::ObjectImpl::nativeLookupPure(jsid id)
{
MOZ_ASSERT(isNative());
return Shape::searchNoHashify(lastProperty(), id);
}
void
js::ObjectImpl::markChildren(JSTracer *trc)
{

View File

@ -1284,6 +1284,18 @@ class ObjectImpl : public gc::Cell
inline bool nativeContains(JSContext *cx, PropertyName* name);
inline bool nativeContains(JSContext *cx, Shape* shape);
/*
* Contextless; can be called from parallel code. Returns false if the
* operation would have been effectful.
*/
Shape *nativeLookupPure(jsid id);
inline Shape *nativeLookupPure(PropertyId pid);
inline Shape *nativeLookupPure(PropertyName *name);
inline bool nativeContainsPure(jsid id);
inline bool nativeContainsPure(PropertyName* name);
inline bool nativeContainsPure(Shape* shape);
inline JSClass *getJSClass() const;
inline bool hasClass(const Class *c) const;
inline const ObjectOps *getOps() const;

View File

@ -516,6 +516,7 @@ class Shape : public js::gc::Cell
static inline RawShape search(JSContext *cx, Shape *start, jsid id,
Shape ***pspp, bool adding = false);
static inline Shape *searchNoHashify(Shape *start, jsid id);
inline void removeFromDictionary(ObjectImpl *obj);
inline void insertIntoDictionary(HeapPtrShape *dictp);
@ -1097,6 +1098,30 @@ Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
return NULL;
}
/*
* Keep this function in sync with search. It should return false whenever
* search would transition to a ShapeTable.
*/
inline Shape *
Shape::searchNoHashify(Shape *start, jsid id)
{
/*
* If we have a table, search in the shape table, else do a linear
* search. We never hashify into a table in parallel.
*/
if (start->hasTable()) {
Shape **spp = start->table().search(id, false);
return SHAPE_FETCH(spp);
}
for (Shape *shape = start; shape; shape = shape->parent) {
if (shape->propidRef() == id)
return shape;
}
return NULL;
}
template<> struct RootKind<Shape *> : SpecificRootKind<Shape *, THING_ROOT_SHAPE> {};
template<> struct RootKind<BaseShape *> : SpecificRootKind<BaseShape *, THING_ROOT_BASE_SHAPE> {};