📄 jsscript.c
字号:
/* -*- 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_TOSOURCEstatic JSBoolscript_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 JSBoolscript_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 JSBoolscript_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; } /* Compile the new script using the caller's scope chain, a la eval(). */ fp->flags |= JSFRAME_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 JSBoolscript_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_XDRstatic JSBoolXDRAtomListElement(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 JSBoolXDRAtomMap(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;}JSBooljs_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)) continue; nsrcnotes = PTRDIFF(sn, notes, jssrcnote);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -