Bug 751377 - Begin to implement [[GetOwnProperty]] for named properties in the new representation. r=bhackett
authorJeff Walden <jwalden@mit.edu>
Thu, 17 May 2012 11:38:25 -0700
changeset 106409 b63ee06d4f51b9a72a022fe8d529fa6f0fa8d660
parent 106408 44d76a524b7051b5e3ec5948a0fc2b5cb4fa6678
child 106410 7f98d720cdb1d6501e8741e83ee96f27253b6d95
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherdermozilla-central@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs751377
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 751377 - Begin to implement [[GetOwnProperty]] for named properties in the new representation. r=bhackett
content/base/src/nsINode.cpp
js/src/jsobjinlines.h
js/src/jsscope.h
js/src/vm/ObjectImpl-inl.h
js/src/vm/ObjectImpl.cpp
js/src/vm/ObjectImpl.h
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1229,16 +1229,32 @@ JSObject::global() const
 static inline bool
 js_IsCallable(const js::Value &v)
 {
     return v.isObject() && v.toObject().isCallable();
 }
 
 namespace js {
 
+PropDesc::PropDesc(const Value &getter, const Value &setter,
+                   Enumerability enumerable, Configurability configurable)
+  : pd_(UndefinedValue()),
+    value_(UndefinedValue()),
+    get_(getter), set_(setter),
+    attrs(JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED |
+          (enumerable ? JSPROP_ENUMERATE : 0) |
+          (configurable ? 0 : JSPROP_PERMANENT)),
+    hasGet_(true), hasSet_(true),
+    hasValue_(false), hasWritable_(false), hasEnumerable_(true), hasConfigurable_(true),
+    isUndefined_(false)
+{
+    MOZ_ASSERT(getter.isUndefined() || js_IsCallable(getter));
+    MOZ_ASSERT(setter.isUndefined() || js_IsCallable(setter));
+}
+
 inline JSObject *
 GetInnerObject(JSContext *cx, HandleObject obj)
 {
     if (JSObjectOp op = obj->getClass()->ext.innerObject)
         return op(cx, obj);
     return obj;
 }
 
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -775,16 +775,26 @@ struct Shape : public js::gc::Cell
 
     bool isDataDescriptor() const {
         return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) == 0;
     }
     bool isAccessorDescriptor() const {
         return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) != 0;
     }
 
+    PropDesc::Writability writability() const {
+        return (attrs & JSPROP_READONLY) ? PropDesc::NonWritable : PropDesc::Writable;
+    }
+    PropDesc::Enumerability enumerability() const {
+        return (attrs & JSPROP_ENUMERATE) ? PropDesc::Enumerable : PropDesc::NonEnumerable;
+    }
+    PropDesc::Configurability configurability() const {
+        return (attrs & JSPROP_PERMANENT) ? PropDesc::NonConfigurable : PropDesc::Configurable;
+    }
+
     /*
      * For ES5 compatibility, we allow properties with PropertyOp-flavored
      * setters to be shadowed when set. The "own" property thereby created in
      * the directly referenced object will have the same getter and setter as
      * the prototype property. See bug 552432.
      */
     bool shadowable() const {
         JS_ASSERT_IF(isDataDescriptor(), writable());
--- a/js/src/vm/ObjectImpl-inl.h
+++ b/js/src/vm/ObjectImpl-inl.h
@@ -35,16 +35,42 @@ Debug_SetSlotRangeToCrashOnTouch(HeapSlo
 {
 #ifdef DEBUG
     Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin);
 #endif
 }
 
 } // namespace js
 
+inline const js::Shape *
+js::ObjectImpl::nativeLookup(JSContext *cx, PropertyId pid)
+{
+    return nativeLookup(cx, pid.asId());
+}
+
+inline const js::Shape *
+js::ObjectImpl::nativeLookup(JSContext *cx, PropertyName *name)
+{
+    return nativeLookup(cx, PropertyId(name));
+}
+
+#ifdef DEBUG
+inline const js::Shape *
+js::ObjectImpl::nativeLookupNoAllocation(JSContext *cx, PropertyId pid)
+{
+    return nativeLookupNoAllocation(cx, pid.asId());
+}
+
+inline const js::Shape *
+js::ObjectImpl::nativeLookupNoAllocation(JSContext *cx, PropertyName *name)
+{
+    return nativeLookupNoAllocation(cx, PropertyId(name));
+}
+#endif
+
 inline bool
 js::ObjectImpl::isExtensible() const
 {
     return !lastProperty()->hasObjectFlag(BaseShape::NOT_EXTENSIBLE);
 }
 
 inline bool
 js::ObjectImpl::isDenseArray() const
--- a/js/src/vm/ObjectImpl.cpp
+++ b/js/src/vm/ObjectImpl.cpp
@@ -484,16 +484,74 @@ ArrayBufferElementsHeader::defineElement
 
     Rooted<JSObject*> delegate(cx, ArrayBufferDelegate(cx, obj));
     if (!delegate)
         return false;
     return DefineElement(cx, delegate, index, desc, shouldThrow, resolveFlags, succeeded);
 }
 
 bool
+js::GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, PropertyId pid_, unsigned resolveFlags,
+                   PropDesc *desc)
+{
+    NEW_OBJECT_REPRESENTATION_ONLY();
+
+    JS_CHECK_RECURSION(cx, return false);
+
+    Rooted<PropertyId> pid(cx, pid_);
+
+    if (static_cast<JSObject *>(obj.value())->isProxy()) {
+        MOZ_NOT_REACHED("NYI: proxy [[GetOwnProperty]]");
+        return false;
+    }
+
+    const Shape *shape = obj->nativeLookup(cx, pid);
+    if (!shape) {
+        /* Not found: attempt to resolve it. */
+        Class *clasp = obj->getClass();
+        JSResolveOp resolve = clasp->resolve;
+        if (resolve != JS_ResolveStub) {
+            Rooted<jsid> id(cx, pid.reference().asId());
+            Rooted<JSObject*> robj(cx, static_cast<JSObject*>(obj.value()));
+            if (clasp->flags & JSCLASS_NEW_RESOLVE) {
+                Rooted<JSObject*> obj2(cx, NULL);
+                JSNewResolveOp op = reinterpret_cast<JSNewResolveOp>(resolve);
+                if (!op(cx, robj, id, resolveFlags, obj2.address()))
+                    return false;
+            } else {
+                if (!resolve(cx, robj, id))
+                    return false;
+            }
+        }
+
+        /* Now look it up again. */
+        shape = obj->nativeLookup(cx, pid);
+        if (!shape) {
+            desc->setUndefined();
+            return true;
+        }
+    }
+
+    if (shape->isDataDescriptor()) {
+        *desc = PropDesc(obj->nativeGetSlot(shape->slot()), shape->writability(),
+                         shape->enumerability(), shape->configurability());
+        return true;
+    }
+
+    if (shape->isAccessorDescriptor()) {
+        *desc = PropDesc(shape->getterValue(), shape->setterValue(),
+                         shape->enumerability(), shape->configurability());
+        return true;
+    }
+
+    MOZ_NOT_REACHED("NYI: PropertyOp-based properties");
+    return false;
+}
+
+bool
 js::GetOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, unsigned resolveFlags,
                   PropDesc *desc)
 {
     ElementsHeader &header = obj->elementsHeader();
     switch (header.kind()) {
       case DenseElements:
         return header.asDenseElements().getOwnElement(cx, obj, index, resolveFlags, desc);
       case SparseElements:
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -147,16 +147,19 @@ struct PropDesc {
         attrs((writable ? 0 : JSPROP_READONLY) |
               (enumerable ? JSPROP_ENUMERATE : 0) |
               (configurable ? 0 : JSPROP_PERMANENT)),
         hasGet_(false), hasSet_(false),
         hasValue_(true), hasWritable_(true), hasEnumerable_(true), hasConfigurable_(true),
         isUndefined_(false)
     {}
 
+    inline PropDesc(const Value &getter, const Value &setter,
+                    Enumerability enumerable, Configurability configurable);
+
     /*
      * 8.10.5 ToPropertyDescriptor(Obj)
      *
      * If checkAccessors is false, skip steps 7.b and 8.b, which throw a
      * TypeError if .get or .set is neither a callable object nor undefined.
      *
      * (DebuggerObject_defineProperty uses this: the .get and .set properties
      * are expected to be Debugger.Object wrappers of functions, which are not
@@ -1131,19 +1134,23 @@ class ObjectImpl : public gc::Cell
     bool hasLazyType() const { return type_->lazy(); }
 
     inline uint32_t slotSpan() const;
 
     /* Compute dynamicSlotsCount() for this object. */
     inline uint32_t numDynamicSlots() const;
 
     const Shape * nativeLookup(JSContext *cx, jsid id);
+    inline const Shape * nativeLookup(JSContext *cx, PropertyId pid);
+    inline const Shape * nativeLookup(JSContext *cx, PropertyName *name);
 
 #ifdef DEBUG
     const Shape * nativeLookupNoAllocation(JSContext *cx, jsid id);
+    inline const Shape * nativeLookupNoAllocation(JSContext *cx, PropertyId pid);
+    inline const Shape * nativeLookupNoAllocation(JSContext *cx, PropertyName *name);
 #endif
 
     inline Class *getClass() const;
     inline JSClass *getJSClass() const;
     inline bool hasClass(const Class *c) const;
     inline const ObjectOps *getOps() const;
 
     /*
@@ -1307,19 +1314,35 @@ ObjectValue(ObjectImpl &obj)
 }
 
 inline Handle<JSObject*>
 Downcast(Handle<ObjectImpl*> obj)
 {
     return Handle<JSObject*>::fromMarkedLocation(reinterpret_cast<JSObject* const*>(obj.address()));
 }
 
+/* Generic [[GetOwnProperty]] method. */
 bool
 GetOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, unsigned resolveFlags,
               PropDesc *desc);
+extern bool
+GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, PropertyId pid, unsigned resolveFlags,
+               PropDesc *desc);
+inline bool
+GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, Handle<PropertyName*> name,
+               unsigned resolveFlags, PropDesc *desc)
+{
+    return GetOwnProperty(cx, obj, PropertyId(name), resolveFlags, desc);
+}
+inline bool
+GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, Handle<SpecialId> sid, unsigned resolveFlags,
+               PropDesc *desc)
+{
+    return GetOwnProperty(cx, obj, PropertyId(sid), resolveFlags, desc);
+}
 
 /* Proposed default [[GetP]](Receiver, P) method. */
 extern bool
 GetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver, uint32_t index,
            unsigned resolveFlags, Value *vp);
 
 extern bool
 DefineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, const PropDesc &desc,