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; }
/* * Construct a call object for the given bindings. If this is a call object * for a function invocation, callee should be the function being called. * Otherwise it must be a call object for eval of strict mode code, and callee * must be null. */ CallObject * CallObject::create(JSContext *cx, JSScript *script, JSObject &enclosing, JSObject *callee) { RootedVarShape shape(cx); shape = script->bindings.callObjectShape(cx); if (shape == NULL) return NULL; gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots() + 1); RootedVarTypeObject type(cx); type = cx->compartment->getEmptyType(cx); if (!type) return NULL; HeapSlot *slots; if (!PreallocateObjectDynamicSlots(cx, shape, &slots)) return NULL; JSObject *obj = JSObject::create(cx, kind, shape, type, slots); if (!obj) return NULL; /* * Update the parent for bindings associated with non-compileAndGo scripts, * whose call objects do not have a consistent global variable and need * to be updated dynamically. */ JSObject &global = enclosing.global(); if (&global != obj->getParent()) { JS_ASSERT(obj->getParent() == NULL); if (!obj->setParent(cx, &global)) return NULL; } #ifdef DEBUG JS_ASSERT(!obj->inDictionaryMode()); for (Shape::Range r = obj->lastProperty(); !r.empty(); r.popFront()) { const Shape &s = r.front(); if (s.hasSlot()) { JS_ASSERT(s.slot() + 1 == obj->slotSpan()); break; } } #endif if (!obj->asScope().setEnclosingScope(cx, enclosing)) return NULL; JS_ASSERT_IF(callee, callee->isFunction()); obj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee)); obj->initFixedSlot(ARGUMENTS_SLOT, MagicValue(JS_UNASSIGNED_ARGUMENTS)); /* * If |bindings| is for a function that has extensible parents, that means * its Call should have its own shape; see BaseShape::extensibleParents. */ if (obj->lastProperty()->extensibleParents() && !obj->generateOwnShape(cx)) return NULL; return &obj->asCall(); }