/[jscoverage]/trunk/js/jsdbgapi.cpp
ViewVC logotype

Annotation of /trunk/js/jsdbgapi.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 585 - (hide annotations)
Sun Sep 12 15:13:23 2010 UTC (9 years, 6 months ago) by siliconforks
File size: 72872 byte(s)
Update to SpiderMonkey from Firefox 3.6.9.

1 siliconforks 507 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 siliconforks 585 * vim: set ts=8 sw=4 et tw=99:
3 siliconforks 332 *
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 Mozilla Communicator client code, released
18     * March 31, 1998.
19     *
20     * The Initial Developer of the Original Code is
21     * Netscape Communications Corporation.
22     * Portions created by the Initial Developer are Copyright (C) 1998
23     * the Initial Developer. All Rights Reserved.
24     *
25     * Contributor(s):
26     *
27     * Alternatively, the contents of this file may be used under the terms of
28     * either of the GNU General Public License Version 2 or later (the "GPL"),
29     * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30     * in which case the provisions of the GPL or the LGPL are applicable instead
31     * of those above. If you wish to allow use of your version of this file only
32     * under the terms of either the GPL or the LGPL, and not to allow others to
33     * use your version of this file under the terms of the MPL, indicate your
34     * decision by deleting the provisions above and replace them with the notice
35     * and other provisions required by the GPL or the LGPL. If you do not delete
36     * the provisions above, a recipient may use your version of this file under
37     * the terms of any one of the MPL, the GPL or the LGPL.
38     *
39     * ***** END LICENSE BLOCK ***** */
40    
41     /*
42     * JS debugging API.
43     */
44     #include <string.h>
45     #include "jstypes.h"
46 siliconforks 507 #include "jsstdint.h"
47 siliconforks 332 #include "jsutil.h" /* Added by JSIFY */
48     #include "jsclist.h"
49     #include "jsapi.h"
50     #include "jscntxt.h"
51     #include "jsversion.h"
52     #include "jsdbgapi.h"
53     #include "jsemit.h"
54     #include "jsfun.h"
55     #include "jsgc.h"
56     #include "jsinterp.h"
57     #include "jslock.h"
58     #include "jsobj.h"
59     #include "jsopcode.h"
60     #include "jsparse.h"
61     #include "jsscope.h"
62     #include "jsscript.h"
63 siliconforks 460 #include "jsstaticcheck.h"
64 siliconforks 332 #include "jsstr.h"
65    
66 siliconforks 507 #include "jsatominlines.h"
67    
68 siliconforks 332 #include "jsautooplen.h"
69    
70     typedef struct JSTrap {
71     JSCList links;
72     JSScript *script;
73     jsbytecode *pc;
74     JSOp op;
75     JSTrapHandler handler;
76     void *closure;
77     } JSTrap;
78    
79     #define DBG_LOCK(rt) JS_ACQUIRE_LOCK((rt)->debuggerLock)
80     #define DBG_UNLOCK(rt) JS_RELEASE_LOCK((rt)->debuggerLock)
81     #define DBG_LOCK_EVAL(rt,expr) (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt))
82    
83     /*
84     * NB: FindTrap must be called with rt->debuggerLock acquired.
85     */
86     static JSTrap *
87     FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc)
88     {
89     JSTrap *trap;
90    
91     for (trap = (JSTrap *)rt->trapList.next;
92     &trap->links != &rt->trapList;
93     trap = (JSTrap *)trap->links.next) {
94     if (trap->script == script && trap->pc == pc)
95     return trap;
96     }
97     return NULL;
98     }
99    
100     jsbytecode *
101     js_UntrapScriptCode(JSContext *cx, JSScript *script)
102     {
103     jsbytecode *code;
104     JSRuntime *rt;
105     JSTrap *trap;
106    
107     code = script->code;
108     rt = cx->runtime;
109     DBG_LOCK(rt);
110     for (trap = (JSTrap *)rt->trapList.next;
111     &trap->links !=
112     &rt->trapList;
113     trap = (JSTrap *)trap->links.next) {
114     if (trap->script == script &&
115     (size_t)(trap->pc - script->code) < script->length) {
116     if (code == script->code) {
117     jssrcnote *sn, *notes;
118     size_t nbytes;
119    
120     nbytes = script->length * sizeof(jsbytecode);
121 siliconforks 507 notes = script->notes();
122 siliconforks 332 for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
123     continue;
124     nbytes += (sn - notes + 1) * sizeof *sn;
125    
126 siliconforks 507 code = (jsbytecode *) cx->malloc(nbytes);
127 siliconforks 332 if (!code)
128     break;
129     memcpy(code, script->code, nbytes);
130 siliconforks 460 JS_PURGE_GSN_CACHE(cx);
131 siliconforks 332 }
132     code[trap->pc - script->code] = trap->op;
133     }
134     }
135     DBG_UNLOCK(rt);
136     return code;
137     }
138    
139     JS_PUBLIC_API(JSBool)
140     JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
141     JSTrapHandler handler, void *closure)
142     {
143     JSTrap *junk, *trap, *twin;
144     JSRuntime *rt;
145     uint32 sample;
146    
147     JS_ASSERT((JSOp) *pc != JSOP_TRAP);
148     junk = NULL;
149     rt = cx->runtime;
150     DBG_LOCK(rt);
151     trap = FindTrap(rt, script, pc);
152     if (trap) {
153     JS_ASSERT(trap->script == script && trap->pc == pc);
154     JS_ASSERT(*pc == JSOP_TRAP);
155     } else {
156     sample = rt->debuggerMutations;
157     DBG_UNLOCK(rt);
158 siliconforks 507 trap = (JSTrap *) cx->malloc(sizeof *trap);
159 siliconforks 332 if (!trap)
160     return JS_FALSE;
161     trap->closure = NULL;
162     if(!js_AddRoot(cx, &trap->closure, "trap->closure")) {
163 siliconforks 507 cx->free(trap);
164 siliconforks 332 return JS_FALSE;
165     }
166     DBG_LOCK(rt);
167     twin = (rt->debuggerMutations != sample)
168     ? FindTrap(rt, script, pc)
169     : NULL;
170     if (twin) {
171     junk = trap;
172     trap = twin;
173     } else {
174     JS_APPEND_LINK(&trap->links, &rt->trapList);
175     ++rt->debuggerMutations;
176     trap->script = script;
177     trap->pc = pc;
178     trap->op = (JSOp)*pc;
179     *pc = JSOP_TRAP;
180     }
181     }
182     trap->handler = handler;
183     trap->closure = closure;
184     DBG_UNLOCK(rt);
185     if (junk) {
186     js_RemoveRoot(rt, &junk->closure);
187 siliconforks 507 cx->free(junk);
188 siliconforks 332 }
189     return JS_TRUE;
190     }
191    
192     JS_PUBLIC_API(JSOp)
193     JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
194     {
195     JSRuntime *rt;
196     JSTrap *trap;
197     JSOp op;
198    
199     rt = cx->runtime;
200     DBG_LOCK(rt);
201     trap = FindTrap(rt, script, pc);
202     op = trap ? trap->op : (JSOp) *pc;
203     DBG_UNLOCK(rt);
204     return op;
205     }
206    
207     static void
208     DestroyTrapAndUnlock(JSContext *cx, JSTrap *trap)
209     {
210     ++cx->runtime->debuggerMutations;
211     JS_REMOVE_LINK(&trap->links);
212     *trap->pc = (jsbytecode)trap->op;
213     DBG_UNLOCK(cx->runtime);
214    
215     js_RemoveRoot(cx->runtime, &trap->closure);
216 siliconforks 507 cx->free(trap);
217 siliconforks 332 }
218    
219     JS_PUBLIC_API(void)
220     JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
221     JSTrapHandler *handlerp, void **closurep)
222     {
223     JSTrap *trap;
224    
225     DBG_LOCK(cx->runtime);
226     trap = FindTrap(cx->runtime, script, pc);
227     if (handlerp)
228     *handlerp = trap ? trap->handler : NULL;
229     if (closurep)
230     *closurep = trap ? trap->closure : NULL;
231     if (trap)
232     DestroyTrapAndUnlock(cx, trap);
233     else
234     DBG_UNLOCK(cx->runtime);
235     }
236    
237     JS_PUBLIC_API(void)
238     JS_ClearScriptTraps(JSContext *cx, JSScript *script)
239     {
240     JSRuntime *rt;
241     JSTrap *trap, *next;
242     uint32 sample;
243    
244     rt = cx->runtime;
245     DBG_LOCK(rt);
246     for (trap = (JSTrap *)rt->trapList.next;
247     &trap->links != &rt->trapList;
248     trap = next) {
249     next = (JSTrap *)trap->links.next;
250     if (trap->script == script) {
251     sample = rt->debuggerMutations;
252     DestroyTrapAndUnlock(cx, trap);
253     DBG_LOCK(rt);
254     if (rt->debuggerMutations != sample + 1)
255     next = (JSTrap *)rt->trapList.next;
256     }
257     }
258     DBG_UNLOCK(rt);
259     }
260    
261     JS_PUBLIC_API(void)
262     JS_ClearAllTraps(JSContext *cx)
263     {
264     JSRuntime *rt;
265     JSTrap *trap, *next;
266     uint32 sample;
267    
268     rt = cx->runtime;
269     DBG_LOCK(rt);
270     for (trap = (JSTrap *)rt->trapList.next;
271     &trap->links != &rt->trapList;
272     trap = next) {
273     next = (JSTrap *)trap->links.next;
274     sample = rt->debuggerMutations;
275     DestroyTrapAndUnlock(cx, trap);
276     DBG_LOCK(rt);
277     if (rt->debuggerMutations != sample + 1)
278     next = (JSTrap *)rt->trapList.next;
279     }
280     DBG_UNLOCK(rt);
281     }
282    
283     JS_PUBLIC_API(JSTrapStatus)
284     JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
285     {
286     JSTrap *trap;
287     jsint op;
288     JSTrapStatus status;
289    
290     DBG_LOCK(cx->runtime);
291     trap = FindTrap(cx->runtime, script, pc);
292     JS_ASSERT(!trap || trap->handler);
293     if (!trap) {
294     op = (JSOp) *pc;
295     DBG_UNLOCK(cx->runtime);
296    
297     /* Defend against "pc for wrong script" API usage error. */
298     JS_ASSERT(op != JSOP_TRAP);
299    
300     #ifdef JS_THREADSAFE
301     /* If the API was abused, we must fail for want of the real op. */
302     if (op == JSOP_TRAP)
303     return JSTRAP_ERROR;
304    
305     /* Assume a race with a debugger thread and try to carry on. */
306     *rval = INT_TO_JSVAL(op);
307     return JSTRAP_CONTINUE;
308     #else
309     /* Always fail if single-threaded (must be an API usage error). */
310     return JSTRAP_ERROR;
311     #endif
312     }
313     DBG_UNLOCK(cx->runtime);
314    
315     /*
316     * It's important that we not use 'trap->' after calling the callback --
317     * the callback might remove the trap!
318     */
319     op = (jsint)trap->op;
320     status = trap->handler(cx, script, pc, rval, trap->closure);
321     if (status == JSTRAP_CONTINUE) {
322     /* By convention, return the true op to the interpreter in rval. */
323     *rval = INT_TO_JSVAL(op);
324     }
325     return status;
326     }
327    
328 siliconforks 507 #ifdef JS_TRACER
329     static void
330     JITInhibitingHookChange(JSRuntime *rt, bool wasInhibited)
331     {
332     if (wasInhibited) {
333     if (!rt->debuggerInhibitsJIT()) {
334     for (JSCList *cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next)
335     js_ContextFromLinkField(cl)->updateJITEnabled();
336     }
337     } else if (rt->debuggerInhibitsJIT()) {
338     for (JSCList *cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next)
339     js_ContextFromLinkField(cl)->jitEnabled = false;
340     }
341     }
342    
343     static void
344     LeaveTraceRT(JSRuntime *rt)
345     {
346     JSThreadData *data = js_CurrentThreadData(rt);
347     JSContext *cx = data ? data->traceMonitor.tracecx : NULL;
348     JS_UNLOCK_GC(rt);
349    
350     if (cx)
351     js_LeaveTrace(cx);
352     }
353     #endif
354    
355 siliconforks 332 JS_PUBLIC_API(JSBool)
356     JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure)
357     {
358 siliconforks 507 #ifdef JS_TRACER
359     JS_LOCK_GC(rt);
360     bool wasInhibited = rt->debuggerInhibitsJIT();
361     #endif
362 siliconforks 332 rt->globalDebugHooks.interruptHandler = handler;
363     rt->globalDebugHooks.interruptHandlerData = closure;
364 siliconforks 507 #ifdef JS_TRACER
365     JITInhibitingHookChange(rt, wasInhibited);
366     JS_UNLOCK_GC(rt);
367     LeaveTraceRT(rt);
368     #endif
369 siliconforks 332 return JS_TRUE;
370     }
371    
372     JS_PUBLIC_API(JSBool)
373     JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep)
374     {
375 siliconforks 507 #ifdef JS_TRACER
376     JS_LOCK_GC(rt);
377     bool wasInhibited = rt->debuggerInhibitsJIT();
378     #endif
379 siliconforks 332 if (handlerp)
380 siliconforks 507 *handlerp = rt->globalDebugHooks.interruptHandler;
381 siliconforks 332 if (closurep)
382     *closurep = rt->globalDebugHooks.interruptHandlerData;
383     rt->globalDebugHooks.interruptHandler = 0;
384     rt->globalDebugHooks.interruptHandlerData = 0;
385 siliconforks 507 #ifdef JS_TRACER
386     JITInhibitingHookChange(rt, wasInhibited);
387     JS_UNLOCK_GC(rt);
388     #endif
389 siliconforks 332 return JS_TRUE;
390     }
391    
392     /************************************************************************/
393    
394     typedef struct JSWatchPoint {
395     JSCList links;
396     JSObject *object; /* weak link, see js_FinalizeObject */
397     JSScopeProperty *sprop;
398     JSPropertyOp setter;
399     JSWatchPointHandler handler;
400 siliconforks 507 JSObject *closure;
401 siliconforks 332 uintN flags;
402     } JSWatchPoint;
403    
404     #define JSWP_LIVE 0x1 /* live because set and not cleared */
405     #define JSWP_HELD 0x2 /* held while running handler/setter */
406    
407     /*
408     * NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases.
409     */
410     static JSBool
411     DropWatchPointAndUnlock(JSContext *cx, JSWatchPoint *wp, uintN flag)
412     {
413     JSBool ok, found;
414     JSScopeProperty *sprop;
415     JSScope *scope;
416     JSPropertyOp setter;
417    
418     ok = JS_TRUE;
419     wp->flags &= ~flag;
420     if (wp->flags != 0) {
421     DBG_UNLOCK(cx->runtime);
422     return ok;
423     }
424    
425     /*
426     * Remove wp from the list, then if there are no other watchpoints for
427     * wp->sprop in any scope, restore wp->sprop->setter from wp.
428     */
429     ++cx->runtime->debuggerMutations;
430     JS_REMOVE_LINK(&wp->links);
431     sprop = wp->sprop;
432    
433     /*
434     * Passing null for the scope parameter tells js_GetWatchedSetter to find
435     * any watch point for sprop, and not to lock or unlock rt->debuggerLock.
436     * If js_ChangeNativePropertyAttrs fails, propagate failure after removing
437     * wp->closure's root and freeing wp.
438     */
439     setter = js_GetWatchedSetter(cx->runtime, NULL, sprop);
440     DBG_UNLOCK(cx->runtime);
441     if (!setter) {
442     JS_LOCK_OBJ(cx, wp->object);
443     scope = OBJ_SCOPE(wp->object);
444 siliconforks 507 found = (scope->lookup(sprop->id) != NULL);
445 siliconforks 332 JS_UNLOCK_SCOPE(cx, scope);
446    
447     /*
448     * If the property wasn't found on wp->object or didn't exist, then
449     * someone else has dealt with this sprop, and we don't need to change
450     * the property attributes.
451     */
452     if (found) {
453 siliconforks 507 sprop = scope->change(cx, sprop, 0, sprop->attrs,
454     sprop->getter, wp->setter);
455 siliconforks 332 if (!sprop)
456     ok = JS_FALSE;
457     }
458     }
459    
460 siliconforks 507 cx->free(wp);
461 siliconforks 332 return ok;
462     }
463    
464     /*
465     * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
466     * the debugger should never be racing with the GC (i.e., the debugger must
467     * respect the request model).
468     */
469     void
470     js_TraceWatchPoints(JSTracer *trc, JSObject *obj)
471     {
472     JSRuntime *rt;
473     JSWatchPoint *wp;
474    
475     rt = trc->context->runtime;
476    
477     for (wp = (JSWatchPoint *)rt->watchPointList.next;
478     &wp->links != &rt->watchPointList;
479     wp = (JSWatchPoint *)wp->links.next) {
480     if (wp->object == obj) {
481 siliconforks 507 wp->sprop->trace(trc);
482 siliconforks 332 if ((wp->sprop->attrs & JSPROP_SETTER) && wp->setter) {
483 siliconforks 460 JS_CALL_OBJECT_TRACER(trc, js_CastAsObject(wp->setter),
484 siliconforks 332 "wp->setter");
485     }
486     JS_SET_TRACING_NAME(trc, "wp->closure");
487 siliconforks 507 js_CallValueTracerIfGCThing(trc, OBJECT_TO_JSVAL(wp->closure));
488 siliconforks 332 }
489     }
490     }
491    
492     void
493     js_SweepWatchPoints(JSContext *cx)
494     {
495     JSRuntime *rt;
496     JSWatchPoint *wp, *next;
497     uint32 sample;
498    
499     rt = cx->runtime;
500     DBG_LOCK(rt);
501     for (wp = (JSWatchPoint *)rt->watchPointList.next;
502     &wp->links != &rt->watchPointList;
503     wp = next) {
504     next = (JSWatchPoint *)wp->links.next;
505     if (js_IsAboutToBeFinalized(cx, wp->object)) {
506     sample = rt->debuggerMutations;
507    
508     /* Ignore failures. */
509     DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
510     DBG_LOCK(rt);
511     if (rt->debuggerMutations != sample + 1)
512     next = (JSWatchPoint *)rt->watchPointList.next;
513     }
514     }
515     DBG_UNLOCK(rt);
516     }
517    
518    
519    
520     /*
521     * NB: FindWatchPoint must be called with rt->debuggerLock acquired.
522     */
523     static JSWatchPoint *
524     FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
525     {
526     JSWatchPoint *wp;
527    
528     for (wp = (JSWatchPoint *)rt->watchPointList.next;
529     &wp->links != &rt->watchPointList;
530     wp = (JSWatchPoint *)wp->links.next) {
531 siliconforks 507 if (OBJ_SCOPE(wp->object) == scope && wp->sprop->id == id)
532 siliconforks 332 return wp;
533     }
534     return NULL;
535     }
536    
537     JSScopeProperty *
538     js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
539     {
540     JSWatchPoint *wp;
541     JSScopeProperty *sprop;
542    
543     DBG_LOCK(rt);
544     wp = FindWatchPoint(rt, scope, id);
545     sprop = wp ? wp->sprop : NULL;
546     DBG_UNLOCK(rt);
547     return sprop;
548     }
549    
550     /*
551     * Secret handshake with DropWatchPointAndUnlock: if (!scope), we know our
552     * caller has acquired rt->debuggerLock, so we don't have to.
553     */
554     JSPropertyOp
555     js_GetWatchedSetter(JSRuntime *rt, JSScope *scope,
556     const JSScopeProperty *sprop)
557     {
558     JSPropertyOp setter;
559     JSWatchPoint *wp;
560    
561     setter = NULL;
562     if (scope)
563     DBG_LOCK(rt);
564     for (wp = (JSWatchPoint *)rt->watchPointList.next;
565     &wp->links != &rt->watchPointList;
566     wp = (JSWatchPoint *)wp->links.next) {
567 siliconforks 507 if ((!scope || OBJ_SCOPE(wp->object) == scope) && wp->sprop == sprop) {
568 siliconforks 332 setter = wp->setter;
569     break;
570     }
571     }
572     if (scope)
573     DBG_UNLOCK(rt);
574     return setter;
575     }
576    
577     JSBool
578     js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
579     {
580     JSRuntime *rt;
581     JSWatchPoint *wp;
582     JSScopeProperty *sprop;
583     jsval propid, userid;
584     JSScope *scope;
585     JSBool ok;
586    
587     rt = cx->runtime;
588     DBG_LOCK(rt);
589     for (wp = (JSWatchPoint *)rt->watchPointList.next;
590     &wp->links != &rt->watchPointList;
591     wp = (JSWatchPoint *)wp->links.next) {
592     sprop = wp->sprop;
593     if (wp->object == obj && SPROP_USERID(sprop) == id &&
594     !(wp->flags & JSWP_HELD)) {
595     wp->flags |= JSWP_HELD;
596     DBG_UNLOCK(rt);
597    
598     JS_LOCK_OBJ(cx, obj);
599     propid = ID_TO_VALUE(sprop->id);
600     userid = (sprop->flags & SPROP_HAS_SHORTID)
601     ? INT_TO_JSVAL(sprop->shortid)
602     : propid;
603     scope = OBJ_SCOPE(obj);
604     JS_UNLOCK_OBJ(cx, obj);
605    
606     /* NB: wp is held, so we can safely dereference it still. */
607     ok = wp->handler(cx, obj, propid,
608     SPROP_HAS_VALID_SLOT(sprop, scope)
609     ? OBJ_GET_SLOT(cx, obj, sprop->slot)
610     : JSVAL_VOID,
611     vp, wp->closure);
612     if (ok) {
613     /*
614     * Create a pseudo-frame for the setter invocation so that any
615     * stack-walking security code under the setter will correctly
616     * identify the guilty party. So that the watcher appears to
617     * be active to obj_eval and other such code, point frame.pc
618     * at the JSOP_STOP at the end of the script.
619     *
620     * The pseudo-frame is not created for fast natives as they
621     * are treated as interpreter frame extensions and always
622     * trusted.
623     */
624     JSObject *closure;
625     JSClass *clasp;
626     JSFunction *fun;
627     JSScript *script;
628     JSBool injectFrame;
629 siliconforks 460 uintN nslots, slotsStart;
630 siliconforks 332 jsval smallv[5];
631     jsval *argv;
632     JSStackFrame frame;
633     JSFrameRegs regs;
634    
635 siliconforks 507 closure = wp->closure;
636 siliconforks 332 clasp = OBJ_GET_CLASS(cx, closure);
637     if (clasp == &js_FunctionClass) {
638     fun = GET_FUNCTION_PRIVATE(cx, closure);
639     script = FUN_SCRIPT(fun);
640     } else if (clasp == &js_ScriptClass) {
641     fun = NULL;
642 siliconforks 507 script = (JSScript *) closure->getPrivate();
643 siliconforks 332 } else {
644     fun = NULL;
645     script = NULL;
646     }
647    
648 siliconforks 460 slotsStart = nslots = 2;
649 siliconforks 332 injectFrame = JS_TRUE;
650     if (fun) {
651     nslots += FUN_MINARGS(fun);
652     if (!FUN_INTERPRETED(fun)) {
653     nslots += fun->u.n.extra;
654     injectFrame = !(fun->flags & JSFUN_FAST_NATIVE);
655     }
656 siliconforks 460
657     slotsStart = nslots;
658 siliconforks 332 }
659 siliconforks 460 if (script)
660     nslots += script->nslots;
661 siliconforks 332
662     if (injectFrame) {
663     if (nslots <= JS_ARRAY_LENGTH(smallv)) {
664     argv = smallv;
665     } else {
666 siliconforks 507 argv = (jsval *) cx->malloc(nslots * sizeof(jsval));
667 siliconforks 332 if (!argv) {
668     DBG_LOCK(rt);
669     DropWatchPointAndUnlock(cx, wp, JSWP_HELD);
670     return JS_FALSE;
671     }
672     }
673    
674     argv[0] = OBJECT_TO_JSVAL(closure);
675     argv[1] = JSVAL_NULL;
676     memset(argv + 2, 0, (nslots - 2) * sizeof(jsval));
677    
678     memset(&frame, 0, sizeof(frame));
679     frame.script = script;
680     frame.regs = NULL;
681 siliconforks 460 frame.fun = fun;
682     frame.argv = argv + 2;
683     frame.down = js_GetTopStackFrame(cx);
684     frame.scopeChain = OBJ_GET_PARENT(cx, closure);
685     if (script && script->nslots)
686     frame.slots = argv + slotsStart;
687 siliconforks 332 if (script) {
688     JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
689     regs.pc = script->code + script->length
690     - JSOP_STOP_LENGTH;
691     regs.sp = NULL;
692     frame.regs = &regs;
693 siliconforks 460 if (fun &&
694     JSFUN_HEAVYWEIGHT_TEST(fun->flags) &&
695     !js_GetCallObject(cx, &frame)) {
696     if (argv != smallv)
697 siliconforks 507 cx->free(argv);
698 siliconforks 460 DBG_LOCK(rt);
699     DropWatchPointAndUnlock(cx, wp, JSWP_HELD);
700     return JS_FALSE;
701     }
702 siliconforks 332 }
703    
704     cx->fp = &frame;
705     }
706     #ifdef __GNUC__
707     else
708     argv = NULL; /* suppress bogus gcc warnings */
709     #endif
710     ok = !wp->setter ||
711     ((sprop->attrs & JSPROP_SETTER)
712 siliconforks 460 ? js_InternalCall(cx, obj,
713     js_CastAsObjectJSVal(wp->setter),
714 siliconforks 332 1, vp, vp)
715 siliconforks 460 : wp->setter(cx, obj, userid, vp));
716 siliconforks 332 if (injectFrame) {
717     /* Evil code can cause us to have an arguments object. */
718 siliconforks 507 frame.putActivationObjects(cx);
719 siliconforks 332 cx->fp = frame.down;
720     if (argv != smallv)
721 siliconforks 507 cx->free(argv);
722 siliconforks 332 }
723     }
724     DBG_LOCK(rt);
725     return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok;
726     }
727     }
728     DBG_UNLOCK(rt);
729     return JS_TRUE;
730     }
731    
732 siliconforks 507 JSBool
733 siliconforks 332 js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
734     jsval *rval)
735     {
736     JSObject *funobj;
737     JSFunction *wrapper;
738     jsval userid;
739    
740     funobj = JSVAL_TO_OBJECT(argv[-2]);
741     wrapper = GET_FUNCTION_PRIVATE(cx, funobj);
742     userid = ATOM_KEY(wrapper->atom);
743     *rval = argv[0];
744     return js_watch_set(cx, obj, userid, rval);
745     }
746    
747     JSPropertyOp
748     js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
749     {
750     JSAtom *atom;
751     JSFunction *wrapper;
752    
753     if (!(attrs & JSPROP_SETTER))
754     return &js_watch_set; /* & to silence schoolmarmish MSVC */
755    
756     if (JSID_IS_ATOM(id)) {
757     atom = JSID_TO_ATOM(id);
758     } else if (JSID_IS_INT(id)) {
759     if (!js_ValueToStringId(cx, INT_JSID_TO_JSVAL(id), &id))
760     return NULL;
761     atom = JSID_TO_ATOM(id);
762     } else {
763     atom = NULL;
764     }
765     wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
766 siliconforks 460 OBJ_GET_PARENT(cx, js_CastAsObject(setter)),
767 siliconforks 332 atom);
768     if (!wrapper)
769     return NULL;
770 siliconforks 460 return js_CastAsPropertyOp(FUN_OBJECT(wrapper));
771 siliconforks 332 }
772    
773     JS_PUBLIC_API(JSBool)
774     JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval,
775     JSWatchPointHandler handler, void *closure)
776     {
777 siliconforks 507 JSObject *origobj;
778     jsval v;
779     uintN attrs;
780 siliconforks 332 jsid propid;
781     JSObject *pobj;
782     JSProperty *prop;
783     JSScopeProperty *sprop;
784     JSRuntime *rt;
785     JSBool ok;
786     JSWatchPoint *wp;
787     JSPropertyOp watcher;
788    
789 siliconforks 507 origobj = obj;
790     obj = js_GetWrappedObject(cx, obj);
791     OBJ_TO_INNER_OBJECT(cx, obj);
792     if (!obj)
793 siliconforks 332 return JS_FALSE;
794    
795 siliconforks 460 if (JSVAL_IS_INT(idval)) {
796 siliconforks 332 propid = INT_JSVAL_TO_JSID(idval);
797 siliconforks 460 } else {
798     if (!js_ValueToStringId(cx, idval, &propid))
799     return JS_FALSE;
800 siliconforks 507 propid = js_CheckForStringIndex(propid);
801 siliconforks 460 }
802 siliconforks 332
803 siliconforks 507 /*
804     * If, by unwrapping and innerizing, we changed the object, check
805     * again to make sure that we're allowed to set a watch point.
806     */
807     if (origobj != obj && !obj->checkAccess(cx, propid, JSACC_WATCH, &v, &attrs))
808     return JS_FALSE;
809    
810     if (!OBJ_IS_NATIVE(obj)) {
811     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
812     OBJ_GET_CLASS(cx, obj)->name);
813     return JS_FALSE;
814     }
815    
816 siliconforks 332 if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
817     return JS_FALSE;
818     sprop = (JSScopeProperty *) prop;
819     rt = cx->runtime;
820     if (!sprop) {
821     /* Check for a deleted symbol watchpoint, which holds its property. */
822     sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
823     if (!sprop) {
824     /* Make a new property in obj so we can watch for the first set. */
825 siliconforks 507 if (!js_DefineNativeProperty(cx, obj, propid, JSVAL_VOID, NULL, NULL,
826     JSPROP_ENUMERATE, 0, 0, &prop)) {
827 siliconforks 332 return JS_FALSE;
828     }
829     sprop = (JSScopeProperty *) prop;
830     }
831     } else if (pobj != obj) {
832     /* Clone the prototype property so we can watch the right object. */
833     jsval value;
834     JSPropertyOp getter, setter;
835     uintN attrs, flags;
836     intN shortid;
837    
838     if (OBJ_IS_NATIVE(pobj)) {
839     value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
840     ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
841     : JSVAL_VOID;
842     getter = sprop->getter;
843     setter = sprop->setter;
844     attrs = sprop->attrs;
845     flags = sprop->flags;
846     shortid = sprop->shortid;
847     } else {
848 siliconforks 507 if (!pobj->getProperty(cx, propid, &value) ||
849     !pobj->getAttributes(cx, propid, prop, &attrs)) {
850     pobj->dropProperty(cx, prop);
851 siliconforks 332 return JS_FALSE;
852     }
853     getter = setter = NULL;
854     flags = 0;
855     shortid = 0;
856     }
857 siliconforks 507 pobj->dropProperty(cx, prop);
858 siliconforks 332
859     /* Recall that obj is native, whether or not pobj is native. */
860     if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter,
861     attrs, flags, shortid, &prop)) {
862     return JS_FALSE;
863     }
864     sprop = (JSScopeProperty *) prop;
865     }
866    
867     /*
868     * At this point, prop/sprop exists in obj, obj is locked, and we must
869 siliconforks 507 * obj->dropProperty(cx, prop) before returning.
870 siliconforks 332 */
871     ok = JS_TRUE;
872     DBG_LOCK(rt);
873     wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
874     if (!wp) {
875     DBG_UNLOCK(rt);
876     watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter);
877     if (!watcher) {
878     ok = JS_FALSE;
879     goto out;
880     }
881    
882 siliconforks 507 wp = (JSWatchPoint *) cx->malloc(sizeof *wp);
883 siliconforks 332 if (!wp) {
884     ok = JS_FALSE;
885     goto out;
886     }
887     wp->handler = NULL;
888     wp->closure = NULL;
889     wp->object = obj;
890     JS_ASSERT(sprop->setter != js_watch_set || pobj != obj);
891     wp->setter = sprop->setter;
892     wp->flags = JSWP_LIVE;
893    
894     /* XXXbe nest in obj lock here */
895     sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs,
896     sprop->getter, watcher);
897     if (!sprop) {
898     /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */
899     JS_INIT_CLIST(&wp->links);
900     DBG_LOCK(rt);
901     DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
902     ok = JS_FALSE;
903     goto out;
904     }
905     wp->sprop = sprop;
906    
907     /*
908     * Now that wp is fully initialized, append it to rt's wp list.
909     * Because obj is locked we know that no other thread could have added
910     * a watchpoint for (obj, propid).
911     */
912     DBG_LOCK(rt);
913     JS_ASSERT(!FindWatchPoint(rt, OBJ_SCOPE(obj), propid));
914     JS_APPEND_LINK(&wp->links, &rt->watchPointList);
915     ++rt->debuggerMutations;
916     }
917     wp->handler = handler;
918 siliconforks 507 wp->closure = reinterpret_cast<JSObject*>(closure);
919 siliconforks 332 DBG_UNLOCK(rt);
920    
921     out:
922 siliconforks 507 obj->dropProperty(cx, prop);
923 siliconforks 332 return ok;
924     }
925    
926     JS_PUBLIC_API(JSBool)
927     JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
928     JSWatchPointHandler *handlerp, void **closurep)
929     {
930     JSRuntime *rt;
931     JSWatchPoint *wp;
932    
933     rt = cx->runtime;
934     DBG_LOCK(rt);
935     for (wp = (JSWatchPoint *)rt->watchPointList.next;
936     &wp->links != &rt->watchPointList;
937     wp = (JSWatchPoint *)wp->links.next) {
938     if (wp->object == obj && SPROP_USERID(wp->sprop) == id) {
939     if (handlerp)
940     *handlerp = wp->handler;
941     if (closurep)
942     *closurep = wp->closure;
943     return DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
944     }
945     }
946     DBG_UNLOCK(rt);
947     if (handlerp)
948     *handlerp = NULL;
949     if (closurep)
950     *closurep = NULL;
951     return JS_TRUE;
952     }
953    
954     JS_PUBLIC_API(JSBool)
955     JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
956     {
957     JSRuntime *rt;
958     JSWatchPoint *wp, *next;
959     uint32 sample;
960    
961     rt = cx->runtime;
962     DBG_LOCK(rt);
963     for (wp = (JSWatchPoint *)rt->watchPointList.next;
964     &wp->links != &rt->watchPointList;
965     wp = next) {
966     next = (JSWatchPoint *)wp->links.next;
967     if (wp->object == obj) {
968     sample = rt->debuggerMutations;
969     if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE))
970     return JS_FALSE;
971     DBG_LOCK(rt);
972     if (rt->debuggerMutations != sample + 1)
973     next = (JSWatchPoint *)rt->watchPointList.next;
974     }
975     }
976     DBG_UNLOCK(rt);
977     return JS_TRUE;
978     }
979    
980     JS_PUBLIC_API(JSBool)
981     JS_ClearAllWatchPoints(JSContext *cx)
982     {
983     JSRuntime *rt;
984     JSWatchPoint *wp, *next;
985     uint32 sample;
986    
987     rt = cx->runtime;
988     DBG_LOCK(rt);
989     for (wp = (JSWatchPoint *)rt->watchPointList.next;
990     &wp->links != &rt->watchPointList;
991     wp = next) {
992     next = (JSWatchPoint *)wp->links.next;
993     sample = rt->debuggerMutations;
994     if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE))
995     return JS_FALSE;
996     DBG_LOCK(rt);
997     if (rt->debuggerMutations != sample + 1)
998     next = (JSWatchPoint *)rt->watchPointList.next;
999     }
1000     DBG_UNLOCK(rt);
1001     return JS_TRUE;
1002     }
1003    
1004     /************************************************************************/
1005    
1006     JS_PUBLIC_API(uintN)
1007     JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
1008     {
1009     return js_PCToLineNumber(cx, script, pc);
1010     }
1011    
1012     JS_PUBLIC_API(jsbytecode *)
1013     JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
1014     {
1015     return js_LineNumberToPC(script, lineno);
1016     }
1017    
1018     JS_PUBLIC_API(JSScript *)
1019     JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
1020     {
1021     return FUN_SCRIPT(fun);
1022     }
1023    
1024     JS_PUBLIC_API(JSNative)
1025     JS_GetFunctionNative(JSContext *cx, JSFunction *fun)
1026     {
1027     return FUN_NATIVE(fun);
1028     }
1029    
1030     JS_PUBLIC_API(JSFastNative)
1031     JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun)
1032     {
1033     return FUN_FAST_NATIVE(fun);
1034     }
1035    
1036     JS_PUBLIC_API(JSPrincipals *)
1037     JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
1038     {
1039     return script->principals;
1040     }
1041    
1042     /************************************************************************/
1043    
1044     /*
1045     * Stack Frame Iterator
1046     */
1047     JS_PUBLIC_API(JSStackFrame *)
1048     JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
1049     {
1050 siliconforks 460 *iteratorp = (*iteratorp == NULL) ? js_GetTopStackFrame(cx) : (*iteratorp)->down;
1051 siliconforks 332 return *iteratorp;
1052     }
1053    
1054     JS_PUBLIC_API(JSScript *)
1055     JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
1056     {
1057     return fp->script;
1058     }
1059    
1060     JS_PUBLIC_API(jsbytecode *)
1061     JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
1062     {
1063     return fp->regs ? fp->regs->pc : NULL;
1064     }
1065    
1066     JS_PUBLIC_API(JSStackFrame *)
1067     JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
1068     {
1069 siliconforks 460 return js_GetScriptedCaller(cx, fp);
1070 siliconforks 332 }
1071    
1072     JS_PUBLIC_API(JSPrincipals *)
1073     JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
1074     {
1075     JSSecurityCallbacks *callbacks;
1076    
1077     if (fp->fun) {
1078     callbacks = JS_GetSecurityCallbacks(cx);
1079     if (callbacks && callbacks->findObjectPrincipals) {
1080 siliconforks 507 if (FUN_OBJECT(fp->fun) != fp->callee())
1081     return callbacks->findObjectPrincipals(cx, fp->callee());
1082 siliconforks 332 /* FALL THROUGH */
1083     }
1084     }
1085     if (fp->script)
1086     return fp->script->principals;
1087     return NULL;
1088     }
1089    
1090     JS_PUBLIC_API(JSPrincipals *)
1091     JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
1092     {
1093     JSPrincipals *principals, *callerPrincipals;
1094     JSSecurityCallbacks *callbacks;
1095    
1096     callbacks = JS_GetSecurityCallbacks(cx);
1097     if (callbacks && callbacks->findObjectPrincipals) {
1098 siliconforks 507 principals = callbacks->findObjectPrincipals(cx, fp->callee());
1099 siliconforks 332 } else {
1100     principals = NULL;
1101     }
1102     if (!caller)
1103     return principals;
1104     callerPrincipals = JS_StackFramePrincipals(cx, caller);
1105     return (callerPrincipals && principals &&
1106     callerPrincipals->subsume(callerPrincipals, principals))
1107     ? principals
1108     : callerPrincipals;
1109     }
1110    
1111     JS_PUBLIC_API(void *)
1112     JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
1113     {
1114     if (fp->annotation && fp->script) {
1115     JSPrincipals *principals = JS_StackFramePrincipals(cx, fp);
1116    
1117     if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
1118     /*
1119     * Give out an annotation only if privileges have not been revoked
1120     * or disabled globally.
1121     */
1122     return fp->annotation;
1123     }
1124     }
1125    
1126     return NULL;
1127     }
1128    
1129     JS_PUBLIC_API(void)
1130     JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
1131     {
1132     fp->annotation = annotation;
1133     }
1134    
1135     JS_PUBLIC_API(void *)
1136     JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
1137     {
1138     JSPrincipals *principals;
1139    
1140     principals = JS_StackFramePrincipals(cx, fp);
1141     if (!principals)
1142     return NULL;
1143     return principals->getPrincipalArray(cx, principals);
1144     }
1145    
1146     JS_PUBLIC_API(JSBool)
1147     JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
1148     {
1149     return !fp->script;
1150     }
1151    
1152     /* this is deprecated, use JS_GetFrameScopeChain instead */
1153     JS_PUBLIC_API(JSObject *)
1154     JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
1155     {
1156     return fp->scopeChain;
1157     }
1158    
1159     JS_PUBLIC_API(JSObject *)
1160     JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
1161     {
1162     /* Force creation of argument and call objects if not yet created */
1163     (void) JS_GetFrameCallObject(cx, fp);
1164     return js_GetScopeChain(cx, fp);
1165     }
1166    
1167     JS_PUBLIC_API(JSObject *)
1168     JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
1169     {
1170     if (! fp->fun)
1171     return NULL;
1172    
1173     /* Force creation of argument object if not yet created */
1174     (void) js_GetArgsObject(cx, fp);
1175    
1176     /*
1177     * XXX ill-defined: null return here means error was reported, unlike a
1178     * null returned above or in the #else
1179     */
1180 siliconforks 460 return js_GetCallObject(cx, fp);
1181 siliconforks 332 }
1182    
1183     JS_PUBLIC_API(JSObject *)
1184     JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
1185     {
1186     JSStackFrame *afp;
1187    
1188     if (fp->flags & JSFRAME_COMPUTED_THIS)
1189     return fp->thisp;
1190    
1191     /* js_ComputeThis gets confused if fp != cx->fp, so set it aside. */
1192 siliconforks 460 if (js_GetTopStackFrame(cx) != fp) {
1193 siliconforks 332 afp = cx->fp;
1194     if (afp) {
1195     afp->dormantNext = cx->dormantFrameChain;
1196     cx->dormantFrameChain = afp;
1197     cx->fp = fp;
1198     }
1199     } else {
1200     afp = NULL;
1201     }
1202    
1203 siliconforks 507 if (fp->argv)
1204 siliconforks 332 fp->thisp = js_ComputeThis(cx, JS_TRUE, fp->argv);
1205    
1206     if (afp) {
1207     cx->fp = afp;
1208     cx->dormantFrameChain = afp->dormantNext;
1209     afp->dormantNext = NULL;
1210     }
1211    
1212     return fp->thisp;
1213     }
1214    
1215     JS_PUBLIC_API(JSFunction *)
1216     JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
1217     {
1218     return fp->fun;
1219     }
1220    
1221     JS_PUBLIC_API(JSObject *)
1222     JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
1223     {
1224     if (!fp->fun)
1225     return NULL;
1226    
1227 siliconforks 507 JS_ASSERT(HAS_FUNCTION_CLASS(fp->callee()));
1228     JS_ASSERT(fp->callee()->getPrivate() == fp->fun);
1229     return fp->callee();
1230 siliconforks 332 }
1231    
1232     JS_PUBLIC_API(JSBool)
1233     JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
1234     {
1235     return (fp->flags & JSFRAME_CONSTRUCTING) != 0;
1236     }
1237    
1238     JS_PUBLIC_API(JSObject *)
1239     JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
1240     {
1241 siliconforks 507 return fp->callee();
1242 siliconforks 332 }
1243    
1244     JS_PUBLIC_API(JSBool)
1245     JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
1246     {
1247     return (fp->flags & JSFRAME_DEBUGGER) != 0;
1248     }
1249    
1250     JS_PUBLIC_API(jsval)
1251     JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
1252     {
1253     return fp->rval;
1254     }
1255    
1256     JS_PUBLIC_API(void)
1257     JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
1258     {
1259     fp->rval = rval;
1260     }
1261    
1262     /************************************************************************/
1263    
1264     JS_PUBLIC_API(const char *)
1265     JS_GetScriptFilename(JSContext *cx, JSScript *script)
1266     {
1267     return script->filename;
1268     }
1269    
1270     JS_PUBLIC_API(uintN)
1271     JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
1272     {
1273     return script->lineno;
1274     }
1275    
1276     JS_PUBLIC_API(uintN)
1277     JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
1278     {
1279     return js_GetScriptLineExtent(script);
1280     }
1281    
1282     JS_PUBLIC_API(JSVersion)
1283     JS_GetScriptVersion(JSContext *cx, JSScript *script)
1284     {
1285     return (JSVersion) (script->version & JSVERSION_MASK);
1286     }
1287    
1288     /***************************************************************************/
1289    
1290     JS_PUBLIC_API(void)
1291     JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
1292     {
1293     rt->globalDebugHooks.newScriptHook = hook;
1294     rt->globalDebugHooks.newScriptHookData = callerdata;
1295     }
1296    
1297     JS_PUBLIC_API(void)
1298     JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
1299     void *callerdata)
1300     {
1301     rt->globalDebugHooks.destroyScriptHook = hook;
1302     rt->globalDebugHooks.destroyScriptHookData = callerdata;
1303     }
1304    
1305     /***************************************************************************/
1306    
1307     JS_PUBLIC_API(JSBool)
1308     JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
1309     const jschar *chars, uintN length,
1310     const char *filename, uintN lineno,
1311     jsval *rval)
1312     {
1313 siliconforks 460 JS_ASSERT_NOT_ON_TRACE(cx);
1314    
1315 siliconforks 332 JSObject *scobj;
1316     JSScript *script;
1317     JSBool ok;
1318    
1319     scobj = JS_GetFrameScopeChain(cx, fp);
1320     if (!scobj)
1321     return JS_FALSE;
1322    
1323 siliconforks 460 /*
1324     * NB: This function breaks the assumption that the compiler can see all
1325     * calls and properly compute a static level. In order to get around this,
1326     * we use a static level that will cause us not to attempt to optimize
1327     * variable references made by this frame.
1328     */
1329     script = JSCompiler::compileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp),
1330     TCF_COMPILE_N_GO |
1331     TCF_PUT_STATIC_LEVEL(JS_DISPLAY_SIZE),
1332     chars, length, NULL,
1333     filename, lineno);
1334    
1335 siliconforks 332 if (!script)
1336     return JS_FALSE;
1337    
1338 siliconforks 460 JSStackFrame *displayCopy[JS_DISPLAY_SIZE];
1339     if (cx->fp != fp) {
1340     memcpy(displayCopy, cx->display, sizeof displayCopy);
1341    
1342     /*
1343     * Set up cx->display as it would have been when fp was active.
1344     *
1345     * NB: To reconstruct cx->display for fp, we have to follow the frame
1346     * chain from oldest to youngest, in the opposite direction to its
1347     * single linkge. To avoid the obvious recursive reversal algorithm,
1348     * which might use too much stack, we reverse in place and reverse
1349     * again as we reconstruct the display. This is safe because cx is
1350     * thread-local and we can't cause GC until the call to js_Execute
1351     * below.
1352     */
1353     JSStackFrame *fp2 = fp, *last = NULL;
1354     while (fp2) {
1355     JSStackFrame *next = fp2->down;
1356     fp2->down = last;
1357     last = fp2;
1358     fp2 = next;
1359     }
1360    
1361     fp2 = last;
1362     last = NULL;
1363     while (fp2) {
1364     JSStackFrame *next = fp2->down;
1365     fp2->down = last;
1366     last = fp2;
1367    
1368     JSScript *script = fp2->script;
1369     if (script && script->staticLevel < JS_DISPLAY_SIZE)
1370     cx->display[script->staticLevel] = fp2;
1371     fp2 = next;
1372     }
1373     }
1374    
1375 siliconforks 332 ok = js_Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL,
1376     rval);
1377 siliconforks 460
1378     if (cx->fp != fp)
1379     memcpy(cx->display, displayCopy, sizeof cx->display);
1380 siliconforks 332 js_DestroyScript(cx, script);
1381     return ok;
1382     }
1383    
1384     JS_PUBLIC_API(JSBool)
1385     JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
1386     const char *bytes, uintN length,
1387     const char *filename, uintN lineno,
1388     jsval *rval)
1389     {
1390     jschar *chars;
1391     JSBool ok;
1392     size_t len = length;
1393    
1394     chars = js_InflateString(cx, bytes, &len);
1395     if (!chars)
1396     return JS_FALSE;
1397     length = (uintN) len;
1398     ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
1399     rval);
1400 siliconforks 507 cx->free(chars);
1401 siliconforks 332
1402     return ok;
1403     }
1404    
1405     /************************************************************************/
1406    
1407     /* XXXbe this all needs to be reworked to avoid requiring JSScope types. */
1408    
1409     JS_PUBLIC_API(JSScopeProperty *)
1410     JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
1411     {
1412     JSScopeProperty *sprop;
1413     JSScope *scope;
1414    
1415     sprop = *iteratorp;
1416     scope = OBJ_SCOPE(obj);
1417    
1418     /* XXXbe minor(?) incompatibility: iterate in reverse definition order */
1419     if (!sprop) {
1420     sprop = SCOPE_LAST_PROP(scope);
1421     } else {
1422     while ((sprop = sprop->parent) != NULL) {
1423 siliconforks 507 if (!scope->hadMiddleDelete())
1424 siliconforks 332 break;
1425 siliconforks 507 if (scope->has(sprop))
1426 siliconforks 332 break;
1427     }
1428     }
1429     *iteratorp = sprop;
1430     return sprop;
1431     }
1432    
1433     JS_PUBLIC_API(JSBool)
1434     JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
1435     JSPropertyDesc *pd)
1436     {
1437     JSScope *scope;
1438     JSScopeProperty *aprop;
1439     jsval lastException;
1440     JSBool wasThrowing;
1441    
1442     pd->id = ID_TO_VALUE(sprop->id);
1443    
1444     wasThrowing = cx->throwing;
1445     if (wasThrowing) {
1446     lastException = cx->exception;
1447     if (JSVAL_IS_GCTHING(lastException) &&
1448     !js_AddRoot(cx, &lastException, "lastException")) {
1449     return JS_FALSE;
1450     }
1451     cx->throwing = JS_FALSE;
1452     }
1453    
1454     if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) {
1455     if (!cx->throwing) {
1456     pd->flags = JSPD_ERROR;
1457     pd->value = JSVAL_VOID;
1458     } else {
1459     pd->flags = JSPD_EXCEPTION;
1460     pd->value = cx->exception;
1461     }
1462     } else {
1463     pd->flags = 0;
1464     }
1465    
1466     cx->throwing = wasThrowing;
1467     if (wasThrowing) {
1468     cx->exception = lastException;
1469     if (JSVAL_IS_GCTHING(lastException))
1470     js_RemoveRoot(cx->runtime, &lastException);
1471     }
1472    
1473     pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
1474     | ((sprop->attrs & JSPROP_READONLY) ? JSPD_READONLY : 0)
1475     | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0);
1476     pd->spare = 0;
1477     if (sprop->getter == js_GetCallArg) {
1478     pd->slot = sprop->shortid;
1479     pd->flags |= JSPD_ARGUMENT;
1480     } else if (sprop->getter == js_GetCallVar) {
1481     pd->slot = sprop->shortid;
1482     pd->flags |= JSPD_VARIABLE;
1483     } else {
1484     pd->slot = 0;
1485     }
1486     pd->alias = JSVAL_VOID;
1487     scope = OBJ_SCOPE(obj);
1488     if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
1489     for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) {
1490     if (aprop != sprop && aprop->slot == sprop->slot) {
1491     pd->alias = ID_TO_VALUE(aprop->id);
1492     break;
1493     }
1494     }
1495     }
1496     return JS_TRUE;
1497     }
1498    
1499     JS_PUBLIC_API(JSBool)
1500     JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
1501     {
1502     JSClass *clasp;
1503     JSScope *scope;
1504     uint32 i, n;
1505     JSPropertyDesc *pd;
1506     JSScopeProperty *sprop;
1507    
1508     clasp = OBJ_GET_CLASS(cx, obj);
1509     if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
1510     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1511     JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
1512     return JS_FALSE;
1513     }
1514     if (!clasp->enumerate(cx, obj))
1515     return JS_FALSE;
1516    
1517     /* have no props, or object's scope has not mutated from that of proto */
1518     scope = OBJ_SCOPE(obj);
1519 siliconforks 507 if (scope->entryCount == 0) {
1520 siliconforks 332 pda->length = 0;
1521     pda->array = NULL;
1522     return JS_TRUE;
1523     }
1524    
1525 siliconforks 460 n = scope->entryCount;
1526 siliconforks 507 pd = (JSPropertyDesc *) cx->malloc((size_t)n * sizeof(JSPropertyDesc));
1527 siliconforks 332 if (!pd)
1528     return JS_FALSE;
1529     i = 0;
1530     for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
1531 siliconforks 507 if (scope->hadMiddleDelete() && !scope->has(sprop))
1532 siliconforks 332 continue;
1533     if (!js_AddRoot(cx, &pd[i].id, NULL))
1534     goto bad;
1535     if (!js_AddRoot(cx, &pd[i].value, NULL))
1536     goto bad;
1537     if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i]))
1538     goto bad;
1539     if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
1540     goto bad;
1541     if (++i == n)
1542     break;
1543     }
1544     pda->length = i;
1545     pda->array = pd;
1546     return JS_TRUE;
1547    
1548     bad:
1549     pda->length = i + 1;
1550     pda->array = pd;
1551     JS_PutPropertyDescArray(cx, pda);
1552     return JS_FALSE;
1553     }
1554    
1555     JS_PUBLIC_API(void)
1556     JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
1557     {
1558     JSPropertyDesc *pd;
1559     uint32 i;
1560    
1561     pd = pda->array;
1562     for (i = 0; i < pda->length; i++) {
1563     js_RemoveRoot(cx->runtime, &pd[i].id);
1564     js_RemoveRoot(cx->runtime, &pd[i].value);
1565     if (pd[i].flags & JSPD_ALIAS)
1566     js_RemoveRoot(cx->runtime, &pd[i].alias);
1567     }
1568 siliconforks 507 cx->free(pd);
1569 siliconforks 332 }
1570    
1571     /************************************************************************/
1572    
1573 siliconforks 585 class FakeFrame {
1574     public:
1575     FakeFrame(JSContext *cx, JSObject *scopeobj)
1576     : cx(cx) {
1577     JSFunction *fun = GET_FUNCTION_PRIVATE(cx, scopeobj);
1578     JS_ASSERT(FUN_MINARGS(fun) == 0 && !FUN_INTERPRETED(fun) && fun->u.n.extra == 0);
1579    
1580     vp[0] = OBJECT_TO_JSVAL(scopeobj);
1581     vp[1] = JSVAL_NULL;
1582    
1583     memset(&frame, 0, sizeof (frame));
1584     frame.fun = fun;
1585     frame.down = js_GetTopStackFrame(cx);
1586     frame.scopeChain = JS_GetGlobalForObject(cx, scopeobj);
1587     frame.argv = vp + 2;
1588    
1589     cx->fp = &frame;
1590     }
1591    
1592     ~FakeFrame() {
1593     if (frame.callobj)
1594     js_PutCallObject(cx, &frame);
1595     else if (frame.argsobj)
1596     js_PutArgsObject(cx, &frame);
1597     cx->fp = frame.down;
1598     }
1599    
1600     private:
1601     JSContext *cx;
1602     JSStackFrame frame;
1603     jsval vp[2];
1604     };
1605    
1606     JS_FRIEND_API(JSBool)
1607     js_GetPropertyByIdWithFakeFrame(JSContext *cx, JSObject *obj, JSObject *scopeobj, jsid id,
1608     jsval *vp)
1609     {
1610     FakeFrame frame(cx, scopeobj);
1611     return JS_GetPropertyById(cx, obj, id, vp);
1612     }
1613    
1614     JS_FRIEND_API(JSBool)
1615     js_SetPropertyByIdWithFakeFrame(JSContext *cx, JSObject *obj, JSObject *scopeobj, jsid id,
1616     jsval *vp)
1617     {
1618     FakeFrame frame(cx, scopeobj);
1619     return JS_SetPropertyById(cx, obj, id, vp);
1620     }
1621    
1622     JS_FRIEND_API(JSBool)
1623     js_CallFunctionValueWithFakeFrame(JSContext *cx, JSObject *obj, JSObject *scopeobj, jsval funval,
1624     uintN argc, jsval *argv, jsval *rval)
1625     {
1626     FakeFrame frame(cx, scopeobj);
1627     return JS_CallFunctionValue(cx, obj, funval, argc, argv, rval);
1628     }
1629    
1630     /************************************************************************/
1631    
1632 siliconforks 332 JS_PUBLIC_API(JSBool)
1633     JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure)
1634     {
1635     rt->globalDebugHooks.debuggerHandler = handler;
1636     rt->globalDebugHooks.debuggerHandlerData = closure;
1637     return JS_TRUE;
1638     }
1639    
1640     JS_PUBLIC_API(JSBool)
1641     JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
1642     {
1643     rt->globalDebugHooks.sourceHandler = handler;
1644     rt->globalDebugHooks.sourceHandlerData = closure;
1645     return JS_TRUE;
1646     }
1647    
1648     JS_PUBLIC_API(JSBool)
1649     JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1650     {
1651     rt->globalDebugHooks.executeHook = hook;
1652     rt->globalDebugHooks.executeHookData = closure;
1653     return JS_TRUE;
1654     }
1655    
1656     JS_PUBLIC_API(JSBool)
1657     JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1658     {
1659 siliconforks 507 #ifdef JS_TRACER
1660     JS_LOCK_GC(rt);
1661     bool wasInhibited = rt->debuggerInhibitsJIT();
1662     #endif
1663 siliconforks 332 rt->globalDebugHooks.callHook = hook;
1664     rt->globalDebugHooks.callHookData = closure;
1665 siliconforks 507 #ifdef JS_TRACER
1666     JITInhibitingHookChange(rt, wasInhibited);
1667     JS_UNLOCK_GC(rt);
1668     if (hook)
1669     LeaveTraceRT(rt);
1670     #endif
1671 siliconforks 332 return JS_TRUE;
1672     }
1673    
1674     JS_PUBLIC_API(JSBool)
1675     JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure)
1676     {
1677 siliconforks 507 #ifdef JS_TRACER
1678     JS_LOCK_GC(rt);
1679     bool wasInhibited = rt->debuggerInhibitsJIT();
1680     #endif
1681 siliconforks 332 rt->globalDebugHooks.objectHook = hook;
1682     rt->globalDebugHooks.objectHookData = closure;
1683 siliconforks 507 #ifdef JS_TRACER
1684     JITInhibitingHookChange(rt, wasInhibited);
1685     JS_UNLOCK_GC(rt);
1686     if (hook)
1687     LeaveTraceRT(rt);
1688     #endif
1689 siliconforks 332 return JS_TRUE;
1690     }
1691    
1692     JS_PUBLIC_API(JSBool)
1693     JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure)
1694     {
1695     rt->globalDebugHooks.throwHook = hook;
1696     rt->globalDebugHooks.throwHookData = closure;
1697     return JS_TRUE;
1698     }
1699    
1700     JS_PUBLIC_API(JSBool)
1701     JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
1702     {
1703     rt->globalDebugHooks.debugErrorHook = hook;
1704     rt->globalDebugHooks.debugErrorHookData = closure;
1705     return JS_TRUE;
1706     }
1707    
1708     /************************************************************************/
1709    
1710     JS_PUBLIC_API(size_t)
1711     JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
1712     {
1713     size_t nbytes;
1714     JSScope *scope;
1715    
1716     nbytes = sizeof *obj;
1717     if (obj->dslots) {
1718     nbytes += ((uint32)obj->dslots[-1] - JS_INITIAL_NSLOTS + 1)
1719     * sizeof obj->dslots[0];
1720     }
1721     if (OBJ_IS_NATIVE(obj)) {
1722     scope = OBJ_SCOPE(obj);
1723 siliconforks 507 if (scope->owned()) {
1724 siliconforks 332 nbytes += sizeof *scope;
1725     nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *);
1726     }
1727     }
1728     return nbytes;
1729     }
1730    
1731     static size_t
1732     GetAtomTotalSize(JSContext *cx, JSAtom *atom)
1733     {
1734     size_t nbytes;
1735    
1736     nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub);
1737     if (ATOM_IS_STRING(atom)) {
1738     nbytes += sizeof(JSString);
1739 siliconforks 507 nbytes += (ATOM_TO_STRING(atom)->flatLength() + 1) * sizeof(jschar);
1740 siliconforks 332 } else if (ATOM_IS_DOUBLE(atom)) {
1741     nbytes += sizeof(jsdouble);
1742     }
1743     return nbytes;
1744     }
1745    
1746     JS_PUBLIC_API(size_t)
1747     JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
1748     {
1749     size_t nbytes;
1750    
1751     nbytes = sizeof *fun;
1752     nbytes += JS_GetObjectTotalSize(cx, FUN_OBJECT(fun));
1753     if (FUN_INTERPRETED(fun))
1754     nbytes += JS_GetScriptTotalSize(cx, fun->u.i.script);
1755     if (fun->atom)
1756     nbytes += GetAtomTotalSize(cx, fun->atom);
1757     return nbytes;
1758     }
1759    
1760     #include "jsemit.h"
1761    
1762     JS_PUBLIC_API(size_t)
1763     JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
1764     {
1765     size_t nbytes, pbytes;
1766     jsatomid i;
1767     jssrcnote *sn, *notes;
1768     JSObjectArray *objarray;
1769     JSPrincipals *principals;
1770    
1771     nbytes = sizeof *script;
1772     if (script->u.object)
1773     nbytes += JS_GetObjectTotalSize(cx, script->u.object);
1774    
1775     nbytes += script->length * sizeof script->code[0];
1776     nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
1777     for (i = 0; i < script->atomMap.length; i++)
1778     nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
1779    
1780     if (script->filename)
1781     nbytes += strlen(script->filename) + 1;
1782    
1783 siliconforks 507 notes = script->notes();
1784 siliconforks 332 for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
1785     continue;
1786     nbytes += (sn - notes + 1) * sizeof *sn;
1787    
1788     if (script->objectsOffset != 0) {
1789 siliconforks 507 objarray = script->objects();
1790 siliconforks 332 i = objarray->length;
1791     nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
1792     do {
1793     nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
1794     } while (i != 0);
1795     }
1796    
1797     if (script->regexpsOffset != 0) {
1798 siliconforks 507 objarray = script->regexps();
1799 siliconforks 332 i = objarray->length;
1800     nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
1801     do {
1802     nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
1803     } while (i != 0);
1804     }
1805    
1806     if (script->trynotesOffset != 0) {
1807     nbytes += sizeof(JSTryNoteArray) +
1808 siliconforks 507 script->trynotes()->length * sizeof(JSTryNote);
1809 siliconforks 332 }
1810    
1811     principals = script->principals;
1812     if (principals) {
1813     JS_ASSERT(principals->refcount);
1814     pbytes = sizeof *principals;
1815     if (principals->refcount > 1)
1816     pbytes = JS_HOWMANY(pbytes, principals->refcount);
1817     nbytes += pbytes;
1818     }
1819    
1820     return nbytes;
1821     }
1822    
1823     JS_PUBLIC_API(uint32)
1824     JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
1825     {
1826     if (!fp)
1827 siliconforks 460 fp = js_GetTopStackFrame(cx);
1828 siliconforks 332 while (fp) {
1829     if (fp->script)
1830     return JS_GetScriptFilenameFlags(fp->script);
1831     fp = fp->down;
1832     }
1833     return 0;
1834     }
1835    
1836     JS_PUBLIC_API(uint32)
1837     JS_GetScriptFilenameFlags(JSScript *script)
1838     {
1839     JS_ASSERT(script);
1840     if (!script->filename)
1841     return JSFILENAME_NULL;
1842     return js_GetScriptFilenameFlags(script->filename);
1843     }
1844    
1845     JS_PUBLIC_API(JSBool)
1846     JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags)
1847     {
1848     if (!js_SaveScriptFilenameRT(rt, prefix, flags))
1849     return JS_FALSE;
1850     return JS_TRUE;
1851     }
1852    
1853     JS_PUBLIC_API(JSBool)
1854     JS_IsSystemObject(JSContext *cx, JSObject *obj)
1855     {
1856 siliconforks 507 return obj->isSystem();
1857 siliconforks 332 }
1858    
1859     JS_PUBLIC_API(JSObject *)
1860     JS_NewSystemObject(JSContext *cx, JSClass *clasp, JSObject *proto,
1861     JSObject *parent, JSBool system)
1862     {
1863     JSObject *obj;
1864    
1865 siliconforks 507 obj = js_NewObject(cx, clasp, proto, parent);
1866 siliconforks 332 if (obj && system)
1867 siliconforks 507 obj->setSystem();
1868 siliconforks 332 return obj;
1869     }
1870    
1871     /************************************************************************/
1872    
1873 siliconforks 507 JS_PUBLIC_API(const JSDebugHooks *)
1874 siliconforks 332 JS_GetGlobalDebugHooks(JSRuntime *rt)
1875     {
1876     return &rt->globalDebugHooks;
1877     }
1878    
1879 siliconforks 535 const JSDebugHooks js_NullDebugHooks = {};
1880    
1881 siliconforks 332 JS_PUBLIC_API(JSDebugHooks *)
1882 siliconforks 507 JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks)
1883 siliconforks 332 {
1884 siliconforks 507 JS_ASSERT(hooks);
1885 siliconforks 535 if (hooks != &cx->runtime->globalDebugHooks && hooks != &js_NullDebugHooks)
1886 siliconforks 507 js_LeaveTrace(cx);
1887 siliconforks 332
1888 siliconforks 507 #ifdef JS_TRACER
1889     JS_LOCK_GC(cx->runtime);
1890     #endif
1891     JSDebugHooks *old = const_cast<JSDebugHooks *>(cx->debugHooks);
1892 siliconforks 332 cx->debugHooks = hooks;
1893 siliconforks 507 #ifdef JS_TRACER
1894     cx->updateJITEnabled();
1895     JS_UNLOCK_GC(cx->runtime);
1896     #endif
1897 siliconforks 332 return old;
1898     }
1899    
1900 siliconforks 535 JS_PUBLIC_API(JSDebugHooks *)
1901     JS_ClearContextDebugHooks(JSContext *cx)
1902     {
1903     return JS_SetContextDebugHooks(cx, &js_NullDebugHooks);
1904     }
1905    
1906 siliconforks 332 #ifdef MOZ_SHARK
1907    
1908     #include <CHUD/CHUD.h>
1909    
1910     JS_PUBLIC_API(JSBool)
1911     JS_StartChudRemote()
1912     {
1913     if (chudIsRemoteAccessAcquired() &&
1914     (chudStartRemotePerfMonitor("Mozilla") == chudSuccess)) {
1915     return JS_TRUE;
1916     }
1917    
1918     return JS_FALSE;
1919     }
1920    
1921     JS_PUBLIC_API(JSBool)
1922     JS_StopChudRemote()
1923     {
1924     if (chudIsRemoteAccessAcquired() &&
1925     (chudStopRemotePerfMonitor() == chudSuccess)) {
1926     return JS_TRUE;
1927     }
1928    
1929     return JS_FALSE;
1930     }
1931    
1932     JS_PUBLIC_API(JSBool)
1933     JS_ConnectShark()
1934     {
1935     if (!chudIsInitialized() && (chudInitialize() != chudSuccess))
1936     return JS_FALSE;
1937    
1938     if (chudAcquireRemoteAccess() != chudSuccess)
1939     return JS_FALSE;
1940    
1941     return JS_TRUE;
1942     }
1943    
1944     JS_PUBLIC_API(JSBool)
1945     JS_DisconnectShark()
1946     {
1947     if (chudIsRemoteAccessAcquired() && (chudReleaseRemoteAccess() != chudSuccess))
1948     return JS_FALSE;
1949    
1950     return JS_TRUE;
1951     }
1952    
1953     JS_FRIEND_API(JSBool)
1954     js_StartShark(JSContext *cx, JSObject *obj,
1955     uintN argc, jsval *argv, jsval *rval)
1956     {
1957     if (!JS_StartChudRemote()) {
1958     JS_ReportError(cx, "Error starting CHUD.");
1959 siliconforks 460 return JS_FALSE;
1960 siliconforks 332 }
1961    
1962     return JS_TRUE;
1963     }
1964    
1965     JS_FRIEND_API(JSBool)
1966     js_StopShark(JSContext *cx, JSObject *obj,
1967     uintN argc, jsval *argv, jsval *rval)
1968     {
1969     if (!JS_StopChudRemote()) {
1970     JS_ReportError(cx, "Error stopping CHUD.");
1971 siliconforks 460 return JS_FALSE;
1972 siliconforks 332 }
1973    
1974     return JS_TRUE;
1975     }
1976    
1977     JS_FRIEND_API(JSBool)
1978     js_ConnectShark(JSContext *cx, JSObject *obj,
1979     uintN argc, jsval *argv, jsval *rval)
1980     {
1981     if (!JS_ConnectShark()) {
1982     JS_ReportError(cx, "Error connecting to Shark.");
1983 siliconforks 460 return JS_FALSE;
1984 siliconforks 332 }
1985    
1986     return JS_TRUE;
1987     }
1988    
1989     JS_FRIEND_API(JSBool)
1990     js_DisconnectShark(JSContext *cx, JSObject *obj,
1991     uintN argc, jsval *argv, jsval *rval)
1992     {
1993     if (!JS_DisconnectShark()) {
1994     JS_ReportError(cx, "Error disconnecting from Shark.");
1995 siliconforks 460 return JS_FALSE;
1996 siliconforks 332 }
1997    
1998     return JS_TRUE;
1999     }
2000    
2001     #endif /* MOZ_SHARK */
2002    
2003     #ifdef MOZ_CALLGRIND
2004    
2005     #include <valgrind/callgrind.h>
2006    
2007     JS_FRIEND_API(JSBool)
2008     js_StartCallgrind(JSContext *cx, JSObject *obj,
2009     uintN argc, jsval *argv, jsval *rval)
2010     {
2011 siliconforks 460 CALLGRIND_START_INSTRUMENTATION;
2012 siliconforks 332 CALLGRIND_ZERO_STATS;
2013     return JS_TRUE;
2014     }
2015    
2016     JS_FRIEND_API(JSBool)
2017     js_StopCallgrind(JSContext *cx, JSObject *obj,
2018     uintN argc, jsval *argv, jsval *rval)
2019     {
2020     CALLGRIND_STOP_INSTRUMENTATION;
2021     return JS_TRUE;
2022     }
2023    
2024     JS_FRIEND_API(JSBool)
2025     js_DumpCallgrind(JSContext *cx, JSObject *obj,
2026     uintN argc, jsval *argv, jsval *rval)
2027     {
2028     JSString *str;
2029     char *cstr;
2030    
2031     if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
2032     str = JSVAL_TO_STRING(argv[0]);
2033 siliconforks 507 cstr = js_DeflateString(cx, str->chars(), str->length());
2034 siliconforks 332 if (cstr) {
2035     CALLGRIND_DUMP_STATS_AT(cstr);
2036 siliconforks 507 cx->free(cstr);
2037 siliconforks 332 return JS_TRUE;
2038     }
2039     }
2040     CALLGRIND_DUMP_STATS;
2041    
2042     return JS_TRUE;
2043     }
2044    
2045     #endif /* MOZ_CALLGRIND */
2046    
2047     #ifdef MOZ_VTUNE
2048     #include <VTuneApi.h>
2049    
2050     static const char *vtuneErrorMessages[] = {
2051     "unknown, error #0",
2052     "invalid 'max samples' field",
2053     "invalid 'samples per buffer' field",
2054     "invalid 'sample interval' field",
2055     "invalid path",
2056     "sample file in use",
2057     "invalid 'number of events' field",
2058     "unknown, error #7",
2059     "internal error",
2060     "bad event name",
2061     "VTStopSampling called without calling VTStartSampling",
2062     "no events selected for event-based sampling",
2063     "events selected cannot be run together",
2064     "no sampling parameters",
2065     "sample database already exists",
2066     "sampling already started",
2067     "time-based sampling not supported",
2068     "invalid 'sampling parameters size' field",
2069     "invalid 'event size' field",
2070     "sampling file already bound",
2071     "invalid event path",
2072     "invalid license",
2073     "invalid 'global options' field",
2074    
2075     };
2076    
2077     JS_FRIEND_API(JSBool)
2078     js_StartVtune(JSContext *cx, JSObject *obj,
2079     uintN argc, jsval *argv, jsval *rval)
2080     {
2081 siliconforks 460 VTUNE_EVENT events[] = {
2082     { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
2083     { 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
2084 siliconforks 332 };
2085    
2086     U32 n_events = sizeof(events) / sizeof(VTUNE_EVENT);
2087     char *default_filename = "mozilla-vtune.tb5";
2088     JSString *str;
2089     U32 status;
2090    
2091 siliconforks 460 VTUNE_SAMPLING_PARAMS params =
2092 siliconforks 332 sizeof(VTUNE_SAMPLING_PARAMS),
2093     sizeof(VTUNE_EVENT),
2094     0, 0, /* Reserved fields */
2095     1, /* Initialize in "paused" state */
2096     0, /* Max samples, or 0 for "continuous" */
2097     4096, /* Samples per buffer */
2098     0.1, /* Sampling interval in ms */
2099     1, /* 1 for event-based sampling, 0 for time-based */
2100    
2101     n_events,
2102     events,
2103     default_filename,
2104     };
2105    
2106     if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
2107     str = JSVAL_TO_STRING(argv[0]);
2108 siliconforks 507 params.tb5Filename = js_DeflateString(cx, str->chars(), str->length());
2109 siliconforks 332 }
2110 siliconforks 460
2111 siliconforks 332 status = VTStartSampling(&params);
2112    
2113     if (params.tb5Filename != default_filename)
2114 siliconforks 507 cx->free(params.tb5Filename);
2115 siliconforks 460
2116     if (status != 0) {
2117 siliconforks 332 if (status == VTAPI_MULTIPLE_RUNS)
2118     VTStopSampling(0);
2119     if (status < sizeof(vtuneErrorMessages))
2120 siliconforks 460 JS_ReportError(cx, "Vtune setup error: %s",
2121 siliconforks 332 vtuneErrorMessages[status]);
2122     else
2123 siliconforks 460 JS_ReportError(cx, "Vtune setup error: %d",
2124     status);
2125 siliconforks 332 return JS_FALSE;
2126     }
2127     return JS_TRUE;
2128     }
2129    
2130     JS_FRIEND_API(JSBool)
2131     js_StopVtune(JSContext *cx, JSObject *obj,
2132     uintN argc, jsval *argv, jsval *rval)
2133     {
2134     U32 status = VTStopSampling(1);
2135     if (status) {
2136     if (status < sizeof(vtuneErrorMessages))
2137 siliconforks 460 JS_ReportError(cx, "Vtune shutdown error: %s",
2138 siliconforks 332 vtuneErrorMessages[status]);
2139     else
2140 siliconforks 460 JS_ReportError(cx, "Vtune shutdown error: %d",
2141 siliconforks 332 status);
2142     return JS_FALSE;
2143     }
2144     return JS_TRUE;
2145     }
2146    
2147     JS_FRIEND_API(JSBool)
2148     js_PauseVtune(JSContext *cx, JSObject *obj,
2149     uintN argc, jsval *argv, jsval *rval)
2150     {
2151     VTPause();
2152     return JS_TRUE;
2153     }
2154    
2155     JS_FRIEND_API(JSBool)
2156     js_ResumeVtune(JSContext *cx, JSObject *obj,
2157     uintN argc, jsval *argv, jsval *rval)
2158     {
2159     VTResume();
2160     return JS_TRUE;
2161     }
2162    
2163     #endif /* MOZ_VTUNE */
2164 siliconforks 507
2165     #ifdef MOZ_TRACEVIS
2166     /*
2167     * Ethogram - Javascript wrapper for TraceVis state
2168     *
2169     * ethology: The scientific study of animal behavior,
2170     * especially as it occurs in a natural environment.
2171     * ethogram: A pictorial catalog of the behavioral patterns of
2172     * an organism or a species.
2173     *
2174     */
2175     #if defined(XP_WIN)
2176     #include <windows.h>
2177     #else
2178     #include <sys/time.h>
2179     #endif
2180     #include "jstracer.h"
2181    
2182     #define ETHOGRAM_BUF_SIZE 65536
2183    
2184     static JSBool
2185     ethogram_construct(JSContext *cx, JSObject *obj,
2186     uintN argc, jsval *argv, jsval *rval);
2187     static void
2188     ethogram_finalize(JSContext *cx, JSObject *obj);
2189    
2190     static JSClass ethogram_class = {
2191     "Ethogram",
2192     JSCLASS_HAS_PRIVATE,
2193     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
2194     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ethogram_finalize,
2195     JSCLASS_NO_OPTIONAL_MEMBERS
2196     };
2197    
2198     struct EthogramEvent {
2199     TraceVisState s;
2200     TraceVisExitReason r;
2201     int ts;
2202     int tus;
2203     JSString *filename;
2204     int lineno;
2205     };
2206    
2207     static int
2208     compare_strings(const void *k1, const void *k2)
2209     {
2210     return strcmp((const char *) k1, (const char *) k2) == 0;
2211     }
2212    
2213     class EthogramEventBuffer {
2214     private:
2215     EthogramEvent mBuf[ETHOGRAM_BUF_SIZE];
2216     int mReadPos;
2217     int mWritePos;
2218     JSObject *mFilenames;
2219     int mStartSecond;
2220    
2221     struct EthogramScriptEntry {
2222     char *filename;
2223     JSString *jsfilename;
2224    
2225     EthogramScriptEntry *next;
2226     };
2227     EthogramScriptEntry *mScripts;
2228    
2229     public:
2230     friend JSBool
2231     ethogram_construct(JSContext *cx, JSObject *obj,
2232     uintN argc, jsval *argv, jsval *rval);
2233    
2234     inline void push(TraceVisState s, TraceVisExitReason r, char *filename, int lineno) {
2235     mBuf[mWritePos].s = s;
2236     mBuf[mWritePos].r = r;
2237     #if defined(XP_WIN)
2238     FILETIME now;
2239     GetSystemTimeAsFileTime(&now);
2240     unsigned long long raw_us = 0.1 *
2241     (((unsigned long long) now.dwHighDateTime << 32ULL) |
2242     (unsigned long long) now.dwLowDateTime);
2243     unsigned int sec = raw_us / 1000000L;
2244     unsigned int usec = raw_us % 1000000L;
2245     mBuf[mWritePos].ts = sec - mStartSecond;
2246     mBuf[mWritePos].tus = usec;
2247     #else
2248     struct timeval tv;
2249     gettimeofday(&tv, NULL);
2250     mBuf[mWritePos].ts = tv.tv_sec - mStartSecond;
2251     mBuf[mWritePos].tus = tv.tv_usec;
2252     #endif
2253    
2254     JSString *jsfilename = findScript(filename);
2255     mBuf[mWritePos].filename = jsfilename;
2256     mBuf[mWritePos].lineno = lineno;
2257    
2258     mWritePos = (mWritePos + 1) % ETHOGRAM_BUF_SIZE;
2259     if (mWritePos == mReadPos) {
2260     mReadPos = (mWritePos + 1) % ETHOGRAM_BUF_SIZE;
2261     }
2262     }
2263    
2264     inline EthogramEvent *pop() {
2265     EthogramEvent *e = &mBuf[mReadPos];
2266     mReadPos = (mReadPos + 1) % ETHOGRAM_BUF_SIZE;
2267     return e;
2268     }
2269    
2270     bool isEmpty() {
2271     return (mReadPos == mWritePos);
2272     }
2273    
2274     EthogramScriptEntry *addScript(JSContext *cx, JSObject *obj, char *filename, JSString *jsfilename) {
2275     JSHashNumber hash = JS_HashString(filename);
2276     JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename);
2277     if (*hep != NULL)
2278     return JS_FALSE;
2279    
2280     JS_HashTableRawAdd(traceVisScriptTable, hep, hash, filename, this);
2281    
2282     EthogramScriptEntry * entry = (EthogramScriptEntry *) JS_malloc(cx, sizeof(EthogramScriptEntry));
2283     if (entry == NULL)
2284     return NULL;
2285    
2286     entry->next = mScripts;
2287     mScripts = entry;
2288     entry->filename = filename;
2289     entry->jsfilename = jsfilename;
2290    
2291     return mScripts;
2292     }
2293    
2294     void removeScripts(JSContext *cx) {
2295     EthogramScriptEntry *se = mScripts;
2296     while (se != NULL) {
2297     char *filename = se->filename;
2298    
2299     JSHashNumber hash = JS_HashString(filename);
2300     JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename);
2301     JSHashEntry *he = *hep;
2302     if (he) {
2303     /* we hardly knew he */
2304     JS_HashTableRawRemove(traceVisScriptTable, hep, he);
2305     }
2306    
2307     EthogramScriptEntry *se_head = se;
2308     se = se->next;
2309     JS_free(cx, se_head);
2310     }
2311     }
2312    
2313     JSString *findScript(char *filename) {
2314     EthogramScriptEntry *se = mScripts;
2315     while (se != NULL) {
2316     if (compare_strings(se->filename, filename))
2317     return (se->jsfilename);
2318     se = se->next;
2319     }
2320     return NULL;
2321     }
2322    
2323     JSObject *filenames() {
2324     return mFilenames;
2325     }
2326    
2327     int length() {
2328     if (mWritePos < mReadPos)
2329     return (mWritePos + ETHOGRAM_BUF_SIZE) - mReadPos;
2330     else
2331     return mWritePos - mReadPos;
2332     }
2333     };
2334    
2335     static char jstv_empty[] = "<null>";
2336    
2337     inline char *
2338     jstv_Filename(JSStackFrame *fp)
2339     {
2340     while (fp && fp->script == NULL)
2341     fp = fp->down;
2342     return (fp && fp->script && fp->script->filename)
2343     ? (char *)fp->script->filename
2344     : jstv_empty;
2345     }
2346     inline uintN
2347     jstv_Lineno(JSContext *cx, JSStackFrame *fp)
2348     {
2349     while (fp && fp->regs == NULL)
2350     fp = fp->down;
2351     return (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0;
2352     }
2353    
2354     /* Collect states here and distribute to a matching buffer, if any */
2355     JS_FRIEND_API(void)
2356     js_StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r)
2357     {
2358     JSStackFrame *fp = cx->fp;
2359    
2360     char *script_file = jstv_Filename(fp);
2361     JSHashNumber hash = JS_HashString(script_file);
2362    
2363     JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, script_file);
2364     /* update event buffer, flag if overflowed */
2365     JSHashEntry *he = *hep;
2366     if (he) {
2367     EthogramEventBuffer *p;
2368     p = (EthogramEventBuffer *) he->value;
2369    
2370     p->push(s, r, script_file, jstv_Lineno(cx, fp));
2371     }
2372     }
2373    
2374     static JSBool
2375     ethogram_construct(JSContext *cx, JSObject *obj,
2376     uintN argc, jsval *argv, jsval *rval)
2377     {
2378     EthogramEventBuffer *p;
2379    
2380     p = (EthogramEventBuffer *) JS_malloc(cx, sizeof(EthogramEventBuffer));
2381    
2382     p->mReadPos = p->mWritePos = 0;
2383     p->mScripts = NULL;
2384     p->mFilenames = JS_NewArrayObject(cx, 0, NULL);
2385    
2386     #if defined(XP_WIN)
2387     FILETIME now;
2388     GetSystemTimeAsFileTime(&now);
2389     unsigned long long raw_us = 0.1 *
2390     (((unsigned long long) now.dwHighDateTime << 32ULL) |
2391     (unsigned long long) now.dwLowDateTime);
2392     unsigned int s = raw_us / 1000000L;
2393     p->mStartSecond = s;
2394     #else
2395     struct timeval tv;
2396     gettimeofday(&tv, NULL);
2397     p->mStartSecond = tv.tv_sec;
2398     #endif
2399     jsval filenames = OBJECT_TO_JSVAL(p->filenames());
2400     if (!JS_DefineProperty(cx, obj, "filenames", filenames,
2401     NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT))
2402     return JS_FALSE;
2403    
2404     if (!JS_IsConstructing(cx)) {
2405     obj = JS_NewObject(cx, &ethogram_class, NULL, NULL);
2406     if (!obj)
2407     return JS_FALSE;
2408     *rval = OBJECT_TO_JSVAL(obj);
2409     }
2410     JS_SetPrivate(cx, obj, p);
2411     return JS_TRUE;
2412     }
2413    
2414     static void
2415     ethogram_finalize(JSContext *cx, JSObject *obj)
2416     {
2417     EthogramEventBuffer *p;
2418     p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, &ethogram_class, NULL);
2419     if (!p)
2420     return;
2421    
2422     p->removeScripts(cx);
2423    
2424     JS_free(cx, p);
2425     }
2426    
2427     static JSBool
2428     ethogram_addScript(JSContext *cx, JSObject *obj,
2429     uintN argc, jsval *argv, jsval *rval)
2430     {
2431     JSString *str;
2432     char *filename = NULL;
2433     if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
2434     str = JSVAL_TO_STRING(argv[0]);
2435     filename = js_DeflateString(cx,
2436     str->chars(),
2437     str->length());
2438     }
2439    
2440     /* silently ignore no args */
2441     if (!filename)
2442     return JS_TRUE;
2443    
2444     EthogramEventBuffer *p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, &ethogram_class, argv);
2445    
2446     p->addScript(cx, obj, filename, str);
2447     JS_CallFunctionName(cx, p->filenames(), "push", 1, argv, rval);
2448     return JS_TRUE;
2449     }
2450    
2451     static JSBool
2452     ethogram_getAllEvents(JSContext *cx, JSObject *obj,
2453     uintN argc, jsval *argv, jsval *rval)
2454     {
2455     EthogramEventBuffer *p;
2456    
2457     p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, &ethogram_class, argv);
2458     if (!p)
2459     return JS_FALSE;
2460    
2461     if (p->isEmpty()) {
2462     *rval = JSVAL_NULL;
2463     return JS_TRUE;
2464     }
2465    
2466     JSObject *rarray = JS_NewArrayObject(cx, 0, NULL);
2467     if (rarray == NULL) {
2468     *rval = JSVAL_NULL;
2469     return JS_TRUE;
2470     }
2471    
2472     *rval = OBJECT_TO_JSVAL(rarray);
2473    
2474     for (int i = 0; !p->isEmpty(); i++) {
2475    
2476     JSObject *x = JS_NewObject(cx, NULL, NULL, NULL);
2477     if (x == NULL)
2478     return JS_FALSE;
2479    
2480     EthogramEvent *e = p->pop();
2481    
2482     jsval state = INT_TO_JSVAL(e->s);
2483     jsval reason = INT_TO_JSVAL(e->r);
2484     jsval ts = INT_TO_JSVAL(e->ts);
2485     jsval tus = INT_TO_JSVAL(e->tus);
2486    
2487     jsval filename = STRING_TO_JSVAL(e->filename);
2488     jsval lineno = INT_TO_JSVAL(e->lineno);
2489    
2490     if (!JS_SetProperty(cx, x, "state", &state))
2491     return JS_FALSE;
2492     if (!JS_SetProperty(cx, x, "reason", &reason))
2493     return JS_FALSE;
2494     if (!JS_SetProperty(cx, x, "ts", &ts))
2495     return JS_FALSE;
2496     if (!JS_SetProperty(cx, x, "tus", &tus))
2497     return JS_FALSE;
2498    
2499     if (!JS_SetProperty(cx, x, "filename", &filename))
2500     return JS_FALSE;
2501     if (!JS_SetProperty(cx, x, "lineno", &lineno))
2502     return JS_FALSE;
2503    
2504     jsval element = OBJECT_TO_JSVAL(x);
2505     JS_SetElement(cx, rarray, i, &element);
2506     }
2507    
2508     return JS_TRUE;
2509     }
2510    
2511     static JSBool
2512     ethogram_getNextEvent(JSContext *cx, JSObject *obj,
2513     uintN argc, jsval *argv, jsval *rval)
2514     {
2515     EthogramEventBuffer *p;
2516    
2517     p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, &ethogram_class, argv);
2518     if (!p)
2519     return JS_FALSE;
2520    
2521     JSObject *x = JS_NewObject(cx, NULL, NULL, NULL);
2522     if (x == NULL)
2523     return JS_FALSE;
2524    
2525     if (p->isEmpty()) {
2526     *rval = JSVAL_NULL;
2527     return JS_TRUE;
2528     }
2529    
2530     EthogramEvent *e = p->pop();
2531     jsval state = INT_TO_JSVAL(e->s);
2532     jsval reason = INT_TO_JSVAL(e->r);
2533     jsval ts = INT_TO_JSVAL(e->ts);
2534     jsval tus = INT_TO_JSVAL(e->tus);
2535    
2536     jsval filename = STRING_TO_JSVAL(e->filename);
2537     jsval lineno = INT_TO_JSVAL(e->lineno);
2538    
2539     if (!JS_SetProperty(cx, x, "state", &state))
2540     return JS_FALSE;
2541     if (!JS_SetProperty(cx, x, "reason", &reason))
2542     return JS_FALSE;
2543     if (!JS_SetProperty(cx, x, "ts", &ts))
2544     return JS_FALSE;
2545     if (!JS_SetProperty(cx, x, "tus"