js/src/jsscript.h

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /* JS script descriptor. */
michael@0 8
michael@0 9 #ifndef jsscript_h
michael@0 10 #define jsscript_h
michael@0 11
michael@0 12 #include "mozilla/MemoryReporting.h"
michael@0 13 #include "mozilla/PodOperations.h"
michael@0 14
michael@0 15 #include "jsatom.h"
michael@0 16 #ifdef JS_THREADSAFE
michael@0 17 #include "jslock.h"
michael@0 18 #endif
michael@0 19 #include "jsobj.h"
michael@0 20 #include "jsopcode.h"
michael@0 21 #include "jstypes.h"
michael@0 22
michael@0 23 #include "gc/Barrier.h"
michael@0 24 #include "gc/Rooting.h"
michael@0 25 #include "jit/IonCode.h"
michael@0 26 #include "vm/Shape.h"
michael@0 27
michael@0 28 namespace JS {
michael@0 29 struct ScriptSourceInfo;
michael@0 30 }
michael@0 31
michael@0 32 namespace js {
michael@0 33
michael@0 34 namespace jit {
michael@0 35 struct BaselineScript;
michael@0 36 struct IonScriptCounts;
michael@0 37 }
michael@0 38
michael@0 39 # define ION_DISABLED_SCRIPT ((js::jit::IonScript *)0x1)
michael@0 40 # define ION_COMPILING_SCRIPT ((js::jit::IonScript *)0x2)
michael@0 41
michael@0 42 # define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript *)0x1)
michael@0 43
michael@0 44 class BreakpointSite;
michael@0 45 class BindingIter;
michael@0 46 class LazyScript;
michael@0 47 class RegExpObject;
michael@0 48 struct SourceCompressionTask;
michael@0 49 class Shape;
michael@0 50 class WatchpointMap;
michael@0 51 class NestedScopeObject;
michael@0 52
michael@0 53 namespace frontend {
michael@0 54 class BytecodeEmitter;
michael@0 55 }
michael@0 56
michael@0 57 }
michael@0 58
michael@0 59 /*
michael@0 60 * Type of try note associated with each catch or finally block, and also with
michael@0 61 * for-in and other kinds of loops. Non-for-in loops do not need these notes
michael@0 62 * for exception unwinding, but storing their boundaries here is helpful for
michael@0 63 * heuristics that need to know whether a given op is inside a loop.
michael@0 64 */
michael@0 65 typedef enum JSTryNoteKind {
michael@0 66 JSTRY_CATCH,
michael@0 67 JSTRY_FINALLY,
michael@0 68 JSTRY_ITER,
michael@0 69 JSTRY_LOOP
michael@0 70 } JSTryNoteKind;
michael@0 71
michael@0 72 /*
michael@0 73 * Exception handling record.
michael@0 74 */
michael@0 75 struct JSTryNote {
michael@0 76 uint8_t kind; /* one of JSTryNoteKind */
michael@0 77 uint32_t stackDepth; /* stack depth upon exception handler entry */
michael@0 78 uint32_t start; /* start of the try statement or loop
michael@0 79 relative to script->main */
michael@0 80 uint32_t length; /* length of the try statement or loop */
michael@0 81 };
michael@0 82
michael@0 83 namespace js {
michael@0 84
michael@0 85 // A block scope has a range in bytecode: it is entered at some offset, and left
michael@0 86 // at some later offset. Scopes can be nested. Given an offset, the
michael@0 87 // BlockScopeNote containing that offset whose with the highest start value
michael@0 88 // indicates the block scope. The block scope list is sorted by increasing
michael@0 89 // start value.
michael@0 90 //
michael@0 91 // It is possible to leave a scope nonlocally, for example via a "break"
michael@0 92 // statement, so there may be short bytecode ranges in a block scope in which we
michael@0 93 // are popping the block chain in preparation for a goto. These exits are also
michael@0 94 // nested with respect to outer scopes. The scopes in these exits are indicated
michael@0 95 // by the "index" field, just like any other block. If a nonlocal exit pops the
michael@0 96 // last block scope, the index will be NoBlockScopeIndex.
michael@0 97 //
michael@0 98 struct BlockScopeNote {
michael@0 99 static const uint32_t NoBlockScopeIndex = UINT32_MAX;
michael@0 100
michael@0 101 uint32_t index; // Index of NestedScopeObject in the object
michael@0 102 // array, or NoBlockScopeIndex if there is no
michael@0 103 // block scope in this range.
michael@0 104 uint32_t start; // Bytecode offset at which this scope starts,
michael@0 105 // from script->main().
michael@0 106 uint32_t length; // Bytecode length of scope.
michael@0 107 uint32_t parent; // Index of parent block scope in notes, or UINT32_MAX.
michael@0 108 };
michael@0 109
michael@0 110 struct ConstArray {
michael@0 111 js::HeapValue *vector; /* array of indexed constant values */
michael@0 112 uint32_t length;
michael@0 113 };
michael@0 114
michael@0 115 struct ObjectArray {
michael@0 116 js::HeapPtrObject *vector; // Array of indexed objects.
michael@0 117 uint32_t length; // Count of indexed objects.
michael@0 118 };
michael@0 119
michael@0 120 struct TryNoteArray {
michael@0 121 JSTryNote *vector; // Array of indexed try notes.
michael@0 122 uint32_t length; // Count of indexed try notes.
michael@0 123 };
michael@0 124
michael@0 125 struct BlockScopeArray {
michael@0 126 BlockScopeNote *vector; // Array of indexed BlockScopeNote records.
michael@0 127 uint32_t length; // Count of indexed try notes.
michael@0 128 };
michael@0 129
michael@0 130 class Binding
michael@0 131 {
michael@0 132 // One JSScript stores one Binding per formal/variable so we use a
michael@0 133 // packed-word representation.
michael@0 134 uintptr_t bits_;
michael@0 135
michael@0 136 static const uintptr_t KIND_MASK = 0x3;
michael@0 137 static const uintptr_t ALIASED_BIT = 0x4;
michael@0 138 static const uintptr_t NAME_MASK = ~(KIND_MASK | ALIASED_BIT);
michael@0 139
michael@0 140 public:
michael@0 141 // A "binding" is a formal, 'var', or 'const' declaration. A function's
michael@0 142 // lexical scope is composed of these three kinds of bindings.
michael@0 143 enum Kind { ARGUMENT, VARIABLE, CONSTANT };
michael@0 144
michael@0 145 explicit Binding() : bits_(0) {}
michael@0 146
michael@0 147 Binding(PropertyName *name, Kind kind, bool aliased) {
michael@0 148 JS_STATIC_ASSERT(CONSTANT <= KIND_MASK);
michael@0 149 JS_ASSERT((uintptr_t(name) & ~NAME_MASK) == 0);
michael@0 150 JS_ASSERT((uintptr_t(kind) & ~KIND_MASK) == 0);
michael@0 151 bits_ = uintptr_t(name) | uintptr_t(kind) | (aliased ? ALIASED_BIT : 0);
michael@0 152 }
michael@0 153
michael@0 154 PropertyName *name() const {
michael@0 155 return (PropertyName *)(bits_ & NAME_MASK);
michael@0 156 }
michael@0 157
michael@0 158 Kind kind() const {
michael@0 159 return Kind(bits_ & KIND_MASK);
michael@0 160 }
michael@0 161
michael@0 162 bool aliased() const {
michael@0 163 return bool(bits_ & ALIASED_BIT);
michael@0 164 }
michael@0 165 };
michael@0 166
michael@0 167 JS_STATIC_ASSERT(sizeof(Binding) == sizeof(uintptr_t));
michael@0 168
michael@0 169 class Bindings;
michael@0 170 typedef InternalHandle<Bindings *> InternalBindingsHandle;
michael@0 171
michael@0 172 /*
michael@0 173 * Formal parameters and local variables are stored in a shape tree
michael@0 174 * path encapsulated within this class. This class represents bindings for
michael@0 175 * both function and top-level scripts (the latter is needed to track names in
michael@0 176 * strict mode eval code, to give such code its own lexical environment).
michael@0 177 */
michael@0 178 class Bindings
michael@0 179 {
michael@0 180 friend class BindingIter;
michael@0 181 friend class AliasedFormalIter;
michael@0 182
michael@0 183 HeapPtr<Shape> callObjShape_;
michael@0 184 uintptr_t bindingArrayAndFlag_;
michael@0 185 uint16_t numArgs_;
michael@0 186 uint16_t numBlockScoped_;
michael@0 187 uint32_t numVars_;
michael@0 188
michael@0 189 /*
michael@0 190 * During parsing, bindings are allocated out of a temporary LifoAlloc.
michael@0 191 * After parsing, a JSScript object is created and the bindings are
michael@0 192 * permanently transferred to it. On error paths, the JSScript object may
michael@0 193 * end up with bindings that still point to the (new released) LifoAlloc
michael@0 194 * memory. To avoid tracing these bindings during GC, we keep track of
michael@0 195 * whether the bindings are temporary or permanent in the low bit of
michael@0 196 * bindingArrayAndFlag_.
michael@0 197 */
michael@0 198 static const uintptr_t TEMPORARY_STORAGE_BIT = 0x1;
michael@0 199 bool bindingArrayUsingTemporaryStorage() const {
michael@0 200 return bindingArrayAndFlag_ & TEMPORARY_STORAGE_BIT;
michael@0 201 }
michael@0 202
michael@0 203 public:
michael@0 204
michael@0 205 Binding *bindingArray() const {
michael@0 206 return reinterpret_cast<Binding *>(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT);
michael@0 207 }
michael@0 208
michael@0 209 inline Bindings();
michael@0 210
michael@0 211 /*
michael@0 212 * Initialize a Bindings with a pointer into temporary storage.
michael@0 213 * bindingArray must have length numArgs+numVars. Before the temporary
michael@0 214 * storage is release, switchToScriptStorage must be called, providing a
michael@0 215 * pointer into the Binding array stored in script->data.
michael@0 216 */
michael@0 217 static bool initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
michael@0 218 unsigned numArgs, uint32_t numVars,
michael@0 219 Binding *bindingArray, unsigned numBlockScoped);
michael@0 220
michael@0 221 // CompileScript parses and compiles one statement at a time, but the result
michael@0 222 // is one Script object. There will be no vars or bindings, because those
michael@0 223 // go on the global, but there may be block-scoped locals, and the number of
michael@0 224 // block-scoped locals may increase as we parse more expressions. This
michael@0 225 // helper updates the number of block scoped variables in a script as it is
michael@0 226 // being parsed.
michael@0 227 void updateNumBlockScoped(unsigned numBlockScoped) {
michael@0 228 JS_ASSERT(!callObjShape_);
michael@0 229 JS_ASSERT(numVars_ == 0);
michael@0 230 JS_ASSERT(numBlockScoped < LOCALNO_LIMIT);
michael@0 231 JS_ASSERT(numBlockScoped >= numBlockScoped_);
michael@0 232 numBlockScoped_ = numBlockScoped;
michael@0 233 }
michael@0 234
michael@0 235 uint8_t *switchToScriptStorage(Binding *newStorage);
michael@0 236
michael@0 237 /*
michael@0 238 * Clone srcScript's bindings (as part of js::CloneScript). dstScriptData
michael@0 239 * is the pointer to what will eventually be dstScript->data.
michael@0 240 */
michael@0 241 static bool clone(JSContext *cx, InternalBindingsHandle self, uint8_t *dstScriptData,
michael@0 242 HandleScript srcScript);
michael@0 243
michael@0 244 unsigned numArgs() const { return numArgs_; }
michael@0 245 uint32_t numVars() const { return numVars_; }
michael@0 246 unsigned numBlockScoped() const { return numBlockScoped_; }
michael@0 247 uint32_t numLocals() const { return numVars() + numBlockScoped(); }
michael@0 248
michael@0 249 // Return the size of the bindingArray.
michael@0 250 uint32_t count() const { return numArgs() + numVars(); }
michael@0 251
michael@0 252 /* Return the initial shape of call objects created for this scope. */
michael@0 253 Shape *callObjShape() const { return callObjShape_; }
michael@0 254
michael@0 255 /* Convenience method to get the var index of 'arguments'. */
michael@0 256 static uint32_t argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle);
michael@0 257
michael@0 258 /* Return whether the binding at bindingIndex is aliased. */
michael@0 259 bool bindingIsAliased(uint32_t bindingIndex);
michael@0 260
michael@0 261 /* Return whether this scope has any aliased bindings. */
michael@0 262 bool hasAnyAliasedBindings() const {
michael@0 263 if (!callObjShape_)
michael@0 264 return false;
michael@0 265
michael@0 266 return !callObjShape_->isEmptyShape();
michael@0 267 }
michael@0 268
michael@0 269 void trace(JSTracer *trc);
michael@0 270 };
michael@0 271
michael@0 272 template <>
michael@0 273 struct GCMethods<Bindings> {
michael@0 274 static Bindings initial();
michael@0 275 static ThingRootKind kind() { return THING_ROOT_BINDINGS; }
michael@0 276 static bool poisoned(const Bindings &bindings) {
michael@0 277 return IsPoisonedPtr(static_cast<Shape *>(bindings.callObjShape()));
michael@0 278 }
michael@0 279 };
michael@0 280
michael@0 281 class ScriptCounts
michael@0 282 {
michael@0 283 friend class ::JSScript;
michael@0 284 friend struct ScriptAndCounts;
michael@0 285
michael@0 286 /*
michael@0 287 * This points to a single block that holds an array of PCCounts followed
michael@0 288 * by an array of doubles. Each element in the PCCounts array has a
michael@0 289 * pointer into the array of doubles.
michael@0 290 */
michael@0 291 PCCounts *pcCountsVector;
michael@0 292
michael@0 293 /* Information about any Ion compilations for the script. */
michael@0 294 jit::IonScriptCounts *ionCounts;
michael@0 295
michael@0 296 public:
michael@0 297 ScriptCounts() : pcCountsVector(nullptr), ionCounts(nullptr) { }
michael@0 298
michael@0 299 inline void destroy(FreeOp *fop);
michael@0 300
michael@0 301 void set(js::ScriptCounts counts) {
michael@0 302 pcCountsVector = counts.pcCountsVector;
michael@0 303 ionCounts = counts.ionCounts;
michael@0 304 }
michael@0 305 };
michael@0 306
michael@0 307 typedef HashMap<JSScript *,
michael@0 308 ScriptCounts,
michael@0 309 DefaultHasher<JSScript *>,
michael@0 310 SystemAllocPolicy> ScriptCountsMap;
michael@0 311
michael@0 312 class DebugScript
michael@0 313 {
michael@0 314 friend class ::JSScript;
michael@0 315
michael@0 316 /*
michael@0 317 * When non-zero, compile script in single-step mode. The top bit is set and
michael@0 318 * cleared by setStepMode, as used by JSD. The lower bits are a count,
michael@0 319 * adjusted by changeStepModeCount, used by the Debugger object. Only
michael@0 320 * when the bit is clear and the count is zero may we compile the script
michael@0 321 * without single-step support.
michael@0 322 */
michael@0 323 uint32_t stepMode;
michael@0 324
michael@0 325 /* Number of breakpoint sites at opcodes in the script. */
michael@0 326 uint32_t numSites;
michael@0 327
michael@0 328 /*
michael@0 329 * Array with all breakpoints installed at opcodes in the script, indexed
michael@0 330 * by the offset of the opcode into the script.
michael@0 331 */
michael@0 332 BreakpointSite *breakpoints[1];
michael@0 333 };
michael@0 334
michael@0 335 typedef HashMap<JSScript *,
michael@0 336 DebugScript *,
michael@0 337 DefaultHasher<JSScript *>,
michael@0 338 SystemAllocPolicy> DebugScriptMap;
michael@0 339
michael@0 340 class ScriptSource;
michael@0 341
michael@0 342 class SourceDataCache
michael@0 343 {
michael@0 344 typedef HashMap<ScriptSource *,
michael@0 345 const jschar *,
michael@0 346 DefaultHasher<ScriptSource *>,
michael@0 347 SystemAllocPolicy> Map;
michael@0 348
michael@0 349 public:
michael@0 350 // Hold an entry in the source data cache and prevent it from being purged on GC.
michael@0 351 class AutoHoldEntry
michael@0 352 {
michael@0 353 SourceDataCache *cache_;
michael@0 354 ScriptSource *source_;
michael@0 355 const jschar *charsToFree_;
michael@0 356 public:
michael@0 357 explicit AutoHoldEntry();
michael@0 358 ~AutoHoldEntry();
michael@0 359 private:
michael@0 360 void holdEntry(SourceDataCache *cache, ScriptSource *source);
michael@0 361 void deferDelete(const jschar *chars);
michael@0 362 ScriptSource *source() const { return source_; }
michael@0 363 friend class SourceDataCache;
michael@0 364 };
michael@0 365
michael@0 366 private:
michael@0 367 Map *map_;
michael@0 368 AutoHoldEntry *holder_;
michael@0 369
michael@0 370 public:
michael@0 371 SourceDataCache() : map_(nullptr), holder_(nullptr) {}
michael@0 372
michael@0 373 const jschar *lookup(ScriptSource *ss, AutoHoldEntry &asp);
michael@0 374 bool put(ScriptSource *ss, const jschar *chars, AutoHoldEntry &asp);
michael@0 375
michael@0 376 void purge();
michael@0 377
michael@0 378 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
michael@0 379
michael@0 380 private:
michael@0 381 void holdEntry(AutoHoldEntry &holder, ScriptSource *ss);
michael@0 382 void releaseEntry(AutoHoldEntry &holder);
michael@0 383 };
michael@0 384
michael@0 385 class ScriptSource
michael@0 386 {
michael@0 387 friend class SourceCompressionTask;
michael@0 388
michael@0 389 // A note on concurrency:
michael@0 390 //
michael@0 391 // The source may be compressed by a worker thread during parsing. (See
michael@0 392 // SourceCompressionTask.) When compression is running in the background,
michael@0 393 // ready() returns false. The compression thread touches the |data| union
michael@0 394 // and |compressedLength_|. Therefore, it is not safe to read these members
michael@0 395 // unless ready() is true. With that said, users of the public ScriptSource
michael@0 396 // API should be fine.
michael@0 397
michael@0 398 union {
michael@0 399 // Before setSourceCopy or setSource are successfully called, this union
michael@0 400 // has a nullptr pointer. When the script source is ready,
michael@0 401 // compressedLength_ != 0 implies compressed holds the compressed data;
michael@0 402 // otherwise, source holds the uncompressed source. There is a special
michael@0 403 // pointer |emptySource| for source code for length 0.
michael@0 404 //
michael@0 405 // The only function allowed to malloc, realloc, or free the pointers in
michael@0 406 // this union is adjustDataSize(). Don't do it elsewhere.
michael@0 407 jschar *source;
michael@0 408 unsigned char *compressed;
michael@0 409 } data;
michael@0 410 uint32_t refs;
michael@0 411 uint32_t length_;
michael@0 412 uint32_t compressedLength_;
michael@0 413 char *filename_;
michael@0 414 jschar *displayURL_;
michael@0 415 jschar *sourceMapURL_;
michael@0 416 JSPrincipals *originPrincipals_;
michael@0 417
michael@0 418 // bytecode offset in caller script that generated this code.
michael@0 419 // This is present for eval-ed code, as well as "new Function(...)"-introduced
michael@0 420 // scripts.
michael@0 421 uint32_t introductionOffset_;
michael@0 422
michael@0 423 // If this ScriptSource was generated by a code-introduction mechanism such as |eval|
michael@0 424 // or |new Function|, the debugger needs access to the "raw" filename of the top-level
michael@0 425 // script that contains the eval-ing code. To keep track of this, we must preserve
michael@0 426 // the original outermost filename (of the original introducer script), so that instead
michael@0 427 // of a filename of "foo.js line 30 > eval line 10 > Function", we can obtain the
michael@0 428 // original raw filename of "foo.js".
michael@0 429 char *introducerFilename_;
michael@0 430
michael@0 431 // A string indicating how this source code was introduced into the system.
michael@0 432 // This accessor returns one of the following values:
michael@0 433 // "eval" for code passed to |eval|.
michael@0 434 // "Function" for code passed to the |Function| constructor.
michael@0 435 // "Worker" for code loaded by calling the Web worker constructor&mdash;the worker's main script.
michael@0 436 // "importScripts" for code by calling |importScripts| in a web worker.
michael@0 437 // "handler" for code assigned to DOM elements' event handler IDL attributes.
michael@0 438 // "scriptElement" for code belonging to <script> elements.
michael@0 439 // undefined if the implementation doesn't know how the code was introduced.
michael@0 440 // This is a constant, statically allocated C string, so does not need
michael@0 441 // memory management.
michael@0 442 const char *introductionType_;
michael@0 443
michael@0 444 // True if we can call JSRuntime::sourceHook to load the source on
michael@0 445 // demand. If sourceRetrievable_ and hasSourceData() are false, it is not
michael@0 446 // possible to get source at all.
michael@0 447 bool sourceRetrievable_:1;
michael@0 448 bool argumentsNotIncluded_:1;
michael@0 449 bool ready_:1;
michael@0 450 bool hasIntroductionOffset_:1;
michael@0 451
michael@0 452 public:
michael@0 453 explicit ScriptSource()
michael@0 454 : refs(0),
michael@0 455 length_(0),
michael@0 456 compressedLength_(0),
michael@0 457 filename_(nullptr),
michael@0 458 displayURL_(nullptr),
michael@0 459 sourceMapURL_(nullptr),
michael@0 460 originPrincipals_(nullptr),
michael@0 461 introductionOffset_(0),
michael@0 462 introducerFilename_(nullptr),
michael@0 463 introductionType_(nullptr),
michael@0 464 sourceRetrievable_(false),
michael@0 465 argumentsNotIncluded_(false),
michael@0 466 ready_(true),
michael@0 467 hasIntroductionOffset_(false)
michael@0 468 {
michael@0 469 data.source = nullptr;
michael@0 470 }
michael@0 471 void incref() { refs++; }
michael@0 472 void decref() {
michael@0 473 JS_ASSERT(refs != 0);
michael@0 474 if (--refs == 0)
michael@0 475 destroy();
michael@0 476 }
michael@0 477 bool initFromOptions(ExclusiveContext *cx, const ReadOnlyCompileOptions &options);
michael@0 478 bool setSourceCopy(ExclusiveContext *cx,
michael@0 479 JS::SourceBufferHolder &srcBuf,
michael@0 480 bool argumentsNotIncluded,
michael@0 481 SourceCompressionTask *tok);
michael@0 482 void setSource(const jschar *src, size_t length);
michael@0 483 bool ready() const { return ready_; }
michael@0 484 void setSourceRetrievable() { sourceRetrievable_ = true; }
michael@0 485 bool sourceRetrievable() const { return sourceRetrievable_; }
michael@0 486 bool hasSourceData() const { return !ready() || !!data.source; }
michael@0 487 uint32_t length() const {
michael@0 488 JS_ASSERT(hasSourceData());
michael@0 489 return length_;
michael@0 490 }
michael@0 491 bool argumentsNotIncluded() const {
michael@0 492 JS_ASSERT(hasSourceData());
michael@0 493 return argumentsNotIncluded_;
michael@0 494 }
michael@0 495 const jschar *chars(JSContext *cx, SourceDataCache::AutoHoldEntry &asp);
michael@0 496 JSFlatString *substring(JSContext *cx, uint32_t start, uint32_t stop);
michael@0 497 void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
michael@0 498 JS::ScriptSourceInfo *info) const;
michael@0 499
michael@0 500 // XDR handling
michael@0 501 template <XDRMode mode>
michael@0 502 bool performXDR(XDRState<mode> *xdr);
michael@0 503
michael@0 504 bool setFilename(ExclusiveContext *cx, const char *filename);
michael@0 505 const char *introducerFilename() const {
michael@0 506 return introducerFilename_;
michael@0 507 }
michael@0 508 bool hasIntroductionType() const {
michael@0 509 return introductionType_;
michael@0 510 }
michael@0 511 const char *introductionType() const {
michael@0 512 JS_ASSERT(hasIntroductionType());
michael@0 513 return introductionType_;
michael@0 514 }
michael@0 515 const char *filename() const {
michael@0 516 return filename_;
michael@0 517 }
michael@0 518
michael@0 519 // Display URLs
michael@0 520 bool setDisplayURL(ExclusiveContext *cx, const jschar *displayURL);
michael@0 521 const jschar *displayURL();
michael@0 522 bool hasDisplayURL() const { return displayURL_ != nullptr; }
michael@0 523
michael@0 524 // Source maps
michael@0 525 bool setSourceMapURL(ExclusiveContext *cx, const jschar *sourceMapURL);
michael@0 526 const jschar *sourceMapURL();
michael@0 527 bool hasSourceMapURL() const { return sourceMapURL_ != nullptr; }
michael@0 528
michael@0 529 JSPrincipals *originPrincipals() const { return originPrincipals_; }
michael@0 530
michael@0 531 bool hasIntroductionOffset() const { return hasIntroductionOffset_; }
michael@0 532 uint32_t introductionOffset() const {
michael@0 533 JS_ASSERT(hasIntroductionOffset());
michael@0 534 return introductionOffset_;
michael@0 535 }
michael@0 536 void setIntroductionOffset(uint32_t offset) {
michael@0 537 JS_ASSERT(!hasIntroductionOffset());
michael@0 538 JS_ASSERT(offset <= (uint32_t)INT32_MAX);
michael@0 539 introductionOffset_ = offset;
michael@0 540 hasIntroductionOffset_ = true;
michael@0 541 }
michael@0 542
michael@0 543 private:
michael@0 544 void destroy();
michael@0 545 bool compressed() const { return compressedLength_ != 0; }
michael@0 546 size_t computedSizeOfData() const {
michael@0 547 return compressed() ? compressedLength_ : sizeof(jschar) * length_;
michael@0 548 }
michael@0 549 bool adjustDataSize(size_t nbytes);
michael@0 550 const jschar *getOffThreadCompressionChars(ExclusiveContext *cx);
michael@0 551 };
michael@0 552
michael@0 553 class ScriptSourceHolder
michael@0 554 {
michael@0 555 ScriptSource *ss;
michael@0 556 public:
michael@0 557 explicit ScriptSourceHolder(ScriptSource *ss)
michael@0 558 : ss(ss)
michael@0 559 {
michael@0 560 ss->incref();
michael@0 561 }
michael@0 562 ~ScriptSourceHolder()
michael@0 563 {
michael@0 564 ss->decref();
michael@0 565 }
michael@0 566 };
michael@0 567
michael@0 568 class ScriptSourceObject : public JSObject
michael@0 569 {
michael@0 570 public:
michael@0 571 static const Class class_;
michael@0 572
michael@0 573 static void trace(JSTracer *trc, JSObject *obj);
michael@0 574 static void finalize(FreeOp *fop, JSObject *obj);
michael@0 575 static ScriptSourceObject *create(ExclusiveContext *cx, ScriptSource *source,
michael@0 576 const ReadOnlyCompileOptions &options);
michael@0 577
michael@0 578 ScriptSource *source() {
michael@0 579 return static_cast<ScriptSource *>(getReservedSlot(SOURCE_SLOT).toPrivate());
michael@0 580 }
michael@0 581
michael@0 582 void setSource(ScriptSource *source);
michael@0 583
michael@0 584 JSObject *element() const;
michael@0 585 void initElement(HandleObject element);
michael@0 586 const Value &elementAttributeName() const;
michael@0 587
michael@0 588 JSScript *introductionScript() const {
michael@0 589 void *untyped = getReservedSlot(INTRODUCTION_SCRIPT_SLOT).toPrivate();
michael@0 590 return static_cast<JSScript *>(untyped);
michael@0 591 }
michael@0 592 void initIntroductionScript(JSScript *script);
michael@0 593
michael@0 594 private:
michael@0 595 static const uint32_t SOURCE_SLOT = 0;
michael@0 596 static const uint32_t ELEMENT_SLOT = 1;
michael@0 597 static const uint32_t ELEMENT_PROPERTY_SLOT = 2;
michael@0 598 static const uint32_t INTRODUCTION_SCRIPT_SLOT = 3;
michael@0 599 static const uint32_t RESERVED_SLOTS = 4;
michael@0 600 };
michael@0 601
michael@0 602 enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };
michael@0 603
michael@0 604 static inline unsigned
michael@0 605 GeneratorKindAsBits(GeneratorKind generatorKind) {
michael@0 606 return static_cast<unsigned>(generatorKind);
michael@0 607 }
michael@0 608
michael@0 609 static inline GeneratorKind
michael@0 610 GeneratorKindFromBits(unsigned val) {
michael@0 611 JS_ASSERT(val <= StarGenerator);
michael@0 612 return static_cast<GeneratorKind>(val);
michael@0 613 }
michael@0 614
michael@0 615 /*
michael@0 616 * NB: after a successful XDR_DECODE, XDRScript callers must do any required
michael@0 617 * subsequent set-up of owning function or script object and then call
michael@0 618 * js_CallNewScriptHook.
michael@0 619 */
michael@0 620 template<XDRMode mode>
michael@0 621 bool
michael@0 622 XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
michael@0 623 HandleFunction fun, MutableHandleScript scriptp);
michael@0 624
michael@0 625 JSScript *
michael@0 626 CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, HandleScript script,
michael@0 627 NewObjectKind newKind = GenericObject);
michael@0 628
michael@0 629 template<XDRMode mode>
michael@0 630 bool
michael@0 631 XDRLazyScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
michael@0 632 HandleFunction fun, MutableHandle<LazyScript *> lazy);
michael@0 633
michael@0 634 /*
michael@0 635 * Code any constant value.
michael@0 636 */
michael@0 637 template<XDRMode mode>
michael@0 638 bool
michael@0 639 XDRScriptConst(XDRState<mode> *xdr, MutableHandleValue vp);
michael@0 640
michael@0 641 } /* namespace js */
michael@0 642
michael@0 643 class JSScript : public js::gc::BarrieredCell<JSScript>
michael@0 644 {
michael@0 645 static const uint32_t stepFlagMask = 0x80000000U;
michael@0 646 static const uint32_t stepCountMask = 0x7fffffffU;
michael@0 647
michael@0 648 template <js::XDRMode mode>
michael@0 649 friend
michael@0 650 bool
michael@0 651 js::XDRScript(js::XDRState<mode> *xdr, js::HandleObject enclosingScope, js::HandleScript enclosingScript,
michael@0 652 js::HandleFunction fun, js::MutableHandleScript scriptp);
michael@0 653
michael@0 654 friend JSScript *
michael@0 655 js::CloneScript(JSContext *cx, js::HandleObject enclosingScope, js::HandleFunction fun, js::HandleScript src,
michael@0 656 js::NewObjectKind newKind);
michael@0 657
michael@0 658 public:
michael@0 659 //
michael@0 660 // We order fields according to their size in order to avoid wasting space
michael@0 661 // for alignment.
michael@0 662 //
michael@0 663
michael@0 664 // Larger-than-word-sized fields.
michael@0 665
michael@0 666 public:
michael@0 667 js::Bindings bindings; /* names of top-level variables in this script
michael@0 668 (and arguments if this is a function script) */
michael@0 669
michael@0 670 bool hasAnyAliasedBindings() const {
michael@0 671 return bindings.hasAnyAliasedBindings();
michael@0 672 }
michael@0 673
michael@0 674 js::Binding *bindingArray() const {
michael@0 675 return bindings.bindingArray();
michael@0 676 }
michael@0 677
michael@0 678 unsigned numArgs() const {
michael@0 679 return bindings.numArgs();
michael@0 680 }
michael@0 681
michael@0 682 js::Shape *callObjShape() const {
michael@0 683 return bindings.callObjShape();
michael@0 684 }
michael@0 685
michael@0 686 // Word-sized fields.
michael@0 687
michael@0 688 private:
michael@0 689 jsbytecode *code_; /* bytecodes and their immediate operands */
michael@0 690 public:
michael@0 691 uint8_t *data; /* pointer to variable-length data array (see
michael@0 692 comment above Create() for details) */
michael@0 693
michael@0 694 js::HeapPtrAtom *atoms; /* maps immediate index to literal struct */
michael@0 695
michael@0 696 JSCompartment *compartment_;
michael@0 697
michael@0 698 /* Persistent type information retained across GCs. */
michael@0 699 js::types::TypeScript *types;
michael@0 700
michael@0 701 private:
michael@0 702 // This script's ScriptSourceObject, or a CCW thereof.
michael@0 703 //
michael@0 704 // (When we clone a JSScript into a new compartment, we don't clone its
michael@0 705 // source object. Instead, the clone refers to a wrapper.)
michael@0 706 js::HeapPtrObject sourceObject_;
michael@0 707
michael@0 708 js::HeapPtrFunction function_;
michael@0 709
michael@0 710 // For callsite clones, which cannot have enclosing scopes, the original
michael@0 711 // function; otherwise the enclosing scope
michael@0 712 js::HeapPtrObject enclosingScopeOrOriginalFunction_;
michael@0 713
michael@0 714 /* Information attached by Baseline/Ion for sequential mode execution. */
michael@0 715 js::jit::IonScript *ion;
michael@0 716 js::jit::BaselineScript *baseline;
michael@0 717
michael@0 718 /* Information attached by Ion for parallel mode execution */
michael@0 719 js::jit::IonScript *parallelIon;
michael@0 720
michael@0 721 /* Information used to re-lazify a lazily-parsed interpreted function. */
michael@0 722 js::LazyScript *lazyScript;
michael@0 723
michael@0 724 /*
michael@0 725 * Pointer to either baseline->method()->raw() or ion->method()->raw(), or
michael@0 726 * nullptr if there's no Baseline or Ion script.
michael@0 727 */
michael@0 728 uint8_t *baselineOrIonRaw;
michael@0 729 uint8_t *baselineOrIonSkipArgCheck;
michael@0 730
michael@0 731 // 32-bit fields.
michael@0 732
michael@0 733 uint32_t length_; /* length of code vector */
michael@0 734 uint32_t dataSize_; /* size of the used part of the data array */
michael@0 735
michael@0 736 uint32_t lineno_; /* base line number of script */
michael@0 737 uint32_t column_; /* base column of script, optionally set */
michael@0 738
michael@0 739 uint32_t mainOffset_;/* offset of main entry point from code, after
michael@0 740 predef'ing prolog */
michael@0 741
michael@0 742 uint32_t natoms_; /* length of atoms array */
michael@0 743 uint32_t nslots_; /* vars plus maximum stack depth */
michael@0 744
michael@0 745 /* Range of characters in scriptSource which contains this script's source. */
michael@0 746 uint32_t sourceStart_;
michael@0 747 uint32_t sourceEnd_;
michael@0 748
michael@0 749 uint32_t useCount; /* Number of times the script has been called
michael@0 750 * or has had backedges taken. When running in
michael@0 751 * ion, also increased for any inlined scripts.
michael@0 752 * Reset if the script's JIT code is forcibly
michael@0 753 * discarded. */
michael@0 754
michael@0 755 #ifdef DEBUG
michael@0 756 // Unique identifier within the compartment for this script, used for
michael@0 757 // printing analysis information.
michael@0 758 uint32_t id_;
michael@0 759 uint32_t idpad;
michael@0 760 #endif
michael@0 761
michael@0 762 // 16-bit fields.
michael@0 763
michael@0 764 uint16_t version; /* JS version under which script was compiled */
michael@0 765
michael@0 766 uint16_t funLength_; /* ES6 function length */
michael@0 767
michael@0 768 uint16_t nTypeSets_; /* number of type sets used in this script for
michael@0 769 dynamic type monitoring */
michael@0 770
michael@0 771 uint16_t staticLevel_;/* static level for display maintenance */
michael@0 772
michael@0 773 // Bit fields.
michael@0 774
michael@0 775 public:
michael@0 776 // The kinds of the optional arrays.
michael@0 777 enum ArrayKind {
michael@0 778 CONSTS,
michael@0 779 OBJECTS,
michael@0 780 REGEXPS,
michael@0 781 TRYNOTES,
michael@0 782 BLOCK_SCOPES,
michael@0 783 ARRAY_KIND_BITS
michael@0 784 };
michael@0 785
michael@0 786 private:
michael@0 787 // The bits in this field indicate the presence/non-presence of several
michael@0 788 // optional arrays in |data|. See the comments above Create() for details.
michael@0 789 uint8_t hasArrayBits:ARRAY_KIND_BITS;
michael@0 790
michael@0 791 // The GeneratorKind of the script.
michael@0 792 uint8_t generatorKindBits_:2;
michael@0 793
michael@0 794 // 1-bit fields.
michael@0 795
michael@0 796 // No need for result value of last expression statement.
michael@0 797 bool noScriptRval_:1;
michael@0 798
michael@0 799 // Can call getCallerFunction().
michael@0 800 bool savedCallerFun_:1;
michael@0 801
michael@0 802 // Code is in strict mode.
michael@0 803 bool strict_:1;
michael@0 804
michael@0 805 // Code has "use strict"; explicitly.
michael@0 806 bool explicitUseStrict_:1;
michael@0 807
michael@0 808 // See Parser::compileAndGo.
michael@0 809 bool compileAndGo_:1;
michael@0 810
michael@0 811 // see Parser::selfHostingMode.
michael@0 812 bool selfHosted_:1;
michael@0 813
michael@0 814 // See FunctionContextFlags.
michael@0 815 bool bindingsAccessedDynamically_:1;
michael@0 816 bool funHasExtensibleScope_:1;
michael@0 817 bool funNeedsDeclEnvObject_:1;
michael@0 818
michael@0 819 // True if any formalIsAliased(i).
michael@0 820 bool funHasAnyAliasedFormal_:1;
michael@0 821
michael@0 822 // Have warned about uses of undefined properties in this script.
michael@0 823 bool warnedAboutUndefinedProp_:1;
michael@0 824
michael@0 825 // Script has singleton objects.
michael@0 826 bool hasSingletons_:1;
michael@0 827
michael@0 828 // Script is a lambda to treat as running once.
michael@0 829 bool treatAsRunOnce_:1;
michael@0 830
michael@0 831 // If treatAsRunOnce, whether script has executed.
michael@0 832 bool hasRunOnce_:1;
michael@0 833
michael@0 834 // Script has been reused for a clone.
michael@0 835 bool hasBeenCloned_:1;
michael@0 836
michael@0 837 // Script has been inlined at least once, and can't be relazified.
michael@0 838 bool hasBeenInlined_:1;
michael@0 839
michael@0 840 // Script came from eval(), and is still active.
michael@0 841 bool isActiveEval_:1;
michael@0 842
michael@0 843 // Script came from eval(), and is in eval cache.
michael@0 844 bool isCachedEval_:1;
michael@0 845
michael@0 846 // Set for functions defined at the top level within an 'eval' script.
michael@0 847 bool directlyInsideEval_:1;
michael@0 848
michael@0 849 // Both 'arguments' and f.apply() are used. This is likely to be a wrapper.
michael@0 850 bool usesArgumentsAndApply_:1;
michael@0 851
michael@0 852 /* script is attempted to be cloned anew at each callsite. This is
michael@0 853 temporarily needed for ParallelArray selfhosted code until type
michael@0 854 information can be made context sensitive. See discussion in
michael@0 855 bug 826148. */
michael@0 856 bool shouldCloneAtCallsite_:1;
michael@0 857 bool isCallsiteClone_:1; /* is a callsite clone; has a link to the original function */
michael@0 858 bool shouldInline_:1; /* hint to inline when possible */
michael@0 859
michael@0 860 // IonMonkey compilation hints.
michael@0 861 bool failedBoundsCheck_:1; /* script has had hoisted bounds checks fail */
michael@0 862 bool failedShapeGuard_:1; /* script has had hoisted shape guard fail */
michael@0 863 bool hadFrequentBailouts_:1;
michael@0 864 bool uninlineable_:1; /* explicitly marked as uninlineable */
michael@0 865
michael@0 866 // Idempotent cache has triggered invalidation.
michael@0 867 bool invalidatedIdempotentCache_:1;
michael@0 868
michael@0 869 // If the generator was created implicitly via a generator expression,
michael@0 870 // isGeneratorExp will be true.
michael@0 871 bool isGeneratorExp_:1;
michael@0 872
michael@0 873 // Script has an entry in JSCompartment::scriptCountsMap.
michael@0 874 bool hasScriptCounts_:1;
michael@0 875
michael@0 876 // Script has an entry in JSCompartment::debugScriptMap.
michael@0 877 bool hasDebugScript_:1;
michael@0 878
michael@0 879 // Freeze constraints for stack type sets have been generated.
michael@0 880 bool hasFreezeConstraints_:1;
michael@0 881
michael@0 882 /* See comments below. */
michael@0 883 bool argsHasVarBinding_:1;
michael@0 884 bool needsArgsAnalysis_:1;
michael@0 885 bool needsArgsObj_:1;
michael@0 886
michael@0 887 //
michael@0 888 // End of fields. Start methods.
michael@0 889 //
michael@0 890
michael@0 891 public:
michael@0 892 static JSScript *Create(js::ExclusiveContext *cx,
michael@0 893 js::HandleObject enclosingScope, bool savedCallerFun,
michael@0 894 const JS::ReadOnlyCompileOptions &options, unsigned staticLevel,
michael@0 895 js::HandleObject sourceObject, uint32_t sourceStart,
michael@0 896 uint32_t sourceEnd);
michael@0 897
michael@0 898 void initCompartment(js::ExclusiveContext *cx);
michael@0 899
michael@0 900 // Three ways ways to initialize a JSScript. Callers of partiallyInit()
michael@0 901 // and fullyInitTrivial() are responsible for notifying the debugger after
michael@0 902 // successfully creating any kind (function or other) of new JSScript.
michael@0 903 // However, callers of fullyInitFromEmitter() do not need to do this.
michael@0 904 static bool partiallyInit(js::ExclusiveContext *cx, JS::Handle<JSScript*> script,
michael@0 905 uint32_t nconsts, uint32_t nobjects, uint32_t nregexps,
michael@0 906 uint32_t ntrynotes, uint32_t nblockscopes,
michael@0 907 uint32_t nTypeSets);
michael@0 908 static bool fullyInitFromEmitter(js::ExclusiveContext *cx, JS::Handle<JSScript*> script,
michael@0 909 js::frontend::BytecodeEmitter *bce);
michael@0 910 // Initialize a no-op script.
michael@0 911 static bool fullyInitTrivial(js::ExclusiveContext *cx, JS::Handle<JSScript*> script);
michael@0 912
michael@0 913 inline JSPrincipals *principals();
michael@0 914
michael@0 915 JSCompartment *compartment() const { return compartment_; }
michael@0 916
michael@0 917 void setVersion(JSVersion v) { version = v; }
michael@0 918
michael@0 919 // Script bytecode is immutable after creation.
michael@0 920 jsbytecode *code() const {
michael@0 921 return code_;
michael@0 922 }
michael@0 923 size_t length() const {
michael@0 924 return length_;
michael@0 925 }
michael@0 926
michael@0 927 void setCode(jsbytecode *code) { code_ = code; }
michael@0 928 void setLength(size_t length) { length_ = length; }
michael@0 929
michael@0 930 jsbytecode *codeEnd() const { return code() + length(); }
michael@0 931
michael@0 932 bool containsPC(const jsbytecode *pc) const {
michael@0 933 return pc >= code() && pc < codeEnd();
michael@0 934 }
michael@0 935
michael@0 936 size_t pcToOffset(const jsbytecode *pc) const {
michael@0 937 JS_ASSERT(containsPC(pc));
michael@0 938 return size_t(pc - code());
michael@0 939 }
michael@0 940
michael@0 941 jsbytecode *offsetToPC(size_t offset) const {
michael@0 942 JS_ASSERT(offset < length());
michael@0 943 return code() + offset;
michael@0 944 }
michael@0 945
michael@0 946 size_t mainOffset() const {
michael@0 947 return mainOffset_;
michael@0 948 }
michael@0 949
michael@0 950 size_t lineno() const {
michael@0 951 return lineno_;
michael@0 952 }
michael@0 953
michael@0 954 size_t column() const {
michael@0 955 return column_;
michael@0 956 }
michael@0 957
michael@0 958 void setColumn(size_t column) { column_ = column; }
michael@0 959
michael@0 960 // The fixed part of a stack frame is comprised of vars (in function code)
michael@0 961 // and block-scoped locals (in all kinds of code).
michael@0 962 size_t nfixed() const {
michael@0 963 return function_ ? bindings.numLocals() : bindings.numBlockScoped();
michael@0 964 }
michael@0 965
michael@0 966 // Number of fixed slots reserved for vars. Only nonzero for function code.
michael@0 967 size_t nfixedvars() const {
michael@0 968 return function_ ? bindings.numVars() : 0;
michael@0 969 }
michael@0 970
michael@0 971 size_t nslots() const {
michael@0 972 return nslots_;
michael@0 973 }
michael@0 974
michael@0 975 size_t staticLevel() const {
michael@0 976 return staticLevel_;
michael@0 977 }
michael@0 978
michael@0 979 size_t nTypeSets() const {
michael@0 980 return nTypeSets_;
michael@0 981 }
michael@0 982
michael@0 983 size_t funLength() const {
michael@0 984 return funLength_;
michael@0 985 }
michael@0 986
michael@0 987 size_t sourceStart() const {
michael@0 988 return sourceStart_;
michael@0 989 }
michael@0 990
michael@0 991 size_t sourceEnd() const {
michael@0 992 return sourceEnd_;
michael@0 993 }
michael@0 994
michael@0 995 bool noScriptRval() const {
michael@0 996 return noScriptRval_;
michael@0 997 }
michael@0 998
michael@0 999 bool savedCallerFun() const { return savedCallerFun_; }
michael@0 1000
michael@0 1001 bool strict() const {
michael@0 1002 return strict_;
michael@0 1003 }
michael@0 1004
michael@0 1005 bool explicitUseStrict() const { return explicitUseStrict_; }
michael@0 1006
michael@0 1007 bool compileAndGo() const {
michael@0 1008 return compileAndGo_;
michael@0 1009 }
michael@0 1010
michael@0 1011 bool selfHosted() const { return selfHosted_; }
michael@0 1012 bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; }
michael@0 1013 bool funHasExtensibleScope() const {
michael@0 1014 return funHasExtensibleScope_;
michael@0 1015 }
michael@0 1016 bool funNeedsDeclEnvObject() const {
michael@0 1017 return funNeedsDeclEnvObject_;
michael@0 1018 }
michael@0 1019 bool funHasAnyAliasedFormal() const {
michael@0 1020 return funHasAnyAliasedFormal_;
michael@0 1021 }
michael@0 1022
michael@0 1023 bool hasSingletons() const { return hasSingletons_; }
michael@0 1024 bool treatAsRunOnce() const {
michael@0 1025 return treatAsRunOnce_;
michael@0 1026 }
michael@0 1027 bool hasRunOnce() const { return hasRunOnce_; }
michael@0 1028 bool hasBeenCloned() const { return hasBeenCloned_; }
michael@0 1029 bool hasBeenInlined() const { return hasBeenInlined_; }
michael@0 1030
michael@0 1031 void setTreatAsRunOnce() { treatAsRunOnce_ = true; }
michael@0 1032 void setHasRunOnce() { hasRunOnce_ = true; }
michael@0 1033 void setHasBeenCloned() { hasBeenCloned_ = true; }
michael@0 1034 void setHasBeenInlined() { hasBeenInlined_ = true; }
michael@0 1035
michael@0 1036 bool isActiveEval() const { return isActiveEval_; }
michael@0 1037 bool isCachedEval() const { return isCachedEval_; }
michael@0 1038 bool directlyInsideEval() const { return directlyInsideEval_; }
michael@0 1039
michael@0 1040 void cacheForEval() {
michael@0 1041 JS_ASSERT(isActiveEval() && !isCachedEval());
michael@0 1042 isActiveEval_ = false;
michael@0 1043 isCachedEval_ = true;
michael@0 1044 }
michael@0 1045
michael@0 1046 void uncacheForEval() {
michael@0 1047 JS_ASSERT(isCachedEval() && !isActiveEval());
michael@0 1048 isCachedEval_ = false;
michael@0 1049 isActiveEval_ = true;
michael@0 1050 }
michael@0 1051
michael@0 1052 void setActiveEval() { isActiveEval_ = true; }
michael@0 1053 void setDirectlyInsideEval() { directlyInsideEval_ = true; }
michael@0 1054
michael@0 1055 bool usesArgumentsAndApply() const {
michael@0 1056 return usesArgumentsAndApply_;
michael@0 1057 }
michael@0 1058 void setUsesArgumentsAndApply() { usesArgumentsAndApply_ = true; }
michael@0 1059
michael@0 1060 bool shouldCloneAtCallsite() const {
michael@0 1061 return shouldCloneAtCallsite_;
michael@0 1062 }
michael@0 1063 bool shouldInline() const {
michael@0 1064 return shouldInline_;
michael@0 1065 }
michael@0 1066
michael@0 1067 void setShouldCloneAtCallsite() { shouldCloneAtCallsite_ = true; }
michael@0 1068 void setShouldInline() { shouldInline_ = true; }
michael@0 1069
michael@0 1070 bool isCallsiteClone() const {
michael@0 1071 return isCallsiteClone_;
michael@0 1072 }
michael@0 1073 bool isGeneratorExp() const { return isGeneratorExp_; }
michael@0 1074
michael@0 1075 bool failedBoundsCheck() const {
michael@0 1076 return failedBoundsCheck_;
michael@0 1077 }
michael@0 1078 bool failedShapeGuard() const {
michael@0 1079 return failedShapeGuard_;
michael@0 1080 }
michael@0 1081 bool hadFrequentBailouts() const {
michael@0 1082 return hadFrequentBailouts_;
michael@0 1083 }
michael@0 1084 bool uninlineable() const {
michael@0 1085 return uninlineable_;
michael@0 1086 }
michael@0 1087 bool invalidatedIdempotentCache() const {
michael@0 1088 return invalidatedIdempotentCache_;
michael@0 1089 }
michael@0 1090
michael@0 1091 void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
michael@0 1092 void setFailedShapeGuard() { failedShapeGuard_ = true; }
michael@0 1093 void setHadFrequentBailouts() { hadFrequentBailouts_ = true; }
michael@0 1094 void setUninlineable() { uninlineable_ = true; }
michael@0 1095 void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; }
michael@0 1096
michael@0 1097 bool hasScriptCounts() const { return hasScriptCounts_; }
michael@0 1098
michael@0 1099 bool hasFreezeConstraints() const { return hasFreezeConstraints_; }
michael@0 1100 void setHasFreezeConstraints() { hasFreezeConstraints_ = true; }
michael@0 1101 void clearHasFreezeConstraints() { hasFreezeConstraints_ = false; }
michael@0 1102
michael@0 1103 bool warnedAboutUndefinedProp() const { return warnedAboutUndefinedProp_; }
michael@0 1104 void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; }
michael@0 1105
michael@0 1106 /* See ContextFlags::funArgumentsHasLocalBinding comment. */
michael@0 1107 bool argumentsHasVarBinding() const {
michael@0 1108 return argsHasVarBinding_;
michael@0 1109 }
michael@0 1110 jsbytecode *argumentsBytecode() const { JS_ASSERT(code()[0] == JSOP_ARGUMENTS); return code(); }
michael@0 1111 void setArgumentsHasVarBinding();
michael@0 1112 bool argumentsAliasesFormals() const {
michael@0 1113 return argumentsHasVarBinding() && !strict();
michael@0 1114 }
michael@0 1115
michael@0 1116 js::GeneratorKind generatorKind() const {
michael@0 1117 return js::GeneratorKindFromBits(generatorKindBits_);
michael@0 1118 }
michael@0 1119 bool isGenerator() const { return generatorKind() != js::NotGenerator; }
michael@0 1120 bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
michael@0 1121 bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
michael@0 1122 void setGeneratorKind(js::GeneratorKind kind) {
michael@0 1123 // A script only gets its generator kind set as part of initialization,
michael@0 1124 // so it can only transition from not being a generator.
michael@0 1125 JS_ASSERT(!isGenerator());
michael@0 1126 generatorKindBits_ = GeneratorKindAsBits(kind);
michael@0 1127 }
michael@0 1128
michael@0 1129 /*
michael@0 1130 * As an optimization, even when argsHasLocalBinding, the function prologue
michael@0 1131 * may not need to create an arguments object. This is determined by
michael@0 1132 * needsArgsObj which is set by AnalyzeArgumentsUsage before running
michael@0 1133 * the script the first time. When !needsArgsObj, the prologue may simply
michael@0 1134 * write MagicValue(JS_OPTIMIZED_ARGUMENTS) to 'arguments's slot and any
michael@0 1135 * uses of 'arguments' will be guaranteed to handle this magic value.
michael@0 1136 * So avoid spurious arguments object creation, we maintain the invariant
michael@0 1137 * that needsArgsObj is only called after the script has been analyzed.
michael@0 1138 */
michael@0 1139 bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
michael@0 1140 inline bool ensureHasAnalyzedArgsUsage(JSContext *cx);
michael@0 1141 bool needsArgsObj() const {
michael@0 1142 JS_ASSERT(analyzedArgsUsage());
michael@0 1143 return needsArgsObj_;
michael@0 1144 }
michael@0 1145 void setNeedsArgsObj(bool needsArgsObj);
michael@0 1146 static bool argumentsOptimizationFailed(JSContext *cx, js::HandleScript script);
michael@0 1147
michael@0 1148 /*
michael@0 1149 * Arguments access (via JSOP_*ARG* opcodes) must access the canonical
michael@0 1150 * location for the argument. If an arguments object exists AND this is a
michael@0 1151 * non-strict function (where 'arguments' aliases formals), then all access
michael@0 1152 * must go through the arguments object. Otherwise, the local slot is the
michael@0 1153 * canonical location for the arguments. Note: if a formal is aliased
michael@0 1154 * through the scope chain, then script->formalIsAliased and JSOP_*ARG*
michael@0 1155 * opcodes won't be emitted at all.
michael@0 1156 */
michael@0 1157 bool argsObjAliasesFormals() const {
michael@0 1158 return needsArgsObj() && !strict();
michael@0 1159 }
michael@0 1160
michael@0 1161 bool hasAnyIonScript() const {
michael@0 1162 return hasIonScript() || hasParallelIonScript();
michael@0 1163 }
michael@0 1164
michael@0 1165 bool hasIonScript() const {
michael@0 1166 bool res = ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT;
michael@0 1167 MOZ_ASSERT_IF(res, baseline);
michael@0 1168 return res;
michael@0 1169 }
michael@0 1170 bool canIonCompile() const {
michael@0 1171 return ion != ION_DISABLED_SCRIPT;
michael@0 1172 }
michael@0 1173
michael@0 1174 bool isIonCompilingOffThread() const {
michael@0 1175 return ion == ION_COMPILING_SCRIPT;
michael@0 1176 }
michael@0 1177
michael@0 1178 js::jit::IonScript *ionScript() const {
michael@0 1179 JS_ASSERT(hasIonScript());
michael@0 1180 return ion;
michael@0 1181 }
michael@0 1182 js::jit::IonScript *maybeIonScript() const {
michael@0 1183 return ion;
michael@0 1184 }
michael@0 1185 js::jit::IonScript *const *addressOfIonScript() const {
michael@0 1186 return &ion;
michael@0 1187 }
michael@0 1188 void setIonScript(js::jit::IonScript *ionScript) {
michael@0 1189 if (hasIonScript())
michael@0 1190 js::jit::IonScript::writeBarrierPre(tenuredZone(), ion);
michael@0 1191 ion = ionScript;
michael@0 1192 MOZ_ASSERT_IF(hasIonScript(), hasBaselineScript());
michael@0 1193 updateBaselineOrIonRaw();
michael@0 1194 }
michael@0 1195
michael@0 1196 bool hasBaselineScript() const {
michael@0 1197 bool res = baseline && baseline != BASELINE_DISABLED_SCRIPT;
michael@0 1198 MOZ_ASSERT_IF(!res, !ion || ion == ION_DISABLED_SCRIPT);
michael@0 1199 return res;
michael@0 1200 }
michael@0 1201 bool canBaselineCompile() const {
michael@0 1202 return baseline != BASELINE_DISABLED_SCRIPT;
michael@0 1203 }
michael@0 1204 js::jit::BaselineScript *baselineScript() const {
michael@0 1205 JS_ASSERT(hasBaselineScript());
michael@0 1206 return baseline;
michael@0 1207 }
michael@0 1208 inline void setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript);
michael@0 1209
michael@0 1210 void updateBaselineOrIonRaw();
michael@0 1211
michael@0 1212 bool hasParallelIonScript() const {
michael@0 1213 return parallelIon && parallelIon != ION_DISABLED_SCRIPT && parallelIon != ION_COMPILING_SCRIPT;
michael@0 1214 }
michael@0 1215
michael@0 1216 bool canParallelIonCompile() const {
michael@0 1217 return parallelIon != ION_DISABLED_SCRIPT;
michael@0 1218 }
michael@0 1219
michael@0 1220 bool isParallelIonCompilingOffThread() const {
michael@0 1221 return parallelIon == ION_COMPILING_SCRIPT;
michael@0 1222 }
michael@0 1223
michael@0 1224 js::jit::IonScript *parallelIonScript() const {
michael@0 1225 JS_ASSERT(hasParallelIonScript());
michael@0 1226 return parallelIon;
michael@0 1227 }
michael@0 1228 js::jit::IonScript *maybeParallelIonScript() const {
michael@0 1229 return parallelIon;
michael@0 1230 }
michael@0 1231 void setParallelIonScript(js::jit::IonScript *ionScript) {
michael@0 1232 if (hasParallelIonScript())
michael@0 1233 js::jit::IonScript::writeBarrierPre(tenuredZone(), parallelIon);
michael@0 1234 parallelIon = ionScript;
michael@0 1235 }
michael@0 1236
michael@0 1237 static size_t offsetOfBaselineScript() {
michael@0 1238 return offsetof(JSScript, baseline);
michael@0 1239 }
michael@0 1240 static size_t offsetOfIonScript() {
michael@0 1241 return offsetof(JSScript, ion);
michael@0 1242 }
michael@0 1243 static size_t offsetOfParallelIonScript() {
michael@0 1244 return offsetof(JSScript, parallelIon);
michael@0 1245 }
michael@0 1246 static size_t offsetOfBaselineOrIonRaw() {
michael@0 1247 return offsetof(JSScript, baselineOrIonRaw);
michael@0 1248 }
michael@0 1249 static size_t offsetOfBaselineOrIonSkipArgCheck() {
michael@0 1250 return offsetof(JSScript, baselineOrIonSkipArgCheck);
michael@0 1251 }
michael@0 1252
michael@0 1253 bool isRelazifiable() const {
michael@0 1254 return (selfHosted() || lazyScript) &&
michael@0 1255 !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() && !hasBeenInlined();
michael@0 1256 }
michael@0 1257 void setLazyScript(js::LazyScript *lazy) {
michael@0 1258 lazyScript = lazy;
michael@0 1259 }
michael@0 1260 js::LazyScript *maybeLazyScript() {
michael@0 1261 return lazyScript;
michael@0 1262 }
michael@0 1263
michael@0 1264 /*
michael@0 1265 * Original compiled function for the script, if it has a function.
michael@0 1266 * nullptr for global and eval scripts.
michael@0 1267 * The delazifying variant ensures that the function isn't lazy. The
michael@0 1268 * non-delazifying variant must only be used after earlier code has
michael@0 1269 * called ensureNonLazyCanonicalFunction and while the function can't
michael@0 1270 * have been relazified.
michael@0 1271 */
michael@0 1272 inline JSFunction *functionDelazifying() const;
michael@0 1273 JSFunction *functionNonDelazifying() const {
michael@0 1274 return function_;
michael@0 1275 }
michael@0 1276 inline void setFunction(JSFunction *fun);
michael@0 1277 /*
michael@0 1278 * De-lazifies the canonical function. Must be called before entering code
michael@0 1279 * that expects the function to be non-lazy.
michael@0 1280 */
michael@0 1281 inline void ensureNonLazyCanonicalFunction(JSContext *cx);
michael@0 1282
michael@0 1283 /*
michael@0 1284 * Donor provided itself to callsite clone; null if this is non-clone.
michael@0 1285 */
michael@0 1286 JSFunction *donorFunction() const;
michael@0 1287 void setIsCallsiteClone(JSObject *fun);
michael@0 1288
michael@0 1289 JSFlatString *sourceData(JSContext *cx);
michael@0 1290
michael@0 1291 static bool loadSource(JSContext *cx, js::ScriptSource *ss, bool *worked);
michael@0 1292
michael@0 1293 void setSourceObject(JSObject *object);
michael@0 1294 JSObject *sourceObject() const {
michael@0 1295 return sourceObject_;
michael@0 1296 }
michael@0 1297 js::ScriptSourceObject &scriptSourceUnwrap() const;
michael@0 1298 js::ScriptSource *scriptSource() const;
michael@0 1299 JSPrincipals *originPrincipals() const { return scriptSource()->originPrincipals(); }
michael@0 1300 const char *filename() const { return scriptSource()->filename(); }
michael@0 1301
michael@0 1302 public:
michael@0 1303
michael@0 1304 /* Return whether this script was compiled for 'eval' */
michael@0 1305 bool isForEval() { return isCachedEval() || isActiveEval(); }
michael@0 1306
michael@0 1307 #ifdef DEBUG
michael@0 1308 unsigned id();
michael@0 1309 #else
michael@0 1310 unsigned id() { return 0; }
michael@0 1311 #endif
michael@0 1312
michael@0 1313 /* Ensure the script has a TypeScript. */
michael@0 1314 inline bool ensureHasTypes(JSContext *cx);
michael@0 1315
michael@0 1316 inline js::GlobalObject &global() const;
michael@0 1317 js::GlobalObject &uninlinedGlobal() const;
michael@0 1318
michael@0 1319 /* See StaticScopeIter comment. */
michael@0 1320 JSObject *enclosingStaticScope() const {
michael@0 1321 if (isCallsiteClone())
michael@0 1322 return nullptr;
michael@0 1323 return enclosingScopeOrOriginalFunction_;
michael@0 1324 }
michael@0 1325
michael@0 1326 private:
michael@0 1327 bool makeTypes(JSContext *cx);
michael@0 1328
michael@0 1329 public:
michael@0 1330 uint32_t getUseCount() const {
michael@0 1331 return useCount;
michael@0 1332 }
michael@0 1333 uint32_t incUseCount(uint32_t amount = 1) { return useCount += amount; }
michael@0 1334 uint32_t *addressOfUseCount() { return &useCount; }
michael@0 1335 static size_t offsetOfUseCount() { return offsetof(JSScript, useCount); }
michael@0 1336 void resetUseCount() { useCount = 0; }
michael@0 1337
michael@0 1338 public:
michael@0 1339 bool initScriptCounts(JSContext *cx);
michael@0 1340 js::PCCounts getPCCounts(jsbytecode *pc);
michael@0 1341 void addIonCounts(js::jit::IonScriptCounts *ionCounts);
michael@0 1342 js::jit::IonScriptCounts *getIonCounts();
michael@0 1343 js::ScriptCounts releaseScriptCounts();
michael@0 1344 void destroyScriptCounts(js::FreeOp *fop);
michael@0 1345
michael@0 1346 jsbytecode *main() {
michael@0 1347 return code() + mainOffset();
michael@0 1348 }
michael@0 1349
michael@0 1350 /*
michael@0 1351 * computedSizeOfData() is the in-use size of all the data sections.
michael@0 1352 * sizeOfData() is the size of the block allocated to hold all the data
michael@0 1353 * sections (which can be larger than the in-use size).
michael@0 1354 */
michael@0 1355 size_t computedSizeOfData() const;
michael@0 1356 size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const;
michael@0 1357 size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
michael@0 1358
michael@0 1359 uint32_t numNotes(); /* Number of srcnote slots in the srcnotes section */
michael@0 1360
michael@0 1361 /* Script notes are allocated right after the code. */
michael@0 1362 jssrcnote *notes() { return (jssrcnote *)(code() + length()); }
michael@0 1363
michael@0 1364 bool hasArray(ArrayKind kind) {
michael@0 1365 return hasArrayBits & (1 << kind);
michael@0 1366 }
michael@0 1367 void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
michael@0 1368 void cloneHasArray(JSScript *script) { hasArrayBits = script->hasArrayBits; }
michael@0 1369
michael@0 1370 bool hasConsts() { return hasArray(CONSTS); }
michael@0 1371 bool hasObjects() { return hasArray(OBJECTS); }
michael@0 1372 bool hasRegexps() { return hasArray(REGEXPS); }
michael@0 1373 bool hasTrynotes() { return hasArray(TRYNOTES); }
michael@0 1374 bool hasBlockScopes() { return hasArray(BLOCK_SCOPES); }
michael@0 1375
michael@0 1376 #define OFF(fooOff, hasFoo, t) (fooOff() + (hasFoo() ? sizeof(t) : 0))
michael@0 1377
michael@0 1378 size_t constsOffset() { return 0; }
michael@0 1379 size_t objectsOffset() { return OFF(constsOffset, hasConsts, js::ConstArray); }
michael@0 1380 size_t regexpsOffset() { return OFF(objectsOffset, hasObjects, js::ObjectArray); }
michael@0 1381 size_t trynotesOffset() { return OFF(regexpsOffset, hasRegexps, js::ObjectArray); }
michael@0 1382 size_t blockScopesOffset(){ return OFF(trynotesOffset, hasTrynotes, js::TryNoteArray); }
michael@0 1383
michael@0 1384 size_t dataSize() const { return dataSize_; }
michael@0 1385
michael@0 1386 js::ConstArray *consts() {
michael@0 1387 JS_ASSERT(hasConsts());
michael@0 1388 return reinterpret_cast<js::ConstArray *>(data + constsOffset());
michael@0 1389 }
michael@0 1390
michael@0 1391 js::ObjectArray *objects() {
michael@0 1392 JS_ASSERT(hasObjects());
michael@0 1393 return reinterpret_cast<js::ObjectArray *>(data + objectsOffset());
michael@0 1394 }
michael@0 1395
michael@0 1396 js::ObjectArray *regexps() {
michael@0 1397 JS_ASSERT(hasRegexps());
michael@0 1398 return reinterpret_cast<js::ObjectArray *>(data + regexpsOffset());
michael@0 1399 }
michael@0 1400
michael@0 1401 js::TryNoteArray *trynotes() {
michael@0 1402 JS_ASSERT(hasTrynotes());
michael@0 1403 return reinterpret_cast<js::TryNoteArray *>(data + trynotesOffset());
michael@0 1404 }
michael@0 1405
michael@0 1406 js::BlockScopeArray *blockScopes() {
michael@0 1407 JS_ASSERT(hasBlockScopes());
michael@0 1408 return reinterpret_cast<js::BlockScopeArray *>(data + blockScopesOffset());
michael@0 1409 }
michael@0 1410
michael@0 1411 bool hasLoops();
michael@0 1412
michael@0 1413 size_t natoms() const { return natoms_; }
michael@0 1414
michael@0 1415 js::HeapPtrAtom &getAtom(size_t index) const {
michael@0 1416 JS_ASSERT(index < natoms());
michael@0 1417 return atoms[index];
michael@0 1418 }
michael@0 1419
michael@0 1420 js::HeapPtrAtom &getAtom(jsbytecode *pc) const {
michael@0 1421 JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
michael@0 1422 return getAtom(GET_UINT32_INDEX(pc));
michael@0 1423 }
michael@0 1424
michael@0 1425 js::PropertyName *getName(size_t index) {
michael@0 1426 return getAtom(index)->asPropertyName();
michael@0 1427 }
michael@0 1428
michael@0 1429 js::PropertyName *getName(jsbytecode *pc) const {
michael@0 1430 JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
michael@0 1431 return getAtom(GET_UINT32_INDEX(pc))->asPropertyName();
michael@0 1432 }
michael@0 1433
michael@0 1434 JSObject *getObject(size_t index) {
michael@0 1435 js::ObjectArray *arr = objects();
michael@0 1436 JS_ASSERT(index < arr->length);
michael@0 1437 return arr->vector[index];
michael@0 1438 }
michael@0 1439
michael@0 1440 size_t innerObjectsStart() {
michael@0 1441 // The first object contains the caller if savedCallerFun is used.
michael@0 1442 return savedCallerFun() ? 1 : 0;
michael@0 1443 }
michael@0 1444
michael@0 1445 JSObject *getObject(jsbytecode *pc) {
michael@0 1446 JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
michael@0 1447 return getObject(GET_UINT32_INDEX(pc));
michael@0 1448 }
michael@0 1449
michael@0 1450 JSVersion getVersion() const {
michael@0 1451 return JSVersion(version);
michael@0 1452 }
michael@0 1453
michael@0 1454 inline JSFunction *getFunction(size_t index);
michael@0 1455 inline JSFunction *getCallerFunction();
michael@0 1456 inline JSFunction *functionOrCallerFunction();
michael@0 1457
michael@0 1458 inline js::RegExpObject *getRegExp(size_t index);
michael@0 1459 inline js::RegExpObject *getRegExp(jsbytecode *pc);
michael@0 1460
michael@0 1461 const js::Value &getConst(size_t index) {
michael@0 1462 js::ConstArray *arr = consts();
michael@0 1463 JS_ASSERT(index < arr->length);
michael@0 1464 return arr->vector[index];
michael@0 1465 }
michael@0 1466
michael@0 1467 js::NestedScopeObject *getStaticScope(jsbytecode *pc);
michael@0 1468
michael@0 1469 /*
michael@0 1470 * The isEmpty method tells whether this script has code that computes any
michael@0 1471 * result (not return value, result AKA normal completion value) other than
michael@0 1472 * JSVAL_VOID, or any other effects.
michael@0 1473 */
michael@0 1474 bool isEmpty() const {
michael@0 1475 if (length() > 3)
michael@0 1476 return false;
michael@0 1477
michael@0 1478 jsbytecode *pc = code();
michael@0 1479 if (noScriptRval() && JSOp(*pc) == JSOP_FALSE)
michael@0 1480 ++pc;
michael@0 1481 return JSOp(*pc) == JSOP_RETRVAL;
michael@0 1482 }
michael@0 1483
michael@0 1484 bool varIsAliased(uint32_t varSlot);
michael@0 1485 bool formalIsAliased(unsigned argSlot);
michael@0 1486 bool formalLivesInArgumentsObject(unsigned argSlot);
michael@0 1487
michael@0 1488 private:
michael@0 1489 /* Change this->stepMode to |newValue|. */
michael@0 1490 void setNewStepMode(js::FreeOp *fop, uint32_t newValue);
michael@0 1491
michael@0 1492 bool ensureHasDebugScript(JSContext *cx);
michael@0 1493 js::DebugScript *debugScript();
michael@0 1494 js::DebugScript *releaseDebugScript();
michael@0 1495 void destroyDebugScript(js::FreeOp *fop);
michael@0 1496
michael@0 1497 public:
michael@0 1498 bool hasBreakpointsAt(jsbytecode *pc);
michael@0 1499 bool hasAnyBreakpointsOrStepMode() { return hasDebugScript_; }
michael@0 1500
michael@0 1501 js::BreakpointSite *getBreakpointSite(jsbytecode *pc)
michael@0 1502 {
michael@0 1503 return hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
michael@0 1504 }
michael@0 1505
michael@0 1506 js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc);
michael@0 1507
michael@0 1508 void destroyBreakpointSite(js::FreeOp *fop, jsbytecode *pc);
michael@0 1509
michael@0 1510 void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JSObject *handler);
michael@0 1511 void clearTraps(js::FreeOp *fop);
michael@0 1512
michael@0 1513 void markTrapClosures(JSTracer *trc);
michael@0 1514
michael@0 1515 /*
michael@0 1516 * Set or clear the single-step flag. If the flag is set or the count
michael@0 1517 * (adjusted by changeStepModeCount) is non-zero, then the script is in
michael@0 1518 * single-step mode. (JSD uses an on/off-style interface; Debugger uses a
michael@0 1519 * count-style interface.)
michael@0 1520 */
michael@0 1521 bool setStepModeFlag(JSContext *cx, bool step);
michael@0 1522
michael@0 1523 /*
michael@0 1524 * Increment or decrement the single-step count. If the count is non-zero or
michael@0 1525 * the flag (set by setStepModeFlag) is set, then the script is in
michael@0 1526 * single-step mode. (JSD uses an on/off-style interface; Debugger uses a
michael@0 1527 * count-style interface.)
michael@0 1528 *
michael@0 1529 * Only incrementing is fallible, as it could allocate a DebugScript.
michael@0 1530 */
michael@0 1531 bool incrementStepModeCount(JSContext *cx);
michael@0 1532 void decrementStepModeCount(js::FreeOp *fop);
michael@0 1533
michael@0 1534 bool stepModeEnabled() { return hasDebugScript_ && !!debugScript()->stepMode; }
michael@0 1535
michael@0 1536 #ifdef DEBUG
michael@0 1537 uint32_t stepModeCount() { return hasDebugScript_ ? (debugScript()->stepMode & stepCountMask) : 0; }
michael@0 1538 #endif
michael@0 1539
michael@0 1540 void finalize(js::FreeOp *fop);
michael@0 1541
michael@0 1542 static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SCRIPT; }
michael@0 1543
michael@0 1544 void markChildren(JSTracer *trc);
michael@0 1545 };
michael@0 1546
michael@0 1547 /* If this fails, add/remove padding within JSScript. */
michael@0 1548 static_assert(sizeof(JSScript) % js::gc::CellSize == 0,
michael@0 1549 "Size of JSScript must be an integral multiple of js::gc::CellSize");
michael@0 1550
michael@0 1551 namespace js {
michael@0 1552
michael@0 1553 /*
michael@0 1554 * Iterator over a script's bindings (formals and variables).
michael@0 1555 * The order of iteration is:
michael@0 1556 * - first, formal arguments, from index 0 to numArgs
michael@0 1557 * - next, variables, from index 0 to numLocals
michael@0 1558 */
michael@0 1559 class BindingIter
michael@0 1560 {
michael@0 1561 const InternalBindingsHandle bindings_;
michael@0 1562 uint32_t i_;
michael@0 1563
michael@0 1564 friend class Bindings;
michael@0 1565
michael@0 1566 public:
michael@0 1567 explicit BindingIter(const InternalBindingsHandle &bindings) : bindings_(bindings), i_(0) {}
michael@0 1568 explicit BindingIter(const HandleScript &script) : bindings_(script, &script->bindings), i_(0) {}
michael@0 1569
michael@0 1570 bool done() const { return i_ == bindings_->count(); }
michael@0 1571 operator bool() const { return !done(); }
michael@0 1572 void operator++(int) { JS_ASSERT(!done()); i_++; }
michael@0 1573 BindingIter &operator++() { (*this)++; return *this; }
michael@0 1574
michael@0 1575 uint32_t frameIndex() const {
michael@0 1576 JS_ASSERT(!done());
michael@0 1577 return i_ < bindings_->numArgs() ? i_ : i_ - bindings_->numArgs();
michael@0 1578 }
michael@0 1579
michael@0 1580 const Binding &operator*() const { JS_ASSERT(!done()); return bindings_->bindingArray()[i_]; }
michael@0 1581 const Binding *operator->() const { JS_ASSERT(!done()); return &bindings_->bindingArray()[i_]; }
michael@0 1582 };
michael@0 1583
michael@0 1584 /*
michael@0 1585 * This helper function fills the given BindingVector with the sequential
michael@0 1586 * values of BindingIter.
michael@0 1587 */
michael@0 1588
michael@0 1589 typedef Vector<Binding, 32> BindingVector;
michael@0 1590
michael@0 1591 extern bool
michael@0 1592 FillBindingVector(HandleScript fromScript, BindingVector *vec);
michael@0 1593
michael@0 1594 /*
michael@0 1595 * Iterator over the aliased formal bindings in ascending index order. This can
michael@0 1596 * be veiwed as a filtering of BindingIter with predicate
michael@0 1597 * bi->aliased() && bi->kind() == Binding::ARGUMENT
michael@0 1598 */
michael@0 1599 class AliasedFormalIter
michael@0 1600 {
michael@0 1601 const Binding *begin_, *p_, *end_;
michael@0 1602 unsigned slot_;
michael@0 1603
michael@0 1604 void settle() {
michael@0 1605 while (p_ != end_ && !p_->aliased())
michael@0 1606 p_++;
michael@0 1607 }
michael@0 1608
michael@0 1609 public:
michael@0 1610 explicit inline AliasedFormalIter(JSScript *script);
michael@0 1611
michael@0 1612 bool done() const { return p_ == end_; }
michael@0 1613 operator bool() const { return !done(); }
michael@0 1614 void operator++(int) { JS_ASSERT(!done()); p_++; slot_++; settle(); }
michael@0 1615
michael@0 1616 const Binding &operator*() const { JS_ASSERT(!done()); return *p_; }
michael@0 1617 const Binding *operator->() const { JS_ASSERT(!done()); return p_; }
michael@0 1618 unsigned frameIndex() const { JS_ASSERT(!done()); return p_ - begin_; }
michael@0 1619 unsigned scopeSlot() const { JS_ASSERT(!done()); return slot_; }
michael@0 1620 };
michael@0 1621
michael@0 1622 // Information about a script which may be (or has been) lazily compiled to
michael@0 1623 // bytecode from its source.
michael@0 1624 class LazyScript : public gc::BarrieredCell<LazyScript>
michael@0 1625 {
michael@0 1626 // If non-nullptr, the script has been compiled and this is a forwarding
michael@0 1627 // pointer to the result.
michael@0 1628 HeapPtrScript script_;
michael@0 1629
michael@0 1630 // Original function with which the lazy script is associated.
michael@0 1631 HeapPtrFunction function_;
michael@0 1632
michael@0 1633 // Function or block chain in which the script is nested, or nullptr.
michael@0 1634 HeapPtrObject enclosingScope_;
michael@0 1635
michael@0 1636 // ScriptSourceObject, or nullptr if the script in which this is nested
michael@0 1637 // has not been compiled yet. This is never a CCW; we don't clone
michael@0 1638 // LazyScripts into other compartments.
michael@0 1639 HeapPtrObject sourceObject_;
michael@0 1640
michael@0 1641 // Heap allocated table with any free variables or inner functions.
michael@0 1642 void *table_;
michael@0 1643
michael@0 1644 #if JS_BITS_PER_WORD == 32
michael@0 1645 uint32_t padding;
michael@0 1646 #endif
michael@0 1647
michael@0 1648 struct PackedView {
michael@0 1649 // Assorted bits that should really be in ScriptSourceObject.
michael@0 1650 uint32_t version : 8;
michael@0 1651
michael@0 1652 uint32_t numFreeVariables : 24;
michael@0 1653 uint32_t numInnerFunctions : 23;
michael@0 1654
michael@0 1655 uint32_t generatorKindBits : 2;
michael@0 1656
michael@0 1657 // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
michael@0 1658 uint32_t strict : 1;
michael@0 1659 uint32_t bindingsAccessedDynamically : 1;
michael@0 1660 uint32_t hasDebuggerStatement : 1;
michael@0 1661 uint32_t directlyInsideEval : 1;
michael@0 1662 uint32_t usesArgumentsAndApply : 1;
michael@0 1663 uint32_t hasBeenCloned : 1;
michael@0 1664 uint32_t treatAsRunOnce : 1;
michael@0 1665 };
michael@0 1666
michael@0 1667 union {
michael@0 1668 PackedView p_;
michael@0 1669 uint64_t packedFields_;
michael@0 1670 };
michael@0 1671
michael@0 1672 // Source location for the script.
michael@0 1673 uint32_t begin_;
michael@0 1674 uint32_t end_;
michael@0 1675 uint32_t lineno_;
michael@0 1676 uint32_t column_;
michael@0 1677
michael@0 1678 LazyScript(JSFunction *fun, void *table, uint64_t packedFields,
michael@0 1679 uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column);
michael@0 1680
michael@0 1681 // Create a LazyScript without initializing the freeVariables and the
michael@0 1682 // innerFunctions. To be GC-safe, the caller must initialize both vectors
michael@0 1683 // with valid atoms and functions.
michael@0 1684 static LazyScript *CreateRaw(ExclusiveContext *cx, HandleFunction fun,
michael@0 1685 uint64_t packedData, uint32_t begin, uint32_t end,
michael@0 1686 uint32_t lineno, uint32_t column);
michael@0 1687
michael@0 1688 public:
michael@0 1689 // Create a LazyScript without initializing the freeVariables and the
michael@0 1690 // innerFunctions. To be GC-safe, the caller must initialize both vectors
michael@0 1691 // with valid atoms and functions.
michael@0 1692 static LazyScript *CreateRaw(ExclusiveContext *cx, HandleFunction fun,
michael@0 1693 uint32_t numFreeVariables, uint32_t numInnerFunctions,
michael@0 1694 JSVersion version, uint32_t begin, uint32_t end,
michael@0 1695 uint32_t lineno, uint32_t column);
michael@0 1696
michael@0 1697 // Create a LazyScript and initialize the freeVariables and the
michael@0 1698 // innerFunctions with dummy values to be replaced in a later initialization
michael@0 1699 // phase.
michael@0 1700 static LazyScript *Create(ExclusiveContext *cx, HandleFunction fun,
michael@0 1701 uint64_t packedData, uint32_t begin, uint32_t end,
michael@0 1702 uint32_t lineno, uint32_t column);
michael@0 1703
michael@0 1704 void initRuntimeFields(uint64_t packedFields);
michael@0 1705
michael@0 1706 inline JSFunction *functionDelazifying(JSContext *cx) const;
michael@0 1707 JSFunction *functionNonDelazifying() const {
michael@0 1708 return function_;
michael@0 1709 }
michael@0 1710
michael@0 1711 void initScript(JSScript *script);
michael@0 1712 void resetScript();
michael@0 1713 JSScript *maybeScript() {
michael@0 1714 return script_;
michael@0 1715 }
michael@0 1716
michael@0 1717 JSObject *enclosingScope() const {
michael@0 1718 return enclosingScope_;
michael@0 1719 }
michael@0 1720 ScriptSourceObject *sourceObject() const;
michael@0 1721 ScriptSource *scriptSource() const {
michael@0 1722 return sourceObject()->source();
michael@0 1723 }
michael@0 1724 JSPrincipals *originPrincipals() const {
michael@0 1725 return scriptSource()->originPrincipals();
michael@0 1726 }
michael@0 1727 JSVersion version() const {
michael@0 1728 JS_STATIC_ASSERT(JSVERSION_UNKNOWN == -1);
michael@0 1729 return (p_.version == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(p_.version);
michael@0 1730 }
michael@0 1731
michael@0 1732 void setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject);
michael@0 1733
michael@0 1734 uint32_t numFreeVariables() const {
michael@0 1735 return p_.numFreeVariables;
michael@0 1736 }
michael@0 1737 HeapPtrAtom *freeVariables() {
michael@0 1738 return (HeapPtrAtom *)table_;
michael@0 1739 }
michael@0 1740
michael@0 1741 uint32_t numInnerFunctions() const {
michael@0 1742 return p_.numInnerFunctions;
michael@0 1743 }
michael@0 1744 HeapPtrFunction *innerFunctions() {
michael@0 1745 return (HeapPtrFunction *)&freeVariables()[numFreeVariables()];
michael@0 1746 }
michael@0 1747
michael@0 1748 GeneratorKind generatorKind() const { return GeneratorKindFromBits(p_.generatorKindBits); }
michael@0 1749
michael@0 1750 bool isGenerator() const { return generatorKind() != NotGenerator; }
michael@0 1751
michael@0 1752 bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
michael@0 1753
michael@0 1754 bool isStarGenerator() const { return generatorKind() == StarGenerator; }
michael@0 1755
michael@0 1756 void setGeneratorKind(GeneratorKind kind) {
michael@0 1757 // A script only gets its generator kind set as part of initialization,
michael@0 1758 // so it can only transition from NotGenerator.
michael@0 1759 JS_ASSERT(!isGenerator());
michael@0 1760 // Legacy generators cannot currently be lazy.
michael@0 1761 JS_ASSERT(kind != LegacyGenerator);
michael@0 1762 p_.generatorKindBits = GeneratorKindAsBits(kind);
michael@0 1763 }
michael@0 1764
michael@0 1765 bool strict() const {
michael@0 1766 return p_.strict;
michael@0 1767 }
michael@0 1768 void setStrict() {
michael@0 1769 p_.strict = true;
michael@0 1770 }
michael@0 1771
michael@0 1772 bool bindingsAccessedDynamically() const {
michael@0 1773 return p_.bindingsAccessedDynamically;
michael@0 1774 }
michael@0 1775 void setBindingsAccessedDynamically() {
michael@0 1776 p_.bindingsAccessedDynamically = true;
michael@0 1777 }
michael@0 1778
michael@0 1779 bool hasDebuggerStatement() const {
michael@0 1780 return p_.hasDebuggerStatement;
michael@0 1781 }
michael@0 1782 void setHasDebuggerStatement() {
michael@0 1783 p_.hasDebuggerStatement = true;
michael@0 1784 }
michael@0 1785
michael@0 1786 bool directlyInsideEval() const {
michael@0 1787 return p_.directlyInsideEval;
michael@0 1788 }
michael@0 1789 void setDirectlyInsideEval() {
michael@0 1790 p_.directlyInsideEval = true;
michael@0 1791 }
michael@0 1792
michael@0 1793 bool usesArgumentsAndApply() const {
michael@0 1794 return p_.usesArgumentsAndApply;
michael@0 1795 }
michael@0 1796 void setUsesArgumentsAndApply() {
michael@0 1797 p_.usesArgumentsAndApply = true;
michael@0 1798 }
michael@0 1799
michael@0 1800 bool hasBeenCloned() const {
michael@0 1801 return p_.hasBeenCloned;
michael@0 1802 }
michael@0 1803 void setHasBeenCloned() {
michael@0 1804 p_.hasBeenCloned = true;
michael@0 1805 }
michael@0 1806
michael@0 1807 bool treatAsRunOnce() const {
michael@0 1808 return p_.treatAsRunOnce;
michael@0 1809 }
michael@0 1810 void setTreatAsRunOnce() {
michael@0 1811 p_.treatAsRunOnce = true;
michael@0 1812 }
michael@0 1813
michael@0 1814 ScriptSource *source() const {
michael@0 1815 return sourceObject()->source();
michael@0 1816 }
michael@0 1817 uint32_t begin() const {
michael@0 1818 return begin_;
michael@0 1819 }
michael@0 1820 uint32_t end() const {
michael@0 1821 return end_;
michael@0 1822 }
michael@0 1823 uint32_t lineno() const {
michael@0 1824 return lineno_;
michael@0 1825 }
michael@0 1826 uint32_t column() const {
michael@0 1827 return column_;
michael@0 1828 }
michael@0 1829
michael@0 1830 bool hasUncompiledEnclosingScript() const;
michael@0 1831 uint32_t staticLevel(JSContext *cx) const;
michael@0 1832
michael@0 1833 void markChildren(JSTracer *trc);
michael@0 1834 void finalize(js::FreeOp *fop);
michael@0 1835
michael@0 1836 static inline js::ThingRootKind rootKind() { return js::THING_ROOT_LAZY_SCRIPT; }
michael@0 1837
michael@0 1838 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
michael@0 1839 {
michael@0 1840 return mallocSizeOf(table_);
michael@0 1841 }
michael@0 1842
michael@0 1843 uint64_t packedFields() const {
michael@0 1844 return packedFields_;
michael@0 1845 }
michael@0 1846 };
michael@0 1847
michael@0 1848 /* If this fails, add/remove padding within LazyScript. */
michael@0 1849 JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0);
michael@0 1850
michael@0 1851 /*
michael@0 1852 * New-script-hook calling is factored from JSScript::fullyInitFromEmitter() so
michael@0 1853 * that it and callers of XDRScript() can share this code. In the case of
michael@0 1854 * callers of XDRScript(), the hook should be invoked only after successful
michael@0 1855 * decode of any owning function (the fun parameter) or script object (null
michael@0 1856 * fun).
michael@0 1857 */
michael@0 1858 extern void
michael@0 1859 CallNewScriptHook(JSContext *cx, JS::HandleScript script, JS::HandleFunction fun);
michael@0 1860
michael@0 1861 extern void
michael@0 1862 CallDestroyScriptHook(FreeOp *fop, JSScript *script);
michael@0 1863
michael@0 1864 struct SharedScriptData
michael@0 1865 {
michael@0 1866 uint32_t length;
michael@0 1867 uint32_t natoms;
michael@0 1868 bool marked;
michael@0 1869 jsbytecode data[1];
michael@0 1870
michael@0 1871 static SharedScriptData *new_(ExclusiveContext *cx, uint32_t codeLength,
michael@0 1872 uint32_t srcnotesLength, uint32_t natoms);
michael@0 1873
michael@0 1874 HeapPtrAtom *atoms() {
michael@0 1875 if (!natoms)
michael@0 1876 return nullptr;
michael@0 1877 return reinterpret_cast<HeapPtrAtom *>(data + length - sizeof(JSAtom *) * natoms);
michael@0 1878 }
michael@0 1879
michael@0 1880 static SharedScriptData *fromBytecode(const jsbytecode *bytecode) {
michael@0 1881 return (SharedScriptData *)(bytecode - offsetof(SharedScriptData, data));
michael@0 1882 }
michael@0 1883
michael@0 1884 private:
michael@0 1885 SharedScriptData() MOZ_DELETE;
michael@0 1886 SharedScriptData(const SharedScriptData&) MOZ_DELETE;
michael@0 1887 };
michael@0 1888
michael@0 1889 struct ScriptBytecodeHasher
michael@0 1890 {
michael@0 1891 struct Lookup
michael@0 1892 {
michael@0 1893 jsbytecode *code;
michael@0 1894 uint32_t length;
michael@0 1895
michael@0 1896 Lookup(SharedScriptData *ssd) : code(ssd->data), length(ssd->length) {}
michael@0 1897 };
michael@0 1898 static HashNumber hash(const Lookup &l) { return mozilla::HashBytes(l.code, l.length); }
michael@0 1899 static bool match(SharedScriptData *entry, const Lookup &lookup) {
michael@0 1900 if (entry->length != lookup.length)
michael@0 1901 return false;
michael@0 1902 return mozilla::PodEqual<jsbytecode>(entry->data, lookup.code, lookup.length);
michael@0 1903 }
michael@0 1904 };
michael@0 1905
michael@0 1906 typedef HashSet<SharedScriptData*,
michael@0 1907 ScriptBytecodeHasher,
michael@0 1908 SystemAllocPolicy> ScriptDataTable;
michael@0 1909
michael@0 1910 extern void
michael@0 1911 UnmarkScriptData(JSRuntime *rt);
michael@0 1912
michael@0 1913 extern void
michael@0 1914 SweepScriptData(JSRuntime *rt);
michael@0 1915
michael@0 1916 extern void
michael@0 1917 FreeScriptData(JSRuntime *rt);
michael@0 1918
michael@0 1919 struct ScriptAndCounts
michael@0 1920 {
michael@0 1921 /* This structure is stored and marked from the JSRuntime. */
michael@0 1922 JSScript *script;
michael@0 1923 ScriptCounts scriptCounts;
michael@0 1924
michael@0 1925 PCCounts &getPCCounts(jsbytecode *pc) const {
michael@0 1926 return scriptCounts.pcCountsVector[script->pcToOffset(pc)];
michael@0 1927 }
michael@0 1928
michael@0 1929 jit::IonScriptCounts *getIonCounts() const {
michael@0 1930 return scriptCounts.ionCounts;
michael@0 1931 }
michael@0 1932 };
michael@0 1933
michael@0 1934 struct GSNCache;
michael@0 1935
michael@0 1936 jssrcnote *
michael@0 1937 GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc);
michael@0 1938
michael@0 1939 } /* namespace js */
michael@0 1940
michael@0 1941 extern jssrcnote *
michael@0 1942 js_GetSrcNote(JSContext *cx, JSScript *script, jsbytecode *pc);
michael@0 1943
michael@0 1944 extern jsbytecode *
michael@0 1945 js_LineNumberToPC(JSScript *script, unsigned lineno);
michael@0 1946
michael@0 1947 extern JS_FRIEND_API(unsigned)
michael@0 1948 js_GetScriptLineExtent(JSScript *script);
michael@0 1949
michael@0 1950 namespace js {
michael@0 1951
michael@0 1952 extern unsigned
michael@0 1953 PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp = nullptr);
michael@0 1954
michael@0 1955 extern unsigned
michael@0 1956 PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc,
michael@0 1957 unsigned *columnp = nullptr);
michael@0 1958
michael@0 1959 /*
michael@0 1960 * This function returns the file and line number of the script currently
michael@0 1961 * executing on cx. If there is no current script executing on cx (e.g., a
michael@0 1962 * native called directly through JSAPI (e.g., by setTimeout)), nullptr and 0
michael@0 1963 * are returned as the file and line. Additionally, this function avoids the
michael@0 1964 * full linear scan to compute line number when the caller guarantees that the
michael@0 1965 * script compilation occurs at a JSOP_EVAL/JSOP_SPREADEVAL.
michael@0 1966 */
michael@0 1967
michael@0 1968 enum LineOption {
michael@0 1969 CALLED_FROM_JSOP_EVAL,
michael@0 1970 NOT_CALLED_FROM_JSOP_EVAL
michael@0 1971 };
michael@0 1972
michael@0 1973 extern void
michael@0 1974 DescribeScriptedCallerForCompilation(JSContext *cx, MutableHandleScript maybeScript,
michael@0 1975 const char **file, unsigned *linenop,
michael@0 1976 uint32_t *pcOffset, JSPrincipals **origin,
michael@0 1977 LineOption opt = NOT_CALLED_FROM_JSOP_EVAL);
michael@0 1978
michael@0 1979 bool
michael@0 1980 CloneFunctionScript(JSContext *cx, HandleFunction original, HandleFunction clone,
michael@0 1981 NewObjectKind newKind = GenericObject);
michael@0 1982
michael@0 1983 /*
michael@0 1984 * JSAPI clients are allowed to leave CompileOptions.originPrincipals nullptr in
michael@0 1985 * which case the JS engine sets options.originPrincipals = origin.principals.
michael@0 1986 * This normalization step must occur before the originPrincipals get stored in
michael@0 1987 * the JSScript/ScriptSource.
michael@0 1988 */
michael@0 1989
michael@0 1990 static inline JSPrincipals *
michael@0 1991 NormalizeOriginPrincipals(JSPrincipals *principals, JSPrincipals *originPrincipals)
michael@0 1992 {
michael@0 1993 return originPrincipals ? originPrincipals : principals;
michael@0 1994 }
michael@0 1995
michael@0 1996 } /* namespace js */
michael@0 1997
michael@0 1998 #endif /* jsscript_h */

mercurial