2001-09-20 04:02:59 +04:00
|
|
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
2006-08-01 02:52:27 +04:00
|
|
|
* vim: set ts=8 sw=4 et tw=78:
|
1998-03-28 05:44:41 +03:00
|
|
|
*
|
2003-11-15 03:11:16 +03:00
|
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
1998-03-28 05:44:41 +03:00
|
|
|
*
|
2003-11-15 03:11:16 +03:00
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
1998-03-28 05:44:41 +03:00
|
|
|
*
|
2001-09-20 04:02:59 +04:00
|
|
|
* The Original Code is Mozilla Communicator client code, released
|
|
|
|
* March 31, 1998.
|
1999-09-29 03:12:09 +04:00
|
|
|
*
|
2003-11-15 03:11:16 +03:00
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
1999-09-29 03:12:09 +04:00
|
|
|
*
|
2003-07-27 02:37:11 +04:00
|
|
|
* Contributor(s):
|
1999-09-29 03:12:09 +04:00
|
|
|
*
|
2003-11-15 03:11:16 +03:00
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* JS script operations.
|
|
|
|
*/
|
1998-06-10 01:10:45 +04:00
|
|
|
#include "jsstddef.h"
|
1998-03-28 05:44:41 +03:00
|
|
|
#include <string.h>
|
1998-10-14 14:22:38 +04:00
|
|
|
#include "jstypes.h"
|
|
|
|
#include "jsutil.h" /* Added by JSIFY */
|
|
|
|
#include "jsprf.h"
|
1998-03-28 05:44:41 +03:00
|
|
|
#include "jsapi.h"
|
1998-04-24 04:31:11 +04:00
|
|
|
#include "jsatom.h"
|
1998-03-28 05:44:41 +03:00
|
|
|
#include "jscntxt.h"
|
1998-04-24 04:31:11 +04:00
|
|
|
#include "jsconfig.h"
|
1998-03-28 05:44:41 +03:00
|
|
|
#include "jsdbgapi.h"
|
|
|
|
#include "jsemit.h"
|
1998-04-24 04:31:11 +04:00
|
|
|
#include "jsfun.h"
|
|
|
|
#include "jsinterp.h"
|
2003-07-27 02:37:11 +04:00
|
|
|
#include "jslock.h"
|
1998-04-24 04:31:11 +04:00
|
|
|
#include "jsnum.h"
|
|
|
|
#include "jsopcode.h"
|
2007-10-03 03:10:09 +04:00
|
|
|
#include "jsparse.h"
|
1998-03-28 05:44:41 +03:00
|
|
|
#include "jsscript.h"
|
1998-04-24 04:31:11 +04:00
|
|
|
#if JS_HAS_XDR
|
|
|
|
#include "jsxdrapi.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if JS_HAS_SCRIPT_OBJECT
|
|
|
|
|
2007-08-02 08:33:52 +04:00
|
|
|
static const char js_script_exec_str[] = "Script.prototype.exec";
|
|
|
|
static const char js_script_compile_str[] = "Script.prototype.compile";
|
2005-10-14 23:05:43 +04:00
|
|
|
|
2007-02-27 07:35:35 +03:00
|
|
|
/*
|
|
|
|
* This routine requires that obj has been locked previously.
|
|
|
|
*/
|
|
|
|
static jsint
|
|
|
|
GetScriptExecDepth(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
jsval v;
|
|
|
|
|
|
|
|
JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj));
|
|
|
|
v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_START(&js_ScriptClass));
|
|
|
|
return JSVAL_TO_INT(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
AdjustScriptExecDepth(JSContext *cx, JSObject *obj, jsint delta)
|
|
|
|
{
|
|
|
|
jsint execDepth;
|
|
|
|
|
|
|
|
JS_LOCK_OBJ(cx, obj);
|
|
|
|
execDepth = GetScriptExecDepth(cx, obj);
|
|
|
|
LOCKED_OBJ_SET_SLOT(obj, JSSLOT_START(&js_ScriptClass),
|
|
|
|
INT_TO_JSVAL(execDepth + delta));
|
|
|
|
JS_UNLOCK_OBJ(cx, obj);
|
|
|
|
}
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
#if JS_HAS_TOSOURCE
|
|
|
|
static JSBool
|
2007-08-02 08:33:52 +04:00
|
|
|
script_toSource(JSContext *cx, uintN argc, jsval *vp)
|
1998-04-24 04:31:11 +04:00
|
|
|
{
|
2007-08-02 08:33:52 +04:00
|
|
|
JSObject *obj;
|
2007-01-29 07:50:34 +03:00
|
|
|
uint32 indent;
|
1998-04-24 04:31:11 +04:00
|
|
|
JSScript *script;
|
|
|
|
size_t i, j, k, n;
|
|
|
|
char buf[16];
|
|
|
|
jschar *s, *t;
|
|
|
|
JSString *str;
|
|
|
|
|
2007-08-02 08:33:52 +04:00
|
|
|
obj = JS_THIS_OBJECT(cx, vp);
|
|
|
|
if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
|
2007-01-29 11:22:31 +03:00
|
|
|
return JS_FALSE;
|
|
|
|
|
2007-01-29 07:50:34 +03:00
|
|
|
indent = 0;
|
2008-03-07 00:40:43 +03:00
|
|
|
if (argc != 0) {
|
|
|
|
indent = js_ValueToECMAUint32(cx, &vp[2]);
|
2008-03-07 02:24:08 +03:00
|
|
|
if (JSVAL_IS_NULL(vp[2]))
|
2008-03-07 00:40:43 +03:00
|
|
|
return JS_FALSE;
|
|
|
|
}
|
2007-01-29 07:50:34 +03:00
|
|
|
|
2000-02-04 05:01:49 +03:00
|
|
|
script = (JSScript *) JS_GetPrivate(cx, obj);
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
/* Let n count the source string length, j the "front porch" length. */
|
1998-10-14 14:22:38 +04:00
|
|
|
j = JS_snprintf(buf, sizeof buf, "(new %s(", js_ScriptClass.name);
|
1998-04-24 04:31:11 +04:00
|
|
|
n = j + 2;
|
|
|
|
if (!script) {
|
2001-03-06 04:56:30 +03:00
|
|
|
/* Let k count the constructor argument string length. */
|
|
|
|
k = 0;
|
1998-11-05 03:08:43 +03:00
|
|
|
s = NULL; /* quell GCC overwarning */
|
1998-04-24 04:31:11 +04:00
|
|
|
} else {
|
2001-03-06 04:56:30 +03:00
|
|
|
str = JS_DecompileScript(cx, script, "Script.prototype.toSource",
|
|
|
|
(uintN)indent);
|
|
|
|
if (!str)
|
|
|
|
return JS_FALSE;
|
|
|
|
str = js_QuoteString(cx, str, '\'');
|
|
|
|
if (!str)
|
|
|
|
return JS_FALSE;
|
2007-08-16 10:23:06 +04:00
|
|
|
JSSTRING_CHARS_AND_LENGTH(str, s, k);
|
2001-03-06 04:56:30 +03:00
|
|
|
n += k;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate the source string and copy into it. */
|
2000-02-04 05:01:49 +03:00
|
|
|
t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!t)
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
1998-04-24 04:31:11 +04:00
|
|
|
for (i = 0; i < j; i++)
|
2001-03-06 04:56:30 +03:00
|
|
|
t[i] = buf[i];
|
1998-04-24 04:31:11 +04:00
|
|
|
for (j = 0; j < k; i++, j++)
|
2001-03-06 04:56:30 +03:00
|
|
|
t[i] = s[j];
|
1998-04-24 04:31:11 +04:00
|
|
|
t[i++] = ')';
|
|
|
|
t[i++] = ')';
|
|
|
|
t[i] = 0;
|
|
|
|
|
|
|
|
/* Create and return a JS string for t. */
|
|
|
|
str = JS_NewUCString(cx, t, n);
|
|
|
|
if (!str) {
|
2001-03-06 04:56:30 +03:00
|
|
|
JS_free(cx, t);
|
|
|
|
return JS_FALSE;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
2007-08-02 08:33:52 +04:00
|
|
|
*vp = STRING_TO_JSVAL(str);
|
1998-04-24 04:31:11 +04:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
#endif /* JS_HAS_TOSOURCE */
|
|
|
|
|
|
|
|
static JSBool
|
2007-08-02 08:33:52 +04:00
|
|
|
script_toString(JSContext *cx, uintN argc, jsval *vp)
|
1998-04-24 04:31:11 +04:00
|
|
|
{
|
|
|
|
uint32 indent;
|
2007-08-02 08:33:52 +04:00
|
|
|
JSObject *obj;
|
2007-01-29 07:50:34 +03:00
|
|
|
JSScript *script;
|
1998-04-24 04:31:11 +04:00
|
|
|
JSString *str;
|
|
|
|
|
2007-01-29 07:50:34 +03:00
|
|
|
indent = 0;
|
2008-03-07 00:40:43 +03:00
|
|
|
if (argc != 0) {
|
|
|
|
indent = js_ValueToECMAUint32(cx, &vp[2]);
|
2008-03-07 02:24:08 +03:00
|
|
|
if (JSVAL_IS_NULL(vp[2]))
|
2008-03-07 00:40:43 +03:00
|
|
|
return JS_FALSE;
|
|
|
|
}
|
2007-01-29 07:50:34 +03:00
|
|
|
|
2007-08-02 08:33:52 +04:00
|
|
|
obj = JS_THIS_OBJECT(cx, vp);
|
|
|
|
if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
2000-02-04 05:01:49 +03:00
|
|
|
script = (JSScript *) JS_GetPrivate(cx, obj);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!script) {
|
2007-08-02 08:33:52 +04:00
|
|
|
*vp = STRING_TO_JSVAL(cx->runtime->emptyString);
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_TRUE;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
str = JS_DecompileScript(cx, script, "Script.prototype.toString",
|
2001-03-06 04:56:30 +03:00
|
|
|
(uintN)indent);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!str)
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
2007-08-02 08:33:52 +04:00
|
|
|
*vp = STRING_TO_JSVAL(str);
|
1998-04-24 04:31:11 +04:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2007-08-02 08:33:52 +04:00
|
|
|
script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|
|
|
jsval *rval)
|
1998-04-24 04:31:11 +04:00
|
|
|
{
|
2006-10-07 00:13:46 +04:00
|
|
|
JSString *str;
|
1998-04-24 04:31:11 +04:00
|
|
|
JSObject *scopeobj;
|
2007-02-27 07:35:35 +03:00
|
|
|
jsval v;
|
|
|
|
JSScript *script, *oldscript;
|
2007-01-29 07:40:34 +03:00
|
|
|
JSStackFrame *fp, *caller;
|
1998-04-24 04:31:11 +04:00
|
|
|
const char *file;
|
|
|
|
uintN line;
|
|
|
|
JSPrincipals *principals;
|
2007-11-29 17:49:42 +03:00
|
|
|
uint32 tcflags;
|
2007-02-27 07:35:35 +03:00
|
|
|
jsint execDepth;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
- [jsemit.c] Fix horrid stupid bugs generating JSOP_ARGCNT and JSOP_ARGSUB,
where any occurrence of arguments.length or arguments[0], e.g., would be
"optimized" to use those bytecodes. This is just wrong if the occurrence
is an operand of delete, ++, --, or the left-hand-side of an assignment
operator!
- [jsfun.c, jsinterp.c] args_getProperty etc. must use JS_GetInstancePrivate,
not JS_GetPrivate, as the arguments object is exposed, and can be made a
prototype of other objects that do not have private data, or private data
that's a JSStackFrame*. Same goes for fun_getProperty, js_GetArgument, etc.
- [jsfun.c, jsobj.c, jsstr.c] No need to specialize fun_delProperty and
str_delProperty to help convince users and ECMA conformance tests that
fun.length and str.length are direct properties of instances, instead of
being delegated to Function.prototype.length and String.prototype.length.
This special case is done universally in js_DeleteProperty for all SHARED
and PERMANENT proto-properties.
- [jshash.c] Sneaking this followup-fix for bug 69271 in: use JS_HASH_BITS
rather than hardcoded 32.
- [jsobj.c, jsscope.[ch]] Fix misnamed js_HashValue (it takes a jsid, so it
is now js_HashId).
- [jsscript.c] script_compile needs to call JS_InstanceOf, to ensure that obj
is a Script object.
2001-03-22 05:52:42 +03:00
|
|
|
/* Make sure obj is a Script object. */
|
|
|
|
if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
/* If no args, leave private undefined and return early. */
|
|
|
|
if (argc == 0)
|
2001-03-06 04:56:30 +03:00
|
|
|
goto out;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
2007-01-29 07:40:34 +03:00
|
|
|
/* Otherwise, the first arg is the script source to compile. */
|
|
|
|
str = js_ValueToString(cx, argv[0]);
|
|
|
|
if (!str)
|
|
|
|
return JS_FALSE;
|
|
|
|
argv[0] = STRING_TO_JSVAL(str);
|
|
|
|
|
|
|
|
scopeobj = NULL;
|
|
|
|
if (argc >= 2) {
|
|
|
|
if (!js_ValueToObject(cx, argv[1], &scopeobj))
|
|
|
|
return JS_FALSE;
|
|
|
|
argv[1] = OBJECT_TO_JSVAL(scopeobj);
|
|
|
|
}
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
/* Compile using the caller's scope chain, which js_Invoke passes to fp. */
|
|
|
|
fp = cx->fp;
|
2003-11-02 04:04:50 +03:00
|
|
|
caller = JS_GetScriptedCaller(cx, fp);
|
|
|
|
JS_ASSERT(!caller || fp->scopeChain == caller->scopeChain);
|
1998-04-24 04:31:11 +04:00
|
|
|
|
2003-11-02 04:04:50 +03:00
|
|
|
if (caller) {
|
2006-05-21 02:27:28 +04:00
|
|
|
if (!scopeobj) {
|
|
|
|
scopeobj = js_GetScopeChain(cx, caller);
|
|
|
|
if (!scopeobj)
|
|
|
|
return JS_FALSE;
|
|
|
|
fp->scopeChain = scopeobj; /* for the compiler's benefit */
|
|
|
|
}
|
1998-04-24 04:31:11 +04:00
|
|
|
|
2003-11-02 04:04:50 +03:00
|
|
|
principals = JS_EvalFramePrincipals(cx, fp, caller);
|
2008-03-07 01:52:58 +03:00
|
|
|
file = js_ComputeFilename(cx, caller, principals, &line);
|
1998-04-24 04:31:11 +04:00
|
|
|
} else {
|
2001-03-06 04:56:30 +03:00
|
|
|
file = NULL;
|
|
|
|
line = 0;
|
|
|
|
principals = NULL;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
2005-10-08 04:28:45 +04:00
|
|
|
/* Ensure we compile this script with the right (inner) principals. */
|
2007-08-02 08:33:52 +04:00
|
|
|
scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_compile_str);
|
2005-10-08 04:28:45 +04:00
|
|
|
if (!scopeobj)
|
|
|
|
return JS_FALSE;
|
|
|
|
|
2004-08-04 21:56:31 +04:00
|
|
|
/*
|
|
|
|
* Compile the new script using the caller's scope chain, a la eval().
|
2007-11-29 17:49:42 +03:00
|
|
|
* Unlike jsobj.c:obj_eval, however, we do not pass TCF_COMPILE_N_GO in
|
|
|
|
* tcflags, because compilation is here separated from execution, and the
|
2004-08-04 21:56:31 +04:00
|
|
|
* run-time scope chain may not match the compile-time. JSFRAME_EVAL is
|
|
|
|
* tested in jsemit.c and jsscan.c to optimize based on identity of run-
|
|
|
|
* and compile-time scope.
|
|
|
|
*/
|
2005-05-12 23:34:13 +04:00
|
|
|
fp->flags |= JSFRAME_SCRIPT_OBJECT;
|
2007-11-29 17:49:42 +03:00
|
|
|
tcflags = 0;
|
|
|
|
script = js_CompileScript(cx, scopeobj, principals, tcflags,
|
|
|
|
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
|
|
|
NULL, file, line);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!script)
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
2007-02-27 07:35:35 +03:00
|
|
|
JS_LOCK_OBJ(cx, obj);
|
|
|
|
execDepth = GetScriptExecDepth(cx, obj);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* execDepth must be 0 to allow compilation here, otherwise the JSScript
|
|
|
|
* struct can be released while running.
|
|
|
|
*/
|
|
|
|
if (execDepth > 0) {
|
|
|
|
JS_UNLOCK_OBJ(cx, obj);
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
|
|
JSMSG_COMPILE_EXECED_SCRIPT);
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
2007-02-27 07:35:35 +03:00
|
|
|
|
|
|
|
/* Swap script for obj's old script, if any. */
|
|
|
|
v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
|
2007-03-02 00:30:48 +03:00
|
|
|
oldscript = !JSVAL_IS_VOID(v) ? JSVAL_TO_PRIVATE(v) : NULL;
|
2007-02-27 07:35:35 +03:00
|
|
|
LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script));
|
|
|
|
JS_UNLOCK_OBJ(cx, obj);
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
if (oldscript)
|
2001-03-06 04:56:30 +03:00
|
|
|
js_DestroyScript(cx, oldscript);
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
script->object = obj;
|
2007-02-27 07:35:35 +03:00
|
|
|
js_CallNewScriptHook(cx, script, NULL);
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
out:
|
|
|
|
/* Return the object. */
|
|
|
|
*rval = OBJECT_TO_JSVAL(obj);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2007-08-02 08:33:52 +04:00
|
|
|
script_compile(JSContext *cx, uintN argc, jsval *vp)
|
|
|
|
{
|
|
|
|
return script_compile_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|
|
|
jsval *rval)
|
1998-04-24 04:31:11 +04:00
|
|
|
{
|
2003-12-05 07:21:05 +03:00
|
|
|
JSObject *scopeobj, *parent;
|
1998-04-24 04:31:11 +04:00
|
|
|
JSStackFrame *fp, *caller;
|
2005-10-23 09:18:29 +04:00
|
|
|
JSPrincipals *principals;
|
2007-01-29 07:18:49 +03:00
|
|
|
JSScript *script;
|
2007-02-27 07:35:35 +03:00
|
|
|
JSBool ok;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
scopeobj = NULL;
|
2007-08-02 08:33:52 +04:00
|
|
|
if (argc != 0) {
|
2001-03-06 04:56:30 +03:00
|
|
|
if (!js_ValueToObject(cx, argv[0], &scopeobj))
|
|
|
|
return JS_FALSE;
|
|
|
|
argv[0] = OBJECT_TO_JSVAL(scopeobj);
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
2003-12-05 07:21:05 +03:00
|
|
|
/*
|
|
|
|
* Emulate eval() by using caller's this, var object, sharp array, etc.,
|
2003-12-10 03:24:13 +03:00
|
|
|
* all propagated by js_Execute via a non-null fourth (down) argument to
|
2003-12-05 07:21:05 +03:00
|
|
|
* js_Execute. If there is no scripted caller, js_Execute uses its second
|
2003-12-10 03:24:13 +03:00
|
|
|
* (chain) argument to set the exec frame's varobj, thisp, and scopeChain.
|
2003-12-05 07:21:05 +03:00
|
|
|
*
|
|
|
|
* Unlike eval, which the compiler detects, Script.prototype.exec may be
|
|
|
|
* called from a lightweight function, or even from native code (in which
|
2003-12-10 03:24:13 +03:00
|
|
|
* case fp->varobj and fp->scopeChain are null). If exec is called from
|
|
|
|
* a lightweight function, we will need to get a Call object representing
|
|
|
|
* its frame, to act as the var object and scope chain head.
|
2003-12-05 07:21:05 +03:00
|
|
|
*/
|
1998-04-24 04:31:11 +04:00
|
|
|
fp = cx->fp;
|
2003-11-02 04:04:50 +03:00
|
|
|
caller = JS_GetScriptedCaller(cx, fp);
|
2003-12-10 03:24:13 +03:00
|
|
|
if (caller && !caller->varobj) {
|
|
|
|
/* Called from a lightweight function. */
|
2006-07-06 22:40:03 +04:00
|
|
|
JS_ASSERT(caller->fun && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags));
|
2003-12-05 07:21:05 +03:00
|
|
|
|
2003-12-10 03:24:13 +03:00
|
|
|
/* Scope chain links from Call object to callee's parent. */
|
2007-08-02 08:33:52 +04:00
|
|
|
parent = OBJ_GET_PARENT(cx, caller->callee);
|
2003-12-10 03:24:13 +03:00
|
|
|
if (!js_GetCallObject(cx, caller, parent))
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
2003-12-05 07:21:05 +03:00
|
|
|
|
2003-12-10 03:24:13 +03:00
|
|
|
if (!scopeobj) {
|
|
|
|
/* No scope object passed in: try to use the caller's scope chain. */
|
|
|
|
if (caller) {
|
|
|
|
/*
|
|
|
|
* Load caller->scopeChain after the conditional js_GetCallObject
|
|
|
|
* call above, which resets scopeChain as well as varobj.
|
|
|
|
*/
|
2006-05-21 02:27:28 +04:00
|
|
|
scopeobj = js_GetScopeChain(cx, caller);
|
|
|
|
if (!scopeobj)
|
|
|
|
return JS_FALSE;
|
2003-12-05 07:21:05 +03:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Called from native code, so we don't know what scope object to
|
|
|
|
* use. We could use parent (see above), but Script.prototype.exec
|
|
|
|
* might be a shared/sealed "superglobal" method. A more general
|
|
|
|
* approach would use cx->globalObject, which will be the same as
|
|
|
|
* exec.__parent__ in the non-superglobal case. In the superglobal
|
|
|
|
* case it's the right object: the global, not the superglobal.
|
|
|
|
*/
|
|
|
|
scopeobj = cx->globalObject;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-02 08:33:52 +04:00
|
|
|
scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_exec_str);
|
2005-10-09 11:45:32 +04:00
|
|
|
if (!scopeobj)
|
|
|
|
return JS_FALSE;
|
|
|
|
|
2007-02-27 07:35:35 +03:00
|
|
|
/* Keep track of nesting depth for the script. */
|
|
|
|
AdjustScriptExecDepth(cx, obj, 1);
|
|
|
|
|
|
|
|
/* Must get to out label after this */
|
2007-01-29 07:18:49 +03:00
|
|
|
script = (JSScript *) JS_GetPrivate(cx, obj);
|
2007-02-27 07:35:35 +03:00
|
|
|
if (!script) {
|
|
|
|
ok = JS_FALSE;
|
|
|
|
goto out;
|
|
|
|
}
|
2007-01-29 07:18:49 +03:00
|
|
|
|
2005-04-12 05:35:05 +04:00
|
|
|
/* Belt-and-braces: check that this script object has access to scopeobj. */
|
2005-07-09 03:26:36 +04:00
|
|
|
principals = script->principals;
|
2007-02-27 07:35:35 +03:00
|
|
|
ok = js_CheckPrincipalsAccess(cx, scopeobj, principals,
|
|
|
|
CLASS_ATOM(cx, Script));
|
|
|
|
if (!ok)
|
|
|
|
goto out;
|
2005-04-12 05:35:05 +04:00
|
|
|
|
2007-02-27 07:35:35 +03:00
|
|
|
ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
|
2007-08-02 08:33:52 +04:00
|
|
|
|
2007-02-27 07:35:35 +03:00
|
|
|
out:
|
2007-08-02 08:33:52 +04:00
|
|
|
AdjustScriptExecDepth(cx, obj, -1);
|
2007-02-27 07:35:35 +03:00
|
|
|
return ok;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
2007-08-02 08:33:52 +04:00
|
|
|
static JSBool
|
|
|
|
script_exec(JSContext *cx, uintN argc, jsval *vp)
|
|
|
|
{
|
|
|
|
return script_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp);
|
|
|
|
}
|
|
|
|
|
2007-01-26 02:08:52 +03:00
|
|
|
#endif /* JS_HAS_SCRIPT_OBJECT */
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
#if JS_HAS_XDR
|
2003-07-27 02:37:11 +04:00
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
JSBool
|
1999-11-12 09:03:40 +03:00
|
|
|
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
|
1998-04-24 04:31:11 +04:00
|
|
|
{
|
2003-07-27 02:37:11 +04:00
|
|
|
JSContext *cx;
|
2007-07-08 13:03:34 +04:00
|
|
|
JSScript *script, *oldscript;
|
2008-03-23 04:11:51 +03:00
|
|
|
JSBool ok;
|
|
|
|
jsbytecode *code;
|
2008-07-21 00:13:17 +04:00
|
|
|
uint32 length, lineno, nslots, magic;
|
2008-06-11 01:44:51 +04:00
|
|
|
uint32 natoms, nsrcnotes, ntrynotes, nobjects, nregexps, i;
|
1999-11-12 09:03:40 +03:00
|
|
|
uint32 prologLength, version;
|
2008-01-31 05:19:49 +03:00
|
|
|
JSTempValueRooter tvr;
|
2007-07-08 13:03:34 +04:00
|
|
|
JSPrincipals *principals;
|
|
|
|
uint32 encodeable;
|
2003-07-27 02:37:11 +04:00
|
|
|
JSBool filenameWasSaved;
|
|
|
|
jssrcnote *notes, *sn;
|
1999-11-12 09:03:40 +03:00
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
cx = xdr->cx;
|
1999-11-12 09:03:40 +03:00
|
|
|
script = *scriptp;
|
2008-06-11 01:44:51 +04:00
|
|
|
nsrcnotes = ntrynotes = natoms = nobjects = nregexps = 0;
|
2003-07-27 02:37:11 +04:00
|
|
|
filenameWasSaved = JS_FALSE;
|
|
|
|
notes = NULL;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
if (xdr->mode == JSXDR_ENCODE)
|
1999-11-12 09:03:40 +03:00
|
|
|
magic = JSXDR_MAGIC_SCRIPT_CURRENT;
|
|
|
|
if (!JS_XDRUint32(xdr, &magic))
|
|
|
|
return JS_FALSE;
|
2007-07-08 13:03:34 +04:00
|
|
|
if (magic != JSXDR_MAGIC_SCRIPT_CURRENT) {
|
|
|
|
/* We do not provide binary compatibility with older scripts. */
|
2001-11-20 05:47:41 +03:00
|
|
|
if (!hasMagic) {
|
2003-07-27 02:37:11 +04:00
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
2001-11-20 05:47:41 +03:00
|
|
|
JSMSG_BAD_SCRIPT_MAGIC);
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
1999-11-12 09:03:40 +03:00
|
|
|
*hasMagic = JS_FALSE;
|
|
|
|
return JS_TRUE;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
2001-11-20 05:47:41 +03:00
|
|
|
if (hasMagic)
|
|
|
|
*hasMagic = JS_TRUE;
|
1999-11-12 09:03:40 +03:00
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
if (xdr->mode == JSXDR_ENCODE) {
|
1999-11-12 09:03:40 +03:00
|
|
|
length = script->length;
|
2003-07-27 02:37:11 +04:00
|
|
|
prologLength = PTRDIFF(script->main, script->code, jsbytecode);
|
2004-04-13 05:25:17 +04:00
|
|
|
JS_ASSERT((int16)script->version != JSVERSION_UNKNOWN);
|
2008-07-21 00:13:17 +04:00
|
|
|
version = (uint32)script->version | (script->nfixed << 16);
|
1999-11-12 09:03:40 +03:00
|
|
|
lineno = (uint32)script->lineno;
|
2008-07-21 00:13:17 +04:00
|
|
|
nslots = (uint32)script->nslots;
|
2007-07-08 13:03:34 +04:00
|
|
|
natoms = (uint32)script->atomMap.length;
|
1999-11-12 09:03:40 +03:00
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
/* Count the srcnotes, keeping notes pointing at the first one. */
|
|
|
|
notes = SCRIPT_NOTES(script);
|
|
|
|
for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
|
|
|
|
continue;
|
|
|
|
nsrcnotes = PTRDIFF(sn, notes, jssrcnote);
|
|
|
|
nsrcnotes++; /* room for the terminator */
|
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
if (script->objectsOffset != 0)
|
|
|
|
nobjects = JS_SCRIPT_OBJECTS(script)->length;
|
|
|
|
if (script->regexpsOffset != 0)
|
|
|
|
nregexps = JS_SCRIPT_REGEXPS(script)->length;
|
|
|
|
if (script->trynotesOffset != 0)
|
|
|
|
ntrynotes = JS_SCRIPT_TRYNOTES(script)->length;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
1999-11-12 09:03:40 +03:00
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!JS_XDRUint32(xdr, &length))
|
1999-11-12 09:03:40 +03:00
|
|
|
return JS_FALSE;
|
2007-07-08 13:03:34 +04:00
|
|
|
if (!JS_XDRUint32(xdr, &prologLength))
|
|
|
|
return JS_FALSE;
|
|
|
|
if (!JS_XDRUint32(xdr, &version))
|
|
|
|
return JS_FALSE;
|
2003-07-27 02:37:11 +04:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
/*
|
2008-06-04 01:48:47 +04:00
|
|
|
* To fuse allocations, we need srcnote, atom, objects, regexp, loop, and
|
|
|
|
* trynote counts early. The last four each use 8 bits in JSScript, so we
|
|
|
|
* compress them into a uint32 in the XDR stream.
|
2007-07-08 13:03:34 +04:00
|
|
|
*/
|
|
|
|
if (!JS_XDRUint32(xdr, &natoms))
|
|
|
|
return JS_FALSE;
|
|
|
|
if (!JS_XDRUint32(xdr, &nsrcnotes))
|
|
|
|
return JS_FALSE;
|
|
|
|
if (!JS_XDRUint32(xdr, &ntrynotes))
|
|
|
|
return JS_FALSE;
|
|
|
|
if (!JS_XDRUint32(xdr, &nobjects))
|
|
|
|
return JS_FALSE;
|
|
|
|
if (!JS_XDRUint32(xdr, &nregexps))
|
|
|
|
return JS_FALSE;
|
1999-11-12 09:03:40 +03:00
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
if (xdr->mode == JSXDR_DECODE) {
|
2008-05-29 06:07:32 +04:00
|
|
|
script = js_NewScript(cx, length, nsrcnotes, ntrynotes, natoms,
|
2008-06-11 01:44:51 +04:00
|
|
|
nobjects, nregexps);
|
1999-11-12 09:03:40 +03:00
|
|
|
if (!script)
|
|
|
|
return JS_FALSE;
|
2007-07-08 13:03:34 +04:00
|
|
|
|
|
|
|
script->main += prologLength;
|
|
|
|
script->version = (JSVersion) (version & 0xffff);
|
2008-07-21 00:13:17 +04:00
|
|
|
script->nfixed = (uint16) (version >> 16);
|
2007-07-08 13:03:34 +04:00
|
|
|
|
|
|
|
/* If we know nsrcnotes, we allocated space for notes in script. */
|
|
|
|
notes = SCRIPT_NOTES(script);
|
1999-11-12 09:03:40 +03:00
|
|
|
*scriptp = script;
|
2008-01-31 05:19:49 +03:00
|
|
|
JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr);
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
1999-11-12 09:03:40 +03:00
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
/*
|
2007-07-08 13:03:34 +04:00
|
|
|
* Control hereafter must goto error on failure, in order for the
|
|
|
|
* DECODE case to destroy script.
|
2003-07-27 02:37:11 +04:00
|
|
|
*/
|
2008-03-24 11:06:39 +03:00
|
|
|
oldscript = xdr->script;
|
2008-03-23 04:11:51 +03:00
|
|
|
code = script->code;
|
|
|
|
if (xdr->mode == JSXDR_ENCODE) {
|
2008-03-24 11:06:39 +03:00
|
|
|
code = js_UntrapScriptCode(cx, script);
|
|
|
|
if (!code)
|
|
|
|
goto error;
|
2008-03-23 04:11:51 +03:00
|
|
|
}
|
|
|
|
|
2006-08-01 02:52:27 +04:00
|
|
|
xdr->script = script;
|
2008-03-23 04:11:51 +03:00
|
|
|
ok = JS_XDRBytes(xdr, (char *) code, length * sizeof(jsbytecode));
|
|
|
|
|
|
|
|
if (code != script->code)
|
|
|
|
JS_free(cx, code);
|
|
|
|
|
|
|
|
if (!ok)
|
2003-07-27 02:37:11 +04:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) ||
|
1999-11-12 09:03:40 +03:00
|
|
|
!JS_XDRCStringOrNull(xdr, (char **)&script->filename) ||
|
|
|
|
!JS_XDRUint32(xdr, &lineno) ||
|
2008-07-21 00:13:17 +04:00
|
|
|
!JS_XDRUint32(xdr, &nslots)) {
|
1999-04-27 19:18:57 +04:00
|
|
|
goto error;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
1999-11-12 09:03:40 +03:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
if (xdr->mode == JSXDR_ENCODE) {
|
|
|
|
principals = script->principals;
|
|
|
|
encodeable = (cx->runtime->principalsTranscoder != NULL);
|
|
|
|
if (!JS_XDRUint32(xdr, &encodeable))
|
|
|
|
goto error;
|
|
|
|
if (encodeable &&
|
|
|
|
!cx->runtime->principalsTranscoder(xdr, &principals)) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!JS_XDRUint32(xdr, &encodeable))
|
|
|
|
goto error;
|
|
|
|
if (encodeable) {
|
|
|
|
if (!cx->runtime->principalsTranscoder) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
|
|
JSMSG_CANT_DECODE_PRINCIPALS);
|
2001-07-31 23:05:34 +04:00
|
|
|
goto error;
|
2001-08-09 05:15:57 +04:00
|
|
|
}
|
2007-07-08 13:03:34 +04:00
|
|
|
if (!cx->runtime->principalsTranscoder(xdr, &principals))
|
2001-07-31 23:05:34 +04:00
|
|
|
goto error;
|
2007-07-08 13:03:34 +04:00
|
|
|
script->principals = principals;
|
2001-07-31 23:05:34 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
if (xdr->mode == JSXDR_DECODE) {
|
2003-07-27 02:37:11 +04:00
|
|
|
const char *filename = script->filename;
|
|
|
|
if (filename) {
|
|
|
|
filename = js_SaveScriptFilename(cx, filename);
|
|
|
|
if (!filename)
|
|
|
|
goto error;
|
|
|
|
JS_free(cx, (void *) script->filename);
|
|
|
|
script->filename = filename;
|
|
|
|
filenameWasSaved = JS_TRUE;
|
|
|
|
}
|
1999-11-12 09:03:40 +03:00
|
|
|
script->lineno = (uintN)lineno;
|
2008-07-21 00:13:17 +04:00
|
|
|
script->nslots = (uintN)nslots;
|
2007-07-08 13:03:34 +04:00
|
|
|
}
|
2003-07-27 02:37:11 +04:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
for (i = 0; i != natoms; ++i) {
|
|
|
|
if (!js_XDRAtom(xdr, &script->atomMap.vector[i]))
|
|
|
|
goto error;
|
|
|
|
}
|
2003-07-27 02:37:11 +04:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
/*
|
|
|
|
* Here looping from 0-to-length to xdr objects is essential. It ensures
|
|
|
|
* that block objects from the script->objects will be written and
|
|
|
|
* restored in the outer-to-inner order. block_xdrObject uses this to
|
|
|
|
* restore the parent chain.
|
|
|
|
*/
|
|
|
|
for (i = 0; i != nobjects; ++i) {
|
|
|
|
if (!js_XDRObject(xdr, &JS_SCRIPT_OBJECTS(script)->vector[i]))
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
for (i = 0; i != nregexps; ++i) {
|
|
|
|
if (!js_XDRObject(xdr, &JS_SCRIPT_REGEXPS(script)->vector[i]))
|
|
|
|
goto error;
|
1999-04-27 19:18:57 +04:00
|
|
|
}
|
2003-07-27 02:37:11 +04:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
if (ntrynotes != 0) {
|
2007-05-24 11:51:46 +04:00
|
|
|
/*
|
2007-07-08 13:03:34 +04:00
|
|
|
* We combine tn->kind and tn->stackDepth when serializing as XDR is not
|
2007-05-24 11:51:46 +04:00
|
|
|
* efficient when serializing small integer types.
|
|
|
|
*/
|
2007-07-08 13:03:34 +04:00
|
|
|
JSTryNote *tn, *tnfirst;
|
|
|
|
uint32 kindAndDepth;
|
2007-05-24 11:51:46 +04:00
|
|
|
JS_STATIC_ASSERT(sizeof(tn->kind) == sizeof(uint8));
|
|
|
|
JS_STATIC_ASSERT(sizeof(tn->stackDepth) == sizeof(uint16));
|
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
tnfirst = JS_SCRIPT_TRYNOTES(script)->vector;
|
|
|
|
JS_ASSERT(JS_SCRIPT_TRYNOTES(script)->length == ntrynotes);
|
|
|
|
tn = tnfirst + ntrynotes;
|
|
|
|
do {
|
|
|
|
--tn;
|
|
|
|
if (xdr->mode == JSXDR_ENCODE) {
|
|
|
|
kindAndDepth = ((uint32)tn->kind << 16)
|
|
|
|
| (uint32)tn->stackDepth;
|
|
|
|
}
|
|
|
|
if (!JS_XDRUint32(xdr, &kindAndDepth) ||
|
|
|
|
!JS_XDRUint32(xdr, &tn->start) ||
|
|
|
|
!JS_XDRUint32(xdr, &tn->length)) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (xdr->mode == JSXDR_DECODE) {
|
|
|
|
tn->kind = (uint8)(kindAndDepth >> 16);
|
|
|
|
tn->stackDepth = (uint16)kindAndDepth;
|
|
|
|
}
|
|
|
|
} while (tn != tnfirst);
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
2006-08-01 02:52:27 +04:00
|
|
|
|
|
|
|
xdr->script = oldscript;
|
2008-01-31 05:19:49 +03:00
|
|
|
if (xdr->mode == JSXDR_DECODE)
|
|
|
|
JS_POP_TEMP_ROOT(cx, &tvr);
|
1998-04-24 04:31:11 +04:00
|
|
|
return JS_TRUE;
|
1999-11-12 09:03:40 +03:00
|
|
|
|
|
|
|
error:
|
1999-04-27 19:18:57 +04:00
|
|
|
if (xdr->mode == JSXDR_DECODE) {
|
2008-01-31 05:19:49 +03:00
|
|
|
JS_POP_TEMP_ROOT(cx, &tvr);
|
2003-07-27 02:37:11 +04:00
|
|
|
if (script->filename && !filenameWasSaved) {
|
|
|
|
JS_free(cx, (void *) script->filename);
|
|
|
|
script->filename = NULL;
|
|
|
|
}
|
|
|
|
js_DestroyScript(cx, script);
|
1999-04-27 19:18:57 +04:00
|
|
|
*scriptp = NULL;
|
|
|
|
}
|
2007-07-08 13:03:34 +04:00
|
|
|
xdr->script = oldscript;
|
1999-04-27 19:18:57 +04:00
|
|
|
return JS_FALSE;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
2007-01-26 02:08:52 +03:00
|
|
|
#if JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW
|
2003-10-08 03:02:29 +04:00
|
|
|
/*
|
|
|
|
* These cannot be exposed to web content, and chrome does not need them, so
|
2003-10-10 05:46:55 +04:00
|
|
|
* we take them out of the Mozilla client altogether. Fortunately, there is
|
|
|
|
* no way to serialize a native function (see fun_xdrObject in jsfun.c).
|
2003-10-08 03:02:29 +04:00
|
|
|
*/
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
static JSBool
|
2007-08-02 08:33:52 +04:00
|
|
|
script_freeze(JSContext *cx, uintN argc, jsval *vp)
|
1998-04-24 04:31:11 +04:00
|
|
|
{
|
2007-08-02 08:33:52 +04:00
|
|
|
JSObject *obj;
|
1998-04-24 04:31:11 +04:00
|
|
|
JSXDRState *xdr;
|
|
|
|
JSScript *script;
|
1999-11-12 09:03:40 +03:00
|
|
|
JSBool ok, hasMagic;
|
1998-04-24 04:31:11 +04:00
|
|
|
uint32 len;
|
|
|
|
void *buf;
|
|
|
|
JSString *str;
|
|
|
|
|
2008-02-18 03:12:33 +03:00
|
|
|
obj = JS_THIS_OBJECT(cx, vp);
|
2007-08-02 08:33:52 +04:00
|
|
|
if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
2000-02-04 05:01:49 +03:00
|
|
|
script = (JSScript *) JS_GetPrivate(cx, obj);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!script)
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_TRUE;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
/* create new XDR */
|
|
|
|
xdr = JS_XDRNewMem(cx, JSXDR_ENCODE);
|
|
|
|
if (!xdr)
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
/* write */
|
1999-11-12 09:03:40 +03:00
|
|
|
ok = js_XDRScript(xdr, &script, &hasMagic);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!ok)
|
2001-03-06 04:56:30 +03:00
|
|
|
goto out;
|
1999-11-12 09:03:40 +03:00
|
|
|
if (!hasMagic) {
|
2007-08-02 08:33:52 +04:00
|
|
|
*vp = JSVAL_VOID;
|
2001-03-06 04:56:30 +03:00
|
|
|
goto out;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
buf = JS_XDRMemGetData(xdr, &len);
|
|
|
|
if (!buf) {
|
2001-03-06 04:56:30 +03:00
|
|
|
ok = JS_FALSE;
|
|
|
|
goto out;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
1998-10-14 14:22:38 +04:00
|
|
|
JS_ASSERT((jsword)buf % sizeof(jschar) == 0);
|
1998-04-24 04:31:11 +04:00
|
|
|
len /= sizeof(jschar);
|
|
|
|
#if IS_BIG_ENDIAN
|
|
|
|
{
|
|
|
|
jschar *chars;
|
|
|
|
uint32 i;
|
|
|
|
|
|
|
|
/* Swap bytes in Unichars to keep frozen strings machine-independent. */
|
2007-03-08 09:25:23 +03:00
|
|
|
chars = (jschar *)buf;
|
1998-04-24 04:31:11 +04:00
|
|
|
for (i = 0; i < len; i++)
|
2001-03-06 04:56:30 +03:00
|
|
|
chars[i] = JSXDR_SWAB16(chars[i]);
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
#endif
|
2007-03-08 09:25:23 +03:00
|
|
|
str = JS_NewUCStringCopyN(cx, (jschar *)buf, len);
|
|
|
|
if (!str) {
|
|
|
|
ok = JS_FALSE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2007-08-02 08:33:52 +04:00
|
|
|
*vp = STRING_TO_JSVAL(str);
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
out:
|
|
|
|
JS_XDRDestroy(xdr);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2007-08-02 08:33:52 +04:00
|
|
|
script_thaw(JSContext *cx, uintN argc, jsval *vp)
|
1998-04-24 04:31:11 +04:00
|
|
|
{
|
2007-08-02 08:33:52 +04:00
|
|
|
JSObject *obj;
|
1998-04-24 04:31:11 +04:00
|
|
|
JSXDRState *xdr;
|
|
|
|
JSString *str;
|
|
|
|
void *buf;
|
|
|
|
uint32 len;
|
2007-02-27 07:35:35 +03:00
|
|
|
jsval v;
|
1998-04-24 04:31:11 +04:00
|
|
|
JSScript *script, *oldscript;
|
1999-11-12 09:03:40 +03:00
|
|
|
JSBool ok, hasMagic;
|
2007-05-24 01:50:43 +04:00
|
|
|
jsint execDepth;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
2008-02-18 03:12:33 +03:00
|
|
|
obj = JS_THIS_OBJECT(cx, vp);
|
2007-08-02 08:33:52 +04:00
|
|
|
if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
if (argc == 0)
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_TRUE;
|
2007-08-02 08:33:52 +04:00
|
|
|
str = js_ValueToString(cx, vp[2]);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!str)
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
2007-08-02 08:33:52 +04:00
|
|
|
vp[2] = STRING_TO_JSVAL(str);
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
/* create new XDR */
|
|
|
|
xdr = JS_XDRNewMem(cx, JSXDR_DECODE);
|
|
|
|
if (!xdr)
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
2007-08-16 10:23:06 +04:00
|
|
|
JSSTRING_CHARS_AND_LENGTH(str, buf, len);
|
1998-04-24 04:31:11 +04:00
|
|
|
#if IS_BIG_ENDIAN
|
|
|
|
{
|
|
|
|
jschar *from, *to;
|
|
|
|
uint32 i;
|
|
|
|
|
|
|
|
/* Swap bytes in Unichars to keep frozen strings machine-independent. */
|
|
|
|
from = (jschar *)buf;
|
2000-02-04 05:01:49 +03:00
|
|
|
to = (jschar *) JS_malloc(cx, len * sizeof(jschar));
|
2000-12-06 09:53:33 +03:00
|
|
|
if (!to) {
|
|
|
|
JS_XDRDestroy(xdr);
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
1998-04-24 04:31:11 +04:00
|
|
|
for (i = 0; i < len; i++)
|
2001-03-06 04:56:30 +03:00
|
|
|
to[i] = JSXDR_SWAB16(from[i]);
|
1998-04-24 04:31:11 +04:00
|
|
|
buf = (char *)to;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
len *= sizeof(jschar);
|
|
|
|
JS_XDRMemSetData(xdr, buf, len);
|
|
|
|
|
|
|
|
/* XXXbe should magic mismatch be error, or false return value? */
|
1999-11-12 09:03:40 +03:00
|
|
|
ok = js_XDRScript(xdr, &script, &hasMagic);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!ok)
|
2001-03-06 04:56:30 +03:00
|
|
|
goto out;
|
1999-11-12 09:03:40 +03:00
|
|
|
if (!hasMagic) {
|
2007-08-02 08:33:52 +04:00
|
|
|
*vp = JSVAL_FALSE;
|
2001-03-06 04:56:30 +03:00
|
|
|
goto out;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
2007-02-27 07:35:35 +03:00
|
|
|
JS_LOCK_OBJ(cx, obj);
|
|
|
|
execDepth = GetScriptExecDepth(cx, obj);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* execDepth must be 0 to allow compilation here, otherwise the JSScript
|
|
|
|
* struct can be released while running.
|
|
|
|
*/
|
|
|
|
if (execDepth > 0) {
|
|
|
|
JS_UNLOCK_OBJ(cx, obj);
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
|
|
JSMSG_COMPILE_EXECED_SCRIPT);
|
2001-03-06 04:56:30 +03:00
|
|
|
goto out;
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
2007-02-27 07:35:35 +03:00
|
|
|
|
|
|
|
/* Swap script for obj's old script, if any. */
|
2007-03-02 00:30:48 +03:00
|
|
|
v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
|
|
|
|
oldscript = !JSVAL_IS_VOID(v) ? JSVAL_TO_PRIVATE(v) : NULL;
|
2007-05-24 02:09:52 +04:00
|
|
|
LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script));
|
2007-02-27 07:35:35 +03:00
|
|
|
JS_UNLOCK_OBJ(cx, obj);
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
if (oldscript)
|
2001-03-06 04:56:30 +03:00
|
|
|
js_DestroyScript(cx, oldscript);
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
script->object = obj;
|
2001-11-20 05:47:41 +03:00
|
|
|
js_CallNewScriptHook(cx, script, NULL);
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
out:
|
|
|
|
/*
|
|
|
|
* We reset the buffer to be NULL so that it doesn't free the chars
|
2007-08-02 08:33:52 +04:00
|
|
|
* memory owned by str (vp[2]).
|
1998-04-24 04:31:11 +04:00
|
|
|
*/
|
|
|
|
JS_XDRMemSetData(xdr, NULL, 0);
|
|
|
|
JS_XDRDestroy(xdr);
|
|
|
|
#if IS_BIG_ENDIAN
|
|
|
|
JS_free(cx, buf);
|
|
|
|
#endif
|
2007-08-02 08:33:52 +04:00
|
|
|
*vp = JSVAL_TRUE;
|
1998-04-24 04:31:11 +04:00
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
static const char js_thaw_str[] = "thaw";
|
1998-04-24 04:31:11 +04:00
|
|
|
|
2007-01-26 02:08:52 +03:00
|
|
|
#endif /* JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW */
|
2003-10-08 03:02:29 +04:00
|
|
|
#endif /* JS_HAS_XDR */
|
|
|
|
|
2007-01-26 02:08:52 +03:00
|
|
|
#if JS_HAS_SCRIPT_OBJECT
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
static JSFunctionSpec script_methods[] = {
|
|
|
|
#if JS_HAS_TOSOURCE
|
2007-10-14 00:09:48 +04:00
|
|
|
JS_FN(js_toSource_str, script_toSource, 0,0,0),
|
1998-04-24 04:31:11 +04:00
|
|
|
#endif
|
2007-10-14 00:09:48 +04:00
|
|
|
JS_FN(js_toString_str, script_toString, 0,0,0),
|
|
|
|
JS_FN("compile", script_compile, 0,2,0),
|
|
|
|
JS_FN("exec", script_exec, 0,1,0),
|
2003-10-11 22:17:53 +04:00
|
|
|
#if JS_HAS_XDR_FREEZE_THAW
|
2007-10-14 00:09:48 +04:00
|
|
|
JS_FN("freeze", script_freeze, 0,0,0),
|
|
|
|
JS_FN(js_thaw_str, script_thaw, 0,1,0),
|
2003-10-11 22:17:53 +04:00
|
|
|
#endif /* JS_HAS_XDR_FREEZE_THAW */
|
2007-08-02 08:33:52 +04:00
|
|
|
JS_FS_END
|
1998-04-24 04:31:11 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* JS_HAS_SCRIPT_OBJECT */
|
|
|
|
|
|
|
|
static void
|
|
|
|
script_finalize(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
JSScript *script;
|
|
|
|
|
2000-02-04 05:01:49 +03:00
|
|
|
script = (JSScript *) JS_GetPrivate(cx, obj);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (script)
|
2001-03-06 04:56:30 +03:00
|
|
|
js_DestroyScript(cx, script);
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
script_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
2000-02-02 04:10:31 +03:00
|
|
|
#if JS_HAS_SCRIPT_OBJECT
|
2007-08-02 08:33:52 +04:00
|
|
|
return script_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval);
|
2000-02-02 04:10:31 +03:00
|
|
|
#else
|
|
|
|
return JS_FALSE;
|
|
|
|
#endif
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
2007-04-17 10:53:37 +04:00
|
|
|
static void
|
|
|
|
script_trace(JSTracer *trc, JSObject *obj)
|
2000-08-26 06:30:22 +04:00
|
|
|
{
|
|
|
|
JSScript *script;
|
|
|
|
|
2007-04-17 10:53:37 +04:00
|
|
|
script = (JSScript *) JS_GetPrivate(trc->context, obj);
|
2000-08-26 06:30:22 +04:00
|
|
|
if (script)
|
2007-04-17 10:53:37 +04:00
|
|
|
js_TraceScript(trc, script);
|
2000-08-26 06:30:22 +04:00
|
|
|
}
|
|
|
|
|
2006-05-21 02:27:28 +04:00
|
|
|
#if !JS_HAS_SCRIPT_OBJECT
|
|
|
|
#define JSProto_Script JSProto_Object
|
|
|
|
#endif
|
|
|
|
|
1999-11-12 09:03:40 +03:00
|
|
|
JS_FRIEND_DATA(JSClass) js_ScriptClass = {
|
2000-08-19 23:17:32 +04:00
|
|
|
js_Script_str,
|
2007-04-17 10:53:37 +04:00
|
|
|
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
|
|
|
|
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Script),
|
1998-04-24 04:31:11 +04:00
|
|
|
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
|
|
|
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, script_finalize,
|
|
|
|
NULL, NULL, script_call, NULL,/*XXXbe xdr*/
|
2007-04-17 10:53:37 +04:00
|
|
|
NULL, NULL, JS_CLASS_TRACE(script_trace), NULL
|
1998-04-24 04:31:11 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
#if JS_HAS_SCRIPT_OBJECT
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
/* If not constructing, replace obj with a new Script object. */
|
Fix for bug 99663 (for loop resolves properties of the object being enumerated
with JSRESOLVE_ASSIGNING, wrongly), plus a few miscellaneous bugfixes.
- Combine the JSStackFrame members constructing, special, overrides, and
reserved into a uint32 flags member.
- Separate JOF_ASSIGNING from the JOF_SET bytecode format flag, and impute
JSRESOLVE_ASSIGNING from the presence of JOF_ASSIGNING among the current
opcode's format flags. To handle the for-in loop opcodes, which do more
than simply assign -- in particular, they do property lookups whose resolve
hook outcalls should not be flagged with JSRESOLVE_ASSIGNING -- a new frame
flag, JSFRAME_ASSIGNING, has been added.
- Fix interpreter version selection to respect JS_SetVersion, whose effect on
cx->version is "sticky".
- Fix js_DecompileValueGenerator to deal with JSOP_ENUMELEM -- it never had,
as this testcase shows (it crashes without this patch):
version(120);
eval("function fe(s) { for (it[s] in this); }");
try { fe('rdonly'); } catch (e) { print(e); }
2001-10-03 10:39:30 +04:00
|
|
|
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
|
2008-03-29 13:34:29 +03:00
|
|
|
obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
|
2001-03-06 04:56:30 +03:00
|
|
|
if (!obj)
|
|
|
|
return JS_FALSE;
|
2006-05-23 11:54:17 +04:00
|
|
|
|
|
|
|
/*
|
2007-08-02 08:33:52 +04:00
|
|
|
* script_compile_sub does not use rval to root its temporaries so we
|
|
|
|
* can use it to root obj.
|
2006-05-23 11:54:17 +04:00
|
|
|
*/
|
|
|
|
*rval = OBJECT_TO_JSVAL(obj);
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
2007-02-27 07:35:35 +03:00
|
|
|
|
|
|
|
if (!JS_SetReservedSlot(cx, obj, 0, INT_TO_JSVAL(0)))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
2007-08-02 08:33:52 +04:00
|
|
|
return script_compile_sub(cx, obj, argc, argv, rval);
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
2007-01-26 02:08:52 +03:00
|
|
|
#if JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
static JSBool
|
2007-08-02 08:33:52 +04:00
|
|
|
script_static_thaw(JSContext *cx, uintN argc, jsval *vp)
|
1998-04-24 04:31:11 +04:00
|
|
|
{
|
2007-08-02 08:33:52 +04:00
|
|
|
JSObject *obj;
|
|
|
|
|
2008-03-29 13:34:29 +03:00
|
|
|
obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!obj)
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
2007-08-02 08:33:52 +04:00
|
|
|
vp[1] = OBJECT_TO_JSVAL(obj);
|
|
|
|
if (!script_thaw(cx, vp))
|
2001-03-06 04:56:30 +03:00
|
|
|
return JS_FALSE;
|
2007-08-02 08:33:52 +04:00
|
|
|
*vp = OBJECT_TO_JSVAL(obj);
|
1998-04-24 04:31:11 +04:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSFunctionSpec script_static_methods[] = {
|
2007-10-14 00:09:48 +04:00
|
|
|
JS_FN(js_thaw_str, script_static_thaw, 1,1,0),
|
2007-08-02 08:33:52 +04:00
|
|
|
JS_FS_END
|
1998-04-24 04:31:11 +04:00
|
|
|
};
|
|
|
|
|
2007-01-26 02:08:52 +03:00
|
|
|
#else /* !JS_HAS_SCRIPT_OBJECT || !JS_HAS_XDR_FREEZE_THAW */
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
#define script_static_methods NULL
|
|
|
|
|
2007-01-26 02:08:52 +03:00
|
|
|
#endif /* !JS_HAS_SCRIPT_OBJECT || !JS_HAS_XDR_FREEZE_THAW */
|
1998-04-24 04:31:11 +04:00
|
|
|
|
|
|
|
JSObject *
|
|
|
|
js_InitScriptClass(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
return JS_InitClass(cx, obj, NULL, &js_ScriptClass, Script, 1,
|
2001-03-06 04:56:30 +03:00
|
|
|
NULL, script_methods, NULL, script_static_methods);
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* JS_HAS_SCRIPT_OBJECT */
|
1998-03-28 05:44:41 +03:00
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
/*
|
|
|
|
* Shared script filename management.
|
|
|
|
*/
|
|
|
|
JS_STATIC_DLL_CALLBACK(int)
|
|
|
|
js_compare_strings(const void *k1, const void *k2)
|
1998-03-28 05:44:41 +03:00
|
|
|
{
|
2007-07-06 00:37:47 +04:00
|
|
|
return strcmp((const char *) k1, (const char *) k2) == 0;
|
2003-07-27 02:37:11 +04:00
|
|
|
}
|
1998-03-28 05:44:41 +03:00
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
/* NB: This struct overlays JSHashEntry -- see jshash.h, do not reorganize. */
|
|
|
|
typedef struct ScriptFilenameEntry {
|
|
|
|
JSHashEntry *next; /* hash chain linkage */
|
|
|
|
JSHashNumber keyHash; /* key hash function result */
|
|
|
|
const void *key; /* ptr to filename, below */
|
2005-05-20 07:12:22 +04:00
|
|
|
uint32 flags; /* user-defined filename prefix flags */
|
|
|
|
JSPackedBool mark; /* GC mark flag */
|
2003-07-27 02:37:11 +04:00
|
|
|
char filename[3]; /* two or more bytes, NUL-terminated */
|
|
|
|
} ScriptFilenameEntry;
|
|
|
|
|
2007-08-12 00:25:16 +04:00
|
|
|
JS_STATIC_DLL_CALLBACK(void *)
|
|
|
|
js_alloc_table_space(void *priv, size_t size)
|
|
|
|
{
|
|
|
|
return malloc(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(void)
|
|
|
|
js_free_table_space(void *priv, void *item)
|
|
|
|
{
|
|
|
|
free(item);
|
|
|
|
}
|
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
JS_STATIC_DLL_CALLBACK(JSHashEntry *)
|
2004-06-20 06:29:19 +04:00
|
|
|
js_alloc_sftbl_entry(void *priv, const void *key)
|
2003-07-27 02:37:11 +04:00
|
|
|
{
|
2007-07-06 00:37:47 +04:00
|
|
|
size_t nbytes = offsetof(ScriptFilenameEntry, filename) +
|
|
|
|
strlen((const char *) key) + 1;
|
2003-10-27 22:13:01 +03:00
|
|
|
|
|
|
|
return (JSHashEntry *) malloc(JS_MAX(nbytes, sizeof(JSHashEntry)));
|
2003-07-27 02:37:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(void)
|
2004-06-20 06:29:19 +04:00
|
|
|
js_free_sftbl_entry(void *priv, JSHashEntry *he, uintN flag)
|
2003-07-27 02:37:11 +04:00
|
|
|
{
|
|
|
|
if (flag != HT_FREE_ENTRY)
|
|
|
|
return;
|
|
|
|
free(he);
|
|
|
|
}
|
|
|
|
|
2004-10-05 14:19:07 +04:00
|
|
|
static JSHashAllocOps sftbl_alloc_ops = {
|
2003-07-27 02:37:11 +04:00
|
|
|
js_alloc_table_space, js_free_table_space,
|
2004-06-20 06:29:19 +04:00
|
|
|
js_alloc_sftbl_entry, js_free_sftbl_entry
|
2003-07-27 02:37:11 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
JSBool
|
2005-05-20 07:12:22 +04:00
|
|
|
js_InitRuntimeScriptState(JSRuntime *rt)
|
2003-07-27 02:37:11 +04:00
|
|
|
{
|
|
|
|
#ifdef JS_THREADSAFE
|
2004-10-05 14:19:07 +04:00
|
|
|
JS_ASSERT(!rt->scriptFilenameTableLock);
|
|
|
|
rt->scriptFilenameTableLock = JS_NEW_LOCK();
|
|
|
|
if (!rt->scriptFilenameTableLock)
|
|
|
|
return JS_FALSE;
|
2003-07-27 02:37:11 +04:00
|
|
|
#endif
|
2004-10-05 14:19:07 +04:00
|
|
|
JS_ASSERT(!rt->scriptFilenameTable);
|
|
|
|
rt->scriptFilenameTable =
|
|
|
|
JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL,
|
|
|
|
&sftbl_alloc_ops, NULL);
|
2004-02-22 06:21:15 +03:00
|
|
|
if (!rt->scriptFilenameTable) {
|
2005-05-20 07:12:22 +04:00
|
|
|
js_FinishRuntimeScriptState(rt); /* free lock if threadsafe */
|
2004-10-05 14:19:07 +04:00
|
|
|
return JS_FALSE;
|
2003-07-27 02:37:11 +04:00
|
|
|
}
|
2005-05-20 07:12:22 +04:00
|
|
|
JS_INIT_CLIST(&rt->scriptFilenamePrefixes);
|
2003-07-27 02:37:11 +04:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2005-05-20 07:12:22 +04:00
|
|
|
typedef struct ScriptFilenamePrefix {
|
|
|
|
JSCList links; /* circular list linkage for easy deletion */
|
|
|
|
const char *name; /* pointer to pinned ScriptFilenameEntry string */
|
|
|
|
size_t length; /* prefix string length, precomputed */
|
|
|
|
uint32 flags; /* user-defined flags to inherit from this prefix */
|
|
|
|
} ScriptFilenamePrefix;
|
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
void
|
2005-05-20 07:12:22 +04:00
|
|
|
js_FinishRuntimeScriptState(JSRuntime *rt)
|
2003-07-27 02:37:11 +04:00
|
|
|
{
|
2004-02-22 06:21:15 +03:00
|
|
|
if (rt->scriptFilenameTable) {
|
|
|
|
JS_HashTableDestroy(rt->scriptFilenameTable);
|
|
|
|
rt->scriptFilenameTable = NULL;
|
2003-07-27 02:37:11 +04:00
|
|
|
}
|
|
|
|
#ifdef JS_THREADSAFE
|
2004-02-22 06:21:15 +03:00
|
|
|
if (rt->scriptFilenameTableLock) {
|
|
|
|
JS_DESTROY_LOCK(rt->scriptFilenameTableLock);
|
|
|
|
rt->scriptFilenameTableLock = NULL;
|
2003-07-27 02:37:11 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-05-20 07:12:22 +04:00
|
|
|
void
|
|
|
|
js_FreeRuntimeScriptState(JSRuntime *rt)
|
|
|
|
{
|
|
|
|
ScriptFilenamePrefix *sfp;
|
|
|
|
|
2006-07-21 06:17:22 +04:00
|
|
|
if (!rt->scriptFilenameTable)
|
|
|
|
return;
|
|
|
|
|
2005-05-20 07:12:22 +04:00
|
|
|
while (!JS_CLIST_IS_EMPTY(&rt->scriptFilenamePrefixes)) {
|
|
|
|
sfp = (ScriptFilenamePrefix *) rt->scriptFilenamePrefixes.next;
|
|
|
|
JS_REMOVE_LINK(&sfp->links);
|
|
|
|
free(sfp);
|
|
|
|
}
|
|
|
|
js_FinishRuntimeScriptState(rt);
|
|
|
|
}
|
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
#ifdef DEBUG_brendan
|
2006-02-09 09:02:02 +03:00
|
|
|
#define DEBUG_SFTBL
|
|
|
|
#endif
|
|
|
|
#ifdef DEBUG_SFTBL
|
2004-06-20 06:29:19 +04:00
|
|
|
size_t sftbl_savings = 0;
|
2003-07-27 02:37:11 +04:00
|
|
|
#endif
|
|
|
|
|
2005-05-20 07:12:22 +04:00
|
|
|
static ScriptFilenameEntry *
|
|
|
|
SaveScriptFilename(JSRuntime *rt, const char *filename, uint32 flags)
|
2003-07-27 02:37:11 +04:00
|
|
|
{
|
|
|
|
JSHashTable *table;
|
|
|
|
JSHashNumber hash;
|
|
|
|
JSHashEntry **hep;
|
|
|
|
ScriptFilenameEntry *sfe;
|
2005-05-20 07:12:22 +04:00
|
|
|
size_t length;
|
|
|
|
JSCList *head, *link;
|
|
|
|
ScriptFilenamePrefix *sfp;
|
2003-07-27 02:37:11 +04:00
|
|
|
|
2004-02-22 06:21:15 +03:00
|
|
|
table = rt->scriptFilenameTable;
|
2003-07-27 02:37:11 +04:00
|
|
|
hash = JS_HashString(filename);
|
|
|
|
hep = JS_HashTableRawLookup(table, hash, filename);
|
|
|
|
sfe = (ScriptFilenameEntry *) *hep;
|
2006-02-09 09:02:02 +03:00
|
|
|
#ifdef DEBUG_SFTBL
|
2003-07-27 02:37:11 +04:00
|
|
|
if (sfe)
|
2004-06-20 06:29:19 +04:00
|
|
|
sftbl_savings += strlen(sfe->filename);
|
2003-07-27 02:37:11 +04:00
|
|
|
#endif
|
2005-05-20 07:12:22 +04:00
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
if (!sfe) {
|
|
|
|
sfe = (ScriptFilenameEntry *)
|
|
|
|
JS_HashTableRawAdd(table, hep, hash, filename, NULL);
|
2005-05-20 07:12:22 +04:00
|
|
|
if (!sfe)
|
|
|
|
return NULL;
|
|
|
|
sfe->key = strcpy(sfe->filename, filename);
|
|
|
|
sfe->flags = 0;
|
|
|
|
sfe->mark = JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If saving a prefix, add it to the set in rt->scriptFilenamePrefixes. */
|
|
|
|
if (flags != 0) {
|
|
|
|
/* Search in case filename was saved already; we must be idempotent. */
|
|
|
|
sfp = NULL;
|
|
|
|
length = strlen(filename);
|
|
|
|
for (head = link = &rt->scriptFilenamePrefixes;
|
|
|
|
link->next != head;
|
|
|
|
link = link->next) {
|
|
|
|
/* Lag link behind sfp to insert in non-increasing length order. */
|
|
|
|
sfp = (ScriptFilenamePrefix *) link->next;
|
|
|
|
if (!strcmp(sfp->name, filename))
|
|
|
|
break;
|
|
|
|
if (sfp->length <= length) {
|
|
|
|
sfp = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
sfp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sfp) {
|
|
|
|
/* No such prefix: add one now. */
|
|
|
|
sfp = (ScriptFilenamePrefix *) malloc(sizeof(ScriptFilenamePrefix));
|
|
|
|
if (!sfp)
|
|
|
|
return NULL;
|
|
|
|
JS_INSERT_AFTER(&sfp->links, link);
|
|
|
|
sfp->name = sfe->filename;
|
|
|
|
sfp->length = length;
|
|
|
|
sfp->flags = 0;
|
2003-12-30 10:54:09 +03:00
|
|
|
}
|
2005-05-20 07:12:22 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Accumulate flags in both sfe and sfp: sfe for later access from the
|
|
|
|
* JS_GetScriptedCallerFilenameFlags debug-API, and sfp so that longer
|
|
|
|
* filename entries can inherit by prefix.
|
|
|
|
*/
|
|
|
|
sfe->flags |= flags;
|
|
|
|
sfp->flags |= flags;
|
2003-07-27 02:37:11 +04:00
|
|
|
}
|
2005-05-20 07:12:22 +04:00
|
|
|
|
|
|
|
return sfe;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
js_SaveScriptFilename(JSContext *cx, const char *filename)
|
|
|
|
{
|
|
|
|
JSRuntime *rt;
|
|
|
|
ScriptFilenameEntry *sfe;
|
|
|
|
JSCList *head, *link;
|
|
|
|
ScriptFilenamePrefix *sfp;
|
|
|
|
|
|
|
|
rt = cx->runtime;
|
|
|
|
JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock);
|
|
|
|
sfe = SaveScriptFilename(rt, filename, 0);
|
2003-12-30 10:54:09 +03:00
|
|
|
if (!sfe) {
|
2005-05-20 07:12:22 +04:00
|
|
|
JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
|
2003-12-30 10:54:09 +03:00
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-05-20 07:12:22 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Try to inherit flags by prefix. We assume there won't be more than a
|
|
|
|
* few (dozen! ;-) prefixes, so linear search is tolerable.
|
|
|
|
* XXXbe every time I've assumed that in the JS engine, I've been wrong!
|
|
|
|
*/
|
|
|
|
for (head = &rt->scriptFilenamePrefixes, link = head->next;
|
|
|
|
link != head;
|
|
|
|
link = link->next) {
|
|
|
|
sfp = (ScriptFilenamePrefix *) link;
|
|
|
|
if (!strncmp(sfp->name, filename, sfp->length)) {
|
|
|
|
sfe->flags |= sfp->flags;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
|
2003-12-30 10:54:09 +03:00
|
|
|
return sfe->filename;
|
2003-07-27 02:37:11 +04:00
|
|
|
}
|
|
|
|
|
2005-05-20 07:12:22 +04:00
|
|
|
const char *
|
|
|
|
js_SaveScriptFilenameRT(JSRuntime *rt, const char *filename, uint32 flags)
|
|
|
|
{
|
|
|
|
ScriptFilenameEntry *sfe;
|
|
|
|
|
|
|
|
/* This may be called very early, via the jsdbgapi.h entry point. */
|
|
|
|
if (!rt->scriptFilenameTable && !js_InitRuntimeScriptState(rt))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock);
|
|
|
|
sfe = SaveScriptFilename(rt, filename, flags);
|
|
|
|
JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
|
|
|
|
if (!sfe)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return sfe->filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Back up from a saved filename by its offset within its hash table entry.
|
|
|
|
*/
|
|
|
|
#define FILENAME_TO_SFE(fn) \
|
|
|
|
((ScriptFilenameEntry *) ((fn) - offsetof(ScriptFilenameEntry, filename)))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The sfe->key member, redundant given sfe->filename but required by the old
|
|
|
|
* jshash.c code, here gives us a useful sanity check. This assertion will
|
|
|
|
* very likely botch if someone tries to mark a string that wasn't allocated
|
|
|
|
* as an sfe->filename.
|
|
|
|
*/
|
|
|
|
#define ASSERT_VALID_SFE(sfe) JS_ASSERT((sfe)->key == (sfe)->filename)
|
|
|
|
|
|
|
|
uint32
|
|
|
|
js_GetScriptFilenameFlags(const char *filename)
|
|
|
|
{
|
|
|
|
ScriptFilenameEntry *sfe;
|
|
|
|
|
|
|
|
sfe = FILENAME_TO_SFE(filename);
|
|
|
|
ASSERT_VALID_SFE(sfe);
|
|
|
|
return sfe->flags;
|
|
|
|
}
|
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
void
|
|
|
|
js_MarkScriptFilename(const char *filename)
|
|
|
|
{
|
|
|
|
ScriptFilenameEntry *sfe;
|
|
|
|
|
2005-05-20 07:12:22 +04:00
|
|
|
sfe = FILENAME_TO_SFE(filename);
|
|
|
|
ASSERT_VALID_SFE(sfe);
|
2003-07-27 02:37:11 +04:00
|
|
|
sfe->mark = JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2006-07-28 17:23:09 +04:00
|
|
|
JS_STATIC_DLL_CALLBACK(intN)
|
|
|
|
js_script_filename_marker(JSHashEntry *he, intN i, void *arg)
|
|
|
|
{
|
|
|
|
ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he;
|
|
|
|
|
|
|
|
sfe->mark = JS_TRUE;
|
|
|
|
return HT_ENUMERATE_NEXT;
|
|
|
|
}
|
|
|
|
|
2005-05-05 04:47:50 +04:00
|
|
|
void
|
2006-08-06 13:23:26 +04:00
|
|
|
js_MarkScriptFilenames(JSRuntime *rt, JSBool keepAtoms)
|
2005-05-05 04:47:50 +04:00
|
|
|
{
|
2005-05-20 07:12:22 +04:00
|
|
|
JSCList *head, *link;
|
|
|
|
ScriptFilenamePrefix *sfp;
|
|
|
|
|
2006-07-28 17:23:09 +04:00
|
|
|
if (!rt->scriptFilenameTable)
|
2006-06-20 22:36:34 +04:00
|
|
|
return;
|
|
|
|
|
2006-08-06 13:23:26 +04:00
|
|
|
if (keepAtoms) {
|
2006-07-28 17:23:09 +04:00
|
|
|
JS_HashTableEnumerateEntries(rt->scriptFilenameTable,
|
|
|
|
js_script_filename_marker,
|
|
|
|
rt);
|
|
|
|
}
|
2005-05-20 07:12:22 +04:00
|
|
|
for (head = &rt->scriptFilenamePrefixes, link = head->next;
|
|
|
|
link != head;
|
|
|
|
link = link->next) {
|
|
|
|
sfp = (ScriptFilenamePrefix *) link;
|
|
|
|
js_MarkScriptFilename(sfp->name);
|
|
|
|
}
|
2005-05-05 04:47:50 +04:00
|
|
|
}
|
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
JS_STATIC_DLL_CALLBACK(intN)
|
|
|
|
js_script_filename_sweeper(JSHashEntry *he, intN i, void *arg)
|
|
|
|
{
|
|
|
|
ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he;
|
|
|
|
|
|
|
|
if (!sfe->mark)
|
|
|
|
return HT_ENUMERATE_REMOVE;
|
|
|
|
sfe->mark = JS_FALSE;
|
|
|
|
return HT_ENUMERATE_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-07-28 17:23:09 +04:00
|
|
|
js_SweepScriptFilenames(JSRuntime *rt)
|
2003-07-27 02:37:11 +04:00
|
|
|
{
|
2006-07-28 17:23:09 +04:00
|
|
|
if (!rt->scriptFilenameTable)
|
2006-06-24 14:48:56 +04:00
|
|
|
return;
|
|
|
|
|
2004-02-22 06:21:15 +03:00
|
|
|
JS_HashTableEnumerateEntries(rt->scriptFilenameTable,
|
2003-07-27 02:37:11 +04:00
|
|
|
js_script_filename_sweeper,
|
|
|
|
rt);
|
2004-12-15 05:59:00 +03:00
|
|
|
#ifdef DEBUG_notme
|
2006-02-09 09:02:02 +03:00
|
|
|
#ifdef DEBUG_SFTBL
|
2004-06-20 06:29:19 +04:00
|
|
|
printf("script filename table savings so far: %u\n", sftbl_savings);
|
2003-07-27 02:37:11 +04:00
|
|
|
#endif
|
2006-02-09 09:02:02 +03:00
|
|
|
#endif
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
/*
|
|
|
|
* JSScript data structures memory alignment:
|
|
|
|
*
|
|
|
|
* JSScript
|
|
|
|
* JSObjectArray script objects' descriptor if JSScript.objectsOffset != 0,
|
|
|
|
* use JS_SCRIPT_OBJECTS(script) macro to access it.
|
|
|
|
* JSObjectArray script regexps' descriptor if JSScript.regexpsOffset != 0,
|
|
|
|
* use JS_SCRIPT_REGEXPS(script) macro to access it.
|
|
|
|
* JSTryNoteArray script try notes' descriptor if JSScript.tryNotesOffset
|
|
|
|
* != 0, use JS_SCRIPT_TRYNOTES(script) macro to access it.
|
|
|
|
* JSAtom *a[] array of JSScript.atomMap.length atoms pointed by
|
|
|
|
* JSScript.atomMap.vector if any.
|
|
|
|
* JSObject *o[] array of JS_SCRIPT_OBJECTS(script)->length objects if any
|
|
|
|
* pointed by JS_SCRIPT_OBJECTS(script)->vector.
|
|
|
|
* JSObject *r[] array of JS_SCRIPT_REGEXPS(script)->length regexps if any
|
|
|
|
* pointed by JS_SCRIPT_REGEXPS(script)->vector.
|
|
|
|
* JSTryNote t[] array of JS_SCRIPT_TRYNOTES(script)->length try notes if any
|
|
|
|
* pointed by JS_SCRIPT_TRYNOTES(script)->vector.
|
|
|
|
* jsbytecode b[] script bytecode pointed by JSScript.code.
|
|
|
|
* jssrcnote s[] script source notes, use SCRIPT_NOTES(script) to access it
|
|
|
|
*
|
|
|
|
* The alignment avoids gaps between entries as alignment requirement for each
|
|
|
|
* subsequent structure or array is the same or divides the alignment
|
|
|
|
* requirement for the previous one.
|
|
|
|
*
|
|
|
|
* The followings asserts checks that assuming that the alignment requirement
|
|
|
|
* for JSObjectArray and JSTryNoteArray are sizeof(void *) and for JSTryNote
|
|
|
|
* it is sizeof(uint32) as the structure consists of 3 uint32 fields.
|
|
|
|
*/
|
|
|
|
JS_STATIC_ASSERT(sizeof(JSScript) % sizeof(void *) == 0);
|
|
|
|
JS_STATIC_ASSERT(sizeof(JSObjectArray) % sizeof(void *) == 0);
|
|
|
|
JS_STATIC_ASSERT(sizeof(JSTryNoteArray) == sizeof(JSObjectArray));
|
|
|
|
JS_STATIC_ASSERT(sizeof(JSAtom *) == sizeof(JSObject *));
|
|
|
|
JS_STATIC_ASSERT(sizeof(JSObject *) % sizeof(uint32) == 0);
|
|
|
|
JS_STATIC_ASSERT(sizeof(JSTryNote) == 3 * sizeof(uint32));
|
|
|
|
JS_STATIC_ASSERT(sizeof(uint32) % sizeof(jsbytecode) == 0);
|
|
|
|
JS_STATIC_ASSERT(sizeof(jsbytecode) % sizeof(jssrcnote) == 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that uint8 offset for object, regexp and try note arrays is sufficient.
|
|
|
|
*/
|
|
|
|
JS_STATIC_ASSERT(sizeof(JSScript) + 2 * sizeof(JSObjectArray) < JS_BIT(8));
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
JSScript *
|
2008-05-29 06:07:32 +04:00
|
|
|
js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 ntrynotes,
|
2008-06-11 01:44:51 +04:00
|
|
|
uint32 natoms, uint32 nobjects, uint32 nregexps)
|
1998-04-24 04:31:11 +04:00
|
|
|
{
|
2007-07-08 13:03:34 +04:00
|
|
|
size_t size, vectorSize;
|
1998-04-24 04:31:11 +04:00
|
|
|
JSScript *script;
|
2007-07-08 13:03:34 +04:00
|
|
|
uint8 *cursor;
|
1998-04-24 04:31:11 +04:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
size = sizeof(JSScript) +
|
|
|
|
sizeof(JSAtom *) * natoms +
|
|
|
|
length * sizeof(jsbytecode) +
|
|
|
|
nsrcnotes * sizeof(jssrcnote);
|
|
|
|
if (nobjects != 0)
|
|
|
|
size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *);
|
|
|
|
if (nregexps != 0)
|
|
|
|
size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *);
|
|
|
|
if (ntrynotes != 0)
|
|
|
|
size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote);
|
|
|
|
|
|
|
|
script = (JSScript *) JS_malloc(cx, size);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!script)
|
2001-03-06 04:56:30 +03:00
|
|
|
return NULL;
|
2003-07-27 02:37:11 +04:00
|
|
|
memset(script, 0, sizeof(JSScript));
|
|
|
|
script->length = length;
|
|
|
|
script->version = cx->version;
|
2007-07-08 13:03:34 +04:00
|
|
|
|
|
|
|
cursor = (uint8 *)script + sizeof(JSScript);
|
|
|
|
if (nobjects != 0) {
|
|
|
|
script->objectsOffset = (uint8)(cursor - (uint8 *)script);
|
|
|
|
cursor += sizeof(JSObjectArray);
|
|
|
|
}
|
|
|
|
if (nregexps != 0) {
|
|
|
|
script->regexpsOffset = (uint8)(cursor - (uint8 *)script);
|
|
|
|
cursor += sizeof(JSObjectArray);
|
|
|
|
}
|
|
|
|
if (ntrynotes != 0) {
|
|
|
|
script->trynotesOffset = (uint8)(cursor - (uint8 *)script);
|
|
|
|
cursor += sizeof(JSTryNoteArray);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (natoms != 0) {
|
|
|
|
script->atomMap.length = natoms;
|
|
|
|
script->atomMap.vector = (JSAtom **)cursor;
|
|
|
|
vectorSize = natoms * sizeof(script->atomMap.vector[0]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clear object map's vector so the GC tracing can run when not yet
|
|
|
|
* all atoms are copied to the array.
|
|
|
|
*/
|
|
|
|
memset(cursor, 0, vectorSize);
|
|
|
|
cursor += vectorSize;
|
|
|
|
}
|
2008-06-04 10:52:28 +04:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
if (nobjects != 0) {
|
|
|
|
JS_SCRIPT_OBJECTS(script)->length = nobjects;
|
|
|
|
JS_SCRIPT_OBJECTS(script)->vector = (JSObject **)cursor;
|
|
|
|
vectorSize = nobjects * sizeof(JS_SCRIPT_OBJECTS(script)->vector[0]);
|
|
|
|
memset(cursor, 0, vectorSize);
|
|
|
|
cursor += vectorSize;
|
|
|
|
}
|
|
|
|
if (nregexps != 0) {
|
|
|
|
JS_SCRIPT_REGEXPS(script)->length = nregexps;
|
|
|
|
JS_SCRIPT_REGEXPS(script)->vector = (JSObject **)cursor;
|
|
|
|
vectorSize = nregexps * sizeof(JS_SCRIPT_REGEXPS(script)->vector[0]);
|
|
|
|
memset(cursor, 0, vectorSize);
|
|
|
|
cursor += vectorSize;
|
|
|
|
}
|
|
|
|
if (ntrynotes != 0) {
|
|
|
|
JS_SCRIPT_TRYNOTES(script)->length = ntrynotes;
|
|
|
|
JS_SCRIPT_TRYNOTES(script)->vector = (JSTryNote *)cursor;
|
|
|
|
vectorSize = ntrynotes * sizeof(JS_SCRIPT_TRYNOTES(script)->vector[0]);
|
|
|
|
#ifdef DEBUG
|
|
|
|
memset(cursor, 0, vectorSize);
|
|
|
|
#endif
|
|
|
|
cursor += vectorSize;
|
|
|
|
}
|
2008-06-04 10:52:28 +04:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
script->code = script->main = (jsbytecode *)cursor;
|
|
|
|
JS_ASSERT(cursor +
|
|
|
|
length * sizeof(jsbytecode) +
|
|
|
|
nsrcnotes * sizeof(jssrcnote) ==
|
|
|
|
(uint8 *)script + size);
|
|
|
|
|
2008-02-08 02:18:45 +03:00
|
|
|
#ifdef CHECK_SCRIPT_OWNER
|
|
|
|
script->owner = cx->thread;
|
|
|
|
#endif
|
1998-04-24 04:31:11 +04:00
|
|
|
return script;
|
|
|
|
}
|
1998-03-28 05:44:41 +03:00
|
|
|
|
2007-11-29 17:49:42 +03:00
|
|
|
JSScript *
|
|
|
|
js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
1998-04-24 04:31:11 +04:00
|
|
|
{
|
2008-07-21 00:13:17 +04:00
|
|
|
uint32 mainLength, prologLength, nsrcnotes, nfixed;
|
1998-04-24 04:31:11 +04:00
|
|
|
JSScript *script;
|
2003-07-27 02:37:11 +04:00
|
|
|
const char *filename;
|
2008-03-29 13:34:29 +03:00
|
|
|
JSFunction *fun;
|
2003-07-27 02:37:11 +04:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
/* The counts of indexed things must be checked during code generation. */
|
|
|
|
JS_ASSERT(cg->atomList.count <= INDEX_LIMIT);
|
|
|
|
JS_ASSERT(cg->objectList.length <= INDEX_LIMIT);
|
|
|
|
JS_ASSERT(cg->regexpList.length <= INDEX_LIMIT);
|
|
|
|
|
2003-07-28 09:46:18 +04:00
|
|
|
mainLength = CG_OFFSET(cg);
|
2003-07-27 02:37:11 +04:00
|
|
|
prologLength = CG_PROLOG_OFFSET(cg);
|
2003-07-29 13:11:04 +04:00
|
|
|
CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
|
2008-05-29 06:07:32 +04:00
|
|
|
script = js_NewScript(cx, prologLength + mainLength,
|
|
|
|
nsrcnotes, cg->ntrynotes, cg->atomList.count,
|
2008-06-11 01:44:51 +04:00
|
|
|
cg->objectList.length, cg->regexpList.length);
|
1998-04-24 04:31:11 +04:00
|
|
|
if (!script)
|
2001-03-06 04:56:30 +03:00
|
|
|
return NULL;
|
2003-07-27 02:37:11 +04:00
|
|
|
|
|
|
|
/* Now that we have script, error control flow must go to label bad. */
|
|
|
|
script->main += prologLength;
|
|
|
|
memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
|
2003-07-28 09:46:18 +04:00
|
|
|
memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
|
2008-07-21 00:13:17 +04:00
|
|
|
nfixed = (cg->treeContext.flags & TCF_IN_FUNCTION)
|
|
|
|
? cg->treeContext.fun->u.i.nvars
|
|
|
|
: cg->treeContext.ngvars + cg->regexpList.length;
|
|
|
|
JS_ASSERT(nfixed < SLOTNO_LIMIT);
|
|
|
|
script->nfixed = (uint16) nfixed;
|
2007-07-08 13:03:34 +04:00
|
|
|
js_InitAtomMap(cx, &script->atomMap, &cg->atomList);
|
2003-07-27 02:37:11 +04:00
|
|
|
|
2007-10-03 03:10:09 +04:00
|
|
|
filename = cg->treeContext.parseContext->tokenStream.filename;
|
2003-07-27 02:37:11 +04:00
|
|
|
if (filename) {
|
|
|
|
script->filename = js_SaveScriptFilename(cx, filename);
|
|
|
|
if (!script->filename)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
script->lineno = cg->firstLine;
|
2008-07-21 00:13:17 +04:00
|
|
|
script->nslots = script->nfixed + cg->maxStackDepth;
|
2007-10-03 03:10:09 +04:00
|
|
|
script->principals = cg->treeContext.parseContext->principals;
|
|
|
|
if (script->principals)
|
2003-07-27 02:37:11 +04:00
|
|
|
JSPRINCIPALS_HOLD(cx, script->principals);
|
1998-03-28 05:44:41 +03:00
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
if (!js_FinishTakingSrcNotes(cx, cg, SCRIPT_NOTES(script)))
|
|
|
|
goto bad;
|
2007-07-08 13:03:34 +04:00
|
|
|
if (cg->ntrynotes != 0)
|
|
|
|
js_FinishTakingTryNotes(cg, JS_SCRIPT_TRYNOTES(script));
|
|
|
|
if (cg->objectList.length != 0)
|
|
|
|
FinishParsedObjects(&cg->objectList, JS_SCRIPT_OBJECTS(script));
|
|
|
|
if (cg->regexpList.length != 0)
|
|
|
|
FinishParsedObjects(&cg->regexpList, JS_SCRIPT_REGEXPS(script));
|
2003-07-27 02:37:11 +04:00
|
|
|
|
2008-03-29 13:34:29 +03:00
|
|
|
/*
|
|
|
|
* We initialize fun->u.script to be the script constructed above
|
|
|
|
* so that the debugger has a valid FUN_SCRIPT(fun).
|
|
|
|
*/
|
2008-03-29 01:27:36 +03:00
|
|
|
fun = NULL;
|
2007-11-29 17:49:42 +03:00
|
|
|
if (cg->treeContext.flags & TCF_IN_FUNCTION) {
|
2008-03-29 01:27:36 +03:00
|
|
|
fun = cg->treeContext.fun;
|
2008-03-29 13:34:29 +03:00
|
|
|
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
|
2008-03-29 01:27:36 +03:00
|
|
|
js_FreezeLocalNames(cx, fun);
|
2008-03-29 13:34:29 +03:00
|
|
|
fun->u.i.script = script;
|
2008-02-08 02:18:45 +03:00
|
|
|
#ifdef CHECK_SCRIPT_OWNER
|
|
|
|
script->owner = NULL;
|
|
|
|
#endif
|
2006-10-28 09:55:06 +04:00
|
|
|
if (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT)
|
2008-03-29 01:27:36 +03:00
|
|
|
fun->flags |= JSFUN_HEAVYWEIGHT;
|
2006-10-04 08:40:18 +04:00
|
|
|
}
|
|
|
|
|
1998-04-24 04:31:11 +04:00
|
|
|
/* Tell the debugger about this compiled script. */
|
2008-03-29 01:27:36 +03:00
|
|
|
js_CallNewScriptHook(cx, script, fun);
|
2001-11-20 05:47:41 +03:00
|
|
|
return script;
|
2003-07-27 02:37:11 +04:00
|
|
|
|
|
|
|
bad:
|
|
|
|
js_DestroyScript(cx, script);
|
|
|
|
return NULL;
|
2001-11-20 05:47:41 +03:00
|
|
|
}
|
|
|
|
|
2008-03-29 13:34:29 +03:00
|
|
|
JS_FRIEND_API(void)
|
|
|
|
js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
|
2001-11-20 05:47:41 +03:00
|
|
|
{
|
|
|
|
JSNewScriptHook hook;
|
|
|
|
|
2007-06-15 10:44:18 +04:00
|
|
|
hook = cx->debugHooks->newScriptHook;
|
1998-04-24 04:31:11 +04:00
|
|
|
if (hook) {
|
2007-06-15 10:44:18 +04:00
|
|
|
JS_KEEP_ATOMS(cx->runtime);
|
2008-03-29 13:34:29 +03:00
|
|
|
hook(cx, script->filename, script->lineno, script, fun,
|
2007-06-15 10:44:18 +04:00
|
|
|
cx->debugHooks->newScriptHookData);
|
|
|
|
JS_UNKEEP_ATOMS(cx->runtime);
|
1998-04-24 04:31:11 +04:00
|
|
|
}
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
|
|
|
|
2008-03-29 13:34:29 +03:00
|
|
|
JS_FRIEND_API(void)
|
2004-11-25 09:57:17 +03:00
|
|
|
js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
|
1998-03-28 05:44:41 +03:00
|
|
|
{
|
1998-04-24 04:31:11 +04:00
|
|
|
JSDestroyScriptHook hook;
|
1998-03-28 05:44:41 +03:00
|
|
|
|
2007-06-15 10:44:18 +04:00
|
|
|
hook = cx->debugHooks->destroyScriptHook;
|
1998-04-24 04:31:11 +04:00
|
|
|
if (hook)
|
2007-06-15 10:44:18 +04:00
|
|
|
hook(cx, script, cx->debugHooks->destroyScriptHookData);
|
2004-11-25 09:57:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
js_DestroyScript(JSContext *cx, JSScript *script)
|
|
|
|
{
|
|
|
|
js_CallDestroyScriptHook(cx, script);
|
1998-03-28 05:44:41 +03:00
|
|
|
JS_ClearScriptTraps(cx, script);
|
2008-02-08 02:18:45 +03:00
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
if (script->principals)
|
2001-03-06 04:56:30 +03:00
|
|
|
JSPRINCIPALS_DROP(cx, script->principals);
|
2008-02-08 02:18:45 +03:00
|
|
|
|
2008-06-26 00:50:26 +04:00
|
|
|
if (JS_GSN_CACHE(cx).code == script->code)
|
2006-10-07 23:14:55 +04:00
|
|
|
JS_CLEAR_GSN_CACHE(cx);
|
2008-02-08 02:18:45 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The GC flushes all property caches, so no need to purge just the
|
|
|
|
* entries for this script.
|
|
|
|
*
|
|
|
|
* JS_THREADSAFE note: js_FlushPropertyCacheForScript flushes only the
|
|
|
|
* current thread's property cache, so a script not owned by a function
|
|
|
|
* or object, which hands off lifetime management for that script to the
|
|
|
|
* GC, must be used by only one thread over its lifetime.
|
|
|
|
*
|
|
|
|
* This should be an API-compatible change, since a script is never safe
|
|
|
|
* against premature GC if shared among threads without a rooted object
|
|
|
|
* wrapping it to protect the script's mapped atoms against GC. We use
|
|
|
|
* script->owner to enforce this requirement via assertions.
|
|
|
|
*/
|
|
|
|
#ifdef CHECK_SCRIPT_OWNER
|
|
|
|
JS_ASSERT_IF(cx->runtime->gcRunning, !script->owner);
|
|
|
|
#endif
|
|
|
|
|
2008-06-04 10:52:28 +04:00
|
|
|
if (!cx->runtime->gcRunning) {
|
|
|
|
if (!(cx->fp && (cx->fp->flags & JSFRAME_EVAL))) {
|
2008-02-08 02:18:45 +03:00
|
|
|
#ifdef CHECK_SCRIPT_OWNER
|
2008-06-04 10:52:28 +04:00
|
|
|
JS_ASSERT(script->owner == cx->thread);
|
2008-02-08 02:18:45 +03:00
|
|
|
#endif
|
2008-06-04 10:52:28 +04:00
|
|
|
js_FlushPropertyCacheForScript(cx, script);
|
|
|
|
}
|
2008-06-03 05:06:33 +04:00
|
|
|
}
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
JS_free(cx, script);
|
|
|
|
}
|
|
|
|
|
2000-08-26 06:30:22 +04:00
|
|
|
void
|
2007-04-17 10:53:37 +04:00
|
|
|
js_TraceScript(JSTracer *trc, JSScript *script)
|
2000-08-26 06:30:22 +04:00
|
|
|
{
|
|
|
|
JSAtomMap *map;
|
|
|
|
uintN i, length;
|
|
|
|
JSAtom **vector;
|
2007-08-12 00:25:16 +04:00
|
|
|
jsval v;
|
2007-07-08 13:03:34 +04:00
|
|
|
JSObjectArray *objarray;
|
2000-08-26 06:30:22 +04:00
|
|
|
|
|
|
|
map = &script->atomMap;
|
|
|
|
length = map->length;
|
|
|
|
vector = map->vector;
|
2007-07-08 13:03:34 +04:00
|
|
|
for (i = 0; i < length; i++) {
|
2007-08-12 00:25:16 +04:00
|
|
|
v = ATOM_KEY(vector[i]);
|
|
|
|
if (JSVAL_IS_TRACEABLE(v)) {
|
|
|
|
JS_SET_TRACING_INDEX(trc, "atomMap", i);
|
|
|
|
JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
|
|
|
|
}
|
2007-07-08 13:03:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (script->objectsOffset != 0) {
|
|
|
|
objarray = JS_SCRIPT_OBJECTS(script);
|
|
|
|
i = objarray->length;
|
|
|
|
do {
|
|
|
|
--i;
|
2008-01-31 05:19:49 +03:00
|
|
|
if (objarray->vector[i]) {
|
|
|
|
JS_SET_TRACING_INDEX(trc, "objects", i);
|
|
|
|
JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT);
|
|
|
|
}
|
2007-07-08 13:03:34 +04:00
|
|
|
} while (i != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (script->regexpsOffset != 0) {
|
|
|
|
objarray = JS_SCRIPT_REGEXPS(script);
|
|
|
|
i = objarray->length;
|
|
|
|
do {
|
|
|
|
--i;
|
2008-01-31 05:19:49 +03:00
|
|
|
if (objarray->vector[i]) {
|
|
|
|
JS_SET_TRACING_INDEX(trc, "regexps", i);
|
|
|
|
JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT);
|
|
|
|
}
|
2007-07-08 13:03:34 +04:00
|
|
|
} while (i != 0);
|
|
|
|
}
|
2003-07-27 02:37:11 +04:00
|
|
|
|
2008-06-13 00:58:07 +04:00
|
|
|
if (script->object) {
|
|
|
|
JS_SET_TRACING_NAME(trc, "object");
|
|
|
|
JS_CallTracer(trc, script->object, JSTRACE_OBJECT);
|
|
|
|
}
|
|
|
|
|
2007-04-17 10:53:37 +04:00
|
|
|
if (IS_GC_MARKING_TRACER(trc) && script->filename)
|
2003-07-27 02:37:11 +04:00
|
|
|
js_MarkScriptFilename(script->filename);
|
2000-08-26 06:30:22 +04:00
|
|
|
}
|
|
|
|
|
2006-10-07 23:14:55 +04:00
|
|
|
typedef struct GSNCacheEntry {
|
|
|
|
JSDHashEntryHdr hdr;
|
|
|
|
jsbytecode *pc;
|
|
|
|
jssrcnote *sn;
|
|
|
|
} GSNCacheEntry;
|
|
|
|
|
|
|
|
#define GSN_CACHE_THRESHOLD 100
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
jssrcnote *
|
2006-10-07 23:14:55 +04:00
|
|
|
js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
|
1998-03-28 05:44:41 +03:00
|
|
|
{
|
2006-10-07 23:14:55 +04:00
|
|
|
ptrdiff_t target, offset;
|
|
|
|
GSNCacheEntry *entry;
|
|
|
|
jssrcnote *sn, *result;
|
|
|
|
uintN nsrcnotes;
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
|
2003-08-06 10:56:01 +04:00
|
|
|
target = PTRDIFF(pc, script->code, jsbytecode);
|
2003-08-13 09:25:04 +04:00
|
|
|
if ((uint32)target >= script->length)
|
2001-03-06 04:56:30 +03:00
|
|
|
return NULL;
|
2006-10-07 23:14:55 +04:00
|
|
|
|
2008-06-26 00:50:26 +04:00
|
|
|
if (JS_GSN_CACHE(cx).code == script->code) {
|
2006-11-25 05:11:28 +03:00
|
|
|
JS_METER_GSN_CACHE(cx, hits);
|
2006-10-07 23:14:55 +04:00
|
|
|
entry = (GSNCacheEntry *)
|
2006-11-25 05:11:28 +03:00
|
|
|
JS_DHashTableOperate(&JS_GSN_CACHE(cx).table, pc,
|
|
|
|
JS_DHASH_LOOKUP);
|
2006-10-07 23:14:55 +04:00
|
|
|
return entry->sn;
|
|
|
|
}
|
|
|
|
|
2006-11-25 05:11:28 +03:00
|
|
|
JS_METER_GSN_CACHE(cx, misses);
|
2003-07-27 02:37:11 +04:00
|
|
|
offset = 0;
|
2006-10-07 23:14:55 +04:00
|
|
|
for (sn = SCRIPT_NOTES(script); ; sn = SN_NEXT(sn)) {
|
|
|
|
if (SN_IS_TERMINATOR(sn)) {
|
|
|
|
result = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2001-03-06 04:56:30 +03:00
|
|
|
offset += SN_DELTA(sn);
|
2006-10-07 23:14:55 +04:00
|
|
|
if (offset == target && SN_IS_GETTABLE(sn)) {
|
|
|
|
result = sn;
|
|
|
|
break;
|
|
|
|
}
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
2006-10-07 23:14:55 +04:00
|
|
|
|
2008-06-26 00:50:26 +04:00
|
|
|
if (JS_GSN_CACHE(cx).code != script->code &&
|
2006-10-07 23:14:55 +04:00
|
|
|
script->length >= GSN_CACHE_THRESHOLD) {
|
|
|
|
JS_CLEAR_GSN_CACHE(cx);
|
|
|
|
nsrcnotes = 0;
|
|
|
|
for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn);
|
|
|
|
sn = SN_NEXT(sn)) {
|
|
|
|
if (SN_IS_GETTABLE(sn))
|
|
|
|
++nsrcnotes;
|
|
|
|
}
|
2006-11-25 05:11:28 +03:00
|
|
|
if (!JS_DHashTableInit(&JS_GSN_CACHE(cx).table, JS_DHashGetStubOps(),
|
2007-01-11 01:11:34 +03:00
|
|
|
NULL, sizeof(GSNCacheEntry),
|
|
|
|
JS_DHASH_DEFAULT_CAPACITY(nsrcnotes))) {
|
2006-11-25 05:11:28 +03:00
|
|
|
JS_GSN_CACHE(cx).table.ops = NULL;
|
2006-10-07 23:27:04 +04:00
|
|
|
} else {
|
2006-10-07 23:14:55 +04:00
|
|
|
pc = script->code;
|
|
|
|
for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn);
|
|
|
|
sn = SN_NEXT(sn)) {
|
|
|
|
pc += SN_DELTA(sn);
|
|
|
|
if (SN_IS_GETTABLE(sn)) {
|
|
|
|
entry = (GSNCacheEntry *)
|
2006-11-25 05:11:28 +03:00
|
|
|
JS_DHashTableOperate(&JS_GSN_CACHE(cx).table, pc,
|
2006-10-07 23:14:55 +04:00
|
|
|
JS_DHASH_ADD);
|
|
|
|
entry->pc = pc;
|
|
|
|
entry->sn = sn;
|
|
|
|
}
|
|
|
|
}
|
2008-06-26 00:50:26 +04:00
|
|
|
JS_GSN_CACHE(cx).code = script->code;
|
2006-11-25 05:11:28 +03:00
|
|
|
JS_METER_GSN_CACHE(cx, fills);
|
2006-10-07 23:14:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
uintN
|
2003-07-27 02:37:11 +04:00
|
|
|
js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
|
1998-03-28 05:44:41 +03:00
|
|
|
{
|
2008-03-29 13:34:29 +03:00
|
|
|
JSFunction *fun;
|
1998-03-28 05:44:41 +03:00
|
|
|
uintN lineno;
|
2003-07-27 02:37:11 +04:00
|
|
|
ptrdiff_t offset, target;
|
|
|
|
jssrcnote *sn;
|
1998-03-28 05:44:41 +03:00
|
|
|
JSSrcNoteType type;
|
|
|
|
|
2006-10-07 07:50:08 +04:00
|
|
|
/* Cope with JSStackFrame.pc value prior to entering js_Interpret. */
|
|
|
|
if (!pc)
|
|
|
|
return 0;
|
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
/*
|
|
|
|
* Special case: function definition needs no line number note because
|
|
|
|
* the function's script contains its starting line number.
|
|
|
|
*/
|
2007-07-08 13:03:34 +04:00
|
|
|
if (js_CodeSpec[*pc].format & JOF_INDEXBASE)
|
2007-01-07 02:25:00 +03:00
|
|
|
pc += js_CodeSpec[*pc].length;
|
|
|
|
if (*pc == JSOP_DEFFUN) {
|
2008-04-02 11:46:12 +04:00
|
|
|
GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun);
|
2008-03-29 13:34:29 +03:00
|
|
|
return fun->u.i.script->lineno;
|
2003-07-27 02:37:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* General case: walk through source notes accumulating their deltas,
|
|
|
|
* keeping track of line-number notes, until we pass the note for pc's
|
|
|
|
* offset within script->code.
|
|
|
|
*/
|
1998-03-28 05:44:41 +03:00
|
|
|
lineno = script->lineno;
|
2003-07-27 02:37:11 +04:00
|
|
|
offset = 0;
|
|
|
|
target = PTRDIFF(pc, script->code, jsbytecode);
|
|
|
|
for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
|
2001-03-06 04:56:30 +03:00
|
|
|
offset += SN_DELTA(sn);
|
|
|
|
type = (JSSrcNoteType) SN_TYPE(sn);
|
|
|
|
if (type == SRC_SETLINE) {
|
|
|
|
if (offset <= target)
|
|
|
|
lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
|
|
|
|
} else if (type == SRC_NEWLINE) {
|
|
|
|
if (offset <= target)
|
|
|
|
lineno++;
|
|
|
|
}
|
|
|
|
if (offset > target)
|
|
|
|
break;
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
|
|
|
return lineno;
|
|
|
|
}
|
|
|
|
|
2005-01-29 21:31:46 +03:00
|
|
|
/* The line number limit is the same as the jssrcnote offset limit. */
|
|
|
|
#define SN_LINE_LIMIT (SN_3BYTE_OFFSET_FLAG << 16)
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
jsbytecode *
|
|
|
|
js_LineNumberToPC(JSScript *script, uintN target)
|
|
|
|
{
|
2005-01-29 21:31:46 +03:00
|
|
|
ptrdiff_t offset, best;
|
|
|
|
uintN lineno, bestdiff, diff;
|
2003-07-27 02:37:11 +04:00
|
|
|
jssrcnote *sn;
|
1998-03-28 05:44:41 +03:00
|
|
|
JSSrcNoteType type;
|
|
|
|
|
2003-07-27 02:37:11 +04:00
|
|
|
offset = 0;
|
2005-01-29 21:31:46 +03:00
|
|
|
best = -1;
|
1998-03-28 05:44:41 +03:00
|
|
|
lineno = script->lineno;
|
2005-01-29 21:31:46 +03:00
|
|
|
bestdiff = SN_LINE_LIMIT;
|
2003-07-27 02:37:11 +04:00
|
|
|
for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
|
2007-04-02 22:13:22 +04:00
|
|
|
/*
|
|
|
|
* Exact-match only if offset is not in the prolog; otherwise use
|
|
|
|
* nearest greater-or-equal line number match.
|
|
|
|
*/
|
|
|
|
if (lineno == target && script->code + offset >= script->main)
|
2005-01-29 21:31:46 +03:00
|
|
|
goto out;
|
2007-04-02 22:13:22 +04:00
|
|
|
if (lineno >= target) {
|
2005-01-29 21:31:46 +03:00
|
|
|
diff = lineno - target;
|
|
|
|
if (diff < bestdiff) {
|
|
|
|
bestdiff = diff;
|
|
|
|
best = offset;
|
|
|
|
}
|
|
|
|
}
|
2001-03-06 04:56:30 +03:00
|
|
|
offset += SN_DELTA(sn);
|
|
|
|
type = (JSSrcNoteType) SN_TYPE(sn);
|
|
|
|
if (type == SRC_SETLINE) {
|
|
|
|
lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
|
|
|
|
} else if (type == SRC_NEWLINE) {
|
|
|
|
lineno++;
|
|
|
|
}
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
2005-01-29 21:31:46 +03:00
|
|
|
if (best >= 0)
|
|
|
|
offset = best;
|
|
|
|
out:
|
2003-07-27 02:37:11 +04:00
|
|
|
return script->code + offset;
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
|
|
|
|
2005-03-29 20:55:43 +04:00
|
|
|
JS_FRIEND_API(uintN)
|
1998-03-28 05:44:41 +03:00
|
|
|
js_GetScriptLineExtent(JSScript *script)
|
|
|
|
{
|
|
|
|
uintN lineno;
|
2003-07-27 02:37:11 +04:00
|
|
|
jssrcnote *sn;
|
1998-03-28 05:44:41 +03:00
|
|
|
JSSrcNoteType type;
|
|
|
|
|
|
|
|
lineno = script->lineno;
|
2003-07-27 02:37:11 +04:00
|
|
|
for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
|
2001-03-06 04:56:30 +03:00
|
|
|
type = (JSSrcNoteType) SN_TYPE(sn);
|
|
|
|
if (type == SRC_SETLINE) {
|
|
|
|
lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
|
|
|
|
} else if (type == SRC_NEWLINE) {
|
|
|
|
lineno++;
|
|
|
|
}
|
1998-03-28 05:44:41 +03:00
|
|
|
}
|
|
|
|
return 1 + lineno - script->lineno;
|
|
|
|
}
|
2006-08-30 03:15:22 +04:00
|
|
|
|
|
|
|
#if JS_HAS_GENERATORS
|
|
|
|
|
2007-05-24 11:51:46 +04:00
|
|
|
JSBool
|
|
|
|
js_IsInsideTryWithFinally(JSScript *script, jsbytecode *pc)
|
2006-08-30 03:15:22 +04:00
|
|
|
{
|
2007-07-08 13:03:34 +04:00
|
|
|
JSTryNoteArray *tarray;
|
2007-05-24 11:51:46 +04:00
|
|
|
JSTryNote *tn, *tnlimit;
|
|
|
|
uint32 off;
|
2006-08-30 03:15:22 +04:00
|
|
|
|
2007-05-24 11:51:46 +04:00
|
|
|
JS_ASSERT(script->code <= pc);
|
|
|
|
JS_ASSERT(pc < script->code + script->length);
|
2006-08-30 03:15:22 +04:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
if (!script->trynotesOffset != 0)
|
2007-05-24 11:51:46 +04:00
|
|
|
return JS_FALSE;
|
2007-07-08 13:03:34 +04:00
|
|
|
tarray = JS_SCRIPT_TRYNOTES(script);
|
|
|
|
JS_ASSERT(tarray->length != 0);
|
2006-08-30 03:15:22 +04:00
|
|
|
|
2007-07-08 13:03:34 +04:00
|
|
|
tn = tarray->vector;
|
|
|
|
tnlimit = tn + tarray->length;
|
2007-05-24 11:51:46 +04:00
|
|
|
off = (uint32)(pc - script->main);
|
2006-08-30 03:15:22 +04:00
|
|
|
do {
|
2007-05-24 11:51:46 +04:00
|
|
|
if (off - tn->start < tn->length) {
|
|
|
|
if (tn->kind == JSTN_FINALLY)
|
|
|
|
return JS_TRUE;
|
|
|
|
JS_ASSERT(tn->kind == JSTN_CATCH);
|
2006-08-30 03:15:22 +04:00
|
|
|
}
|
2007-05-24 11:51:46 +04:00
|
|
|
} while (++tn != tnlimit);
|
|
|
|
return JS_FALSE;
|
2006-08-30 03:15:22 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|