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/. */
6 
7 #include "jsfriendapi.h"
8 
9 #include "mozilla/PodOperations.h"
10 
11 #include <stdint.h>
12 
13 #include "builtin/Promise.h"
14 #include "builtin/TestingFunctions.h"
15 #include "gc/GCInternals.h"
16 #include "gc/PublicIterators.h"
17 #include "gc/WeakMap.h"
18 #include "js/Printf.h"
19 #include "js/Proxy.h"
20 #include "js/Wrapper.h"
21 #include "proxy/DeadObjectProxy.h"
22 #include "vm/ArgumentsObject.h"
23 #include "vm/JSCompartment.h"
24 #include "vm/JSContext.h"
25 #include "vm/JSObject.h"
26 #include "vm/Time.h"
27 #include "vm/WrapperObject.h"
28 
29 #include "gc/Nursery-inl.h"
30 #include "vm/EnvironmentObject-inl.h"
31 #include "vm/JSObject-inl.h"
32 #include "vm/JSScript-inl.h"
33 #include "vm/NativeObject-inl.h"
34 
35 using namespace js;
36 
37 using mozilla::Move;
38 using mozilla::PodArrayZero;
39 
RootingContext()40 JS::RootingContext::RootingContext()
41     : autoGCRooters_(nullptr), compartment_(nullptr), zone_(nullptr) {
42   for (auto& stackRootPtr : stackRoots_) stackRootPtr = nullptr;
43 
44   PodArrayZero(nativeStackLimit);
45 #if JS_STACK_GROWTH_DIRECTION > 0
46   for (int i = 0; i < StackKindCount; i++) nativeStackLimit[i] = UINTPTR_MAX;
47 #endif
48 }
49 
SetSourceHook(JSContext * cx,mozilla::UniquePtr<SourceHook> hook)50 JS_FRIEND_API void js::SetSourceHook(JSContext* cx,
51                                      mozilla::UniquePtr<SourceHook> hook) {
52   cx->runtime()->sourceHook.ref() = Move(hook);
53 }
54 
ForgetSourceHook(JSContext * cx)55 JS_FRIEND_API mozilla::UniquePtr<SourceHook> js::ForgetSourceHook(
56     JSContext* cx) {
57   return Move(cx->runtime()->sourceHook.ref());
58 }
59 
JS_SetGrayGCRootsTracer(JSContext * cx,JSTraceDataOp traceOp,void * data)60 JS_FRIEND_API void JS_SetGrayGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp,
61                                            void* data) {
62   cx->runtime()->gc.setGrayRootsTracer(traceOp, data);
63 }
64 
JS_FindCompilationScope(JSContext * cx,HandleObject objArg)65 JS_FRIEND_API JSObject* JS_FindCompilationScope(JSContext* cx,
66                                                 HandleObject objArg) {
67   assertSameCompartment(cx, objArg);
68 
69   RootedObject obj(cx, objArg);
70 
71   /*
72    * We unwrap wrappers here. This is a little weird, but it's what's being
73    * asked of us.
74    */
75   if (obj->is<WrapperObject>()) obj = UncheckedUnwrap(obj);
76 
77   /*
78    * Get the Window if `obj` is a WindowProxy so that we compile in the
79    * correct (global) scope.
80    */
81   return ToWindowIfWindowProxy(obj);
82 }
83 
JS_GetObjectFunction(JSObject * obj)84 JS_FRIEND_API JSFunction* JS_GetObjectFunction(JSObject* obj) {
85   if (obj->is<JSFunction>()) return &obj->as<JSFunction>();
86   return nullptr;
87 }
88 
JS_SplicePrototype(JSContext * cx,HandleObject obj,HandleObject proto)89 JS_FRIEND_API bool JS_SplicePrototype(JSContext* cx, HandleObject obj,
90                                       HandleObject proto) {
91   /*
92    * Change the prototype of an object which hasn't been used anywhere
93    * and does not share its type with another object. Unlike JS_SetPrototype,
94    * does not nuke type information for the object.
95    */
96   CHECK_REQUEST(cx);
97   assertSameCompartment(cx, obj, proto);
98 
99   if (!obj->isSingleton()) {
100     /*
101      * We can see non-singleton objects when trying to splice prototypes
102      * due to mutable __proto__ (ugh).
103      */
104     return JS_SetPrototype(cx, obj, proto);
105   }
106 
107   Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
108   return JSObject::splicePrototype(cx, obj, obj->getClass(), tagged);
109 }
110 
JS_NewObjectWithUniqueType(JSContext * cx,const JSClass * clasp,HandleObject proto)111 JS_FRIEND_API JSObject* JS_NewObjectWithUniqueType(JSContext* cx,
112                                                    const JSClass* clasp,
113                                                    HandleObject proto) {
114   /*
115    * Create our object with a null proto and then splice in the correct proto
116    * after we setSingleton, so that we don't pollute the default
117    * ObjectGroup attached to our proto with information about our object, since
118    * we're not going to be using that ObjectGroup anyway.
119    */
120   RootedObject obj(cx, NewObjectWithGivenProto(cx, (const js::Class*)clasp,
121                                                nullptr, SingletonObject));
122   if (!obj) return nullptr;
123   if (!JS_SplicePrototype(cx, obj, proto)) return nullptr;
124   return obj;
125 }
126 
JS_NewObjectWithoutMetadata(JSContext * cx,const JSClass * clasp,JS::Handle<JSObject * > proto)127 JS_FRIEND_API JSObject* JS_NewObjectWithoutMetadata(
128     JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto) {
129   assertSameCompartment(cx, proto);
130   AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
131   return JS_NewObjectWithGivenProto(cx, clasp, proto);
132 }
133 
JS_GetIsSecureContext(JSCompartment * compartment)134 JS_FRIEND_API bool JS_GetIsSecureContext(JSCompartment* compartment) {
135   return compartment->creationOptions().secureContext();
136 }
137 
JS_GetCompartmentPrincipals(JSCompartment * compartment)138 JS_FRIEND_API JSPrincipals* JS_GetCompartmentPrincipals(
139     JSCompartment* compartment) {
140   return compartment->principals();
141 }
142 
JS_SetCompartmentPrincipals(JSCompartment * compartment,JSPrincipals * principals)143 JS_FRIEND_API void JS_SetCompartmentPrincipals(JSCompartment* compartment,
144                                                JSPrincipals* principals) {
145   // Short circuit if there's no change.
146   if (principals == compartment->principals()) return;
147 
148   // Any compartment with the trusted principals -- and there can be
149   // multiple -- is a system compartment.
150   const JSPrincipals* trusted =
151       compartment->runtimeFromActiveCooperatingThread()->trustedPrincipals();
152   bool isSystem = principals && principals == trusted;
153 
154   // Clear out the old principals, if any.
155   if (compartment->principals()) {
156     JS_DropPrincipals(TlsContext.get(), compartment->principals());
157     compartment->setPrincipals(nullptr);
158     // We'd like to assert that our new principals is always same-origin
159     // with the old one, but JSPrincipals doesn't give us a way to do that.
160     // But we can at least assert that we're not switching between system
161     // and non-system.
162     MOZ_ASSERT(compartment->isSystem() == isSystem);
163   }
164 
165   // Set up the new principals.
166   if (principals) {
167     JS_HoldPrincipals(principals);
168     compartment->setPrincipals(principals);
169   }
170 
171   // Update the system flag.
172   compartment->setIsSystem(isSystem);
173 }
174 
JS_GetScriptPrincipals(JSScript * script)175 JS_FRIEND_API JSPrincipals* JS_GetScriptPrincipals(JSScript* script) {
176   return script->principals();
177 }
178 
GetScriptCompartment(JSScript * script)179 JS_FRIEND_API JSCompartment* js::GetScriptCompartment(JSScript* script) {
180   return script->compartment();
181 }
182 
JS_ScriptHasMutedErrors(JSScript * script)183 JS_FRIEND_API bool JS_ScriptHasMutedErrors(JSScript* script) {
184   return script->mutedErrors();
185 }
186 
JS_WrapPropertyDescriptor(JSContext * cx,JS::MutableHandle<js::PropertyDescriptor> desc)187 JS_FRIEND_API bool JS_WrapPropertyDescriptor(
188     JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc) {
189   return cx->compartment()->wrap(cx, desc);
190 }
191 
JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer * trc,JS::GCCellPtr shape)192 JS_FRIEND_API void JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc,
193                                                        JS::GCCellPtr shape) {
194   MOZ_ASSERT(shape.is<Shape>());
195   TraceCycleCollectorChildren(trc, &shape.as<Shape>());
196 }
197 
JS_TraceObjectGroupCycleCollectorChildren(JS::CallbackTracer * trc,JS::GCCellPtr group)198 JS_FRIEND_API void JS_TraceObjectGroupCycleCollectorChildren(
199     JS::CallbackTracer* trc, JS::GCCellPtr group) {
200   MOZ_ASSERT(group.is<ObjectGroup>());
201   TraceCycleCollectorChildren(trc, &group.as<ObjectGroup>());
202 }
203 
DefineHelpProperty(JSContext * cx,HandleObject obj,const char * prop,const char * value)204 static bool DefineHelpProperty(JSContext* cx, HandleObject obj,
205                                const char* prop, const char* value) {
206   RootedAtom atom(cx, Atomize(cx, value, strlen(value)));
207   if (!atom) return false;
208   return JS_DefineProperty(cx, obj, prop, atom,
209                            JSPROP_READONLY | JSPROP_PERMANENT);
210 }
211 
JS_DefineFunctionsWithHelp(JSContext * cx,HandleObject obj,const JSFunctionSpecWithHelp * fs)212 JS_FRIEND_API bool JS_DefineFunctionsWithHelp(
213     JSContext* cx, HandleObject obj, const JSFunctionSpecWithHelp* fs) {
214   MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
215 
216   CHECK_REQUEST(cx);
217   assertSameCompartment(cx, obj);
218   for (; fs->name; fs++) {
219     JSAtom* atom = Atomize(cx, fs->name, strlen(fs->name));
220     if (!atom) return false;
221 
222     Rooted<jsid> id(cx, AtomToId(atom));
223     RootedFunction fun(cx, DefineFunction(cx, obj, id, fs->call, fs->nargs,
224                                           fs->flags | JSPROP_RESOLVING));
225     if (!fun) return false;
226 
227     if (fs->jitInfo) fun->setJitInfo(fs->jitInfo);
228 
229     if (fs->usage) {
230       if (!DefineHelpProperty(cx, fun, "usage", fs->usage)) return false;
231     }
232 
233     if (fs->help) {
234       if (!DefineHelpProperty(cx, fun, "help", fs->help)) return false;
235     }
236   }
237 
238   return true;
239 }
240 
GetBuiltinClass(JSContext * cx,HandleObject obj,ESClass * cls)241 JS_FRIEND_API bool js::GetBuiltinClass(JSContext* cx, HandleObject obj,
242                                        ESClass* cls) {
243   if (MOZ_UNLIKELY(obj->is<ProxyObject>()))
244     return Proxy::getBuiltinClass(cx, obj, cls);
245 
246   if (obj->is<PlainObject>() || obj->is<UnboxedPlainObject>())
247     *cls = ESClass::Object;
248   else if (obj->is<ArrayObject>())
249     *cls = ESClass::Array;
250   else if (obj->is<NumberObject>())
251     *cls = ESClass::Number;
252   else if (obj->is<StringObject>())
253     *cls = ESClass::String;
254   else if (obj->is<BooleanObject>())
255     *cls = ESClass::Boolean;
256   else if (obj->is<RegExpObject>())
257     *cls = ESClass::RegExp;
258   else if (obj->is<ArrayBufferObject>())
259     *cls = ESClass::ArrayBuffer;
260   else if (obj->is<SharedArrayBufferObject>())
261     *cls = ESClass::SharedArrayBuffer;
262   else if (obj->is<DateObject>())
263     *cls = ESClass::Date;
264   else if (obj->is<SetObject>())
265     *cls = ESClass::Set;
266   else if (obj->is<MapObject>())
267     *cls = ESClass::Map;
268   else if (obj->is<PromiseObject>())
269     *cls = ESClass::Promise;
270   else if (obj->is<MapIteratorObject>())
271     *cls = ESClass::MapIterator;
272   else if (obj->is<SetIteratorObject>())
273     *cls = ESClass::SetIterator;
274   else if (obj->is<ArgumentsObject>())
275     *cls = ESClass::Arguments;
276   else if (obj->is<ErrorObject>())
277     *cls = ESClass::Error;
278   else
279     *cls = ESClass::Other;
280 
281   return true;
282 }
283 
ObjectClassName(JSContext * cx,HandleObject obj)284 JS_FRIEND_API const char* js::ObjectClassName(JSContext* cx, HandleObject obj) {
285   assertSameCompartment(cx, obj);
286   return GetObjectClassName(cx, obj);
287 }
288 
GetCompartmentZone(JSCompartment * comp)289 JS_FRIEND_API JS::Zone* js::GetCompartmentZone(JSCompartment* comp) {
290   return comp->zone();
291 }
292 
IsSystemCompartment(JSCompartment * comp)293 JS_FRIEND_API bool js::IsSystemCompartment(JSCompartment* comp) {
294   return comp->isSystem();
295 }
296 
IsSystemZone(Zone * zone)297 JS_FRIEND_API bool js::IsSystemZone(Zone* zone) { return zone->isSystem; }
298 
IsAtomsCompartment(JSCompartment * comp)299 JS_FRIEND_API bool js::IsAtomsCompartment(JSCompartment* comp) {
300   return comp->runtimeFromAnyThread()->isAtomsCompartment(comp);
301 }
302 
IsAtomsZone(JS::Zone * zone)303 JS_FRIEND_API bool js::IsAtomsZone(JS::Zone* zone) {
304   return zone->runtimeFromAnyThread()->isAtomsZone(zone);
305 }
306 
IsFunctionObject(JSObject * obj)307 JS_FRIEND_API bool js::IsFunctionObject(JSObject* obj) {
308   return obj->is<JSFunction>();
309 }
310 
GetGlobalForObjectCrossCompartment(JSObject * obj)311 JS_FRIEND_API JSObject* js::GetGlobalForObjectCrossCompartment(JSObject* obj) {
312   return &obj->global();
313 }
314 
GetPrototypeNoProxy(JSObject * obj)315 JS_FRIEND_API JSObject* js::GetPrototypeNoProxy(JSObject* obj) {
316   MOZ_ASSERT(!obj->is<js::ProxyObject>());
317   return obj->staticPrototype();
318 }
319 
AssertSameCompartment(JSContext * cx,JSObject * obj)320 JS_FRIEND_API void js::AssertSameCompartment(JSContext* cx, JSObject* obj) {
321   assertSameCompartment(cx, obj);
322 }
323 
AssertSameCompartment(JSContext * cx,JS::HandleValue v)324 JS_FRIEND_API void js::AssertSameCompartment(JSContext* cx, JS::HandleValue v) {
325   assertSameCompartment(cx, v);
326 }
327 
328 #ifdef DEBUG
AssertSameCompartment(JSObject * objA,JSObject * objB)329 JS_FRIEND_API void js::AssertSameCompartment(JSObject* objA, JSObject* objB) {
330   MOZ_ASSERT(objA->compartment() == objB->compartment());
331 }
332 #endif
333 
NotifyAnimationActivity(JSObject * obj)334 JS_FRIEND_API void js::NotifyAnimationActivity(JSObject* obj) {
335   int64_t timeNow = PRMJ_Now();
336   obj->compartment()->lastAnimationTime = timeNow;
337   obj->runtimeFromActiveCooperatingThread()->lastAnimationTime = timeNow;
338 }
339 
GetObjectSlotSpan(JSObject * obj)340 JS_FRIEND_API uint32_t js::GetObjectSlotSpan(JSObject* obj) {
341   return obj->as<NativeObject>().slotSpan();
342 }
343 
IsObjectInContextCompartment(JSObject * obj,const JSContext * cx)344 JS_FRIEND_API bool js::IsObjectInContextCompartment(JSObject* obj,
345                                                     const JSContext* cx) {
346   return obj->compartment() == cx->compartment();
347 }
348 
RunningWithTrustedPrincipals(JSContext * cx)349 JS_FRIEND_API bool js::RunningWithTrustedPrincipals(JSContext* cx) {
350   return cx->runningWithTrustedPrincipals();
351 }
352 
DefineFunctionWithReserved(JSContext * cx,JSObject * objArg,const char * name,JSNative call,unsigned nargs,unsigned attrs)353 JS_FRIEND_API JSFunction* js::DefineFunctionWithReserved(
354     JSContext* cx, JSObject* objArg, const char* name, JSNative call,
355     unsigned nargs, unsigned attrs) {
356   RootedObject obj(cx, objArg);
357   MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
358   CHECK_REQUEST(cx);
359   assertSameCompartment(cx, obj);
360   JSAtom* atom = Atomize(cx, name, strlen(name));
361   if (!atom) return nullptr;
362   Rooted<jsid> id(cx, AtomToId(atom));
363   return DefineFunction(cx, obj, id, call, nargs, attrs,
364                         gc::AllocKind::FUNCTION_EXTENDED);
365 }
366 
NewFunctionWithReserved(JSContext * cx,JSNative native,unsigned nargs,unsigned flags,const char * name)367 JS_FRIEND_API JSFunction* js::NewFunctionWithReserved(JSContext* cx,
368                                                       JSNative native,
369                                                       unsigned nargs,
370                                                       unsigned flags,
371                                                       const char* name) {
372   MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
373 
374   CHECK_REQUEST(cx);
375 
376   RootedAtom atom(cx);
377   if (name) {
378     atom = Atomize(cx, name, strlen(name));
379     if (!atom) return nullptr;
380   }
381 
382   return (flags & JSFUN_CONSTRUCTOR)
383              ? NewNativeConstructor(cx, native, nargs, atom,
384                                     gc::AllocKind::FUNCTION_EXTENDED)
385              : NewNativeFunction(cx, native, nargs, atom,
386                                  gc::AllocKind::FUNCTION_EXTENDED);
387 }
388 
NewFunctionByIdWithReserved(JSContext * cx,JSNative native,unsigned nargs,unsigned flags,jsid id)389 JS_FRIEND_API JSFunction* js::NewFunctionByIdWithReserved(
390     JSContext* cx, JSNative native, unsigned nargs, unsigned flags, jsid id) {
391   MOZ_ASSERT(JSID_IS_STRING(id));
392   MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
393   CHECK_REQUEST(cx);
394   assertSameCompartment(cx, id);
395 
396   RootedAtom atom(cx, JSID_TO_ATOM(id));
397   return (flags & JSFUN_CONSTRUCTOR)
398              ? NewNativeConstructor(cx, native, nargs, atom,
399                                     gc::AllocKind::FUNCTION_EXTENDED)
400              : NewNativeFunction(cx, native, nargs, atom,
401                                  gc::AllocKind::FUNCTION_EXTENDED);
402 }
403 
GetFunctionNativeReserved(JSObject * fun,size_t which)404 JS_FRIEND_API const Value& js::GetFunctionNativeReserved(JSObject* fun,
405                                                          size_t which) {
406   MOZ_ASSERT(fun->as<JSFunction>().isNative());
407   return fun->as<JSFunction>().getExtendedSlot(which);
408 }
409 
SetFunctionNativeReserved(JSObject * fun,size_t which,const Value & val)410 JS_FRIEND_API void js::SetFunctionNativeReserved(JSObject* fun, size_t which,
411                                                  const Value& val) {
412   MOZ_ASSERT(fun->as<JSFunction>().isNative());
413   MOZ_ASSERT_IF(val.isObject(),
414                 val.toObject().compartment() == fun->compartment());
415   fun->as<JSFunction>().setExtendedSlot(which, val);
416 }
417 
FunctionHasNativeReserved(JSObject * fun)418 JS_FRIEND_API bool js::FunctionHasNativeReserved(JSObject* fun) {
419   MOZ_ASSERT(fun->as<JSFunction>().isNative());
420   return fun->as<JSFunction>().isExtended();
421 }
422 
GetObjectProto(JSContext * cx,JS::Handle<JSObject * > obj,JS::MutableHandle<JSObject * > proto)423 JS_FRIEND_API bool js::GetObjectProto(JSContext* cx, JS::Handle<JSObject*> obj,
424                                       JS::MutableHandle<JSObject*> proto) {
425   assertSameCompartment(cx, obj);
426 
427   if (IsProxy(obj)) return JS_GetPrototype(cx, obj, proto);
428 
429   proto.set(reinterpret_cast<const shadow::Object*>(obj.get())->group->proto);
430   return true;
431 }
432 
GetStaticPrototype(JSObject * obj)433 JS_FRIEND_API JSObject* js::GetStaticPrototype(JSObject* obj) {
434   MOZ_ASSERT(obj->hasStaticPrototype());
435   return obj->staticPrototype();
436 }
437 
GetOriginalEval(JSContext * cx,HandleObject scope,MutableHandleObject eval)438 JS_FRIEND_API bool js::GetOriginalEval(JSContext* cx, HandleObject scope,
439                                        MutableHandleObject eval) {
440   assertSameCompartment(cx, scope);
441   Rooted<GlobalObject*> global(cx, &scope->global());
442   return GlobalObject::getOrCreateEval(cx, global, eval);
443 }
444 
SetReservedSlotWithBarrier(JSObject * obj,size_t slot,const js::Value & value)445 JS_FRIEND_API void js::SetReservedSlotWithBarrier(JSObject* obj, size_t slot,
446                                                   const js::Value& value) {
447   if (IsProxy(obj))
448     obj->as<ProxyObject>().setReservedSlot(slot, value);
449   else
450     obj->as<NativeObject>().setSlot(slot, value);
451 }
452 
SetPreserveWrapperCallback(JSContext * cx,PreserveWrapperCallback callback)453 void js::SetPreserveWrapperCallback(JSContext* cx,
454                                     PreserveWrapperCallback callback) {
455   cx->runtime()->preserveWrapperCallback = callback;
456 }
457 
JS_PCToLineNumber(JSScript * script,jsbytecode * pc,unsigned * columnp)458 JS_FRIEND_API unsigned JS_PCToLineNumber(JSScript* script, jsbytecode* pc,
459                                          unsigned* columnp) {
460   return PCToLineNumber(script, pc, columnp);
461 }
462 
JS_IsDeadWrapper(JSObject * obj)463 JS_FRIEND_API bool JS_IsDeadWrapper(JSObject* obj) {
464   return IsDeadProxyObject(obj);
465 }
466 
JS_NewDeadWrapper(JSContext * cx,JSObject * origObj)467 JS_FRIEND_API JSObject* JS_NewDeadWrapper(JSContext* cx, JSObject* origObj) {
468   return NewDeadProxyObject(cx, origObj);
469 }
470 
JS_IsScriptSourceObject(JSObject * obj)471 JS_FRIEND_API bool JS_IsScriptSourceObject(JSObject* obj) {
472   return obj->is<ScriptSourceObject>();
473 }
474 
TraceWeakMaps(WeakMapTracer * trc)475 void js::TraceWeakMaps(WeakMapTracer* trc) {
476   WeakMapBase::traceAllMappings(trc);
477 }
478 
AreGCGrayBitsValid(JSRuntime * rt)479 extern JS_FRIEND_API bool js::AreGCGrayBitsValid(JSRuntime* rt) {
480   return rt->gc.areGrayBitsValid();
481 }
482 
ZoneGlobalsAreAllGray(JS::Zone * zone)483 JS_FRIEND_API bool js::ZoneGlobalsAreAllGray(JS::Zone* zone) {
484   for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
485     JSObject* obj = comp->unsafeUnbarrieredMaybeGlobal();
486     if (!obj || !JS::ObjectIsMarkedGray(obj)) return false;
487   }
488   return true;
489 }
490 
IsObjectZoneSweepingOrCompacting(JSObject * obj)491 JS_FRIEND_API bool js::IsObjectZoneSweepingOrCompacting(JSObject* obj) {
492   MOZ_ASSERT(obj);
493   return MaybeForwarded(obj)->zone()->isGCSweepingOrCompacting();
494 }
495 
496 namespace {
497 struct VisitGrayCallbackFunctor {
498   GCThingCallback callback_;
499   void* closure_;
VisitGrayCallbackFunctor__anone4bbc3a70111::VisitGrayCallbackFunctor500   VisitGrayCallbackFunctor(GCThingCallback callback, void* closure)
501       : callback_(callback), closure_(closure) {}
502 
503   template <class T>
operator ()__anone4bbc3a70111::VisitGrayCallbackFunctor504   void operator()(T tp) const {
505     if ((*tp)->isMarkedGray()) callback_(closure_, JS::GCCellPtr(*tp));
506   }
507 };
508 }  // namespace
509 
VisitGrayWrapperTargets(Zone * zone,GCThingCallback callback,void * closure)510 JS_FRIEND_API void js::VisitGrayWrapperTargets(Zone* zone,
511                                                GCThingCallback callback,
512                                                void* closure) {
513   for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
514     for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront())
515       e.front().mutableKey().applyToWrapped(
516           VisitGrayCallbackFunctor(callback, closure));
517   }
518 }
519 
GetWeakmapKeyDelegate(JSObject * key)520 JS_FRIEND_API JSObject* js::GetWeakmapKeyDelegate(JSObject* key) {
521   if (JSWeakmapKeyDelegateOp op = key->getClass()->extWeakmapKeyDelegateOp())
522     return op(key);
523   return nullptr;
524 }
525 
StringToLinearStringSlow(JSContext * cx,JSString * str)526 JS_FRIEND_API JSLinearString* js::StringToLinearStringSlow(JSContext* cx,
527                                                            JSString* str) {
528   return str->ensureLinear(cx);
529 }
530 
JS_SetAccumulateTelemetryCallback(JSContext * cx,JSAccumulateTelemetryDataCallback callback)531 JS_FRIEND_API void JS_SetAccumulateTelemetryCallback(
532     JSContext* cx, JSAccumulateTelemetryDataCallback callback) {
533   cx->runtime()->setTelemetryCallback(cx->runtime(), callback);
534 }
535 
JS_SetSetUseCounterCallback(JSContext * cx,JSSetUseCounterCallback callback)536 JS_FRIEND_API void JS_SetSetUseCounterCallback(
537     JSContext* cx, JSSetUseCounterCallback callback) {
538   cx->runtime()->setUseCounterCallback(cx->runtime(), callback);
539 }
540 
JS_CloneObject(JSContext * cx,HandleObject obj,HandleObject protoArg)541 JS_FRIEND_API JSObject* JS_CloneObject(JSContext* cx, HandleObject obj,
542                                        HandleObject protoArg) {
543   // |obj| might be in a different compartment.
544   assertSameCompartment(cx, protoArg);
545   Rooted<TaggedProto> proto(cx, TaggedProto(protoArg.get()));
546   return CloneObject(cx, obj, proto);
547 }
548 
549 #ifdef DEBUG
550 
551 // We don't want jsfriendapi.h to depend on GenericPrinter,
552 // so these functions are declared directly in the cpp.
553 
554 namespace js {
555 
556 extern JS_FRIEND_API void DumpString(JSString* str, js::GenericPrinter& out);
557 
558 extern JS_FRIEND_API void DumpAtom(JSAtom* atom, js::GenericPrinter& out);
559 
560 extern JS_FRIEND_API void DumpObject(JSObject* obj, js::GenericPrinter& out);
561 
562 extern JS_FRIEND_API void DumpChars(const char16_t* s, size_t n,
563                                     js::GenericPrinter& out);
564 
565 extern JS_FRIEND_API void DumpValue(const JS::Value& val,
566                                     js::GenericPrinter& out);
567 
568 extern JS_FRIEND_API void DumpId(jsid id, js::GenericPrinter& out);
569 
570 extern JS_FRIEND_API void DumpInterpreterFrame(
571     JSContext* cx, js::GenericPrinter& out, InterpreterFrame* start = nullptr);
572 
573 }  // namespace js
574 
DumpString(JSString * str,js::GenericPrinter & out)575 JS_FRIEND_API void js::DumpString(JSString* str, js::GenericPrinter& out) {
576   str->dump(out);
577 }
578 
DumpAtom(JSAtom * atom,js::GenericPrinter & out)579 JS_FRIEND_API void js::DumpAtom(JSAtom* atom, js::GenericPrinter& out) {
580   atom->dump(out);
581 }
582 
DumpChars(const char16_t * s,size_t n,js::GenericPrinter & out)583 JS_FRIEND_API void js::DumpChars(const char16_t* s, size_t n,
584                                  js::GenericPrinter& out) {
585   out.printf("char16_t * (%p) = ", (void*)s);
586   JSString::dumpChars(s, n, out);
587   out.putChar('\n');
588 }
589 
DumpObject(JSObject * obj,js::GenericPrinter & out)590 JS_FRIEND_API void js::DumpObject(JSObject* obj, js::GenericPrinter& out) {
591   if (!obj) {
592     out.printf("NULL\n");
593     return;
594   }
595   obj->dump(out);
596 }
597 
DumpString(JSString * str,FILE * fp)598 JS_FRIEND_API void js::DumpString(JSString* str, FILE* fp) {
599   Fprinter out(fp);
600   js::DumpString(str, out);
601 }
602 
DumpAtom(JSAtom * atom,FILE * fp)603 JS_FRIEND_API void js::DumpAtom(JSAtom* atom, FILE* fp) {
604   Fprinter out(fp);
605   js::DumpAtom(atom, out);
606 }
607 
DumpChars(const char16_t * s,size_t n,FILE * fp)608 JS_FRIEND_API void js::DumpChars(const char16_t* s, size_t n, FILE* fp) {
609   Fprinter out(fp);
610   js::DumpChars(s, n, out);
611 }
612 
DumpObject(JSObject * obj,FILE * fp)613 JS_FRIEND_API void js::DumpObject(JSObject* obj, FILE* fp) {
614   Fprinter out(fp);
615   js::DumpObject(obj, out);
616 }
617 
DumpId(jsid id,FILE * fp)618 JS_FRIEND_API void js::DumpId(jsid id, FILE* fp) {
619   Fprinter out(fp);
620   js::DumpId(id, out);
621 }
622 
DumpValue(const JS::Value & val,FILE * fp)623 JS_FRIEND_API void js::DumpValue(const JS::Value& val, FILE* fp) {
624   Fprinter out(fp);
625   js::DumpValue(val, out);
626 }
627 
DumpString(JSString * str)628 JS_FRIEND_API void js::DumpString(JSString* str) { DumpString(str, stderr); }
DumpAtom(JSAtom * atom)629 JS_FRIEND_API void js::DumpAtom(JSAtom* atom) { DumpAtom(atom, stderr); }
DumpObject(JSObject * obj)630 JS_FRIEND_API void js::DumpObject(JSObject* obj) { DumpObject(obj, stderr); }
DumpChars(const char16_t * s,size_t n)631 JS_FRIEND_API void js::DumpChars(const char16_t* s, size_t n) {
632   DumpChars(s, n, stderr);
633 }
DumpValue(const JS::Value & val)634 JS_FRIEND_API void js::DumpValue(const JS::Value& val) {
635   DumpValue(val, stderr);
636 }
DumpId(jsid id)637 JS_FRIEND_API void js::DumpId(jsid id) { DumpId(id, stderr); }
DumpInterpreterFrame(JSContext * cx,InterpreterFrame * start)638 JS_FRIEND_API void js::DumpInterpreterFrame(JSContext* cx,
639                                             InterpreterFrame* start) {
640   Fprinter out(stderr);
641   DumpInterpreterFrame(cx, out, start);
642 }
DumpPC(JSContext * cx)643 JS_FRIEND_API bool js::DumpPC(JSContext* cx) { return DumpPC(cx, stdout); }
DumpScript(JSContext * cx,JSScript * scriptArg)644 JS_FRIEND_API bool js::DumpScript(JSContext* cx, JSScript* scriptArg) {
645   return DumpScript(cx, scriptArg, stdout);
646 }
647 
648 #endif
649 
FormatValue(JSContext * cx,const Value & vArg,JSAutoByteString & bytes)650 static const char* FormatValue(JSContext* cx, const Value& vArg,
651                                JSAutoByteString& bytes) {
652   RootedValue v(cx, vArg);
653 
654   if (v.isMagic(JS_OPTIMIZED_OUT)) return "[unavailable]";
655 
656   /*
657    * We could use Maybe<AutoCompartment> here, but G++ can't quite follow
658    * that, and warns about uninitialized members being used in the
659    * destructor.
660    */
661   RootedString str(cx);
662   if (v.isObject()) {
663     AutoCompartment ac(cx, &v.toObject());
664     str = ToString<CanGC>(cx, v);
665   } else {
666     str = ToString<CanGC>(cx, v);
667   }
668 
669   if (!str) return nullptr;
670   const char* buf = bytes.encodeLatin1(cx, str);
671   if (!buf) return nullptr;
672   const char* found = strstr(buf, "function ");
673   if (found && (found - buf <= 2)) return "[function]";
674   return buf;
675 }
676 
677 // Wrapper for JS_sprintf_append() that reports allocation failure to the
678 // context.
679 static JS::UniqueChars MOZ_FORMAT_PRINTF(3, 4)
sprintf_append(JSContext * cx,JS::UniqueChars && buf,const char * fmt,...)680     sprintf_append(JSContext* cx, JS::UniqueChars&& buf, const char* fmt, ...) {
681   va_list ap;
682 
683   va_start(ap, fmt);
684   JS::UniqueChars result = JS_vsprintf_append(Move(buf), fmt, ap);
685   va_end(ap);
686 
687   if (!result) {
688     ReportOutOfMemory(cx);
689     return nullptr;
690   }
691 
692   return result;
693 }
694 
FormatFrame(JSContext * cx,const FrameIter & iter,JS::UniqueChars && inBuf,int num,bool showArgs,bool showLocals,bool showThisProps)695 static JS::UniqueChars FormatFrame(JSContext* cx, const FrameIter& iter,
696                                    JS::UniqueChars&& inBuf, int num,
697                                    bool showArgs, bool showLocals,
698                                    bool showThisProps) {
699   MOZ_ASSERT(!cx->isExceptionPending());
700   RootedScript script(cx, iter.script());
701   jsbytecode* pc = iter.pc();
702 
703   RootedObject envChain(cx, iter.environmentChain(cx));
704   JSAutoCompartment ac(cx, envChain);
705 
706   const char* filename = script->filename();
707   unsigned lineno = PCToLineNumber(script, pc);
708   RootedFunction fun(cx, iter.maybeCallee(cx));
709   RootedString funname(cx);
710   if (fun) funname = fun->displayAtom();
711 
712   RootedValue thisVal(cx);
713   if (iter.hasUsableAbstractFramePtr() && iter.isFunctionFrame() && fun &&
714       !fun->isArrow() && !fun->isDerivedClassConstructor() &&
715       !(fun->isBoundFunction() && iter.isConstructing())) {
716     if (!GetFunctionThis(cx, iter.abstractFramePtr(), &thisVal)) return nullptr;
717   }
718 
719   // print the frame number and function name
720   JS::UniqueChars buf(Move(inBuf));
721   if (funname) {
722     JSAutoByteString funbytes;
723     char* str = funbytes.encodeLatin1(cx, funname);
724     if (!str) return nullptr;
725     buf = sprintf_append(cx, Move(buf), "%d %s(", num, str);
726   } else if (fun) {
727     buf = sprintf_append(cx, Move(buf), "%d anonymous(", num);
728   } else {
729     buf = sprintf_append(cx, Move(buf), "%d <TOP LEVEL>", num);
730   }
731   if (!buf) return nullptr;
732 
733   if (showArgs && iter.hasArgs()) {
734     PositionalFormalParameterIter fi(script);
735     bool first = true;
736     for (unsigned i = 0; i < iter.numActualArgs(); i++) {
737       RootedValue arg(cx);
738       if (i < iter.numFormalArgs() && fi.closedOver()) {
739         arg = iter.callObj(cx).aliasedBinding(fi);
740       } else if (iter.hasUsableAbstractFramePtr()) {
741         if (script->analyzedArgsUsage() && script->argsObjAliasesFormals() &&
742             iter.hasArgsObj()) {
743           arg = iter.argsObj().arg(i);
744         } else {
745           arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING);
746         }
747       } else {
748         arg = MagicValue(JS_OPTIMIZED_OUT);
749       }
750 
751       JSAutoByteString valueBytes;
752       const char* value = FormatValue(cx, arg, valueBytes);
753       if (!value) {
754         if (cx->isThrowingOutOfMemory()) return nullptr;
755         cx->clearPendingException();
756       }
757 
758       JSAutoByteString nameBytes;
759       const char* name = nullptr;
760 
761       if (i < iter.numFormalArgs()) {
762         MOZ_ASSERT(fi.argumentSlot() == i);
763         if (!fi.isDestructured()) {
764           name = nameBytes.encodeLatin1(cx, fi.name());
765           if (!name) return nullptr;
766         } else {
767           name = "(destructured parameter)";
768         }
769         fi++;
770       }
771 
772       if (value) {
773         buf = sprintf_append(cx, Move(buf), "%s%s%s%s%s%s", !first ? ", " : "",
774                              name ? name : "", name ? " = " : "",
775                              arg.isString() ? "\"" : "", value,
776                              arg.isString() ? "\"" : "");
777         if (!buf) return nullptr;
778 
779         first = false;
780       } else {
781         buf = sprintf_append(
782             cx, Move(buf),
783             "    <Failed to get argument while inspecting stack frame>\n");
784         if (!buf) return nullptr;
785       }
786     }
787   }
788 
789   // print filename and line number
790   buf = sprintf_append(cx, Move(buf), "%s [\"%s\":%d]\n", fun ? ")" : "",
791                        filename ? filename : "<unknown>", lineno);
792   if (!buf) return nullptr;
793 
794   // Note: Right now we don't dump the local variables anymore, because
795   // that is hard to support across all the JITs etc.
796 
797   // print the value of 'this'
798   if (showLocals) {
799     if (!thisVal.isUndefined()) {
800       JSAutoByteString thisValBytes;
801       RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal));
802       if (!thisValStr) {
803         if (cx->isThrowingOutOfMemory()) return nullptr;
804         cx->clearPendingException();
805       }
806       if (thisValStr) {
807         const char* str = thisValBytes.encodeLatin1(cx, thisValStr);
808         if (!str) return nullptr;
809         buf = sprintf_append(cx, Move(buf), "    this = %s\n", str);
810       } else {
811         buf =
812             sprintf_append(cx, Move(buf), "    <failed to get 'this' value>\n");
813       }
814       if (!buf) return nullptr;
815     }
816   }
817 
818   if (showThisProps && thisVal.isObject()) {
819     RootedObject obj(cx, &thisVal.toObject());
820 
821     AutoIdVector keys(cx);
822     if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &keys)) {
823       if (cx->isThrowingOutOfMemory()) return nullptr;
824       cx->clearPendingException();
825     }
826 
827     RootedId id(cx);
828     for (size_t i = 0; i < keys.length(); i++) {
829       RootedId id(cx, keys[i]);
830       RootedValue key(cx, IdToValue(id));
831       RootedValue v(cx);
832 
833       if (!GetProperty(cx, obj, obj, id, &v)) {
834         if (cx->isThrowingOutOfMemory()) return nullptr;
835         cx->clearPendingException();
836         buf = sprintf_append(
837             cx, Move(buf),
838             "    <Failed to fetch property while inspecting stack frame>\n");
839         if (!buf) return nullptr;
840         continue;
841       }
842 
843       JSAutoByteString nameBytes;
844       const char* name = FormatValue(cx, key, nameBytes);
845       if (!name) {
846         if (cx->isThrowingOutOfMemory()) return nullptr;
847         cx->clearPendingException();
848       }
849 
850       JSAutoByteString valueBytes;
851       const char* value = FormatValue(cx, v, valueBytes);
852       if (!value) {
853         if (cx->isThrowingOutOfMemory()) return nullptr;
854         cx->clearPendingException();
855       }
856 
857       if (name && value) {
858         buf = sprintf_append(cx, Move(buf), "    this.%s = %s%s%s\n", name,
859                              v.isString() ? "\"" : "", value,
860                              v.isString() ? "\"" : "");
861       } else {
862         buf = sprintf_append(
863             cx, Move(buf),
864             "    <Failed to format values while inspecting stack frame>\n");
865       }
866       if (!buf) return nullptr;
867     }
868   }
869 
870   MOZ_ASSERT(!cx->isExceptionPending());
871   return buf;
872 }
873 
FormatWasmFrame(JSContext * cx,const FrameIter & iter,JS::UniqueChars && inBuf,int num)874 static JS::UniqueChars FormatWasmFrame(JSContext* cx, const FrameIter& iter,
875                                        JS::UniqueChars&& inBuf, int num) {
876   JSAtom* functionDisplayAtom = iter.functionDisplayAtom();
877   UniqueChars nameStr;
878   if (functionDisplayAtom)
879     nameStr = StringToNewUTF8CharsZ(cx, *functionDisplayAtom);
880 
881   JS::UniqueChars buf =
882       sprintf_append(cx, Move(inBuf), "%d %s()", num,
883                      nameStr ? nameStr.get() : "<wasm-function>");
884   if (!buf) return nullptr;
885   const char* filename = iter.filename();
886   uint32_t lineno = iter.computeLine();
887   buf = sprintf_append(cx, Move(buf), " [\"%s\":%d]\n",
888                        filename ? filename : "<unknown>", lineno);
889 
890   MOZ_ASSERT(!cx->isExceptionPending());
891   return buf;
892 }
893 
FormatStackDump(JSContext * cx,JS::UniqueChars && inBuf,bool showArgs,bool showLocals,bool showThisProps)894 JS_FRIEND_API JS::UniqueChars JS::FormatStackDump(JSContext* cx,
895                                                   JS::UniqueChars&& inBuf,
896                                                   bool showArgs,
897                                                   bool showLocals,
898                                                   bool showThisProps) {
899   int num = 0;
900 
901   JS::UniqueChars buf(Move(inBuf));
902   for (AllFramesIter i(cx); !i.done(); ++i) {
903     if (i.hasScript())
904       buf = FormatFrame(cx, i, Move(buf), num, showArgs, showLocals,
905                         showThisProps);
906     else
907       buf = FormatWasmFrame(cx, i, Move(buf), num);
908     if (!buf) return nullptr;
909     num++;
910   }
911 
912   if (!num) buf = JS_sprintf_append(Move(buf), "JavaScript stack is empty\n");
913 
914   return buf;
915 }
916 
ForceLexicalInitialization(JSContext * cx,HandleObject obj)917 extern JS_FRIEND_API bool JS::ForceLexicalInitialization(JSContext* cx,
918                                                          HandleObject obj) {
919   AssertHeapIsIdle();
920   CHECK_REQUEST(cx);
921   assertSameCompartment(cx, obj);
922 
923   bool initializedAny = false;
924   NativeObject* nobj = &obj->as<NativeObject>();
925 
926   for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
927     Shape* s = &r.front();
928     Value v = nobj->getSlot(s->slot());
929     if (s->isDataProperty() && v.isMagic() &&
930         v.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
931       nobj->setSlot(s->slot(), UndefinedValue());
932       initializedAny = true;
933     }
934   }
935   return initializedAny;
936 }
937 
IsGCPoisoning()938 extern JS_FRIEND_API int JS::IsGCPoisoning() {
939 #ifdef JS_GC_POISONING
940   static bool disablePoison = bool(getenv("JSGC_DISABLE_POISONING"));
941   return !disablePoison;
942 #else
943   return false;
944 #endif
945 }
946 
947 struct DumpHeapTracer : public JS::CallbackTracer, public WeakMapTracer {
948   const char* prefix;
949   FILE* output;
950 
DumpHeapTracerDumpHeapTracer951   DumpHeapTracer(FILE* fp, JSContext* cx)
952       : JS::CallbackTracer(cx, DoNotTraceWeakMaps),
953         js::WeakMapTracer(cx->runtime()),
954         prefix(""),
955         output(fp) {}
956 
957  private:
traceDumpHeapTracer958   void trace(JSObject* map, JS::GCCellPtr key, JS::GCCellPtr value) override {
959     JSObject* kdelegate = nullptr;
960     if (key.is<JSObject>())
961       kdelegate = js::GetWeakmapKeyDelegate(&key.as<JSObject>());
962 
963     fprintf(output, "WeakMapEntry map=%p key=%p keyDelegate=%p value=%p\n", map,
964             key.asCell(), kdelegate, value.asCell());
965   }
966 
967   void onChild(const JS::GCCellPtr& thing) override;
968 };
969 
MarkDescriptor(void * thing)970 static char MarkDescriptor(void* thing) {
971   gc::TenuredCell* cell = gc::TenuredCell::fromPointer(thing);
972   if (cell->isMarkedBlack()) return 'B';
973   if (cell->isMarkedGray()) return 'G';
974   if (cell->isMarkedAny()) return 'X';
975   return 'W';
976 }
977 
DumpHeapVisitZone(JSRuntime * rt,void * data,Zone * zone)978 static void DumpHeapVisitZone(JSRuntime* rt, void* data, Zone* zone) {
979   DumpHeapTracer* dtrc = static_cast<DumpHeapTracer*>(data);
980   fprintf(dtrc->output, "# zone %p\n", (void*)zone);
981 }
982 
DumpHeapVisitCompartment(JSContext * cx,void * data,JSCompartment * comp)983 static void DumpHeapVisitCompartment(JSContext* cx, void* data,
984                                      JSCompartment* comp) {
985   char name[1024];
986   if (cx->runtime()->compartmentNameCallback)
987     (*cx->runtime()->compartmentNameCallback)(cx, comp, name, sizeof(name));
988   else
989     strcpy(name, "<unknown>");
990 
991   DumpHeapTracer* dtrc = static_cast<DumpHeapTracer*>(data);
992   fprintf(dtrc->output, "# compartment %s [in zone %p]\n", name,
993           (void*)comp->zone());
994 }
995 
DumpHeapVisitArena(JSRuntime * rt,void * data,gc::Arena * arena,JS::TraceKind traceKind,size_t thingSize)996 static void DumpHeapVisitArena(JSRuntime* rt, void* data, gc::Arena* arena,
997                                JS::TraceKind traceKind, size_t thingSize) {
998   DumpHeapTracer* dtrc = static_cast<DumpHeapTracer*>(data);
999   fprintf(dtrc->output, "# arena allockind=%u size=%u\n",
1000           unsigned(arena->getAllocKind()), unsigned(thingSize));
1001 }
1002 
DumpHeapVisitCell(JSRuntime * rt,void * data,void * thing,JS::TraceKind traceKind,size_t thingSize)1003 static void DumpHeapVisitCell(JSRuntime* rt, void* data, void* thing,
1004                               JS::TraceKind traceKind, size_t thingSize) {
1005   DumpHeapTracer* dtrc = static_cast<DumpHeapTracer*>(data);
1006   char cellDesc[1024 * 32];
1007   JS_GetTraceThingInfo(cellDesc, sizeof(cellDesc), dtrc, thing, traceKind,
1008                        true);
1009   fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing), cellDesc);
1010   js::TraceChildren(dtrc, thing, traceKind);
1011 }
1012 
onChild(const JS::GCCellPtr & thing)1013 void DumpHeapTracer::onChild(const JS::GCCellPtr& thing) {
1014   if (gc::IsInsideNursery(thing.asCell())) return;
1015 
1016   char buffer[1024];
1017   getTracingEdgeName(buffer, sizeof(buffer));
1018   fprintf(output, "%s%p %c %s\n", prefix, thing.asCell(),
1019           MarkDescriptor(thing.asCell()), buffer);
1020 }
1021 
DumpHeap(JSContext * cx,FILE * fp,js::DumpHeapNurseryBehaviour nurseryBehaviour)1022 void js::DumpHeap(JSContext* cx, FILE* fp,
1023                   js::DumpHeapNurseryBehaviour nurseryBehaviour) {
1024   if (nurseryBehaviour == js::CollectNurseryBeforeDump)
1025     EvictAllNurseries(cx->runtime(), JS::gcreason::API);
1026 
1027   DumpHeapTracer dtrc(fp, cx);
1028 
1029   fprintf(dtrc.output, "# Roots.\n");
1030   {
1031     JSRuntime* rt = cx->runtime();
1032     js::gc::AutoPrepareForTracing prep(cx);
1033     gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
1034     rt->gc.traceRuntime(&dtrc, prep.session());
1035   }
1036 
1037   fprintf(dtrc.output, "# Weak maps.\n");
1038   WeakMapBase::traceAllMappings(&dtrc);
1039 
1040   fprintf(dtrc.output, "==========\n");
1041 
1042   dtrc.prefix = "> ";
1043   IterateHeapUnbarriered(cx, &dtrc, DumpHeapVisitZone, DumpHeapVisitCompartment,
1044                          DumpHeapVisitArena, DumpHeapVisitCell);
1045 
1046   fflush(dtrc.output);
1047 }
1048 
SetActivityCallback(JSContext * cx,ActivityCallback cb,void * arg)1049 JS_FRIEND_API void js::SetActivityCallback(JSContext* cx, ActivityCallback cb,
1050                                            void* arg) {
1051   cx->activityCallback = cb;
1052   cx->activityCallbackArg = arg;
1053 }
1054 
NotifyGCRootsRemoved(JSContext * cx)1055 JS_FRIEND_API void JS::NotifyGCRootsRemoved(JSContext* cx) {
1056   cx->runtime()->gc.notifyRootsRemoved();
1057 }
1058 
GetAnyCompartmentInZone(JS::Zone * zone)1059 JS_FRIEND_API JSCompartment* js::GetAnyCompartmentInZone(JS::Zone* zone) {
1060   CompartmentsInZoneIter comp(zone);
1061   MOZ_ASSERT(!comp.done());
1062   return comp.get();
1063 }
1064 
finalize(JSRuntime * rt)1065 void JS::ObjectPtr::finalize(JSRuntime* rt) {
1066   if (IsIncrementalBarrierNeeded(rt->activeContextFromOwnThread()))
1067     IncrementalPreWriteBarrier(value);
1068   value = nullptr;
1069 }
1070 
finalize(JSContext * cx)1071 void JS::ObjectPtr::finalize(JSContext* cx) { finalize(cx->runtime()); }
1072 
updateWeakPointerAfterGC()1073 void JS::ObjectPtr::updateWeakPointerAfterGC() {
1074   if (js::gc::IsAboutToBeFinalizedUnbarriered(value.unsafeGet()))
1075     value = nullptr;
1076 }
1077 
trace(JSTracer * trc,const char * name)1078 void JS::ObjectPtr::trace(JSTracer* trc, const char* name) {
1079   JS::TraceEdge(trc, &value, name);
1080 }
1081 
GetTestingFunctions(JSContext * cx)1082 JS_FRIEND_API JSObject* js::GetTestingFunctions(JSContext* cx) {
1083   RootedObject obj(cx, JS_NewPlainObject(cx));
1084   if (!obj) return nullptr;
1085 
1086   if (!DefineTestingFunctions(cx, obj, false, false)) return nullptr;
1087 
1088   return obj;
1089 }
1090 
1091 #ifdef DEBUG
GetEnterCompartmentDepth(JSContext * cx)1092 JS_FRIEND_API unsigned js::GetEnterCompartmentDepth(JSContext* cx) {
1093   return cx->getEnterCompartmentDepth();
1094 }
1095 #endif
1096 
SetDOMCallbacks(JSContext * cx,const DOMCallbacks * callbacks)1097 JS_FRIEND_API void js::SetDOMCallbacks(JSContext* cx,
1098                                        const DOMCallbacks* callbacks) {
1099   cx->runtime()->DOMcallbacks = callbacks;
1100 }
1101 
GetDOMCallbacks(JSContext * cx)1102 JS_FRIEND_API const DOMCallbacks* js::GetDOMCallbacks(JSContext* cx) {
1103   return cx->runtime()->DOMcallbacks;
1104 }
1105 
1106 static const void* gDOMProxyHandlerFamily = nullptr;
1107 static DOMProxyShadowsCheck gDOMProxyShadowsCheck;
1108 
SetDOMProxyInformation(const void * domProxyHandlerFamily,DOMProxyShadowsCheck domProxyShadowsCheck)1109 JS_FRIEND_API void js::SetDOMProxyInformation(
1110     const void* domProxyHandlerFamily,
1111     DOMProxyShadowsCheck domProxyShadowsCheck) {
1112   gDOMProxyHandlerFamily = domProxyHandlerFamily;
1113   gDOMProxyShadowsCheck = domProxyShadowsCheck;
1114 }
1115 
GetDOMProxyHandlerFamily()1116 const void* js::GetDOMProxyHandlerFamily() { return gDOMProxyHandlerFamily; }
1117 
GetDOMProxyShadowsCheck()1118 DOMProxyShadowsCheck js::GetDOMProxyShadowsCheck() {
1119   return gDOMProxyShadowsCheck;
1120 }
1121 
1122 static XrayJitInfo* gXrayJitInfo = nullptr;
1123 
SetXrayJitInfo(XrayJitInfo * info)1124 JS_FRIEND_API void js::SetXrayJitInfo(XrayJitInfo* info) {
1125   gXrayJitInfo = info;
1126 }
1127 
GetXrayJitInfo()1128 XrayJitInfo* js::GetXrayJitInfo() { return gXrayJitInfo; }
1129 
IdMatchesAtom(jsid id,JSAtom * atom)1130 bool js::detail::IdMatchesAtom(jsid id, JSAtom* atom) {
1131   return id == INTERNED_STRING_TO_JSID(nullptr, atom);
1132 }
1133 
IdMatchesAtom(jsid id,JSString * atom)1134 bool js::detail::IdMatchesAtom(jsid id, JSString* atom) {
1135   return id == INTERNED_STRING_TO_JSID(nullptr, atom);
1136 }
1137 
PrepareScriptEnvironmentAndInvoke(JSContext * cx,HandleObject scope,ScriptEnvironmentPreparer::Closure & closure)1138 JS_FRIEND_API void js::PrepareScriptEnvironmentAndInvoke(
1139     JSContext* cx, HandleObject scope,
1140     ScriptEnvironmentPreparer::Closure& closure) {
1141   MOZ_ASSERT(!cx->isExceptionPending());
1142 
1143   MOZ_RELEASE_ASSERT(
1144       cx->runtime()->scriptEnvironmentPreparer,
1145       "Embedding needs to set a scriptEnvironmentPreparer callback");
1146 
1147   cx->runtime()->scriptEnvironmentPreparer->invoke(scope, closure);
1148 }
1149 
SetScriptEnvironmentPreparer(JSContext * cx,ScriptEnvironmentPreparer * preparer)1150 JS_FRIEND_API void js::SetScriptEnvironmentPreparer(
1151     JSContext* cx, ScriptEnvironmentPreparer* preparer) {
1152   cx->runtime()->scriptEnvironmentPreparer = preparer;
1153 }
1154 
SetCTypesActivityCallback(JSContext * cx,CTypesActivityCallback cb)1155 JS_FRIEND_API void js::SetCTypesActivityCallback(JSContext* cx,
1156                                                  CTypesActivityCallback cb) {
1157   cx->runtime()->ctypesActivityCallback = cb;
1158 }
1159 
AutoCTypesActivityCallback(JSContext * cx,js::CTypesActivityType beginType,js::CTypesActivityType endType MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)1160 js::AutoCTypesActivityCallback::AutoCTypesActivityCallback(
1161     JSContext* cx, js::CTypesActivityType beginType,
1162     js::CTypesActivityType endType MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
1163     : cx(cx),
1164       callback(cx->runtime()->ctypesActivityCallback),
1165       endType(endType) {
1166   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1167 
1168   if (callback) callback(cx, beginType);
1169 }
1170 
SetAllocationMetadataBuilder(JSContext * cx,const AllocationMetadataBuilder * callback)1171 JS_FRIEND_API void js::SetAllocationMetadataBuilder(
1172     JSContext* cx, const AllocationMetadataBuilder* callback) {
1173   cx->compartment()->setAllocationMetadataBuilder(callback);
1174 }
1175 
GetAllocationMetadata(JSObject * obj)1176 JS_FRIEND_API JSObject* js::GetAllocationMetadata(JSObject* obj) {
1177   ObjectWeakMap* map = obj->compartment()->objectMetadataTable;
1178   if (map) return map->lookup(obj);
1179   return nullptr;
1180 }
1181 
ReportIsNotFunction(JSContext * cx,HandleValue v)1182 JS_FRIEND_API bool js::ReportIsNotFunction(JSContext* cx, HandleValue v) {
1183   assertSameCompartment(cx, v);
1184   return ReportIsNotFunction(cx, v, -1);
1185 }
1186 
1187 #ifdef DEBUG
HasObjectMovedOp(JSObject * obj)1188 bool js::HasObjectMovedOp(JSObject* obj) {
1189   return !!GetObjectClass(obj)->extObjectMovedOp();
1190 }
1191 #endif
1192 
ForwardToNative(JSContext * cx,JSNative native,const CallArgs & args)1193 JS_FRIEND_API bool js::ForwardToNative(JSContext* cx, JSNative native,
1194                                        const CallArgs& args) {
1195   return native(cx, args.length(), args.base());
1196 }
1197 
ConvertArgsToArray(JSContext * cx,const CallArgs & args)1198 JS_FRIEND_API JSObject* js::ConvertArgsToArray(JSContext* cx,
1199                                                const CallArgs& args) {
1200   RootedObject argsArray(cx,
1201                          NewDenseCopiedArray(cx, args.length(), args.array()));
1202   return argsArray;
1203 }
1204 
GetPropertyNameFromPC(JSScript * script,jsbytecode * pc)1205 JS_FRIEND_API JSAtom* js::GetPropertyNameFromPC(JSScript* script,
1206                                                 jsbytecode* pc) {
1207   if (!IsGetPropPC(pc) && !IsSetPropPC(pc)) return nullptr;
1208   return script->getName(pc);
1209 }
1210 
SetWindowProxyClass(JSContext * cx,const js::Class * clasp)1211 JS_FRIEND_API void js::SetWindowProxyClass(JSContext* cx,
1212                                            const js::Class* clasp) {
1213   MOZ_ASSERT(!cx->runtime()->maybeWindowProxyClass());
1214   cx->runtime()->setWindowProxyClass(clasp);
1215 }
1216 
SetWindowProxy(JSContext * cx,HandleObject global,HandleObject windowProxy)1217 JS_FRIEND_API void js::SetWindowProxy(JSContext* cx, HandleObject global,
1218                                       HandleObject windowProxy) {
1219   AssertHeapIsIdle();
1220   CHECK_REQUEST(cx);
1221 
1222   assertSameCompartment(cx, global, windowProxy);
1223 
1224   MOZ_ASSERT(IsWindowProxy(windowProxy));
1225   global->as<GlobalObject>().setWindowProxy(windowProxy);
1226 }
1227 
ToWindowIfWindowProxy(JSObject * obj)1228 JS_FRIEND_API JSObject* js::ToWindowIfWindowProxy(JSObject* obj) {
1229   if (IsWindowProxy(obj)) return &obj->global();
1230   return obj;
1231 }
1232 
ToWindowProxyIfWindowSlow(JSObject * obj)1233 JS_FRIEND_API JSObject* js::detail::ToWindowProxyIfWindowSlow(JSObject* obj) {
1234   if (JSObject* windowProxy = obj->as<GlobalObject>().maybeWindowProxy())
1235     return windowProxy;
1236   return obj;
1237 }
1238 
IsWindowProxy(JSObject * obj)1239 JS_FRIEND_API bool js::IsWindowProxy(JSObject* obj) {
1240   // Note: simply checking `obj == obj->global().windowProxy()` is not
1241   // sufficient: we may have transplanted the window proxy with a CCW.
1242   // Check the Class to ensure we really have a window proxy.
1243   return obj->getClass() ==
1244          obj->runtimeFromAnyThread()->maybeWindowProxyClass();
1245 }
1246 
IsWindowSlow(JSObject * obj)1247 JS_FRIEND_API bool js::detail::IsWindowSlow(JSObject* obj) {
1248   return obj->as<GlobalObject>().maybeWindowProxy();
1249 }
1250 
AutoAssertNoContentJS(JSContext * cx)1251 AutoAssertNoContentJS::AutoAssertNoContentJS(JSContext* cx)
1252     : context_(cx), prevAllowContentJS_(cx->runtime()->allowContentJS_) {
1253   cx->runtime()->allowContentJS_ = false;
1254 }
1255 
~AutoAssertNoContentJS()1256 AutoAssertNoContentJS::~AutoAssertNoContentJS() {
1257   context_->runtime()->allowContentJS_ = prevAllowContentJS_;
1258 }
1259 
EnableAccessValidation(JSContext * cx,bool enabled)1260 JS_FRIEND_API void js::EnableAccessValidation(JSContext* cx, bool enabled) {
1261   cx->enableAccessValidation = enabled;
1262 }
1263 
SetCompartmentValidAccessPtr(JSContext * cx,JS::HandleObject global,bool * accessp)1264 JS_FRIEND_API void js::SetCompartmentValidAccessPtr(JSContext* cx,
1265                                                     JS::HandleObject global,
1266                                                     bool* accessp) {
1267   global->compartment()->setValidAccessPtr(accessp);
1268 }
1269 
SetCooperativeYieldCallback(JSContext * cx,YieldCallback callback)1270 JS_FRIEND_API void js::SetCooperativeYieldCallback(JSContext* cx,
1271                                                    YieldCallback callback) {
1272   cx->setYieldCallback(callback);
1273 }
1274 
SystemZoneAvailable(JSContext * cx)1275 JS_FRIEND_API bool js::SystemZoneAvailable(JSContext* cx) {
1276   CooperatingContext& owner = cx->runtime()->gc.systemZoneGroup->ownerContext();
1277   return owner.context() == nullptr;
1278 }
1279