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 : #include "jsinfer.h"
51 : #include "jsopcode.h"
52 : #include "jsscope.h"
53 :
54 : #include "gc/Barrier.h"
55 :
56 : /*
57 : * Type of try note associated with each catch or finally block, and also with
58 : * for-in loops.
59 : */
60 : typedef enum JSTryNoteKind {
61 : JSTRY_CATCH,
62 : JSTRY_FINALLY,
63 : JSTRY_ITER
64 : } JSTryNoteKind;
65 :
66 : namespace js {
67 :
68 : /*
69 : * Indicates a location in the stack that an upvar value can be retrieved from
70 : * as a two tuple of (level, slot).
71 : *
72 : * Some existing client code uses the level value as a delta, or level "skip"
73 : * quantity. We could probably document that through use of more types at some
74 : * point in the future.
75 : *
76 : * Existing XDR code wants this to be backed by a 32b integer for serialization,
77 : * so we oblige.
78 : *
79 : * TODO: consider giving more bits to the slot value and takings ome from the level.
80 : */
81 : class UpvarCookie
82 205910 : {
83 : uint32_t value;
84 :
85 : static const uint32_t FREE_VALUE = 0xfffffffful;
86 :
87 : void checkInvariants() {
88 : JS_STATIC_ASSERT(sizeof(UpvarCookie) == sizeof(uint32_t));
89 : JS_STATIC_ASSERT(UPVAR_LEVEL_LIMIT < FREE_LEVEL);
90 : }
91 :
92 : public:
93 : /*
94 : * All levels above-and-including FREE_LEVEL are reserved so that
95 : * FREE_VALUE can be used as a special value.
96 : */
97 : static const uint16_t FREE_LEVEL = 0x3fff;
98 :
99 : /*
100 : * If a function has a higher static level than this limit, we will not
101 : * optimize it using UPVAR opcodes.
102 : */
103 : static const uint16_t UPVAR_LEVEL_LIMIT = 16;
104 : static const uint16_t CALLEE_SLOT = 0xffff;
105 1101840 : static bool isLevelReserved(uint16_t level) { return level >= FREE_LEVEL; }
106 :
107 118801165 : bool isFree() const { return value == FREE_VALUE; }
108 520988 : uint32_t asInteger() const { return value; }
109 : /* isFree check should be performed before using these accessors. */
110 11144255 : uint16_t level() const { JS_ASSERT(!isFree()); return uint16_t(value >> 16); }
111 21786603 : uint16_t slot() const { JS_ASSERT(!isFree()); return uint16_t(value); }
112 :
113 : void set(const UpvarCookie &other) { set(other.level(), other.slot()); }
114 30966458 : void set(uint16_t newLevel, uint16_t newSlot) { value = (uint32_t(newLevel) << 16) | newSlot; }
115 21609523 : void makeFree() { set(0xffff, 0xffff); JS_ASSERT(isFree()); }
116 0 : void fromInteger(uint32_t u32) { value = u32; }
117 : };
118 :
119 : }
120 :
121 : /*
122 : * Exception handling record.
123 : */
124 : struct JSTryNote {
125 : uint8_t kind; /* one of JSTryNoteKind */
126 : uint8_t padding; /* explicit padding on uint16_t boundary */
127 : uint16_t stackDepth; /* stack depth upon exception handler entry */
128 : uint32_t start; /* start of the try statement or for-in loop
129 : relative to script->main */
130 : uint32_t length; /* length of the try statement or for-in loop */
131 : };
132 :
133 : typedef struct JSTryNoteArray {
134 : JSTryNote *vector; /* array of indexed try notes */
135 : uint32_t length; /* count of indexed try notes */
136 : } JSTryNoteArray;
137 :
138 : typedef struct JSObjectArray {
139 : js::HeapPtrObject *vector; /* array of indexed objects */
140 : uint32_t length; /* count of indexed objects */
141 : } JSObjectArray;
142 :
143 : typedef struct JSUpvarArray {
144 : js::UpvarCookie *vector; /* array of indexed upvar cookies */
145 : uint32_t length; /* count of indexed upvar cookies */
146 : } JSUpvarArray;
147 :
148 : typedef struct JSConstArray {
149 : js::HeapValue *vector; /* array of indexed constant values */
150 : uint32_t length;
151 : } JSConstArray;
152 :
153 : namespace js {
154 :
155 : struct GlobalSlotArray {
156 31216 : struct Entry {
157 : uint32_t atomIndex; /* index into atom table */
158 : uint32_t slot; /* global obj slot number */
159 : };
160 : Entry *vector;
161 : uint32_t length;
162 : };
163 :
164 : struct Shape;
165 :
166 : enum BindingKind { NONE, ARGUMENT, VARIABLE, CONSTANT, UPVAR };
167 :
168 : /*
169 : * Formal parameters, local variables, and upvars are stored in a shape tree
170 : * path encapsulated within this class. This class represents bindings for
171 : * both function and top-level scripts (the latter is needed to track names in
172 : * strict mode eval code, to give such code its own lexical environment).
173 : */
174 5995995 : class Bindings {
175 : HeapPtr<Shape> lastBinding;
176 : uint16_t nargs;
177 : uint16_t nvars;
178 : uint16_t nupvars;
179 : bool hasDup_:1; // true if there are duplicate argument names
180 :
181 : inline Shape *initialShape(JSContext *cx) const;
182 : public:
183 : inline Bindings(JSContext *cx);
184 :
185 : /*
186 : * Transfers ownership of bindings data from bindings into this fresh
187 : * Bindings instance. Once such a transfer occurs, the old bindings must
188 : * not be used again.
189 : */
190 : inline void transfer(JSContext *cx, Bindings *bindings);
191 :
192 : /*
193 : * Clones bindings data from bindings, which must be immutable, into this
194 : * fresh Bindings instance. A Bindings instance may be cloned multiple
195 : * times.
196 : */
197 : inline void clone(JSContext *cx, Bindings *bindings);
198 :
199 3438604 : uint16_t countArgs() const { return nargs; }
200 5619172 : uint16_t countVars() const { return nvars; }
201 6982580 : uint16_t countUpvars() const { return nupvars; }
202 :
203 701226 : unsigned countArgsAndVars() const { return nargs + nvars; }
204 :
205 825776 : unsigned countLocalNames() const { return nargs + nvars + nupvars; }
206 :
207 1144699 : bool hasUpvars() const { return nupvars > 0; }
208 391256 : bool hasLocalNames() const { return countLocalNames() > 0; }
209 :
210 : /* Ensure these bindings have a shape lineage. */
211 : inline bool ensureShape(JSContext *cx);
212 :
213 : /* Return the shape lineage generated for these bindings. */
214 : inline Shape *lastShape() const;
215 :
216 : /*
217 : * Return the shape to use to create a call object for these bindings.
218 : * The result is guaranteed not to have duplicate property names.
219 : */
220 : Shape *callObjectShape(JSContext *cx) const;
221 :
222 : /* See Scope::extensibleParents */
223 : inline bool extensibleParents();
224 : bool setExtensibleParents(JSContext *cx);
225 :
226 : bool setParent(JSContext *cx, JSObject *obj);
227 :
228 : enum {
229 : /*
230 : * A script may have no more than this many arguments, variables, or
231 : * upvars.
232 : */
233 : BINDING_COUNT_LIMIT = 0xFFFF
234 : };
235 :
236 : /*
237 : * Add a local binding for the given name, of the given type, for the code
238 : * being compiled. If fun is non-null, this binding set is being created
239 : * for that function, so adjust corresponding metadata in that function
240 : * while adding. Otherwise this set must correspond to a top-level script.
241 : *
242 : * A binding may be added twice with different kinds; the last one for a
243 : * given name prevails. (We preserve both bindings for the decompiler,
244 : * which must deal with such cases.) Pass null for name when indicating a
245 : * destructuring argument. Return true on success.
246 : *
247 : * The parser builds shape paths for functions, usable by Call objects at
248 : * runtime, by calling an "add" method. All ARGUMENT bindings must be added
249 : * before before any VARIABLE or CONSTANT bindings, which themselves must
250 : * be added before all UPVAR bindings.
251 : */
252 : bool add(JSContext *cx, JSAtom *name, BindingKind kind);
253 :
254 : /* Convenience specializations. */
255 41008 : bool addVariable(JSContext *cx, JSAtom *name) {
256 41008 : return add(cx, name, VARIABLE);
257 : }
258 : bool addConstant(JSContext *cx, JSAtom *name) {
259 : return add(cx, name, CONSTANT);
260 : }
261 112704 : bool addUpvar(JSContext *cx, JSAtom *name) {
262 112704 : return add(cx, name, UPVAR);
263 : }
264 1208443 : bool addArgument(JSContext *cx, JSAtom *name, uint16_t *slotp) {
265 1208443 : JS_ASSERT(name != NULL); /* not destructuring */
266 1208443 : *slotp = nargs;
267 1208443 : return add(cx, name, ARGUMENT);
268 : }
269 1556 : bool addDestructuring(JSContext *cx, uint16_t *slotp) {
270 1556 : *slotp = nargs;
271 1556 : return add(cx, NULL, ARGUMENT);
272 : }
273 :
274 18 : void noteDup() { hasDup_ = true; }
275 703452 : bool hasDup() const { return hasDup_; }
276 :
277 : /*
278 : * Look up an argument or variable name, returning its kind when found or
279 : * NONE when no such name exists. When indexp is not null and the name
280 : * exists, *indexp will receive the index of the corresponding argument or
281 : * variable.
282 : */
283 : BindingKind lookup(JSContext *cx, JSAtom *name, unsigned *indexp) const;
284 :
285 : /* Convenience method to check for any binding for a name. */
286 1588831 : bool hasBinding(JSContext *cx, JSAtom *name) const {
287 1588831 : return lookup(cx, name, NULL) != NONE;
288 : }
289 :
290 : /*
291 : * This method returns the local variable, argument, etc. names used by a
292 : * script. This function must be called only when hasLocalNames().
293 : *
294 : * The elements of the vector with index less than nargs correspond to the
295 : * the names of arguments. An index >= nargs addresses a var binding.
296 : * The name at an element will be null when the element is for an argument
297 : * corresponding to a destructuring pattern.
298 : */
299 : bool getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp);
300 :
301 : /*
302 : * Protect stored bindings from mutation. Subsequent attempts to add
303 : * bindings will copy the existing bindings before adding to them, allowing
304 : * the original bindings to be safely shared.
305 : */
306 : void makeImmutable();
307 :
308 : /*
309 : * These methods provide direct access to the shape path normally
310 : * encapsulated by js::Bindings. These methods may be used to make a
311 : * Shape::Range for iterating over the relevant shapes from youngest to
312 : * oldest (i.e., last or right-most to first or left-most in source order).
313 : *
314 : * Sometimes iteration order must be from oldest to youngest, however. For
315 : * such cases, use js::Bindings::getLocalNameArray.
316 : */
317 : const js::Shape *lastArgument() const;
318 : const js::Shape *lastVariable() const;
319 : const js::Shape *lastUpvar() const;
320 :
321 : void trace(JSTracer *trc);
322 :
323 : /* Rooter for stack allocated Bindings. */
324 2093498 : struct StackRoot {
325 : RootShape root;
326 2093498 : StackRoot(JSContext *cx, Bindings *bindings)
327 2093498 : : root(cx, (Shape **) &bindings->lastBinding)
328 2093498 : {}
329 : };
330 : };
331 :
332 : } /* namespace js */
333 :
334 : #define JS_OBJECT_ARRAY_SIZE(length) \
335 : (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length))
336 :
337 : #ifdef JS_METHODJIT
338 : namespace JSC {
339 : class ExecutablePool;
340 : }
341 :
342 : #define JS_UNJITTABLE_SCRIPT (reinterpret_cast<void*>(1))
343 :
344 : namespace js { namespace mjit { struct JITScript; } }
345 : #endif
346 :
347 : namespace js {
348 :
349 : namespace analyze { class ScriptAnalysis; }
350 :
351 : class ScriptOpcodeCounts
352 : {
353 : friend struct ::JSScript;
354 : friend struct ScriptOpcodeCountsPair;
355 : OpcodeCounts *counts;
356 :
357 : public:
358 :
359 0 : ScriptOpcodeCounts() : counts(NULL) {
360 0 : }
361 :
362 : inline void destroy(JSContext *cx);
363 :
364 0 : void steal(ScriptOpcodeCounts &other) {
365 0 : *this = other;
366 0 : js::PodZero(&other);
367 0 : }
368 :
369 : // Boolean conversion, for 'if (counters) ...'
370 -1737678852 : operator void*() const {
371 -1737678852 : return counts;
372 : }
373 : };
374 :
375 : class DebugScript
376 : {
377 : friend struct ::JSScript;
378 :
379 : /*
380 : * When non-zero, compile script in single-step mode. The top bit is set and
381 : * cleared by setStepMode, as used by JSD. The lower bits are a count,
382 : * adjusted by changeStepModeCount, used by the Debugger object. Only
383 : * when the bit is clear and the count is zero may we compile the script
384 : * without single-step support.
385 : */
386 : uint32_t stepMode;
387 :
388 : /* Number of breakpoint sites at opcodes in the script. */
389 : uint32_t numSites;
390 :
391 : /*
392 : * Array with all breakpoints installed at opcodes in the script, indexed
393 : * by the offset of the opcode into the script.
394 : */
395 : BreakpointSite *breakpoints[1];
396 : };
397 :
398 : } /* namespace js */
399 :
400 : static const uint32_t JS_SCRIPT_COOKIE = 0xc00cee;
401 :
402 : struct JSScript : public js::gc::Cell {
403 : /*
404 : * Two successively less primitive ways to make a new JSScript. The first
405 : * does *not* call a non-null cx->runtime->newScriptHook -- only the second,
406 : * NewScriptFromEmitter, calls this optional debugger hook.
407 : *
408 : * The NewScript function can't know whether the script it creates belongs
409 : * to a function, or is top-level or eval code, but the debugger wants access
410 : * to the newly made script's function, if any -- so callers of NewScript
411 : * are responsible for notifying the debugger after successfully creating any
412 : * kind (function or other) of new JSScript.
413 : */
414 : static JSScript *NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
415 : uint32_t nobjects, uint32_t nupvars, uint32_t nregexps,
416 : uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals,
417 : uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets,
418 : JSVersion version);
419 :
420 : static JSScript *NewScriptFromEmitter(JSContext *cx, js::BytecodeEmitter *bce);
421 :
422 : #ifdef JS_CRASH_DIAGNOSTICS
423 : /*
424 : * Make sure that the cookie size does not affect the GC alignment
425 : * requirements.
426 : */
427 : uint32_t cookie1[Cell::CellSize / sizeof(uint32_t)];
428 : #endif
429 : jsbytecode *code; /* bytecodes and their immediate operands */
430 : uint8_t *data; /* pointer to variable-length data array */
431 :
432 : uint32_t length; /* length of code vector */
433 : private:
434 : uint16_t version; /* JS version under which script was compiled */
435 :
436 : public:
437 : uint16_t nfixed; /* number of slots besides stack operands in
438 : slot array */
439 : /*
440 : * Offsets to various array structures from the end of this script, or
441 : * JSScript::INVALID_OFFSET if the array has length 0.
442 : */
443 : uint8_t objectsOffset; /* offset to the array of nested function,
444 : block, scope, xml and one-time regexps
445 : objects */
446 : uint8_t upvarsOffset; /* offset of the array of display ("up")
447 : closure vars */
448 : uint8_t regexpsOffset; /* offset to the array of to-be-cloned
449 : regexps */
450 : uint8_t trynotesOffset; /* offset to the array of try notes */
451 : uint8_t globalsOffset; /* offset to the array of global slots */
452 : uint8_t constOffset; /* offset to the array of constants */
453 :
454 : uint16_t nTypeSets; /* number of type sets used in this script for
455 : dynamic type monitoring */
456 :
457 : uint32_t lineno; /* base line number of script */
458 :
459 : uint32_t mainOffset; /* offset of main entry point from code, after
460 : predef'ing prolog */
461 : bool noScriptRval:1; /* no need for result value of last
462 : expression statement */
463 : bool savedCallerFun:1; /* can call getCallerFunction() */
464 : bool strictModeCode:1; /* code is in strict mode */
465 : bool compileAndGo:1; /* script was compiled with TCF_COMPILE_N_GO */
466 : bool usesEval:1; /* script uses eval() */
467 : bool usesArguments:1; /* script uses arguments */
468 : bool warnedAboutTwoArgumentEval:1; /* have warned about use of
469 : obsolete eval(s, o) in
470 : this script */
471 : bool warnedAboutUndefinedProp:1; /* have warned about uses of
472 : undefined properties in this
473 : script */
474 : bool hasSingletons:1; /* script has singleton objects */
475 : bool isOuterFunction:1; /* function is heavyweight, with inner functions */
476 : bool isInnerFunction:1; /* function is directly nested in a heavyweight
477 : * outer function */
478 : bool isActiveEval:1; /* script came from eval(), and is still active */
479 : bool isCachedEval:1; /* script came from eval(), and is in eval cache */
480 : bool usedLazyArgs:1; /* script has used lazy arguments at some point */
481 : bool createdArgs:1; /* script has had arguments objects created */
482 : bool uninlineable:1; /* script is considered uninlineable by analysis */
483 : bool reentrantOuterFunction:1; /* outer function marked reentrant */
484 : bool typesPurged:1; /* TypeScript has been purged at some point */
485 : #ifdef JS_METHODJIT
486 : bool debugMode:1; /* script was compiled in debug mode */
487 : bool failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
488 : #endif
489 : bool callDestroyHook:1;/* need to call destroy hook */
490 :
491 : uint32_t natoms; /* length of atoms array */
492 : uint16_t nslots; /* vars plus maximum stack depth */
493 : uint16_t staticLevel;/* static level for display maintenance */
494 :
495 : uint16_t nClosedArgs; /* number of args which are closed over. */
496 : uint16_t nClosedVars; /* number of vars which are closed over. */
497 :
498 : /*
499 : * To ensure sizeof(JSScript) % gc::Cell::CellSize == 0 on we must pad
500 : * the script with 4 bytes. We use them to store tiny scripts like empty
501 : * scripts.
502 : */
503 : #if JS_BITS_PER_WORD == 64
504 : #define JS_SCRIPT_INLINE_DATA_LIMIT 4
505 : uint8_t inlineData[JS_SCRIPT_INLINE_DATA_LIMIT];
506 : #endif
507 :
508 : const char *filename; /* source filename or null */
509 : JSAtom **atoms; /* maps immediate index to literal struct */
510 : private:
511 : size_t useCount; /* Number of times the script has been called
512 : * or has had backedges taken. Reset if the
513 : * script's JIT code is forcibly discarded. */
514 : public:
515 : js::Bindings bindings; /* names of top-level variables in this script
516 : (and arguments if this is a function script) */
517 : JSPrincipals *principals;/* principals for this script */
518 : JSPrincipals *originPrincipals; /* see jsapi.h 'originPrincipals' comment */
519 : jschar *sourceMap; /* source map file or null */
520 :
521 : /*
522 : * A global object for the script.
523 : * - All scripts returned by JSAPI functions (JS_CompileScript,
524 : * JS_CompileUTF8File, etc.) have a non-null globalObject.
525 : * - A function script has a globalObject if the function comes from a
526 : * compile-and-go script.
527 : * - Temporary scripts created by obj_eval, JS_EvaluateScript, and
528 : * similar functions never have the globalObject field set; for such
529 : * scripts the global should be extracted from the JS frame that
530 : * execute scripts.
531 : */
532 : js::HeapPtr<js::GlobalObject, JSScript*> globalObject;
533 :
534 : /* Hash table chaining for JSCompartment::evalCache. */
535 293618 : JSScript *&evalHashLink() { return *globalObject.unsafeGetUnioned(); }
536 :
537 : uint32_t *closedSlots; /* vector of closed slots; args first, then vars. */
538 :
539 : /* Execution and profiling information for JIT code in the script. */
540 : js::ScriptOpcodeCounts pcCounters;
541 :
542 : private:
543 : js::DebugScript *debug;
544 : js::HeapPtrFunction function_;
545 : public:
546 :
547 : /*
548 : * Original compiled function for the script, if it has a function.
549 : * NULL for global and eval scripts.
550 : */
551 133909610 : JSFunction *function() const { return function_; }
552 : void setFunction(JSFunction *fun);
553 :
554 : #ifdef JS_CRASH_DIAGNOSTICS
555 : /* All diagnostic fields must be multiples of Cell::CellSize. */
556 : uint32_t cookie2[Cell::CellSize / sizeof(uint32_t)];
557 :
558 : void CheckScript(JSScript *prev);
559 : #else
560 : void CheckScript(JSScript *prev) {}
561 : #endif /* !JS_CRASH_DIAGNOSTICS */
562 :
563 : #ifdef DEBUG
564 : /*
565 : * Unique identifier within the compartment for this script, used for
566 : * printing analysis information.
567 : */
568 : uint32_t id_;
569 : uint32_t idpad;
570 : unsigned id();
571 : #else
572 : unsigned id() { return 0; }
573 : #endif
574 :
575 : /* Persistent type information retained across GCs. */
576 : js::types::TypeScript *types;
577 :
578 : #if JS_BITS_PER_WORD == 32
579 : private:
580 : void *padding_;
581 : public:
582 : #endif
583 :
584 : /* Ensure the script has a TypeScript. */
585 : inline bool ensureHasTypes(JSContext *cx);
586 :
587 : /*
588 : * Ensure the script has scope and bytecode analysis information.
589 : * Performed when the script first runs, or first runs after a TypeScript
590 : * GC purge. If scope is NULL then the script must already have types with
591 : * scope information.
592 : */
593 : inline bool ensureRanAnalysis(JSContext *cx, JSObject *scope);
594 :
595 : /* Ensure the script has type inference analysis information. */
596 : inline bool ensureRanInference(JSContext *cx);
597 :
598 : inline bool hasAnalysis();
599 : inline void clearAnalysis();
600 : inline js::analyze::ScriptAnalysis *analysis();
601 :
602 : /*
603 : * Associates this script with a specific function, constructing a new type
604 : * object for the function if necessary.
605 : */
606 : bool typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton = false);
607 :
608 : inline bool hasGlobal() const;
609 : inline bool hasClearedGlobal() const;
610 :
611 : inline js::GlobalObject *global() const;
612 : inline js::types::TypeScriptNesting *nesting() const;
613 :
614 : inline void clearNesting();
615 :
616 : /* Return creation time global or null. */
617 1686 : js::GlobalObject *getGlobalObjectOrNull() const {
618 1686 : return isCachedEval ? NULL : globalObject.get();
619 : }
620 :
621 : private:
622 : bool makeTypes(JSContext *cx);
623 : bool makeAnalysis(JSContext *cx);
624 : public:
625 :
626 : #ifdef JS_METHODJIT
627 : // Fast-cached pointers to make calls faster. These are also used to
628 : // quickly test whether there is JIT code; a NULL value means no
629 : // compilation has been attempted. A JS_UNJITTABLE_SCRIPT value means
630 : // compilation failed. Any value is the arity-check entry point.
631 : void *jitArityCheckNormal;
632 : void *jitArityCheckCtor;
633 :
634 : js::mjit::JITScript *jitNormal; /* Extra JIT info for normal scripts */
635 : js::mjit::JITScript *jitCtor; /* Extra JIT info for constructors */
636 : #endif
637 :
638 : #ifdef JS_METHODJIT
639 48092 : bool hasJITCode() {
640 48092 : return jitNormal || jitCtor;
641 : }
642 :
643 : // These methods are implemented in MethodJIT.h.
644 : inline void **nativeMap(bool constructing);
645 : inline void *nativeCodeForPC(bool constructing, jsbytecode *pc);
646 :
647 39677746 : js::mjit::JITScript *getJIT(bool constructing) {
648 39677746 : return constructing ? jitCtor : jitNormal;
649 : }
650 :
651 26302 : size_t getUseCount() const { return useCount; }
652 9938535 : size_t incUseCount() { return ++useCount; }
653 2737 : size_t *addressOfUseCount() { return &useCount; }
654 8108534 : void resetUseCount() { useCount = 0; }
655 :
656 : /*
657 : * Size of the JITScript and all sections. If |mallocSizeOf| is NULL, the
658 : * size is computed analytically. (This method is implemented in
659 : * MethodJIT.cpp.)
660 : */
661 : size_t sizeOfJitScripts(JSMallocSizeOfFun mallocSizeOf);
662 :
663 : #endif
664 :
665 : /* Counter accessors. */
666 0 : js::OpcodeCounts getCounts(jsbytecode *pc) {
667 0 : JS_ASSERT(size_t(pc - code) < length);
668 0 : return pcCounters.counts[pc - code];
669 : }
670 :
671 : bool initCounts(JSContext *cx);
672 : void destroyCounts(JSContext *cx);
673 :
674 3470627 : jsbytecode *main() {
675 3470627 : return code + mainOffset;
676 : }
677 :
678 : /*
679 : * computedSizeOfData() is the in-use size of all the data sections.
680 : * sizeOfData() is the size of the block allocated to hold all the data sections
681 : * (which can be larger than the in-use size).
682 : */
683 : size_t computedSizeOfData();
684 : size_t sizeOfData(JSMallocSizeOfFun mallocSizeOf);
685 :
686 : uint32_t numNotes(); /* Number of srcnote slots in the srcnotes section */
687 :
688 : /* Script notes are allocated right after the code. */
689 38652984 : jssrcnote *notes() { return (jssrcnote *)(code + length); }
690 :
691 : static const uint8_t INVALID_OFFSET = 0xFF;
692 48493575 : static bool isValidOffset(uint8_t offset) { return offset != INVALID_OFFSET; }
693 :
694 9753379 : JSObjectArray *objects() {
695 9753379 : JS_ASSERT(isValidOffset(objectsOffset));
696 9753379 : return reinterpret_cast<JSObjectArray *>(data + objectsOffset);
697 : }
698 :
699 3141733 : JSUpvarArray *upvars() {
700 3141733 : JS_ASSERT(isValidOffset(upvarsOffset));
701 3141733 : return reinterpret_cast<JSUpvarArray *>(data + upvarsOffset);
702 : }
703 :
704 387713 : JSObjectArray *regexps() {
705 387713 : JS_ASSERT(isValidOffset(regexpsOffset));
706 387713 : return reinterpret_cast<JSObjectArray *>(data + regexpsOffset);
707 : }
708 :
709 1631955 : JSTryNoteArray *trynotes() {
710 1631955 : JS_ASSERT(isValidOffset(trynotesOffset));
711 1631955 : return reinterpret_cast<JSTryNoteArray *>(data + trynotesOffset);
712 : }
713 :
714 51196 : js::GlobalSlotArray *globals() {
715 51196 : JS_ASSERT(isValidOffset(globalsOffset));
716 51196 : return reinterpret_cast<js::GlobalSlotArray *>(data + globalsOffset);
717 : }
718 :
719 1653197 : JSConstArray *consts() {
720 1653197 : JS_ASSERT(isValidOffset(constOffset));
721 1653197 : return reinterpret_cast<JSConstArray *>(data + constOffset);
722 : }
723 :
724 35770964 : JSAtom *getAtom(size_t index) {
725 35770964 : JS_ASSERT(index < natoms);
726 35770964 : return atoms[index];
727 : }
728 :
729 2238353 : js::PropertyName *getName(size_t index) {
730 2238353 : return getAtom(index)->asPropertyName();
731 : }
732 :
733 4314897 : JSObject *getObject(size_t index) {
734 4314897 : JSObjectArray *arr = objects();
735 4314897 : JS_ASSERT(index < arr->length);
736 4314897 : return arr->vector[index];
737 : }
738 :
739 6435474 : JSVersion getVersion() const {
740 6435474 : return JSVersion(version);
741 : }
742 :
743 : inline JSFunction *getFunction(size_t index);
744 : inline JSFunction *getCallerFunction();
745 :
746 : inline JSObject *getRegExp(size_t index);
747 :
748 1515459 : const js::Value &getConst(size_t index) {
749 1515459 : JSConstArray *arr = consts();
750 1515459 : JS_ASSERT(index < arr->length);
751 1515459 : return arr->vector[index];
752 : }
753 :
754 : /*
755 : * The isEmpty method tells whether this script has code that computes any
756 : * result (not return value, result AKA normal completion value) other than
757 : * JSVAL_VOID, or any other effects.
758 : */
759 : inline bool isEmpty() const;
760 :
761 491553 : uint32_t getClosedArg(uint32_t index) {
762 491553 : JS_ASSERT(index < nClosedArgs);
763 491553 : return closedSlots[index];
764 : }
765 :
766 288961 : uint32_t getClosedVar(uint32_t index) {
767 288961 : JS_ASSERT(index < nClosedVars);
768 288961 : return closedSlots[nClosedArgs + index];
769 : }
770 :
771 : void copyClosedSlotsTo(JSScript *other);
772 :
773 : private:
774 : static const uint32_t stepFlagMask = 0x80000000U;
775 : static const uint32_t stepCountMask = 0x7fffffffU;
776 :
777 : /*
778 : * Attempt to recompile with or without single-stepping support, as directed
779 : * by stepModeEnabled().
780 : */
781 : bool recompileForStepMode(JSContext *cx);
782 :
783 : /* Attempt to change this->stepMode to |newValue|. */
784 : bool tryNewStepMode(JSContext *cx, uint32_t newValue);
785 :
786 : bool ensureHasDebug(JSContext *cx);
787 :
788 : public:
789 143689538 : bool hasBreakpointsAt(jsbytecode *pc) { return !!getBreakpointSite(pc); }
790 35516783 : bool hasAnyBreakpointsOrStepMode() { return !!debug; }
791 :
792 152606042 : js::BreakpointSite *getBreakpointSite(jsbytecode *pc)
793 : {
794 152606042 : JS_ASSERT(size_t(pc - code) < length);
795 152606042 : return debug ? debug->breakpoints[pc - code] : NULL;
796 : }
797 :
798 : js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
799 : js::GlobalObject *scriptGlobal);
800 :
801 : void destroyBreakpointSite(JSRuntime *rt, jsbytecode *pc);
802 :
803 : void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler);
804 : void clearTraps(JSContext *cx);
805 :
806 : void markTrapClosures(JSTracer *trc);
807 :
808 : /*
809 : * Set or clear the single-step flag. If the flag is set or the count
810 : * (adjusted by changeStepModeCount) is non-zero, then the script is in
811 : * single-step mode. (JSD uses an on/off-style interface; Debugger uses a
812 : * count-style interface.)
813 : */
814 : bool setStepModeFlag(JSContext *cx, bool step);
815 :
816 : /*
817 : * Increment or decrement the single-step count. If the count is non-zero or
818 : * the flag (set by setStepModeFlag) is set, then the script is in
819 : * single-step mode. (JSD uses an on/off-style interface; Debugger uses a
820 : * count-style interface.)
821 : */
822 : bool changeStepModeCount(JSContext *cx, int delta);
823 :
824 8846094 : bool stepModeEnabled() { return debug && !!debug->stepMode; }
825 :
826 : #ifdef DEBUG
827 5785 : uint32_t stepModeCount() { return debug ? (debug->stepMode & stepCountMask) : 0; }
828 : #endif
829 :
830 : void finalize(JSContext *cx, bool background);
831 :
832 : static inline void writeBarrierPre(JSScript *script);
833 : static inline void writeBarrierPost(JSScript *script, void *addr);
834 :
835 : static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SCRIPT; }
836 :
837 141277 : static JSPrincipals *normalizeOriginPrincipals(JSPrincipals *principals,
838 : JSPrincipals *originPrincipals) {
839 141277 : return originPrincipals ? originPrincipals : principals;
840 : }
841 :
842 : void markChildren(JSTracer *trc);
843 : };
844 :
845 : /* If this fails, padding_ can be removed. */
846 : JS_STATIC_ASSERT(sizeof(JSScript) % js::gc::Cell::CellSize == 0);
847 :
848 : static JS_INLINE unsigned
849 71057769 : StackDepth(JSScript *script)
850 : {
851 71057769 : return script->nslots - script->nfixed;
852 : }
853 :
854 : extern void
855 : js_MarkScriptFilename(const char *filename);
856 :
857 : extern void
858 : js_SweepScriptFilenames(JSCompartment *comp);
859 :
860 : /*
861 : * New-script-hook calling is factored from NewScriptFromEmitter so that it
862 : * and callers of XDRScript can share this code. In the case of callers
863 : * of XDRScript, the hook should be invoked only after successful decode
864 : * of any owning function (the fun parameter) or script object (null fun).
865 : */
866 : extern JS_FRIEND_API(void)
867 : js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun);
868 :
869 : extern void
870 : js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
871 :
872 : namespace js {
873 :
874 : struct ScriptOpcodeCountsPair
875 0 : {
876 : JSScript *script;
877 : ScriptOpcodeCounts counters;
878 :
879 0 : OpcodeCounts &getCounts(jsbytecode *pc) const {
880 0 : JS_ASSERT(unsigned(pc - script->code) < script->length);
881 0 : return counters.counts[pc - script->code];
882 : }
883 : };
884 :
885 : #ifdef JS_CRASH_DIAGNOSTICS
886 :
887 : void
888 : CheckScript(JSScript *script, JSScript *prev);
889 :
890 : #else
891 :
892 : inline void
893 : CheckScript(JSScript *script, JSScript *prev)
894 : {
895 : }
896 :
897 : #endif /* !JS_CRASH_DIAGNOSTICS */
898 :
899 : } /* namespace js */
900 :
901 : /*
902 : * To perturb as little code as possible, we introduce a js_GetSrcNote lookup
903 : * cache without adding an explicit cx parameter. Thus js_GetSrcNote becomes
904 : * a macro that uses cx from its calls' lexical environments.
905 : */
906 : #define js_GetSrcNote(script,pc) js_GetSrcNoteCached(cx, script, pc)
907 :
908 : extern jssrcnote *
909 : js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc);
910 :
911 : extern jsbytecode *
912 : js_LineNumberToPC(JSScript *script, unsigned lineno);
913 :
914 : extern JS_FRIEND_API(unsigned)
915 : js_GetScriptLineExtent(JSScript *script);
916 :
917 : namespace js {
918 :
919 : extern unsigned
920 : PCToLineNumber(JSScript *script, jsbytecode *pc);
921 :
922 : extern unsigned
923 : PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc);
924 :
925 : extern unsigned
926 : CurrentLine(JSContext *cx);
927 :
928 : /*
929 : * This function returns the file and line number of the script currently
930 : * executing on cx. If there is no current script executing on cx (e.g., a
931 : * native called directly through JSAPI (e.g., by setTimeout)), NULL and 0 are
932 : * returned as the file and line. Additionally, this function avoids the full
933 : * linear scan to compute line number when the caller guarnatees that the
934 : * script compilation occurs at a JSOP_EVAL.
935 : */
936 :
937 : enum LineOption {
938 : CALLED_FROM_JSOP_EVAL,
939 : NOT_CALLED_FROM_JSOP_EVAL
940 : };
941 :
942 : inline void
943 : CurrentScriptFileLineOrigin(JSContext *cx, unsigned *linenop, LineOption = NOT_CALLED_FROM_JSOP_EVAL);
944 :
945 : extern JSScript *
946 : CloneScript(JSContext *cx, JSScript *script);
947 :
948 : /*
949 : * NB: after a successful JSXDR_DECODE, XDRScript callers must do any
950 : * required subsequent set-up of owning function or script object and then call
951 : * js_CallNewScriptHook.
952 : */
953 : extern JSBool
954 : XDRScript(JSXDRState *xdr, JSScript **scriptp);
955 :
956 : }
957 :
958 : #endif /* jsscript_h___ */
|