📄 jsscript.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sw=4 et tw=78: * * ***** 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_OBJECTstatic const char js_script_exec[] = "Script.prototype.exec";static const char js_script_compile[] = "Script.prototype.compile";/* * This routine requires that obj has been locked previously. */static jsintGetScriptExecDepth(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 voidAdjustScriptExecDepth(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);}#if JS_HAS_TOSOURCEstatic JSBoolscript_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ uint32 indent; JSScript *script; size_t i, j, k, n; char buf[16]; jschar *s, *t; JSString *str; if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) return JS_FALSE; indent = 0; if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent)) 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 { 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){ uint32 indent; JSScript *script; JSString *str; indent = 0; if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent)) return JS_FALSE; 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; } 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){ JSString *str; JSObject *scopeobj; jsval v; JSScript *script, *oldscript; JSStackFrame *fp, *caller; const char *file; uintN line; JSPrincipals *principals; jsint execDepth; /* 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; 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); } /* 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); if (caller) { if (!scopeobj) { scopeobj = js_GetScopeChain(cx, caller); if (!scopeobj) return JS_FALSE; fp->scopeChain = scopeobj; /* for the compiler's benefit */ } principals = JS_EvalFramePrincipals(cx, fp, caller); if (principals == caller->script->principals) { file = caller->script->filename; line = js_PCToLineNumber(cx, caller->script, caller->pc); } else { file = principals->codebase; line = 0; } } else { file = NULL; line = 0; principals = NULL; } /* Ensure we compile this script with the right (inner) principals. */ scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_compile); if (!scopeobj) return JS_FALSE; /* * Compile the new script using the caller's scope chain, a la eval(). * Unlike jsobj.c:obj_eval, however, we do not set JSFRAME_EVAL in fp's * flags, because compilation is here separated from execution, and the * 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. */ fp->flags |= JSFRAME_SCRIPT_OBJECT; script = JS_CompileUCScriptForPrincipals(cx, scopeobj, principals, JSSTRING_CHARS(str), JSSTRING_LENGTH(str), file, line); if (!script) return JS_FALSE; 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); return JS_FALSE; } /* Swap script for obj's old script, if any. */ v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE); oldscript = !JSVAL_IS_VOID(v) ? (JSScript *) JSVAL_TO_PRIVATE(v) : NULL; LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script)); JS_UNLOCK_OBJ(cx, obj); if (oldscript) js_DestroyScript(cx, oldscript); script->object = obj; js_CallNewScriptHook(cx, script, NULL);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){ JSObject *scopeobj, *parent; JSStackFrame *fp, *caller; JSScript *script; JSBool ok; if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) return JS_FALSE; 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 && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags)); /* 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 = js_GetScopeChain(cx, caller); if (!scopeobj) return JS_FALSE; } 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; } } scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_exec); if (!scopeobj) return JS_FALSE; /* Keep track of nesting depth for the script. */ AdjustScriptExecDepth(cx, obj, 1); /* Must get to out label after this */ script = (JSScript *) JS_GetPrivate(cx, obj); if (!script) { ok = JS_FALSE; goto out; } /* Belt-and-braces: check that this script object has access to scopeobj. */ ok = js_CheckPrincipalsAccess(cx, scopeobj, script->principals, CLASS_ATOM(cx, Script)); if (!ok) goto out; ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval); out: AdjustScriptExecDepth(cx, obj, -1); return ok;}#if JS_HAS_XDRstatic JSBoolXDRAtomMap(JSXDRState *xdr, JSAtomMap *map){ JSContext *cx; uint32 natoms, i, index; JSAtom **atoms; cx = xdr->cx; if (xdr->mode == JSXDR_ENCODE) natoms = (uint32)map->length; if (!JS_XDRUint32(xdr, &natoms)) return JS_FALSE; if (xdr->mode == JSXDR_ENCODE) { atoms = map->vector; } else { if (natoms == 0) { atoms = NULL; } else { atoms = (JSAtom **) JS_malloc(cx, (size_t)natoms * sizeof *atoms); if (!atoms) return JS_FALSE;#ifdef DEBUG memset(atoms, 0, (size_t)natoms * sizeof *atoms);#endif } map->vector = atoms; map->length = natoms; } for (i = 0; i != natoms; ++i) { if (xdr->mode == JSXDR_ENCODE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -