Exemple #1
0
bool
CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval)
{
    rval.set(MagicValue(JS_IS_CONSTRUCTING));

    if (callee->isFunction()) {
        JSFunction *fun = callee->toFunction();
        if (fun->isInterpreted()) {
            JSScript *script = fun->getOrCreateScript(cx);
            if (!script || !script->ensureHasTypes(cx))
                return false;
            JSObject *thisObj = CreateThisForFunction(cx, callee, false);
            if (!thisObj)
                return false;
            rval.set(ObjectValue(*thisObj));
        }
    }

    return true;
}
JS_SplicePrototype(JSContext* cx, HandleObject obj, HandleObject proto)
{
    /*
     * Change the prototype of an object which hasn't been used anywhere
     * and does not share its type with another object. Unlike JS_SetPrototype,
     * does not nuke type information for the object.
     */
    CHECK_REQUEST(cx);

    if (!obj->isSingleton()) {
        /*
         * We can see non-singleton objects when trying to splice prototypes
         * due to mutable __proto__ (ugh).
         */
        return JS_SetPrototype(cx, obj, proto);
    }

    Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
    return obj->splicePrototype(cx, obj->getClass(), tagged);
}
Exemple #3
0
bool
jit::SetPropertyPar(ForkJoinSlice *slice, HandleObject obj, HandlePropertyName name,
                    HandleValue value, bool strict, jsbytecode *pc)
{
    JS_ASSERT(slice->isThreadLocal(obj));

    if (*pc == JSOP_SETALIASEDVAR) {
        // See comment in jit::SetProperty.
        Shape *shape = obj->nativeLookupPure(name);
        JS_ASSERT(shape && shape->hasSlot());
        return obj->nativeSetSlotIfHasType(shape, value);
    }

    // Fail early on hooks.
    if (obj->getOps()->setProperty)
        return TP_RETRY_SEQUENTIALLY;

    RootedValue v(slice, value);
    RootedId id(slice, NameToId(name));
    return baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0, &v, strict);
}
static RawObject
CloneDenseArray(JSContext *cx, HandleObject obj, CloneMemory &clonedObjects)
{
    uint32_t len = obj->getArrayLength();
    RootedObject clone(cx, NewDenseAllocatedArray(cx, len));
    clone->setDenseArrayInitializedLength(len);
    for (uint32_t i = 0; i < len; i++)
        JSObject::initDenseArrayElementWithType(cx, clone, i, UndefinedValue());
    RootedValue elt(cx);
    for (uint32_t i = 0; i < len; i++) {
        bool present;
        if (!obj->getElementIfPresent(cx, obj, obj, i, &elt, &present))
            return NULL;
        if (present) {
            if (!CloneValue(cx, &elt, clonedObjects))
                return NULL;
            JSObject::setDenseArrayElementWithType(cx, clone, i, elt);
        }
    }
    return clone;
}
Exemple #5
0
static JSBool
fun_enumerate(JSContext *cx, HandleObject obj)
{
    JS_ASSERT(obj->isFunction());

    RootedId id(cx);
    bool found;

    if (!obj->isBoundFunction()) {
        id = NameToId(cx->runtime->atomState.classPrototypeAtom);
        if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
            return false;
    }

    id = NameToId(cx->runtime->atomState.lengthAtom);
    if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
        return false;

    id = NameToId(cx->runtime->atomState.nameAtom);
    if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
        return false;

    for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
        const uint16_t offset = poisonPillProps[i];
        id = NameToId(OFFSET_TO_NAME(cx->runtime, offset));
        if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
            return false;
    }

    return true;
}
Exemple #6
0
static inline bool
Enumerate(JSContext* cx, HandleObject pobj, jsid id,
          bool enumerable, unsigned flags, Maybe<IdSet>& ht, AutoIdVector* props)
{
    if (CheckForDuplicates) {
        if (!ht) {
            ht.emplace(cx);
            // Most of the time there are only a handful of entries.
            if (!ht->init(5))
                return false;
        }

        // If we've already seen this, we definitely won't add it.
        IdSet::AddPtr p = ht->lookupForAdd(id);
        if (MOZ_UNLIKELY(!!p))
            return true;

        // It's not necessary to add properties to the hash table at the end of
        // the prototype chain, but custom enumeration behaviors might return
        // duplicated properties, so always add in such cases.
        if (pobj->is<ProxyObject>() ||
            pobj->staticPrototype() ||
            pobj->getClass()->getNewEnumerate())
        {
            if (!ht->add(p, id))
                return false;
        }
    }

    if (!enumerable && !(flags & JSITER_HIDDEN))
        return true;

    // Symbol-keyed properties and nonenumerable properties are skipped unless
    // the caller specifically asks for them. A caller can also filter out
    // non-symbols by asking for JSITER_SYMBOLSONLY.
    if (JSID_IS_SYMBOL(id) ? !(flags & JSITER_SYMBOLS) : (flags & JSITER_SYMBOLSONLY))
        return true;

    return props->append(id);
}
Exemple #7
0
static JSBool
ArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp)
{
    if (!obj->isNormalArguments())
        return true;

    NormalArgumentsObject &argsobj = obj->asNormalArguments();

    if (JSID_IS_INT(id)) {
        unsigned arg = unsigned(JSID_TO_INT(id));
        if (arg < argsobj.initialLength()) {
            if (StackFrame *fp = argsobj.maybeStackFrame()) {
                JSScript *script = fp->functionScript();
                JS_ASSERT(script->needsArgsObj());
                if (arg < fp->numFormalArgs()) {
                    JS_ASSERT(fp->script()->formalIsAliased(arg));
                    types::TypeScript::SetArgument(cx, script, arg, *vp);
                }
                fp->canonicalActualArg(arg) = *vp;
                return true;
            }
        }
    } else {
        JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
                  JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
    }

    /*
     * For simplicity we use delete/define to replace the property with one
     * backed by the default Object getter and setter. Note that we rely on
     * args_delProperty to clear the corresponding reserved slot so the GC can
     * collect its value. Note also that we must define the property instead
     * of setting it in case the user has changed the prototype to an object
     * that has a setter for this id.
     */
    RootedVarValue value(cx);
    return baseops::DeleteGeneric(cx, obj, id, value.address(), false) &&
           baseops::DefineProperty(cx, obj, id, vp, NULL, NULL, JSPROP_ENUMERATE);
}
bool
ArrayPushDense(JSContext *cx, HandleObject obj, HandleValue v, uint32_t *length)
{
    JS_ASSERT(obj->isArray());

    Value argv[] = { UndefinedValue(), ObjectValue(*obj), v };
    AutoValueArray ava(cx, argv, 3);
    if (!js::array_push(cx, 1, argv))
        return false;

    *length = argv[0].toInt32();
    return true;
}
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(jit::JitFrameLayout* frame, HandleObject callObj,
                                          ArgumentsObject* obj, ArgumentsData* data)
{
    JSFunction* callee = jit::CalleeTokenToFunction(frame->calleeToken());
    JSScript* script = callee->nonLazyScript();
    if (callee->needsCallObject() && script->argsObjAliasesFormals()) {
        MOZ_ASSERT(callObj && callObj->is<CallObject>());
        obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get()));
        for (AliasedFormalIter fi(script); fi; fi++)
            data->args[fi.frameIndex()] = MagicScopeSlotValue(fi.scopeSlot());
    }
}
Exemple #10
0
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(ion::IonJSFrameLayout *frame, HandleObject callObj,
        JSObject *obj, ArgumentsData *data)
{
    JSFunction *callee = ion::CalleeTokenToFunction(frame->calleeToken());
    JSScript *script = callee->nonLazyScript();
    if (callee->isHeavyweight() && script->argsObjAliasesFormals()) {
        JS_ASSERT(callObj && callObj->is<CallObject>());
        obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get()));
        for (AliasedFormalIter fi(script); fi; fi++)
            data->args[fi.frameIndex()] = MagicValue(JS_FORWARD_TO_CALL_OBJECT);
    }
}
Exemple #11
0
bool
SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value,
                bool strict)
{
    // This function is called from Ion code for StoreElementHole's OOL path.
    // In this case we know the object is native, has no indexed properties
    // and we can use setDenseElement instead of setDenseElementWithType.

    MOZ_ASSERT(obj->isNative());
    MOZ_ASSERT(!obj->isIndexed());

    JSObject::EnsureDenseResult result = JSObject::ED_SPARSE;
    do {
        if (index < 0)
            break;
        bool isArray = obj->is<ArrayObject>();
        if (isArray && !obj->as<ArrayObject>().lengthIsWritable())
            break;
        uint32_t idx = uint32_t(index);
        result = obj->ensureDenseElements(cx, idx, 1);
        if (result != JSObject::ED_OK)
            break;
        if (isArray) {
            ArrayObject &arr = obj->as<ArrayObject>();
            if (idx >= arr.length())
                arr.setLengthInt32(idx + 1);
        }
        obj->setDenseElement(idx, value);
        return true;
    } while (false);

    if (result == JSObject::ED_FAILED)
        return false;
    MOZ_ASSERT(result == JSObject::ED_SPARSE);

    RootedValue indexVal(cx, Int32Value(index));
    return SetObjectElement(cx, obj, indexVal, value, strict);
}
Exemple #12
0
bool
GetPropIRGenerator::tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId)
{
    MOZ_ASSERT(IsCacheableDOMProxy(obj));

    writer.guardShape(objId, obj->maybeShape());

    // No need for more guards: we know this is a DOM proxy, since the shape
    // guard enforces a given JSClass, so just go ahead and emit the call to
    // ProxyGet.
    writer.callProxyGetResult(objId, NameToId(name_));
    writer.typeMonitorResult();
    return true;
}
static JSBool
StrictArgGetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
{
    if (!obj->isStrictArguments())
        return true;

    StrictArgumentsObject &argsobj = obj->asStrictArguments();

    if (JSID_IS_INT(id)) {
        /*
         * arg can exceed the number of arguments if a script changed the
         * prototype to point to another Arguments object with a bigger argc.
         */
        unsigned arg = unsigned(JSID_TO_INT(id));
        if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg))
            vp.set(argsobj.element(arg));
    } else {
        JS_ASSERT(JSID_IS_ATOM(id, cx->names().length));
        if (!argsobj.hasOverriddenLength())
            vp.setInt32(argsobj.initialLength());
    }
    return true;
}
Exemple #14
0
bool
SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
            bool strict, int jsop)
{
    RootedValue v(cx, value);
    RootedId id(cx, NameToId(name));

    if (jsop == JSOP_SETALIASEDVAR) {
        // Aliased var assigns ignore readonly attributes on the property, as
        // required for initializing 'const' closure variables.
        Shape *shape = obj->nativeLookup(cx, name);
        JS_ASSERT(shape && shape->hasSlot());
        JSObject::nativeSetSlotWithType(cx, obj, shape, value);
        return true;
    }

    if (JS_LIKELY(!obj->getOps()->setProperty)) {
        unsigned defineHow = (jsop == JSOP_SETNAME || jsop == JSOP_SETGNAME) ? DNP_UNQUALIFIED : 0;
        return baseops::SetPropertyHelper(cx, obj, obj, id, defineHow, &v, strict);
    }

    return JSObject::setGeneric(cx, obj, obj, id, &v, strict);
}
bool
SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
            bool strict, bool isSetName)
{
    RootedValue v(cx, value);
    RootedId id(cx, NameToId(name));

    if (JS_LIKELY(!obj->getOps()->setProperty)) {
        unsigned defineHow = isSetName ? DNP_UNQUALIFIED : 0;
        return baseops::SetPropertyHelper(cx, obj, obj, id, defineHow, &v, strict);
    }

    return JSObject::setGeneric(cx, obj, obj, id, &v, strict);
}
Exemple #16
0
static bool
GetUnclonedValue(JSContext *cx, HandleObject selfHostedObject, HandleId id, MutableHandleValue vp)
{
    vp.setUndefined();

    if (JSID_IS_INT(id)) {
        size_t index = JSID_TO_INT(id);
        if (index < selfHostedObject->getDenseInitializedLength() &&
            !selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE))
        {
            vp.set(selfHostedObject->getDenseElement(JSID_TO_INT(id)));
            return true;
        }
    }

    // Since all atoms used by self hosting are marked as permanent, any
    // attempt to look up a non-permanent atom will fail. We should only
    // see such atoms when code is looking for properties on the self
    // hosted global which aren't present.
    if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) {
        JS_ASSERT(selfHostedObject->is<GlobalObject>());
        RootedValue value(cx, IdToValue(id));
        return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
                                        JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
    }

    RootedShape shape(cx, selfHostedObject->nativeLookupPure(id));
    if (!shape) {
        RootedValue value(cx, IdToValue(id));
        return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
                                        JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
    }

    JS_ASSERT(shape->hasSlot() && shape->hasDefaultGetter());
    vp.set(selfHostedObject->getSlot(shape->slot()));
    return true;
}
Exemple #17
0
static MOZ_ALWAYS_INLINE bool
SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
                        HandleObject key, HandleValue value)
{
    ObjectValueMap* map = mapObj->getMap();
    if (!map) {
        AutoInitGCManagedObject<ObjectValueMap> newMap(
            cx->make_unique<ObjectValueMap>(cx, mapObj.get()));
        if (!newMap)
            return false;
        if (!newMap->init()) {
            JS_ReportOutOfMemory(cx);
            return false;
        }
        map = newMap.release();
        mapObj->setPrivate(map);
    }

    // Preserve wrapped native keys to prevent wrapper optimization.
    if (!TryPreserveReflector(cx, key))
        return false;

    if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) {
        RootedObject delegate(cx, op(key));
        if (delegate && !TryPreserveReflector(cx, delegate))
            return false;
    }

    MOZ_ASSERT(key->compartment() == mapObj->compartment());
    MOZ_ASSERT_IF(value.isObject(), value.toObject().compartment() == mapObj->compartment());
    if (!map->put(key, value)) {
        JS_ReportOutOfMemory(cx);
        return false;
    }
    WeakMapPostWriteBarrier(cx->runtime(), map, key.get());
    return true;
}
Exemple #18
0
/* static */ bool
GlobalObject::warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber)
{
    Rooted<GlobalObject*> global(cx, &obj->global());
    HeapSlot &v = global->getSlotRef(slot);
    if (v.isUndefined()) {
        if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
                                          errorNumber))
        {
            return false;
        }
        v.init(global, HeapSlot::Slot, slot, BooleanValue(true));
    }
    return true;
}
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(jit::JitFrameLayout* frame, HandleObject callObj,
                                          ArgumentsObject* obj, ArgumentsData* data)
{
    JSFunction* callee = jit::CalleeTokenToFunction(frame->calleeToken());
    JSScript* script = callee->nonLazyScript();
    if (callee->needsCallObject() && script->argumentsAliasesFormals()) {
        MOZ_ASSERT(callObj && callObj->is<CallObject>());
        obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get()));
        for (PositionalFormalParameterIter fi(script); fi; fi++) {
            if (fi.closedOver())
                data->args[fi.argumentSlot()] = MagicEnvSlotValue(fi.location().slot());
        }
    }
}
static JSBool
args_delProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
{
    ArgumentsObject &argsobj = obj->asArguments();
    if (JSID_IS_INT(id)) {
        unsigned arg = unsigned(JSID_TO_INT(id));
        if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg))
            argsobj.markElementDeleted(arg);
    } else if (JSID_IS_ATOM(id, cx->names().length)) {
        argsobj.markLengthOverridden();
    } else if (JSID_IS_ATOM(id, cx->names().callee)) {
        argsobj.asNormalArguments().clearCallee();
    }
    return true;
}
Exemple #21
0
static bool
WrapForSameCompartment(JSContext *cx, HandleObject obj, MutableHandleValue vp)
{
    JS_ASSERT(cx->compartment == obj->compartment());
    if (!cx->runtime->sameCompartmentWrapObjectCallback) {
        vp.setObject(*obj);
        return true;
    }

    JSObject *wrapped = cx->runtime->sameCompartmentWrapObjectCallback(cx, obj);
    if (!wrapped)
        return false;
    vp.setObject(*wrapped);
    return true;
}
Exemple #22
0
/* static */ bool
GlobalObject::warnOnceAboutWatch(JSContext *cx, HandleObject obj)
{
    Rooted<GlobalObject*> global(cx, &obj->global());
    HeapSlot &v = global->getSlotRef(WARNED_WATCH_DEPRECATED);
    if (v.isUndefined()) {
        // Warn only once per global object.
        if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
                                          JSMSG_OBJECT_WATCH_DEPRECATED))
        {
            return false;
        }
        v.init(global, HeapSlot::Slot, WARNED_WATCH_DEPRECATED, BooleanValue(true));
    }
    return true;
}
Exemple #23
0
static JSBool
args_delProperty(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
{
    ArgumentsObject &argsobj = obj->asArguments();
    if (JSID_IS_INT(id)) {
        unsigned arg = unsigned(JSID_TO_INT(id));
        if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) {
            argsobj.setElement(arg, UndefinedValue());
            argsobj.markElementDeleted(arg);
        }
    } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
        argsobj.markLengthOverridden();
    } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
        argsobj.asNormalArguments().clearCallee();
    }
    return true;
}
Exemple #24
0
bool
WatchpointMap::watch(JSContext *cx, HandleObject obj, HandleId id,
                     JSWatchPointHandler handler, HandleObject closure)
{
    JS_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id));

    if (!obj->setWatched(cx))
        return false;

    Watchpoint w;
    w.handler = handler;
    w.closure = closure;
    w.held = false;
    if (!map.put(WatchKey(obj, id), w)) {
        js_ReportOutOfMemory(cx);
        return false;
    }
    return true;
}
bool
GetPropIRGenerator::tryAttachDenseElement(HandleObject obj, ObjOperandId objId,
                                          ValOperandId indexId)
{
    MOZ_ASSERT(idVal_.isInt32());

    if (!obj->isNative())
        return false;

    if (!obj->as<NativeObject>().containsDenseElement(uint32_t(idVal_.toInt32())))
        return false;

    writer.guardShape(objId, obj->as<NativeObject>().lastProperty());

    Int32OperandId int32IndexId = writer.guardIsInt32(indexId);
    writer.loadDenseElementResult(objId, int32IndexId);
    writer.typeMonitorResult();
    return true;
}
bool
GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id)
{
    // Attach a stub when the receiver is a WindowProxy and we are calling some
    // kinds of JSNative getters on the Window object (the global object).

    if (!IsWindowProxy(obj))
        return false;

    // This must be a WindowProxy for the current Window/global. Else it would
    // be a cross-compartment wrapper and IsWindowProxy returns false for
    // those.
    MOZ_ASSERT(obj->getClass() == cx_->maybeWindowProxyClass());
    MOZ_ASSERT(ToWindowIfWindowProxy(obj) == cx_->global());

    // Now try to do the lookup on the Window (the current global) and see if
    // it's a native getter.
    HandleObject windowObj = cx_->global();
    RootedShape shape(cx_);
    RootedNativeObject holder(cx_);
    NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, windowObj, id, &holder, &shape, pc_,
                                                            engine_, isTemporarilyUnoptimizable_);
    if (type != CanAttachCallGetter ||
        !IsCacheableGetPropCallNative(windowObj, holder, shape))
    {
        return false;
    }

    // Make sure the native getter is okay with the IC passing the Window
    // instead of the WindowProxy as |this| value.
    JSFunction* callee = &shape->getterObject()->as<JSFunction>();
    MOZ_ASSERT(callee->isNative());
    if (!callee->jitInfo() || callee->jitInfo()->needsOuterizedThisObject())
        return false;

    // Guard the incoming object is a WindowProxy and inline a getter call based
    // on the Window object.
    maybeEmitIdGuard(id);
    writer.guardClass(objId, GuardClassKind::WindowProxy);
    ObjOperandId windowObjId = writer.loadObject(windowObj);
    EmitCallGetterResult(writer, windowObj, holder, shape, windowObjId);
    return true;
}
bool
ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval)
{
    JS_ASSERT(obj->isArray());

    AutoDetectInvalidation adi(cx, rval.address());

    Value argv[] = { UndefinedValue(), ObjectValue(*obj) };
    AutoValueArray ava(cx, argv, 2);
    if (!js::array_shift(cx, 0, argv))
        return false;

    // If the result is |undefined|, the array was probably empty and we
    // have to monitor the return value.
    rval.set(argv[0]);
    if (rval.isUndefined())
        types::TypeScript::Monitor(cx, rval);
    return true;
}
Exemple #28
0
static bool
FindErrorInstanceOrPrototype(JSContext* cx, HandleObject obj, MutableHandleObject result)
{
    // Walk up the prototype chain until we find an error object instance or
    // prototype object. This allows code like:
    //  Object.create(Error.prototype).stack
    // or
    //   function NYI() { }
    //   NYI.prototype = new Error;
    //   (new NYI).stack
    // to continue returning stacks that are useless, but at least don't throw.

    RootedObject target(cx, CheckedUnwrap(obj));
    if (!target) {
        ReportAccessDenied(cx);
        return false;
    }

    RootedObject proto(cx);
    while (!IsErrorProtoKey(StandardProtoKeyOrNull(target))) {
        if (!GetPrototype(cx, target, &proto))
            return false;

        if (!proto) {
            // We walked the whole prototype chain and did not find an Error
            // object.
            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
                                      js_Error_str, "(get stack)", obj->getClass()->name);
            return false;
        }

        target = CheckedUnwrap(proto);
        if (!target) {
            ReportAccessDenied(cx);
            return false;
        }
    }

    result.set(target);
    return true;
}
bool
WatchpointMap::watch(JSContext* cx, HandleObject obj, HandleId id,
                     JSWatchPointHandler handler, HandleObject closure)
{
    MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id));

    if (!obj->setWatched(cx))
        return false;

    Watchpoint w(handler, closure, false);
    if (!map.put(WatchKey(obj, id), w)) {
        ReportOutOfMemory(cx);
        return false;
    }
    /*
     * For generational GC, we don't need to post-barrier writes to the
     * hashtable here because we mark all watchpoints as part of root marking in
     * markAll().
     */
    return true;
}
/* static */ bool
GlobalObject::warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag,
                            unsigned errorNumber)
{
    Rooted<GlobalObject*> global(cx, &obj->global());
    HeapSlot& v = global->getSlotRef(WARNED_ONCE_FLAGS);
    MOZ_ASSERT_IF(!v.isUndefined(), v.toInt32());
    int32_t flags = v.isUndefined() ? 0 : v.toInt32();
    if (!(flags & flag)) {
        if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
                                          errorNumber))
        {
            return false;
        }
        if (v.isUndefined())
            v.init(global, HeapSlot::Slot, WARNED_ONCE_FLAGS, Int32Value(flags | flag));
        else
            v.set(global, HeapSlot::Slot, WARNED_ONCE_FLAGS, Int32Value(flags | flag));
    }
    return true;
}