jsscript.c
来自「一个基于alice开发的机器人」· C语言 代码 · 共 1,288 行 · 第 1/3 页
C
1,288 行
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* 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.
*
* Contributor(s):
*
* 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 ***** */
/*
* JS script operations.
*/
#include "jsstddef.h"
#include <string.h>
#include "jstypes.h"
#include "jsutil.h" /* Added by JSIFY */
#include "jsprf.h"
#include "jsapi.h"
#include "jsatom.h"
#include "jscntxt.h"
#include "jsconfig.h"
#include "jsdbgapi.h"
#include "jsemit.h"
#include "jsfun.h"
#include "jsinterp.h"
#include "jslock.h"
#include "jsnum.h"
#include "jsopcode.h"
#include "jsscript.h"
#if JS_HAS_XDR
#include "jsxdrapi.h"
#endif
#if JS_HAS_SCRIPT_OBJECT
#if JS_HAS_TOSOURCE
static JSBool
script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
JSScript *script;
size_t i, j, k, n;
char buf[16];
jschar *s, *t;
uint32 indent;
JSString *str;
if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
return JS_FALSE;
script = (JSScript *) JS_GetPrivate(cx, obj);
/* Let n count the source string length, j the "front porch" length. */
j = JS_snprintf(buf, sizeof buf, "(new %s(", js_ScriptClass.name);
n = j + 2;
if (!script) {
/* Let k count the constructor argument string length. */
k = 0;
s = NULL; /* quell GCC overwarning */
} else {
indent = 0;
if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent))
return JS_FALSE;
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;
s = JSSTRING_CHARS(str);
k = JSSTRING_LENGTH(str);
n += k;
}
/* Allocate the source string and copy into it. */
t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
if (!t)
return JS_FALSE;
for (i = 0; i < j; i++)
t[i] = buf[i];
for (j = 0; j < k; i++, j++)
t[i] = s[j];
t[i++] = ')';
t[i++] = ')';
t[i] = 0;
/* Create and return a JS string for t. */
str = JS_NewUCString(cx, t, n);
if (!str) {
JS_free(cx, t);
return JS_FALSE;
}
*rval = STRING_TO_JSVAL(str);
return JS_TRUE;
}
#endif /* JS_HAS_TOSOURCE */
static JSBool
script_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
JSScript *script;
uint32 indent;
JSString *str;
if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
return JS_FALSE;
script = (JSScript *) JS_GetPrivate(cx, obj);
if (!script) {
*rval = STRING_TO_JSVAL(cx->runtime->emptyString);
return JS_TRUE;
}
indent = 0;
if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent))
return JS_FALSE;
str = JS_DecompileScript(cx, script, "Script.prototype.toString",
(uintN)indent);
if (!str)
return JS_FALSE;
*rval = STRING_TO_JSVAL(str);
return JS_TRUE;
}
static JSBool
script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
JSScript *oldscript, *script;
JSString *str;
JSStackFrame *fp, *caller;
JSObject *scopeobj;
const char *file;
uintN line;
JSPrincipals *principals;
/* Make sure obj is a Script object. */
if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
return JS_FALSE;
/* If no args, leave private undefined and return early. */
if (argc == 0)
goto out;
/* Otherwise, the first arg is the script source to compile. */
str = js_ValueToString(cx, argv[0]);
if (!str)
return JS_FALSE;
/* Compile using the caller's scope chain, which js_Invoke passes to fp. */
fp = cx->fp;
caller = JS_GetScriptedCaller(cx, fp);
JS_ASSERT(!caller || fp->scopeChain == caller->scopeChain);
scopeobj = NULL;
if (argc >= 2) {
if (!js_ValueToObject(cx, argv[1], &scopeobj))
return JS_FALSE;
argv[1] = OBJECT_TO_JSVAL(scopeobj);
}
if (caller) {
if (!scopeobj)
scopeobj = caller->scopeChain;
file = caller->script->filename;
line = js_PCToLineNumber(cx, caller->script, caller->pc);
principals = JS_EvalFramePrincipals(cx, fp, caller);
} else {
file = NULL;
line = 0;
principals = NULL;
}
/* XXXbe set only for the compiler, which does not currently test it */
fp->flags |= JSFRAME_EVAL;
/* Compile the new script using the caller's scope chain, a la eval(). */
script = JS_CompileUCScriptForPrincipals(cx, scopeobj, principals,
JSSTRING_CHARS(str),
JSSTRING_LENGTH(str),
file, line);
if (!script)
return JS_FALSE;
/* Swap script for obj's old script, if any. */
oldscript = (JSScript *) JS_GetPrivate(cx, obj);
if (!JS_SetPrivate(cx, obj, script)) {
js_DestroyScript(cx, script);
return JS_FALSE;
}
if (oldscript)
js_DestroyScript(cx, oldscript);
script->object = obj;
out:
/* Return the object. */
*rval = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
static JSBool
script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
JSScript *script;
JSObject *scopeobj, *parent;
JSStackFrame *fp, *caller;
if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
return JS_FALSE;
script = (JSScript *) JS_GetPrivate(cx, obj);
if (!script)
return JS_TRUE;
scopeobj = NULL;
if (argc) {
if (!js_ValueToObject(cx, argv[0], &scopeobj))
return JS_FALSE;
argv[0] = OBJECT_TO_JSVAL(scopeobj);
}
/*
* Emulate eval() by using caller's this, var object, sharp array, etc.,
* all propagated by js_Execute via a non-null fourth (down) argument to
* js_Execute. If there is no scripted caller, js_Execute uses its second
* (chain) argument to set the exec frame's varobj, thisp, and scopeChain.
*
* Unlike eval, which the compiler detects, Script.prototype.exec may be
* called from a lightweight function, or even from native code (in which
* 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.
*/
fp = cx->fp;
caller = JS_GetScriptedCaller(cx, fp);
if (caller && !caller->varobj) {
/* Called from a lightweight function. */
JS_ASSERT(caller->fun && !(caller->fun->flags & JSFUN_HEAVYWEIGHT));
/* Scope chain links from Call object to callee's parent. */
parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(caller->argv[-2]));
if (!js_GetCallObject(cx, caller, parent))
return JS_FALSE;
}
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.
*/
scopeobj = caller->scopeChain;
} 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;
}
}
return js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
}
#if JS_HAS_XDR
static JSBool
XDRAtomListElement(JSXDRState *xdr, JSAtomListElement *ale)
{
jsval value;
jsatomid index;
if (xdr->mode == JSXDR_ENCODE)
value = ATOM_KEY(ALE_ATOM(ale));
index = ALE_INDEX(ale);
if (!JS_XDRUint32(xdr, &index))
return JS_FALSE;
ALE_SET_INDEX(ale, index);
if (!JS_XDRValue(xdr, &value))
return JS_FALSE;
if (xdr->mode == JSXDR_DECODE) {
if (!ALE_SET_ATOM(ale, js_AtomizeValue(xdr->cx, value, 0)))
return JS_FALSE;
}
return JS_TRUE;
}
static JSBool
XDRAtomMap(JSXDRState *xdr, JSAtomMap *map)
{
uint32 length;
uintN i;
JSBool ok;
if (xdr->mode == JSXDR_ENCODE)
length = map->length;
if (!JS_XDRUint32(xdr, &length))
return JS_FALSE;
if (xdr->mode == JSXDR_DECODE) {
JSContext *cx;
void *mark;
JSAtomList al;
JSAtomListElement *ale;
cx = xdr->cx;
mark = JS_ARENA_MARK(&cx->tempPool);
ATOM_LIST_INIT(&al);
for (i = 0; i < length; i++) {
JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &cx->tempPool);
if (!ale ||
!XDRAtomListElement(xdr, ale)) {
if (!ale)
JS_ReportOutOfMemory(cx);
JS_ARENA_RELEASE(&cx->tempPool, mark);
return JS_FALSE;
}
ALE_SET_NEXT(ale, al.list);
al.count++;
al.list = ale;
}
ok = js_InitAtomMap(cx, map, &al);
JS_ARENA_RELEASE(&cx->tempPool, mark);
return ok;
}
if (xdr->mode == JSXDR_ENCODE) {
JSAtomListElement ale;
for (i = 0; i < map->length; i++) {
ALE_SET_ATOM(&ale, map->vector[i]);
ALE_SET_INDEX(&ale, i);
if (!XDRAtomListElement(xdr, &ale))
return JS_FALSE;
}
}
return JS_TRUE;
}
JSBool
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
{
JSContext *cx;
JSScript *script, *newscript;
uint32 length, lineno, depth, magic, nsrcnotes, ntrynotes;
uint32 prologLength, version;
JSBool filenameWasSaved;
jssrcnote *notes, *sn;
cx = xdr->cx;
script = *scriptp;
nsrcnotes = ntrynotes = 0;
filenameWasSaved = JS_FALSE;
notes = NULL;
/*
* Encode prologLength and version after script->length (_2 or greater),
* but decode both new (>= _2) and old, prolog&version-free (_1) scripts.
* Version _3 supports principals serialization. Version _4 reorders the
* nsrcnotes and ntrynotes fields to come before everything except magic,
* length, prologLength, and version, so that srcnote and trynote storage
* can be allocated as part of the JSScript (along with bytecode storage).
*/
if (xdr->mode == JSXDR_ENCODE)
magic = JSXDR_MAGIC_SCRIPT_CURRENT;
if (!JS_XDRUint32(xdr, &magic))
return JS_FALSE;
if (magic != JSXDR_MAGIC_SCRIPT_4 &&
magic != JSXDR_MAGIC_SCRIPT_3 &&
magic != JSXDR_MAGIC_SCRIPT_2 &&
magic != JSXDR_MAGIC_SCRIPT_1) {
if (!hasMagic) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_SCRIPT_MAGIC);
return JS_FALSE;
}
*hasMagic = JS_FALSE;
return JS_TRUE;
}
if (hasMagic)
*hasMagic = JS_TRUE;
if (xdr->mode == JSXDR_ENCODE) {
length = script->length;
prologLength = PTRDIFF(script->main, script->code, jsbytecode);
version = (int32)script->version;
lineno = (uint32)script->lineno;
depth = (uint32)script->depth;
/* 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))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?