js/src/jsfriendapi.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "jsfriendapi.h"
     9 #include "mozilla/PodOperations.h"
    11 #include <stdint.h>
    13 #include "jscntxt.h"
    14 #include "jscompartment.h"
    15 #include "jsgc.h"
    16 #include "jsobj.h"
    17 #include "jsproxy.h"
    18 #include "jswatchpoint.h"
    19 #include "jsweakmap.h"
    20 #include "jswrapper.h"
    21 #include "prmjtime.h"
    23 #include "builtin/TestingFunctions.h"
    24 #include "vm/WrapperObject.h"
    26 #include "jsobjinlines.h"
    28 #include "vm/ScopeObject-inl.h"
    30 using namespace js;
    31 using namespace JS;
    33 using mozilla::PodArrayZero;
    35 // Required by PerThreadDataFriendFields::getMainThread()
    36 JS_STATIC_ASSERT(offsetof(JSRuntime, mainThread) ==
    37                  PerThreadDataFriendFields::RuntimeMainThreadOffset);
    39 PerThreadDataFriendFields::PerThreadDataFriendFields()
    40 {
    41     PodArrayZero(nativeStackLimit);
    42 #if JS_STACK_GROWTH_DIRECTION > 0
    43     for (int i=0; i<StackKindCount; i++)
    44         nativeStackLimit[i] = UINTPTR_MAX;
    45 #endif
    46 #if defined(JSGC_USE_EXACT_ROOTING)
    47     PodArrayZero(thingGCRooters);
    48 #endif
    49 }
    51 JS_FRIEND_API(void)
    52 js::SetSourceHook(JSRuntime *rt, SourceHook *hook)
    53 {
    54     rt->sourceHook = hook;
    55 }
    57 JS_FRIEND_API(SourceHook *)
    58 js::ForgetSourceHook(JSRuntime *rt)
    59 {
    60     return rt->sourceHook.forget();
    61 }
    63 JS_FRIEND_API(void)
    64 JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
    65 {
    66     rt->gcGrayRootTracer.op = traceOp;
    67     rt->gcGrayRootTracer.data = data;
    68 }
    70 JS_FRIEND_API(JSString *)
    71 JS_GetAnonymousString(JSRuntime *rt)
    72 {
    73     JS_ASSERT(rt->hasContexts());
    74     return rt->commonNames->anonymous;
    75 }
    77 JS_FRIEND_API(void)
    78 JS_SetIsWorkerRuntime(JSRuntime *rt)
    79 {
    80     rt->setIsWorkerRuntime();
    81 }
    83 JS_FRIEND_API(JSObject *)
    84 JS_FindCompilationScope(JSContext *cx, HandleObject objArg)
    85 {
    86     RootedObject obj(cx, objArg);
    88     /*
    89      * We unwrap wrappers here. This is a little weird, but it's what's being
    90      * asked of us.
    91      */
    92     if (obj->is<WrapperObject>())
    93         obj = UncheckedUnwrap(obj);
    95     /*
    96      * Innerize the target_obj so that we compile in the correct (inner)
    97      * scope.
    98      */
    99     if (JSObjectOp op = obj->getClass()->ext.innerObject)
   100         obj = op(cx, obj);
   101     return obj;
   102 }
   104 JS_FRIEND_API(JSFunction *)
   105 JS_GetObjectFunction(JSObject *obj)
   106 {
   107     if (obj->is<JSFunction>())
   108         return &obj->as<JSFunction>();
   109     return nullptr;
   110 }
   112 JS_FRIEND_API(bool)
   113 JS_SplicePrototype(JSContext *cx, HandleObject obj, HandleObject proto)
   114 {
   115     /*
   116      * Change the prototype of an object which hasn't been used anywhere
   117      * and does not share its type with another object. Unlike JS_SetPrototype,
   118      * does not nuke type information for the object.
   119      */
   120     CHECK_REQUEST(cx);
   122     if (!obj->hasSingletonType()) {
   123         /*
   124          * We can see non-singleton objects when trying to splice prototypes
   125          * due to mutable __proto__ (ugh).
   126          */
   127         return JS_SetPrototype(cx, obj, proto);
   128     }
   130     Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
   131     return obj->splicePrototype(cx, obj->getClass(), tagged);
   132 }
   134 JS_FRIEND_API(JSObject *)
   135 JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, HandleObject proto,
   136                            HandleObject parent)
   137 {
   138     /*
   139      * Create our object with a null proto and then splice in the correct proto
   140      * after we setSingletonType, so that we don't pollute the default
   141      * TypeObject attached to our proto with information about our object, since
   142      * we're not going to be using that TypeObject anyway.
   143      */
   144     RootedObject obj(cx, NewObjectWithGivenProto(cx, (const js::Class *)clasp, nullptr,
   145                                                  parent, SingletonObject));
   146     if (!obj)
   147         return nullptr;
   148     if (!JS_SplicePrototype(cx, obj, proto))
   149         return nullptr;
   150     return obj;
   151 }
   153 JS_FRIEND_API(void)
   154 JS::PrepareZoneForGC(Zone *zone)
   155 {
   156     zone->scheduleGC();
   157 }
   159 JS_FRIEND_API(void)
   160 JS::PrepareForFullGC(JSRuntime *rt)
   161 {
   162     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
   163         zone->scheduleGC();
   164 }
   166 JS_FRIEND_API(void)
   167 JS::PrepareForIncrementalGC(JSRuntime *rt)
   168 {
   169     if (!JS::IsIncrementalGCInProgress(rt))
   170         return;
   172     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
   173         if (zone->wasGCStarted())
   174             PrepareZoneForGC(zone);
   175     }
   176 }
   178 JS_FRIEND_API(bool)
   179 JS::IsGCScheduled(JSRuntime *rt)
   180 {
   181     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
   182         if (zone->isGCScheduled())
   183             return true;
   184     }
   186     return false;
   187 }
   189 JS_FRIEND_API(void)
   190 JS::SkipZoneForGC(Zone *zone)
   191 {
   192     zone->unscheduleGC();
   193 }
   195 JS_FRIEND_API(void)
   196 JS::GCForReason(JSRuntime *rt, gcreason::Reason reason)
   197 {
   198     GC(rt, GC_NORMAL, reason);
   199 }
   201 JS_FRIEND_API(void)
   202 JS::ShrinkingGC(JSRuntime *rt, gcreason::Reason reason)
   203 {
   204     GC(rt, GC_SHRINK, reason);
   205 }
   207 JS_FRIEND_API(void)
   208 JS::IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis)
   209 {
   210     GCSlice(rt, GC_NORMAL, reason, millis);
   211 }
   213 JS_FRIEND_API(void)
   214 JS::FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason)
   215 {
   216     GCFinalSlice(rt, GC_NORMAL, reason);
   217 }
   219 JS_FRIEND_API(JSPrincipals *)
   220 JS_GetCompartmentPrincipals(JSCompartment *compartment)
   221 {
   222     return compartment->principals;
   223 }
   225 JS_FRIEND_API(void)
   226 JS_SetCompartmentPrincipals(JSCompartment *compartment, JSPrincipals *principals)
   227 {
   228     // Short circuit if there's no change.
   229     if (principals == compartment->principals)
   230         return;
   232     // Any compartment with the trusted principals -- and there can be
   233     // multiple -- is a system compartment.
   234     const JSPrincipals *trusted = compartment->runtimeFromMainThread()->trustedPrincipals();
   235     bool isSystem = principals && principals == trusted;
   237     // Clear out the old principals, if any.
   238     if (compartment->principals) {
   239         JS_DropPrincipals(compartment->runtimeFromMainThread(), compartment->principals);
   240         compartment->principals = nullptr;
   241         // We'd like to assert that our new principals is always same-origin
   242         // with the old one, but JSPrincipals doesn't give us a way to do that.
   243         // But we can at least assert that we're not switching between system
   244         // and non-system.
   245         JS_ASSERT(compartment->isSystem == isSystem);
   246     }
   248     // Set up the new principals.
   249     if (principals) {
   250         JS_HoldPrincipals(principals);
   251         compartment->principals = principals;
   252     }
   254     // Update the system flag.
   255     compartment->isSystem = isSystem;
   256 }
   258 JS_FRIEND_API(bool)
   259 JS_WrapPropertyDescriptor(JSContext *cx, JS::MutableHandle<js::PropertyDescriptor> desc)
   260 {
   261     return cx->compartment()->wrap(cx, desc);
   262 }
   264 JS_FRIEND_API(bool)
   265 JS_WrapAutoIdVector(JSContext *cx, js::AutoIdVector &props)
   266 {
   267     return cx->compartment()->wrap(cx, props);
   268 }
   270 JS_FRIEND_API(void)
   271 JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape)
   272 {
   273     MarkCycleCollectorChildren(trc, static_cast<Shape *>(shape));
   274 }
   276 static bool
   277 DefineHelpProperty(JSContext *cx, HandleObject obj, const char *prop, const char *value)
   278 {
   279     RootedAtom atom(cx, Atomize(cx, value, strlen(value)));
   280     if (!atom)
   281         return false;
   282     return JS_DefineProperty(cx, obj, prop, atom, JSPROP_READONLY | JSPROP_PERMANENT,
   283                              JS_PropertyStub, JS_StrictPropertyStub);
   284 }
   286 JS_FRIEND_API(bool)
   287 JS_DefineFunctionsWithHelp(JSContext *cx, HandleObject obj, const JSFunctionSpecWithHelp *fs)
   288 {
   289     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
   291     CHECK_REQUEST(cx);
   292     assertSameCompartment(cx, obj);
   293     for (; fs->name; fs++) {
   294         JSAtom *atom = Atomize(cx, fs->name, strlen(fs->name));
   295         if (!atom)
   296             return false;
   298         Rooted<jsid> id(cx, AtomToId(atom));
   299         RootedFunction fun(cx, DefineFunction(cx, obj, id, fs->call, fs->nargs, fs->flags));
   300         if (!fun)
   301             return false;
   303         if (fs->usage) {
   304             if (!DefineHelpProperty(cx, fun, "usage", fs->usage))
   305                 return false;
   306         }
   308         if (fs->help) {
   309             if (!DefineHelpProperty(cx, fun, "help", fs->help))
   310                 return false;
   311         }
   312     }
   314     return true;
   315 }
   317 JS_FRIEND_API(bool)
   318 js_ObjectClassIs(JSContext *cx, HandleObject obj, ESClassValue classValue)
   319 {
   320     return ObjectClassIs(obj, classValue, cx);
   321 }
   323 JS_FRIEND_API(const char *)
   324 js_ObjectClassName(JSContext *cx, HandleObject obj)
   325 {
   326     return JSObject::className(cx, obj);
   327 }
   329 JS_FRIEND_API(JS::Zone *)
   330 js::GetCompartmentZone(JSCompartment *comp)
   331 {
   332     return comp->zone();
   333 }
   335 JS_FRIEND_API(bool)
   336 js::IsSystemCompartment(JSCompartment *comp)
   337 {
   338     return comp->isSystem;
   339 }
   341 JS_FRIEND_API(bool)
   342 js::IsSystemZone(Zone *zone)
   343 {
   344     return zone->isSystem;
   345 }
   347 JS_FRIEND_API(bool)
   348 js::IsAtomsCompartment(JSCompartment *comp)
   349 {
   350     return comp->runtimeFromAnyThread()->isAtomsCompartment(comp);
   351 }
   353 JS_FRIEND_API(bool)
   354 js::IsInNonStrictPropertySet(JSContext *cx)
   355 {
   356     jsbytecode *pc;
   357     JSScript *script = cx->currentScript(&pc, JSContext::ALLOW_CROSS_COMPARTMENT);
   358     return script && !script->strict() && (js_CodeSpec[*pc].format & JOF_SET);
   359 }
   361 JS_FRIEND_API(bool)
   362 js::IsFunctionObject(JSObject *obj)
   363 {
   364     return obj->is<JSFunction>();
   365 }
   367 JS_FRIEND_API(bool)
   368 js::IsScopeObject(JSObject *obj)
   369 {
   370     return obj->is<ScopeObject>();
   371 }
   373 JS_FRIEND_API(bool)
   374 js::IsCallObject(JSObject *obj)
   375 {
   376     return obj->is<CallObject>();
   377 }
   379 JS_FRIEND_API(JSObject *)
   380 js::GetObjectParentMaybeScope(JSObject *obj)
   381 {
   382     return obj->enclosingScope();
   383 }
   385 JS_FRIEND_API(JSObject *)
   386 js::GetGlobalForObjectCrossCompartment(JSObject *obj)
   387 {
   388     return &obj->global();
   389 }
   391 JS_FRIEND_API(void)
   392 js::SetPendingExceptionCrossContext(JSContext *cx, JS::HandleValue v)
   393 {
   394     cx->setPendingException(v);
   395 }
   397 JS_FRIEND_API(void)
   398 js::AssertSameCompartment(JSContext *cx, JSObject *obj)
   399 {
   400     assertSameCompartment(cx, obj);
   401 }
   403 #ifdef DEBUG
   404 JS_FRIEND_API(void)
   405 js::AssertSameCompartment(JSObject *objA, JSObject *objB)
   406 {
   407     JS_ASSERT(objA->compartment() == objB->compartment());
   408 }
   409 #endif
   411 JS_FRIEND_API(JSObject *)
   412 js::DefaultObjectForContextOrNull(JSContext *cx)
   413 {
   414     if (cx->options().noDefaultCompartmentObject())
   415         return nullptr;
   416     return cx->maybeDefaultCompartmentObject();
   417 }
   419 JS_FRIEND_API(void)
   420 js::SetDefaultObjectForContext(JSContext *cx, JSObject *obj)
   421 {
   422     cx->setDefaultCompartmentObject(obj);
   423 }
   425 JS_FRIEND_API(void)
   426 js::NotifyAnimationActivity(JSObject *obj)
   427 {
   428     obj->compartment()->lastAnimationTime = PRMJ_Now();
   429 }
   431 JS_FRIEND_API(uint32_t)
   432 js::GetObjectSlotSpan(JSObject *obj)
   433 {
   434     return obj->slotSpan();
   435 }
   437 JS_FRIEND_API(bool)
   438 js::IsObjectInContextCompartment(JSObject *obj, const JSContext *cx)
   439 {
   440     return obj->compartment() == cx->compartment();
   441 }
   443 JS_FRIEND_API(bool)
   444 js::RunningWithTrustedPrincipals(JSContext *cx)
   445 {
   446     return cx->runningWithTrustedPrincipals();
   447 }
   449 JS_FRIEND_API(JSScript *)
   450 js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx)
   451 {
   452     ScriptFrameIter iter(cx);
   453     if (iter.done())
   454         return nullptr;
   456     if (!iter.isFunctionFrame())
   457         return nullptr;
   459     RootedFunction scriptedCaller(cx, iter.callee());
   460     RootedScript outermost(cx, scriptedCaller->nonLazyScript());
   461     for (StaticScopeIter<NoGC> i(scriptedCaller); !i.done(); i++) {
   462         if (i.type() == StaticScopeIter<NoGC>::FUNCTION)
   463             outermost = i.funScript();
   464     }
   465     return outermost;
   466 }
   468 JS_FRIEND_API(JSFunction *)
   469 js::DefineFunctionWithReserved(JSContext *cx, JSObject *objArg, const char *name, JSNative call,
   470                                unsigned nargs, unsigned attrs)
   471 {
   472     RootedObject obj(cx, objArg);
   473     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
   474     CHECK_REQUEST(cx);
   475     assertSameCompartment(cx, obj);
   476     JSAtom *atom = Atomize(cx, name, strlen(name));
   477     if (!atom)
   478         return nullptr;
   479     Rooted<jsid> id(cx, AtomToId(atom));
   480     return DefineFunction(cx, obj, id, call, nargs, attrs, JSFunction::ExtendedFinalizeKind);
   481 }
   483 JS_FRIEND_API(JSFunction *)
   484 js::NewFunctionWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
   485                             JSObject *parentArg, const char *name)
   486 {
   487     RootedObject parent(cx, parentArg);
   488     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
   490     CHECK_REQUEST(cx);
   491     assertSameCompartment(cx, parent);
   493     RootedAtom atom(cx);
   494     if (name) {
   495         atom = Atomize(cx, name, strlen(name));
   496         if (!atom)
   497             return nullptr;
   498     }
   500     JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
   501     return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom,
   502                        JSFunction::ExtendedFinalizeKind);
   503 }
   505 JS_FRIEND_API(JSFunction *)
   506 js::NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parentArg,
   507                                 jsid id)
   508 {
   509     RootedObject parent(cx, parentArg);
   510     JS_ASSERT(JSID_IS_STRING(id));
   511     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
   512     CHECK_REQUEST(cx);
   513     assertSameCompartment(cx, parent);
   515     RootedAtom atom(cx, JSID_TO_ATOM(id));
   516     JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
   517     return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom,
   518                        JSFunction::ExtendedFinalizeKind);
   519 }
   521 JS_FRIEND_API(JSObject *)
   522 js::InitClassWithReserved(JSContext *cx, JSObject *objArg, JSObject *parent_protoArg,
   523                           const JSClass *clasp, JSNative constructor, unsigned nargs,
   524                           const JSPropertySpec *ps, const JSFunctionSpec *fs,
   525                           const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs)
   526 {
   527     RootedObject obj(cx, objArg);
   528     RootedObject parent_proto(cx, parent_protoArg);
   529     CHECK_REQUEST(cx);
   530     assertSameCompartment(cx, obj, parent_proto);
   531     return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor,
   532                         nargs, ps, fs, static_ps, static_fs, nullptr,
   533                         JSFunction::ExtendedFinalizeKind);
   534 }
   536 JS_FRIEND_API(const Value &)
   537 js::GetFunctionNativeReserved(JSObject *fun, size_t which)
   538 {
   539     JS_ASSERT(fun->as<JSFunction>().isNative());
   540     return fun->as<JSFunction>().getExtendedSlot(which);
   541 }
   543 JS_FRIEND_API(void)
   544 js::SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val)
   545 {
   546     JS_ASSERT(fun->as<JSFunction>().isNative());
   547     MOZ_ASSERT_IF(val.isObject(), val.toObject().compartment() == fun->compartment());
   548     fun->as<JSFunction>().setExtendedSlot(which, val);
   549 }
   551 JS_FRIEND_API(bool)
   552 js::GetObjectProto(JSContext *cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JSObject*> proto)
   553 {
   554     if (IsProxy(obj))
   555         return JS_GetPrototype(cx, obj, proto);
   557     proto.set(reinterpret_cast<const shadow::Object*>(obj.get())->type->proto);
   558     return true;
   559 }
   561 JS_FRIEND_API(bool)
   562 js::GetOriginalEval(JSContext *cx, HandleObject scope, MutableHandleObject eval)
   563 {
   564     assertSameCompartment(cx, scope);
   565     Rooted<GlobalObject *> global(cx, &scope->global());
   566     return GlobalObject::getOrCreateEval(cx, global, eval);
   567 }
   569 JS_FRIEND_API(void)
   570 js::SetReservedSlotWithBarrier(JSObject *obj, size_t slot, const js::Value &value)
   571 {
   572     obj->setSlot(slot, value);
   573 }
   575 JS_FRIEND_API(bool)
   576 js::GetGeneric(JSContext *cx, JSObject *objArg, JSObject *receiverArg, jsid idArg,
   577                Value *vp)
   578 {
   579     RootedObject obj(cx, objArg), receiver(cx, receiverArg);
   580     RootedId id(cx, idArg);
   581     RootedValue value(cx);
   582     if (!JSObject::getGeneric(cx, obj, receiver, id, &value))
   583         return false;
   584     *vp = value;
   585     return true;
   586 }
   588 void
   589 js::SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback)
   590 {
   591     rt->preserveWrapperCallback = callback;
   592 }
   594 /*
   595  * The below code is for temporary telemetry use. It can be removed when
   596  * sufficient data has been harvested.
   597  */
   599 namespace js {
   600 // Defined in vm/GlobalObject.cpp.
   601 extern size_t sSetProtoCalled;
   602 }
   604 JS_FRIEND_API(size_t)
   605 JS_SetProtoCalled(JSContext *)
   606 {
   607     return sSetProtoCalled;
   608 }
   610 // Defined in jsiter.cpp.
   611 extern size_t sCustomIteratorCount;
   613 JS_FRIEND_API(size_t)
   614 JS_GetCustomIteratorCount(JSContext *cx)
   615 {
   616     return sCustomIteratorCount;
   617 }
   619 JS_FRIEND_API(bool)
   620 JS_IsDeadWrapper(JSObject *obj)
   621 {
   622     if (!obj->is<ProxyObject>()) {
   623         return false;
   624     }
   626     return obj->as<ProxyObject>().handler()->family() == &DeadObjectProxy::sDeadObjectFamily;
   627 }
   629 void
   630 js::TraceWeakMaps(WeakMapTracer *trc)
   631 {
   632     WeakMapBase::traceAllMappings(trc);
   633     WatchpointMap::traceAll(trc);
   634 }
   636 extern JS_FRIEND_API(bool)
   637 js::AreGCGrayBitsValid(JSRuntime *rt)
   638 {
   639     return rt->gcGrayBitsValid;
   640 }
   642 JS_FRIEND_API(bool)
   643 js::ZoneGlobalsAreAllGray(JS::Zone *zone)
   644 {
   645     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
   646         JSObject *obj = comp->maybeGlobal();
   647         if (!obj || !JS::GCThingIsMarkedGray(obj))
   648             return false;
   649     }
   650     return true;
   651 }
   653 JS_FRIEND_API(JSGCTraceKind)
   654 js::GCThingTraceKind(void *thing)
   655 {
   656     JS_ASSERT(thing);
   657     return gc::GetGCThingTraceKind(thing);
   658 }
   660 JS_FRIEND_API(void)
   661 js::VisitGrayWrapperTargets(Zone *zone, GCThingCallback callback, void *closure)
   662 {
   663     JSRuntime *rt = zone->runtimeFromMainThread();
   664     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
   665         for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
   666             gc::Cell *thing = e.front().key().wrapped;
   667             if (!IsInsideNursery(rt, thing) && thing->isMarked(gc::GRAY))
   668                 callback(closure, thing);
   669         }
   670     }
   671 }
   673 JS_FRIEND_API(JSObject *)
   674 js::GetWeakmapKeyDelegate(JSObject *key)
   675 {
   676     if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp)
   677         return op(key);
   678     return nullptr;
   679 }
   681 JS_FRIEND_API(void)
   682 JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback)
   683 {
   684     rt->telemetryCallback = callback;
   685 }
   687 JS_FRIEND_API(JSObject *)
   688 JS_CloneObject(JSContext *cx, HandleObject obj, HandleObject protoArg, HandleObject parent)
   689 {
   690     Rooted<js::TaggedProto> proto(cx, protoArg.get());
   691     return CloneObject(cx, obj, proto, parent);
   692 }
   694 #ifdef DEBUG
   695 JS_FRIEND_API(void)
   696 js_DumpString(JSString *str)
   697 {
   698     str->dump();
   699 }
   701 JS_FRIEND_API(void)
   702 js_DumpAtom(JSAtom *atom)
   703 {
   704     atom->dump();
   705 }
   707 JS_FRIEND_API(void)
   708 js_DumpChars(const jschar *s, size_t n)
   709 {
   710     fprintf(stderr, "jschar * (%p) = ", (void *) s);
   711     JSString::dumpChars(s, n);
   712     fputc('\n', stderr);
   713 }
   715 JS_FRIEND_API(void)
   716 js_DumpObject(JSObject *obj)
   717 {
   718     if (!obj) {
   719         fprintf(stderr, "NULL\n");
   720         return;
   721     }
   722     obj->dump();
   723 }
   725 #endif
   727 struct DumpHeapTracer : public JSTracer
   728 {
   729     FILE   *output;
   731     DumpHeapTracer(FILE *fp, JSRuntime *rt, JSTraceCallback callback,
   732                    WeakMapTraceKind weakTraceKind)
   733       : JSTracer(rt, callback, weakTraceKind), output(fp)
   734     {}
   735 };
   737 static char
   738 MarkDescriptor(void *thing)
   739 {
   740     gc::Cell *cell = static_cast<gc::Cell*>(thing);
   741     if (cell->isMarked(gc::BLACK))
   742         return cell->isMarked(gc::GRAY) ? 'G' : 'B';
   743     else
   744         return cell->isMarked(gc::GRAY) ? 'X' : 'W';
   745 }
   747 static void
   748 DumpHeapVisitZone(JSRuntime *rt, void *data, Zone *zone)
   749 {
   750     DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
   751     fprintf(dtrc->output, "# zone %p\n", (void *)zone);
   752 }
   754 static void
   755 DumpHeapVisitCompartment(JSRuntime *rt, void *data, JSCompartment *comp)
   756 {
   757     char name[1024];
   758     if (rt->compartmentNameCallback)
   759         (*rt->compartmentNameCallback)(rt, comp, name, sizeof(name));
   760     else
   761         strcpy(name, "<unknown>");
   763     DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
   764     fprintf(dtrc->output, "# compartment %s [in zone %p]\n", name, (void *)comp->zone());
   765 }
   767 static void
   768 DumpHeapVisitArena(JSRuntime *rt, void *data, gc::Arena *arena,
   769                    JSGCTraceKind traceKind, size_t thingSize)
   770 {
   771     DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
   772     fprintf(dtrc->output, "# arena allockind=%u size=%u\n",
   773             unsigned(arena->aheader.getAllocKind()), unsigned(thingSize));
   774 }
   776 static void
   777 DumpHeapVisitCell(JSRuntime *rt, void *data, void *thing,
   778                   JSGCTraceKind traceKind, size_t thingSize)
   779 {
   780     DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
   781     char cellDesc[1024 * 32];
   782     JS_GetTraceThingInfo(cellDesc, sizeof(cellDesc), dtrc, thing, traceKind, true);
   783     fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing), cellDesc);
   784     JS_TraceChildren(dtrc, thing, traceKind);
   785 }
   787 static void
   788 DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind)
   789 {
   790     if (gc::IsInsideNursery(trc->runtime(), *thingp))
   791         return;
   793     DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(trc);
   794     char buffer[1024];
   795     fprintf(dtrc->output, "> %p %c %s\n", *thingp, MarkDescriptor(*thingp),
   796             dtrc->getTracingEdgeName(buffer, sizeof(buffer)));
   797 }
   799 static void
   800 DumpHeapVisitRoot(JSTracer *trc, void **thingp, JSGCTraceKind kind)
   801 {
   802     if (gc::IsInsideNursery(trc->runtime(), *thingp))
   803         return;
   805     DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(trc);
   806     char buffer[1024];
   807     fprintf(dtrc->output, "%p %c %s\n", *thingp, MarkDescriptor(*thingp),
   808             dtrc->getTracingEdgeName(buffer, sizeof(buffer)));
   809 }
   811 void
   812 js::DumpHeapComplete(JSRuntime *rt, FILE *fp, js::DumpHeapNurseryBehaviour nurseryBehaviour)
   813 {
   814 #ifdef JSGC_GENERATIONAL
   815     if (nurseryBehaviour == js::CollectNurseryBeforeDump)
   816         MinorGC(rt, JS::gcreason::API);
   817 #endif
   819     DumpHeapTracer dtrc(fp, rt, DumpHeapVisitRoot, TraceWeakMapKeysValues);
   820     TraceRuntime(&dtrc);
   822     fprintf(dtrc.output, "==========\n");
   824     dtrc.setTraceCallback(DumpHeapVisitChild);
   825     IterateZonesCompartmentsArenasCells(rt, &dtrc,
   826                                         DumpHeapVisitZone,
   827                                         DumpHeapVisitCompartment,
   828                                         DumpHeapVisitArena,
   829                                         DumpHeapVisitCell);
   831     fflush(dtrc.output);
   832 }
   834 JS_FRIEND_API(const JSStructuredCloneCallbacks *)
   835 js::GetContextStructuredCloneCallbacks(JSContext *cx)
   836 {
   837     return cx->runtime()->structuredCloneCallbacks;
   838 }
   840 #ifdef JS_THREADSAFE
   841 JS_FRIEND_API(bool)
   842 js::ContextHasOutstandingRequests(const JSContext *cx)
   843 {
   844     return cx->outstandingRequests > 0;
   845 }
   846 #endif
   848 JS_FRIEND_API(void)
   849 js::SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg)
   850 {
   851     rt->activityCallback = cb;
   852     rt->activityCallbackArg = arg;
   853 }
   855 JS_FRIEND_API(bool)
   856 js::IsContextRunningJS(JSContext *cx)
   857 {
   858     return cx->currentlyRunning();
   859 }
   861 JS_FRIEND_API(JS::GCSliceCallback)
   862 JS::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
   863 {
   864     JS::GCSliceCallback old = rt->gcSliceCallback;
   865     rt->gcSliceCallback = callback;
   866     return old;
   867 }
   869 JS_FRIEND_API(bool)
   870 JS::WasIncrementalGC(JSRuntime *rt)
   871 {
   872     return rt->gcIsIncremental;
   873 }
   875 jschar *
   876 GCDescription::formatMessage(JSRuntime *rt) const
   877 {
   878     return rt->gcStats.formatMessage();
   879 }
   881 jschar *
   882 GCDescription::formatJSON(JSRuntime *rt, uint64_t timestamp) const
   883 {
   884     return rt->gcStats.formatJSON(timestamp);
   885 }
   887 JS_FRIEND_API(void)
   888 JS::NotifyDidPaint(JSRuntime *rt)
   889 {
   890     if (rt->gcZeal() == gc::ZealFrameVerifierPreValue) {
   891         gc::VerifyBarriers(rt, gc::PreBarrierVerifier);
   892         return;
   893     }
   895     if (rt->gcZeal() == gc::ZealFrameVerifierPostValue) {
   896         gc::VerifyBarriers(rt, gc::PostBarrierVerifier);
   897         return;
   898     }
   900     if (rt->gcZeal() == gc::ZealFrameGCValue) {
   901         PrepareForFullGC(rt);
   902         GCSlice(rt, GC_NORMAL, gcreason::REFRESH_FRAME);
   903         return;
   904     }
   906     if (JS::IsIncrementalGCInProgress(rt) && !rt->gcInterFrameGC) {
   907         JS::PrepareForIncrementalGC(rt);
   908         GCSlice(rt, GC_NORMAL, gcreason::REFRESH_FRAME);
   909     }
   911     rt->gcInterFrameGC = false;
   912 }
   914 JS_FRIEND_API(bool)
   915 JS::IsIncrementalGCEnabled(JSRuntime *rt)
   916 {
   917     return rt->gcIncrementalEnabled && rt->gcMode() == JSGC_MODE_INCREMENTAL;
   918 }
   920 JS_FRIEND_API(bool)
   921 JS::IsIncrementalGCInProgress(JSRuntime *rt)
   922 {
   923     return rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcVerifyPreData;
   924 }
   926 JS_FRIEND_API(void)
   927 JS::DisableIncrementalGC(JSRuntime *rt)
   928 {
   929     rt->gcIncrementalEnabled = false;
   930 }
   932 JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt)
   933   : runtime(rt)
   934 #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
   935   , restartVerifier(rt->gcVerifyPostData)
   936 #endif
   937 {
   938 #ifdef JSGC_GENERATIONAL
   939     if (IsGenerationalGCEnabled(rt)) {
   940 #ifdef JS_GC_ZEAL
   941         if (restartVerifier)
   942             gc::EndVerifyPostBarriers(rt);
   943 #endif
   944         MinorGC(rt, JS::gcreason::API);
   945         rt->gcNursery.disable();
   946         rt->gcStoreBuffer.disable();
   947     }
   948 #endif
   949     ++rt->gcGenerationalDisabled;
   950 }
   952 JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC()
   953 {
   954     JS_ASSERT(runtime->gcGenerationalDisabled > 0);
   955     --runtime->gcGenerationalDisabled;
   956 #ifdef JSGC_GENERATIONAL
   957     if (runtime->gcGenerationalDisabled == 0) {
   958         runtime->gcNursery.enable();
   959         runtime->gcStoreBuffer.enable();
   960 #ifdef JS_GC_ZEAL
   961         if (restartVerifier)
   962             gc::StartVerifyPostBarriers(runtime);
   963 #endif
   964     }
   965 #endif
   966 }
   968 extern JS_FRIEND_API(bool)
   969 JS::IsGenerationalGCEnabled(JSRuntime *rt)
   970 {
   971     return rt->gcGenerationalDisabled == 0;
   972 }
   974 JS_FRIEND_API(bool)
   975 JS::IsIncrementalBarrierNeeded(JSRuntime *rt)
   976 {
   977     return rt->gcIncrementalState == gc::MARK && !rt->isHeapBusy();
   978 }
   980 JS_FRIEND_API(bool)
   981 JS::IsIncrementalBarrierNeeded(JSContext *cx)
   982 {
   983     return IsIncrementalBarrierNeeded(cx->runtime());
   984 }
   986 JS_FRIEND_API(void)
   987 JS::IncrementalObjectBarrier(JSObject *obj)
   988 {
   989     if (!obj)
   990         return;
   992     JS_ASSERT(!obj->zone()->runtimeFromMainThread()->isHeapMajorCollecting());
   994     AutoMarkInDeadZone amn(obj->zone());
   996     JSObject::writeBarrierPre(obj);
   997 }
   999 JS_FRIEND_API(void)
  1000 JS::IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind)
  1002     if (!ptr)
  1003         return;
  1005     if (kind == JSTRACE_STRING && StringIsPermanentAtom(static_cast<JSString *>(ptr)))
  1006         return;
  1008     gc::Cell *cell = static_cast<gc::Cell *>(ptr);
  1009     Zone *zone = kind == JSTRACE_OBJECT
  1010                  ? static_cast<JSObject *>(cell)->zone()
  1011                  : cell->tenuredZone();
  1013     JS_ASSERT(!zone->runtimeFromMainThread()->isHeapMajorCollecting());
  1015     AutoMarkInDeadZone amn(zone);
  1017     if (kind == JSTRACE_OBJECT)
  1018         JSObject::writeBarrierPre(static_cast<JSObject*>(cell));
  1019     else if (kind == JSTRACE_STRING)
  1020         JSString::writeBarrierPre(static_cast<JSString*>(cell));
  1021     else if (kind == JSTRACE_SCRIPT)
  1022         JSScript::writeBarrierPre(static_cast<JSScript*>(cell));
  1023     else if (kind == JSTRACE_LAZY_SCRIPT)
  1024         LazyScript::writeBarrierPre(static_cast<LazyScript*>(cell));
  1025     else if (kind == JSTRACE_SHAPE)
  1026         Shape::writeBarrierPre(static_cast<Shape*>(cell));
  1027     else if (kind == JSTRACE_BASE_SHAPE)
  1028         BaseShape::writeBarrierPre(static_cast<BaseShape*>(cell));
  1029     else if (kind == JSTRACE_TYPE_OBJECT)
  1030         types::TypeObject::writeBarrierPre((types::TypeObject *) ptr);
  1031     else
  1032         MOZ_ASSUME_UNREACHABLE("invalid trace kind");
  1035 JS_FRIEND_API(void)
  1036 JS::IncrementalValueBarrier(const Value &v)
  1038     js::HeapValue::writeBarrierPre(v);
  1041 JS_FRIEND_API(void)
  1042 JS::PokeGC(JSRuntime *rt)
  1044     rt->gcPoke = true;
  1047 JS_FRIEND_API(JSCompartment *)
  1048 js::GetAnyCompartmentInZone(JS::Zone *zone)
  1050     CompartmentsInZoneIter comp(zone);
  1051     JS_ASSERT(!comp.done());
  1052     return comp.get();
  1055 bool
  1056 JS::ObjectPtr::isAboutToBeFinalized()
  1058     return JS_IsAboutToBeFinalized(&value);
  1061 void
  1062 JS::ObjectPtr::trace(JSTracer *trc, const char *name)
  1064     JS_CallHeapObjectTracer(trc, &value, name);
  1067 JS_FRIEND_API(JSObject *)
  1068 js::GetTestingFunctions(JSContext *cx)
  1070     RootedObject obj(cx, JS_NewObject(cx, nullptr, NullPtr(), NullPtr()));
  1071     if (!obj)
  1072         return nullptr;
  1074     if (!DefineTestingFunctions(cx, obj, false))
  1075         return nullptr;
  1077     return obj;
  1080 #ifdef DEBUG
  1081 JS_FRIEND_API(unsigned)
  1082 js::GetEnterCompartmentDepth(JSContext *cx)
  1084   return cx->getEnterCompartmentDepth();
  1086 #endif
  1088 JS_FRIEND_API(void)
  1089 js::SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks)
  1091     rt->DOMcallbacks = callbacks;
  1094 JS_FRIEND_API(const DOMCallbacks *)
  1095 js::GetDOMCallbacks(JSRuntime *rt)
  1097     return rt->DOMcallbacks;
  1100 static const void *gDOMProxyHandlerFamily = nullptr;
  1101 static uint32_t gDOMProxyExpandoSlot = 0;
  1102 static DOMProxyShadowsCheck gDOMProxyShadowsCheck;
  1104 JS_FRIEND_API(void)
  1105 js::SetDOMProxyInformation(const void *domProxyHandlerFamily, uint32_t domProxyExpandoSlot,
  1106                            DOMProxyShadowsCheck domProxyShadowsCheck)
  1108     gDOMProxyHandlerFamily = domProxyHandlerFamily;
  1109     gDOMProxyExpandoSlot = domProxyExpandoSlot;
  1110     gDOMProxyShadowsCheck = domProxyShadowsCheck;
  1113 const void *
  1114 js::GetDOMProxyHandlerFamily()
  1116     return gDOMProxyHandlerFamily;
  1119 uint32_t
  1120 js::GetDOMProxyExpandoSlot()
  1122     return gDOMProxyExpandoSlot;
  1125 DOMProxyShadowsCheck
  1126 js::GetDOMProxyShadowsCheck()
  1128     return gDOMProxyShadowsCheck;
  1131 bool
  1132 js::detail::IdMatchesAtom(jsid id, JSAtom *atom)
  1134     return id == INTERNED_STRING_TO_JSID(nullptr, atom);
  1137 JS_FRIEND_API(JSContext *)
  1138 js::DefaultJSContext(JSRuntime *rt)
  1140     if (rt->defaultJSContextCallback) {
  1141         JSContext *cx = rt->defaultJSContextCallback(rt);
  1142         JS_ASSERT(cx);
  1143         return cx;
  1145     JS_ASSERT(rt->contextList.getFirst() == rt->contextList.getLast());
  1146     return rt->contextList.getFirst();
  1149 JS_FRIEND_API(void)
  1150 js::SetDefaultJSContextCallback(JSRuntime *rt, DefaultJSContextCallback cb)
  1152     rt->defaultJSContextCallback = cb;
  1155 #ifdef DEBUG
  1156 JS_FRIEND_API(void)
  1157 js::Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx)
  1159     rt->activeContext = cx;
  1161 #endif
  1163 JS_FRIEND_API(void)
  1164 js::SetCTypesActivityCallback(JSRuntime *rt, CTypesActivityCallback cb)
  1166     rt->ctypesActivityCallback = cb;
  1169 js::AutoCTypesActivityCallback::AutoCTypesActivityCallback(JSContext *cx,
  1170                                                            js::CTypesActivityType beginType,
  1171                                                            js::CTypesActivityType endType
  1172                                                            MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
  1173   : cx(cx), callback(cx->runtime()->ctypesActivityCallback), endType(endType)
  1175     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
  1177     if (callback)
  1178         callback(cx, beginType);
  1181 JS_FRIEND_API(void)
  1182 js::SetObjectMetadataCallback(JSContext *cx, ObjectMetadataCallback callback)
  1184     cx->compartment()->setObjectMetadataCallback(callback);
  1187 JS_FRIEND_API(bool)
  1188 js::SetObjectMetadata(JSContext *cx, HandleObject obj, HandleObject metadata)
  1190     return JSObject::setMetadata(cx, obj, metadata);
  1193 JS_FRIEND_API(JSObject *)
  1194 js::GetObjectMetadata(JSObject *obj)
  1196     return obj->getMetadata();
  1199 JS_FRIEND_API(void)
  1200 js::UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value)
  1202     JS_ASSERT(obj->isNative());
  1203     JS_ASSERT(index < obj->getDenseInitializedLength());
  1204     obj->setDenseElementWithType(cx, index, value);
  1207 JS_FRIEND_API(bool)
  1208 js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg,
  1209                      JS::Handle<js::PropertyDescriptor> descriptor, bool *bp)
  1211     RootedObject obj(cx, objArg);
  1212     RootedId id(cx, idArg);
  1213     JS_ASSERT(cx->runtime()->heapState == js::Idle);
  1214     CHECK_REQUEST(cx);
  1215     assertSameCompartment(cx, obj, id, descriptor.value());
  1216     if (descriptor.hasGetterObject())
  1217         assertSameCompartment(cx, descriptor.getterObject());
  1218     if (descriptor.hasSetterObject())
  1219         assertSameCompartment(cx, descriptor.setterObject());
  1221     return DefineOwnProperty(cx, HandleObject(obj), id, descriptor, bp);
  1224 JS_FRIEND_API(bool)
  1225 js_ReportIsNotFunction(JSContext *cx, JS::HandleValue v)
  1227     return ReportIsNotFunction(cx, v);
  1230 #ifdef DEBUG
  1231 JS_PUBLIC_API(bool)
  1232 js::IsInRequest(JSContext *cx)
  1234 #ifdef JS_THREADSAFE
  1235     return !!cx->runtime()->requestDepth;
  1236 #else
  1237     return true;
  1238 #endif
  1240 #endif
  1242 #ifdef JSGC_GENERATIONAL
  1243 JS_FRIEND_API(void)
  1244 JS_StoreObjectPostBarrierCallback(JSContext* cx,
  1245                                   void (*callback)(JSTracer *trc, JSObject *key, void *data),
  1246                                   JSObject *key, void *data)
  1248     JSRuntime *rt = cx->runtime();
  1249     if (IsInsideNursery(rt, key))
  1250         rt->gcStoreBuffer.putCallback(callback, key, data);
  1253 extern JS_FRIEND_API(void)
  1254 JS_StoreStringPostBarrierCallback(JSContext* cx,
  1255                                   void (*callback)(JSTracer *trc, JSString *key, void *data),
  1256                                   JSString *key, void *data)
  1258     JSRuntime *rt = cx->runtime();
  1259     if (IsInsideNursery(rt, key))
  1260         rt->gcStoreBuffer.putCallback(callback, key, data);
  1262 #endif /* JSGC_GENERATIONAL */

mercurial