bool js::HasElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, unsigned resolveFlags, bool *found) { NEW_OBJECT_REPRESENTATION_ONLY(); Rooted<ObjectImpl*> current(cx, obj); do { MOZ_ASSERT(current); if (Downcast(current)->is<ProxyObject>()) MOZ_ASSUME_UNREACHABLE("NYI: proxy [[HasProperty]]"); PropDesc prop; if (!GetOwnElement(cx, current, index, resolveFlags, &prop)) return false; if (!prop.isUndefined()) { *found = true; return true; } current = current->getProto(); if (current) continue; *found = false; return true; } while (false); MOZ_ASSUME_UNREACHABLE("buggy control flow"); }
bool js::HasElement(JSContext *cx, ObjectImpl *obj, uint32_t index, bool *found) { NEW_OBJECT_REPRESENTATION_ONLY(); do { MOZ_ASSERT(obj); if (static_cast<JSObject *>(obj)->isProxy()) { // XXX MOZ_NOT_REACHED("NYI: proxy [[HasProperty]]"); return false; } PropDesc prop; if (!GetOwnElement(cx, obj, index, &prop)) return false; if (!prop.isUndefined()) { *found = true; return true; } obj = obj->getProto(); if (obj) continue; *found = false; return true; } while (false); MOZ_NOT_REACHED("buggy control flow"); return false; }
bool js::SetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver, uint32_t index, const Value &v, unsigned resolveFlags, bool *succeeded) { NEW_OBJECT_REPRESENTATION_ONLY(); Rooted<ObjectImpl*> current(cx, obj); RootedValue setter(cx); MOZ_ASSERT(receiver); do { MOZ_ASSERT(current); if (Downcast(current)->isProxy()) { MOZ_NOT_REACHED("NYI: proxy [[SetP]]"); return false; } PropDesc ownDesc; if (!GetOwnElement(cx, current, index, resolveFlags, &ownDesc)) return false; if (!ownDesc.isUndefined()) { if (ownDesc.isDataDescriptor()) { if (!ownDesc.writable()) { *succeeded = false; return true; } if (receiver == current) { PropDesc updateDesc = PropDesc::valueOnly(v); return DefineElement(cx, receiver, index, updateDesc, false, resolveFlags, succeeded); } PropDesc newDesc; return DefineElement(cx, receiver, index, newDesc, false, resolveFlags, succeeded); } if (ownDesc.isAccessorDescriptor()) { setter = ownDesc.setterValue(); if (setter.isUndefined()) { *succeeded = false; return true; } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 1, &args)) return false; /* Push set, receiver, and v as the sole argument. */ args.setCallee(setter); args.setThis(ObjectValue(*current)); args[0] = v; *succeeded = true; return Invoke(cx, args); } MOZ_NOT_REACHED("NYI: setting PropertyOp-based property"); return false; } current = current->getProto(); if (current) continue; PropDesc newDesc(v, PropDesc::Writable, PropDesc::Enumerable, PropDesc::Configurable); return DefineElement(cx, receiver, index, newDesc, false, resolveFlags, succeeded); } while (false); MOZ_NOT_REACHED("buggy control flow"); return false; }
bool js::GetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver, uint32_t index, unsigned resolveFlags, Value *vp) { NEW_OBJECT_REPRESENTATION_ONLY(); Rooted<ObjectImpl*> current(cx, obj); RootedValue getter(cx); do { MOZ_ASSERT(current); if (Downcast(current)->isProxy()) { MOZ_NOT_REACHED("NYI: proxy [[GetP]]"); return false; } PropDesc desc; if (!GetOwnElement(cx, current, index, resolveFlags, &desc)) return false; /* No property? Recur or bottom out. */ if (desc.isUndefined()) { current = current->getProto(); if (current) continue; vp->setUndefined(); return true; } /* If it's a data property, return the value. */ if (desc.isDataDescriptor()) { *vp = desc.value(); return true; } /* If it's an accessor property, call its [[Get]] with the receiver. */ if (desc.isAccessorDescriptor()) { getter = desc.getterValue(); if (getter.isUndefined()) { vp->setUndefined(); return true; } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 0, &args)) return false; /* Push getter, receiver, and no args. */ args.setCallee(getter); args.setThis(ObjectValue(*current)); bool ok = Invoke(cx, args); *vp = args.rval(); return ok; } /* Otherwise it's a PropertyOp-based property. XXX handle this! */ MOZ_NOT_REACHED("NYI: handle PropertyOp'd properties here"); return false; } while (false); MOZ_NOT_REACHED("buggy control flow"); return false; }
bool js::GetProperty(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver, Handle<PropertyId> pid, unsigned resolveFlags, MutableHandle<Value> vp) { NEW_OBJECT_REPRESENTATION_ONLY(); MOZ_ASSERT(receiver); Rooted<ObjectImpl*> current(cx, obj); do { MOZ_ASSERT(obj); if (Downcast(current)->isProxy()) { MOZ_NOT_REACHED("NYI: proxy [[GetP]]"); return false; } PropDesc desc; PropDesc::AutoRooter rootDesc(cx, &desc); if (!GetOwnProperty(cx, current, pid, resolveFlags, &desc)) return false; /* No property? Recur or bottom out. */ if (desc.isUndefined()) { current = current->getProto(); if (current) continue; vp.setUndefined(); return true; } /* If it's a data property, return the value. */ if (desc.isDataDescriptor()) { vp.set(desc.value()); return true; } /* If it's an accessor property, call its [[Get]] with the receiver. */ if (desc.isAccessorDescriptor()) { Rooted<Value> get(cx, desc.getterValue()); if (get.isUndefined()) { vp.setUndefined(); return true; } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 0, &args)) return false; args.setCallee(get); args.setThis(ObjectValue(*receiver)); bool ok = Invoke(cx, args); vp.set(args.rval()); return ok; } /* Otherwise it's a PropertyOp-based property. XXX handle this! */ MOZ_NOT_REACHED("NYI: handle PropertyOp'd properties here"); return false; } while (false); MOZ_NOT_REACHED("buggy control flow"); return false; }
bool DenseElementsHeader::defineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, const PropDesc &desc, bool shouldThrow, unsigned resolveFlags, bool *succeeded) { MOZ_ASSERT(this == &obj->elementsHeader()); MOZ_ASSERT_IF(desc.hasGet() || desc.hasSet(), !desc.hasValue() && !desc.hasWritable()); MOZ_ASSERT_IF(desc.hasValue() || desc.hasWritable(), !desc.hasGet() && !desc.hasSet()); /* * If desc is an accessor descriptor or a data descriptor with atypical * attributes, convert to sparse and retry. */ if (desc.hasGet() || desc.hasSet() || (desc.hasEnumerable() && !desc.enumerable()) || (desc.hasConfigurable() && !desc.configurable()) || (desc.hasWritable() && !desc.writable())) { if (!obj->makeElementsSparse(cx)) return false; SparseElementsHeader &elts = obj->elementsHeader().asSparseElements(); return elts.defineElement(cx, obj, index, desc, shouldThrow, resolveFlags, succeeded); } /* Does the element exist? All behavior depends upon this. */ uint32_t initLen = initializedLength(); if (index < initLen) { HeapSlot &slot = obj->elements[index]; if (!slot.isMagic(JS_ELEMENTS_HOLE)) { /* * The element exists with attributes { [[Enumerable]]: true, * [[Configurable]]: true, [[Writable]]: true, [[Value]]: slot }. */ // XXX jwalden fill this in! } } /* * If the element doesn't exist, we can only add it if the object is * extensible. */ if (!obj->isExtensible()) { *succeeded = false; if (!shouldThrow) return true; RootedValue val(cx, ObjectValue(*obj)); MOZ_ALWAYS_FALSE(js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_OBJECT_NOT_EXTENSIBLE, JSDVG_IGNORE_STACK, val, NullPtr(), NULL, NULL)); return false; } /* Otherwise we ensure space for it exists and that it's initialized. */ ObjectImpl::DenseElementsResult res = obj->ensureDenseElementsInitialized(cx, index, 0); /* Propagate any error. */ if (res == ObjectImpl::Failure) return false; /* Otherwise, if the index was too far out of range, go sparse. */ if (res == ObjectImpl::ConvertToSparse) { if (!obj->makeElementsSparse(cx)) return false; SparseElementsHeader &elts = obj->elementsHeader().asSparseElements(); return elts.defineElement(cx, obj, index, desc, shouldThrow, resolveFlags, succeeded); } /* But if we were able to ensure the element's existence, we're good. */ MOZ_ASSERT(res == ObjectImpl::Succeeded); obj->elements[index].set(obj->asObjectPtr(), HeapSlot::Element, index, desc.value()); *succeeded = true; return true; }
bool js::SetElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, const Value &v, bool *succeeded) { NEW_OBJECT_REPRESENTATION_ONLY(); do { MOZ_ASSERT(obj); if (static_cast<JSObject *>(obj)->isProxy()) { // XXX MOZ_NOT_REACHED("NYI: proxy [[SetP]]"); return false; } PropDesc ownDesc; if (!GetOwnElement(cx, obj, index, &ownDesc)) return false; if (!ownDesc.isUndefined()) { if (ownDesc.isDataDescriptor()) { if (!ownDesc.writable()) { *succeeded = false; return true; } if (receiver == obj) { PropDesc updateDesc = PropDesc::valueOnly(v); return DefineElement(cx, receiver, index, updateDesc, false, succeeded); } PropDesc newDesc; return DefineElement(cx, receiver, index, newDesc, false, succeeded); } if (ownDesc.isAccessorDescriptor()) { Value setter = ownDesc.setterValue(); if (setter.isUndefined()) { *succeeded = false; return true; } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 1, &args)) return false; /* Push set, receiver, and v as the sole argument. */ args.calleev() = setter; args.thisv() = ObjectValue(*receiver); args[0] = v; *succeeded = true; return Invoke(cx, args); } MOZ_NOT_REACHED("NYI: setting PropertyOp-based property"); return false; } obj = obj->getProto(); if (obj) continue; PropDesc newDesc(v, PropDesc::Writable, PropDesc::Enumerable, PropDesc::Configurable); return DefineElement(cx, receiver, index, newDesc, false, succeeded); } while (false); MOZ_NOT_REACHED("buggy control flow"); return false; }
bool js::GetElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, Value *vp) { NEW_OBJECT_REPRESENTATION_ONLY(); do { MOZ_ASSERT(obj); if (static_cast<JSObject *>(obj)->isProxy()) { // XXX MOZ_NOT_REACHED("NYI: proxy [[GetP]]"); return false; } PropDesc desc; if (!GetOwnElement(cx, obj, index, &desc)) return false; /* No property? Recur or bottom out. */ if (desc.isUndefined()) { obj = obj->getProto(); if (obj) continue; vp->setUndefined(); return true; } /* If it's a data property, return the value. */ if (desc.isDataDescriptor()) { *vp = desc.value(); return true; } /* If it's an accessor property, call its [[Get]] with the receiver. */ if (desc.isAccessorDescriptor()) { Value get = desc.getterValue(); if (get.isUndefined()) { vp->setUndefined(); return true; } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 0, &args)) return false; /* Push get, receiver, and no args. */ args.calleev() = get; args.thisv() = ObjectValue(*receiver); bool ok = Invoke(cx, args); *vp = args.rval(); return ok; } /* Otherwise it's a PropertyOp-based property. XXX handle this! */ MOZ_NOT_REACHED("NYI: handle PropertyOp'd properties here"); return false; } while (false); MOZ_NOT_REACHED("buggy control flow"); return false; }