1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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/Atomics.h"
10 #include "mozilla/Maybe.h"
11 #include "mozilla/PodOperations.h"
12 #include "mozilla/TimeStamp.h"
13 
14 #include <stdint.h>
15 
16 #include "builtin/BigInt.h"
17 #include "builtin/MapObject.h"
18 #include "builtin/TestingFunctions.h"
19 #include "gc/GC.h"
20 #include "gc/PublicIterators.h"
21 #include "gc/WeakMap.h"
22 #include "js/CharacterEncoding.h"
23 #include "js/experimental/CodeCoverage.h"  // js::EnableCodeCoverage
24 #include "js/Printf.h"
25 #include "js/Proxy.h"
26 #include "js/Wrapper.h"
27 #include "proxy/DeadObjectProxy.h"
28 #include "util/Poison.h"
29 #include "vm/ArgumentsObject.h"
30 #include "vm/DateObject.h"
31 #include "vm/ErrorObject.h"
32 #include "vm/FrameIter.h"  // js::FrameIter
33 #include "vm/JSContext.h"
34 #include "vm/JSObject.h"
35 #include "vm/PlainObject.h"  // js::PlainObject
36 #include "vm/Printer.h"
37 #include "vm/PromiseObject.h"  // js::PromiseObject
38 #include "vm/Realm.h"
39 #include "vm/Time.h"
40 #include "vm/WrapperObject.h"
41 
42 #include "gc/Nursery-inl.h"
43 #include "vm/Compartment-inl.h"  // JS::Compartment::wrap
44 #include "vm/EnvironmentObject-inl.h"
45 #include "vm/JSObject-inl.h"
46 #include "vm/JSScript-inl.h"
47 #include "vm/NativeObject-inl.h"
48 
49 using namespace js;
50 
51 using mozilla::PodArrayZero;
52 
RootingContext()53 JS::RootingContext::RootingContext() : realm_(nullptr), zone_(nullptr) {
54   for (auto& listHead : stackRoots_) {
55     listHead = nullptr;
56   }
57   for (auto& listHead : autoGCRooters_) {
58     listHead = nullptr;
59   }
60 
61   PodArrayZero(nativeStackLimit);
62 #if JS_STACK_GROWTH_DIRECTION > 0
63   for (int i = 0; i < StackKindCount; i++) {
64     nativeStackLimit[i] = UINTPTR_MAX;
65   }
66 #endif
67 }
68 
JS_SetGrayGCRootsTracer(JSContext * cx,JSTraceDataOp traceOp,void * data)69 JS_FRIEND_API void JS_SetGrayGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp,
70                                            void* data) {
71   cx->runtime()->gc.setGrayRootsTracer(traceOp, data);
72 }
73 
JS_FindCompilationScope(JSContext * cx,HandleObject objArg)74 JS_FRIEND_API JSObject* JS_FindCompilationScope(JSContext* cx,
75                                                 HandleObject objArg) {
76   cx->check(objArg);
77 
78   RootedObject obj(cx, objArg);
79 
80   /*
81    * We unwrap wrappers here. This is a little weird, but it's what's being
82    * asked of us.
83    */
84   if (obj->is<WrapperObject>()) {
85     obj = UncheckedUnwrap(obj);
86   }
87 
88   /*
89    * Get the Window if `obj` is a WindowProxy so that we compile in the
90    * correct (global) scope.
91    */
92   return ToWindowIfWindowProxy(obj);
93 }
94 
JS_GetObjectFunction(JSObject * obj)95 JS_FRIEND_API JSFunction* JS_GetObjectFunction(JSObject* obj) {
96   if (obj->is<JSFunction>()) {
97     return &obj->as<JSFunction>();
98   }
99   return nullptr;
100 }
101 
JS_SplicePrototype(JSContext * cx,HandleObject obj,HandleObject proto)102 JS_FRIEND_API bool JS_SplicePrototype(JSContext* cx, HandleObject obj,
103                                       HandleObject proto) {
104   /*
105    * Change the prototype of an object which hasn't been used anywhere
106    * and does not share its type with another object. Unlike JS_SetPrototype,
107    * does not nuke type information for the object.
108    */
109   CHECK_THREAD(cx);
110   cx->check(obj, proto);
111 
112   if (!obj->isSingleton()) {
113     /*
114      * We can see non-singleton objects when trying to splice prototypes
115      * due to mutable __proto__ (ugh).
116      */
117     return JS_SetPrototype(cx, obj, proto);
118   }
119 
120   Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
121   return JSObject::splicePrototype(cx, obj, tagged);
122 }
123 
JS_NewObjectWithUniqueType(JSContext * cx,const JSClass * clasp,HandleObject proto)124 JS_FRIEND_API JSObject* JS_NewObjectWithUniqueType(JSContext* cx,
125                                                    const JSClass* clasp,
126                                                    HandleObject proto) {
127   /*
128    * Create our object with a null proto and then splice in the correct proto
129    * after we setSingleton, so that we don't pollute the default
130    * ObjectGroup attached to our proto with information about our object, since
131    * we're not going to be using that ObjectGroup anyway.
132    */
133   RootedObject obj(cx, NewSingletonObjectWithGivenProto(cx, clasp, nullptr));
134   if (!obj) {
135     return nullptr;
136   }
137   if (!JS_SplicePrototype(cx, obj, proto)) {
138     return nullptr;
139   }
140   return obj;
141 }
142 
JS_NewObjectWithoutMetadata(JSContext * cx,const JSClass * clasp,JS::Handle<JSObject * > proto)143 JS_FRIEND_API JSObject* JS_NewObjectWithoutMetadata(
144     JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto) {
145   cx->check(proto);
146   AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
147   return JS_NewObjectWithGivenProto(cx, clasp, proto);
148 }
149 
GetIsSecureContext(JS::Realm * realm)150 JS_FRIEND_API bool JS::GetIsSecureContext(JS::Realm* realm) {
151   return realm->creationOptions().secureContext();
152 }
153 
AssertCompartmentHasSingleRealm(JS::Compartment * comp)154 JS_FRIEND_API void js::AssertCompartmentHasSingleRealm(JS::Compartment* comp) {
155   MOZ_RELEASE_ASSERT(comp->realms().length() == 1);
156 }
157 
GetRealmPrincipals(JS::Realm * realm)158 JS_FRIEND_API JSPrincipals* JS::GetRealmPrincipals(JS::Realm* realm) {
159   return realm->principals();
160 }
161 
SetRealmPrincipals(JS::Realm * realm,JSPrincipals * principals)162 JS_FRIEND_API void JS::SetRealmPrincipals(JS::Realm* realm,
163                                           JSPrincipals* principals) {
164   // Short circuit if there's no change.
165   if (principals == realm->principals()) {
166     return;
167   }
168 
169   // We'd like to assert that our new principals is always same-origin
170   // with the old one, but JSPrincipals doesn't give us a way to do that.
171   // But we can at least assert that we're not switching between system
172   // and non-system.
173   const JSPrincipals* trusted =
174       realm->runtimeFromMainThread()->trustedPrincipals();
175   bool isSystem = principals && principals == trusted;
176   MOZ_RELEASE_ASSERT(realm->isSystem() == isSystem);
177 
178   // Clear out the old principals, if any.
179   if (realm->principals()) {
180     JS_DropPrincipals(TlsContext.get(), realm->principals());
181     realm->setPrincipals(nullptr);
182   }
183 
184   // Set up the new principals.
185   if (principals) {
186     JS_HoldPrincipals(principals);
187     realm->setPrincipals(principals);
188   }
189 }
190 
JS_GetScriptPrincipals(JSScript * script)191 JS_FRIEND_API JSPrincipals* JS_GetScriptPrincipals(JSScript* script) {
192   return script->principals();
193 }
194 
GetScriptRealm(JSScript * script)195 JS_FRIEND_API JS::Realm* js::GetScriptRealm(JSScript* script) {
196   return script->realm();
197 }
198 
JS_ScriptHasMutedErrors(JSScript * script)199 JS_FRIEND_API bool JS_ScriptHasMutedErrors(JSScript* script) {
200   return script->mutedErrors();
201 }
202 
JS_WrapPropertyDescriptor(JSContext * cx,JS::MutableHandle<JS::PropertyDescriptor> desc)203 JS_FRIEND_API bool JS_WrapPropertyDescriptor(
204     JSContext* cx, JS::MutableHandle<JS::PropertyDescriptor> desc) {
205   return cx->compartment()->wrap(cx, desc);
206 }
207 
JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer * trc,JS::GCCellPtr shape)208 JS_FRIEND_API void JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc,
209                                                        JS::GCCellPtr shape) {
210   MOZ_ASSERT(shape.is<Shape>());
211   TraceCycleCollectorChildren(trc, &shape.as<Shape>());
212 }
213 
JS_TraceObjectGroupCycleCollectorChildren(JS::CallbackTracer * trc,JS::GCCellPtr group)214 JS_FRIEND_API void JS_TraceObjectGroupCycleCollectorChildren(
215     JS::CallbackTracer* trc, JS::GCCellPtr group) {
216   MOZ_ASSERT(group.is<ObjectGroup>());
217   TraceCycleCollectorChildren(trc, &group.as<ObjectGroup>());
218 }
219 
DefineHelpProperty(JSContext * cx,HandleObject obj,const char * prop,const char * value)220 static bool DefineHelpProperty(JSContext* cx, HandleObject obj,
221                                const char* prop, const char* value) {
222   RootedAtom atom(cx, Atomize(cx, value, strlen(value)));
223   if (!atom) {
224     return false;
225   }
226   return JS_DefineProperty(cx, obj, prop, atom,
227                            JSPROP_READONLY | JSPROP_PERMANENT);
228 }
229 
JS_DefineFunctionsWithHelp(JSContext * cx,HandleObject obj,const JSFunctionSpecWithHelp * fs)230 JS_FRIEND_API bool JS_DefineFunctionsWithHelp(
231     JSContext* cx, HandleObject obj, const JSFunctionSpecWithHelp* fs) {
232   MOZ_ASSERT(!cx->zone()->isAtomsZone());
233 
234   CHECK_THREAD(cx);
235   cx->check(obj);
236   for (; fs->name; fs++) {
237     JSAtom* atom = Atomize(cx, fs->name, strlen(fs->name));
238     if (!atom) {
239       return false;
240     }
241 
242     Rooted<jsid> id(cx, AtomToId(atom));
243     RootedFunction fun(cx, DefineFunction(cx, obj, id, fs->call, fs->nargs,
244                                           fs->flags | JSPROP_RESOLVING));
245     if (!fun) {
246       return false;
247     }
248 
249     if (fs->jitInfo) {
250       fun->setJitInfo(fs->jitInfo);
251     }
252 
253     if (fs->usage) {
254       if (!DefineHelpProperty(cx, fun, "usage", fs->usage)) {
255         return false;
256       }
257     }
258 
259     if (fs->help) {
260       if (!DefineHelpProperty(cx, fun, "help", fs->help)) {
261         return false;
262       }
263     }
264   }
265 
266   return true;
267 }
268 
GetBuiltinClass(JSContext * cx,HandleObject obj,ESClass * cls)269 JS_FRIEND_API bool js::GetBuiltinClass(JSContext* cx, HandleObject obj,
270                                        ESClass* cls) {
271   if (MOZ_UNLIKELY(obj->is<ProxyObject>())) {
272     return Proxy::getBuiltinClass(cx, obj, cls);
273   }
274 
275   if (obj->is<PlainObject>()) {
276     *cls = ESClass::Object;
277   } else if (obj->is<ArrayObject>()) {
278     *cls = ESClass::Array;
279   } else if (obj->is<NumberObject>()) {
280     *cls = ESClass::Number;
281   } else if (obj->is<StringObject>()) {
282     *cls = ESClass::String;
283   } else if (obj->is<BooleanObject>()) {
284     *cls = ESClass::Boolean;
285   } else if (obj->is<RegExpObject>()) {
286     *cls = ESClass::RegExp;
287   } else if (obj->is<ArrayBufferObject>()) {
288     *cls = ESClass::ArrayBuffer;
289   } else if (obj->is<SharedArrayBufferObject>()) {
290     *cls = ESClass::SharedArrayBuffer;
291   } else if (obj->is<DateObject>()) {
292     *cls = ESClass::Date;
293   } else if (obj->is<SetObject>()) {
294     *cls = ESClass::Set;
295   } else if (obj->is<MapObject>()) {
296     *cls = ESClass::Map;
297   } else if (obj->is<PromiseObject>()) {
298     *cls = ESClass::Promise;
299   } else if (obj->is<MapIteratorObject>()) {
300     *cls = ESClass::MapIterator;
301   } else if (obj->is<SetIteratorObject>()) {
302     *cls = ESClass::SetIterator;
303   } else if (obj->is<ArgumentsObject>()) {
304     *cls = ESClass::Arguments;
305   } else if (obj->is<ErrorObject>()) {
306     *cls = ESClass::Error;
307   } else if (obj->is<BigIntObject>()) {
308     *cls = ESClass::BigInt;
309   } else if (obj->is<JSFunction>()) {
310     *cls = ESClass::Function;
311   } else {
312     *cls = ESClass::Other;
313   }
314 
315   return true;
316 }
317 
IsArgumentsObject(HandleObject obj)318 JS_FRIEND_API bool js::IsArgumentsObject(HandleObject obj) {
319   return obj->is<ArgumentsObject>();
320 }
321 
ObjectClassName(JSContext * cx,HandleObject obj)322 JS_FRIEND_API const char* js::ObjectClassName(JSContext* cx, HandleObject obj) {
323   cx->check(obj);
324   return GetObjectClassName(cx, obj);
325 }
326 
GetRealmZone(JS::Realm * realm)327 JS_FRIEND_API JS::Zone* js::GetRealmZone(JS::Realm* realm) {
328   return realm->zone();
329 }
330 
IsSystemCompartment(JS::Compartment * comp)331 JS_FRIEND_API bool js::IsSystemCompartment(JS::Compartment* comp) {
332   // Realms in the same compartment must either all be system realms or
333   // non-system realms. We assert this in NewRealm and SetRealmPrincipals,
334   // but do an extra sanity check here.
335   MOZ_ASSERT(comp->realms()[0]->isSystem() ==
336              comp->realms().back()->isSystem());
337   return comp->realms()[0]->isSystem();
338 }
339 
IsSystemRealm(JS::Realm * realm)340 JS_FRIEND_API bool js::IsSystemRealm(JS::Realm* realm) {
341   return realm->isSystem();
342 }
343 
IsSystemZone(Zone * zone)344 JS_FRIEND_API bool js::IsSystemZone(Zone* zone) { return zone->isSystemZone(); }
345 
IsAtomsZone(JS::Zone * zone)346 JS_FRIEND_API bool js::IsAtomsZone(JS::Zone* zone) {
347   return zone->isAtomsZone();
348 }
349 
IsFunctionObject(JSObject * obj)350 JS_FRIEND_API bool js::IsFunctionObject(JSObject* obj) {
351   return obj->is<JSFunction>();
352 }
353 
IsSavedFrame(JSObject * obj)354 JS_FRIEND_API bool js::IsSavedFrame(JSObject* obj) {
355   return obj->is<SavedFrame>();
356 }
357 
UninlinedIsCrossCompartmentWrapper(const JSObject * obj)358 JS_FRIEND_API bool js::UninlinedIsCrossCompartmentWrapper(const JSObject* obj) {
359   return js::IsCrossCompartmentWrapper(obj);
360 }
361 
GetPrototypeNoProxy(JSObject * obj)362 JS_FRIEND_API JSObject* js::GetPrototypeNoProxy(JSObject* obj) {
363   MOZ_ASSERT(!obj->is<js::ProxyObject>());
364   return obj->staticPrototype();
365 }
366 
AssertSameCompartment(JSContext * cx,JSObject * obj)367 JS_FRIEND_API void js::AssertSameCompartment(JSContext* cx, JSObject* obj) {
368   cx->check(obj);
369 }
370 
AssertSameCompartment(JSContext * cx,JS::HandleValue v)371 JS_FRIEND_API void js::AssertSameCompartment(JSContext* cx, JS::HandleValue v) {
372   cx->check(v);
373 }
374 
375 #ifdef DEBUG
AssertSameCompartment(JSObject * objA,JSObject * objB)376 JS_FRIEND_API void js::AssertSameCompartment(JSObject* objA, JSObject* objB) {
377   MOZ_ASSERT(objA->compartment() == objB->compartment());
378 }
379 #endif
380 
NotifyAnimationActivity(JSObject * obj)381 JS_FRIEND_API void js::NotifyAnimationActivity(JSObject* obj) {
382   MOZ_ASSERT(obj->is<GlobalObject>());
383 
384   auto timeNow = mozilla::TimeStamp::Now();
385   obj->as<GlobalObject>().realm()->lastAnimationTime = timeNow;
386   obj->runtimeFromMainThread()->lastAnimationTime = timeNow;
387 }
388 
GetObjectSlotSpan(JSObject * obj)389 JS_FRIEND_API uint32_t js::GetObjectSlotSpan(JSObject* obj) {
390   return obj->as<NativeObject>().slotSpan();
391 }
392 
IsObjectInContextCompartment(JSObject * obj,const JSContext * cx)393 JS_FRIEND_API bool js::IsObjectInContextCompartment(JSObject* obj,
394                                                     const JSContext* cx) {
395   return obj->compartment() == cx->compartment();
396 }
397 
RunningWithTrustedPrincipals(JSContext * cx)398 JS_FRIEND_API bool js::RunningWithTrustedPrincipals(JSContext* cx) {
399   return cx->runningWithTrustedPrincipals();
400 }
401 
DefineFunctionWithReserved(JSContext * cx,JSObject * objArg,const char * name,JSNative call,unsigned nargs,unsigned attrs)402 JS_FRIEND_API JSFunction* js::DefineFunctionWithReserved(
403     JSContext* cx, JSObject* objArg, const char* name, JSNative call,
404     unsigned nargs, unsigned attrs) {
405   RootedObject obj(cx, objArg);
406   MOZ_ASSERT(!cx->zone()->isAtomsZone());
407   CHECK_THREAD(cx);
408   cx->check(obj);
409   JSAtom* atom = Atomize(cx, name, strlen(name));
410   if (!atom) {
411     return nullptr;
412   }
413   Rooted<jsid> id(cx, AtomToId(atom));
414   return DefineFunction(cx, obj, id, call, nargs, attrs,
415                         gc::AllocKind::FUNCTION_EXTENDED);
416 }
417 
NewFunctionWithReserved(JSContext * cx,JSNative native,unsigned nargs,unsigned flags,const char * name)418 JS_FRIEND_API JSFunction* js::NewFunctionWithReserved(JSContext* cx,
419                                                       JSNative native,
420                                                       unsigned nargs,
421                                                       unsigned flags,
422                                                       const char* name) {
423   MOZ_ASSERT(!cx->zone()->isAtomsZone());
424 
425   CHECK_THREAD(cx);
426 
427   RootedAtom atom(cx);
428   if (name) {
429     atom = Atomize(cx, name, strlen(name));
430     if (!atom) {
431       return nullptr;
432     }
433   }
434 
435   return (flags & JSFUN_CONSTRUCTOR)
436              ? NewNativeConstructor(cx, native, nargs, atom,
437                                     gc::AllocKind::FUNCTION_EXTENDED)
438              : NewNativeFunction(cx, native, nargs, atom,
439                                  gc::AllocKind::FUNCTION_EXTENDED);
440 }
441 
NewFunctionByIdWithReserved(JSContext * cx,JSNative native,unsigned nargs,unsigned flags,jsid id)442 JS_FRIEND_API JSFunction* js::NewFunctionByIdWithReserved(
443     JSContext* cx, JSNative native, unsigned nargs, unsigned flags, jsid id) {
444   MOZ_ASSERT(JSID_IS_STRING(id));
445   MOZ_ASSERT(!cx->zone()->isAtomsZone());
446   CHECK_THREAD(cx);
447   cx->check(id);
448 
449   RootedAtom atom(cx, JSID_TO_ATOM(id));
450   return (flags & JSFUN_CONSTRUCTOR)
451              ? NewNativeConstructor(cx, native, nargs, atom,
452                                     gc::AllocKind::FUNCTION_EXTENDED)
453              : NewNativeFunction(cx, native, nargs, atom,
454                                  gc::AllocKind::FUNCTION_EXTENDED);
455 }
456 
GetFunctionNativeReserved(JSObject * fun,size_t which)457 JS_FRIEND_API const Value& js::GetFunctionNativeReserved(JSObject* fun,
458                                                          size_t which) {
459   MOZ_ASSERT(fun->as<JSFunction>().isNative());
460   return fun->as<JSFunction>().getExtendedSlot(which);
461 }
462 
SetFunctionNativeReserved(JSObject * fun,size_t which,const Value & val)463 JS_FRIEND_API void js::SetFunctionNativeReserved(JSObject* fun, size_t which,
464                                                  const Value& val) {
465   MOZ_ASSERT(fun->as<JSFunction>().isNative());
466   MOZ_ASSERT_IF(val.isObject(),
467                 val.toObject().compartment() == fun->compartment());
468   fun->as<JSFunction>().setExtendedSlot(which, val);
469 }
470 
FunctionHasNativeReserved(JSObject * fun)471 JS_FRIEND_API bool js::FunctionHasNativeReserved(JSObject* fun) {
472   MOZ_ASSERT(fun->as<JSFunction>().isNative());
473   return fun->as<JSFunction>().isExtended();
474 }
475 
GetObjectProto(JSContext * cx,JS::Handle<JSObject * > obj,JS::MutableHandle<JSObject * > proto)476 JS_FRIEND_API bool js::GetObjectProto(JSContext* cx, JS::Handle<JSObject*> obj,
477                                       JS::MutableHandle<JSObject*> proto) {
478   cx->check(obj);
479 
480   if (IsProxy(obj)) {
481     return JS_GetPrototype(cx, obj, proto);
482   }
483 
484   proto.set(reinterpret_cast<const shadow::Object*>(obj.get())->group->proto);
485   return true;
486 }
487 
GetStaticPrototype(JSObject * obj)488 JS_FRIEND_API JSObject* js::GetStaticPrototype(JSObject* obj) {
489   MOZ_ASSERT(obj->hasStaticPrototype());
490   return obj->staticPrototype();
491 }
492 
GetRealmOriginalEval(JSContext * cx,MutableHandleObject eval)493 JS_FRIEND_API bool js::GetRealmOriginalEval(JSContext* cx,
494                                             MutableHandleObject eval) {
495   return GlobalObject::getOrCreateEval(cx, cx->global(), eval);
496 }
497 
SetReservedSlotWithBarrier(JSObject * obj,size_t slot,const js::Value & value)498 JS_FRIEND_API void js::SetReservedSlotWithBarrier(JSObject* obj, size_t slot,
499                                                   const js::Value& value) {
500   if (IsProxy(obj)) {
501     obj->as<ProxyObject>().setReservedSlot(slot, value);
502   } else {
503     obj->as<NativeObject>().setSlot(slot, value);
504   }
505 }
506 
SetPreserveWrapperCallback(JSContext * cx,PreserveWrapperCallback callback)507 void js::SetPreserveWrapperCallback(JSContext* cx,
508                                     PreserveWrapperCallback callback) {
509   cx->runtime()->preserveWrapperCallback = callback;
510 }
511 
JS_PCToLineNumber(JSScript * script,jsbytecode * pc,unsigned * columnp)512 JS_FRIEND_API unsigned JS_PCToLineNumber(JSScript* script, jsbytecode* pc,
513                                          unsigned* columnp) {
514   return PCToLineNumber(script, pc, columnp);
515 }
516 
JS_IsDeadWrapper(JSObject * obj)517 JS_FRIEND_API bool JS_IsDeadWrapper(JSObject* obj) {
518   return IsDeadProxyObject(obj);
519 }
520 
JS_NewDeadWrapper(JSContext * cx,JSObject * origObj)521 JS_FRIEND_API JSObject* JS_NewDeadWrapper(JSContext* cx, JSObject* origObj) {
522   return NewDeadProxyObject(cx, origObj);
523 }
524 
TraceWeakMaps(WeakMapTracer * trc)525 void js::TraceWeakMaps(WeakMapTracer* trc) {
526   WeakMapBase::traceAllMappings(trc);
527 }
528 
AreGCGrayBitsValid(JSRuntime * rt)529 extern JS_FRIEND_API bool js::AreGCGrayBitsValid(JSRuntime* rt) {
530   return rt->gc.areGrayBitsValid();
531 }
532 
ZoneGlobalsAreAllGray(JS::Zone * zone)533 JS_FRIEND_API bool js::ZoneGlobalsAreAllGray(JS::Zone* zone) {
534   for (RealmsInZoneIter realm(zone); !realm.done(); realm.next()) {
535     JSObject* obj = realm->unsafeUnbarrieredMaybeGlobal();
536     if (!obj || !JS::ObjectIsMarkedGray(obj)) {
537       return false;
538     }
539   }
540   return true;
541 }
542 
IsCompartmentZoneSweepingOrCompacting(JS::Compartment * comp)543 JS_FRIEND_API bool js::IsCompartmentZoneSweepingOrCompacting(
544     JS::Compartment* comp) {
545   MOZ_ASSERT(comp);
546   return comp->zone()->isGCSweepingOrCompacting();
547 }
548 
VisitGrayWrapperTargets(Zone * zone,GCThingCallback callback,void * closure)549 JS_FRIEND_API void js::VisitGrayWrapperTargets(Zone* zone,
550                                                GCThingCallback callback,
551                                                void* closure) {
552   for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
553     for (Compartment::ObjectWrapperEnum e(comp); !e.empty(); e.popFront()) {
554       JSObject* target = e.front().key();
555       if (target->isMarkedGray()) {
556         JS::AutoSuppressGCAnalysis nogc;
557         callback(closure, JS::GCCellPtr(target));
558       }
559     }
560   }
561 }
562 
StringToLinearStringSlow(JSContext * cx,JSString * str)563 JS_FRIEND_API JSLinearString* js::StringToLinearStringSlow(JSContext* cx,
564                                                            JSString* str) {
565   return str->ensureLinear(cx);
566 }
567 
JS_SetAccumulateTelemetryCallback(JSContext * cx,JSAccumulateTelemetryDataCallback callback)568 JS_FRIEND_API void JS_SetAccumulateTelemetryCallback(
569     JSContext* cx, JSAccumulateTelemetryDataCallback callback) {
570   cx->runtime()->setTelemetryCallback(cx->runtime(), callback);
571 }
572 
JS_SetSetUseCounterCallback(JSContext * cx,JSSetUseCounterCallback callback)573 JS_FRIEND_API void JS_SetSetUseCounterCallback(
574     JSContext* cx, JSSetUseCounterCallback callback) {
575   cx->runtime()->setUseCounterCallback(cx->runtime(), callback);
576 }
577 
CopyProxyObject(JSContext * cx,Handle<ProxyObject * > from,Handle<ProxyObject * > to)578 static bool CopyProxyObject(JSContext* cx, Handle<ProxyObject*> from,
579                             Handle<ProxyObject*> to) {
580   MOZ_ASSERT(from->getClass() == to->getClass());
581 
582   if (from->is<WrapperObject>() &&
583       (Wrapper::wrapperHandler(from)->flags() & Wrapper::CROSS_COMPARTMENT)) {
584     to->setCrossCompartmentPrivate(GetProxyPrivate(from));
585   } else {
586     RootedValue v(cx, GetProxyPrivate(from));
587     if (!cx->compartment()->wrap(cx, &v)) {
588       return false;
589     }
590     to->setSameCompartmentPrivate(v);
591   }
592 
593   MOZ_ASSERT(from->numReservedSlots() == to->numReservedSlots());
594 
595   RootedValue v(cx);
596   for (size_t n = 0; n < from->numReservedSlots(); n++) {
597     v = GetProxyReservedSlot(from, n);
598     if (!cx->compartment()->wrap(cx, &v)) {
599       return false;
600     }
601     SetProxyReservedSlot(to, n, v);
602   }
603 
604   return true;
605 }
606 
JS_CloneObject(JSContext * cx,HandleObject obj,HandleObject proto)607 JS_FRIEND_API JSObject* JS_CloneObject(JSContext* cx, HandleObject obj,
608                                        HandleObject proto) {
609   // |obj| might be in a different compartment.
610   cx->check(proto);
611 
612   if (!obj->isNative() && !obj->is<ProxyObject>()) {
613     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
614                               JSMSG_CANT_CLONE_OBJECT);
615     return nullptr;
616   }
617 
618   RootedObject clone(cx);
619   if (obj->isNative()) {
620     // JS_CloneObject is used to create the target object for JSObject::swap().
621     // swap() requires its arguments are tenured, so ensure tenure allocation.
622     clone = NewTenuredObjectWithGivenProto(cx, obj->getClass(), proto);
623     if (!clone) {
624       return nullptr;
625     }
626 
627     if (clone->is<JSFunction>() &&
628         (obj->compartment() != clone->compartment())) {
629       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
630                                 JSMSG_CANT_CLONE_OBJECT);
631       return nullptr;
632     }
633 
634     if (obj->as<NativeObject>().hasPrivate()) {
635       clone->as<NativeObject>().setPrivate(
636           obj->as<NativeObject>().getPrivate());
637     }
638   } else {
639     auto* handler = GetProxyHandler(obj);
640 
641     // Same as above, require tenure allocation of the clone. This means for
642     // proxy objects we need to reject nursery allocatable proxies.
643     if (handler->canNurseryAllocate()) {
644       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
645                                 JSMSG_CANT_CLONE_OBJECT);
646       return nullptr;
647     }
648 
649     clone = ProxyObject::New(cx, handler, JS::NullHandleValue,
650                              AsTaggedProto(proto), obj->getClass());
651     if (!clone) {
652       return nullptr;
653     }
654 
655     if (!CopyProxyObject(cx, obj.as<ProxyObject>(), clone.as<ProxyObject>())) {
656       return nullptr;
657     }
658   }
659 
660   return clone;
661 }
662 
663 // We don't want jsfriendapi.h to depend on GenericPrinter,
664 // so these functions are declared directly in the cpp.
665 
666 namespace js {
667 
668 extern JS_FRIEND_API void DumpString(JSString* str, js::GenericPrinter& out);
669 
670 extern JS_FRIEND_API void DumpAtom(JSAtom* atom, js::GenericPrinter& out);
671 
672 extern JS_FRIEND_API void DumpObject(JSObject* obj, js::GenericPrinter& out);
673 
674 extern JS_FRIEND_API void DumpChars(const char16_t* s, size_t n,
675                                     js::GenericPrinter& out);
676 
677 extern JS_FRIEND_API void DumpValue(const JS::Value& val,
678                                     js::GenericPrinter& out);
679 
680 extern JS_FRIEND_API void DumpId(jsid id, js::GenericPrinter& out);
681 
682 extern JS_FRIEND_API void DumpInterpreterFrame(
683     JSContext* cx, js::GenericPrinter& out, InterpreterFrame* start = nullptr);
684 
685 }  // namespace js
686 
DumpString(JSString * str,js::GenericPrinter & out)687 JS_FRIEND_API void js::DumpString(JSString* str, js::GenericPrinter& out) {
688 #if defined(DEBUG) || defined(JS_JITSPEW)
689   str->dump(out);
690 #endif
691 }
692 
DumpAtom(JSAtom * atom,js::GenericPrinter & out)693 JS_FRIEND_API void js::DumpAtom(JSAtom* atom, js::GenericPrinter& out) {
694 #if defined(DEBUG) || defined(JS_JITSPEW)
695   atom->dump(out);
696 #endif
697 }
698 
DumpChars(const char16_t * s,size_t n,js::GenericPrinter & out)699 JS_FRIEND_API void js::DumpChars(const char16_t* s, size_t n,
700                                  js::GenericPrinter& out) {
701 #if defined(DEBUG) || defined(JS_JITSPEW)
702   out.printf("char16_t * (%p) = ", (void*)s);
703   JSString::dumpChars(s, n, out);
704   out.putChar('\n');
705 #endif
706 }
707 
DumpObject(JSObject * obj,js::GenericPrinter & out)708 JS_FRIEND_API void js::DumpObject(JSObject* obj, js::GenericPrinter& out) {
709 #if defined(DEBUG) || defined(JS_JITSPEW)
710   if (!obj) {
711     out.printf("NULL\n");
712     return;
713   }
714   obj->dump(out);
715 #endif
716 }
717 
DumpString(JSString * str,FILE * fp)718 JS_FRIEND_API void js::DumpString(JSString* str, FILE* fp) {
719 #if defined(DEBUG) || defined(JS_JITSPEW)
720   Fprinter out(fp);
721   js::DumpString(str, out);
722 #endif
723 }
724 
DumpAtom(JSAtom * atom,FILE * fp)725 JS_FRIEND_API void js::DumpAtom(JSAtom* atom, FILE* fp) {
726 #if defined(DEBUG) || defined(JS_JITSPEW)
727   Fprinter out(fp);
728   js::DumpAtom(atom, out);
729 #endif
730 }
731 
DumpChars(const char16_t * s,size_t n,FILE * fp)732 JS_FRIEND_API void js::DumpChars(const char16_t* s, size_t n, FILE* fp) {
733 #if defined(DEBUG) || defined(JS_JITSPEW)
734   Fprinter out(fp);
735   js::DumpChars(s, n, out);
736 #endif
737 }
738 
DumpObject(JSObject * obj,FILE * fp)739 JS_FRIEND_API void js::DumpObject(JSObject* obj, FILE* fp) {
740 #if defined(DEBUG) || defined(JS_JITSPEW)
741   Fprinter out(fp);
742   js::DumpObject(obj, out);
743 #endif
744 }
745 
DumpId(jsid id,FILE * fp)746 JS_FRIEND_API void js::DumpId(jsid id, FILE* fp) {
747 #if defined(DEBUG) || defined(JS_JITSPEW)
748   Fprinter out(fp);
749   js::DumpId(id, out);
750 #endif
751 }
752 
DumpValue(const JS::Value & val,FILE * fp)753 JS_FRIEND_API void js::DumpValue(const JS::Value& val, FILE* fp) {
754 #if defined(DEBUG) || defined(JS_JITSPEW)
755   Fprinter out(fp);
756   js::DumpValue(val, out);
757 #endif
758 }
759 
DumpString(JSString * str)760 JS_FRIEND_API void js::DumpString(JSString* str) { DumpString(str, stderr); }
DumpAtom(JSAtom * atom)761 JS_FRIEND_API void js::DumpAtom(JSAtom* atom) { DumpAtom(atom, stderr); }
DumpObject(JSObject * obj)762 JS_FRIEND_API void js::DumpObject(JSObject* obj) { DumpObject(obj, stderr); }
DumpChars(const char16_t * s,size_t n)763 JS_FRIEND_API void js::DumpChars(const char16_t* s, size_t n) {
764   DumpChars(s, n, stderr);
765 }
DumpValue(const JS::Value & val)766 JS_FRIEND_API void js::DumpValue(const JS::Value& val) {
767   DumpValue(val, stderr);
768 }
DumpId(jsid id)769 JS_FRIEND_API void js::DumpId(jsid id) { DumpId(id, stderr); }
DumpInterpreterFrame(JSContext * cx,InterpreterFrame * start)770 JS_FRIEND_API void js::DumpInterpreterFrame(JSContext* cx,
771                                             InterpreterFrame* start) {
772 #if defined(DEBUG) || defined(JS_JITSPEW)
773   Fprinter out(stderr);
774   DumpInterpreterFrame(cx, out, start);
775 #endif
776 }
DumpPC(JSContext * cx)777 JS_FRIEND_API bool js::DumpPC(JSContext* cx) {
778 #if defined(DEBUG) || defined(JS_JITSPEW)
779   return DumpPC(cx, stdout);
780 #else
781   return true;
782 #endif
783 }
DumpScript(JSContext * cx,JSScript * scriptArg)784 JS_FRIEND_API bool js::DumpScript(JSContext* cx, JSScript* scriptArg) {
785 #if defined(DEBUG) || defined(JS_JITSPEW)
786   return DumpScript(cx, scriptArg, stdout);
787 #else
788   return true;
789 #endif
790 }
791 
FormatValue(JSContext * cx,HandleValue v,UniqueChars & bytes)792 static const char* FormatValue(JSContext* cx, HandleValue v,
793                                UniqueChars& bytes) {
794   if (v.isMagic()) {
795     MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_OUT ||
796                v.whyMagic() == JS_UNINITIALIZED_LEXICAL);
797     return "[unavailable]";
798   }
799 
800   if (IsCallable(v)) {
801     return "[function]";
802   }
803 
804   if (v.isObject() && IsCrossCompartmentWrapper(&v.toObject())) {
805     return "[cross-compartment wrapper]";
806   }
807 
808   JSString* str;
809   {
810     mozilla::Maybe<AutoRealm> ar;
811     if (v.isObject()) {
812       ar.emplace(cx, &v.toObject());
813     }
814 
815     str = ToString<CanGC>(cx, v);
816     if (!str) {
817       return nullptr;
818     }
819   }
820 
821   bytes = QuoteString(cx, str, '"');
822   return bytes.get();
823 }
824 
FormatFrame(JSContext * cx,const FrameIter & iter,Sprinter & sp,int num,bool showArgs,bool showLocals,bool showThisProps)825 static bool FormatFrame(JSContext* cx, const FrameIter& iter, Sprinter& sp,
826                         int num, bool showArgs, bool showLocals,
827                         bool showThisProps) {
828   MOZ_ASSERT(!cx->isExceptionPending());
829   RootedScript script(cx, iter.script());
830   jsbytecode* pc = iter.pc();
831 
832   RootedObject envChain(cx, iter.environmentChain(cx));
833   JSAutoRealm ar(cx, envChain);
834 
835   const char* filename = script->filename();
836   unsigned column = 0;
837   unsigned lineno = PCToLineNumber(script, pc, &column);
838   RootedFunction fun(cx, iter.maybeCallee(cx));
839   RootedString funname(cx);
840   if (fun) {
841     funname = fun->displayAtom();
842   }
843 
844   RootedValue thisVal(cx);
845   if (iter.hasUsableAbstractFramePtr() && iter.isFunctionFrame() && fun &&
846       !fun->isArrow() && !fun->isDerivedClassConstructor() &&
847       !(fun->isBoundFunction() && iter.isConstructing())) {
848     if (!GetFunctionThis(cx, iter.abstractFramePtr(), &thisVal)) {
849       return false;
850     }
851   }
852 
853   // print the frame number and function name
854   if (funname) {
855     UniqueChars funbytes = QuoteString(cx, funname);
856     if (!funbytes) {
857       return false;
858     }
859     if (!sp.printf("%d %s(", num, funbytes.get())) {
860       return false;
861     }
862   } else if (fun) {
863     if (!sp.printf("%d anonymous(", num)) {
864       return false;
865     }
866   } else {
867     if (!sp.printf("%d <TOP LEVEL>", num)) {
868       return false;
869     }
870   }
871 
872   if (showArgs && iter.hasArgs()) {
873     PositionalFormalParameterIter fi(script);
874     bool first = true;
875     for (unsigned i = 0; i < iter.numActualArgs(); i++) {
876       RootedValue arg(cx);
877       if (i < iter.numFormalArgs() && fi.closedOver()) {
878         if (iter.hasInitialEnvironment(cx)) {
879           arg = iter.callObj(cx).aliasedBinding(fi);
880         } else {
881           arg = MagicValue(JS_OPTIMIZED_OUT);
882         }
883       } else if (iter.hasUsableAbstractFramePtr()) {
884         if (!script->needsArgsAnalysis() && script->argsObjAliasesFormals() &&
885             iter.hasArgsObj()) {
886           arg = iter.argsObj().arg(i);
887         } else {
888           arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING);
889         }
890       } else {
891         arg = MagicValue(JS_OPTIMIZED_OUT);
892       }
893 
894       UniqueChars valueBytes;
895       const char* value = FormatValue(cx, arg, valueBytes);
896       if (!value) {
897         if (cx->isThrowingOutOfMemory()) {
898           return false;
899         }
900         cx->clearPendingException();
901       }
902 
903       UniqueChars nameBytes;
904       const char* name = nullptr;
905 
906       if (i < iter.numFormalArgs()) {
907         MOZ_ASSERT(fi.argumentSlot() == i);
908         if (!fi.isDestructured()) {
909           nameBytes = StringToNewUTF8CharsZ(cx, *fi.name());
910           name = nameBytes.get();
911           if (!name) {
912             return false;
913           }
914         } else {
915           name = "(destructured parameter)";
916         }
917         fi++;
918       }
919 
920       if (value) {
921         if (!sp.printf("%s%s%s%s%s%s", !first ? ", " : "", name ? name : "",
922                        name ? " = " : "", arg.isString() ? "\"" : "", value,
923                        arg.isString() ? "\"" : "")) {
924           return false;
925         }
926 
927         first = false;
928       } else {
929         if (!sp.put("    <Failed to get argument while inspecting stack "
930                     "frame>\n")) {
931           return false;
932         }
933       }
934     }
935   }
936 
937   // print filename, line number and column
938   if (!sp.printf("%s [\"%s\":%u:%u]\n", fun ? ")" : "",
939                  filename ? filename : "<unknown>", lineno, column)) {
940     return false;
941   }
942 
943   // Note: Right now we don't dump the local variables anymore, because
944   // that is hard to support across all the JITs etc.
945 
946   // print the value of 'this'
947   if (showLocals) {
948     if (!thisVal.isUndefined()) {
949       RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal));
950       if (!thisValStr) {
951         if (cx->isThrowingOutOfMemory()) {
952           return false;
953         }
954         cx->clearPendingException();
955       }
956       if (thisValStr) {
957         UniqueChars thisValBytes = QuoteString(cx, thisValStr);
958         if (!thisValBytes) {
959           return false;
960         }
961         if (!sp.printf("    this = %s\n", thisValBytes.get())) {
962           return false;
963         }
964       } else {
965         if (!sp.put("    <failed to get 'this' value>\n")) {
966           return false;
967         }
968       }
969     }
970   }
971 
972   if (showThisProps && thisVal.isObject()) {
973     RootedObject obj(cx, &thisVal.toObject());
974 
975     RootedIdVector keys(cx);
976     if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &keys)) {
977       if (cx->isThrowingOutOfMemory()) {
978         return false;
979       }
980       cx->clearPendingException();
981     }
982 
983     for (size_t i = 0; i < keys.length(); i++) {
984       RootedId id(cx, keys[i]);
985       RootedValue key(cx, IdToValue(id));
986       RootedValue v(cx);
987 
988       if (!GetProperty(cx, obj, obj, id, &v)) {
989         if (cx->isThrowingOutOfMemory()) {
990           return false;
991         }
992         cx->clearPendingException();
993         if (!sp.put("    <Failed to fetch property while inspecting stack "
994                     "frame>\n")) {
995           return false;
996         }
997         continue;
998       }
999 
1000       UniqueChars nameBytes;
1001       const char* name = FormatValue(cx, key, nameBytes);
1002       if (!name) {
1003         if (cx->isThrowingOutOfMemory()) {
1004           return false;
1005         }
1006         cx->clearPendingException();
1007       }
1008 
1009       UniqueChars valueBytes;
1010       const char* value = FormatValue(cx, v, valueBytes);
1011       if (!value) {
1012         if (cx->isThrowingOutOfMemory()) {
1013           return false;
1014         }
1015         cx->clearPendingException();
1016       }
1017 
1018       if (name && value) {
1019         if (!sp.printf("    this.%s = %s%s%s\n", name, v.isString() ? "\"" : "",
1020                        value, v.isString() ? "\"" : "")) {
1021           return false;
1022         }
1023       } else {
1024         if (!sp.put("    <Failed to format values while inspecting stack "
1025                     "frame>\n")) {
1026           return false;
1027         }
1028       }
1029     }
1030   }
1031 
1032   MOZ_ASSERT(!cx->isExceptionPending());
1033   return true;
1034 }
1035 
FormatWasmFrame(JSContext * cx,const FrameIter & iter,Sprinter & sp,int num)1036 static bool FormatWasmFrame(JSContext* cx, const FrameIter& iter, Sprinter& sp,
1037                             int num) {
1038   UniqueChars nameStr;
1039   if (JSAtom* functionDisplayAtom = iter.maybeFunctionDisplayAtom()) {
1040     nameStr = StringToNewUTF8CharsZ(cx, *functionDisplayAtom);
1041     if (!nameStr) {
1042       return false;
1043     }
1044   }
1045 
1046   if (!sp.printf("%d %s()", num, nameStr ? nameStr.get() : "<wasm-function>")) {
1047     return false;
1048   }
1049 
1050   if (!sp.printf(" [\"%s\":wasm-function[%u]:0x%x]\n",
1051                  iter.filename() ? iter.filename() : "<unknown>",
1052                  iter.wasmFuncIndex(), iter.wasmBytecodeOffset())) {
1053     return false;
1054   }
1055 
1056   MOZ_ASSERT(!cx->isExceptionPending());
1057   return true;
1058 }
1059 
FormatStackDump(JSContext * cx,bool showArgs,bool showLocals,bool showThisProps)1060 JS_FRIEND_API JS::UniqueChars JS::FormatStackDump(JSContext* cx, bool showArgs,
1061                                                   bool showLocals,
1062                                                   bool showThisProps) {
1063   int num = 0;
1064 
1065   Sprinter sp(cx);
1066   if (!sp.init()) {
1067     return nullptr;
1068   }
1069 
1070   for (AllFramesIter i(cx); !i.done(); ++i) {
1071     bool ok = i.hasScript() ? FormatFrame(cx, i, sp, num, showArgs, showLocals,
1072                                           showThisProps)
1073                             : FormatWasmFrame(cx, i, sp, num);
1074     if (!ok) {
1075       return nullptr;
1076     }
1077     num++;
1078   }
1079 
1080   if (num == 0) {
1081     if (!sp.put("JavaScript stack is empty\n")) {
1082       return nullptr;
1083     }
1084   }
1085 
1086   return sp.release();
1087 }
1088 
ForceLexicalInitialization(JSContext * cx,HandleObject obj)1089 extern JS_FRIEND_API bool JS::ForceLexicalInitialization(JSContext* cx,
1090                                                          HandleObject obj) {
1091   AssertHeapIsIdle();
1092   CHECK_THREAD(cx);
1093   cx->check(obj);
1094 
1095   bool initializedAny = false;
1096   NativeObject* nobj = &obj->as<NativeObject>();
1097 
1098   for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
1099     Shape* s = &r.front();
1100     Value v = nobj->getSlot(s->slot());
1101     if (s->isDataProperty() && v.isMagic() &&
1102         v.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
1103       nobj->setSlot(s->slot(), UndefinedValue());
1104       initializedAny = true;
1105     }
1106   }
1107   return initializedAny;
1108 }
1109 
IsGCPoisoning()1110 extern JS_FRIEND_API int JS::IsGCPoisoning() {
1111 #ifdef JS_GC_POISONING
1112   return !js::gDisablePoisoning;
1113 #else
1114   return false;
1115 #endif
1116 }
1117 
1118 struct DumpHeapTracer final : public JS::CallbackTracer, public WeakMapTracer {
1119   const char* prefix;
1120   FILE* output;
1121   mozilla::MallocSizeOf mallocSizeOf;
1122 
DumpHeapTracerDumpHeapTracer1123   DumpHeapTracer(FILE* fp, JSContext* cx, mozilla::MallocSizeOf mallocSizeOf)
1124       : JS::CallbackTracer(cx, DoNotTraceWeakMaps),
1125         js::WeakMapTracer(cx->runtime()),
1126         prefix(""),
1127         output(fp),
1128         mallocSizeOf(mallocSizeOf) {}
1129 
1130  private:
traceDumpHeapTracer1131   void trace(JSObject* map, JS::GCCellPtr key, JS::GCCellPtr value) override {
1132     JSObject* kdelegate = nullptr;
1133     if (key.is<JSObject>()) {
1134       kdelegate = UncheckedUnwrapWithoutExpose(&key.as<JSObject>());
1135     }
1136 
1137     fprintf(output, "WeakMapEntry map=%p key=%p keyDelegate=%p value=%p\n", map,
1138             key.asCell(), kdelegate, value.asCell());
1139   }
1140 
1141   bool onChild(const JS::GCCellPtr& thing) override;
1142 };
1143 
MarkDescriptor(gc::Cell * thing)1144 static char MarkDescriptor(gc::Cell* thing) {
1145   gc::TenuredCell* cell = &thing->asTenured();
1146   if (cell->isMarkedBlack()) {
1147     return 'B';
1148   }
1149   if (cell->isMarkedGray()) {
1150     return 'G';
1151   }
1152   if (cell->isMarkedAny()) {
1153     return 'X';
1154   }
1155   return 'W';
1156 }
1157 
DumpHeapVisitZone(JSRuntime * rt,void * data,Zone * zone)1158 static void DumpHeapVisitZone(JSRuntime* rt, void* data, Zone* zone) {
1159   DumpHeapTracer* dtrc = static_cast<DumpHeapTracer*>(data);
1160   fprintf(dtrc->output, "# zone %p\n", (void*)zone);
1161 }
1162 
DumpHeapVisitRealm(JSContext * cx,void * data,Handle<Realm * > realm)1163 static void DumpHeapVisitRealm(JSContext* cx, void* data,
1164                                Handle<Realm*> realm) {
1165   char name[1024];
1166   if (auto nameCallback = cx->runtime()->realmNameCallback) {
1167     nameCallback(cx, realm, name, sizeof(name));
1168   } else {
1169     strcpy(name, "<unknown>");
1170   }
1171 
1172   DumpHeapTracer* dtrc = static_cast<DumpHeapTracer*>(data);
1173   fprintf(dtrc->output, "# realm %s [in compartment %p, zone %p]\n", name,
1174           (void*)realm->compartment(), (void*)realm->zone());
1175 }
1176 
DumpHeapVisitArena(JSRuntime * rt,void * data,gc::Arena * arena,JS::TraceKind traceKind,size_t thingSize)1177 static void DumpHeapVisitArena(JSRuntime* rt, void* data, gc::Arena* arena,
1178                                JS::TraceKind traceKind, size_t thingSize) {
1179   DumpHeapTracer* dtrc = static_cast<DumpHeapTracer*>(data);
1180   fprintf(dtrc->output, "# arena allockind=%u size=%u\n",
1181           unsigned(arena->getAllocKind()), unsigned(thingSize));
1182 }
1183 
DumpHeapVisitCell(JSRuntime * rt,void * data,JS::GCCellPtr cellptr,size_t thingSize)1184 static void DumpHeapVisitCell(JSRuntime* rt, void* data, JS::GCCellPtr cellptr,
1185                               size_t thingSize) {
1186   DumpHeapTracer* dtrc = static_cast<DumpHeapTracer*>(data);
1187   char cellDesc[1024 * 32];
1188   JS_GetTraceThingInfo(cellDesc, sizeof(cellDesc), dtrc, cellptr.asCell(),
1189                        cellptr.kind(), true);
1190 
1191   fprintf(dtrc->output, "%p %c %s", cellptr.asCell(),
1192           MarkDescriptor(cellptr.asCell()), cellDesc);
1193   if (dtrc->mallocSizeOf) {
1194     auto size = JS::ubi::Node(cellptr).size(dtrc->mallocSizeOf);
1195     fprintf(dtrc->output, " SIZE:: %" PRIu64 "\n", size);
1196   } else {
1197     fprintf(dtrc->output, "\n");
1198   }
1199 
1200   js::TraceChildren(dtrc, cellptr.asCell(), cellptr.kind());
1201 }
1202 
onChild(const JS::GCCellPtr & thing)1203 bool DumpHeapTracer::onChild(const JS::GCCellPtr& thing) {
1204   if (gc::IsInsideNursery(thing.asCell())) {
1205     return true;
1206   }
1207 
1208   char buffer[1024];
1209   getTracingEdgeName(buffer, sizeof(buffer));
1210   fprintf(output, "%s%p %c %s\n", prefix, thing.asCell(),
1211           MarkDescriptor(thing.asCell()), buffer);
1212   return true;
1213 }
1214 
DumpHeap(JSContext * cx,FILE * fp,js::DumpHeapNurseryBehaviour nurseryBehaviour,mozilla::MallocSizeOf mallocSizeOf)1215 void js::DumpHeap(JSContext* cx, FILE* fp,
1216                   js::DumpHeapNurseryBehaviour nurseryBehaviour,
1217                   mozilla::MallocSizeOf mallocSizeOf) {
1218   if (nurseryBehaviour == js::CollectNurseryBeforeDump) {
1219     cx->runtime()->gc.evictNursery(JS::GCReason::API);
1220   }
1221 
1222   DumpHeapTracer dtrc(fp, cx, mallocSizeOf);
1223 
1224   fprintf(dtrc.output, "# Roots.\n");
1225   TraceRuntimeWithoutEviction(&dtrc);
1226 
1227   fprintf(dtrc.output, "# Weak maps.\n");
1228   WeakMapBase::traceAllMappings(&dtrc);
1229 
1230   fprintf(dtrc.output, "==========\n");
1231 
1232   dtrc.prefix = "> ";
1233   IterateHeapUnbarriered(cx, &dtrc, DumpHeapVisitZone, DumpHeapVisitRealm,
1234                          DumpHeapVisitArena, DumpHeapVisitCell);
1235 
1236   fflush(dtrc.output);
1237 }
1238 
NotifyGCRootsRemoved(JSContext * cx)1239 JS_FRIEND_API void JS::NotifyGCRootsRemoved(JSContext* cx) {
1240   cx->runtime()->gc.notifyRootsRemoved();
1241 }
1242 
GetAnyRealmInZone(JS::Zone * zone)1243 JS_FRIEND_API JS::Realm* js::GetAnyRealmInZone(JS::Zone* zone) {
1244   if (zone->isAtomsZone()) {
1245     return nullptr;
1246   }
1247 
1248   RealmsInZoneIter realm(zone);
1249   MOZ_ASSERT(!realm.done());
1250   return realm.get();
1251 }
1252 
IsSharableCompartment(JS::Compartment * comp)1253 JS_FRIEND_API bool js::IsSharableCompartment(JS::Compartment* comp) {
1254   // If this compartment has nuked outgoing wrappers (because all its globals
1255   // got nuked), we won't be able to create any useful CCWs out of it in the
1256   // future, and so we shouldn't use it for any new globals.
1257   if (comp->nukedOutgoingWrappers) {
1258     return false;
1259   }
1260 
1261   // If this compartment has no live globals, it might be in the middle of being
1262   // GCed.  Don't create any new Realms inside.  There's no point to doing that
1263   // anyway, since the idea would be to avoid CCWs from existing Realms in the
1264   // compartment to the new Realm, and there are no existing Realms.
1265   if (!CompartmentHasLiveGlobal(comp)) {
1266     return false;
1267   }
1268 
1269   // Good to go.
1270   return true;
1271 }
1272 
GetTestingFunctions(JSContext * cx)1273 JS_FRIEND_API JSObject* js::GetTestingFunctions(JSContext* cx) {
1274   RootedObject obj(cx, JS_NewPlainObject(cx));
1275   if (!obj) {
1276     return nullptr;
1277   }
1278 
1279   if (!DefineTestingFunctions(cx, obj, false, false)) {
1280     return nullptr;
1281   }
1282 
1283   return obj;
1284 }
1285 
SetDOMCallbacks(JSContext * cx,const DOMCallbacks * callbacks)1286 JS_FRIEND_API void js::SetDOMCallbacks(JSContext* cx,
1287                                        const DOMCallbacks* callbacks) {
1288   cx->runtime()->DOMcallbacks = callbacks;
1289 }
1290 
GetDOMCallbacks(JSContext * cx)1291 JS_FRIEND_API const DOMCallbacks* js::GetDOMCallbacks(JSContext* cx) {
1292   return cx->runtime()->DOMcallbacks;
1293 }
1294 
1295 static const void* gDOMProxyHandlerFamily = nullptr;
1296 static DOMProxyShadowsCheck gDOMProxyShadowsCheck;
1297 static const void* gDOMRemoteProxyHandlerFamily = nullptr;
1298 
SetDOMProxyInformation(const void * domProxyHandlerFamily,DOMProxyShadowsCheck domProxyShadowsCheck,const void * domRemoteProxyHandlerFamily)1299 JS_FRIEND_API void js::SetDOMProxyInformation(
1300     const void* domProxyHandlerFamily,
1301     DOMProxyShadowsCheck domProxyShadowsCheck,
1302     const void* domRemoteProxyHandlerFamily) {
1303   gDOMProxyHandlerFamily = domProxyHandlerFamily;
1304   gDOMProxyShadowsCheck = domProxyShadowsCheck;
1305   gDOMRemoteProxyHandlerFamily = domRemoteProxyHandlerFamily;
1306 }
1307 
GetDOMProxyHandlerFamily()1308 const void* js::GetDOMProxyHandlerFamily() { return gDOMProxyHandlerFamily; }
1309 
GetDOMProxyShadowsCheck()1310 DOMProxyShadowsCheck js::GetDOMProxyShadowsCheck() {
1311   return gDOMProxyShadowsCheck;
1312 }
1313 
GetDOMRemoteProxyHandlerFamily()1314 const void* js::GetDOMRemoteProxyHandlerFamily() {
1315   return gDOMRemoteProxyHandlerFamily;
1316 }
1317 
IsDOMRemoteProxyObject(JSObject * object)1318 JS_FRIEND_API bool js::IsDOMRemoteProxyObject(JSObject* object) {
1319   return js::IsProxy(object) && js::GetProxyHandler(object)->family() ==
1320                                     js::GetDOMRemoteProxyHandlerFamily();
1321 }
1322 
1323 static XrayJitInfo* gXrayJitInfo = nullptr;
1324 
SetXrayJitInfo(XrayJitInfo * info)1325 JS_FRIEND_API void js::SetXrayJitInfo(XrayJitInfo* info) {
1326   gXrayJitInfo = info;
1327 }
1328 
GetXrayJitInfo()1329 XrayJitInfo* js::GetXrayJitInfo() { return gXrayJitInfo; }
1330 
PrepareScriptEnvironmentAndInvoke(JSContext * cx,HandleObject global,ScriptEnvironmentPreparer::Closure & closure)1331 JS_FRIEND_API void js::PrepareScriptEnvironmentAndInvoke(
1332     JSContext* cx, HandleObject global,
1333     ScriptEnvironmentPreparer::Closure& closure) {
1334   MOZ_ASSERT(!cx->isExceptionPending());
1335   MOZ_ASSERT(global->is<GlobalObject>());
1336 
1337   MOZ_RELEASE_ASSERT(
1338       cx->runtime()->scriptEnvironmentPreparer,
1339       "Embedding needs to set a scriptEnvironmentPreparer callback");
1340 
1341   cx->runtime()->scriptEnvironmentPreparer->invoke(global, closure);
1342 }
1343 
SetScriptEnvironmentPreparer(JSContext * cx,ScriptEnvironmentPreparer * preparer)1344 JS_FRIEND_API void js::SetScriptEnvironmentPreparer(
1345     JSContext* cx, ScriptEnvironmentPreparer* preparer) {
1346   cx->runtime()->scriptEnvironmentPreparer = preparer;
1347 }
1348 
SetCTypesActivityCallback(JSContext * cx,CTypesActivityCallback cb)1349 JS_FRIEND_API void js::SetCTypesActivityCallback(JSContext* cx,
1350                                                  CTypesActivityCallback cb) {
1351   cx->runtime()->ctypesActivityCallback = cb;
1352 }
1353 
AutoCTypesActivityCallback(JSContext * cx,js::CTypesActivityType beginType,js::CTypesActivityType endType MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)1354 js::AutoCTypesActivityCallback::AutoCTypesActivityCallback(
1355     JSContext* cx, js::CTypesActivityType beginType,
1356     js::CTypesActivityType endType MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
1357     : cx(cx),
1358       callback(cx->runtime()->ctypesActivityCallback),
1359       endType(endType) {
1360   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1361 
1362   if (callback) {
1363     callback(cx, beginType);
1364   }
1365 }
1366 
SetAllocationMetadataBuilder(JSContext * cx,const AllocationMetadataBuilder * callback)1367 JS_FRIEND_API void js::SetAllocationMetadataBuilder(
1368     JSContext* cx, const AllocationMetadataBuilder* callback) {
1369   cx->realm()->setAllocationMetadataBuilder(callback);
1370 }
1371 
GetAllocationMetadata(JSObject * obj)1372 JS_FRIEND_API JSObject* js::GetAllocationMetadata(JSObject* obj) {
1373   ObjectWeakMap* map = ObjectRealm::get(obj).objectMetadataTable.get();
1374   if (map) {
1375     return map->lookup(obj);
1376   }
1377   return nullptr;
1378 }
1379 
ReportIsNotFunction(JSContext * cx,HandleValue v)1380 JS_FRIEND_API bool js::ReportIsNotFunction(JSContext* cx, HandleValue v) {
1381   cx->check(v);
1382   return ReportIsNotFunction(cx, v, -1);
1383 }
1384 
1385 #ifdef DEBUG
HasObjectMovedOp(JSObject * obj)1386 bool js::HasObjectMovedOp(JSObject* obj) {
1387   return !!GetObjectClass(obj)->extObjectMovedOp();
1388 }
1389 #endif
1390 
ForwardToNative(JSContext * cx,JSNative native,const CallArgs & args)1391 JS_FRIEND_API bool js::ForwardToNative(JSContext* cx, JSNative native,
1392                                        const CallArgs& args) {
1393   return native(cx, args.length(), args.base());
1394 }
1395 
ConvertArgsToArray(JSContext * cx,const CallArgs & args)1396 JS_FRIEND_API JSObject* js::ConvertArgsToArray(JSContext* cx,
1397                                                const CallArgs& args) {
1398   RootedObject argsArray(cx,
1399                          NewDenseCopiedArray(cx, args.length(), args.array()));
1400   return argsArray;
1401 }
1402 
GetPropertyNameFromPC(JSScript * script,jsbytecode * pc)1403 JS_FRIEND_API JSAtom* js::GetPropertyNameFromPC(JSScript* script,
1404                                                 jsbytecode* pc) {
1405   if (!IsGetPropPC(pc) && !IsSetPropPC(pc)) {
1406     return nullptr;
1407   }
1408   return script->getName(pc);
1409 }
1410 
SetWindowProxyClass(JSContext * cx,const JSClass * clasp)1411 JS_FRIEND_API void js::SetWindowProxyClass(JSContext* cx,
1412                                            const JSClass* clasp) {
1413   MOZ_ASSERT(!cx->runtime()->maybeWindowProxyClass());
1414   cx->runtime()->setWindowProxyClass(clasp);
1415 }
1416 
SetWindowProxy(JSContext * cx,HandleObject global,HandleObject windowProxy)1417 JS_FRIEND_API void js::SetWindowProxy(JSContext* cx, HandleObject global,
1418                                       HandleObject windowProxy) {
1419   AssertHeapIsIdle();
1420   CHECK_THREAD(cx);
1421 
1422   cx->check(global, windowProxy);
1423   MOZ_ASSERT(IsWindowProxy(windowProxy));
1424 
1425   GlobalObject& globalObj = global->as<GlobalObject>();
1426   globalObj.setWindowProxy(windowProxy);
1427   globalObj.lexicalEnvironment().setWindowProxyThisValue(windowProxy);
1428 }
1429 
ToWindowIfWindowProxy(JSObject * obj)1430 JS_FRIEND_API JSObject* js::ToWindowIfWindowProxy(JSObject* obj) {
1431   if (IsWindowProxy(obj)) {
1432     return &obj->nonCCWGlobal();
1433   }
1434   return obj;
1435 }
1436 
ToWindowProxyIfWindowSlow(JSObject * obj)1437 JS_FRIEND_API JSObject* js::detail::ToWindowProxyIfWindowSlow(JSObject* obj) {
1438   if (JSObject* windowProxy = obj->as<GlobalObject>().maybeWindowProxy()) {
1439     return windowProxy;
1440   }
1441   return obj;
1442 }
1443 
IsWindowProxy(JSObject * obj)1444 JS_FRIEND_API bool js::IsWindowProxy(JSObject* obj) {
1445   // Note: simply checking `obj == obj->global().windowProxy()` is not
1446   // sufficient: we may have transplanted the window proxy with a CCW.
1447   // Check the Class to ensure we really have a window proxy.
1448   return obj->getClass() ==
1449          obj->runtimeFromAnyThread()->maybeWindowProxyClass();
1450 }
1451 
IsWindowSlow(JSObject * obj)1452 JS_FRIEND_API bool js::detail::IsWindowSlow(JSObject* obj) {
1453   return obj->as<GlobalObject>().maybeWindowProxy();
1454 }
1455 
AutoAssertNoContentJS(JSContext * cx)1456 AutoAssertNoContentJS::AutoAssertNoContentJS(JSContext* cx)
1457     : context_(cx), prevAllowContentJS_(cx->runtime()->allowContentJS_) {
1458   cx->runtime()->allowContentJS_ = false;
1459 }
1460 
~AutoAssertNoContentJS()1461 AutoAssertNoContentJS::~AutoAssertNoContentJS() {
1462   context_->runtime()->allowContentJS_ = prevAllowContentJS_;
1463 }
1464 
EnableAccessValidation(JSContext * cx,bool enabled)1465 JS_FRIEND_API void js::EnableAccessValidation(JSContext* cx, bool enabled) {
1466   cx->enableAccessValidation = enabled;
1467 }
1468 
EnableCodeCoverage()1469 JS_FRIEND_API void js::EnableCodeCoverage() { js::coverage::EnableLCov(); }
1470 
SetRealmValidAccessPtr(JSContext * cx,JS::HandleObject global,bool * accessp)1471 JS_FRIEND_API void js::SetRealmValidAccessPtr(JSContext* cx,
1472                                               JS::HandleObject global,
1473                                               bool* accessp) {
1474   MOZ_ASSERT(global->is<GlobalObject>());
1475   global->as<GlobalObject>().realm()->setValidAccessPtr(accessp);
1476 }
1477 
SystemZoneAvailable(JSContext * cx)1478 JS_FRIEND_API bool js::SystemZoneAvailable(JSContext* cx) { return true; }
1479 
1480 static LogCtorDtor sLogCtor = nullptr;
1481 static LogCtorDtor sLogDtor = nullptr;
1482 
SetLogCtorDtorFunctions(LogCtorDtor ctor,LogCtorDtor dtor)1483 JS_FRIEND_API void js::SetLogCtorDtorFunctions(LogCtorDtor ctor,
1484                                                LogCtorDtor dtor) {
1485   MOZ_ASSERT(!sLogCtor && !sLogDtor);
1486   MOZ_ASSERT(ctor && dtor);
1487   sLogCtor = ctor;
1488   sLogDtor = dtor;
1489 }
1490 
LogCtor(void * self,const char * type,uint32_t sz)1491 JS_FRIEND_API void js::LogCtor(void* self, const char* type, uint32_t sz) {
1492   if (LogCtorDtor fun = sLogCtor) {
1493     fun(self, type, sz);
1494   }
1495 }
1496 
LogDtor(void * self,const char * type,uint32_t sz)1497 JS_FRIEND_API void js::LogDtor(void* self, const char* type, uint32_t sz) {
1498   if (LogCtorDtor fun = sLogDtor) {
1499     fun(self, type, sz);
1500   }
1501 }
1502 
MaybeGetScriptPrivate(JSObject * object)1503 JS_FRIEND_API JS::Value js::MaybeGetScriptPrivate(JSObject* object) {
1504   if (!object->is<ScriptSourceObject>()) {
1505     return UndefinedValue();
1506   }
1507 
1508   return object->as<ScriptSourceObject>().canonicalPrivate();
1509 }
1510 
GetGCHeapUsageForObjectZone(JSObject * obj)1511 JS_FRIEND_API uint64_t js::GetGCHeapUsageForObjectZone(JSObject* obj) {
1512   return obj->zone()->gcHeapSize.bytes();
1513 }
1514 
1515 #ifdef DEBUG
RuntimeIsBeingDestroyed()1516 JS_FRIEND_API bool js::RuntimeIsBeingDestroyed() {
1517   JSRuntime* runtime = TlsContext.get()->runtime();
1518   MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime));
1519   return runtime->isBeingDestroyed();
1520 }
1521 #endif
1522 
1523 // No-op implementations of public API that would depend on --with-intl-api
1524 
1525 #ifndef JS_HAS_INTL_API
1526 
IntlNotEnabled(JSContext * cx)1527 static bool IntlNotEnabled(JSContext* cx) {
1528   JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr,
1529                             JSMSG_SUPPORT_NOT_ENABLED, "Intl");
1530   return false;
1531 }
1532 
AddMozDateTimeFormatConstructor(JSContext * cx,JS::HandleObject intl)1533 bool js::AddMozDateTimeFormatConstructor(JSContext* cx, JS::HandleObject intl) {
1534   return IntlNotEnabled(cx);
1535 }
1536 
AddMozDisplayNamesConstructor(JSContext * cx,JS::HandleObject intl)1537 bool js::AddMozDisplayNamesConstructor(JSContext* cx, JS::HandleObject intl) {
1538   return IntlNotEnabled(cx);
1539 }
1540 
AddDisplayNamesConstructor(JSContext * cx,JS::HandleObject intl)1541 bool js::AddDisplayNamesConstructor(JSContext* cx, JS::HandleObject intl) {
1542   return IntlNotEnabled(cx);
1543 }
1544 
1545 #endif  // !JS_HAS_INTL_API
1546 
GetObjectZoneFromAnyThread(const JSObject * obj)1547 JS_FRIEND_API JS::Zone* js::GetObjectZoneFromAnyThread(const JSObject* obj) {
1548   return MaybeForwarded(obj)->zoneFromAnyThread();
1549 }
1550