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