michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "jsfriendapi.h" michael@0: michael@0: #include "mozilla/PodOperations.h" michael@0: michael@0: #include michael@0: michael@0: #include "jscntxt.h" michael@0: #include "jscompartment.h" michael@0: #include "jsgc.h" michael@0: #include "jsobj.h" michael@0: #include "jsproxy.h" michael@0: #include "jswatchpoint.h" michael@0: #include "jsweakmap.h" michael@0: #include "jswrapper.h" michael@0: #include "prmjtime.h" michael@0: michael@0: #include "builtin/TestingFunctions.h" michael@0: #include "vm/WrapperObject.h" michael@0: michael@0: #include "jsobjinlines.h" michael@0: michael@0: #include "vm/ScopeObject-inl.h" michael@0: michael@0: using namespace js; michael@0: using namespace JS; michael@0: michael@0: using mozilla::PodArrayZero; michael@0: michael@0: // Required by PerThreadDataFriendFields::getMainThread() michael@0: JS_STATIC_ASSERT(offsetof(JSRuntime, mainThread) == michael@0: PerThreadDataFriendFields::RuntimeMainThreadOffset); michael@0: michael@0: PerThreadDataFriendFields::PerThreadDataFriendFields() michael@0: { michael@0: PodArrayZero(nativeStackLimit); michael@0: #if JS_STACK_GROWTH_DIRECTION > 0 michael@0: for (int i=0; isourceHook = hook; michael@0: } michael@0: michael@0: JS_FRIEND_API(SourceHook *) michael@0: js::ForgetSourceHook(JSRuntime *rt) michael@0: { michael@0: return rt->sourceHook.forget(); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data) michael@0: { michael@0: rt->gcGrayRootTracer.op = traceOp; michael@0: rt->gcGrayRootTracer.data = data; michael@0: } michael@0: michael@0: JS_FRIEND_API(JSString *) michael@0: JS_GetAnonymousString(JSRuntime *rt) michael@0: { michael@0: JS_ASSERT(rt->hasContexts()); michael@0: return rt->commonNames->anonymous; michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS_SetIsWorkerRuntime(JSRuntime *rt) michael@0: { michael@0: rt->setIsWorkerRuntime(); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: JS_FindCompilationScope(JSContext *cx, HandleObject objArg) michael@0: { michael@0: RootedObject obj(cx, objArg); michael@0: michael@0: /* michael@0: * We unwrap wrappers here. This is a little weird, but it's what's being michael@0: * asked of us. michael@0: */ michael@0: if (obj->is()) michael@0: obj = UncheckedUnwrap(obj); michael@0: michael@0: /* michael@0: * Innerize the target_obj so that we compile in the correct (inner) michael@0: * scope. michael@0: */ michael@0: if (JSObjectOp op = obj->getClass()->ext.innerObject) michael@0: obj = op(cx, obj); michael@0: return obj; michael@0: } michael@0: michael@0: JS_FRIEND_API(JSFunction *) michael@0: JS_GetObjectFunction(JSObject *obj) michael@0: { michael@0: if (obj->is()) michael@0: return &obj->as(); michael@0: return nullptr; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS_SplicePrototype(JSContext *cx, HandleObject obj, HandleObject proto) michael@0: { michael@0: /* michael@0: * Change the prototype of an object which hasn't been used anywhere michael@0: * and does not share its type with another object. Unlike JS_SetPrototype, michael@0: * does not nuke type information for the object. michael@0: */ michael@0: CHECK_REQUEST(cx); michael@0: michael@0: if (!obj->hasSingletonType()) { michael@0: /* michael@0: * We can see non-singleton objects when trying to splice prototypes michael@0: * due to mutable __proto__ (ugh). michael@0: */ michael@0: return JS_SetPrototype(cx, obj, proto); michael@0: } michael@0: michael@0: Rooted tagged(cx, TaggedProto(proto)); michael@0: return obj->splicePrototype(cx, obj->getClass(), tagged); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, HandleObject proto, michael@0: HandleObject parent) michael@0: { michael@0: /* michael@0: * Create our object with a null proto and then splice in the correct proto michael@0: * after we setSingletonType, so that we don't pollute the default michael@0: * TypeObject attached to our proto with information about our object, since michael@0: * we're not going to be using that TypeObject anyway. michael@0: */ michael@0: RootedObject obj(cx, NewObjectWithGivenProto(cx, (const js::Class *)clasp, nullptr, michael@0: parent, SingletonObject)); michael@0: if (!obj) michael@0: return nullptr; michael@0: if (!JS_SplicePrototype(cx, obj, proto)) michael@0: return nullptr; michael@0: return obj; michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::PrepareZoneForGC(Zone *zone) michael@0: { michael@0: zone->scheduleGC(); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::PrepareForFullGC(JSRuntime *rt) michael@0: { michael@0: for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) michael@0: zone->scheduleGC(); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::PrepareForIncrementalGC(JSRuntime *rt) michael@0: { michael@0: if (!JS::IsIncrementalGCInProgress(rt)) michael@0: return; michael@0: michael@0: for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { michael@0: if (zone->wasGCStarted()) michael@0: PrepareZoneForGC(zone); michael@0: } michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS::IsGCScheduled(JSRuntime *rt) michael@0: { michael@0: for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { michael@0: if (zone->isGCScheduled()) michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::SkipZoneForGC(Zone *zone) michael@0: { michael@0: zone->unscheduleGC(); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::GCForReason(JSRuntime *rt, gcreason::Reason reason) michael@0: { michael@0: GC(rt, GC_NORMAL, reason); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::ShrinkingGC(JSRuntime *rt, gcreason::Reason reason) michael@0: { michael@0: GC(rt, GC_SHRINK, reason); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis) michael@0: { michael@0: GCSlice(rt, GC_NORMAL, reason, millis); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason) michael@0: { michael@0: GCFinalSlice(rt, GC_NORMAL, reason); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSPrincipals *) michael@0: JS_GetCompartmentPrincipals(JSCompartment *compartment) michael@0: { michael@0: return compartment->principals; michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS_SetCompartmentPrincipals(JSCompartment *compartment, JSPrincipals *principals) michael@0: { michael@0: // Short circuit if there's no change. michael@0: if (principals == compartment->principals) michael@0: return; michael@0: michael@0: // Any compartment with the trusted principals -- and there can be michael@0: // multiple -- is a system compartment. michael@0: const JSPrincipals *trusted = compartment->runtimeFromMainThread()->trustedPrincipals(); michael@0: bool isSystem = principals && principals == trusted; michael@0: michael@0: // Clear out the old principals, if any. michael@0: if (compartment->principals) { michael@0: JS_DropPrincipals(compartment->runtimeFromMainThread(), compartment->principals); michael@0: compartment->principals = nullptr; michael@0: // We'd like to assert that our new principals is always same-origin michael@0: // with the old one, but JSPrincipals doesn't give us a way to do that. michael@0: // But we can at least assert that we're not switching between system michael@0: // and non-system. michael@0: JS_ASSERT(compartment->isSystem == isSystem); michael@0: } michael@0: michael@0: // Set up the new principals. michael@0: if (principals) { michael@0: JS_HoldPrincipals(principals); michael@0: compartment->principals = principals; michael@0: } michael@0: michael@0: // Update the system flag. michael@0: compartment->isSystem = isSystem; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS_WrapPropertyDescriptor(JSContext *cx, JS::MutableHandle desc) michael@0: { michael@0: return cx->compartment()->wrap(cx, desc); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS_WrapAutoIdVector(JSContext *cx, js::AutoIdVector &props) michael@0: { michael@0: return cx->compartment()->wrap(cx, props); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape) michael@0: { michael@0: MarkCycleCollectorChildren(trc, static_cast(shape)); michael@0: } michael@0: michael@0: static bool michael@0: DefineHelpProperty(JSContext *cx, HandleObject obj, const char *prop, const char *value) michael@0: { michael@0: RootedAtom atom(cx, Atomize(cx, value, strlen(value))); michael@0: if (!atom) michael@0: return false; michael@0: return JS_DefineProperty(cx, obj, prop, atom, JSPROP_READONLY | JSPROP_PERMANENT, michael@0: JS_PropertyStub, JS_StrictPropertyStub); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS_DefineFunctionsWithHelp(JSContext *cx, HandleObject obj, const JSFunctionSpecWithHelp *fs) michael@0: { michael@0: JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); michael@0: michael@0: CHECK_REQUEST(cx); michael@0: assertSameCompartment(cx, obj); michael@0: for (; fs->name; fs++) { michael@0: JSAtom *atom = Atomize(cx, fs->name, strlen(fs->name)); michael@0: if (!atom) michael@0: return false; michael@0: michael@0: Rooted id(cx, AtomToId(atom)); michael@0: RootedFunction fun(cx, DefineFunction(cx, obj, id, fs->call, fs->nargs, fs->flags)); michael@0: if (!fun) michael@0: return false; michael@0: michael@0: if (fs->usage) { michael@0: if (!DefineHelpProperty(cx, fun, "usage", fs->usage)) michael@0: return false; michael@0: } michael@0: michael@0: if (fs->help) { michael@0: if (!DefineHelpProperty(cx, fun, "help", fs->help)) michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js_ObjectClassIs(JSContext *cx, HandleObject obj, ESClassValue classValue) michael@0: { michael@0: return ObjectClassIs(obj, classValue, cx); michael@0: } michael@0: michael@0: JS_FRIEND_API(const char *) michael@0: js_ObjectClassName(JSContext *cx, HandleObject obj) michael@0: { michael@0: return JSObject::className(cx, obj); michael@0: } michael@0: michael@0: JS_FRIEND_API(JS::Zone *) michael@0: js::GetCompartmentZone(JSCompartment *comp) michael@0: { michael@0: return comp->zone(); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::IsSystemCompartment(JSCompartment *comp) michael@0: { michael@0: return comp->isSystem; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::IsSystemZone(Zone *zone) michael@0: { michael@0: return zone->isSystem; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::IsAtomsCompartment(JSCompartment *comp) michael@0: { michael@0: return comp->runtimeFromAnyThread()->isAtomsCompartment(comp); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::IsInNonStrictPropertySet(JSContext *cx) michael@0: { michael@0: jsbytecode *pc; michael@0: JSScript *script = cx->currentScript(&pc, JSContext::ALLOW_CROSS_COMPARTMENT); michael@0: return script && !script->strict() && (js_CodeSpec[*pc].format & JOF_SET); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::IsFunctionObject(JSObject *obj) michael@0: { michael@0: return obj->is(); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::IsScopeObject(JSObject *obj) michael@0: { michael@0: return obj->is(); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::IsCallObject(JSObject *obj) michael@0: { michael@0: return obj->is(); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: js::GetObjectParentMaybeScope(JSObject *obj) michael@0: { michael@0: return obj->enclosingScope(); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: js::GetGlobalForObjectCrossCompartment(JSObject *obj) michael@0: { michael@0: return &obj->global(); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::SetPendingExceptionCrossContext(JSContext *cx, JS::HandleValue v) michael@0: { michael@0: cx->setPendingException(v); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::AssertSameCompartment(JSContext *cx, JSObject *obj) michael@0: { michael@0: assertSameCompartment(cx, obj); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: JS_FRIEND_API(void) michael@0: js::AssertSameCompartment(JSObject *objA, JSObject *objB) michael@0: { michael@0: JS_ASSERT(objA->compartment() == objB->compartment()); michael@0: } michael@0: #endif michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: js::DefaultObjectForContextOrNull(JSContext *cx) michael@0: { michael@0: if (cx->options().noDefaultCompartmentObject()) michael@0: return nullptr; michael@0: return cx->maybeDefaultCompartmentObject(); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::SetDefaultObjectForContext(JSContext *cx, JSObject *obj) michael@0: { michael@0: cx->setDefaultCompartmentObject(obj); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::NotifyAnimationActivity(JSObject *obj) michael@0: { michael@0: obj->compartment()->lastAnimationTime = PRMJ_Now(); michael@0: } michael@0: michael@0: JS_FRIEND_API(uint32_t) michael@0: js::GetObjectSlotSpan(JSObject *obj) michael@0: { michael@0: return obj->slotSpan(); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::IsObjectInContextCompartment(JSObject *obj, const JSContext *cx) michael@0: { michael@0: return obj->compartment() == cx->compartment(); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::RunningWithTrustedPrincipals(JSContext *cx) michael@0: { michael@0: return cx->runningWithTrustedPrincipals(); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSScript *) michael@0: js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx) michael@0: { michael@0: ScriptFrameIter iter(cx); michael@0: if (iter.done()) michael@0: return nullptr; michael@0: michael@0: if (!iter.isFunctionFrame()) michael@0: return nullptr; michael@0: michael@0: RootedFunction scriptedCaller(cx, iter.callee()); michael@0: RootedScript outermost(cx, scriptedCaller->nonLazyScript()); michael@0: for (StaticScopeIter i(scriptedCaller); !i.done(); i++) { michael@0: if (i.type() == StaticScopeIter::FUNCTION) michael@0: outermost = i.funScript(); michael@0: } michael@0: return outermost; michael@0: } michael@0: michael@0: JS_FRIEND_API(JSFunction *) michael@0: js::DefineFunctionWithReserved(JSContext *cx, JSObject *objArg, const char *name, JSNative call, michael@0: unsigned nargs, unsigned attrs) michael@0: { michael@0: RootedObject obj(cx, objArg); michael@0: JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); michael@0: CHECK_REQUEST(cx); michael@0: assertSameCompartment(cx, obj); michael@0: JSAtom *atom = Atomize(cx, name, strlen(name)); michael@0: if (!atom) michael@0: return nullptr; michael@0: Rooted id(cx, AtomToId(atom)); michael@0: return DefineFunction(cx, obj, id, call, nargs, attrs, JSFunction::ExtendedFinalizeKind); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSFunction *) michael@0: js::NewFunctionWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, michael@0: JSObject *parentArg, const char *name) michael@0: { michael@0: RootedObject parent(cx, parentArg); michael@0: JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); michael@0: michael@0: CHECK_REQUEST(cx); michael@0: assertSameCompartment(cx, parent); michael@0: michael@0: RootedAtom atom(cx); michael@0: if (name) { michael@0: atom = Atomize(cx, name, strlen(name)); michael@0: if (!atom) michael@0: return nullptr; michael@0: } michael@0: michael@0: JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags); michael@0: return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom, michael@0: JSFunction::ExtendedFinalizeKind); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSFunction *) michael@0: js::NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parentArg, michael@0: jsid id) michael@0: { michael@0: RootedObject parent(cx, parentArg); michael@0: JS_ASSERT(JSID_IS_STRING(id)); michael@0: JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); michael@0: CHECK_REQUEST(cx); michael@0: assertSameCompartment(cx, parent); michael@0: michael@0: RootedAtom atom(cx, JSID_TO_ATOM(id)); michael@0: JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags); michael@0: return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom, michael@0: JSFunction::ExtendedFinalizeKind); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: js::InitClassWithReserved(JSContext *cx, JSObject *objArg, JSObject *parent_protoArg, michael@0: const JSClass *clasp, JSNative constructor, unsigned nargs, michael@0: const JSPropertySpec *ps, const JSFunctionSpec *fs, michael@0: const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs) michael@0: { michael@0: RootedObject obj(cx, objArg); michael@0: RootedObject parent_proto(cx, parent_protoArg); michael@0: CHECK_REQUEST(cx); michael@0: assertSameCompartment(cx, obj, parent_proto); michael@0: return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor, michael@0: nargs, ps, fs, static_ps, static_fs, nullptr, michael@0: JSFunction::ExtendedFinalizeKind); michael@0: } michael@0: michael@0: JS_FRIEND_API(const Value &) michael@0: js::GetFunctionNativeReserved(JSObject *fun, size_t which) michael@0: { michael@0: JS_ASSERT(fun->as().isNative()); michael@0: return fun->as().getExtendedSlot(which); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val) michael@0: { michael@0: JS_ASSERT(fun->as().isNative()); michael@0: MOZ_ASSERT_IF(val.isObject(), val.toObject().compartment() == fun->compartment()); michael@0: fun->as().setExtendedSlot(which, val); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::GetObjectProto(JSContext *cx, JS::Handle obj, JS::MutableHandle proto) michael@0: { michael@0: if (IsProxy(obj)) michael@0: return JS_GetPrototype(cx, obj, proto); michael@0: michael@0: proto.set(reinterpret_cast(obj.get())->type->proto); michael@0: return true; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::GetOriginalEval(JSContext *cx, HandleObject scope, MutableHandleObject eval) michael@0: { michael@0: assertSameCompartment(cx, scope); michael@0: Rooted global(cx, &scope->global()); michael@0: return GlobalObject::getOrCreateEval(cx, global, eval); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::SetReservedSlotWithBarrier(JSObject *obj, size_t slot, const js::Value &value) michael@0: { michael@0: obj->setSlot(slot, value); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::GetGeneric(JSContext *cx, JSObject *objArg, JSObject *receiverArg, jsid idArg, michael@0: Value *vp) michael@0: { michael@0: RootedObject obj(cx, objArg), receiver(cx, receiverArg); michael@0: RootedId id(cx, idArg); michael@0: RootedValue value(cx); michael@0: if (!JSObject::getGeneric(cx, obj, receiver, id, &value)) michael@0: return false; michael@0: *vp = value; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: js::SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback) michael@0: { michael@0: rt->preserveWrapperCallback = callback; michael@0: } michael@0: michael@0: /* michael@0: * The below code is for temporary telemetry use. It can be removed when michael@0: * sufficient data has been harvested. michael@0: */ michael@0: michael@0: namespace js { michael@0: // Defined in vm/GlobalObject.cpp. michael@0: extern size_t sSetProtoCalled; michael@0: } michael@0: michael@0: JS_FRIEND_API(size_t) michael@0: JS_SetProtoCalled(JSContext *) michael@0: { michael@0: return sSetProtoCalled; michael@0: } michael@0: michael@0: // Defined in jsiter.cpp. michael@0: extern size_t sCustomIteratorCount; michael@0: michael@0: JS_FRIEND_API(size_t) michael@0: JS_GetCustomIteratorCount(JSContext *cx) michael@0: { michael@0: return sCustomIteratorCount; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS_IsDeadWrapper(JSObject *obj) michael@0: { michael@0: if (!obj->is()) { michael@0: return false; michael@0: } michael@0: michael@0: return obj->as().handler()->family() == &DeadObjectProxy::sDeadObjectFamily; michael@0: } michael@0: michael@0: void michael@0: js::TraceWeakMaps(WeakMapTracer *trc) michael@0: { michael@0: WeakMapBase::traceAllMappings(trc); michael@0: WatchpointMap::traceAll(trc); michael@0: } michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: js::AreGCGrayBitsValid(JSRuntime *rt) michael@0: { michael@0: return rt->gcGrayBitsValid; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::ZoneGlobalsAreAllGray(JS::Zone *zone) michael@0: { michael@0: for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { michael@0: JSObject *obj = comp->maybeGlobal(); michael@0: if (!obj || !JS::GCThingIsMarkedGray(obj)) michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: JS_FRIEND_API(JSGCTraceKind) michael@0: js::GCThingTraceKind(void *thing) michael@0: { michael@0: JS_ASSERT(thing); michael@0: return gc::GetGCThingTraceKind(thing); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::VisitGrayWrapperTargets(Zone *zone, GCThingCallback callback, void *closure) michael@0: { michael@0: JSRuntime *rt = zone->runtimeFromMainThread(); michael@0: for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { michael@0: for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) { michael@0: gc::Cell *thing = e.front().key().wrapped; michael@0: if (!IsInsideNursery(rt, thing) && thing->isMarked(gc::GRAY)) michael@0: callback(closure, thing); michael@0: } michael@0: } michael@0: } michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: js::GetWeakmapKeyDelegate(JSObject *key) michael@0: { michael@0: if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) michael@0: return op(key); michael@0: return nullptr; michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback) michael@0: { michael@0: rt->telemetryCallback = callback; michael@0: } michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: JS_CloneObject(JSContext *cx, HandleObject obj, HandleObject protoArg, HandleObject parent) michael@0: { michael@0: Rooted proto(cx, protoArg.get()); michael@0: return CloneObject(cx, obj, proto, parent); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: JS_FRIEND_API(void) michael@0: js_DumpString(JSString *str) michael@0: { michael@0: str->dump(); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js_DumpAtom(JSAtom *atom) michael@0: { michael@0: atom->dump(); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js_DumpChars(const jschar *s, size_t n) michael@0: { michael@0: fprintf(stderr, "jschar * (%p) = ", (void *) s); michael@0: JSString::dumpChars(s, n); michael@0: fputc('\n', stderr); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js_DumpObject(JSObject *obj) michael@0: { michael@0: if (!obj) { michael@0: fprintf(stderr, "NULL\n"); michael@0: return; michael@0: } michael@0: obj->dump(); michael@0: } michael@0: michael@0: #endif michael@0: michael@0: struct DumpHeapTracer : public JSTracer michael@0: { michael@0: FILE *output; michael@0: michael@0: DumpHeapTracer(FILE *fp, JSRuntime *rt, JSTraceCallback callback, michael@0: WeakMapTraceKind weakTraceKind) michael@0: : JSTracer(rt, callback, weakTraceKind), output(fp) michael@0: {} michael@0: }; michael@0: michael@0: static char michael@0: MarkDescriptor(void *thing) michael@0: { michael@0: gc::Cell *cell = static_cast(thing); michael@0: if (cell->isMarked(gc::BLACK)) michael@0: return cell->isMarked(gc::GRAY) ? 'G' : 'B'; michael@0: else michael@0: return cell->isMarked(gc::GRAY) ? 'X' : 'W'; michael@0: } michael@0: michael@0: static void michael@0: DumpHeapVisitZone(JSRuntime *rt, void *data, Zone *zone) michael@0: { michael@0: DumpHeapTracer *dtrc = static_cast(data); michael@0: fprintf(dtrc->output, "# zone %p\n", (void *)zone); michael@0: } michael@0: michael@0: static void michael@0: DumpHeapVisitCompartment(JSRuntime *rt, void *data, JSCompartment *comp) michael@0: { michael@0: char name[1024]; michael@0: if (rt->compartmentNameCallback) michael@0: (*rt->compartmentNameCallback)(rt, comp, name, sizeof(name)); michael@0: else michael@0: strcpy(name, ""); michael@0: michael@0: DumpHeapTracer *dtrc = static_cast(data); michael@0: fprintf(dtrc->output, "# compartment %s [in zone %p]\n", name, (void *)comp->zone()); michael@0: } michael@0: michael@0: static void michael@0: DumpHeapVisitArena(JSRuntime *rt, void *data, gc::Arena *arena, michael@0: JSGCTraceKind traceKind, size_t thingSize) michael@0: { michael@0: DumpHeapTracer *dtrc = static_cast(data); michael@0: fprintf(dtrc->output, "# arena allockind=%u size=%u\n", michael@0: unsigned(arena->aheader.getAllocKind()), unsigned(thingSize)); michael@0: } michael@0: michael@0: static void michael@0: DumpHeapVisitCell(JSRuntime *rt, void *data, void *thing, michael@0: JSGCTraceKind traceKind, size_t thingSize) michael@0: { michael@0: DumpHeapTracer *dtrc = static_cast(data); michael@0: char cellDesc[1024 * 32]; michael@0: JS_GetTraceThingInfo(cellDesc, sizeof(cellDesc), dtrc, thing, traceKind, true); michael@0: fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing), cellDesc); michael@0: JS_TraceChildren(dtrc, thing, traceKind); michael@0: } michael@0: michael@0: static void michael@0: DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind) michael@0: { michael@0: if (gc::IsInsideNursery(trc->runtime(), *thingp)) michael@0: return; michael@0: michael@0: DumpHeapTracer *dtrc = static_cast(trc); michael@0: char buffer[1024]; michael@0: fprintf(dtrc->output, "> %p %c %s\n", *thingp, MarkDescriptor(*thingp), michael@0: dtrc->getTracingEdgeName(buffer, sizeof(buffer))); michael@0: } michael@0: michael@0: static void michael@0: DumpHeapVisitRoot(JSTracer *trc, void **thingp, JSGCTraceKind kind) michael@0: { michael@0: if (gc::IsInsideNursery(trc->runtime(), *thingp)) michael@0: return; michael@0: michael@0: DumpHeapTracer *dtrc = static_cast(trc); michael@0: char buffer[1024]; michael@0: fprintf(dtrc->output, "%p %c %s\n", *thingp, MarkDescriptor(*thingp), michael@0: dtrc->getTracingEdgeName(buffer, sizeof(buffer))); michael@0: } michael@0: michael@0: void michael@0: js::DumpHeapComplete(JSRuntime *rt, FILE *fp, js::DumpHeapNurseryBehaviour nurseryBehaviour) michael@0: { michael@0: #ifdef JSGC_GENERATIONAL michael@0: if (nurseryBehaviour == js::CollectNurseryBeforeDump) michael@0: MinorGC(rt, JS::gcreason::API); michael@0: #endif michael@0: michael@0: DumpHeapTracer dtrc(fp, rt, DumpHeapVisitRoot, TraceWeakMapKeysValues); michael@0: TraceRuntime(&dtrc); michael@0: michael@0: fprintf(dtrc.output, "==========\n"); michael@0: michael@0: dtrc.setTraceCallback(DumpHeapVisitChild); michael@0: IterateZonesCompartmentsArenasCells(rt, &dtrc, michael@0: DumpHeapVisitZone, michael@0: DumpHeapVisitCompartment, michael@0: DumpHeapVisitArena, michael@0: DumpHeapVisitCell); michael@0: michael@0: fflush(dtrc.output); michael@0: } michael@0: michael@0: JS_FRIEND_API(const JSStructuredCloneCallbacks *) michael@0: js::GetContextStructuredCloneCallbacks(JSContext *cx) michael@0: { michael@0: return cx->runtime()->structuredCloneCallbacks; michael@0: } michael@0: michael@0: #ifdef JS_THREADSAFE michael@0: JS_FRIEND_API(bool) michael@0: js::ContextHasOutstandingRequests(const JSContext *cx) michael@0: { michael@0: return cx->outstandingRequests > 0; michael@0: } michael@0: #endif michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg) michael@0: { michael@0: rt->activityCallback = cb; michael@0: rt->activityCallbackArg = arg; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::IsContextRunningJS(JSContext *cx) michael@0: { michael@0: return cx->currentlyRunning(); michael@0: } michael@0: michael@0: JS_FRIEND_API(JS::GCSliceCallback) michael@0: JS::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback) michael@0: { michael@0: JS::GCSliceCallback old = rt->gcSliceCallback; michael@0: rt->gcSliceCallback = callback; michael@0: return old; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS::WasIncrementalGC(JSRuntime *rt) michael@0: { michael@0: return rt->gcIsIncremental; michael@0: } michael@0: michael@0: jschar * michael@0: GCDescription::formatMessage(JSRuntime *rt) const michael@0: { michael@0: return rt->gcStats.formatMessage(); michael@0: } michael@0: michael@0: jschar * michael@0: GCDescription::formatJSON(JSRuntime *rt, uint64_t timestamp) const michael@0: { michael@0: return rt->gcStats.formatJSON(timestamp); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::NotifyDidPaint(JSRuntime *rt) michael@0: { michael@0: if (rt->gcZeal() == gc::ZealFrameVerifierPreValue) { michael@0: gc::VerifyBarriers(rt, gc::PreBarrierVerifier); michael@0: return; michael@0: } michael@0: michael@0: if (rt->gcZeal() == gc::ZealFrameVerifierPostValue) { michael@0: gc::VerifyBarriers(rt, gc::PostBarrierVerifier); michael@0: return; michael@0: } michael@0: michael@0: if (rt->gcZeal() == gc::ZealFrameGCValue) { michael@0: PrepareForFullGC(rt); michael@0: GCSlice(rt, GC_NORMAL, gcreason::REFRESH_FRAME); michael@0: return; michael@0: } michael@0: michael@0: if (JS::IsIncrementalGCInProgress(rt) && !rt->gcInterFrameGC) { michael@0: JS::PrepareForIncrementalGC(rt); michael@0: GCSlice(rt, GC_NORMAL, gcreason::REFRESH_FRAME); michael@0: } michael@0: michael@0: rt->gcInterFrameGC = false; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS::IsIncrementalGCEnabled(JSRuntime *rt) michael@0: { michael@0: return rt->gcIncrementalEnabled && rt->gcMode() == JSGC_MODE_INCREMENTAL; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS::IsIncrementalGCInProgress(JSRuntime *rt) michael@0: { michael@0: return rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcVerifyPreData; michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::DisableIncrementalGC(JSRuntime *rt) michael@0: { michael@0: rt->gcIncrementalEnabled = false; michael@0: } michael@0: michael@0: JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt) michael@0: : runtime(rt) michael@0: #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL) michael@0: , restartVerifier(rt->gcVerifyPostData) michael@0: #endif michael@0: { michael@0: #ifdef JSGC_GENERATIONAL michael@0: if (IsGenerationalGCEnabled(rt)) { michael@0: #ifdef JS_GC_ZEAL michael@0: if (restartVerifier) michael@0: gc::EndVerifyPostBarriers(rt); michael@0: #endif michael@0: MinorGC(rt, JS::gcreason::API); michael@0: rt->gcNursery.disable(); michael@0: rt->gcStoreBuffer.disable(); michael@0: } michael@0: #endif michael@0: ++rt->gcGenerationalDisabled; michael@0: } michael@0: michael@0: JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC() michael@0: { michael@0: JS_ASSERT(runtime->gcGenerationalDisabled > 0); michael@0: --runtime->gcGenerationalDisabled; michael@0: #ifdef JSGC_GENERATIONAL michael@0: if (runtime->gcGenerationalDisabled == 0) { michael@0: runtime->gcNursery.enable(); michael@0: runtime->gcStoreBuffer.enable(); michael@0: #ifdef JS_GC_ZEAL michael@0: if (restartVerifier) michael@0: gc::StartVerifyPostBarriers(runtime); michael@0: #endif michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: JS::IsGenerationalGCEnabled(JSRuntime *rt) michael@0: { michael@0: return rt->gcGenerationalDisabled == 0; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS::IsIncrementalBarrierNeeded(JSRuntime *rt) michael@0: { michael@0: return rt->gcIncrementalState == gc::MARK && !rt->isHeapBusy(); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: JS::IsIncrementalBarrierNeeded(JSContext *cx) michael@0: { michael@0: return IsIncrementalBarrierNeeded(cx->runtime()); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::IncrementalObjectBarrier(JSObject *obj) michael@0: { michael@0: if (!obj) michael@0: return; michael@0: michael@0: JS_ASSERT(!obj->zone()->runtimeFromMainThread()->isHeapMajorCollecting()); michael@0: michael@0: AutoMarkInDeadZone amn(obj->zone()); michael@0: michael@0: JSObject::writeBarrierPre(obj); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind) michael@0: { michael@0: if (!ptr) michael@0: return; michael@0: michael@0: if (kind == JSTRACE_STRING && StringIsPermanentAtom(static_cast(ptr))) michael@0: return; michael@0: michael@0: gc::Cell *cell = static_cast(ptr); michael@0: Zone *zone = kind == JSTRACE_OBJECT michael@0: ? static_cast(cell)->zone() michael@0: : cell->tenuredZone(); michael@0: michael@0: JS_ASSERT(!zone->runtimeFromMainThread()->isHeapMajorCollecting()); michael@0: michael@0: AutoMarkInDeadZone amn(zone); michael@0: michael@0: if (kind == JSTRACE_OBJECT) michael@0: JSObject::writeBarrierPre(static_cast(cell)); michael@0: else if (kind == JSTRACE_STRING) michael@0: JSString::writeBarrierPre(static_cast(cell)); michael@0: else if (kind == JSTRACE_SCRIPT) michael@0: JSScript::writeBarrierPre(static_cast(cell)); michael@0: else if (kind == JSTRACE_LAZY_SCRIPT) michael@0: LazyScript::writeBarrierPre(static_cast(cell)); michael@0: else if (kind == JSTRACE_SHAPE) michael@0: Shape::writeBarrierPre(static_cast(cell)); michael@0: else if (kind == JSTRACE_BASE_SHAPE) michael@0: BaseShape::writeBarrierPre(static_cast(cell)); michael@0: else if (kind == JSTRACE_TYPE_OBJECT) michael@0: types::TypeObject::writeBarrierPre((types::TypeObject *) ptr); michael@0: else michael@0: MOZ_ASSUME_UNREACHABLE("invalid trace kind"); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::IncrementalValueBarrier(const Value &v) michael@0: { michael@0: js::HeapValue::writeBarrierPre(v); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: JS::PokeGC(JSRuntime *rt) michael@0: { michael@0: rt->gcPoke = true; michael@0: } michael@0: michael@0: JS_FRIEND_API(JSCompartment *) michael@0: js::GetAnyCompartmentInZone(JS::Zone *zone) michael@0: { michael@0: CompartmentsInZoneIter comp(zone); michael@0: JS_ASSERT(!comp.done()); michael@0: return comp.get(); michael@0: } michael@0: michael@0: bool michael@0: JS::ObjectPtr::isAboutToBeFinalized() michael@0: { michael@0: return JS_IsAboutToBeFinalized(&value); michael@0: } michael@0: michael@0: void michael@0: JS::ObjectPtr::trace(JSTracer *trc, const char *name) michael@0: { michael@0: JS_CallHeapObjectTracer(trc, &value, name); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: js::GetTestingFunctions(JSContext *cx) michael@0: { michael@0: RootedObject obj(cx, JS_NewObject(cx, nullptr, NullPtr(), NullPtr())); michael@0: if (!obj) michael@0: return nullptr; michael@0: michael@0: if (!DefineTestingFunctions(cx, obj, false)) michael@0: return nullptr; michael@0: michael@0: return obj; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: JS_FRIEND_API(unsigned) michael@0: js::GetEnterCompartmentDepth(JSContext *cx) michael@0: { michael@0: return cx->getEnterCompartmentDepth(); michael@0: } michael@0: #endif michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks) michael@0: { michael@0: rt->DOMcallbacks = callbacks; michael@0: } michael@0: michael@0: JS_FRIEND_API(const DOMCallbacks *) michael@0: js::GetDOMCallbacks(JSRuntime *rt) michael@0: { michael@0: return rt->DOMcallbacks; michael@0: } michael@0: michael@0: static const void *gDOMProxyHandlerFamily = nullptr; michael@0: static uint32_t gDOMProxyExpandoSlot = 0; michael@0: static DOMProxyShadowsCheck gDOMProxyShadowsCheck; michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::SetDOMProxyInformation(const void *domProxyHandlerFamily, uint32_t domProxyExpandoSlot, michael@0: DOMProxyShadowsCheck domProxyShadowsCheck) michael@0: { michael@0: gDOMProxyHandlerFamily = domProxyHandlerFamily; michael@0: gDOMProxyExpandoSlot = domProxyExpandoSlot; michael@0: gDOMProxyShadowsCheck = domProxyShadowsCheck; michael@0: } michael@0: michael@0: const void * michael@0: js::GetDOMProxyHandlerFamily() michael@0: { michael@0: return gDOMProxyHandlerFamily; michael@0: } michael@0: michael@0: uint32_t michael@0: js::GetDOMProxyExpandoSlot() michael@0: { michael@0: return gDOMProxyExpandoSlot; michael@0: } michael@0: michael@0: DOMProxyShadowsCheck michael@0: js::GetDOMProxyShadowsCheck() michael@0: { michael@0: return gDOMProxyShadowsCheck; michael@0: } michael@0: michael@0: bool michael@0: js::detail::IdMatchesAtom(jsid id, JSAtom *atom) michael@0: { michael@0: return id == INTERNED_STRING_TO_JSID(nullptr, atom); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSContext *) michael@0: js::DefaultJSContext(JSRuntime *rt) michael@0: { michael@0: if (rt->defaultJSContextCallback) { michael@0: JSContext *cx = rt->defaultJSContextCallback(rt); michael@0: JS_ASSERT(cx); michael@0: return cx; michael@0: } michael@0: JS_ASSERT(rt->contextList.getFirst() == rt->contextList.getLast()); michael@0: return rt->contextList.getFirst(); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::SetDefaultJSContextCallback(JSRuntime *rt, DefaultJSContextCallback cb) michael@0: { michael@0: rt->defaultJSContextCallback = cb; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: JS_FRIEND_API(void) michael@0: js::Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx) michael@0: { michael@0: rt->activeContext = cx; michael@0: } michael@0: #endif michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::SetCTypesActivityCallback(JSRuntime *rt, CTypesActivityCallback cb) michael@0: { michael@0: rt->ctypesActivityCallback = cb; michael@0: } michael@0: michael@0: js::AutoCTypesActivityCallback::AutoCTypesActivityCallback(JSContext *cx, michael@0: js::CTypesActivityType beginType, michael@0: js::CTypesActivityType endType michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) michael@0: : cx(cx), callback(cx->runtime()->ctypesActivityCallback), endType(endType) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: michael@0: if (callback) michael@0: callback(cx, beginType); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::SetObjectMetadataCallback(JSContext *cx, ObjectMetadataCallback callback) michael@0: { michael@0: cx->compartment()->setObjectMetadataCallback(callback); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js::SetObjectMetadata(JSContext *cx, HandleObject obj, HandleObject metadata) michael@0: { michael@0: return JSObject::setMetadata(cx, obj, metadata); michael@0: } michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: js::GetObjectMetadata(JSObject *obj) michael@0: { michael@0: return obj->getMetadata(); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: js::UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value) michael@0: { michael@0: JS_ASSERT(obj->isNative()); michael@0: JS_ASSERT(index < obj->getDenseInitializedLength()); michael@0: obj->setDenseElementWithType(cx, index, value); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg, michael@0: JS::Handle descriptor, bool *bp) michael@0: { michael@0: RootedObject obj(cx, objArg); michael@0: RootedId id(cx, idArg); michael@0: JS_ASSERT(cx->runtime()->heapState == js::Idle); michael@0: CHECK_REQUEST(cx); michael@0: assertSameCompartment(cx, obj, id, descriptor.value()); michael@0: if (descriptor.hasGetterObject()) michael@0: assertSameCompartment(cx, descriptor.getterObject()); michael@0: if (descriptor.hasSetterObject()) michael@0: assertSameCompartment(cx, descriptor.setterObject()); michael@0: michael@0: return DefineOwnProperty(cx, HandleObject(obj), id, descriptor, bp); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js_ReportIsNotFunction(JSContext *cx, JS::HandleValue v) michael@0: { michael@0: return ReportIsNotFunction(cx, v); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: JS_PUBLIC_API(bool) michael@0: js::IsInRequest(JSContext *cx) michael@0: { michael@0: #ifdef JS_THREADSAFE michael@0: return !!cx->runtime()->requestDepth; michael@0: #else michael@0: return true; michael@0: #endif michael@0: } michael@0: #endif michael@0: michael@0: #ifdef JSGC_GENERATIONAL michael@0: JS_FRIEND_API(void) michael@0: JS_StoreObjectPostBarrierCallback(JSContext* cx, michael@0: void (*callback)(JSTracer *trc, JSObject *key, void *data), michael@0: JSObject *key, void *data) michael@0: { michael@0: JSRuntime *rt = cx->runtime(); michael@0: if (IsInsideNursery(rt, key)) michael@0: rt->gcStoreBuffer.putCallback(callback, key, data); michael@0: } michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: JS_StoreStringPostBarrierCallback(JSContext* cx, michael@0: void (*callback)(JSTracer *trc, JSString *key, void *data), michael@0: JSString *key, void *data) michael@0: { michael@0: JSRuntime *rt = cx->runtime(); michael@0: if (IsInsideNursery(rt, key)) michael@0: rt->gcStoreBuffer.putCallback(callback, key, data); michael@0: } michael@0: #endif /* JSGC_GENERATIONAL */