Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsscript.h
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=4 sw=4 et tw=79 ft=cpp:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is Mozilla Communicator client code, released
18  * March 31, 1998.
19  *
20  * The Initial Developer of the Original Code is
21  * Netscape Communications Corporation.
22  * Portions created by the Initial Developer are Copyright (C) 1998
23  * the Initial Developer. All Rights Reserved.
24  *
25  * Contributor(s):
26  *
27  * Alternatively, the contents of this file may be used under the terms of
28  * either of the GNU General Public License Version 2 or later (the "GPL"),
29  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30  * in which case the provisions of the GPL or the LGPL are applicable instead
31  * of those above. If you wish to allow use of your version of this file only
32  * under the terms of either the GPL or the LGPL, and not to allow others to
33  * use your version of this file under the terms of the MPL, indicate your
34  * decision by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL or the LGPL. If you do not delete
36  * the provisions above, a recipient may use your version of this file under
37  * the terms of any one of the MPL, the GPL or the LGPL.
38  *
39  * ***** END LICENSE BLOCK ***** */
40
41 #ifndef jsscript_h___
42 #define jsscript_h___
43 /*
44  * JS script descriptor.
45  */
46 #include "jsatom.h"
47 #include "jsprvtd.h"
48 #include "jsdbgapi.h"
49 #include "jsclist.h"
50
51 /*
52  * Type of try note associated with each catch or finally block, and also with
53  * for-in loops.
54  */
55 typedef enum JSTryNoteKind {
56     JSTRY_CATCH,
57     JSTRY_FINALLY,
58     JSTRY_ITER
59 } JSTryNoteKind;
60
61 namespace js {
62
63 /*
64  * Indicates a location in the stack that an upvar value can be retrieved from
65  * as a two tuple of (level, slot).
66  *
67  * Some existing client code uses the level value as a delta, or level "skip"
68  * quantity. We could probably document that through use of more types at some
69  * point in the future.
70  *
71  * Existing XDR code wants this to be backed by a 32b integer for serialization,
72  * so we oblige.
73  *
74  * TODO: consider giving more bits to the slot value and takings ome from the level.
75  */
76 class UpvarCookie
77 {
78     uint32 value;
79
80     static const uint32 FREE_VALUE = 0xfffffffful;
81
82     void checkInvariants() {
83         JS_STATIC_ASSERT(sizeof(UpvarCookie) == sizeof(uint32));
84         JS_STATIC_ASSERT(UPVAR_LEVEL_LIMIT < FREE_LEVEL);
85     }
86
87   public:
88     /*
89      * All levels above-and-including FREE_LEVEL are reserved so that
90      * FREE_VALUE can be used as a special value.
91      */
92     static const uint16 FREE_LEVEL = 0x3fff;
93
94     /*
95      * If a function has a higher static level than this limit, we will not
96      * optimize it using UPVAR opcodes.
97      */
98     static const uint16 UPVAR_LEVEL_LIMIT = 16;
99     static const uint16 CALLEE_SLOT = 0xffff;
100     static bool isLevelReserved(uint16 level) { return level >= FREE_LEVEL; }
101
102     bool isFree() const { return value == FREE_VALUE; }
103     uint32 asInteger() const { return value; }
104     /* isFree check should be performed before using these accessors. */
105     uint16 level() const { JS_ASSERT(!isFree()); return uint16(value >> 16); }
106     uint16 slot() const { JS_ASSERT(!isFree()); return uint16(value); }
107
108     void set(const UpvarCookie &other) { set(other.level(), other.slot()); }
109     void set(uint16 newLevel, uint16 newSlot) { value = (uint32(newLevel) << 16) | newSlot; }
110     void makeFree() { set(0xffff, 0xffff); JS_ASSERT(isFree()); }
111     void fromInteger(uint32 u32) { value = u32; }
112 };
113
114 }
115
116 /*
117  * Exception handling record.
118  */
119 struct JSTryNote {
120     uint8           kind;       /* one of JSTryNoteKind */
121     uint8           padding;    /* explicit padding on uint16 boundary */
122     uint16          stackDepth; /* stack depth upon exception handler entry */
123     uint32          start;      /* start of the try statement or for-in loop
124                                    relative to script->main */
125     uint32          length;     /* length of the try statement or for-in loop */
126 };
127
128 typedef struct JSTryNoteArray {
129     JSTryNote       *vector;    /* array of indexed try notes */
130     uint32          length;     /* count of indexed try notes */
131 } JSTryNoteArray;
132
133 typedef struct JSObjectArray {
134     JSObject        **vector;   /* array of indexed objects */
135     uint32          length;     /* count of indexed objects */
136 } JSObjectArray;
137
138 typedef struct JSUpvarArray {
139     js::UpvarCookie *vector;    /* array of indexed upvar cookies */
140     uint32          length;     /* count of indexed upvar cookies */
141 } JSUpvarArray;
142
143 typedef struct JSConstArray {
144     js::Value       *vector;    /* array of indexed constant values */
145     uint32          length;
146 } JSConstArray;
147
148 struct JSArenaPool;
149
150 namespace js {
151
152 struct GlobalSlotArray {
153     struct Entry {
154         uint32      atomIndex;  /* index into atom table */
155         uint32      slot;       /* global obj slot number */
156     };
157     Entry           *vector;
158     uint32          length;
159 };
160
161 struct Shape;
162
163 enum BindingKind { NONE, ARGUMENT, VARIABLE, CONSTANT, UPVAR };
164
165 /*
166  * Formal parameters, local variables, and upvars are stored in a shape tree
167  * path encapsulated within this class.  This class represents bindings for
168  * both function and top-level scripts (the latter is needed to track names in
169  * strict mode eval code, to give such code its own lexical environment).
170  */
171 class Bindings {
172     js::Shape *lastBinding;
173     uint16 nargs;
174     uint16 nvars;
175     uint16 nupvars;
176
177   public:
178     inline Bindings(JSContext *cx);
179
180     /*
181      * Transfers ownership of bindings data from bindings into this fresh
182      * Bindings instance. Once such a transfer occurs, the old bindings must
183      * not be used again.
184      */
185     inline void transfer(JSContext *cx, Bindings *bindings);
186
187     /*
188      * Clones bindings data from bindings, which must be immutable, into this
189      * fresh Bindings instance. A Bindings instance may be cloned multiple
190      * times.
191      */
192     inline void clone(JSContext *cx, Bindings *bindings);
193
194     uint16 countArgs() const { return nargs; }
195     uint16 countVars() const { return nvars; }
196     uint16 countUpvars() const { return nupvars; }
197
198     uintN countArgsAndVars() const { return nargs + nvars; }
199
200     uintN countLocalNames() const { return nargs + nvars + nupvars; }
201
202     bool hasUpvars() const { return nupvars > 0; }
203     bool hasLocalNames() const { return countLocalNames() > 0; }
204
205     /* Returns the shape lineage generated for these bindings. */
206     inline const js::Shape *lastShape() const;
207
208     enum {
209         /*
210          * A script may have no more than this many arguments, variables, or
211          * upvars.
212          */
213         BINDING_COUNT_LIMIT = 0xFFFF
214     };
215
216     /*
217      * Add a local binding for the given name, of the given type, for the code
218      * being compiled.  If fun is non-null, this binding set is being created
219      * for that function, so adjust corresponding metadata in that function
220      * while adding.  Otherwise this set must correspond to a top-level script.
221      *
222      * A binding may be added twice with different kinds; the last one for a
223      * given name prevails.  (We preserve both bindings for the decompiler,
224      * which must deal with such cases.)  Pass null for name when indicating a
225      * destructuring argument.  Return true on success.
226      *
227      * The parser builds shape paths for functions, usable by Call objects at
228      * runtime, by calling an "add" method. All ARGUMENT bindings must be added
229      * before before any VARIABLE or CONSTANT bindings, which themselves must
230      * be added before all UPVAR bindings.
231      */
232     bool add(JSContext *cx, JSAtom *name, BindingKind kind);
233
234     /* Convenience specializations. */
235     bool addVariable(JSContext *cx, JSAtom *name) {
236         return add(cx, name, VARIABLE);
237     }
238     bool addConstant(JSContext *cx, JSAtom *name) {
239         return add(cx, name, CONSTANT);
240     }
241     bool addUpvar(JSContext *cx, JSAtom *name) {
242         return add(cx, name, UPVAR);
243     }
244     bool addArgument(JSContext *cx, JSAtom *name, uint16 *slotp) {
245         JS_ASSERT(name != NULL); /* not destructuring */
246         *slotp = nargs;
247         return add(cx, name, ARGUMENT);
248     }
249     bool addDestructuring(JSContext *cx, uint16 *slotp) {
250         *slotp = nargs;
251         return add(cx, NULL, ARGUMENT);
252     }
253
254     /*
255      * Look up an argument or variable name, returning its kind when found or
256      * NONE when no such name exists. When indexp is not null and the name
257      * exists, *indexp will receive the index of the corresponding argument or
258      * variable.
259      */
260     BindingKind lookup(JSContext *cx, JSAtom *name, uintN *indexp) const;
261
262     /* Convenience method to check for any binding for a name. */
263     bool hasBinding(JSContext *cx, JSAtom *name) const {
264         return lookup(cx, name, NULL) != NONE;
265     }
266
267     /*
268      * Function and macros to work with local names as an array of words.
269      * getLocalNameArray returns the array, or null if we are out of memory.
270      * This function must be called only when hasLocalNames().
271      *
272      * The supplied pool is used to allocate the returned array, so the caller
273      * is obligated to mark and release to free it.
274      *
275      * The elements of the array with index less than nargs correspond to the
276      * the names of arguments. An index >= nargs addresses a var binding. Use
277      * JS_LOCAL_NAME_TO_ATOM to convert array's element to an atom pointer.
278      * This pointer can be null when the element is for an argument
279      * corresponding to a destructuring pattern.
280      *
281      * If nameWord does not name an argument, use JS_LOCAL_NAME_IS_CONST to
282      * check if nameWord corresponds to the const declaration.
283      */
284     jsuword *
285     getLocalNameArray(JSContext *cx, JSArenaPool *pool);
286
287     /*
288      * Returns the slot where the sharp array is stored, or a value < 0 if no
289      * sharps are present or in case of failure.
290      */
291     int sharpSlotBase(JSContext *cx);
292
293     /*
294      * Protect stored bindings from mutation.  Subsequent attempts to add
295      * bindings will copy the existing bindings before adding to them, allowing
296      * the original bindings to be safely shared.
297      */
298     void makeImmutable();
299
300     /*
301      * These methods provide direct access to the shape path normally
302      * encapsulated by js::Bindings. These methods may be used to make a
303      * Shape::Range for iterating over the relevant shapes from youngest to
304      * oldest (i.e., last or right-most to first or left-most in source order).
305      *
306      * Sometimes iteration order must be from oldest to youngest, however. For
307      * such cases, use js::Bindings::getLocalNameArray. The RAII class
308      * js::AutoLocalNameArray, defined in jscntxt.h, should be used where
309      * possible instead of direct calls to getLocalNameArray.
310      */
311     const js::Shape *lastArgument() const;
312     const js::Shape *lastVariable() const;
313     const js::Shape *lastUpvar() const;
314
315     void trace(JSTracer *trc);
316 };
317
318 } /* namespace js */
319
320 #define JS_OBJECT_ARRAY_SIZE(length)                                          \
321     (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length))
322
323 #if defined DEBUG && defined JS_THREADSAFE
324 # define CHECK_SCRIPT_OWNER 1
325 #endif
326
327 #ifdef JS_METHODJIT
328 namespace JSC {
329     class ExecutablePool;
330 }
331
332 #define JS_UNJITTABLE_SCRIPT (reinterpret_cast<void*>(1))
333
334 enum JITScriptStatus {
335     JITScript_None,
336     JITScript_Invalid,
337     JITScript_Valid
338 };
339
340 namespace js {
341 namespace mjit {
342
343 struct JITScript;
344
345 }
346 }
347 #endif
348
349 struct JSScript {
350     /*
351      * Two successively less primitive ways to make a new JSScript.  The first
352      * does *not* call a non-null cx->runtime->newScriptHook -- only the second,
353      * NewScriptFromCG, calls this optional debugger hook.
354      *
355      * The NewScript function can't know whether the script it creates belongs
356      * to a function, or is top-level or eval code, but the debugger wants access
357      * to the newly made script's function, if any -- so callers of NewScript
358      * are responsible for notifying the debugger after successfully creating any
359      * kind (function or other) of new JSScript.
360      */
361     static JSScript *NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
362                                uint32 nobjects, uint32 nupvars, uint32 nregexps,
363                                uint32 ntrynotes, uint32 nconsts, uint32 nglobals,
364                                uint16 nClosedArgs, uint16 nClosedVars, JSVersion version);
365
366     static JSScript *NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg);
367
368     /* FIXME: bug 586181 */
369     JSCList         links;      /* Links for compartment script list */
370     jsbytecode      *code;      /* bytecodes and their immediate operands */
371     uint32          length;     /* length of code vector */
372
373   private:
374     uint16          version;    /* JS version under which script was compiled */
375
376     size_t          callCount_; /* Number of times the script has been called. */
377
378   public:
379     uint16          nfixed;     /* number of slots besides stack operands in
380                                    slot array */
381
382     /*
383      * Offsets to various array structures from the end of this script, or
384      * JSScript::INVALID_OFFSET if the array has length 0.
385      */
386     uint8           objectsOffset;  /* offset to the array of nested function,
387                                        block, scope, xml and one-time regexps
388                                        objects */
389     uint8           upvarsOffset;   /* offset of the array of display ("up")
390                                        closure vars */
391     uint8           regexpsOffset;  /* offset to the array of to-be-cloned
392                                        regexps  */
393     uint8           trynotesOffset; /* offset to the array of try notes */
394     uint8           globalsOffset;  /* offset to the array of global slots */
395     uint8           constOffset;    /* offset to the array of constants */
396
397     bool            noScriptRval:1; /* no need for result value of last
398                                        expression statement */
399     bool            savedCallerFun:1; /* object 0 is caller function */
400     bool            hasSharps:1;      /* script uses sharp variables */
401     bool            strictModeCode:1; /* code is in strict mode */
402     bool            compileAndGo:1;   /* script was compiled with TCF_COMPILE_N_GO */
403     bool            usesEval:1;       /* script uses eval() */
404     bool            usesArguments:1;  /* script uses arguments */
405     bool            warnedAboutTwoArgumentEval:1; /* have warned about use of
406                                                      obsolete eval(s, o) in
407                                                      this script */
408     bool            hasSingletons:1;  /* script has singleton objects */
409 #ifdef JS_METHODJIT
410     bool            debugMode:1;      /* script was compiled in debug mode */
411     bool            singleStepMode:1; /* compile script in single-step mode */
412 #endif
413
414     jsbytecode      *main;      /* main entry point, after predef'ing prolog */
415     JSAtomMap       atomMap;    /* maps immediate index to literal struct */
416     JSCompartment   *compartment; /* compartment the script was compiled for */
417     const char      *filename;  /* source filename or null */
418     uint32          lineno;     /* base line number of script */
419     uint16          nslots;     /* vars plus maximum stack depth */
420     uint16          staticLevel;/* static level for display maintenance */
421     uint16          nClosedArgs; /* number of args which are closed over. */
422     uint16          nClosedVars; /* number of vars which are closed over. */
423     js::Bindings    bindings;   /* names of top-level variables in this script
424                                    (and arguments if this is a function script) */
425     JSPrincipals    *principals;/* principals for this script */
426     union {
427         /*
428          * A script object of class js_ScriptClass, to ensure the script is GC'd.
429          * - All scripts returned by JSAPI functions (JS_CompileScript,
430          *   JS_CompileFile, etc.) have these objects.
431          * - Function scripts never have script objects; such scripts are owned
432          *   by their function objects.
433          * - Temporary scripts created by obj_eval, JS_EvaluateScript, and
434          *   similar functions never have these objects; such scripts are
435          *   explicitly destroyed by the code that created them.
436          * Debugging API functions (JSDebugHooks::newScriptHook;
437          * JS_GetFunctionScript) may reveal sans-script-object Function and
438          * temporary scripts to clients, but clients must never call
439          * JS_NewScriptObject on such scripts: doing so would double-free them,
440          * once from the explicit call to js_DestroyScript, and once when the
441          * script object is garbage collected.
442          */
443         JSObject    *object;
444         JSScript    *nextToGC;  /* next to GC in rt->scriptsToGC list */
445     } u;
446
447 #ifdef CHECK_SCRIPT_OWNER
448     JSThread        *owner;     /* for thread-safe life-cycle assertions */
449 #endif
450
451     uint32          *closedSlots; /* vector of closed slots; args first, then vars. */
452
453   public:
454 #ifdef JS_METHODJIT
455     // Fast-cached pointers to make calls faster. These are also used to
456     // quickly test whether there is JIT code; a NULL value means no
457     // compilation has been attempted. A JS_UNJITTABLE_SCRIPT value means
458     // compilation failed. Any value is the arity-check entry point.
459     void *jitArityCheckNormal;
460     void *jitArityCheckCtor;
461
462     js::mjit::JITScript *jitNormal;   /* Extra JIT info for normal scripts */
463     js::mjit::JITScript *jitCtor;     /* Extra JIT info for constructors */
464
465     bool hasJITCode() {
466         return jitNormal || jitCtor;
467     }
468
469     // These methods are implemented in MethodJIT.h.
470     inline void **nativeMap(bool constructing);
471     inline void *maybeNativeCodeForPC(bool constructing, jsbytecode *pc);
472     inline void *nativeCodeForPC(bool constructing, jsbytecode *pc);
473
474     js::mjit::JITScript *getJIT(bool constructing) {
475         return constructing ? jitCtor : jitNormal;
476     }
477
478     size_t callCount() const  { return callCount_; }
479     size_t incCallCount() { return ++callCount_; }
480
481     JITScriptStatus getJITStatus(bool constructing) {
482         void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal;
483         if (addr == NULL)
484             return JITScript_None;
485         if (addr == JS_UNJITTABLE_SCRIPT)
486             return JITScript_Invalid;
487         return JITScript_Valid;
488     }
489 #endif
490
491     /* Script notes are allocated right after the code. */
492     jssrcnote *notes() { return (jssrcnote *)(code + length); }
493
494     static const uint8 INVALID_OFFSET = 0xFF;
495     static bool isValidOffset(uint8 offset) { return offset != INVALID_OFFSET; }
496
497     JSObjectArray *objects() {
498         JS_ASSERT(isValidOffset(objectsOffset));
499         return (JSObjectArray *)((uint8 *) (this + 1) + objectsOffset);
500     }
501
502     JSUpvarArray *upvars() {
503         JS_ASSERT(isValidOffset(upvarsOffset));
504         return (JSUpvarArray *) ((uint8 *) (this + 1) + upvarsOffset);
505     }
506
507     JSObjectArray *regexps() {
508         JS_ASSERT(isValidOffset(regexpsOffset));
509         return (JSObjectArray *) ((uint8 *) (this + 1) + regexpsOffset);
510     }
511
512     JSTryNoteArray *trynotes() {
513         JS_ASSERT(isValidOffset(trynotesOffset));
514         return (JSTryNoteArray *) ((uint8 *) (this + 1) + trynotesOffset);
515     }
516
517     js::GlobalSlotArray *globals() {
518         JS_ASSERT(isValidOffset(globalsOffset));
519         return (js::GlobalSlotArray *) ((uint8 *) (this + 1) + globalsOffset);
520     }
521
522     JSConstArray *consts() {
523         JS_ASSERT(isValidOffset(constOffset));
524         return (JSConstArray *) ((uint8 *) (this + 1) + constOffset);
525     }
526
527     JSAtom *getAtom(size_t index) {
528         JS_ASSERT(index < atomMap.length);
529         return atomMap.vector[index];
530     }
531
532     JSObject *getObject(size_t index) {
533         JSObjectArray *arr = objects();
534         JS_ASSERT(index < arr->length);
535         return arr->vector[index];
536     }
537
538     uint32 getGlobalSlot(size_t index) {
539         js::GlobalSlotArray *arr = globals();
540         JS_ASSERT(index < arr->length);
541         return arr->vector[index].slot;
542     }
543
544     JSAtom *getGlobalAtom(size_t index) {
545         js::GlobalSlotArray *arr = globals();
546         JS_ASSERT(index < arr->length);
547         return getAtom(arr->vector[index].atomIndex);
548     }
549
550     JSVersion getVersion() const {
551         return JSVersion(version);
552     }
553
554     inline JSFunction *getFunction(size_t index);
555
556     inline JSObject *getRegExp(size_t index);
557
558     const js::Value &getConst(size_t index) {
559         JSConstArray *arr = consts();
560         JS_ASSERT(index < arr->length);
561         return arr->vector[index];
562     }
563
564     /*
565      * The isEmpty method tells whether this script has code that computes any
566      * result (not return value, result AKA normal completion value) other than
567      * JSVAL_VOID, or any other effects.
568      */
569     inline bool isEmpty() const;
570
571     uint32 getClosedArg(uint32 index) {
572         JS_ASSERT(index < nClosedArgs);
573         return closedSlots[index];
574     }
575
576     uint32 getClosedVar(uint32 index) {
577         JS_ASSERT(index < nClosedVars);
578         return closedSlots[nClosedArgs + index];
579     }
580
581     void copyClosedSlotsTo(JSScript *other);
582 };
583
584 #define SHARP_NSLOTS            2       /* [#array, #depth] slots if the script
585                                            uses sharp variables */
586
587 static JS_INLINE uintN
588 StackDepth(JSScript *script)
589 {
590     return script->nslots - script->nfixed;
591 }
592
593 /*
594  * If pc_ does not point within script_'s bytecode, then it must point into an
595  * imacro body, so we use cx->runtime common atoms instead of script_'s atoms.
596  * This macro uses cx from its callers' environments in the pc-in-imacro case.
597  */
598 #define JS_GET_SCRIPT_ATOM(script_, pc_, index, atom)                         \
599     JS_BEGIN_MACRO                                                            \
600         if ((pc_) < (script_)->code ||                                        \
601             (script_)->code + (script_)->length <= (pc_)) {                   \
602             JS_ASSERT((size_t)(index) < js_common_atom_count);                \
603             (atom) = COMMON_ATOMS_START(&cx->runtime->atomState)[index];      \
604         } else {                                                              \
605             (atom) = script_->getAtom(index);                                 \
606         }                                                                     \
607     JS_END_MACRO
608
609 extern JS_FRIEND_DATA(js::Class) js_ScriptClass;
610
611 extern JSObject *
612 js_InitScriptClass(JSContext *cx, JSObject *obj);
613
614 /*
615  * On first new context in rt, initialize script runtime state, specifically
616  * the script filename table and its lock.
617  */
618 extern JSBool
619 js_InitRuntimeScriptState(JSRuntime *rt);
620
621 /*
622  * On JS_DestroyRuntime(rt), forcibly free script filename prefixes and any
623  * script filename table entries that have not been GC'd.
624  *
625  * This allows script filename prefixes to outlive any context in rt.
626  */
627 extern void
628 js_FreeRuntimeScriptState(JSRuntime *rt);
629
630 extern const char *
631 js_SaveScriptFilename(JSContext *cx, const char *filename);
632
633 extern const char *
634 js_SaveScriptFilenameRT(JSRuntime *rt, const char *filename, uint32 flags);
635
636 extern uint32
637 js_GetScriptFilenameFlags(const char *filename);
638
639 extern void
640 js_MarkScriptFilename(const char *filename);
641
642 extern void
643 js_MarkScriptFilenames(JSRuntime *rt);
644
645 extern void
646 js_SweepScriptFilenames(JSRuntime *rt);
647
648 /*
649  * New-script-hook calling is factored from js_NewScriptFromCG so that it
650  * and callers of js_XDRScript can share this code.  In the case of callers
651  * of js_XDRScript, the hook should be invoked only after successful decode
652  * of any owning function (the fun parameter) or script object (null fun).
653  */
654 extern JS_FRIEND_API(void)
655 js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun);
656
657 extern void
658 js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
659
660 /*
661  * The function must be used only outside the GC for a script that was run
662  * only on the current thread.
663  */
664 extern void
665 js_DestroyScript(JSContext *cx, JSScript *script);
666
667 extern void
668 js_DestroyScriptFromGC(JSContext *cx, JSScript *script);
669
670 /*
671  * Script objects may be cached and reused, in which case their JSD-visible
672  * lifetimes may be shorter than their actual lifetimes. Destroy one such
673  * script for real as part of a GC pass. From JSD's point of view, the script
674  * is already dead.
675  */
676 extern void
677 js_DestroyCachedScript(JSContext *cx, JSScript *script);
678
679 extern void
680 js_TraceScript(JSTracer *trc, JSScript *script);
681
682 extern JSObject *
683 js_NewScriptObject(JSContext *cx, JSScript *script);
684
685 /*
686  * To perturb as little code as possible, we introduce a js_GetSrcNote lookup
687  * cache without adding an explicit cx parameter.  Thus js_GetSrcNote becomes
688  * a macro that uses cx from its calls' lexical environments.
689  */
690 #define js_GetSrcNote(script,pc) js_GetSrcNoteCached(cx, script, pc)
691
692 extern jssrcnote *
693 js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc);
694
695 /*
696  * NOTE: use js_FramePCToLineNumber(cx, fp) when you have an active fp, in
697  * preference to js_PCToLineNumber (cx, fp->script  fp->regs->pc), because
698  * fp->imacpc may be non-null, indicating an active imacro.
699  */
700 extern uintN
701 js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp);
702
703 extern uintN
704 js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
705
706 extern jsbytecode *
707 js_LineNumberToPC(JSScript *script, uintN lineno);
708
709 extern JS_FRIEND_API(uintN)
710 js_GetScriptLineExtent(JSScript *script);
711
712 static JS_INLINE JSOp
713 js_GetOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
714 {
715     JSOp op = (JSOp) *pc;
716     if (op == JSOP_TRAP)
717         op = JS_GetTrapOpcode(cx, script, pc);
718     return op;
719 }
720
721 extern JSScript *
722 js_CloneScript(JSContext *cx, JSScript *script);
723
724 /*
725  * If magic is non-null, js_XDRScript succeeds on magic number mismatch but
726  * returns false in *magic; it reflects a match via a true *magic out param.
727  * If magic is null, js_XDRScript returns false on bad magic number errors,
728  * which it reports.
729  *
730  * NB: after a successful JSXDR_DECODE, js_XDRScript callers must do any
731  * required subsequent set-up of owning function or script object and then call
732  * js_CallNewScriptHook.
733  */
734 extern JSBool
735 js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic);
736
737 inline bool
738 JSObject::isScript() const
739 {
740     return getClass() == &js_ScriptClass;
741 }
742
743 inline JSScript *
744 JSObject::getScript() const
745 {
746     JS_ASSERT(isScript());
747     return static_cast<JSScript *>(getPrivate());
748 }
749
750 #endif /* jsscript_h___ */