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