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:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
17 * The Original Code is Mozilla Communicator client code, released
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.
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.
39 * ***** END LICENSE BLOCK ***** */
44 * JS script descriptor.
52 * Type of try note associated with each catch or finally block, and also with
55 typedef enum JSTryNoteKind
{
64 * Indicates a location in the stack that an upvar value can be retrieved from
65 * as a two tuple of (level, slot).
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.
71 * Existing XDR code wants this to be backed by a 32b integer for serialization,
74 * TODO: consider giving more bits to the slot value and takings ome from the level.
80 static const uint32 FREE_VALUE
= 0xfffffffful
;
82 void checkInvariants() {
83 JS_STATIC_ASSERT(sizeof(UpvarCookie
) == sizeof(uint32
));
84 JS_STATIC_ASSERT(UPVAR_LEVEL_LIMIT
< FREE_LEVEL
);
89 * All levels above-and-including FREE_LEVEL are reserved so that
90 * FREE_VALUE can be used as a special value.
92 static const uint16 FREE_LEVEL
= 0x3fff;
95 * If a function has a higher static level than this limit, we will not
96 * optimize it using UPVAR opcodes.
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
; }
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
); }
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
; }
117 * Exception handling record.
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 */
128 typedef struct JSTryNoteArray
{
129 JSTryNote
*vector
; /* array of indexed try notes */
130 uint32 length
; /* count of indexed try notes */
133 typedef struct JSObjectArray
{
134 JSObject
**vector
; /* array of indexed objects */
135 uint32 length
; /* count of indexed objects */
138 typedef struct JSUpvarArray
{
139 js::UpvarCookie
*vector
; /* array of indexed upvar cookies */
140 uint32 length
; /* count of indexed upvar cookies */
143 typedef struct JSConstArray
{
144 js::Value
*vector
; /* array of indexed constant values */
152 struct GlobalSlotArray
{
154 uint32 atomIndex
; /* index into atom table */
155 uint32 slot
; /* global obj slot number */
163 enum BindingKind
{ NONE
, ARGUMENT
, VARIABLE
, CONSTANT
, UPVAR
};
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).
172 js::Shape
*lastBinding
;
178 inline Bindings(JSContext
*cx
);
181 * Transfers ownership of bindings data from bindings into this fresh
182 * Bindings instance. Once such a transfer occurs, the old bindings must
185 inline void transfer(JSContext
*cx
, Bindings
*bindings
);
188 * Clones bindings data from bindings, which must be immutable, into this
189 * fresh Bindings instance. A Bindings instance may be cloned multiple
192 inline void clone(JSContext
*cx
, Bindings
*bindings
);
194 uint16
countArgs() const { return nargs
; }
195 uint16
countVars() const { return nvars
; }
196 uint16
countUpvars() const { return nupvars
; }
198 uintN
countArgsAndVars() const { return nargs
+ nvars
; }
200 uintN
countLocalNames() const { return nargs
+ nvars
+ nupvars
; }
202 bool hasUpvars() const { return nupvars
> 0; }
203 bool hasLocalNames() const { return countLocalNames() > 0; }
205 /* Returns the shape lineage generated for these bindings. */
206 inline const js::Shape
*lastShape() const;
210 * A script may have no more than this many arguments, variables, or
213 BINDING_COUNT_LIMIT
= 0xFFFF
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.
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.
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.
232 bool add(JSContext
*cx
, JSAtom
*name
, BindingKind kind
);
234 /* Convenience specializations. */
235 bool addVariable(JSContext
*cx
, JSAtom
*name
) {
236 return add(cx
, name
, VARIABLE
);
238 bool addConstant(JSContext
*cx
, JSAtom
*name
) {
239 return add(cx
, name
, CONSTANT
);
241 bool addUpvar(JSContext
*cx
, JSAtom
*name
) {
242 return add(cx
, name
, UPVAR
);
244 bool addArgument(JSContext
*cx
, JSAtom
*name
, uint16
*slotp
) {
245 JS_ASSERT(name
!= NULL
); /* not destructuring */
247 return add(cx
, name
, ARGUMENT
);
249 bool addDestructuring(JSContext
*cx
, uint16
*slotp
) {
251 return add(cx
, NULL
, ARGUMENT
);
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
260 BindingKind
lookup(JSContext
*cx
, JSAtom
*name
, uintN
*indexp
) const;
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
;
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().
272 * The supplied pool is used to allocate the returned array, so the caller
273 * is obligated to mark and release to free it.
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.
281 * If nameWord does not name an argument, use JS_LOCAL_NAME_IS_CONST to
282 * check if nameWord corresponds to the const declaration.
285 getLocalNameArray(JSContext
*cx
, JSArenaPool
*pool
);
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.
291 int sharpSlotBase(JSContext
*cx
);
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.
298 void makeImmutable();
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).
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.
311 const js::Shape
*lastArgument() const;
312 const js::Shape
*lastVariable() const;
313 const js::Shape
*lastUpvar() const;
315 void trace(JSTracer
*trc
);
320 #define JS_OBJECT_ARRAY_SIZE(length) \
321 (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length))
323 #if defined DEBUG && defined JS_THREADSAFE
324 # define CHECK_SCRIPT_OWNER 1
329 class ExecutablePool
;
332 #define JS_UNJITTABLE_SCRIPT (reinterpret_cast<void*>(1))
334 enum JITScriptStatus
{
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.
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.
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
);
366 static JSScript
*NewScriptFromCG(JSContext
*cx
, JSCodeGenerator
*cg
);
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 */
374 uint16 version
; /* JS version under which script was compiled */
376 size_t callCount_
; /* Number of times the script has been called. */
379 uint16 nfixed
; /* number of slots besides stack operands in
383 * Offsets to various array structures from the end of this script, or
384 * JSScript::INVALID_OFFSET if the array has length 0.
386 uint8 objectsOffset
; /* offset to the array of nested function,
387 block, scope, xml and one-time regexps
389 uint8 upvarsOffset
; /* offset of the array of display ("up")
391 uint8 regexpsOffset
; /* offset to the array of to-be-cloned
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 */
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
408 bool hasSingletons
:1; /* script has singleton objects */
410 bool debugMode
:1; /* script was compiled in debug mode */
411 bool singleStepMode
:1; /* compile script in single-step mode */
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 */
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.
444 JSScript
*nextToGC
; /* next to GC in rt->scriptsToGC list */
447 #ifdef CHECK_SCRIPT_OWNER
448 JSThread
*owner
; /* for thread-safe life-cycle assertions */
451 uint32
*closedSlots
; /* vector of closed slots; args first, then vars. */
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
;
462 js::mjit::JITScript
*jitNormal
; /* Extra JIT info for normal scripts */
463 js::mjit::JITScript
*jitCtor
; /* Extra JIT info for constructors */
466 return jitNormal
|| jitCtor
;
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
);
474 js::mjit::JITScript
*getJIT(bool constructing
) {
475 return constructing
? jitCtor
: jitNormal
;
478 size_t callCount() const { return callCount_
; }
479 size_t incCallCount() { return ++callCount_
; }
481 JITScriptStatus
getJITStatus(bool constructing
) {
482 void *addr
= constructing
? jitArityCheckCtor
: jitArityCheckNormal
;
484 return JITScript_None
;
485 if (addr
== JS_UNJITTABLE_SCRIPT
)
486 return JITScript_Invalid
;
487 return JITScript_Valid
;
491 /* Script notes are allocated right after the code. */
492 jssrcnote
*notes() { return (jssrcnote
*)(code
+ length
); }
494 static const uint8 INVALID_OFFSET
= 0xFF;
495 static bool isValidOffset(uint8 offset
) { return offset
!= INVALID_OFFSET
; }
497 JSObjectArray
*objects() {
498 JS_ASSERT(isValidOffset(objectsOffset
));
499 return (JSObjectArray
*)((uint8
*) (this + 1) + objectsOffset
);
502 JSUpvarArray
*upvars() {
503 JS_ASSERT(isValidOffset(upvarsOffset
));
504 return (JSUpvarArray
*) ((uint8
*) (this + 1) + upvarsOffset
);
507 JSObjectArray
*regexps() {
508 JS_ASSERT(isValidOffset(regexpsOffset
));
509 return (JSObjectArray
*) ((uint8
*) (this + 1) + regexpsOffset
);
512 JSTryNoteArray
*trynotes() {
513 JS_ASSERT(isValidOffset(trynotesOffset
));
514 return (JSTryNoteArray
*) ((uint8
*) (this + 1) + trynotesOffset
);
517 js::GlobalSlotArray
*globals() {
518 JS_ASSERT(isValidOffset(globalsOffset
));
519 return (js::GlobalSlotArray
*) ((uint8
*) (this + 1) + globalsOffset
);
522 JSConstArray
*consts() {
523 JS_ASSERT(isValidOffset(constOffset
));
524 return (JSConstArray
*) ((uint8
*) (this + 1) + constOffset
);
527 JSAtom
*getAtom(size_t index
) {
528 JS_ASSERT(index
< atomMap
.length
);
529 return atomMap
.vector
[index
];
532 JSObject
*getObject(size_t index
) {
533 JSObjectArray
*arr
= objects();
534 JS_ASSERT(index
< arr
->length
);
535 return arr
->vector
[index
];
538 uint32
getGlobalSlot(size_t index
) {
539 js::GlobalSlotArray
*arr
= globals();
540 JS_ASSERT(index
< arr
->length
);
541 return arr
->vector
[index
].slot
;
544 JSAtom
*getGlobalAtom(size_t index
) {
545 js::GlobalSlotArray
*arr
= globals();
546 JS_ASSERT(index
< arr
->length
);
547 return getAtom(arr
->vector
[index
].atomIndex
);
550 JSVersion
getVersion() const {
551 return JSVersion(version
);
554 inline JSFunction
*getFunction(size_t index
);
556 inline JSObject
*getRegExp(size_t index
);
558 const js::Value
&getConst(size_t index
) {
559 JSConstArray
*arr
= consts();
560 JS_ASSERT(index
< arr
->length
);
561 return arr
->vector
[index
];
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.
569 inline bool isEmpty() const;
571 uint32
getClosedArg(uint32 index
) {
572 JS_ASSERT(index
< nClosedArgs
);
573 return closedSlots
[index
];
576 uint32
getClosedVar(uint32 index
) {
577 JS_ASSERT(index
< nClosedVars
);
578 return closedSlots
[nClosedArgs
+ index
];
581 void copyClosedSlotsTo(JSScript
*other
);
584 #define SHARP_NSLOTS 2 /* [#array, #depth] slots if the script
585 uses sharp variables */
587 static JS_INLINE uintN
588 StackDepth(JSScript
*script
)
590 return script
->nslots
- script
->nfixed
;
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.
598 #define JS_GET_SCRIPT_ATOM(script_, pc_, index, atom) \
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]; \
605 (atom) = script_->getAtom(index); \
609 extern JS_FRIEND_DATA(js::Class
) js_ScriptClass
;
612 js_InitScriptClass(JSContext
*cx
, JSObject
*obj
);
615 * On first new context in rt, initialize script runtime state, specifically
616 * the script filename table and its lock.
619 js_InitRuntimeScriptState(JSRuntime
*rt
);
622 * On JS_DestroyRuntime(rt), forcibly free script filename prefixes and any
623 * script filename table entries that have not been GC'd.
625 * This allows script filename prefixes to outlive any context in rt.
628 js_FreeRuntimeScriptState(JSRuntime
*rt
);
631 js_SaveScriptFilename(JSContext
*cx
, const char *filename
);
634 js_SaveScriptFilenameRT(JSRuntime
*rt
, const char *filename
, uint32 flags
);
637 js_GetScriptFilenameFlags(const char *filename
);
640 js_MarkScriptFilename(const char *filename
);
643 js_MarkScriptFilenames(JSRuntime
*rt
);
646 js_SweepScriptFilenames(JSRuntime
*rt
);
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).
654 extern JS_FRIEND_API(void)
655 js_CallNewScriptHook(JSContext
*cx
, JSScript
*script
, JSFunction
*fun
);
658 js_CallDestroyScriptHook(JSContext
*cx
, JSScript
*script
);
661 * The function must be used only outside the GC for a script that was run
662 * only on the current thread.
665 js_DestroyScript(JSContext
*cx
, JSScript
*script
);
668 js_DestroyScriptFromGC(JSContext
*cx
, JSScript
*script
);
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
677 js_DestroyCachedScript(JSContext
*cx
, JSScript
*script
);
680 js_TraceScript(JSTracer
*trc
, JSScript
*script
);
683 js_NewScriptObject(JSContext
*cx
, JSScript
*script
);
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.
690 #define js_GetSrcNote(script,pc) js_GetSrcNoteCached(cx, script, pc)
693 js_GetSrcNoteCached(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
);
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.
701 js_FramePCToLineNumber(JSContext
*cx
, JSStackFrame
*fp
);
704 js_PCToLineNumber(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
);
707 js_LineNumberToPC(JSScript
*script
, uintN lineno
);
709 extern JS_FRIEND_API(uintN
)
710 js_GetScriptLineExtent(JSScript
*script
);
712 static JS_INLINE JSOp
713 js_GetOpcode(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
)
715 JSOp op
= (JSOp
) *pc
;
717 op
= JS_GetTrapOpcode(cx
, script
, pc
);
722 js_CloneScript(JSContext
*cx
, JSScript
*script
);
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,
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.
735 js_XDRScript(JSXDRState
*xdr
, JSScript
**scriptp
, JSBool
*hasMagic
);
737 #endif /* jsscript_h___ */