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 1404 : JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
59 : {
60 1404 : rt->gcGrayRootsTraceOp = traceOp;
61 1404 : rt->gcGrayRootsData = data;
62 1404 : }
63 :
64 : JS_FRIEND_API(JSString *)
65 2 : JS_GetAnonymousString(JSRuntime *rt)
66 : {
67 2 : JS_ASSERT(rt->hasContexts());
68 2 : return rt->atomState.anonymousAtom;
69 : }
70 :
71 : JS_FRIEND_API(JSObject *)
72 709 : 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 709 : 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 709 : if (JSObjectOp op = obj->getClass()->ext.innerObject)
86 0 : obj = op(cx, obj);
87 709 : return obj;
88 : }
89 :
90 : JS_FRIEND_API(JSFunction *)
91 1867919 : JS_GetObjectFunction(JSObject *obj)
92 : {
93 1867919 : if (obj->isFunction())
94 1867909 : return obj->toFunction();
95 10 : return NULL;
96 : }
97 :
98 : JS_FRIEND_API(JSObject *)
99 445 : JS_GetGlobalForFrame(JSStackFrame *fp)
100 : {
101 445 : return &Valueify(fp)->scopeChain().global();
102 : }
103 :
104 : JS_FRIEND_API(JSBool)
105 13217 : 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 26434 : CHECK_REQUEST(cx);
113 :
114 13217 : if (!obj->hasSingletonType()) {
115 : /*
116 : * We can see non-singleton objects when trying to splice prototypes
117 : * due to mutable __proto__ (ugh).
118 : */
119 13217 : return JS_SetPrototype(cx, obj, proto);
120 : }
121 :
122 0 : return obj->splicePrototype(cx, proto);
123 : }
124 :
125 : JS_FRIEND_API(JSObject *)
126 186922 : JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
127 : {
128 186922 : JSObject *obj = JS_NewObject(cx, clasp, proto, parent);
129 186922 : if (!obj || !obj->setSingletonType(cx))
130 0 : return NULL;
131 186922 : return obj;
132 : }
133 :
134 : JS_FRIEND_API(void)
135 1871 : js::GCForReason(JSContext *cx, gcreason::Reason reason)
136 : {
137 1871 : GC(cx, NULL, GC_NORMAL, reason);
138 1871 : }
139 :
140 : JS_FRIEND_API(void)
141 0 : js::CompartmentGCForReason(JSContext *cx, JSCompartment *comp, gcreason::Reason reason)
142 : {
143 : /* We cannot GC the atoms compartment alone; use a full GC instead. */
144 0 : JS_ASSERT(comp != cx->runtime->atomsCompartment);
145 :
146 0 : GC(cx, comp, GC_NORMAL, reason);
147 0 : }
148 :
149 : JS_FRIEND_API(void)
150 0 : js::ShrinkingGC(JSContext *cx, gcreason::Reason reason)
151 : {
152 0 : GC(cx, NULL, GC_SHRINK, reason);
153 0 : }
154 :
155 : JS_FRIEND_API(void)
156 4 : js::IncrementalGC(JSContext *cx, gcreason::Reason reason)
157 : {
158 4 : GCSlice(cx, NULL, GC_NORMAL, reason);
159 4 : }
160 :
161 : JS_FRIEND_API(void)
162 0 : JS_ShrinkGCBuffers(JSRuntime *rt)
163 : {
164 0 : ShrinkGCBuffers(rt);
165 0 : }
166 :
167 : JS_FRIEND_API(JSPrincipals *)
168 1579994 : JS_GetCompartmentPrincipals(JSCompartment *compartment)
169 : {
170 1579994 : return compartment->principals;
171 : }
172 :
173 : JS_FRIEND_API(JSBool)
174 0 : JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc)
175 : {
176 0 : return cx->compartment->wrap(cx, desc);
177 : }
178 :
179 : JS_FRIEND_API(void)
180 375083 : JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape)
181 : {
182 375083 : MarkCycleCollectorChildren(trc, (Shape *)shape);
183 375083 : }
184 :
185 : static bool
186 3514896 : DefineHelpProperty(JSContext *cx, JSObject *obj, const char *prop, const char *value)
187 : {
188 3514896 : JSAtom *atom = js_Atomize(cx, value, strlen(value));
189 3514896 : if (!atom)
190 0 : return false;
191 3514896 : jsval v = STRING_TO_JSVAL(atom);
192 : return JS_DefineProperty(cx, obj, prop, v,
193 : JS_PropertyStub, JS_StrictPropertyStub,
194 3514896 : JSPROP_READONLY | JSPROP_PERMANENT);
195 : }
196 :
197 : JS_FRIEND_API(bool)
198 45648 : JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj, const JSFunctionSpecWithHelp *fs)
199 : {
200 91296 : RootObject objRoot(cx, &obj);
201 :
202 45648 : JS_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
203 :
204 91296 : CHECK_REQUEST(cx);
205 45648 : assertSameCompartment(cx, obj);
206 1803096 : for (; fs->name; fs++) {
207 1757448 : JSAtom *atom = js_Atomize(cx, fs->name, strlen(fs->name));
208 1757448 : if (!atom)
209 0 : return false;
210 :
211 : JSFunction *fun = js_DefineFunction(cx, objRoot,
212 1757448 : ATOM_TO_JSID(atom), fs->call, fs->nargs, fs->flags);
213 1757448 : if (!fun)
214 0 : return false;
215 :
216 1757448 : if (fs->usage) {
217 1757448 : if (!DefineHelpProperty(cx, fun, "usage", fs->usage))
218 0 : return false;
219 : }
220 :
221 1757448 : if (fs->help) {
222 1757448 : if (!DefineHelpProperty(cx, fun, "help", fs->help))
223 0 : return false;
224 : }
225 : }
226 :
227 45648 : return true;
228 : }
229 :
230 11830 : AutoPreserveCompartment::AutoPreserveCompartment(JSContext *cx
231 : JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
232 11830 : : cx(cx), oldCompartment(cx->compartment)
233 : {
234 11830 : JS_GUARD_OBJECT_NOTIFIER_INIT;
235 11830 : }
236 :
237 23660 : AutoPreserveCompartment::~AutoPreserveCompartment()
238 : {
239 : /* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
240 11830 : cx->compartment = oldCompartment;
241 11830 : }
242 :
243 11826 : AutoSwitchCompartment::AutoSwitchCompartment(JSContext *cx, JSCompartment *newCompartment
244 : JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
245 11826 : : cx(cx), oldCompartment(cx->compartment)
246 : {
247 11826 : JS_GUARD_OBJECT_NOTIFIER_INIT;
248 11826 : cx->setCompartment(newCompartment);
249 11826 : }
250 :
251 0 : AutoSwitchCompartment::AutoSwitchCompartment(JSContext *cx, JSObject *target
252 : JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
253 0 : : cx(cx), oldCompartment(cx->compartment)
254 : {
255 0 : JS_GUARD_OBJECT_NOTIFIER_INIT;
256 0 : cx->setCompartment(target->compartment());
257 0 : }
258 :
259 23652 : AutoSwitchCompartment::~AutoSwitchCompartment()
260 : {
261 : /* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
262 11826 : cx->compartment = oldCompartment;
263 11826 : }
264 :
265 : JS_FRIEND_API(bool)
266 21 : js::IsSystemCompartment(const JSCompartment *c)
267 : {
268 21 : return c->isSystemCompartment;
269 : }
270 :
271 : JS_FRIEND_API(bool)
272 18 : js::IsAtomsCompartment(const JSCompartment *c)
273 : {
274 18 : return c == c->rt->atomsCompartment;
275 : }
276 :
277 : JS_FRIEND_API(bool)
278 13043148 : js::IsScopeObject(JSObject *obj)
279 : {
280 13043148 : return obj->isScope();
281 : }
282 :
283 : JS_FRIEND_API(JSObject *)
284 5110 : js::GetObjectParentMaybeScope(JSObject *obj)
285 : {
286 5110 : return obj->enclosingScope();
287 : }
288 :
289 : JS_FRIEND_API(JSObject *)
290 4321 : js::GetGlobalForObjectCrossCompartment(JSObject *obj)
291 : {
292 4321 : return &obj->global();
293 : }
294 :
295 : JS_FRIEND_API(uint32_t)
296 782856 : js::GetObjectSlotSpan(JSObject *obj)
297 : {
298 782856 : return obj->slotSpan();
299 : }
300 :
301 : JS_FRIEND_API(bool)
302 11276148 : js::IsObjectInContextCompartment(const JSObject *obj, const JSContext *cx)
303 : {
304 11276148 : return obj->compartment() == cx->compartment;
305 : }
306 :
307 : JS_FRIEND_API(bool)
308 1867625 : js::IsOriginalScriptFunction(JSFunction *fun)
309 : {
310 1867625 : return fun->script()->function() == fun;
311 : }
312 :
313 : JS_FRIEND_API(JSFunction *)
314 138588 : js::DefineFunctionWithReserved(JSContext *cx, JSObject *obj, const char *name, JSNative call,
315 : unsigned nargs, unsigned attrs)
316 : {
317 277176 : RootObject objRoot(cx, &obj);
318 :
319 138588 : JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
320 277176 : CHECK_REQUEST(cx);
321 138588 : assertSameCompartment(cx, obj);
322 138588 : JSAtom *atom = js_Atomize(cx, name, strlen(name));
323 138588 : if (!atom)
324 0 : return NULL;
325 : return js_DefineFunction(cx, objRoot, ATOM_TO_JSID(atom), call, nargs, attrs,
326 138588 : JSFunction::ExtendedFinalizeKind);
327 : }
328 :
329 : JS_FRIEND_API(JSFunction *)
330 0 : js::NewFunctionWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
331 : JSObject *parent, const char *name)
332 : {
333 0 : RootObject parentRoot(cx, &parent);
334 :
335 0 : JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
336 : JSAtom *atom;
337 :
338 0 : CHECK_REQUEST(cx);
339 0 : assertSameCompartment(cx, parent);
340 :
341 0 : if (!name) {
342 0 : atom = NULL;
343 : } else {
344 0 : atom = js_Atomize(cx, name, strlen(name));
345 0 : if (!atom)
346 0 : return NULL;
347 : }
348 :
349 : return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, atom,
350 0 : JSFunction::ExtendedFinalizeKind);
351 : }
352 :
353 : JS_FRIEND_API(JSFunction *)
354 1710919 : js::NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parent,
355 : jsid id)
356 : {
357 3421838 : RootObject parentRoot(cx, &parent);
358 :
359 1710919 : JS_ASSERT(JSID_IS_STRING(id));
360 1710919 : JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
361 3421838 : CHECK_REQUEST(cx);
362 1710919 : assertSameCompartment(cx, parent);
363 :
364 : return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, JSID_TO_ATOM(id),
365 1710919 : JSFunction::ExtendedFinalizeKind);
366 : }
367 :
368 : JS_FRIEND_API(JSObject *)
369 18699 : js::InitClassWithReserved(JSContext *cx, JSObject *obj, JSObject *parent_proto,
370 : JSClass *clasp, JSNative constructor, unsigned nargs,
371 : JSPropertySpec *ps, JSFunctionSpec *fs,
372 : JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
373 : {
374 37398 : CHECK_REQUEST(cx);
375 18699 : assertSameCompartment(cx, obj, parent_proto);
376 37398 : RootObject objRoot(cx, &obj);
377 : return js_InitClass(cx, objRoot, parent_proto, Valueify(clasp), constructor,
378 : nargs, ps, fs, static_ps, static_fs, NULL,
379 18699 : JSFunction::ExtendedFinalizeKind);
380 : }
381 :
382 : JS_FRIEND_API(const Value &)
383 13443790 : js::GetFunctionNativeReserved(JSObject *fun, size_t which)
384 : {
385 13443790 : JS_ASSERT(fun->toFunction()->isNative());
386 13443790 : return fun->toFunction()->getExtendedSlot(which);
387 : }
388 :
389 : JS_FRIEND_API(void)
390 3578831 : js::SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val)
391 : {
392 3578831 : JS_ASSERT(fun->toFunction()->isNative());
393 3578831 : fun->toFunction()->setExtendedSlot(which, val);
394 3578831 : }
395 :
396 : JS_FRIEND_API(void)
397 0 : js::SetReservedSlotWithBarrier(JSObject *obj, size_t slot, const js::Value &value)
398 : {
399 0 : obj->setSlot(slot, value);
400 0 : }
401 :
402 : void
403 1404 : js::SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback)
404 : {
405 1404 : rt->preserveWrapperCallback = callback;
406 1404 : }
407 :
408 : /*
409 : * The below code is for temporary telemetry use. It can be removed when
410 : * sufficient data has been harvested.
411 : */
412 :
413 : extern size_t sE4XObjectsCreated;
414 :
415 : JS_FRIEND_API(size_t)
416 3 : JS_GetE4XObjectsCreated(JSContext *)
417 : {
418 3 : return sE4XObjectsCreated;
419 : }
420 :
421 : extern size_t sSetProtoCalled;
422 :
423 : JS_FRIEND_API(size_t)
424 3 : JS_SetProtoCalled(JSContext *)
425 : {
426 3 : return sSetProtoCalled;
427 : }
428 :
429 : extern size_t sCustomIteratorCount;
430 :
431 : JS_FRIEND_API(size_t)
432 3 : JS_GetCustomIteratorCount(JSContext *cx)
433 : {
434 3 : return sCustomIteratorCount;
435 : }
436 :
437 : void
438 1910 : js::TraceWeakMaps(WeakMapTracer *trc)
439 : {
440 1910 : WeakMapBase::traceAllMappings(trc);
441 1910 : WatchpointMap::traceAll(trc);
442 1910 : }
443 :
444 : JS_FRIEND_API(bool)
445 26568033 : js::GCThingIsMarkedGray(void *thing)
446 : {
447 26568033 : JS_ASSERT(thing);
448 26568033 : return reinterpret_cast<gc::Cell *>(thing)->isMarked(gc::GRAY);
449 : }
450 :
451 : JS_FRIEND_API(void)
452 1404 : JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback)
453 : {
454 1404 : rt->telemetryCallback = callback;
455 1404 : }
456 :
457 : #ifdef DEBUG
458 : JS_FRIEND_API(void)
459 0 : js_DumpString(JSString *str)
460 : {
461 0 : str->dump();
462 0 : }
463 :
464 : JS_FRIEND_API(void)
465 0 : js_DumpAtom(JSAtom *atom)
466 : {
467 0 : atom->dump();
468 0 : }
469 :
470 : extern void
471 0 : DumpChars(const jschar *s, size_t n)
472 : {
473 0 : if (n == SIZE_MAX) {
474 0 : n = 0;
475 0 : while (s[n])
476 0 : n++;
477 : }
478 :
479 0 : fputc('"', stderr);
480 0 : for (size_t i = 0; i < n; i++) {
481 0 : if (s[i] == '\n')
482 0 : fprintf(stderr, "\\n");
483 0 : else if (s[i] == '\t')
484 0 : fprintf(stderr, "\\t");
485 0 : else if (s[i] >= 32 && s[i] < 127)
486 0 : fputc(s[i], stderr);
487 0 : else if (s[i] <= 255)
488 0 : fprintf(stderr, "\\x%02x", (unsigned int) s[i]);
489 : else
490 0 : fprintf(stderr, "\\u%04x", (unsigned int) s[i]);
491 : }
492 0 : fputc('"', stderr);
493 0 : }
494 :
495 : JS_FRIEND_API(void)
496 0 : js_DumpChars(const jschar *s, size_t n)
497 : {
498 0 : fprintf(stderr, "jschar * (%p) = ", (void *) s);
499 0 : DumpChars(s, n);
500 0 : fputc('\n', stderr);
501 0 : }
502 :
503 : JS_FRIEND_API(void)
504 0 : js_DumpObject(JSObject *obj)
505 : {
506 0 : obj->dump();
507 0 : }
508 :
509 0 : struct DumpingChildInfo {
510 : void *node;
511 : JSGCTraceKind kind;
512 :
513 0 : DumpingChildInfo (void *n, JSGCTraceKind k)
514 0 : : node(n), kind(k)
515 0 : {}
516 : };
517 :
518 : typedef HashSet<void *, DefaultHasher<void *>, SystemAllocPolicy> PtrSet;
519 :
520 0 : struct JSDumpHeapTracer : public JSTracer {
521 : PtrSet visited;
522 : FILE *output;
523 : Vector<DumpingChildInfo, 0, SystemAllocPolicy> nodes;
524 : char buffer[200];
525 : bool rootTracing;
526 :
527 0 : JSDumpHeapTracer(FILE *fp)
528 0 : : output(fp)
529 0 : {}
530 : };
531 :
532 : static void
533 : DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind);
534 :
535 : static char
536 0 : MarkDescriptor(void *thing)
537 : {
538 0 : gc::Cell *cell = static_cast<gc::Cell*>(thing);
539 0 : if (cell->isMarked(gc::BLACK))
540 0 : return cell->isMarked(gc::GRAY) ? 'G' : 'B';
541 : else
542 0 : return cell->isMarked(gc::GRAY) ? 'X' : 'W';
543 : }
544 :
545 : static void
546 0 : DumpHeapPushIfNew(JSTracer *trc, void **thingp, JSGCTraceKind kind)
547 : {
548 0 : JS_ASSERT(trc->callback == DumpHeapPushIfNew ||
549 0 : trc->callback == DumpHeapVisitChild);
550 0 : void *thing = *thingp;
551 0 : JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
552 :
553 : /*
554 : * If we're tracing roots, print root information. Do this even if we've
555 : * already seen thing, for complete root information.
556 : */
557 0 : if (dtrc->rootTracing) {
558 0 : fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing),
559 0 : JS_GetTraceEdgeName(dtrc, dtrc->buffer, sizeof(dtrc->buffer)));
560 : }
561 :
562 0 : PtrSet::AddPtr ptrEntry = dtrc->visited.lookupForAdd(thing);
563 0 : if (ptrEntry || !dtrc->visited.add(ptrEntry, thing))
564 0 : return;
565 :
566 0 : dtrc->nodes.append(DumpingChildInfo(thing, kind));
567 : }
568 :
569 : static void
570 0 : DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind)
571 : {
572 0 : JS_ASSERT(trc->callback == DumpHeapVisitChild);
573 0 : JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
574 0 : const char *edgeName = JS_GetTraceEdgeName(dtrc, dtrc->buffer, sizeof(dtrc->buffer));
575 0 : fprintf(dtrc->output, "> %p %c %s\n", *thingp, MarkDescriptor(*thingp), edgeName);
576 0 : DumpHeapPushIfNew(dtrc, thingp, kind);
577 0 : }
578 :
579 : void
580 0 : js::DumpHeapComplete(JSRuntime *rt, FILE *fp)
581 : {
582 0 : JSDumpHeapTracer dtrc(fp);
583 0 : JS_TracerInit(&dtrc, rt, DumpHeapPushIfNew);
584 0 : if (!dtrc.visited.init(10000))
585 : return;
586 :
587 : /* Store and log the root information. */
588 0 : dtrc.rootTracing = true;
589 0 : TraceRuntime(&dtrc);
590 0 : fprintf(dtrc.output, "==========\n");
591 :
592 : /* Log the graph. */
593 0 : dtrc.rootTracing = false;
594 0 : dtrc.callback = DumpHeapVisitChild;
595 :
596 0 : while (!dtrc.nodes.empty()) {
597 0 : DumpingChildInfo dci = dtrc.nodes.popCopy();
598 : JS_PrintTraceThingInfo(dtrc.buffer, sizeof(dtrc.buffer),
599 0 : &dtrc, dci.node, dci.kind, JS_TRUE);
600 0 : fprintf(fp, "%p %c %s\n", dci.node, MarkDescriptor(dci.node), dtrc.buffer);
601 0 : JS_TraceChildren(&dtrc, dci.node, dci.kind);
602 : }
603 :
604 0 : dtrc.visited.finish();
605 0 : fflush(dtrc.output);
606 : }
607 :
608 : #endif
609 :
610 : namespace js {
611 :
612 : JS_FRIEND_API(const JSStructuredCloneCallbacks *)
613 0 : GetContextStructuredCloneCallbacks(JSContext *cx)
614 : {
615 0 : return cx->runtime->structuredCloneCallbacks;
616 : }
617 :
618 : JS_FRIEND_API(JSVersion)
619 968 : VersionSetXML(JSVersion version, bool enable)
620 : {
621 : return enable ? JSVersion(uint32_t(version) | VersionFlags::HAS_XML)
622 968 : : JSVersion(uint32_t(version) & ~VersionFlags::HAS_XML);
623 : }
624 :
625 : JS_FRIEND_API(bool)
626 0 : CanCallContextDebugHandler(JSContext *cx)
627 : {
628 0 : return !!cx->runtime->debugHooks.debuggerHandler;
629 : }
630 :
631 : JS_FRIEND_API(JSTrapStatus)
632 0 : CallContextDebugHandler(JSContext *cx, JSScript *script, jsbytecode *bc, Value *rval)
633 : {
634 0 : if (!cx->runtime->debugHooks.debuggerHandler)
635 0 : return JSTRAP_RETURN;
636 :
637 : return cx->runtime->debugHooks.debuggerHandler(cx, script, bc, rval,
638 0 : cx->runtime->debugHooks.debuggerHandlerData);
639 : }
640 :
641 : #ifdef JS_THREADSAFE
642 : void *
643 27226744 : GetOwnerThread(const JSContext *cx)
644 : {
645 27226744 : return cx->runtime->ownerThread();
646 : }
647 :
648 : JS_FRIEND_API(unsigned)
649 5298 : GetContextOutstandingRequests(const JSContext *cx)
650 : {
651 5298 : return cx->outstandingRequests;
652 : }
653 :
654 1868 : AutoSkipConservativeScan::AutoSkipConservativeScan(JSContext *cx
655 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
656 1868 : : context(cx)
657 : {
658 1868 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
659 :
660 1868 : JSRuntime *rt = context->runtime;
661 1868 : JS_ASSERT(rt->requestDepth >= 1);
662 1868 : JS_ASSERT(!rt->conservativeGC.requestThreshold);
663 1868 : if (rt->requestDepth == 1)
664 1868 : rt->conservativeGC.requestThreshold = 1;
665 1868 : }
666 :
667 3736 : AutoSkipConservativeScan::~AutoSkipConservativeScan()
668 : {
669 1868 : JSRuntime *rt = context->runtime;
670 1868 : if (rt->requestDepth == 1)
671 1868 : rt->conservativeGC.requestThreshold = 0;
672 1868 : }
673 : #endif
674 :
675 : JS_FRIEND_API(JSCompartment *)
676 10841 : GetContextCompartment(const JSContext *cx)
677 : {
678 10841 : return cx->compartment;
679 : }
680 :
681 : JS_FRIEND_API(bool)
682 66484 : HasUnrootedGlobal(const JSContext *cx)
683 : {
684 66484 : return cx->hasRunOption(JSOPTION_UNROOTED_GLOBAL);
685 : }
686 :
687 : JS_FRIEND_API(void)
688 1404 : SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg)
689 : {
690 1404 : rt->activityCallback = cb;
691 1404 : rt->activityCallbackArg = arg;
692 1404 : }
693 :
694 : JS_FRIEND_API(bool)
695 0 : IsContextRunningJS(JSContext *cx)
696 : {
697 0 : return !cx->stack.empty();
698 : }
699 :
700 : JS_FRIEND_API(const CompartmentVector&)
701 280 : GetRuntimeCompartments(JSRuntime *rt)
702 : {
703 280 : return rt->compartments;
704 : }
705 :
706 : JS_FRIEND_API(size_t)
707 5298 : SizeOfJSContext()
708 : {
709 5298 : return sizeof(JSContext);
710 : }
711 :
712 : JS_FRIEND_API(GCSliceCallback)
713 330 : SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
714 : {
715 330 : GCSliceCallback old = rt->gcSliceCallback;
716 330 : rt->gcSliceCallback = callback;
717 330 : return old;
718 : }
719 :
720 : JS_FRIEND_API(bool)
721 0 : WantGCSlice(JSRuntime *rt)
722 : {
723 0 : if (rt->gcZeal() == gc::ZealFrameVerifierValue || rt->gcZeal() == gc::ZealFrameGCValue)
724 0 : return true;
725 :
726 0 : if (rt->gcIncrementalState != gc::NO_INCREMENTAL)
727 0 : return true;
728 :
729 0 : return false;
730 : }
731 :
732 : JS_FRIEND_API(void)
733 0 : NotifyDidPaint(JSContext *cx)
734 : {
735 0 : JSRuntime *rt = cx->runtime;
736 :
737 0 : if (rt->gcZeal() == gc::ZealFrameVerifierValue) {
738 0 : gc::VerifyBarriers(cx);
739 0 : return;
740 : }
741 :
742 0 : if (rt->gcZeal() == gc::ZealFrameGCValue) {
743 0 : GCSlice(cx, NULL, GC_NORMAL, gcreason::REFRESH_FRAME);
744 0 : return;
745 : }
746 :
747 0 : if (rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcInterFrameGC)
748 0 : GCSlice(cx, rt->gcIncrementalCompartment, GC_NORMAL, gcreason::REFRESH_FRAME);
749 :
750 0 : rt->gcInterFrameGC = false;
751 : }
752 :
753 : extern JS_FRIEND_API(bool)
754 0 : IsIncrementalGCEnabled(JSRuntime *rt)
755 : {
756 0 : return rt->gcIncrementalEnabled;
757 : }
758 :
759 : extern JS_FRIEND_API(void)
760 0 : DisableIncrementalGC(JSRuntime *rt)
761 : {
762 0 : rt->gcIncrementalEnabled = false;
763 0 : }
764 :
765 : JS_FRIEND_API(bool)
766 1488662 : IsIncrementalBarrierNeeded(JSRuntime *rt)
767 : {
768 1488662 : return (rt->gcIncrementalState == gc::MARK && !rt->gcRunning);
769 : }
770 :
771 : JS_FRIEND_API(bool)
772 0 : IsIncrementalBarrierNeeded(JSContext *cx)
773 : {
774 0 : return IsIncrementalBarrierNeeded(cx->runtime);
775 : }
776 :
777 : JS_FRIEND_API(bool)
778 20314329 : IsIncrementalBarrierNeededOnObject(JSObject *obj)
779 : {
780 20314329 : return obj->compartment()->needsBarrier();
781 : }
782 :
783 : extern JS_FRIEND_API(void)
784 217998 : IncrementalReferenceBarrier(void *ptr)
785 : {
786 217998 : if (!ptr)
787 217872 : return;
788 126 : JS_ASSERT(!static_cast<gc::Cell *>(ptr)->compartment()->rt->gcRunning);
789 126 : uint32_t kind = gc::GetGCThingTraceKind(ptr);
790 126 : if (kind == JSTRACE_OBJECT)
791 126 : JSObject::writeBarrierPre((JSObject *) ptr);
792 0 : else if (kind == JSTRACE_STRING)
793 0 : JSString::writeBarrierPre((JSString *) ptr);
794 : else
795 0 : JS_NOT_REACHED("invalid trace kind");
796 : }
797 :
798 : extern JS_FRIEND_API(void)
799 0 : IncrementalValueBarrier(const Value &v)
800 : {
801 0 : HeapValue::writeBarrierPre(v);
802 0 : }
803 :
804 : JS_FRIEND_API(JSObject *)
805 0 : GetTestingFunctions(JSContext *cx)
806 : {
807 0 : JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
808 0 : if (!obj)
809 0 : return NULL;
810 :
811 0 : if (!DefineTestingFunctions(cx, obj))
812 0 : return NULL;
813 :
814 0 : return obj;
815 : }
816 :
817 : } // namespace js
|