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