1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=4 sw=4 et tw=99:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is SpiderMonkey code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Mozilla Foundation
21 : * Portions created by the Initial Developer are Copyright (C) 2010
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "mozilla/GuardObjects.h"
41 : #include "mozilla/StandardInteger.h"
42 :
43 : #include "jscntxt.h"
44 : #include "jscompartment.h"
45 : #include "jsfriendapi.h"
46 : #include "jswrapper.h"
47 : #include "jsweakmap.h"
48 : #include "jswatchpoint.h"
49 :
50 : #include "builtin/TestingFunctions.h"
51 :
52 : #include "jsobjinlines.h"
53 :
54 : using namespace js;
55 : using namespace JS;
56 :
57 : JS_FRIEND_API(void)
58 0 : JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
59 : {
60 0 : rt->gcGrayRootsTraceOp = traceOp;
61 0 : rt->gcGrayRootsData = data;
62 0 : }
63 :
64 : JS_FRIEND_API(JSString *)
65 0 : JS_GetAnonymousString(JSRuntime *rt)
66 : {
67 0 : JS_ASSERT(rt->hasContexts());
68 0 : return rt->atomState.anonymousAtom;
69 : }
70 :
71 : JS_FRIEND_API(JSObject *)
72 0 : JS_FindCompilationScope(JSContext *cx, JSObject *obj)
73 : {
74 : /*
75 : * We unwrap wrappers here. This is a little weird, but it's what's being
76 : * asked of us.
77 : */
78 0 : if (obj->isWrapper())
79 0 : obj = UnwrapObject(obj);
80 :
81 : /*
82 : * Innerize the target_obj so that we compile in the correct (inner)
83 : * scope.
84 : */
85 0 : if (JSObjectOp op = obj->getClass()->ext.innerObject)
86 0 : obj = op(cx, obj);
87 0 : return obj;
88 : }
89 :
90 : JS_FRIEND_API(JSFunction *)
91 19 : JS_GetObjectFunction(JSObject *obj)
92 : {
93 19 : if (obj->isFunction())
94 19 : return obj->toFunction();
95 0 : return NULL;
96 : }
97 :
98 : JS_FRIEND_API(JSObject *)
99 0 : JS_GetGlobalForFrame(JSStackFrame *fp)
100 : {
101 0 : return &Valueify(fp)->scopeChain().global();
102 : }
103 :
104 : JS_FRIEND_API(JSBool)
105 0 : JS_SplicePrototype(JSContext *cx, JSObject *obj, JSObject *proto)
106 : {
107 : /*
108 : * Change the prototype of an object which hasn't been used anywhere
109 : * and does not share its type with another object. Unlike JS_SetPrototype,
110 : * does not nuke type information for the object.
111 : */
112 0 : CHECK_REQUEST(cx);
113 :
114 0 : if (!obj->hasSingletonType()) {
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 : return obj->splicePrototype(cx, proto);
123 : }
124 :
125 : JS_FRIEND_API(JSObject *)
126 0 : JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
127 : {
128 0 : JSObject *obj = JS_NewObject(cx, clasp, proto, parent);
129 0 : if (!obj || !obj->setSingletonType(cx))
130 0 : return NULL;
131 0 : return obj;
132 : }
133 :
134 : JS_FRIEND_API(void)
135 97849 : js::PrepareCompartmentForGC(JSCompartment *comp)
136 : {
137 97849 : comp->scheduleGC();
138 97849 : }
139 :
140 : JS_FRIEND_API(void)
141 38323 : js::PrepareForFullGC(JSRuntime *rt)
142 : {
143 121937 : for (CompartmentsIter c(rt); !c.done(); c.next())
144 83614 : c->scheduleGC();
145 38323 : }
146 :
147 : JS_FRIEND_API(void)
148 8732 : js::GCForReason(JSContext *cx, gcreason::Reason reason)
149 : {
150 8732 : GC(cx, GC_NORMAL, reason);
151 8732 : }
152 :
153 : JS_FRIEND_API(void)
154 0 : js::ShrinkingGC(JSContext *cx, gcreason::Reason reason)
155 : {
156 0 : GC(cx, GC_SHRINK, reason);
157 0 : }
158 :
159 : JS_FRIEND_API(void)
160 0 : js::IncrementalGC(JSContext *cx, gcreason::Reason reason)
161 : {
162 0 : GCSlice(cx, GC_NORMAL, reason);
163 0 : }
164 :
165 : JS_FRIEND_API(void)
166 0 : JS_ShrinkGCBuffers(JSRuntime *rt)
167 : {
168 0 : ShrinkGCBuffers(rt);
169 0 : }
170 :
171 : JS_FRIEND_API(JSPrincipals *)
172 0 : JS_GetCompartmentPrincipals(JSCompartment *compartment)
173 : {
174 0 : return compartment->principals;
175 : }
176 :
177 : JS_FRIEND_API(JSBool)
178 0 : JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc)
179 : {
180 0 : return cx->compartment->wrap(cx, desc);
181 : }
182 :
183 : JS_FRIEND_API(void)
184 0 : JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape)
185 : {
186 0 : MarkCycleCollectorChildren(trc, (Shape *)shape);
187 0 : }
188 :
189 : static bool
190 3639168 : DefineHelpProperty(JSContext *cx, JSObject *obj, const char *prop, const char *value)
191 : {
192 3639168 : JSAtom *atom = js_Atomize(cx, value, strlen(value));
193 3639168 : if (!atom)
194 0 : return false;
195 3639168 : jsval v = STRING_TO_JSVAL(atom);
196 : return JS_DefineProperty(cx, obj, prop, v,
197 : JS_PropertyStub, JS_StrictPropertyStub,
198 3639168 : JSPROP_READONLY | JSPROP_PERMANENT);
199 : }
200 :
201 : JS_FRIEND_API(bool)
202 46656 : JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj, const JSFunctionSpecWithHelp *fs)
203 : {
204 93312 : RootObject objRoot(cx, &obj);
205 :
206 46656 : JS_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
207 :
208 93312 : CHECK_REQUEST(cx);
209 46656 : assertSameCompartment(cx, obj);
210 1866240 : for (; fs->name; fs++) {
211 1819584 : JSAtom *atom = js_Atomize(cx, fs->name, strlen(fs->name));
212 1819584 : if (!atom)
213 0 : return false;
214 :
215 : JSFunction *fun = js_DefineFunction(cx, objRoot,
216 1819584 : ATOM_TO_JSID(atom), fs->call, fs->nargs, fs->flags);
217 1819584 : if (!fun)
218 0 : return false;
219 :
220 1819584 : if (fs->usage) {
221 1819584 : if (!DefineHelpProperty(cx, fun, "usage", fs->usage))
222 0 : return false;
223 : }
224 :
225 1819584 : if (fs->help) {
226 1819584 : if (!DefineHelpProperty(cx, fun, "help", fs->help))
227 0 : return false;
228 : }
229 : }
230 :
231 46656 : return true;
232 : }
233 :
234 0 : AutoPreserveCompartment::AutoPreserveCompartment(JSContext *cx
235 : JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
236 0 : : cx(cx), oldCompartment(cx->compartment)
237 : {
238 0 : JS_GUARD_OBJECT_NOTIFIER_INIT;
239 0 : }
240 :
241 0 : AutoPreserveCompartment::~AutoPreserveCompartment()
242 : {
243 : /* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
244 0 : cx->compartment = oldCompartment;
245 0 : }
246 :
247 0 : AutoSwitchCompartment::AutoSwitchCompartment(JSContext *cx, JSCompartment *newCompartment
248 : JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
249 0 : : cx(cx), oldCompartment(cx->compartment)
250 : {
251 0 : JS_GUARD_OBJECT_NOTIFIER_INIT;
252 0 : cx->setCompartment(newCompartment);
253 0 : }
254 :
255 0 : AutoSwitchCompartment::AutoSwitchCompartment(JSContext *cx, JSObject *target
256 : JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
257 0 : : cx(cx), oldCompartment(cx->compartment)
258 : {
259 0 : JS_GUARD_OBJECT_NOTIFIER_INIT;
260 0 : cx->setCompartment(target->compartment());
261 0 : }
262 :
263 0 : AutoSwitchCompartment::~AutoSwitchCompartment()
264 : {
265 : /* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
266 0 : cx->compartment = oldCompartment;
267 0 : }
268 :
269 : JS_FRIEND_API(bool)
270 0 : js::IsSystemCompartment(const JSCompartment *c)
271 : {
272 0 : return c->isSystemCompartment;
273 : }
274 :
275 : JS_FRIEND_API(bool)
276 0 : js::IsAtomsCompartment(const JSCompartment *c)
277 : {
278 0 : return c == c->rt->atomsCompartment;
279 : }
280 :
281 : JS_FRIEND_API(bool)
282 0 : js::IsScopeObject(JSObject *obj)
283 : {
284 0 : return obj->isScope();
285 : }
286 :
287 : JS_FRIEND_API(JSObject *)
288 0 : js::GetObjectParentMaybeScope(JSObject *obj)
289 : {
290 0 : return obj->enclosingScope();
291 : }
292 :
293 : JS_FRIEND_API(JSObject *)
294 0 : js::GetGlobalForObjectCrossCompartment(JSObject *obj)
295 : {
296 0 : return &obj->global();
297 : }
298 :
299 : JS_FRIEND_API(uint32_t)
300 0 : js::GetObjectSlotSpan(JSObject *obj)
301 : {
302 0 : return obj->slotSpan();
303 : }
304 :
305 : JS_FRIEND_API(bool)
306 0 : js::IsObjectInContextCompartment(const JSObject *obj, const JSContext *cx)
307 : {
308 0 : return obj->compartment() == cx->compartment;
309 : }
310 :
311 : JS_FRIEND_API(bool)
312 0 : js::IsOriginalScriptFunction(JSFunction *fun)
313 : {
314 0 : return fun->script()->function() == fun;
315 : }
316 :
317 : JS_FRIEND_API(JSFunction *)
318 139968 : js::DefineFunctionWithReserved(JSContext *cx, JSObject *obj, const char *name, JSNative call,
319 : unsigned nargs, unsigned attrs)
320 : {
321 279936 : RootObject objRoot(cx, &obj);
322 :
323 139968 : JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
324 279936 : CHECK_REQUEST(cx);
325 139968 : assertSameCompartment(cx, obj);
326 139968 : JSAtom *atom = js_Atomize(cx, name, strlen(name));
327 139968 : if (!atom)
328 0 : return NULL;
329 : return js_DefineFunction(cx, objRoot, ATOM_TO_JSID(atom), call, nargs, attrs,
330 139968 : JSFunction::ExtendedFinalizeKind);
331 : }
332 :
333 : JS_FRIEND_API(JSFunction *)
334 0 : js::NewFunctionWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
335 : JSObject *parent, const char *name)
336 : {
337 0 : RootObject parentRoot(cx, &parent);
338 :
339 0 : JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
340 : JSAtom *atom;
341 :
342 0 : CHECK_REQUEST(cx);
343 0 : assertSameCompartment(cx, parent);
344 :
345 0 : if (!name) {
346 0 : atom = NULL;
347 : } else {
348 0 : atom = js_Atomize(cx, name, strlen(name));
349 0 : if (!atom)
350 0 : return NULL;
351 : }
352 :
353 : return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, atom,
354 0 : JSFunction::ExtendedFinalizeKind);
355 : }
356 :
357 : JS_FRIEND_API(JSFunction *)
358 0 : js::NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parent,
359 : jsid id)
360 : {
361 0 : RootObject parentRoot(cx, &parent);
362 :
363 0 : JS_ASSERT(JSID_IS_STRING(id));
364 0 : JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
365 0 : CHECK_REQUEST(cx);
366 0 : assertSameCompartment(cx, parent);
367 :
368 : return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, JSID_TO_ATOM(id),
369 0 : JSFunction::ExtendedFinalizeKind);
370 : }
371 :
372 : JS_FRIEND_API(JSObject *)
373 18666 : js::InitClassWithReserved(JSContext *cx, JSObject *obj, JSObject *parent_proto,
374 : JSClass *clasp, JSNative constructor, unsigned nargs,
375 : JSPropertySpec *ps, JSFunctionSpec *fs,
376 : JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
377 : {
378 37332 : CHECK_REQUEST(cx);
379 18666 : assertSameCompartment(cx, obj, parent_proto);
380 37332 : RootObject objRoot(cx, &obj);
381 : return js_InitClass(cx, objRoot, parent_proto, Valueify(clasp), constructor,
382 : nargs, ps, fs, static_ps, static_fs, NULL,
383 18666 : JSFunction::ExtendedFinalizeKind);
384 : }
385 :
386 : JS_FRIEND_API(const Value &)
387 0 : js::GetFunctionNativeReserved(JSObject *fun, size_t which)
388 : {
389 0 : JS_ASSERT(fun->toFunction()->isNative());
390 0 : return fun->toFunction()->getExtendedSlot(which);
391 : }
392 :
393 : JS_FRIEND_API(void)
394 158634 : js::SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val)
395 : {
396 158634 : JS_ASSERT(fun->toFunction()->isNative());
397 158634 : fun->toFunction()->setExtendedSlot(which, val);
398 158634 : }
399 :
400 : JS_FRIEND_API(void)
401 0 : js::SetReservedSlotWithBarrier(JSObject *obj, size_t slot, const js::Value &value)
402 : {
403 0 : obj->setSlot(slot, value);
404 0 : }
405 :
406 : void
407 0 : js::SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback)
408 : {
409 0 : rt->preserveWrapperCallback = callback;
410 0 : }
411 :
412 : /*
413 : * The below code is for temporary telemetry use. It can be removed when
414 : * sufficient data has been harvested.
415 : */
416 :
417 : extern size_t sE4XObjectsCreated;
418 :
419 : JS_FRIEND_API(size_t)
420 0 : JS_GetE4XObjectsCreated(JSContext *)
421 : {
422 0 : return sE4XObjectsCreated;
423 : }
424 :
425 : extern size_t sSetProtoCalled;
426 :
427 : JS_FRIEND_API(size_t)
428 0 : JS_SetProtoCalled(JSContext *)
429 : {
430 0 : return sSetProtoCalled;
431 : }
432 :
433 : extern size_t sCustomIteratorCount;
434 :
435 : JS_FRIEND_API(size_t)
436 0 : JS_GetCustomIteratorCount(JSContext *cx)
437 : {
438 0 : return sCustomIteratorCount;
439 : }
440 :
441 : void
442 0 : js::TraceWeakMaps(WeakMapTracer *trc)
443 : {
444 0 : WeakMapBase::traceAllMappings(trc);
445 0 : WatchpointMap::traceAll(trc);
446 0 : }
447 :
448 : JS_FRIEND_API(bool)
449 0 : js::GCThingIsMarkedGray(void *thing)
450 : {
451 0 : JS_ASSERT(thing);
452 0 : return reinterpret_cast<gc::Cell *>(thing)->isMarked(gc::GRAY);
453 : }
454 :
455 : JS_FRIEND_API(void)
456 0 : JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback)
457 : {
458 0 : rt->telemetryCallback = callback;
459 0 : }
460 :
461 : #ifdef DEBUG
462 : JS_FRIEND_API(void)
463 0 : js_DumpString(JSString *str)
464 : {
465 0 : str->dump();
466 0 : }
467 :
468 : JS_FRIEND_API(void)
469 0 : js_DumpAtom(JSAtom *atom)
470 : {
471 0 : atom->dump();
472 0 : }
473 :
474 : extern void
475 0 : DumpChars(const jschar *s, size_t n)
476 : {
477 0 : if (n == SIZE_MAX) {
478 0 : n = 0;
479 0 : while (s[n])
480 0 : n++;
481 : }
482 :
483 0 : fputc('"', stderr);
484 0 : for (size_t i = 0; i < n; i++) {
485 0 : if (s[i] == '\n')
486 0 : fprintf(stderr, "\\n");
487 0 : else if (s[i] == '\t')
488 0 : fprintf(stderr, "\\t");
489 0 : else if (s[i] >= 32 && s[i] < 127)
490 0 : fputc(s[i], stderr);
491 0 : else if (s[i] <= 255)
492 0 : fprintf(stderr, "\\x%02x", (unsigned int) s[i]);
493 : else
494 0 : fprintf(stderr, "\\u%04x", (unsigned int) s[i]);
495 : }
496 0 : fputc('"', stderr);
497 0 : }
498 :
499 : JS_FRIEND_API(void)
500 0 : js_DumpChars(const jschar *s, size_t n)
501 : {
502 0 : fprintf(stderr, "jschar * (%p) = ", (void *) s);
503 0 : DumpChars(s, n);
504 0 : fputc('\n', stderr);
505 0 : }
506 :
507 : JS_FRIEND_API(void)
508 0 : js_DumpObject(JSObject *obj)
509 : {
510 0 : obj->dump();
511 0 : }
512 :
513 0 : struct DumpingChildInfo {
514 : void *node;
515 : JSGCTraceKind kind;
516 :
517 0 : DumpingChildInfo (void *n, JSGCTraceKind k)
518 0 : : node(n), kind(k)
519 0 : {}
520 : };
521 :
522 : typedef HashSet<void *, DefaultHasher<void *>, SystemAllocPolicy> PtrSet;
523 :
524 0 : struct JSDumpHeapTracer : public JSTracer {
525 : PtrSet visited;
526 : FILE *output;
527 : Vector<DumpingChildInfo, 0, SystemAllocPolicy> nodes;
528 : char buffer[200];
529 : bool rootTracing;
530 :
531 0 : JSDumpHeapTracer(FILE *fp)
532 0 : : output(fp)
533 0 : {}
534 : };
535 :
536 : static void
537 : DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind);
538 :
539 : static char
540 0 : MarkDescriptor(void *thing)
541 : {
542 0 : gc::Cell *cell = static_cast<gc::Cell*>(thing);
543 0 : if (cell->isMarked(gc::BLACK))
544 0 : return cell->isMarked(gc::GRAY) ? 'G' : 'B';
545 : else
546 0 : return cell->isMarked(gc::GRAY) ? 'X' : 'W';
547 : }
548 :
549 : static void
550 0 : DumpHeapPushIfNew(JSTracer *trc, void **thingp, JSGCTraceKind kind)
551 : {
552 0 : JS_ASSERT(trc->callback == DumpHeapPushIfNew ||
553 0 : trc->callback == DumpHeapVisitChild);
554 0 : void *thing = *thingp;
555 0 : JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
556 :
557 : /*
558 : * If we're tracing roots, print root information. Do this even if we've
559 : * already seen thing, for complete root information.
560 : */
561 0 : if (dtrc->rootTracing) {
562 0 : fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing),
563 0 : JS_GetTraceEdgeName(dtrc, dtrc->buffer, sizeof(dtrc->buffer)));
564 : }
565 :
566 0 : PtrSet::AddPtr ptrEntry = dtrc->visited.lookupForAdd(thing);
567 0 : if (ptrEntry || !dtrc->visited.add(ptrEntry, thing))
568 : return;
569 :
570 0 : dtrc->nodes.append(DumpingChildInfo(thing, kind));
571 : }
572 :
573 : static void
574 0 : DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind)
575 : {
576 0 : JS_ASSERT(trc->callback == DumpHeapVisitChild);
577 0 : JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
578 0 : const char *edgeName = JS_GetTraceEdgeName(dtrc, dtrc->buffer, sizeof(dtrc->buffer));
579 0 : fprintf(dtrc->output, "> %p %c %s\n", *thingp, MarkDescriptor(*thingp), edgeName);
580 0 : DumpHeapPushIfNew(dtrc, thingp, kind);
581 0 : }
582 :
583 : void
584 0 : js::DumpHeapComplete(JSRuntime *rt, FILE *fp)
585 : {
586 0 : JSDumpHeapTracer dtrc(fp);
587 0 : JS_TracerInit(&dtrc, rt, DumpHeapPushIfNew);
588 0 : if (!dtrc.visited.init(10000))
589 : return;
590 :
591 : /* Store and log the root information. */
592 0 : dtrc.rootTracing = true;
593 0 : TraceRuntime(&dtrc);
594 0 : fprintf(dtrc.output, "==========\n");
595 :
596 : /* Log the graph. */
597 0 : dtrc.rootTracing = false;
598 0 : dtrc.callback = DumpHeapVisitChild;
599 :
600 0 : while (!dtrc.nodes.empty()) {
601 0 : DumpingChildInfo dci = dtrc.nodes.popCopy();
602 : JS_PrintTraceThingInfo(dtrc.buffer, sizeof(dtrc.buffer),
603 0 : &dtrc, dci.node, dci.kind, JS_TRUE);
604 0 : fprintf(fp, "%p %c %s\n", dci.node, MarkDescriptor(dci.node), dtrc.buffer);
605 0 : JS_TraceChildren(&dtrc, dci.node, dci.kind);
606 : }
607 :
608 0 : dtrc.visited.finish();
609 0 : fflush(dtrc.output);
610 : }
611 :
612 : #endif
613 :
614 : namespace js {
615 :
616 : JS_FRIEND_API(const JSStructuredCloneCallbacks *)
617 0 : GetContextStructuredCloneCallbacks(JSContext *cx)
618 : {
619 0 : return cx->runtime->structuredCloneCallbacks;
620 : }
621 :
622 : JS_FRIEND_API(JSVersion)
623 3 : VersionSetXML(JSVersion version, bool enable)
624 : {
625 : return enable ? JSVersion(uint32_t(version) | VersionFlags::HAS_XML)
626 3 : : JSVersion(uint32_t(version) & ~VersionFlags::HAS_XML);
627 : }
628 :
629 : JS_FRIEND_API(bool)
630 0 : CanCallContextDebugHandler(JSContext *cx)
631 : {
632 0 : return !!cx->runtime->debugHooks.debuggerHandler;
633 : }
634 :
635 : JS_FRIEND_API(JSTrapStatus)
636 0 : CallContextDebugHandler(JSContext *cx, JSScript *script, jsbytecode *bc, Value *rval)
637 : {
638 0 : if (!cx->runtime->debugHooks.debuggerHandler)
639 0 : return JSTRAP_RETURN;
640 :
641 : return cx->runtime->debugHooks.debuggerHandler(cx, script, bc, rval,
642 0 : cx->runtime->debugHooks.debuggerHandlerData);
643 : }
644 :
645 : #ifdef JS_THREADSAFE
646 : void *
647 0 : GetOwnerThread(const JSContext *cx)
648 : {
649 0 : return cx->runtime->ownerThread();
650 : }
651 :
652 : JS_FRIEND_API(unsigned)
653 0 : GetContextOutstandingRequests(const JSContext *cx)
654 : {
655 0 : return cx->outstandingRequests;
656 : }
657 :
658 0 : AutoSkipConservativeScan::AutoSkipConservativeScan(JSContext *cx
659 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
660 0 : : context(cx)
661 : {
662 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
663 :
664 0 : JSRuntime *rt = context->runtime;
665 0 : JS_ASSERT(rt->requestDepth >= 1);
666 0 : JS_ASSERT(!rt->conservativeGC.requestThreshold);
667 0 : if (rt->requestDepth == 1)
668 0 : rt->conservativeGC.requestThreshold = 1;
669 0 : }
670 :
671 0 : AutoSkipConservativeScan::~AutoSkipConservativeScan()
672 : {
673 0 : JSRuntime *rt = context->runtime;
674 0 : if (rt->requestDepth == 1)
675 0 : rt->conservativeGC.requestThreshold = 0;
676 0 : }
677 : #endif
678 :
679 : JS_FRIEND_API(JSCompartment *)
680 0 : GetContextCompartment(const JSContext *cx)
681 : {
682 0 : return cx->compartment;
683 : }
684 :
685 : JS_FRIEND_API(bool)
686 0 : HasUnrootedGlobal(const JSContext *cx)
687 : {
688 0 : return cx->hasRunOption(JSOPTION_UNROOTED_GLOBAL);
689 : }
690 :
691 : JS_FRIEND_API(void)
692 0 : SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg)
693 : {
694 0 : rt->activityCallback = cb;
695 0 : rt->activityCallbackArg = arg;
696 0 : }
697 :
698 : JS_FRIEND_API(bool)
699 0 : IsContextRunningJS(JSContext *cx)
700 : {
701 0 : return !cx->stack.empty();
702 : }
703 :
704 : JS_FRIEND_API(const CompartmentVector&)
705 0 : GetRuntimeCompartments(JSRuntime *rt)
706 : {
707 0 : return rt->compartments;
708 : }
709 :
710 : JS_FRIEND_API(size_t)
711 0 : SizeOfJSContext()
712 : {
713 0 : return sizeof(JSContext);
714 : }
715 :
716 : JS_FRIEND_API(GCSliceCallback)
717 0 : SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
718 : {
719 0 : GCSliceCallback old = rt->gcSliceCallback;
720 0 : rt->gcSliceCallback = callback;
721 0 : return old;
722 : }
723 :
724 : jschar *
725 0 : GCDescription::formatMessage(JSRuntime *rt) const
726 : {
727 0 : return rt->gcStats.formatMessage();
728 : }
729 :
730 : jschar *
731 0 : GCDescription::formatJSON(JSRuntime *rt, uint64_t timestamp) const
732 : {
733 0 : return rt->gcStats.formatJSON(timestamp);
734 : }
735 :
736 : JS_FRIEND_API(bool)
737 0 : WantGCSlice(JSRuntime *rt)
738 : {
739 0 : if (rt->gcZeal() == gc::ZealFrameVerifierValue || rt->gcZeal() == gc::ZealFrameGCValue)
740 0 : return true;
741 :
742 0 : if (rt->gcIncrementalState != gc::NO_INCREMENTAL)
743 0 : return true;
744 :
745 0 : return false;
746 : }
747 :
748 : JS_FRIEND_API(void)
749 0 : NotifyDidPaint(JSContext *cx)
750 : {
751 0 : JSRuntime *rt = cx->runtime;
752 :
753 0 : if (rt->gcZeal() == gc::ZealFrameVerifierValue) {
754 0 : gc::VerifyBarriers(cx);
755 0 : return;
756 : }
757 :
758 0 : if (rt->gcZeal() == gc::ZealFrameGCValue) {
759 0 : PrepareForFullGC(rt);
760 0 : GCSlice(cx, GC_NORMAL, gcreason::REFRESH_FRAME);
761 0 : return;
762 : }
763 :
764 0 : if (rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcInterFrameGC) {
765 0 : for (CompartmentsIter c(rt); !c.done(); c.next()) {
766 0 : if (c->needsBarrier())
767 0 : PrepareCompartmentForGC(c);
768 : }
769 0 : GCSlice(cx, GC_NORMAL, gcreason::REFRESH_FRAME);
770 : }
771 :
772 0 : rt->gcInterFrameGC = false;
773 : }
774 :
775 : extern JS_FRIEND_API(bool)
776 0 : IsIncrementalGCEnabled(JSRuntime *rt)
777 : {
778 0 : return rt->gcIncrementalEnabled;
779 : }
780 :
781 : extern JS_FRIEND_API(void)
782 0 : DisableIncrementalGC(JSRuntime *rt)
783 : {
784 0 : rt->gcIncrementalEnabled = false;
785 0 : }
786 :
787 : JS_FRIEND_API(bool)
788 0 : IsIncrementalBarrierNeeded(JSRuntime *rt)
789 : {
790 0 : return (rt->gcIncrementalState == gc::MARK && !rt->gcRunning);
791 : }
792 :
793 : JS_FRIEND_API(bool)
794 0 : IsIncrementalBarrierNeeded(JSContext *cx)
795 : {
796 0 : return IsIncrementalBarrierNeeded(cx->runtime);
797 : }
798 :
799 : JS_FRIEND_API(bool)
800 0 : IsIncrementalBarrierNeededOnObject(JSObject *obj)
801 : {
802 0 : return obj->compartment()->needsBarrier();
803 : }
804 :
805 : extern JS_FRIEND_API(void)
806 0 : IncrementalReferenceBarrier(void *ptr)
807 : {
808 0 : if (!ptr)
809 0 : return;
810 0 : JS_ASSERT(!static_cast<gc::Cell *>(ptr)->compartment()->rt->gcRunning);
811 0 : uint32_t kind = gc::GetGCThingTraceKind(ptr);
812 0 : if (kind == JSTRACE_OBJECT)
813 0 : JSObject::writeBarrierPre((JSObject *) ptr);
814 0 : else if (kind == JSTRACE_STRING)
815 0 : JSString::writeBarrierPre((JSString *) ptr);
816 : else
817 0 : JS_NOT_REACHED("invalid trace kind");
818 : }
819 :
820 : extern JS_FRIEND_API(void)
821 0 : IncrementalValueBarrier(const Value &v)
822 : {
823 0 : HeapValue::writeBarrierPre(v);
824 0 : }
825 :
826 : JS_FRIEND_API(JSObject *)
827 0 : GetTestingFunctions(JSContext *cx)
828 : {
829 0 : JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
830 0 : if (!obj)
831 0 : return NULL;
832 :
833 0 : if (!DefineTestingFunctions(cx, obj))
834 0 : return NULL;
835 :
836 0 : return obj;
837 : }
838 :
839 : } // namespace js
|