📄 jsscript.c
字号:
#endif /* !JS_HAS_XDR_FREEZE_THAW */JSObject *js_InitScriptClass(JSContext *cx, JSObject *obj){ return JS_InitClass(cx, obj, NULL, &js_ScriptClass, Script, 1, NULL, script_methods, NULL, script_static_methods);}#endif /* JS_HAS_SCRIPT_OBJECT *//* * Shared script filename management. */JS_STATIC_DLL_CALLBACK(int)js_compare_strings(const void *k1, const void *k2){ return strcmp(k1, k2) == 0;}/* Shared with jsatom.c to save code space. */extern void * JS_DLL_CALLBACKjs_alloc_table_space(void *priv, size_t size);extern void JS_DLL_CALLBACKjs_free_table_space(void *priv, void *item);/* 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 */ JSPackedBool mark; /* mark flag, for GC */ char filename[3]; /* two or more bytes, NUL-terminated */} ScriptFilenameEntry;JS_STATIC_DLL_CALLBACK(JSHashEntry *)js_alloc_entry(void *priv, const void *key){ size_t nbytes = offsetof(ScriptFilenameEntry, filename) + strlen(key) + 1; return (JSHashEntry *) malloc(JS_MAX(nbytes, sizeof(JSHashEntry)));}JS_STATIC_DLL_CALLBACK(void)js_free_entry(void *priv, JSHashEntry *he, uintN flag){ if (flag != HT_FREE_ENTRY) return; free(he);}static JSHashAllocOps table_alloc_ops = { js_alloc_table_space, js_free_table_space, js_alloc_entry, js_free_entry};JSBooljs_InitRuntimeScriptState(JSContext *cx){ 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; }#endif 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; } } return JS_TRUE;}voidjs_FinishRuntimeScriptState(JSContext *cx){ JSRuntime *rt = cx->runtime; if (rt->scriptFilenameTable) { JS_HashTableDestroy(rt->scriptFilenameTable); rt->scriptFilenameTable = NULL; }#ifdef JS_THREADSAFE if (rt->scriptFilenameTableLock) { JS_DESTROY_LOCK(rt->scriptFilenameTableLock); rt->scriptFilenameTableLock = NULL; }#endif}#ifdef DEBUG_brendansize_t sft_savings = 0;#endifconst char *js_SaveScriptFilename(JSContext *cx, const char *filename){ JSRuntime *rt = cx->runtime; JSHashTable *table; JSHashNumber hash; JSHashEntry **hep; ScriptFilenameEntry *sfe; JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock); table = rt->scriptFilenameTable; hash = JS_HashString(filename); hep = JS_HashTableRawLookup(table, hash, filename); sfe = (ScriptFilenameEntry *) *hep;#ifdef DEBUG_brendan if (sfe) sft_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); } } JS_RELEASE_LOCK(rt->scriptFilenameTableLock); if (!sfe) { JS_ReportOutOfMemory(cx); return NULL; } return sfe->filename;}voidjs_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->mark = JS_TRUE;}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;}voidjs_SweepScriptFilenames(JSRuntime *rt){ JS_HashTableEnumerateEntries(rt->scriptFilenameTable, js_script_filename_sweeper, rt);#ifdef DEBUG_brendan printf("script filename table savings so far: %u\n", sft_savings);#endif}JSScript *js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 ntrynotes){ JSScript *script; /* Round up source note count to align script->trynotes for its type. */ if (ntrynotes) nsrcnotes += JSTRYNOTE_ALIGNMASK; script = (JSScript *) JS_malloc(cx, sizeof(JSScript) + length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote) + ntrynotes * sizeof(JSTryNote)); if (!script) return NULL; memset(script, 0, sizeof(JSScript)); script->code = script->main = (jsbytecode *)(script + 1); script->length = length; script->version = cx->version; if (ntrynotes) { script->trynotes = (JSTryNote *) ((jsword)(SCRIPT_NOTES(script) + nsrcnotes) & ~(jsword)JSTRYNOTE_ALIGNMASK); } return script;}JS_FRIEND_API(JSScript *)js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun){ uint32 mainLength, prologLength, nsrcnotes, ntrynotes; JSScript *script; const char *filename; mainLength = CG_OFFSET(cg); prologLength = CG_PROLOG_OFFSET(cg); CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes); CG_COUNT_FINAL_TRYNOTES(cg, ntrynotes); script = js_NewScript(cx, prologLength + mainLength, nsrcnotes, ntrynotes); if (!script) return NULL; /* 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)); memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode)); if (!js_InitAtomMap(cx, &script->atomMap, &cg->atomList)) goto bad; filename = cg->filename; if (filename) { script->filename = js_SaveScriptFilename(cx, filename); if (!script->filename) goto bad; } script->lineno = cg->firstLine; script->depth = cg->maxStackDepth; if (cg->principals) { script->principals = cg->principals; JSPRINCIPALS_HOLD(cx, script->principals); } if (!js_FinishTakingSrcNotes(cx, cg, SCRIPT_NOTES(script))) goto bad; if (script->trynotes) js_FinishTakingTryNotes(cx, cg, script->trynotes); /* Tell the debugger about this compiled script. */ js_CallNewScriptHook(cx, script, fun); return script;bad: js_DestroyScript(cx, script); return NULL;}JS_FRIEND_API(void)js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun){ JSRuntime *rt; JSNewScriptHook hook; rt = cx->runtime; hook = rt->newScriptHook; if (hook) { /* * We use a dummy stack frame to protect the script from a GC caused * by debugger-hook execution. * * XXX We really need a way to manage local roots and such more * XXX automatically, at which point we can remove this one-off hack * XXX and others within the engine. See bug 40757 for discussion. */ JSStackFrame dummy; memset(&dummy, 0, sizeof dummy); dummy.down = cx->fp; dummy.script = script; cx->fp = &dummy; hook(cx, script->filename, script->lineno, script, fun, rt->newScriptHookData); cx->fp = dummy.down; }}voidjs_DestroyScript(JSContext *cx, JSScript *script){ JSRuntime *rt; JSDestroyScriptHook hook; rt = cx->runtime; hook = rt->destroyScriptHook; if (hook) hook(cx, script, rt->destroyScriptHookData); JS_ClearScriptTraps(cx, script); js_FreeAtomMap(cx, &script->atomMap); if (script->principals) JSPRINCIPALS_DROP(cx, script->principals); JS_free(cx, script);}voidjs_MarkScript(JSContext *cx, JSScript *script, void *arg){ JSAtomMap *map; uintN i, length; JSAtom **vector; map = &script->atomMap; length = map->length; vector = map->vector; for (i = 0; i < length; i++) GC_MARK_ATOM(cx, vector[i], arg); if (script->filename) js_MarkScriptFilename(script->filename);}jssrcnote *js_GetSrcNote(JSScript *script, jsbytecode *pc){ jssrcnote *sn; ptrdiff_t offset, target; target = PTRDIFF(pc, script->code, jsbytecode); if ((uint32)target >= script->length) return NULL; offset = 0; for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { offset += SN_DELTA(sn); if (offset == target && SN_IS_GETTABLE(sn)) return sn; } return NULL;}uintNjs_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc){ JSAtom *atom; JSFunction *fun; uintN lineno; ptrdiff_t offset, target; jssrcnote *sn; JSSrcNoteType type; /* * Special case: function definition needs no line number note because * the function's script contains its starting line number. */ if (*pc == JSOP_DEFFUN) { atom = GET_ATOM(cx, script, pc); fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(atom)); return fun->script->lineno; } /* * 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. */ lineno = script->lineno; offset = 0; target = PTRDIFF(pc, script->code, jsbytecode); for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { 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; } return lineno;}jsbytecode *js_LineNumberToPC(JSScript *script, uintN target){ ptrdiff_t offset; uintN lineno; jssrcnote *sn; JSSrcNoteType type; offset = 0; lineno = script->lineno; for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { if (lineno >= target) break; 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++; } } return script->code + offset;}uintNjs_GetScriptLineExtent(JSScript *script){ uintN lineno; jssrcnote *sn; JSSrcNoteType type; lineno = script->lineno; for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { type = (JSSrcNoteType) SN_TYPE(sn); if (type == SRC_SETLINE) { lineno = (uintN) js_GetSrcNoteOffset(sn, 0); } else if (type == SRC_NEWLINE) { lineno++; } } return 1 + lineno - script->lineno;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -