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

Annotation of /trunk/js/jsscript.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 460 - (hide annotations)
Sat Sep 26 23:15:22 2009 UTC (12 years, 9 months ago) by siliconforks
File size: 58412 byte(s)
Upgrade to SpiderMonkey from Firefox 3.5.3.

1 siliconforks 332 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2     * vim: set ts=8 sw=4 et tw=78:
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 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 script operations.
43     */
44     #include "jsstddef.h"
45     #include <string.h>
46     #include "jstypes.h"
47     #include "jsutil.h" /* Added by JSIFY */
48     #include "jsprf.h"
49     #include "jsapi.h"
50     #include "jsatom.h"
51     #include "jscntxt.h"
52     #include "jsversion.h"
53     #include "jsdbgapi.h"
54     #include "jsemit.h"
55     #include "jsfun.h"
56     #include "jsinterp.h"
57     #include "jslock.h"
58     #include "jsnum.h"
59     #include "jsopcode.h"
60     #include "jsparse.h"
61     #include "jsscope.h"
62     #include "jsscript.h"
63 siliconforks 460 #include "jstracer.h"
64 siliconforks 332 #if JS_HAS_XDR
65     #include "jsxdrapi.h"
66     #endif
67    
68     #if JS_HAS_SCRIPT_OBJECT
69    
70     static const char js_script_exec_str[] = "Script.prototype.exec";
71     static const char js_script_compile_str[] = "Script.prototype.compile";
72    
73     /*
74     * This routine requires that obj has been locked previously.
75     */
76     static jsint
77     GetScriptExecDepth(JSContext *cx, JSObject *obj)
78     {
79     jsval v;
80    
81     JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj));
82     v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_START(&js_ScriptClass));
83     return JSVAL_TO_INT(v);
84     }
85    
86     static void
87     AdjustScriptExecDepth(JSContext *cx, JSObject *obj, jsint delta)
88     {
89     jsint execDepth;
90    
91     JS_LOCK_OBJ(cx, obj);
92     execDepth = GetScriptExecDepth(cx, obj);
93     LOCKED_OBJ_SET_SLOT(obj, JSSLOT_START(&js_ScriptClass),
94     INT_TO_JSVAL(execDepth + delta));
95     JS_UNLOCK_OBJ(cx, obj);
96     }
97    
98     #if JS_HAS_TOSOURCE
99     static JSBool
100     script_toSource(JSContext *cx, uintN argc, jsval *vp)
101     {
102     JSObject *obj;
103     uint32 indent;
104     JSScript *script;
105     size_t i, j, k, n;
106     char buf[16];
107     jschar *s, *t;
108     JSString *str;
109    
110     obj = JS_THIS_OBJECT(cx, vp);
111     if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
112     return JS_FALSE;
113    
114     indent = 0;
115     if (argc != 0) {
116     indent = js_ValueToECMAUint32(cx, &vp[2]);
117     if (JSVAL_IS_NULL(vp[2]))
118     return JS_FALSE;
119     }
120    
121     script = (JSScript *) JS_GetPrivate(cx, obj);
122    
123     /* Let n count the source string length, j the "front porch" length. */
124     j = JS_snprintf(buf, sizeof buf, "(new %s(", js_ScriptClass.name);
125     n = j + 2;
126     if (!script) {
127     /* Let k count the constructor argument string length. */
128     k = 0;
129     s = NULL; /* quell GCC overwarning */
130     } else {
131     str = JS_DecompileScript(cx, script, "Script.prototype.toSource",
132     (uintN)indent);
133     if (!str)
134     return JS_FALSE;
135     str = js_QuoteString(cx, str, '\'');
136     if (!str)
137     return JS_FALSE;
138     JSSTRING_CHARS_AND_LENGTH(str, s, k);
139     n += k;
140     }
141    
142     /* Allocate the source string and copy into it. */
143     t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
144     if (!t)
145     return JS_FALSE;
146     for (i = 0; i < j; i++)
147     t[i] = buf[i];
148     for (j = 0; j < k; i++, j++)
149     t[i] = s[j];
150     t[i++] = ')';
151     t[i++] = ')';
152     t[i] = 0;
153    
154     /* Create and return a JS string for t. */
155     str = JS_NewUCString(cx, t, n);
156     if (!str) {
157     JS_free(cx, t);
158     return JS_FALSE;
159     }
160     *vp = STRING_TO_JSVAL(str);
161     return JS_TRUE;
162     }
163     #endif /* JS_HAS_TOSOURCE */
164    
165     static JSBool
166     script_toString(JSContext *cx, uintN argc, jsval *vp)
167     {
168     uint32 indent;
169     JSObject *obj;
170     JSScript *script;
171     JSString *str;
172    
173     indent = 0;
174     if (argc != 0) {
175     indent = js_ValueToECMAUint32(cx, &vp[2]);
176     if (JSVAL_IS_NULL(vp[2]))
177     return JS_FALSE;
178     }
179    
180     obj = JS_THIS_OBJECT(cx, vp);
181     if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
182     return JS_FALSE;
183     script = (JSScript *) JS_GetPrivate(cx, obj);
184     if (!script) {
185     *vp = STRING_TO_JSVAL(cx->runtime->emptyString);
186     return JS_TRUE;
187     }
188    
189     str = JS_DecompileScript(cx, script, "Script.prototype.toString",
190     (uintN)indent);
191     if (!str)
192     return JS_FALSE;
193     *vp = STRING_TO_JSVAL(str);
194     return JS_TRUE;
195     }
196    
197     static JSBool
198     script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
199     jsval *rval)
200     {
201     JSString *str;
202     JSObject *scopeobj;
203     jsval v;
204     JSScript *script, *oldscript;
205     JSStackFrame *caller;
206     const char *file;
207     uintN line;
208     JSPrincipals *principals;
209     uint32 tcflags;
210     jsint execDepth;
211    
212     /* Make sure obj is a Script object. */
213     if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
214     return JS_FALSE;
215    
216     /* If no args, leave private undefined and return early. */
217     if (argc == 0)
218     goto out;
219    
220     /* Otherwise, the first arg is the script source to compile. */
221     str = js_ValueToString(cx, argv[0]);
222     if (!str)
223     return JS_FALSE;
224     argv[0] = STRING_TO_JSVAL(str);
225    
226     scopeobj = NULL;
227     if (argc >= 2) {
228     if (!js_ValueToObject(cx, argv[1], &scopeobj))
229     return JS_FALSE;
230     argv[1] = OBJECT_TO_JSVAL(scopeobj);
231     }
232    
233     /* Compile using the caller's scope chain, which js_Invoke passes to fp. */
234 siliconforks 460 caller = js_GetScriptedCaller(cx, NULL);
235 siliconforks 332 JS_ASSERT(!caller || cx->fp->scopeChain == caller->scopeChain);
236    
237     if (caller) {
238     if (!scopeobj) {
239     scopeobj = js_GetScopeChain(cx, caller);
240     if (!scopeobj)
241     return JS_FALSE;
242     }
243    
244     principals = JS_EvalFramePrincipals(cx, cx->fp, caller);
245     file = js_ComputeFilename(cx, caller, principals, &line);
246     } else {
247     file = NULL;
248     line = 0;
249     principals = NULL;
250     }
251    
252     /* Ensure we compile this script with the right (inner) principals. */
253     scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_compile_str);
254     if (!scopeobj)
255     return JS_FALSE;
256    
257     /*
258     * Compile the new script using the caller's scope chain, a la eval().
259     * Unlike jsobj.c:obj_eval, however, we do not pass TCF_COMPILE_N_GO in
260     * tcflags and use NULL for the callerFrame argument, because compilation
261     * is here separated from execution, and the run-time scope chain may not
262     * match the compile-time. TCF_COMPILE_N_GO is tested in jsemit.c and
263     * jsparse.c to optimize based on identity of run- and compile-time scope.
264     */
265     tcflags = 0;
266 siliconforks 460 script = JSCompiler::compileScript(cx, scopeobj, NULL, principals, tcflags,
267     JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
268     NULL, file, line);
269 siliconforks 332 if (!script)
270     return JS_FALSE;
271    
272     JS_LOCK_OBJ(cx, obj);
273     execDepth = GetScriptExecDepth(cx, obj);
274    
275     /*
276     * execDepth must be 0 to allow compilation here, otherwise the JSScript
277     * struct can be released while running.
278     */
279     if (execDepth > 0) {
280     JS_UNLOCK_OBJ(cx, obj);
281     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
282     JSMSG_COMPILE_EXECED_SCRIPT);
283     return JS_FALSE;
284     }
285    
286     /* Swap script for obj's old script, if any. */
287     v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
288     oldscript = (JSScript*) (!JSVAL_IS_VOID(v) ? JSVAL_TO_PRIVATE(v) : NULL);
289     LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script));
290     JS_UNLOCK_OBJ(cx, obj);
291    
292     if (oldscript)
293     js_DestroyScript(cx, oldscript);
294    
295     script->u.object = obj;
296     js_CallNewScriptHook(cx, script, NULL);
297    
298     out:
299     /* Return the object. */
300     *rval = OBJECT_TO_JSVAL(obj);
301     return JS_TRUE;
302     }
303    
304     static JSBool
305     script_compile(JSContext *cx, uintN argc, jsval *vp)
306     {
307     return script_compile_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp);
308     }
309    
310     static JSBool
311     script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
312     jsval *rval)
313     {
314 siliconforks 460 JSObject *scopeobj;
315     JSStackFrame *caller;
316 siliconforks 332 JSPrincipals *principals;
317     JSScript *script;
318     JSBool ok;
319    
320     if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
321     return JS_FALSE;
322    
323     scopeobj = NULL;
324     if (argc != 0) {
325     if (!js_ValueToObject(cx, argv[0], &scopeobj))
326     return JS_FALSE;
327     argv[0] = OBJECT_TO_JSVAL(scopeobj);
328     }
329    
330     /*
331     * Emulate eval() by using caller's this, var object, sharp array, etc.,
332     * all propagated by js_Execute via a non-null fourth (down) argument to
333     * js_Execute. If there is no scripted caller, js_Execute uses its second
334     * (chain) argument to set the exec frame's varobj, thisp, and scopeChain.
335     *
336     * Unlike eval, which the compiler detects, Script.prototype.exec may be
337     * called from a lightweight function, or even from native code (in which
338     * case fp->varobj and fp->scopeChain are null). If exec is called from
339     * a lightweight function, we will need to get a Call object representing
340     * its frame, to act as the var object and scope chain head.
341     */
342 siliconforks 460 caller = js_GetScriptedCaller(cx, NULL);
343 siliconforks 332 if (caller && !caller->varobj) {
344     /* Called from a lightweight function. */
345     JS_ASSERT(caller->fun && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags));
346    
347 siliconforks 460 /* Scope chain links from Call object to caller's scope chain. */
348     if (!js_GetCallObject(cx, caller))
349 siliconforks 332 return JS_FALSE;
350     }
351    
352     if (!scopeobj) {
353     /* No scope object passed in: try to use the caller's scope chain. */
354     if (caller) {
355     /*
356     * Load caller->scopeChain after the conditional js_GetCallObject
357     * call above, which resets scopeChain as well as varobj.
358     */
359     scopeobj = js_GetScopeChain(cx, caller);
360     if (!scopeobj)
361     return JS_FALSE;
362     } else {
363     /*
364     * Called from native code, so we don't know what scope object to
365 siliconforks 460 * use. We could use the caller's scope chain (see above), but Script.prototype.exec
366 siliconforks 332 * might be a shared/sealed "superglobal" method. A more general
367     * approach would use cx->globalObject, which will be the same as
368     * exec.__parent__ in the non-superglobal case. In the superglobal
369     * case it's the right object: the global, not the superglobal.
370     */
371     scopeobj = cx->globalObject;
372     }
373     }
374    
375     scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_exec_str);
376     if (!scopeobj)
377     return JS_FALSE;
378    
379     /* Keep track of nesting depth for the script. */
380     AdjustScriptExecDepth(cx, obj, 1);
381    
382     /* Must get to out label after this */
383     script = (JSScript *) JS_GetPrivate(cx, obj);
384     if (!script) {
385     ok = JS_FALSE;
386     goto out;
387     }
388    
389     /* Belt-and-braces: check that this script object has access to scopeobj. */
390     principals = script->principals;
391     ok = js_CheckPrincipalsAccess(cx, scopeobj, principals,
392     CLASS_ATOM(cx, Script));
393     if (!ok)
394     goto out;
395    
396     ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
397    
398     out:
399     AdjustScriptExecDepth(cx, obj, -1);
400     return ok;
401     }
402    
403     static JSBool
404     script_exec(JSContext *cx, uintN argc, jsval *vp)
405     {
406     return script_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp);
407     }
408    
409     #endif /* JS_HAS_SCRIPT_OBJECT */
410    
411     #if JS_HAS_XDR
412    
413     JSBool
414     js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
415     {
416     JSContext *cx;
417     JSScript *script, *oldscript;
418     JSBool ok;
419     jsbytecode *code;
420     uint32 length, lineno, nslots, magic;
421     uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, i;
422     uint32 prologLength, version;
423     JSTempValueRooter tvr;
424     JSPrincipals *principals;
425     uint32 encodeable;
426     JSBool filenameWasSaved;
427     jssrcnote *notes, *sn;
428     JSSecurityCallbacks *callbacks;
429    
430     cx = xdr->cx;
431     script = *scriptp;
432     nsrcnotes = ntrynotes = natoms = nobjects = nupvars = nregexps = 0;
433     filenameWasSaved = JS_FALSE;
434     notes = NULL;
435    
436     if (xdr->mode == JSXDR_ENCODE)
437     magic = JSXDR_MAGIC_SCRIPT_CURRENT;
438     if (!JS_XDRUint32(xdr, &magic))
439     return JS_FALSE;
440     if (magic != JSXDR_MAGIC_SCRIPT_CURRENT) {
441     /* We do not provide binary compatibility with older scripts. */
442     if (!hasMagic) {
443     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
444     JSMSG_BAD_SCRIPT_MAGIC);
445     return JS_FALSE;
446     }
447     *hasMagic = JS_FALSE;
448     return JS_TRUE;
449     }
450     if (hasMagic)
451     *hasMagic = JS_TRUE;
452    
453     if (xdr->mode == JSXDR_ENCODE) {
454     length = script->length;
455     prologLength = PTRDIFF(script->main, script->code, jsbytecode);
456     JS_ASSERT((int16)script->version != JSVERSION_UNKNOWN);
457     version = (uint32)script->version | (script->nfixed << 16);
458     lineno = (uint32)script->lineno;
459     nslots = (uint32)script->nslots;
460 siliconforks 460 nslots = (uint32)((script->staticLevel << 16) | script->nslots);
461 siliconforks 332 natoms = (uint32)script->atomMap.length;
462    
463     /* Count the srcnotes, keeping notes pointing at the first one. */
464     notes = SCRIPT_NOTES(script);
465     for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
466     continue;
467     nsrcnotes = PTRDIFF(sn, notes, jssrcnote);
468     nsrcnotes++; /* room for the terminator */
469    
470     if (script->objectsOffset != 0)
471     nobjects = JS_SCRIPT_OBJECTS(script)->length;
472     if (script->upvarsOffset != 0)
473     nupvars = JS_SCRIPT_UPVARS(script)->length;
474     if (script->regexpsOffset != 0)
475     nregexps = JS_SCRIPT_REGEXPS(script)->length;
476     if (script->trynotesOffset != 0)
477     ntrynotes = JS_SCRIPT_TRYNOTES(script)->length;
478     }
479    
480     if (!JS_XDRUint32(xdr, &length))
481     return JS_FALSE;
482     if (!JS_XDRUint32(xdr, &prologLength))
483     return JS_FALSE;
484     if (!JS_XDRUint32(xdr, &version))
485     return JS_FALSE;
486    
487     /*
488     * To fuse allocations, we need srcnote, atom, objects, upvar, regexp,
489     * and trynote counts early.
490     */
491     if (!JS_XDRUint32(xdr, &natoms))
492     return JS_FALSE;
493     if (!JS_XDRUint32(xdr, &nsrcnotes))
494     return JS_FALSE;
495     if (!JS_XDRUint32(xdr, &ntrynotes))
496     return JS_FALSE;
497     if (!JS_XDRUint32(xdr, &nobjects))
498     return JS_FALSE;
499     if (!JS_XDRUint32(xdr, &nupvars))
500     return JS_FALSE;
501     if (!JS_XDRUint32(xdr, &nregexps))
502     return JS_FALSE;
503    
504     if (xdr->mode == JSXDR_DECODE) {
505     script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars,
506     nregexps, ntrynotes);
507     if (!script)
508     return JS_FALSE;
509    
510     script->main += prologLength;
511 siliconforks 460 script->version = JSVersion(version & 0xffff);
512     script->nfixed = uint16(version >> 16);
513 siliconforks 332
514     /* If we know nsrcnotes, we allocated space for notes in script. */
515     notes = SCRIPT_NOTES(script);
516     *scriptp = script;
517     JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr);
518     }
519    
520     /*
521     * Control hereafter must goto error on failure, in order for the
522     * DECODE case to destroy script.
523     */
524     oldscript = xdr->script;
525     code = script->code;
526     if (xdr->mode == JSXDR_ENCODE) {
527     code = js_UntrapScriptCode(cx, script);
528     if (!code)
529     goto error;
530     }
531    
532     xdr->script = script;
533     ok = JS_XDRBytes(xdr, (char *) code, length * sizeof(jsbytecode));
534    
535     if (code != script->code)
536     JS_free(cx, code);
537    
538     if (!ok)
539     goto error;
540    
541     if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) ||
542     !JS_XDRCStringOrNull(xdr, (char **)&script->filename) ||
543     !JS_XDRUint32(xdr, &lineno) ||
544     !JS_XDRUint32(xdr, &nslots)) {
545     goto error;
546     }
547    
548     callbacks = JS_GetSecurityCallbacks(cx);
549     if (xdr->mode == JSXDR_ENCODE) {
550     principals = script->principals;
551     encodeable = callbacks && callbacks->principalsTranscoder;
552     if (!JS_XDRUint32(xdr, &encodeable))
553     goto error;
554     if (encodeable &&
555     !callbacks->principalsTranscoder(xdr, &principals)) {
556     goto error;
557     }
558     } else {
559     if (!JS_XDRUint32(xdr, &encodeable))
560     goto error;
561     if (encodeable) {
562     if (!(callbacks && callbacks->principalsTranscoder)) {
563     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
564     JSMSG_CANT_DECODE_PRINCIPALS);
565     goto error;
566     }
567     if (!callbacks->principalsTranscoder(xdr, &principals))
568     goto error;
569     script->principals = principals;
570     }
571     }
572    
573     if (xdr->mode == JSXDR_DECODE) {
574     const char *filename = script->filename;
575     if (filename) {
576     filename = js_SaveScriptFilename(cx, filename);
577     if (!filename)
578     goto error;
579     JS_free(cx, (void *) script->filename);
580     script->filename = filename;
581     filenameWasSaved = JS_TRUE;
582     }
583     script->lineno = (uintN)lineno;
584     script->nslots = (uint16)nslots;
585 siliconforks 460 script->staticLevel = (uint16)(nslots >> 16);
586 siliconforks 332 }
587    
588     for (i = 0; i != natoms; ++i) {
589     if (!js_XDRAtom(xdr, &script->atomMap.vector[i]))
590     goto error;
591     }
592    
593     /*
594     * Here looping from 0-to-length to xdr objects is essential. It ensures
595     * that block objects from the script->objects array will be written and
596 siliconforks 460 * restored in the outer-to-inner order. js_XDRBlockObject relies on this
597     * to restore the parent chain.
598 siliconforks 332 */
599     for (i = 0; i != nobjects; ++i) {
600 siliconforks 460 JSObject **objp = &JS_SCRIPT_OBJECTS(script)->vector[i];
601     uint32 isBlock;
602     if (xdr->mode == JSXDR_ENCODE) {
603     JSClass *clasp = STOBJ_GET_CLASS(*objp);
604     JS_ASSERT(clasp == &js_FunctionClass ||
605     clasp == &js_BlockClass);
606     isBlock = (clasp == &js_BlockClass) ? 1 : 0;
607     }
608     if (!JS_XDRUint32(xdr, &isBlock))
609 siliconforks 332 goto error;
610 siliconforks 460 if (isBlock == 0) {
611     if (!js_XDRFunctionObject(xdr, objp))
612     goto error;
613     } else {
614     JS_ASSERT(isBlock == 1);
615     if (!js_XDRBlockObject(xdr, objp))
616     goto error;
617     }
618 siliconforks 332 }
619     for (i = 0; i != nupvars; ++i) {
620     if (!JS_XDRUint32(xdr, &JS_SCRIPT_UPVARS(script)->vector[i]))
621     goto error;
622     }
623     for (i = 0; i != nregexps; ++i) {
624 siliconforks 460 if (!js_XDRRegExpObject(xdr, &JS_SCRIPT_REGEXPS(script)->vector[i]))
625 siliconforks 332 goto error;
626     }
627    
628     if (ntrynotes != 0) {
629     /*
630     * We combine tn->kind and tn->stackDepth when serializing as XDR is not
631     * efficient when serializing small integer types.
632     */
633     JSTryNote *tn, *tnfirst;
634     uint32 kindAndDepth;
635     JS_STATIC_ASSERT(sizeof(tn->kind) == sizeof(uint8));
636     JS_STATIC_ASSERT(sizeof(tn->stackDepth) == sizeof(uint16));
637    
638     tnfirst = JS_SCRIPT_TRYNOTES(script)->vector;
639     JS_ASSERT(JS_SCRIPT_TRYNOTES(script)->length == ntrynotes);
640     tn = tnfirst + ntrynotes;
641     do {
642     --tn;
643     if (xdr->mode == JSXDR_ENCODE) {
644     kindAndDepth = ((uint32)tn->kind << 16)
645     | (uint32)tn->stackDepth;
646     }
647     if (!JS_XDRUint32(xdr, &kindAndDepth) ||
648     !JS_XDRUint32(xdr, &tn->start) ||
649     !JS_XDRUint32(xdr, &tn->length)) {
650     goto error;
651     }
652     if (xdr->mode == JSXDR_DECODE) {
653     tn->kind = (uint8)(kindAndDepth >> 16);
654     tn->stackDepth = (uint16)kindAndDepth;
655     }
656     } while (tn != tnfirst);
657     }
658    
659     xdr->script = oldscript;
660     if (xdr->mode == JSXDR_DECODE)
661     JS_POP_TEMP_ROOT(cx, &tvr);
662     return JS_TRUE;
663    
664     error:
665     if (xdr->mode == JSXDR_DECODE) {
666     JS_POP_TEMP_ROOT(cx, &tvr);
667     if (script->filename && !filenameWasSaved) {
668     JS_free(cx, (void *) script->filename);
669     script->filename = NULL;
670     }
671     js_DestroyScript(cx, script);
672     *scriptp = NULL;
673     }
674     xdr->script = oldscript;
675     return JS_FALSE;
676     }
677    
678     #if JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW
679     /*
680     * These cannot be exposed to web content, and chrome does not need them, so
681     * we take them out of the Mozilla client altogether. Fortunately, there is
682     * no way to serialize a native function (see fun_xdrObject in jsfun.c).
683     */
684    
685     static JSBool
686     script_freeze(JSContext *cx, uintN argc, jsval *vp)
687     {
688     JSObject *obj;
689     JSXDRState *xdr;
690     JSScript *script;
691     JSBool ok, hasMagic;
692     uint32 len;
693     void *buf;
694     JSString *str;
695    
696     obj = JS_THIS_OBJECT(cx, vp);
697     if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
698     return JS_FALSE;
699     script = (JSScript *) JS_GetPrivate(cx, obj);
700     if (!script)
701     return JS_TRUE;
702    
703     /* create new XDR */
704     xdr = JS_XDRNewMem(cx, JSXDR_ENCODE);
705     if (!xdr)
706     return JS_FALSE;
707    
708     /* write */
709     ok = js_XDRScript(xdr, &script, &hasMagic);
710     if (!ok)
711     goto out;
712     if (!hasMagic) {
713     *vp = JSVAL_VOID;
714     goto out;
715     }
716    
717     buf = JS_XDRMemGetData(xdr, &len);
718     if (!buf) {
719     ok = JS_FALSE;
720     goto out;
721     }
722    
723     JS_ASSERT((jsword)buf % sizeof(jschar) == 0);
724     len /= sizeof(jschar);
725     #if IS_BIG_ENDIAN
726     {
727     jschar *chars;
728     uint32 i;
729    
730     /* Swap bytes in Unichars to keep frozen strings machine-independent. */
731     chars = (jschar *)buf;
732     for (i = 0; i < len; i++)
733     chars[i] = JSXDR_SWAB16(chars[i]);
734     }
735     #endif
736     str = JS_NewUCStringCopyN(cx, (jschar *)buf, len);
737     if (!str) {
738     ok = JS_FALSE;
739     goto out;
740     }
741    
742     *vp = STRING_TO_JSVAL(str);
743    
744     out:
745     JS_XDRDestroy(xdr);
746     return ok;
747     }
748    
749     static JSBool
750     script_thaw(JSContext *cx, uintN argc, jsval *vp)
751     {
752     JSObject *obj;
753     JSXDRState *xdr;
754     JSString *str;
755     void *buf;
756     uint32 len;
757     jsval v;
758     JSScript *script, *oldscript;
759     JSBool ok, hasMagic;
760     jsint execDepth;
761    
762     obj = JS_THIS_OBJECT(cx, vp);
763     if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
764     return JS_FALSE;
765    
766     if (argc == 0)
767     return JS_TRUE;
768     str = js_ValueToString(cx, vp[2]);
769     if (!str)
770     return JS_FALSE;
771     vp[2] = STRING_TO_JSVAL(str);
772    
773     /* create new XDR */
774     xdr = JS_XDRNewMem(cx, JSXDR_DECODE);
775     if (!xdr)
776     return JS_FALSE;
777    
778     JSSTRING_CHARS_AND_LENGTH(str, buf, len);
779     #if IS_BIG_ENDIAN
780     {
781     jschar *from, *to;
782     uint32 i;
783    
784     /* Swap bytes in Unichars to keep frozen strings machine-independent. */
785     from = (jschar *)buf;
786     to = (jschar *) JS_malloc(cx, len * sizeof(jschar));
787     if (!to) {
788     JS_XDRDestroy(xdr);
789     return JS_FALSE;
790     }
791     for (i = 0; i < len; i++)
792     to[i] = JSXDR_SWAB16(from[i]);
793     buf = (char *)to;
794     }
795     #endif
796     len *= sizeof(jschar);
797     JS_XDRMemSetData(xdr, buf, len);
798    
799     /* XXXbe should magic mismatch be error, or false return value? */
800     ok = js_XDRScript(xdr, &script, &hasMagic);
801     if (!ok)
802     goto out;
803     if (!hasMagic) {
804     *vp = JSVAL_FALSE;
805     goto out;
806     }
807    
808     JS_LOCK_OBJ(cx, obj);
809     execDepth = GetScriptExecDepth(cx, obj);
810    
811     /*
812     * execDepth must be 0 to allow compilation here, otherwise the JSScript
813     * struct can be released while running.
814     */
815     if (execDepth > 0) {
816     JS_UNLOCK_OBJ(cx, obj);
817     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
818     JSMSG_COMPILE_EXECED_SCRIPT);
819     goto out;
820     }
821    
822     /* Swap script for obj's old script, if any. */
823     v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
824     oldscript = !JSVAL_IS_VOID(v) ? JSVAL_TO_PRIVATE(v) : NULL;
825     LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script));
826     JS_UNLOCK_OBJ(cx, obj);
827    
828     if (oldscript)
829     js_DestroyScript(cx, oldscript);
830    
831     script->u.object = obj;
832     js_CallNewScriptHook(cx, script, NULL);
833    
834     out:
835     /*
836     * We reset the buffer to be NULL so that it doesn't free the chars
837     * memory owned by str (vp[2]).
838     */
839     JS_XDRMemSetData(xdr, NULL, 0);
840     JS_XDRDestroy(xdr);
841     #if IS_BIG_ENDIAN
842     JS_free(cx, buf);
843     #endif
844     *vp = JSVAL_TRUE;
845     return ok;
846     }
847    
848     static const char js_thaw_str[] = "thaw";
849    
850     #endif /* JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW */
851     #endif /* JS_HAS_XDR */
852    
853     #if JS_HAS_SCRIPT_OBJECT
854    
855     static JSFunctionSpec script_methods[] = {
856     #if JS_HAS_TOSOURCE
857     JS_FN(js_toSource_str, script_toSource, 0,0),
858     #endif
859     JS_FN(js_toString_str, script_toString, 0,0),
860     JS_FN("compile", script_compile, 2,0),
861     JS_FN("exec", script_exec, 1,0),
862     #if JS_HAS_XDR_FREEZE_THAW
863     JS_FN("freeze", script_freeze, 0,0),
864     JS_FN(js_thaw_str, script_thaw, 1,0),
865     #endif /* JS_HAS_XDR_FREEZE_THAW */
866     JS_FS_END
867     };
868    
869     #endif /* JS_HAS_SCRIPT_OBJECT */
870    
871     static void
872     script_finalize(JSContext *cx, JSObject *obj)
873     {
874     JSScript *script;
875    
876     script = (JSScript *) JS_GetPrivate(cx, obj);
877     if (script)
878     js_DestroyScript(cx, script);
879     }
880    
881     static JSBool
882     script_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
883     {
884     #if JS_HAS_SCRIPT_OBJECT
885     return script_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval);
886     #else
887     return JS_FALSE;
888     #endif
889     }
890    
891     static void
892     script_trace(JSTracer *trc, JSObject *obj)
893     {
894     JSScript *script;
895    
896     script = (JSScript *) JS_GetPrivate(trc->context, obj);
897     if (script)
898     js_TraceScript(trc, script);
899     }
900    
901     #if !JS_HAS_SCRIPT_OBJECT
902     #define JSProto_Script JSProto_Object
903     #endif
904    
905     JS_FRIEND_DATA(JSClass) js_ScriptClass = {
906     js_Script_str,
907     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
908     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Script),
909     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
910     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, script_finalize,
911     NULL, NULL, script_call, NULL,/*XXXbe xdr*/
912     NULL, NULL, JS_CLASS_TRACE(script_trace), NULL
913     };
914    
915     #if JS_HAS_SCRIPT_OBJECT
916    
917     static JSBool
918     Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
919     {
920     /* If not constructing, replace obj with a new Script object. */
921 siliconforks 460 if (!JS_IsConstructing(cx)) {
922 siliconforks 332 obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
923     if (!obj)
924     return JS_FALSE;
925    
926     /*
927     * script_compile_sub does not use rval to root its temporaries so we
928     * can use it to root obj.
929     */
930     *rval = OBJECT_TO_JSVAL(obj);
931     }
932    
933     if (!JS_SetReservedSlot(cx, obj, 0, INT_TO_JSVAL(0)))
934     return JS_FALSE;
935    
936     return script_compile_sub(cx, obj, argc, argv, rval);
937     }
938    
939     #if JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW
940    
941     static JSBool
942     script_static_thaw(JSContext *cx, uintN argc, jsval *vp)
943     {
944     JSObject *obj;
945    
946     obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
947     if (!obj)
948     return JS_FALSE;
949     vp[1] = OBJECT_TO_JSVAL(obj);
950     if (!script_thaw(cx, argc, vp))
951     return JS_FALSE;
952     *vp = OBJECT_TO_JSVAL(obj);
953     return JS_TRUE;
954     }
955    
956     static JSFunctionSpec script_static_methods[] = {
957     JS_FN(js_thaw_str, script_static_thaw, 1,0),
958     JS_FS_END
959     };
960    
961     #else /* !JS_HAS_SCRIPT_OBJECT || !JS_HAS_XDR_FREEZE_THAW */
962    
963     #define script_static_methods NULL
964    
965     #endif /* !JS_HAS_SCRIPT_OBJECT || !JS_HAS_XDR_FREEZE_THAW */
966    
967     JSObject *
968     js_InitScriptClass(JSContext *cx, JSObject *obj)
969     {
970     return JS_InitClass(cx, obj, NULL, &js_ScriptClass, Script, 1,
971     NULL, script_methods, NULL, script_static_methods);
972     }
973    
974     #endif /* JS_HAS_SCRIPT_OBJECT */
975    
976     /*
977     * Shared script filename management.
978     */
979     static int
980     js_compare_strings(const void *k1, const void *k2)
981     {
982     return strcmp((const char *) k1, (const char *) k2) == 0;
983     }
984    
985     /* NB: This struct overlays JSHashEntry -- see jshash.h, do not reorganize. */
986     typedef struct ScriptFilenameEntry {
987     JSHashEntry *next; /* hash chain linkage */
988     JSHashNumber keyHash; /* key hash function result */
989     const void *key; /* ptr to filename, below */
990     uint32 flags; /* user-defined filename prefix flags */
991     JSPackedBool mark; /* GC mark flag */
992     char filename[3]; /* two or more bytes, NUL-terminated */
993     } ScriptFilenameEntry;
994    
995     static void *
996     js_alloc_table_space(void *priv, size_t size)
997     {
998     return malloc(size);
999     }
1000    
1001     static void
1002 siliconforks 460 js_free_table_space(void *priv, void *item, size_t size)
1003 siliconforks 332 {
1004     free(item);
1005     }
1006    
1007     static JSHashEntry *
1008     js_alloc_sftbl_entry(void *priv, const void *key)
1009     {
1010     size_t nbytes = offsetof(ScriptFilenameEntry, filename) +
1011     strlen((const char *) key) + 1;
1012    
1013     return (JSHashEntry *) malloc(JS_MAX(nbytes, sizeof(JSHashEntry)));
1014     }
1015    
1016     static void
1017     js_free_sftbl_entry(void *priv, JSHashEntry *he, uintN flag)
1018     {
1019     if (flag != HT_FREE_ENTRY)
1020     return;
1021     free(he);
1022     }
1023    
1024     static JSHashAllocOps sftbl_alloc_ops = {
1025     js_alloc_table_space, js_free_table_space,
1026     js_alloc_sftbl_entry, js_free_sftbl_entry
1027     };
1028    
1029     JSBool
1030     js_InitRuntimeScriptState(JSRuntime *rt)
1031     {
1032     #ifdef JS_THREADSAFE
1033     JS_ASSERT(!rt->scriptFilenameTableLock);
1034     rt->scriptFilenameTableLock = JS_NEW_LOCK();
1035     if (!rt->scriptFilenameTableLock)
1036     return JS_FALSE;
1037     #endif
1038     JS_ASSERT(!rt->scriptFilenameTable);
1039     rt->scriptFilenameTable =
1040     JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL,
1041     &sftbl_alloc_ops, NULL);
1042     if (!rt->scriptFilenameTable) {
1043     js_FinishRuntimeScriptState(rt); /* free lock if threadsafe */
1044     return JS_FALSE;
1045     }
1046     JS_INIT_CLIST(&rt->scriptFilenamePrefixes);
1047     return JS_TRUE;
1048     }
1049    
1050     typedef struct ScriptFilenamePrefix {
1051     JSCList links; /* circular list linkage for easy deletion */
1052     const char *name; /* pointer to pinned ScriptFilenameEntry string */
1053     size_t length; /* prefix string length, precomputed */
1054     uint32 flags; /* user-defined flags to inherit from this prefix */
1055     } ScriptFilenamePrefix;
1056    
1057     void
1058     js_FinishRuntimeScriptState(JSRuntime *rt)
1059     {
1060     if (rt->scriptFilenameTable) {
1061     JS_HashTableDestroy(rt->scriptFilenameTable);
1062     rt->scriptFilenameTable = NULL;
1063     }
1064     #ifdef JS_THREADSAFE
1065     if (rt->scriptFilenameTableLock) {
1066     JS_DESTROY_LOCK(rt->scriptFilenameTableLock);
1067     rt->scriptFilenameTableLock = NULL;
1068     }
1069     #endif
1070     }
1071    
1072     void
1073     js_FreeRuntimeScriptState(JSRuntime *rt)
1074     {
1075     ScriptFilenamePrefix *sfp;
1076    
1077     if (!rt->scriptFilenameTable)
1078     return;
1079    
1080     while (!JS_CLIST_IS_EMPTY(&rt->scriptFilenamePrefixes)) {
1081     sfp = (ScriptFilenamePrefix *) rt->scriptFilenamePrefixes.next;
1082     JS_REMOVE_LINK(&sfp->links);
1083     free(sfp);
1084     }
1085     js_FinishRuntimeScriptState(rt);
1086     }
1087    
1088     #ifdef DEBUG_brendan
1089     #define DEBUG_SFTBL
1090     #endif
1091     #ifdef DEBUG_SFTBL
1092     size_t sftbl_savings = 0;
1093     #endif
1094    
1095     static ScriptFilenameEntry *
1096     SaveScriptFilename(JSRuntime *rt, const char *filename, uint32 flags)
1097     {
1098     JSHashTable *table;
1099     JSHashNumber hash;
1100     JSHashEntry **hep;
1101     ScriptFilenameEntry *sfe;
1102     size_t length;
1103     JSCList *head, *link;
1104     ScriptFilenamePrefix *sfp;
1105    
1106     table = rt->scriptFilenameTable;
1107     hash = JS_HashString(filename);
1108     hep = JS_HashTableRawLookup(table, hash, filename);
1109     sfe = (ScriptFilenameEntry *) *hep;
1110     #ifdef DEBUG_SFTBL
1111     if (sfe)
1112     sftbl_savings += strlen(sfe->filename);
1113     #endif
1114    
1115     if (!sfe) {
1116     sfe = (ScriptFilenameEntry *)
1117     JS_HashTableRawAdd(table, hep, hash, filename, NULL);
1118     if (!sfe)
1119     return NULL;
1120     sfe->key = strcpy(sfe->filename, filename);
1121     sfe->flags = 0;
1122     sfe->mark = JS_FALSE;
1123     }
1124    
1125     /* If saving a prefix, add it to the set in rt->scriptFilenamePrefixes. */
1126     if (flags != 0) {
1127     /* Search in case filename was saved already; we must be idempotent. */
1128     sfp = NULL;
1129     length = strlen(filename);
1130     for (head = link = &rt->scriptFilenamePrefixes;
1131     link->next != head;
1132     link = link->next) {
1133     /* Lag link behind sfp to insert in non-increasing length order. */
1134     sfp = (ScriptFilenamePrefix *) link->next;
1135     if (!strcmp(sfp->name, filename))
1136     break;
1137     if (sfp->length <= length) {
1138     sfp = NULL;
1139     break;
1140     }
1141     sfp = NULL;
1142     }
1143    
1144     if (!sfp) {
1145     /* No such prefix: add one now. */
1146     sfp = (ScriptFilenamePrefix *) malloc(sizeof(ScriptFilenamePrefix));
1147     if (!sfp)
1148     return NULL;
1149     JS_INSERT_AFTER(&sfp->links, link);
1150     sfp->name = sfe->filename;
1151     sfp->length = length;
1152     sfp->flags = 0;
1153     }
1154    
1155     /*
1156     * Accumulate flags in both sfe and sfp: sfe for later access from the
1157     * JS_GetScriptedCallerFilenameFlags debug-API, and sfp so that longer
1158     * filename entries can inherit by prefix.
1159     */
1160     sfe->flags |= flags;
1161     sfp->flags |= flags;
1162     }
1163    
1164 siliconforks 460 #ifdef JS_FUNCTION_METERING
1165     size_t len = strlen(sfe->filename);
1166     if (len >= sizeof rt->lastScriptFilename)
1167     len = sizeof rt->lastScriptFilename - 1;
1168     memcpy(rt->lastScriptFilename, sfe->filename, len);
1169     rt->lastScriptFilename[len] = '\0';
1170     #endif
1171    
1172 siliconforks 332 return sfe;
1173     }
1174    
1175     const char *
1176     js_SaveScriptFilename(JSContext *cx, const char *filename)
1177     {
1178     JSRuntime *rt;
1179     ScriptFilenameEntry *sfe;
1180     JSCList *head, *link;
1181     ScriptFilenamePrefix *sfp;
1182    
1183     rt = cx->runtime;
1184     JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock);
1185     sfe = SaveScriptFilename(rt, filename, 0);
1186     if (!sfe) {
1187     JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
1188     JS_ReportOutOfMemory(cx);
1189     return NULL;
1190     }
1191    
1192     /*
1193     * Try to inherit flags by prefix. We assume there won't be more than a
1194     * few (dozen! ;-) prefixes, so linear search is tolerable.
1195     * XXXbe every time I've assumed that in the JS engine, I've been wrong!
1196     */
1197     for (head = &rt->scriptFilenamePrefixes, link = head->next;
1198     link != head;
1199     link = link->next) {
1200     sfp = (ScriptFilenamePrefix *) link;
1201     if (!strncmp(sfp->name, filename, sfp->length)) {
1202     sfe->flags |= sfp->flags;
1203     break;
1204     }
1205     }
1206     JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
1207     return sfe->filename;
1208     }
1209    
1210     const char *
1211     js_SaveScriptFilenameRT(JSRuntime *rt, const char *filename, uint32 flags)
1212     {
1213     ScriptFilenameEntry *sfe;
1214    
1215     /* This may be called very early, via the jsdbgapi.h entry point. */
1216     if (!rt->scriptFilenameTable && !js_InitRuntimeScriptState(rt))
1217     return NULL;
1218    
1219     JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock);
1220     sfe = SaveScriptFilename(rt, filename, flags);
1221     JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
1222     if (!sfe)
1223     return NULL;
1224    
1225     return sfe->filename;
1226     }
1227    
1228     /*
1229     * Back up from a saved filename by its offset within its hash table entry.
1230     */
1231     #define FILENAME_TO_SFE(fn) \
1232     ((ScriptFilenameEntry *) ((fn) - offsetof(ScriptFilenameEntry, filename)))
1233    
1234     /*
1235     * The sfe->key member, redundant given sfe->filename but required by the old
1236     * jshash.c code, here gives us a useful sanity check. This assertion will
1237     * very likely botch if someone tries to mark a string that wasn't allocated
1238     * as an sfe->filename.
1239     */
1240     #define ASSERT_VALID_SFE(sfe) JS_ASSERT((sfe)->key == (sfe)->filename)
1241    
1242     uint32
1243     js_GetScriptFilenameFlags(const char *filename)
1244     {
1245     ScriptFilenameEntry *sfe;
1246    
1247     sfe = FILENAME_TO_SFE(filename);
1248     ASSERT_VALID_SFE(sfe);
1249     return sfe->flags;
1250     }
1251    
1252     void
1253     js_MarkScriptFilename(const char *filename)
1254     {
1255     ScriptFilenameEntry *sfe;
1256    
1257     sfe = FILENAME_TO_SFE(filename);
1258     ASSERT_VALID_SFE(sfe);
1259     sfe->mark = JS_TRUE;
1260     }
1261    
1262     static intN
1263     js_script_filename_marker(JSHashEntry *he, intN i, void *arg)
1264     {
1265     ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he;
1266    
1267     sfe->mark = JS_TRUE;
1268     return HT_ENUMERATE_NEXT;
1269     }
1270    
1271     void
1272     js_MarkScriptFilenames(JSRuntime *rt, JSBool keepAtoms)
1273     {
1274     JSCList *head, *link;
1275     ScriptFilenamePrefix *sfp;
1276    
1277     if (!rt->scriptFilenameTable)
1278     return;
1279    
1280     if (keepAtoms) {
1281     JS_HashTableEnumerateEntries(rt->scriptFilenameTable,
1282     js_script_filename_marker,
1283     rt);
1284     }
1285     for (head = &rt->scriptFilenamePrefixes, link = head->next;
1286     link != head;
1287     link = link->next) {
1288     sfp = (ScriptFilenamePrefix *) link;
1289     js_MarkScriptFilename(sfp->name);
1290     }
1291     }
1292    
1293     static intN
1294     js_script_filename_sweeper(JSHashEntry *he, intN i, void *arg)
1295     {
1296     ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he;
1297    
1298     if (!sfe->mark)
1299     return HT_ENUMERATE_REMOVE;
1300     sfe->mark = JS_FALSE;
1301     return HT_ENUMERATE_NEXT;
1302     }
1303    
1304     void
1305     js_SweepScriptFilenames(JSRuntime *rt)
1306     {
1307     if (!rt->scriptFilenameTable)
1308     return;
1309    
1310     JS_HashTableEnumerateEntries(rt->scriptFilenameTable,
1311     js_script_filename_sweeper,
1312     rt);
1313     #ifdef DEBUG_notme
1314     #ifdef DEBUG_SFTBL
1315     printf("script filename table savings so far: %u\n", sftbl_savings);
1316     #endif
1317     #endif
1318     }
1319    
1320     /*
1321     * JSScript data structures memory alignment:
1322     *
1323     * JSScript
1324     * JSObjectArray script objects' descriptor if JSScript.objectsOffset != 0,
1325     * use JS_SCRIPT_OBJECTS(script) macro to access it.
1326     * JSObjectArray script regexps' descriptor if JSScript.regexpsOffset != 0,
1327     * use JS_SCRIPT_REGEXPS(script) macro to access it.
1328     * JSTryNoteArray script try notes' descriptor if JSScript.tryNotesOffset
1329     * != 0, use JS_SCRIPT_TRYNOTES(script) macro to access it.
1330     * JSAtom *a[] array of JSScript.atomMap.length atoms pointed by
1331     * JSScript.atomMap.vector if any.
1332     * JSObject *o[] array of JS_SCRIPT_OBJECTS(script)->length objects if any
1333     * pointed by JS_SCRIPT_OBJECTS(script)->vector.
1334     * JSObject *r[] array of JS_SCRIPT_REGEXPS(script)->length regexps if any
1335     * pointed by JS_SCRIPT_REGEXPS(script)->vector.
1336     * JSTryNote t[] array of JS_SCRIPT_TRYNOTES(script)->length try notes if any
1337     * pointed by JS_SCRIPT_TRYNOTES(script)->vector.
1338     * jsbytecode b[] script bytecode pointed by JSScript.code.
1339     * jssrcnote s[] script source notes, use SCRIPT_NOTES(script) to access it
1340     *
1341     * The alignment avoids gaps between entries as alignment requirement for each
1342     * subsequent structure or array is the same or divides the alignment
1343     * requirement for the previous one.
1344     *
1345     * The followings asserts checks that assuming that the alignment requirement
1346     * for JSObjectArray and JSTryNoteArray are sizeof(void *) and for JSTryNote
1347     * it is sizeof(uint32) as the structure consists of 3 uint32 fields.
1348     */
1349     JS_STATIC_ASSERT(sizeof(JSScript) % sizeof(void *) == 0);
1350     JS_STATIC_ASSERT(sizeof(JSObjectArray) % sizeof(void *) == 0);
1351     JS_STATIC_ASSERT(sizeof(JSTryNoteArray) == sizeof(JSObjectArray));
1352     JS_STATIC_ASSERT(sizeof(JSAtom *) == sizeof(JSObject *));
1353     JS_STATIC_ASSERT(sizeof(JSObject *) % sizeof(uint32) == 0);
1354     JS_STATIC_ASSERT(sizeof(JSTryNote) == 3 * sizeof(uint32));
1355     JS_STATIC_ASSERT(sizeof(uint32) % sizeof(jsbytecode) == 0);
1356     JS_STATIC_ASSERT(sizeof(jsbytecode) % sizeof(jssrcnote) == 0);
1357    
1358     /*
1359     * Check that uint8 offset for object, upvar, regexp, and try note arrays is
1360     * sufficient.
1361     */
1362     JS_STATIC_ASSERT(sizeof(JSScript) + 2 * sizeof(JSObjectArray) +
1363     sizeof(JSUpvarArray) < JS_BIT(8));
1364    
1365     JSScript *
1366     js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
1367     uint32 nobjects, uint32 nupvars, uint32 nregexps,
1368     uint32 ntrynotes)
1369     {
1370     size_t size, vectorSize;
1371     JSScript *script;
1372     uint8 *cursor;
1373    
1374     size = sizeof(JSScript) +
1375     sizeof(JSAtom *) * natoms +
1376     length * sizeof(jsbytecode) +
1377     nsrcnotes * sizeof(jssrcnote);
1378     if (nobjects != 0)
1379     size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *);
1380     if (nupvars != 0)
1381     size += sizeof(JSUpvarArray) + nupvars * sizeof(uint32);
1382     if (nregexps != 0)
1383     size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *);
1384     if (ntrynotes != 0)
1385     size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote);
1386    
1387     script = (JSScript *) JS_malloc(cx, size);
1388     if (!script)
1389     return NULL;
1390     memset(script, 0, sizeof(JSScript));
1391     script->length = length;
1392     script->version = cx->version;
1393    
1394     cursor = (uint8 *)script + sizeof(JSScript);
1395     if (nobjects != 0) {
1396     script->objectsOffset = (uint8)(cursor - (uint8 *)script);
1397     cursor += sizeof(JSObjectArray);
1398     }
1399     if (nupvars != 0) {
1400     script->upvarsOffset = (uint8)(cursor - (uint8 *)script);
1401     cursor += sizeof(JSUpvarArray);
1402     }
1403     if (nregexps != 0) {
1404     script->regexpsOffset = (uint8)(cursor - (uint8 *)script);
1405     cursor += sizeof(JSObjectArray);
1406     }
1407     if (ntrynotes != 0) {
1408     script->trynotesOffset = (uint8)(cursor - (uint8 *)script);
1409     cursor += sizeof(JSTryNoteArray);
1410     }
1411    
1412     if (natoms != 0) {
1413     script->atomMap.length = natoms;
1414     script->atomMap.vector = (JSAtom **)cursor;
1415     vectorSize = natoms * sizeof(script->atomMap.vector[0]);
1416    
1417     /*
1418     * Clear object map's vector so the GC tracing can run when not yet
1419     * all atoms are copied to the array.
1420     */
1421     memset(cursor, 0, vectorSize);
1422     cursor += vectorSize;
1423     }
1424    
1425     if (nobjects != 0) {
1426     JS_SCRIPT_OBJECTS(script)->length = nobjects;
1427     JS_SCRIPT_OBJECTS(script)->vector = (JSObject **)cursor;
1428     vectorSize = nobjects * sizeof(JS_SCRIPT_OBJECTS(script)->vector[0]);
1429     memset(cursor, 0, vectorSize);
1430     cursor += vectorSize;
1431     }
1432    
1433     if (nupvars != 0) {
1434     JS_SCRIPT_UPVARS(script)->length = nupvars;
1435     JS_SCRIPT_UPVARS(script)->vector = (uint32 *)cursor;
1436     vectorSize = nupvars * sizeof(JS_SCRIPT_UPVARS(script)->vector[0]);
1437     memset(cursor, 0, vectorSize);
1438     cursor += vectorSize;
1439     }
1440    
1441     if (nregexps != 0) {
1442     JS_SCRIPT_REGEXPS(script)->length = nregexps;
1443     JS_SCRIPT_REGEXPS(script)->vector = (JSObject **)cursor;
1444     vectorSize = nregexps * sizeof(JS_SCRIPT_REGEXPS(script)->vector[0]);
1445     memset(cursor, 0, vectorSize);
1446     cursor += vectorSize;
1447     }
1448    
1449     if (ntrynotes != 0) {
1450     JS_SCRIPT_TRYNOTES(script)->length = ntrynotes;
1451     JS_SCRIPT_TRYNOTES(script)->vector = (JSTryNote *)cursor;
1452     vectorSize = ntrynotes * sizeof(JS_SCRIPT_TRYNOTES(script)->vector[0]);
1453     #ifdef DEBUG
1454     memset(cursor, 0, vectorSize);
1455     #endif
1456     cursor += vectorSize;
1457     }
1458    
1459     script->code = script->main = (jsbytecode *)cursor;
1460     JS_ASSERT(cursor +
1461     length * sizeof(jsbytecode) +
1462     nsrcnotes * sizeof(jssrcnote) ==
1463     (uint8 *)script + size);
1464    
1465     #ifdef CHECK_SCRIPT_OWNER
1466     script->owner = cx->thread;
1467     #endif
1468     return script;
1469     }
1470    
1471     JSScript *
1472     js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
1473     {
1474     uint32 mainLength, prologLength, nsrcnotes, nfixed;
1475     JSScript *script;
1476     const char *filename;
1477     JSFunction *fun;
1478    
1479     /* The counts of indexed things must be checked during code generation. */
1480     JS_ASSERT(cg->atomList.count <= INDEX_LIMIT);
1481     JS_ASSERT(cg->objectList.length <= INDEX_LIMIT);
1482     JS_ASSERT(cg->regexpList.length <= INDEX_LIMIT);
1483    
1484     mainLength = CG_OFFSET(cg);
1485     prologLength = CG_PROLOG_OFFSET(cg);
1486     CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
1487     script = js_NewScript(cx, prologLength + mainLength, nsrcnotes,
1488     cg->atomList.count, cg->objectList.length,
1489     cg->upvarList.count, cg->regexpList.length,
1490     cg->ntrynotes);
1491     if (!script)
1492     return NULL;
1493    
1494     /* Now that we have script, error control flow must go to label bad. */
1495     script->main += prologLength;
1496     memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
1497     memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
1498 siliconforks 460 nfixed = (cg->flags & TCF_IN_FUNCTION)
1499     ? cg->fun->u.i.nvars
1500     : cg->ngvars + cg->regexpList.length;
1501 siliconforks 332 JS_ASSERT(nfixed < SLOTNO_LIMIT);
1502     script->nfixed = (uint16) nfixed;
1503     js_InitAtomMap(cx, &script->atomMap, &cg->atomList);
1504    
1505 siliconforks 460 filename = cg->compiler->tokenStream.filename;
1506 siliconforks 332 if (filename) {
1507     script->filename = js_SaveScriptFilename(cx, filename);
1508     if (!script->filename)
1509     goto bad;
1510     }
1511     script->lineno = cg->firstLine;
1512     if (script->nfixed + cg->maxStackDepth >= JS_BIT(16)) {
1513     js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR,
1514     JSMSG_NEED_DIET, "script");
1515     goto bad;
1516     }
1517     script->nslots = script->nfixed + cg->maxStackDepth;
1518 siliconforks 460 script->staticLevel = cg->staticLevel;
1519     script->principals = cg->compiler->principals;
1520 siliconforks 332 if (script->principals)
1521     JSPRINCIPALS_HOLD(cx, script->principals);
1522    
1523     if (!js_FinishTakingSrcNotes(cx, cg, SCRIPT_NOTES(script)))
1524     goto bad;
1525     if (cg->ntrynotes != 0)
1526     js_FinishTakingTryNotes(cg, JS_SCRIPT_TRYNOTES(script));
1527     if (cg->objectList.length != 0)
1528 siliconforks 460 cg->objectList.finish(JS_SCRIPT_OBJECTS(script));
1529 siliconforks 332 if (cg->regexpList.length != 0)
1530 siliconforks 460 cg->regexpList.finish(JS_SCRIPT_REGEXPS(script));
1531     if (cg->flags & TCF_NO_SCRIPT_RVAL)
1532 siliconforks 332 script->flags |= JSSF_NO_SCRIPT_RVAL;
1533    
1534     if (cg->upvarList.count != 0) {
1535     JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length);
1536     memcpy(JS_SCRIPT_UPVARS(script)->vector, cg->upvarMap.vector,
1537     cg->upvarList.count * sizeof(uint32));
1538 siliconforks 460 cg->upvarList.clear();
1539 siliconforks 332 JS_free(cx, cg->upvarMap.vector);
1540     cg->upvarMap.vector = NULL;
1541     }
1542    
1543     /*
1544     * We initialize fun->u.script to be the script constructed above
1545     * so that the debugger has a valid FUN_SCRIPT(fun).
1546     */
1547     fun = NULL;
1548 siliconforks 460 if (cg->flags & TCF_IN_FUNCTION) {
1549     fun = cg->fun;
1550 siliconforks 332 JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
1551     JS_ASSERT_IF(script->upvarsOffset != 0,
1552     JS_SCRIPT_UPVARS(script)->length == fun->u.i.nupvars);
1553    
1554     js_FreezeLocalNames(cx, fun);
1555     fun->u.i.script = script;
1556     #ifdef CHECK_SCRIPT_OWNER
1557     script->owner = NULL;
1558     #endif
1559 siliconforks 460 if (cg->flags & TCF_FUN_HEAVYWEIGHT)
1560 siliconforks 332 fun->flags |= JSFUN_HEAVYWEIGHT;
1561     }
1562    
1563     /* Tell the debugger about this compiled script. */
1564     js_CallNewScriptHook(cx, script, fun);
1565     return script;
1566    
1567     bad:
1568     js_DestroyScript(cx, script);
1569     return NULL;
1570     }
1571    
1572     JS_FRIEND_API(void)
1573     js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
1574     {
1575     JSNewScriptHook hook;
1576    
1577     hook = cx->debugHooks->newScriptHook;
1578     if (hook) {
1579     JS_KEEP_ATOMS(cx->runtime);
1580     hook(cx, script->filename, script->lineno, script, fun,
1581     cx->debugHooks->newScriptHookData);
1582     JS_UNKEEP_ATOMS(cx->runtime);
1583     }
1584     }
1585    
1586     JS_FRIEND_API(void)
1587     js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
1588     {
1589     JSDestroyScriptHook hook;
1590    
1591     hook = cx->debugHooks->destroyScriptHook;
1592     if (hook)
1593     hook(cx, script, cx->debugHooks->destroyScriptHookData);
1594     }
1595    
1596     void
1597     js_DestroyScript(JSContext *cx, JSScript *script)
1598     {
1599     js_CallDestroyScriptHook(cx, script);
1600     JS_ClearScriptTraps(cx, script);
1601    
1602     if (script->principals)
1603     JSPRINCIPALS_DROP(cx, script->principals);
1604    
1605     if (JS_GSN_CACHE(cx).code == script->code)
1606 siliconforks 460 JS_PURGE_GSN_CACHE(cx);
1607 siliconforks 332
1608     /*
1609     * The GC flushes all property caches, so no need to purge just the
1610     * entries for this script.
1611     *
1612 siliconforks 460 * JS_THREADSAFE note: js_PurgePropertyCacheForScript purges only the
1613 siliconforks 332 * current thread's property cache, so a script not owned by a function
1614     * or object, which hands off lifetime management for that script to the
1615     * GC, must be used by only one thread over its lifetime.
1616     *
1617     * This should be an API-compatible change, since a script is never safe
1618     * against premature GC if shared among threads without a rooted object
1619     * wrapping it to protect the script's mapped atoms against GC. We use
1620     * script->owner to enforce this requirement via assertions.
1621     */
1622     #ifdef CHECK_SCRIPT_OWNER
1623     JS_ASSERT_IF(cx->runtime->gcRunning, !script->owner);
1624     #endif
1625    
1626     if (!cx->runtime->gcRunning) {
1627 siliconforks 460 JSStackFrame *fp = js_GetTopStackFrame(cx);
1628    
1629     if (!(fp && (fp->flags & JSFRAME_EVAL))) {
1630 siliconforks 332 #ifdef CHECK_SCRIPT_OWNER
1631     JS_ASSERT(script->owner == cx->thread);
1632     #endif
1633 siliconforks 460 js_PurgePropertyCacheForScript(cx, script);
1634     #ifdef JS_TRACER
1635     js_PurgeScriptFragments(cx, script);
1636     #endif
1637 siliconforks 332 }
1638     }
1639    
1640     JS_free(cx, script);
1641     }
1642    
1643     void
1644     js_TraceScript(JSTracer *trc, JSScript *script)
1645     {
1646     JSAtomMap *map;
1647     uintN i, length;
1648     JSAtom **vector;
1649     jsval v;
1650     JSObjectArray *objarray;
1651    
1652     map = &script->atomMap;
1653     length = map->length;
1654     vector = map->vector;
1655     for (i = 0; i < length; i++) {
1656     v = ATOM_KEY(vector[i]);
1657     if (JSVAL_IS_TRACEABLE(v)) {
1658     JS_SET_TRACING_INDEX(trc, "atomMap", i);
1659     JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
1660     }
1661     }
1662    
1663     if (script->objectsOffset != 0) {
1664     objarray = JS_SCRIPT_OBJECTS(script);
1665     i = objarray->length;
1666     do {
1667     --i;
1668     if (objarray->vector[i]) {
1669     JS_SET_TRACING_INDEX(trc, "objects", i);
1670     JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT);
1671     }
1672     } while (i != 0);
1673     }
1674    
1675     if (script->regexpsOffset != 0) {
1676     objarray = JS_SCRIPT_REGEXPS(script);
1677     i = objarray->length;
1678     do {
1679     --i;
1680     if (objarray->vector[i]) {
1681     JS_SET_TRACING_INDEX(trc, "regexps", i);
1682     JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT);
1683     }
1684     } while (i != 0);
1685     }
1686    
1687     if (script->u.object) {
1688     JS_SET_TRACING_NAME(trc, "object");
1689     JS_CallTracer(trc, script->u.object, JSTRACE_OBJECT);
1690     }
1691    
1692     if (IS_GC_MARKING_TRACER(trc) && script->filename)
1693     js_MarkScriptFilename(script->filename);
1694     }
1695    
1696     typedef struct GSNCacheEntry {
1697     JSDHashEntryHdr hdr;
1698     jsbytecode *pc;
1699     jssrcnote *sn;
1700     } GSNCacheEntry;
1701    
1702     #define GSN_CACHE_THRESHOLD 100
1703    
1704 siliconforks 460 void
1705     js_PurgeGSNCache(JSGSNCache *cache)
1706     {
1707     cache->code = NULL;
1708     if (cache->table.ops) {
1709     JS_DHashTableFinish(&cache->table);
1710     cache->table.ops = NULL;
1711     }
1712     GSN_CACHE_METER(cache, purges);
1713     }
1714    
1715 siliconforks 332 jssrcnote *
1716     js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
1717     {
1718     ptrdiff_t target, offset;
1719     GSNCacheEntry *entry;
1720     jssrcnote *sn, *result;
1721     uintN nsrcnotes;
1722    
1723    
1724     target = PTRDIFF(pc, script->code, jsbytecode);
1725     if ((uint32)target >= script->length)
1726     return NULL;
1727    
1728     if (JS_GSN_CACHE(cx).code == script->code) {
1729     JS_METER_GSN_CACHE(cx, hits);
1730     entry = (GSNCacheEntry *)
1731     JS_DHashTableOperate(&JS_GSN_CACHE(cx).table, pc,
1732     JS_DHASH_LOOKUP);
1733     return entry->sn;
1734     }
1735    
1736     JS_METER_GSN_CACHE(cx, misses);
1737     offset = 0;
1738     for (sn = SCRIPT_NOTES(script); ; sn = SN_NEXT(sn)) {
1739     if (SN_IS_TERMINATOR(sn)) {
1740     result = NULL;
1741     break;
1742     }
1743     offset += SN_DELTA(sn);
1744     if (offset == target && SN_IS_GETTABLE(sn)) {
1745     result = sn;
1746     break;
1747     }
1748     }
1749    
1750     if (JS_GSN_CACHE(cx).code != script->code &&
1751     script->length >= GSN_CACHE_THRESHOLD) {
1752 siliconforks 460 JS_PURGE_GSN_CACHE(cx);
1753 siliconforks 332 nsrcnotes = 0;
1754     for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn);
1755     sn = SN_NEXT(sn)) {
1756     if (SN_IS_GETTABLE(sn))
1757     ++nsrcnotes;
1758     }
1759     if (!JS_DHashTableInit(&JS_GSN_CACHE(cx).table, JS_DHashGetStubOps(),
1760     NULL, sizeof(GSNCacheEntry),
1761     JS_DHASH_DEFAULT_CAPACITY(nsrcnotes))) {
1762     JS_GSN_CACHE(cx).table.ops = NULL;
1763     } else {
1764     pc = script->code;
1765     for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn);
1766     sn = SN_NEXT(sn)) {
1767     pc += SN_DELTA(sn);
1768     if (SN_IS_GETTABLE(sn)) {
1769     entry = (GSNCacheEntry *)
1770     JS_DHashTableOperate(&JS_GSN_CACHE(cx).table, pc,
1771     JS_DHASH_ADD);
1772     entry->pc = pc;
1773     entry->sn = sn;
1774     }
1775     }
1776     JS_GSN_CACHE(cx).code = script->code;
1777     JS_METER_GSN_CACHE(cx, fills);
1778     }
1779     }
1780    
1781     return result;
1782     }
1783    
1784     uintN
1785 siliconforks 399 js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp)
1786     {
1787     return js_PCToLineNumber(cx, fp->script, fp->imacpc ? fp->imacpc : fp->regs->pc);
1788     }
1789    
1790     uintN
1791 siliconforks 332 js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
1792     {
1793 siliconforks 460 JSOp op;
1794 siliconforks 332 JSFunction *fun;
1795     uintN lineno;
1796     ptrdiff_t offset, target;
1797     jssrcnote *sn;
1798     JSSrcNoteType type;
1799    
1800     /* Cope with JSStackFrame.pc value prior to entering js_Interpret. */
1801     if (!pc)
1802     return 0;
1803    
1804     /*
1805     * Special case: function definition needs no line number note because
1806     * the function's script contains its starting line number.
1807     */
1808 siliconforks 460 op = js_GetOpcode(cx, script, pc);
1809     if (js_CodeSpec[op].format & JOF_INDEXBASE)
1810     pc += js_CodeSpec[op].length;
1811 siliconforks 332 if (*pc == JSOP_DEFFUN) {
1812     GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun);
1813     return fun->u.i.script->lineno;
1814     }
1815    
1816     /*
1817     * General case: walk through source notes accumulating their deltas,
1818     * keeping track of line-number notes, until we pass the note for pc's
1819     * offset within script->code.
1820     */
1821     lineno = script->lineno;
1822     offset = 0;
1823     target = PTRDIFF(pc, script->code, jsbytecode);
1824     for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
1825     offset += SN_DELTA(sn);
1826     type = (JSSrcNoteType) SN_TYPE(sn);
1827     if (type == SRC_SETLINE) {
1828     if (offset <= target)
1829     lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
1830     } else if (type == SRC_NEWLINE) {
1831     if (offset <= target)
1832     lineno++;
1833     }
1834     if (offset > target)
1835     break;
1836     }
1837     return lineno;
1838     }
1839    
1840     /* The line number limit is the same as the jssrcnote offset limit. */
1841     #define SN_LINE_LIMIT (SN_3BYTE_OFFSET_FLAG << 16)
1842    
1843     jsbytecode *
1844     js_LineNumberToPC(JSScript *script, uintN target)
1845     {
1846     ptrdiff_t offset, best;
1847     uintN lineno, bestdiff, diff;
1848     jssrcnote *sn;
1849     JSSrcNoteType type;
1850    
1851     offset = 0;
1852     best = -1;
1853     lineno = script->lineno;
1854     bestdiff = SN_LINE_LIMIT;
1855     for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
1856     /*
1857     * Exact-match only if offset is not in the prolog; otherwise use
1858     * nearest greater-or-equal line number match.
1859     */
1860     if (lineno == target && script->code + offset >= script->main)
1861     goto out;
1862     if (lineno >= target) {
1863     diff = lineno - target;
1864     if (diff < bestdiff) {
1865     bestdiff = diff;
1866     best = offset;
1867     }
1868     }
1869     offset += SN_DELTA(sn);
1870     type = (JSSrcNoteType) SN_TYPE(sn);
1871     if (type == SRC_SETLINE) {
1872     lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
1873     } else if (type == SRC_NEWLINE) {
1874     lineno++;
1875     }
1876     }
1877     if (best >= 0)
1878     offset = best;
1879     out:
1880     return script->code + offset;
1881     }
1882    
1883     JS_FRIEND_API(uintN)
1884     js_GetScriptLineExtent(JSScript *script)
1885     {
1886     uintN lineno;
1887     jssrcnote *sn;
1888     JSSrcNoteType type;
1889    
1890     lineno = script->lineno;
1891     for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
1892     type = (JSSrcNoteType) SN_TYPE(sn);
1893     if (type == SRC_SETLINE) {
1894     lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
1895     } else if (type == SRC_NEWLINE) {
1896     lineno++;
1897     }
1898     }
1899     return 1 + lineno - script->lineno;
1900     }
1901    
1902     #if JS_HAS_GENERATORS
1903    
1904     JSBool
1905     js_IsInsideTryWithFinally(JSScript *script, jsbytecode *pc)
1906     {
1907     JSTryNoteArray *tarray;
1908     JSTryNote *tn, *tnlimit;
1909     uint32 off;
1910    
1911     JS_ASSERT(script->code <= pc);
1912     JS_ASSERT(pc < script->code + script->length);
1913    
1914     if (!script->trynotesOffset != 0)
1915     return JS_FALSE;
1916     tarray = JS_SCRIPT_TRYNOTES(script);
1917     JS_ASSERT(tarray->length != 0);
1918    
1919     tn = tarray->vector;
1920     tnlimit = tn + tarray->length;
1921     off = (uint32)(pc - script->main);
1922     do {
1923     if (off - tn->start < tn->length) {
1924 siliconforks 399 if (tn->kind == JSTRY_FINALLY)
1925 siliconforks 332 return JS_TRUE;
1926 siliconforks 399 JS_ASSERT(tn->kind == JSTRY_CATCH);
1927 siliconforks 332 }
1928     } while (++tn != tnlimit);
1929     return JS_FALSE;
1930     }
1931    
1932     #endif

  ViewVC Help
Powered by ViewVC 1.1.24