JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda) { assertSameCompartment(cx, obj); Class *clasp = obj->getClass(); if (!obj->isNative() || (clasp->flags & JSCLASS_NEW_ENUMERATE)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DESCRIBE_PROPS, clasp->name); return JS_FALSE; } if (!clasp->enumerate(cx, obj)) return JS_FALSE; /* Return an empty pda early if obj has no own properties. */ if (obj->nativeEmpty()) { pda->length = 0; pda->array = NULL; return JS_TRUE; } uint32_t n = obj->propertyCount(); JSPropertyDesc *pd = (JSPropertyDesc *) cx->malloc_(size_t(n) * sizeof(JSPropertyDesc)); if (!pd) return JS_FALSE; uint32_t i = 0; for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) { if (!js_AddRoot(cx, &pd[i].id, NULL)) goto bad; if (!js_AddRoot(cx, &pd[i].value, NULL)) goto bad; Shape *shape = const_cast<Shape *>(&r.front()); if (!JS_GetPropertyDesc(cx, obj, reinterpret_cast<JSScopeProperty *>(shape), &pd[i])) goto bad; if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL)) goto bad; if (++i == n) break; } pda->length = i; pda->array = pd; return JS_TRUE; bad: pda->length = i + 1; pda->array = pd; JS_PutPropertyDescArray(cx, pda); return JS_FALSE; }
JS_GetPropertyDescArray(JSContext *cx, JSObject *obj_, JSPropertyDescArray *pda) { RootedObject obj(cx, obj_); assertSameCompartment(cx, obj); uint32_t i = 0; JSPropertyDesc *pd = NULL; if (obj->isDebugScope()) { AutoIdVector props(cx); if (!Proxy::enumerate(cx, obj, props)) return false; pd = cx->pod_calloc<JSPropertyDesc>(props.length()); if (!pd) return false; for (i = 0; i < props.length(); ++i) { pd[i].id = JSVAL_NULL; pd[i].value = JSVAL_NULL; if (!js_AddRoot(cx, &pd[i].id, NULL)) goto bad; pd[i].id = IdToValue(props[i]); if (!js_AddRoot(cx, &pd[i].value, NULL)) goto bad; if (!Proxy::get(cx, obj, obj, props.handleAt(i), MutableHandleValue::fromMarkedLocation(&pd[i].value))) goto bad; } pda->length = props.length(); pda->array = pd; return true; } Class *clasp; clasp = obj->getClass(); if (!obj->isNative() || (clasp->flags & JSCLASS_NEW_ENUMERATE)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DESCRIBE_PROPS, clasp->name); return false; } if (!clasp->enumerate(cx, obj)) return false; /* Return an empty pda early if obj has no own properties. */ if (obj->nativeEmpty()) { pda->length = 0; pda->array = NULL; return true; } pd = cx->pod_malloc<JSPropertyDesc>(obj->propertyCount()); if (!pd) return false; for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) { pd[i].id = JSVAL_NULL; pd[i].value = JSVAL_NULL; pd[i].alias = JSVAL_NULL; if (!js_AddRoot(cx, &pd[i].id, NULL)) goto bad; if (!js_AddRoot(cx, &pd[i].value, NULL)) goto bad; RootedShape shape(cx, const_cast<Shape *>(&r.front())); if (!GetPropertyDesc(cx, obj, shape, &pd[i])) goto bad; if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL)) goto bad; if (++i == obj->propertyCount()) break; } pda->length = i; pda->array = pd; return true; bad: pda->length = i + 1; pda->array = pd; JS_PutPropertyDescArray(cx, pda); return false; }
static bool Snapshot(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector *props) { IdSet ht(cx); if (!ht.init(32)) return NULL; JSObject *pobj = obj; do { Class *clasp = pobj->getClass(); if (pobj->isNative() && !pobj->getOps()->enumerate && !(clasp->flags & JSCLASS_NEW_ENUMERATE)) { if (!clasp->enumerate(cx, pobj)) return false; if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) return false; } else if (pobj->isDenseArray()) { if (!EnumerateDenseArrayProperties(cx, obj, pobj, flags, ht, props)) return false; } else { if (pobj->isProxy()) { AutoIdVector proxyProps(cx); if (flags & JSITER_OWNONLY) { if (flags & JSITER_HIDDEN) { if (!JSProxy::getOwnPropertyNames(cx, pobj, proxyProps)) return false; } else { if (!JSProxy::keys(cx, pobj, proxyProps)) return false; } } else { if (!JSProxy::enumerate(cx, pobj, proxyProps)) return false; } for (size_t n = 0, len = proxyProps.length(); n < len; n++) { if (!Enumerate(cx, obj, pobj, proxyProps[n], true, flags, ht, props)) return false; } /* Proxy objects enumerate the prototype on their own, so we are done here. */ break; } Value state; JSIterateOp op = (flags & JSITER_HIDDEN) ? JSENUMERATE_INIT_ALL : JSENUMERATE_INIT; if (!pobj->enumerate(cx, op, &state, NULL)) return false; if (state.isMagic(JS_NATIVE_ENUMERATE)) { if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) return false; } else { while (true) { jsid id; if (!pobj->enumerate(cx, JSENUMERATE_NEXT, &state, &id)) return false; if (state.isNull()) break; if (!Enumerate(cx, obj, pobj, id, true, flags, ht, props)) return false; } } } if ((flags & JSITER_OWNONLY) || pobj->isXML()) break; } while ((pobj = pobj->getProto()) != NULL); return true; }