diff options
| author | Bob Jamison <ishmalius@gmail.com> | 2007-03-05 10:34:59 +0000 |
|---|---|---|
| committer | ishmal <ishmal@users.sourceforge.net> | 2007-03-05 10:34:59 +0000 |
| commit | 33837efd4b94c4ebb80f95b3d9dbb6efd5499a98 (patch) | |
| tree | de482d7687b3bffa97cc78608ba75a8ad7e52b60 /src/dom/js/jsscript.c | |
| parent | Adding optional dialog preview. Implments RFE [ 1435276 ] switch preview on/o... (diff) | |
| download | inkscape-33837efd4b94c4ebb80f95b3d9dbb6efd5499a98.tar.gz inkscape-33837efd4b94c4ebb80f95b3d9dbb6efd5499a98.zip | |
update JS
(bzr r2555)
Diffstat (limited to 'src/dom/js/jsscript.c')
| -rw-r--r-- | src/dom/js/jsscript.c | 312 |
1 files changed, 259 insertions, 53 deletions
diff --git a/src/dom/js/jsscript.c b/src/dom/js/jsscript.c index 7e5aefc30..6fc92de93 100644 --- a/src/dom/js/jsscript.c +++ b/src/dom/js/jsscript.c @@ -1,4 +1,5 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=80: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 @@ -63,6 +64,9 @@ #if JS_HAS_SCRIPT_OBJECT +static const char js_script_exec[] = "Script.prototype.exec"; +static const char js_script_compile[] = "Script.prototype.compile"; + #if JS_HAS_TOSOURCE static JSBool script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, @@ -157,8 +161,8 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSScript *oldscript, *script; - JSString *str; JSStackFrame *fp, *caller; + JSString *str; JSObject *scopeobj; const char *file; uintN line; @@ -172,10 +176,23 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (argc == 0) goto out; + /* XXX thread safety was completely neglected in this function... */ + oldscript = (JSScript *) JS_GetPrivate(cx, obj); + if (oldscript) { + for (fp = cx->fp; fp; fp = fp->down) { + if (fp->script == oldscript) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_SELF_MODIFYING_SCRIPT); + return JS_FALSE; + } + } + } + /* 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); /* Compile using the caller's scope chain, which js_Invoke passes to fp. */ fp = cx->fp; @@ -201,6 +218,11 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, 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 @@ -209,6 +231,7 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, * 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), @@ -217,7 +240,6 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, 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; @@ -238,6 +260,7 @@ script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) JSScript *script; JSObject *scopeobj, *parent; JSStackFrame *fp, *caller; + JSPrincipals *principals; if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) return JS_FALSE; @@ -297,6 +320,15 @@ script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } } + scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_exec); + if (!scopeobj) + return JS_FALSE; + + /* Belt-and-braces: check that this script object has access to scopeobj. */ + principals = script->principals; + if (!js_CheckPrincipalsAccess(cx, scopeobj, principals, js_script_exec)) + return JS_FALSE; + return js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval); } @@ -704,6 +736,7 @@ script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, str = js_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; + argv[0] = STRING_TO_JSVAL(str); /* create new XDR */ xdr = JS_XDRNewMem(cx, JSXDR_DECODE); @@ -839,6 +872,12 @@ Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); if (!obj) return JS_FALSE; + + /* + * script_compile does not use rval to root its temporaries + * so we can use it to root obj. + */ + *rval = OBJECT_TO_JSVAL(obj); } return script_compile(cx, obj, argc, argv, rval); } @@ -899,7 +938,8 @@ typedef struct ScriptFilenameEntry { JSHashEntry *next; /* hash chain linkage */ JSHashNumber keyHash; /* key hash function result */ const void *key; /* ptr to filename, below */ - JSPackedBool mark; /* mark flag, for GC */ + uint32 flags; /* user-defined filename prefix flags */ + JSPackedBool mark; /* GC mark flag */ char filename[3]; /* two or more bytes, NUL-terminated */ } ScriptFilenameEntry; @@ -919,45 +959,42 @@ js_free_sftbl_entry(void *priv, JSHashEntry *he, uintN flag) free(he); } -static JSHashAllocOps table_alloc_ops = { +static JSHashAllocOps sftbl_alloc_ops = { js_alloc_table_space, js_free_table_space, js_alloc_sftbl_entry, js_free_sftbl_entry }; JSBool -js_InitRuntimeScriptState(JSContext *cx) +js_InitRuntimeScriptState(JSRuntime *rt) { - JSRuntime *rt = cx->runtime; - #ifdef JS_THREADSAFE - /* Must come through here once in primordial thread to init safely! */ - if (!rt->scriptFilenameTableLock) { - rt->scriptFilenameTableLock = JS_NEW_LOCK(); - if (!rt->scriptFilenameTableLock) - return JS_FALSE; - } + JS_ASSERT(!rt->scriptFilenameTableLock); + rt->scriptFilenameTableLock = JS_NEW_LOCK(); + if (!rt->scriptFilenameTableLock) + return JS_FALSE; #endif + JS_ASSERT(!rt->scriptFilenameTable); + rt->scriptFilenameTable = + JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL, + &sftbl_alloc_ops, NULL); if (!rt->scriptFilenameTable) { - JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock); - if (!rt->scriptFilenameTable) { - rt->scriptFilenameTable = - JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL, - &table_alloc_ops, NULL); - } - JS_RELEASE_LOCK(rt->scriptFilenameTableLock); - if (!rt->scriptFilenameTable) { - js_FinishRuntimeScriptState(cx); /* free lock if threadsafe */ - return JS_FALSE; - } + js_FinishRuntimeScriptState(rt); /* free lock if threadsafe */ + return JS_FALSE; } + JS_INIT_CLIST(&rt->scriptFilenamePrefixes); return JS_TRUE; } +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; + void -js_FinishRuntimeScriptState(JSContext *cx) +js_FinishRuntimeScriptState(JSRuntime *rt) { - JSRuntime *rt = cx->runtime; - if (rt->scriptFilenameTable) { JS_HashTableDestroy(rt->scriptFilenameTable); rt->scriptFilenameTable = NULL; @@ -970,20 +1007,34 @@ js_FinishRuntimeScriptState(JSContext *cx) #endif } +void +js_FreeRuntimeScriptState(JSRuntime *rt) +{ + ScriptFilenamePrefix *sfp; + + while (!JS_CLIST_IS_EMPTY(&rt->scriptFilenamePrefixes)) { + sfp = (ScriptFilenamePrefix *) rt->scriptFilenamePrefixes.next; + JS_REMOVE_LINK(&sfp->links); + free(sfp); + } + js_FinishRuntimeScriptState(rt); +} + #ifdef DEBUG_brendan size_t sftbl_savings = 0; #endif -const char * -js_SaveScriptFilename(JSContext *cx, const char *filename) +static ScriptFilenameEntry * +SaveScriptFilename(JSRuntime *rt, const char *filename, uint32 flags) { - JSRuntime *rt = cx->runtime; JSHashTable *table; JSHashNumber hash; JSHashEntry **hep; ScriptFilenameEntry *sfe; + size_t length; + JSCList *head, *link; + ScriptFilenamePrefix *sfp; - JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock); table = rt->scriptFilenameTable; hash = JS_HashString(filename); hep = JS_HashTableRawLookup(table, hash, filename); @@ -992,41 +1043,175 @@ js_SaveScriptFilename(JSContext *cx, const char *filename) if (sfe) sftbl_savings += strlen(sfe->filename); #endif + if (!sfe) { sfe = (ScriptFilenameEntry *) JS_HashTableRawAdd(table, hep, hash, filename, NULL); - if (sfe) { - sfe->key = strcpy(sfe->filename, filename); - JS_ASSERT(!sfe->mark); + 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; + } + + /* + * 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; } - JS_RELEASE_LOCK(rt->scriptFilenameTableLock); + + 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); if (!sfe) { + JS_RELEASE_LOCK(rt->scriptFilenameTableLock); JS_ReportOutOfMemory(cx); return NULL; } + + /* + * 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); return sfe->filename; } +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; +} + void js_MarkScriptFilename(const char *filename) { ScriptFilenameEntry *sfe; - /* - * Back up from filename by its offset within its hash table entry. - * 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. - */ - sfe = (ScriptFilenameEntry *) - (filename - offsetof(ScriptFilenameEntry, filename)); - JS_ASSERT(sfe->key == sfe->filename); + sfe = FILENAME_TO_SFE(filename); + ASSERT_VALID_SFE(sfe); sfe->mark = JS_TRUE; } 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; +} + +void +js_MarkScriptFilenames(JSRuntime *rt, uintN gcflags) +{ + JSCList *head, *link; + ScriptFilenamePrefix *sfp; + + if (gcflags & GC_KEEP_ATOMS) { + JS_HashTableEnumerateEntries(rt->scriptFilenameTable, + js_script_filename_marker, + rt); + } + for (head = &rt->scriptFilenamePrefixes, link = head->next; + link != head; + link = link->next) { + sfp = (ScriptFilenamePrefix *) link; + js_MarkScriptFilename(sfp->name); + } +} + +JS_STATIC_DLL_CALLBACK(intN) js_script_filename_sweeper(JSHashEntry *he, intN i, void *arg) { ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he; @@ -1043,7 +1228,7 @@ js_SweepScriptFilenames(JSRuntime *rt) JS_HashTableEnumerateEntries(rt->scriptFilenameTable, js_script_filename_sweeper, rt); -#ifdef DEBUG_brendan +#ifdef DEBUG_notme printf("script filename table savings so far: %u\n", sftbl_savings); #endif } @@ -1142,8 +1327,8 @@ js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun) } } -void -js_DestroyScript(JSContext *cx, JSScript *script) +JS_FRIEND_API(void) +js_CallDestroyScriptHook(JSContext *cx, JSScript *script) { JSRuntime *rt; JSDestroyScriptHook hook; @@ -1152,6 +1337,12 @@ js_DestroyScript(JSContext *cx, JSScript *script) hook = rt->destroyScriptHook; if (hook) hook(cx, script, rt->destroyScriptHookData); +} + +void +js_DestroyScript(JSContext *cx, JSScript *script) +{ + js_CallDestroyScriptHook(cx, script); JS_ClearScriptTraps(cx, script); js_FreeAtomMap(cx, &script->atomMap); @@ -1240,19 +1431,31 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) return lineno; } +/* The line number limit is the same as the jssrcnote offset limit. */ +#define SN_LINE_LIMIT (SN_3BYTE_OFFSET_FLAG << 16) + jsbytecode * js_LineNumberToPC(JSScript *script, uintN target) { - ptrdiff_t offset; - uintN lineno; + ptrdiff_t offset, best; + uintN lineno, bestdiff, diff; jssrcnote *sn; JSSrcNoteType type; offset = 0; + best = -1; lineno = script->lineno; + bestdiff = SN_LINE_LIMIT; for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { - if (lineno >= target) - break; + if (lineno == target) + goto out; + if (lineno > target) { + diff = lineno - target; + if (diff < bestdiff) { + bestdiff = diff; + best = offset; + } + } offset += SN_DELTA(sn); type = (JSSrcNoteType) SN_TYPE(sn); if (type == SRC_SETLINE) { @@ -1261,10 +1464,13 @@ js_LineNumberToPC(JSScript *script, uintN target) lineno++; } } + if (best >= 0) + offset = best; +out: return script->code + offset; } -uintN +JS_FRIEND_API(uintN) js_GetScriptLineExtent(JSScript *script) { uintN lineno; |
