Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
7 #include "jsfriendapi.h"
9 #include "mozilla/PodOperations.h"
11 #include <stdint.h>
13 #include "jscntxt.h"
14 #include "jscompartment.h"
15 #include "jsgc.h"
16 #include "jsobj.h"
17 #include "jsproxy.h"
18 #include "jswatchpoint.h"
19 #include "jsweakmap.h"
20 #include "jswrapper.h"
21 #include "prmjtime.h"
23 #include "builtin/TestingFunctions.h"
24 #include "vm/WrapperObject.h"
26 #include "jsobjinlines.h"
28 #include "vm/ScopeObject-inl.h"
30 using namespace js;
31 using namespace JS;
33 using mozilla::PodArrayZero;
35 // Required by PerThreadDataFriendFields::getMainThread()
36 JS_STATIC_ASSERT(offsetof(JSRuntime, mainThread) ==
37 PerThreadDataFriendFields::RuntimeMainThreadOffset);
39 PerThreadDataFriendFields::PerThreadDataFriendFields()
40 {
41 PodArrayZero(nativeStackLimit);
42 #if JS_STACK_GROWTH_DIRECTION > 0
43 for (int i=0; i<StackKindCount; i++)
44 nativeStackLimit[i] = UINTPTR_MAX;
45 #endif
46 #if defined(JSGC_USE_EXACT_ROOTING)
47 PodArrayZero(thingGCRooters);
48 #endif
49 }
51 JS_FRIEND_API(void)
52 js::SetSourceHook(JSRuntime *rt, SourceHook *hook)
53 {
54 rt->sourceHook = hook;
55 }
57 JS_FRIEND_API(SourceHook *)
58 js::ForgetSourceHook(JSRuntime *rt)
59 {
60 return rt->sourceHook.forget();
61 }
63 JS_FRIEND_API(void)
64 JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
65 {
66 rt->gcGrayRootTracer.op = traceOp;
67 rt->gcGrayRootTracer.data = data;
68 }
70 JS_FRIEND_API(JSString *)
71 JS_GetAnonymousString(JSRuntime *rt)
72 {
73 JS_ASSERT(rt->hasContexts());
74 return rt->commonNames->anonymous;
75 }
77 JS_FRIEND_API(void)
78 JS_SetIsWorkerRuntime(JSRuntime *rt)
79 {
80 rt->setIsWorkerRuntime();
81 }
83 JS_FRIEND_API(JSObject *)
84 JS_FindCompilationScope(JSContext *cx, HandleObject objArg)
85 {
86 RootedObject obj(cx, objArg);
88 /*
89 * We unwrap wrappers here. This is a little weird, but it's what's being
90 * asked of us.
91 */
92 if (obj->is<WrapperObject>())
93 obj = UncheckedUnwrap(obj);
95 /*
96 * Innerize the target_obj so that we compile in the correct (inner)
97 * scope.
98 */
99 if (JSObjectOp op = obj->getClass()->ext.innerObject)
100 obj = op(cx, obj);
101 return obj;
102 }
104 JS_FRIEND_API(JSFunction *)
105 JS_GetObjectFunction(JSObject *obj)
106 {
107 if (obj->is<JSFunction>())
108 return &obj->as<JSFunction>();
109 return nullptr;
110 }
112 JS_FRIEND_API(bool)
113 JS_SplicePrototype(JSContext *cx, HandleObject obj, HandleObject proto)
114 {
115 /*
116 * Change the prototype of an object which hasn't been used anywhere
117 * and does not share its type with another object. Unlike JS_SetPrototype,
118 * does not nuke type information for the object.
119 */
120 CHECK_REQUEST(cx);
122 if (!obj->hasSingletonType()) {
123 /*
124 * We can see non-singleton objects when trying to splice prototypes
125 * due to mutable __proto__ (ugh).
126 */
127 return JS_SetPrototype(cx, obj, proto);
128 }
130 Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
131 return obj->splicePrototype(cx, obj->getClass(), tagged);
132 }
134 JS_FRIEND_API(JSObject *)
135 JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, HandleObject proto,
136 HandleObject parent)
137 {
138 /*
139 * Create our object with a null proto and then splice in the correct proto
140 * after we setSingletonType, so that we don't pollute the default
141 * TypeObject attached to our proto with information about our object, since
142 * we're not going to be using that TypeObject anyway.
143 */
144 RootedObject obj(cx, NewObjectWithGivenProto(cx, (const js::Class *)clasp, nullptr,
145 parent, SingletonObject));
146 if (!obj)
147 return nullptr;
148 if (!JS_SplicePrototype(cx, obj, proto))
149 return nullptr;
150 return obj;
151 }
153 JS_FRIEND_API(void)
154 JS::PrepareZoneForGC(Zone *zone)
155 {
156 zone->scheduleGC();
157 }
159 JS_FRIEND_API(void)
160 JS::PrepareForFullGC(JSRuntime *rt)
161 {
162 for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
163 zone->scheduleGC();
164 }
166 JS_FRIEND_API(void)
167 JS::PrepareForIncrementalGC(JSRuntime *rt)
168 {
169 if (!JS::IsIncrementalGCInProgress(rt))
170 return;
172 for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
173 if (zone->wasGCStarted())
174 PrepareZoneForGC(zone);
175 }
176 }
178 JS_FRIEND_API(bool)
179 JS::IsGCScheduled(JSRuntime *rt)
180 {
181 for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
182 if (zone->isGCScheduled())
183 return true;
184 }
186 return false;
187 }
189 JS_FRIEND_API(void)
190 JS::SkipZoneForGC(Zone *zone)
191 {
192 zone->unscheduleGC();
193 }
195 JS_FRIEND_API(void)
196 JS::GCForReason(JSRuntime *rt, gcreason::Reason reason)
197 {
198 GC(rt, GC_NORMAL, reason);
199 }
201 JS_FRIEND_API(void)
202 JS::ShrinkingGC(JSRuntime *rt, gcreason::Reason reason)
203 {
204 GC(rt, GC_SHRINK, reason);
205 }
207 JS_FRIEND_API(void)
208 JS::IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis)
209 {
210 GCSlice(rt, GC_NORMAL, reason, millis);
211 }
213 JS_FRIEND_API(void)
214 JS::FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason)
215 {
216 GCFinalSlice(rt, GC_NORMAL, reason);
217 }
219 JS_FRIEND_API(JSPrincipals *)
220 JS_GetCompartmentPrincipals(JSCompartment *compartment)
221 {
222 return compartment->principals;
223 }
225 JS_FRIEND_API(void)
226 JS_SetCompartmentPrincipals(JSCompartment *compartment, JSPrincipals *principals)
227 {
228 // Short circuit if there's no change.
229 if (principals == compartment->principals)
230 return;
232 // Any compartment with the trusted principals -- and there can be
233 // multiple -- is a system compartment.
234 const JSPrincipals *trusted = compartment->runtimeFromMainThread()->trustedPrincipals();
235 bool isSystem = principals && principals == trusted;
237 // Clear out the old principals, if any.
238 if (compartment->principals) {
239 JS_DropPrincipals(compartment->runtimeFromMainThread(), compartment->principals);
240 compartment->principals = nullptr;
241 // We'd like to assert that our new principals is always same-origin
242 // with the old one, but JSPrincipals doesn't give us a way to do that.
243 // But we can at least assert that we're not switching between system
244 // and non-system.
245 JS_ASSERT(compartment->isSystem == isSystem);
246 }
248 // Set up the new principals.
249 if (principals) {
250 JS_HoldPrincipals(principals);
251 compartment->principals = principals;
252 }
254 // Update the system flag.
255 compartment->isSystem = isSystem;
256 }
258 JS_FRIEND_API(bool)
259 JS_WrapPropertyDescriptor(JSContext *cx, JS::MutableHandle<js::PropertyDescriptor> desc)
260 {
261 return cx->compartment()->wrap(cx, desc);
262 }
264 JS_FRIEND_API(bool)
265 JS_WrapAutoIdVector(JSContext *cx, js::AutoIdVector &props)
266 {
267 return cx->compartment()->wrap(cx, props);
268 }
270 JS_FRIEND_API(void)
271 JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape)
272 {
273 MarkCycleCollectorChildren(trc, static_cast<Shape *>(shape));
274 }
276 static bool
277 DefineHelpProperty(JSContext *cx, HandleObject obj, const char *prop, const char *value)
278 {
279 RootedAtom atom(cx, Atomize(cx, value, strlen(value)));
280 if (!atom)
281 return false;
282 return JS_DefineProperty(cx, obj, prop, atom, JSPROP_READONLY | JSPROP_PERMANENT,
283 JS_PropertyStub, JS_StrictPropertyStub);
284 }
286 JS_FRIEND_API(bool)
287 JS_DefineFunctionsWithHelp(JSContext *cx, HandleObject obj, const JSFunctionSpecWithHelp *fs)
288 {
289 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
291 CHECK_REQUEST(cx);
292 assertSameCompartment(cx, obj);
293 for (; fs->name; fs++) {
294 JSAtom *atom = Atomize(cx, fs->name, strlen(fs->name));
295 if (!atom)
296 return false;
298 Rooted<jsid> id(cx, AtomToId(atom));
299 RootedFunction fun(cx, DefineFunction(cx, obj, id, fs->call, fs->nargs, fs->flags));
300 if (!fun)
301 return false;
303 if (fs->usage) {
304 if (!DefineHelpProperty(cx, fun, "usage", fs->usage))
305 return false;
306 }
308 if (fs->help) {
309 if (!DefineHelpProperty(cx, fun, "help", fs->help))
310 return false;
311 }
312 }
314 return true;
315 }
317 JS_FRIEND_API(bool)
318 js_ObjectClassIs(JSContext *cx, HandleObject obj, ESClassValue classValue)
319 {
320 return ObjectClassIs(obj, classValue, cx);
321 }
323 JS_FRIEND_API(const char *)
324 js_ObjectClassName(JSContext *cx, HandleObject obj)
325 {
326 return JSObject::className(cx, obj);
327 }
329 JS_FRIEND_API(JS::Zone *)
330 js::GetCompartmentZone(JSCompartment *comp)
331 {
332 return comp->zone();
333 }
335 JS_FRIEND_API(bool)
336 js::IsSystemCompartment(JSCompartment *comp)
337 {
338 return comp->isSystem;
339 }
341 JS_FRIEND_API(bool)
342 js::IsSystemZone(Zone *zone)
343 {
344 return zone->isSystem;
345 }
347 JS_FRIEND_API(bool)
348 js::IsAtomsCompartment(JSCompartment *comp)
349 {
350 return comp->runtimeFromAnyThread()->isAtomsCompartment(comp);
351 }
353 JS_FRIEND_API(bool)
354 js::IsInNonStrictPropertySet(JSContext *cx)
355 {
356 jsbytecode *pc;
357 JSScript *script = cx->currentScript(&pc, JSContext::ALLOW_CROSS_COMPARTMENT);
358 return script && !script->strict() && (js_CodeSpec[*pc].format & JOF_SET);
359 }
361 JS_FRIEND_API(bool)
362 js::IsFunctionObject(JSObject *obj)
363 {
364 return obj->is<JSFunction>();
365 }
367 JS_FRIEND_API(bool)
368 js::IsScopeObject(JSObject *obj)
369 {
370 return obj->is<ScopeObject>();
371 }
373 JS_FRIEND_API(bool)
374 js::IsCallObject(JSObject *obj)
375 {
376 return obj->is<CallObject>();
377 }
379 JS_FRIEND_API(JSObject *)
380 js::GetObjectParentMaybeScope(JSObject *obj)
381 {
382 return obj->enclosingScope();
383 }
385 JS_FRIEND_API(JSObject *)
386 js::GetGlobalForObjectCrossCompartment(JSObject *obj)
387 {
388 return &obj->global();
389 }
391 JS_FRIEND_API(void)
392 js::SetPendingExceptionCrossContext(JSContext *cx, JS::HandleValue v)
393 {
394 cx->setPendingException(v);
395 }
397 JS_FRIEND_API(void)
398 js::AssertSameCompartment(JSContext *cx, JSObject *obj)
399 {
400 assertSameCompartment(cx, obj);
401 }
403 #ifdef DEBUG
404 JS_FRIEND_API(void)
405 js::AssertSameCompartment(JSObject *objA, JSObject *objB)
406 {
407 JS_ASSERT(objA->compartment() == objB->compartment());
408 }
409 #endif
411 JS_FRIEND_API(JSObject *)
412 js::DefaultObjectForContextOrNull(JSContext *cx)
413 {
414 if (cx->options().noDefaultCompartmentObject())
415 return nullptr;
416 return cx->maybeDefaultCompartmentObject();
417 }
419 JS_FRIEND_API(void)
420 js::SetDefaultObjectForContext(JSContext *cx, JSObject *obj)
421 {
422 cx->setDefaultCompartmentObject(obj);
423 }
425 JS_FRIEND_API(void)
426 js::NotifyAnimationActivity(JSObject *obj)
427 {
428 obj->compartment()->lastAnimationTime = PRMJ_Now();
429 }
431 JS_FRIEND_API(uint32_t)
432 js::GetObjectSlotSpan(JSObject *obj)
433 {
434 return obj->slotSpan();
435 }
437 JS_FRIEND_API(bool)
438 js::IsObjectInContextCompartment(JSObject *obj, const JSContext *cx)
439 {
440 return obj->compartment() == cx->compartment();
441 }
443 JS_FRIEND_API(bool)
444 js::RunningWithTrustedPrincipals(JSContext *cx)
445 {
446 return cx->runningWithTrustedPrincipals();
447 }
449 JS_FRIEND_API(JSScript *)
450 js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx)
451 {
452 ScriptFrameIter iter(cx);
453 if (iter.done())
454 return nullptr;
456 if (!iter.isFunctionFrame())
457 return nullptr;
459 RootedFunction scriptedCaller(cx, iter.callee());
460 RootedScript outermost(cx, scriptedCaller->nonLazyScript());
461 for (StaticScopeIter<NoGC> i(scriptedCaller); !i.done(); i++) {
462 if (i.type() == StaticScopeIter<NoGC>::FUNCTION)
463 outermost = i.funScript();
464 }
465 return outermost;
466 }
468 JS_FRIEND_API(JSFunction *)
469 js::DefineFunctionWithReserved(JSContext *cx, JSObject *objArg, const char *name, JSNative call,
470 unsigned nargs, unsigned attrs)
471 {
472 RootedObject obj(cx, objArg);
473 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
474 CHECK_REQUEST(cx);
475 assertSameCompartment(cx, obj);
476 JSAtom *atom = Atomize(cx, name, strlen(name));
477 if (!atom)
478 return nullptr;
479 Rooted<jsid> id(cx, AtomToId(atom));
480 return DefineFunction(cx, obj, id, call, nargs, attrs, JSFunction::ExtendedFinalizeKind);
481 }
483 JS_FRIEND_API(JSFunction *)
484 js::NewFunctionWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
485 JSObject *parentArg, const char *name)
486 {
487 RootedObject parent(cx, parentArg);
488 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
490 CHECK_REQUEST(cx);
491 assertSameCompartment(cx, parent);
493 RootedAtom atom(cx);
494 if (name) {
495 atom = Atomize(cx, name, strlen(name));
496 if (!atom)
497 return nullptr;
498 }
500 JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
501 return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom,
502 JSFunction::ExtendedFinalizeKind);
503 }
505 JS_FRIEND_API(JSFunction *)
506 js::NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parentArg,
507 jsid id)
508 {
509 RootedObject parent(cx, parentArg);
510 JS_ASSERT(JSID_IS_STRING(id));
511 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
512 CHECK_REQUEST(cx);
513 assertSameCompartment(cx, parent);
515 RootedAtom atom(cx, JSID_TO_ATOM(id));
516 JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
517 return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom,
518 JSFunction::ExtendedFinalizeKind);
519 }
521 JS_FRIEND_API(JSObject *)
522 js::InitClassWithReserved(JSContext *cx, JSObject *objArg, JSObject *parent_protoArg,
523 const JSClass *clasp, JSNative constructor, unsigned nargs,
524 const JSPropertySpec *ps, const JSFunctionSpec *fs,
525 const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs)
526 {
527 RootedObject obj(cx, objArg);
528 RootedObject parent_proto(cx, parent_protoArg);
529 CHECK_REQUEST(cx);
530 assertSameCompartment(cx, obj, parent_proto);
531 return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor,
532 nargs, ps, fs, static_ps, static_fs, nullptr,
533 JSFunction::ExtendedFinalizeKind);
534 }
536 JS_FRIEND_API(const Value &)
537 js::GetFunctionNativeReserved(JSObject *fun, size_t which)
538 {
539 JS_ASSERT(fun->as<JSFunction>().isNative());
540 return fun->as<JSFunction>().getExtendedSlot(which);
541 }
543 JS_FRIEND_API(void)
544 js::SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val)
545 {
546 JS_ASSERT(fun->as<JSFunction>().isNative());
547 MOZ_ASSERT_IF(val.isObject(), val.toObject().compartment() == fun->compartment());
548 fun->as<JSFunction>().setExtendedSlot(which, val);
549 }
551 JS_FRIEND_API(bool)
552 js::GetObjectProto(JSContext *cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JSObject*> proto)
553 {
554 if (IsProxy(obj))
555 return JS_GetPrototype(cx, obj, proto);
557 proto.set(reinterpret_cast<const shadow::Object*>(obj.get())->type->proto);
558 return true;
559 }
561 JS_FRIEND_API(bool)
562 js::GetOriginalEval(JSContext *cx, HandleObject scope, MutableHandleObject eval)
563 {
564 assertSameCompartment(cx, scope);
565 Rooted<GlobalObject *> global(cx, &scope->global());
566 return GlobalObject::getOrCreateEval(cx, global, eval);
567 }
569 JS_FRIEND_API(void)
570 js::SetReservedSlotWithBarrier(JSObject *obj, size_t slot, const js::Value &value)
571 {
572 obj->setSlot(slot, value);
573 }
575 JS_FRIEND_API(bool)
576 js::GetGeneric(JSContext *cx, JSObject *objArg, JSObject *receiverArg, jsid idArg,
577 Value *vp)
578 {
579 RootedObject obj(cx, objArg), receiver(cx, receiverArg);
580 RootedId id(cx, idArg);
581 RootedValue value(cx);
582 if (!JSObject::getGeneric(cx, obj, receiver, id, &value))
583 return false;
584 *vp = value;
585 return true;
586 }
588 void
589 js::SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback)
590 {
591 rt->preserveWrapperCallback = callback;
592 }
594 /*
595 * The below code is for temporary telemetry use. It can be removed when
596 * sufficient data has been harvested.
597 */
599 namespace js {
600 // Defined in vm/GlobalObject.cpp.
601 extern size_t sSetProtoCalled;
602 }
604 JS_FRIEND_API(size_t)
605 JS_SetProtoCalled(JSContext *)
606 {
607 return sSetProtoCalled;
608 }
610 // Defined in jsiter.cpp.
611 extern size_t sCustomIteratorCount;
613 JS_FRIEND_API(size_t)
614 JS_GetCustomIteratorCount(JSContext *cx)
615 {
616 return sCustomIteratorCount;
617 }
619 JS_FRIEND_API(bool)
620 JS_IsDeadWrapper(JSObject *obj)
621 {
622 if (!obj->is<ProxyObject>()) {
623 return false;
624 }
626 return obj->as<ProxyObject>().handler()->family() == &DeadObjectProxy::sDeadObjectFamily;
627 }
629 void
630 js::TraceWeakMaps(WeakMapTracer *trc)
631 {
632 WeakMapBase::traceAllMappings(trc);
633 WatchpointMap::traceAll(trc);
634 }
636 extern JS_FRIEND_API(bool)
637 js::AreGCGrayBitsValid(JSRuntime *rt)
638 {
639 return rt->gcGrayBitsValid;
640 }
642 JS_FRIEND_API(bool)
643 js::ZoneGlobalsAreAllGray(JS::Zone *zone)
644 {
645 for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
646 JSObject *obj = comp->maybeGlobal();
647 if (!obj || !JS::GCThingIsMarkedGray(obj))
648 return false;
649 }
650 return true;
651 }
653 JS_FRIEND_API(JSGCTraceKind)
654 js::GCThingTraceKind(void *thing)
655 {
656 JS_ASSERT(thing);
657 return gc::GetGCThingTraceKind(thing);
658 }
660 JS_FRIEND_API(void)
661 js::VisitGrayWrapperTargets(Zone *zone, GCThingCallback callback, void *closure)
662 {
663 JSRuntime *rt = zone->runtimeFromMainThread();
664 for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
665 for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
666 gc::Cell *thing = e.front().key().wrapped;
667 if (!IsInsideNursery(rt, thing) && thing->isMarked(gc::GRAY))
668 callback(closure, thing);
669 }
670 }
671 }
673 JS_FRIEND_API(JSObject *)
674 js::GetWeakmapKeyDelegate(JSObject *key)
675 {
676 if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp)
677 return op(key);
678 return nullptr;
679 }
681 JS_FRIEND_API(void)
682 JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback)
683 {
684 rt->telemetryCallback = callback;
685 }
687 JS_FRIEND_API(JSObject *)
688 JS_CloneObject(JSContext *cx, HandleObject obj, HandleObject protoArg, HandleObject parent)
689 {
690 Rooted<js::TaggedProto> proto(cx, protoArg.get());
691 return CloneObject(cx, obj, proto, parent);
692 }
694 #ifdef DEBUG
695 JS_FRIEND_API(void)
696 js_DumpString(JSString *str)
697 {
698 str->dump();
699 }
701 JS_FRIEND_API(void)
702 js_DumpAtom(JSAtom *atom)
703 {
704 atom->dump();
705 }
707 JS_FRIEND_API(void)
708 js_DumpChars(const jschar *s, size_t n)
709 {
710 fprintf(stderr, "jschar * (%p) = ", (void *) s);
711 JSString::dumpChars(s, n);
712 fputc('\n', stderr);
713 }
715 JS_FRIEND_API(void)
716 js_DumpObject(JSObject *obj)
717 {
718 if (!obj) {
719 fprintf(stderr, "NULL\n");
720 return;
721 }
722 obj->dump();
723 }
725 #endif
727 struct DumpHeapTracer : public JSTracer
728 {
729 FILE *output;
731 DumpHeapTracer(FILE *fp, JSRuntime *rt, JSTraceCallback callback,
732 WeakMapTraceKind weakTraceKind)
733 : JSTracer(rt, callback, weakTraceKind), output(fp)
734 {}
735 };
737 static char
738 MarkDescriptor(void *thing)
739 {
740 gc::Cell *cell = static_cast<gc::Cell*>(thing);
741 if (cell->isMarked(gc::BLACK))
742 return cell->isMarked(gc::GRAY) ? 'G' : 'B';
743 else
744 return cell->isMarked(gc::GRAY) ? 'X' : 'W';
745 }
747 static void
748 DumpHeapVisitZone(JSRuntime *rt, void *data, Zone *zone)
749 {
750 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
751 fprintf(dtrc->output, "# zone %p\n", (void *)zone);
752 }
754 static void
755 DumpHeapVisitCompartment(JSRuntime *rt, void *data, JSCompartment *comp)
756 {
757 char name[1024];
758 if (rt->compartmentNameCallback)
759 (*rt->compartmentNameCallback)(rt, comp, name, sizeof(name));
760 else
761 strcpy(name, "<unknown>");
763 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
764 fprintf(dtrc->output, "# compartment %s [in zone %p]\n", name, (void *)comp->zone());
765 }
767 static void
768 DumpHeapVisitArena(JSRuntime *rt, void *data, gc::Arena *arena,
769 JSGCTraceKind traceKind, size_t thingSize)
770 {
771 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
772 fprintf(dtrc->output, "# arena allockind=%u size=%u\n",
773 unsigned(arena->aheader.getAllocKind()), unsigned(thingSize));
774 }
776 static void
777 DumpHeapVisitCell(JSRuntime *rt, void *data, void *thing,
778 JSGCTraceKind traceKind, size_t thingSize)
779 {
780 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data);
781 char cellDesc[1024 * 32];
782 JS_GetTraceThingInfo(cellDesc, sizeof(cellDesc), dtrc, thing, traceKind, true);
783 fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing), cellDesc);
784 JS_TraceChildren(dtrc, thing, traceKind);
785 }
787 static void
788 DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind)
789 {
790 if (gc::IsInsideNursery(trc->runtime(), *thingp))
791 return;
793 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(trc);
794 char buffer[1024];
795 fprintf(dtrc->output, "> %p %c %s\n", *thingp, MarkDescriptor(*thingp),
796 dtrc->getTracingEdgeName(buffer, sizeof(buffer)));
797 }
799 static void
800 DumpHeapVisitRoot(JSTracer *trc, void **thingp, JSGCTraceKind kind)
801 {
802 if (gc::IsInsideNursery(trc->runtime(), *thingp))
803 return;
805 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(trc);
806 char buffer[1024];
807 fprintf(dtrc->output, "%p %c %s\n", *thingp, MarkDescriptor(*thingp),
808 dtrc->getTracingEdgeName(buffer, sizeof(buffer)));
809 }
811 void
812 js::DumpHeapComplete(JSRuntime *rt, FILE *fp, js::DumpHeapNurseryBehaviour nurseryBehaviour)
813 {
814 #ifdef JSGC_GENERATIONAL
815 if (nurseryBehaviour == js::CollectNurseryBeforeDump)
816 MinorGC(rt, JS::gcreason::API);
817 #endif
819 DumpHeapTracer dtrc(fp, rt, DumpHeapVisitRoot, TraceWeakMapKeysValues);
820 TraceRuntime(&dtrc);
822 fprintf(dtrc.output, "==========\n");
824 dtrc.setTraceCallback(DumpHeapVisitChild);
825 IterateZonesCompartmentsArenasCells(rt, &dtrc,
826 DumpHeapVisitZone,
827 DumpHeapVisitCompartment,
828 DumpHeapVisitArena,
829 DumpHeapVisitCell);
831 fflush(dtrc.output);
832 }
834 JS_FRIEND_API(const JSStructuredCloneCallbacks *)
835 js::GetContextStructuredCloneCallbacks(JSContext *cx)
836 {
837 return cx->runtime()->structuredCloneCallbacks;
838 }
840 #ifdef JS_THREADSAFE
841 JS_FRIEND_API(bool)
842 js::ContextHasOutstandingRequests(const JSContext *cx)
843 {
844 return cx->outstandingRequests > 0;
845 }
846 #endif
848 JS_FRIEND_API(void)
849 js::SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg)
850 {
851 rt->activityCallback = cb;
852 rt->activityCallbackArg = arg;
853 }
855 JS_FRIEND_API(bool)
856 js::IsContextRunningJS(JSContext *cx)
857 {
858 return cx->currentlyRunning();
859 }
861 JS_FRIEND_API(JS::GCSliceCallback)
862 JS::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
863 {
864 JS::GCSliceCallback old = rt->gcSliceCallback;
865 rt->gcSliceCallback = callback;
866 return old;
867 }
869 JS_FRIEND_API(bool)
870 JS::WasIncrementalGC(JSRuntime *rt)
871 {
872 return rt->gcIsIncremental;
873 }
875 jschar *
876 GCDescription::formatMessage(JSRuntime *rt) const
877 {
878 return rt->gcStats.formatMessage();
879 }
881 jschar *
882 GCDescription::formatJSON(JSRuntime *rt, uint64_t timestamp) const
883 {
884 return rt->gcStats.formatJSON(timestamp);
885 }
887 JS_FRIEND_API(void)
888 JS::NotifyDidPaint(JSRuntime *rt)
889 {
890 if (rt->gcZeal() == gc::ZealFrameVerifierPreValue) {
891 gc::VerifyBarriers(rt, gc::PreBarrierVerifier);
892 return;
893 }
895 if (rt->gcZeal() == gc::ZealFrameVerifierPostValue) {
896 gc::VerifyBarriers(rt, gc::PostBarrierVerifier);
897 return;
898 }
900 if (rt->gcZeal() == gc::ZealFrameGCValue) {
901 PrepareForFullGC(rt);
902 GCSlice(rt, GC_NORMAL, gcreason::REFRESH_FRAME);
903 return;
904 }
906 if (JS::IsIncrementalGCInProgress(rt) && !rt->gcInterFrameGC) {
907 JS::PrepareForIncrementalGC(rt);
908 GCSlice(rt, GC_NORMAL, gcreason::REFRESH_FRAME);
909 }
911 rt->gcInterFrameGC = false;
912 }
914 JS_FRIEND_API(bool)
915 JS::IsIncrementalGCEnabled(JSRuntime *rt)
916 {
917 return rt->gcIncrementalEnabled && rt->gcMode() == JSGC_MODE_INCREMENTAL;
918 }
920 JS_FRIEND_API(bool)
921 JS::IsIncrementalGCInProgress(JSRuntime *rt)
922 {
923 return rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcVerifyPreData;
924 }
926 JS_FRIEND_API(void)
927 JS::DisableIncrementalGC(JSRuntime *rt)
928 {
929 rt->gcIncrementalEnabled = false;
930 }
932 JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt)
933 : runtime(rt)
934 #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
935 , restartVerifier(rt->gcVerifyPostData)
936 #endif
937 {
938 #ifdef JSGC_GENERATIONAL
939 if (IsGenerationalGCEnabled(rt)) {
940 #ifdef JS_GC_ZEAL
941 if (restartVerifier)
942 gc::EndVerifyPostBarriers(rt);
943 #endif
944 MinorGC(rt, JS::gcreason::API);
945 rt->gcNursery.disable();
946 rt->gcStoreBuffer.disable();
947 }
948 #endif
949 ++rt->gcGenerationalDisabled;
950 }
952 JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC()
953 {
954 JS_ASSERT(runtime->gcGenerationalDisabled > 0);
955 --runtime->gcGenerationalDisabled;
956 #ifdef JSGC_GENERATIONAL
957 if (runtime->gcGenerationalDisabled == 0) {
958 runtime->gcNursery.enable();
959 runtime->gcStoreBuffer.enable();
960 #ifdef JS_GC_ZEAL
961 if (restartVerifier)
962 gc::StartVerifyPostBarriers(runtime);
963 #endif
964 }
965 #endif
966 }
968 extern JS_FRIEND_API(bool)
969 JS::IsGenerationalGCEnabled(JSRuntime *rt)
970 {
971 return rt->gcGenerationalDisabled == 0;
972 }
974 JS_FRIEND_API(bool)
975 JS::IsIncrementalBarrierNeeded(JSRuntime *rt)
976 {
977 return rt->gcIncrementalState == gc::MARK && !rt->isHeapBusy();
978 }
980 JS_FRIEND_API(bool)
981 JS::IsIncrementalBarrierNeeded(JSContext *cx)
982 {
983 return IsIncrementalBarrierNeeded(cx->runtime());
984 }
986 JS_FRIEND_API(void)
987 JS::IncrementalObjectBarrier(JSObject *obj)
988 {
989 if (!obj)
990 return;
992 JS_ASSERT(!obj->zone()->runtimeFromMainThread()->isHeapMajorCollecting());
994 AutoMarkInDeadZone amn(obj->zone());
996 JSObject::writeBarrierPre(obj);
997 }
999 JS_FRIEND_API(void)
1000 JS::IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind)
1001 {
1002 if (!ptr)
1003 return;
1005 if (kind == JSTRACE_STRING && StringIsPermanentAtom(static_cast<JSString *>(ptr)))
1006 return;
1008 gc::Cell *cell = static_cast<gc::Cell *>(ptr);
1009 Zone *zone = kind == JSTRACE_OBJECT
1010 ? static_cast<JSObject *>(cell)->zone()
1011 : cell->tenuredZone();
1013 JS_ASSERT(!zone->runtimeFromMainThread()->isHeapMajorCollecting());
1015 AutoMarkInDeadZone amn(zone);
1017 if (kind == JSTRACE_OBJECT)
1018 JSObject::writeBarrierPre(static_cast<JSObject*>(cell));
1019 else if (kind == JSTRACE_STRING)
1020 JSString::writeBarrierPre(static_cast<JSString*>(cell));
1021 else if (kind == JSTRACE_SCRIPT)
1022 JSScript::writeBarrierPre(static_cast<JSScript*>(cell));
1023 else if (kind == JSTRACE_LAZY_SCRIPT)
1024 LazyScript::writeBarrierPre(static_cast<LazyScript*>(cell));
1025 else if (kind == JSTRACE_SHAPE)
1026 Shape::writeBarrierPre(static_cast<Shape*>(cell));
1027 else if (kind == JSTRACE_BASE_SHAPE)
1028 BaseShape::writeBarrierPre(static_cast<BaseShape*>(cell));
1029 else if (kind == JSTRACE_TYPE_OBJECT)
1030 types::TypeObject::writeBarrierPre((types::TypeObject *) ptr);
1031 else
1032 MOZ_ASSUME_UNREACHABLE("invalid trace kind");
1033 }
1035 JS_FRIEND_API(void)
1036 JS::IncrementalValueBarrier(const Value &v)
1037 {
1038 js::HeapValue::writeBarrierPre(v);
1039 }
1041 JS_FRIEND_API(void)
1042 JS::PokeGC(JSRuntime *rt)
1043 {
1044 rt->gcPoke = true;
1045 }
1047 JS_FRIEND_API(JSCompartment *)
1048 js::GetAnyCompartmentInZone(JS::Zone *zone)
1049 {
1050 CompartmentsInZoneIter comp(zone);
1051 JS_ASSERT(!comp.done());
1052 return comp.get();
1053 }
1055 bool
1056 JS::ObjectPtr::isAboutToBeFinalized()
1057 {
1058 return JS_IsAboutToBeFinalized(&value);
1059 }
1061 void
1062 JS::ObjectPtr::trace(JSTracer *trc, const char *name)
1063 {
1064 JS_CallHeapObjectTracer(trc, &value, name);
1065 }
1067 JS_FRIEND_API(JSObject *)
1068 js::GetTestingFunctions(JSContext *cx)
1069 {
1070 RootedObject obj(cx, JS_NewObject(cx, nullptr, NullPtr(), NullPtr()));
1071 if (!obj)
1072 return nullptr;
1074 if (!DefineTestingFunctions(cx, obj, false))
1075 return nullptr;
1077 return obj;
1078 }
1080 #ifdef DEBUG
1081 JS_FRIEND_API(unsigned)
1082 js::GetEnterCompartmentDepth(JSContext *cx)
1083 {
1084 return cx->getEnterCompartmentDepth();
1085 }
1086 #endif
1088 JS_FRIEND_API(void)
1089 js::SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks)
1090 {
1091 rt->DOMcallbacks = callbacks;
1092 }
1094 JS_FRIEND_API(const DOMCallbacks *)
1095 js::GetDOMCallbacks(JSRuntime *rt)
1096 {
1097 return rt->DOMcallbacks;
1098 }
1100 static const void *gDOMProxyHandlerFamily = nullptr;
1101 static uint32_t gDOMProxyExpandoSlot = 0;
1102 static DOMProxyShadowsCheck gDOMProxyShadowsCheck;
1104 JS_FRIEND_API(void)
1105 js::SetDOMProxyInformation(const void *domProxyHandlerFamily, uint32_t domProxyExpandoSlot,
1106 DOMProxyShadowsCheck domProxyShadowsCheck)
1107 {
1108 gDOMProxyHandlerFamily = domProxyHandlerFamily;
1109 gDOMProxyExpandoSlot = domProxyExpandoSlot;
1110 gDOMProxyShadowsCheck = domProxyShadowsCheck;
1111 }
1113 const void *
1114 js::GetDOMProxyHandlerFamily()
1115 {
1116 return gDOMProxyHandlerFamily;
1117 }
1119 uint32_t
1120 js::GetDOMProxyExpandoSlot()
1121 {
1122 return gDOMProxyExpandoSlot;
1123 }
1125 DOMProxyShadowsCheck
1126 js::GetDOMProxyShadowsCheck()
1127 {
1128 return gDOMProxyShadowsCheck;
1129 }
1131 bool
1132 js::detail::IdMatchesAtom(jsid id, JSAtom *atom)
1133 {
1134 return id == INTERNED_STRING_TO_JSID(nullptr, atom);
1135 }
1137 JS_FRIEND_API(JSContext *)
1138 js::DefaultJSContext(JSRuntime *rt)
1139 {
1140 if (rt->defaultJSContextCallback) {
1141 JSContext *cx = rt->defaultJSContextCallback(rt);
1142 JS_ASSERT(cx);
1143 return cx;
1144 }
1145 JS_ASSERT(rt->contextList.getFirst() == rt->contextList.getLast());
1146 return rt->contextList.getFirst();
1147 }
1149 JS_FRIEND_API(void)
1150 js::SetDefaultJSContextCallback(JSRuntime *rt, DefaultJSContextCallback cb)
1151 {
1152 rt->defaultJSContextCallback = cb;
1153 }
1155 #ifdef DEBUG
1156 JS_FRIEND_API(void)
1157 js::Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx)
1158 {
1159 rt->activeContext = cx;
1160 }
1161 #endif
1163 JS_FRIEND_API(void)
1164 js::SetCTypesActivityCallback(JSRuntime *rt, CTypesActivityCallback cb)
1165 {
1166 rt->ctypesActivityCallback = cb;
1167 }
1169 js::AutoCTypesActivityCallback::AutoCTypesActivityCallback(JSContext *cx,
1170 js::CTypesActivityType beginType,
1171 js::CTypesActivityType endType
1172 MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
1173 : cx(cx), callback(cx->runtime()->ctypesActivityCallback), endType(endType)
1174 {
1175 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1177 if (callback)
1178 callback(cx, beginType);
1179 }
1181 JS_FRIEND_API(void)
1182 js::SetObjectMetadataCallback(JSContext *cx, ObjectMetadataCallback callback)
1183 {
1184 cx->compartment()->setObjectMetadataCallback(callback);
1185 }
1187 JS_FRIEND_API(bool)
1188 js::SetObjectMetadata(JSContext *cx, HandleObject obj, HandleObject metadata)
1189 {
1190 return JSObject::setMetadata(cx, obj, metadata);
1191 }
1193 JS_FRIEND_API(JSObject *)
1194 js::GetObjectMetadata(JSObject *obj)
1195 {
1196 return obj->getMetadata();
1197 }
1199 JS_FRIEND_API(void)
1200 js::UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value)
1201 {
1202 JS_ASSERT(obj->isNative());
1203 JS_ASSERT(index < obj->getDenseInitializedLength());
1204 obj->setDenseElementWithType(cx, index, value);
1205 }
1207 JS_FRIEND_API(bool)
1208 js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg,
1209 JS::Handle<js::PropertyDescriptor> descriptor, bool *bp)
1210 {
1211 RootedObject obj(cx, objArg);
1212 RootedId id(cx, idArg);
1213 JS_ASSERT(cx->runtime()->heapState == js::Idle);
1214 CHECK_REQUEST(cx);
1215 assertSameCompartment(cx, obj, id, descriptor.value());
1216 if (descriptor.hasGetterObject())
1217 assertSameCompartment(cx, descriptor.getterObject());
1218 if (descriptor.hasSetterObject())
1219 assertSameCompartment(cx, descriptor.setterObject());
1221 return DefineOwnProperty(cx, HandleObject(obj), id, descriptor, bp);
1222 }
1224 JS_FRIEND_API(bool)
1225 js_ReportIsNotFunction(JSContext *cx, JS::HandleValue v)
1226 {
1227 return ReportIsNotFunction(cx, v);
1228 }
1230 #ifdef DEBUG
1231 JS_PUBLIC_API(bool)
1232 js::IsInRequest(JSContext *cx)
1233 {
1234 #ifdef JS_THREADSAFE
1235 return !!cx->runtime()->requestDepth;
1236 #else
1237 return true;
1238 #endif
1239 }
1240 #endif
1242 #ifdef JSGC_GENERATIONAL
1243 JS_FRIEND_API(void)
1244 JS_StoreObjectPostBarrierCallback(JSContext* cx,
1245 void (*callback)(JSTracer *trc, JSObject *key, void *data),
1246 JSObject *key, void *data)
1247 {
1248 JSRuntime *rt = cx->runtime();
1249 if (IsInsideNursery(rt, key))
1250 rt->gcStoreBuffer.putCallback(callback, key, data);
1251 }
1253 extern JS_FRIEND_API(void)
1254 JS_StoreStringPostBarrierCallback(JSContext* cx,
1255 void (*callback)(JSTracer *trc, JSString *key, void *data),
1256 JSString *key, void *data)
1257 {
1258 JSRuntime *rt = cx->runtime();
1259 if (IsInsideNursery(rt, key))
1260 rt->gcStoreBuffer.putCallback(callback, key, data);
1261 }
1262 #endif /* JSGC_GENERATIONAL */