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