1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsscript.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1998 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* JS script descriptor. */ 1.11 + 1.12 +#ifndef jsscript_h 1.13 +#define jsscript_h 1.14 + 1.15 +#include "mozilla/MemoryReporting.h" 1.16 +#include "mozilla/PodOperations.h" 1.17 + 1.18 +#include "jsatom.h" 1.19 +#ifdef JS_THREADSAFE 1.20 +#include "jslock.h" 1.21 +#endif 1.22 +#include "jsobj.h" 1.23 +#include "jsopcode.h" 1.24 +#include "jstypes.h" 1.25 + 1.26 +#include "gc/Barrier.h" 1.27 +#include "gc/Rooting.h" 1.28 +#include "jit/IonCode.h" 1.29 +#include "vm/Shape.h" 1.30 + 1.31 +namespace JS { 1.32 +struct ScriptSourceInfo; 1.33 +} 1.34 + 1.35 +namespace js { 1.36 + 1.37 +namespace jit { 1.38 + struct BaselineScript; 1.39 + struct IonScriptCounts; 1.40 +} 1.41 + 1.42 +# define ION_DISABLED_SCRIPT ((js::jit::IonScript *)0x1) 1.43 +# define ION_COMPILING_SCRIPT ((js::jit::IonScript *)0x2) 1.44 + 1.45 +# define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript *)0x1) 1.46 + 1.47 +class BreakpointSite; 1.48 +class BindingIter; 1.49 +class LazyScript; 1.50 +class RegExpObject; 1.51 +struct SourceCompressionTask; 1.52 +class Shape; 1.53 +class WatchpointMap; 1.54 +class NestedScopeObject; 1.55 + 1.56 +namespace frontend { 1.57 + class BytecodeEmitter; 1.58 +} 1.59 + 1.60 +} 1.61 + 1.62 +/* 1.63 + * Type of try note associated with each catch or finally block, and also with 1.64 + * for-in and other kinds of loops. Non-for-in loops do not need these notes 1.65 + * for exception unwinding, but storing their boundaries here is helpful for 1.66 + * heuristics that need to know whether a given op is inside a loop. 1.67 + */ 1.68 +typedef enum JSTryNoteKind { 1.69 + JSTRY_CATCH, 1.70 + JSTRY_FINALLY, 1.71 + JSTRY_ITER, 1.72 + JSTRY_LOOP 1.73 +} JSTryNoteKind; 1.74 + 1.75 +/* 1.76 + * Exception handling record. 1.77 + */ 1.78 +struct JSTryNote { 1.79 + uint8_t kind; /* one of JSTryNoteKind */ 1.80 + uint32_t stackDepth; /* stack depth upon exception handler entry */ 1.81 + uint32_t start; /* start of the try statement or loop 1.82 + relative to script->main */ 1.83 + uint32_t length; /* length of the try statement or loop */ 1.84 +}; 1.85 + 1.86 +namespace js { 1.87 + 1.88 +// A block scope has a range in bytecode: it is entered at some offset, and left 1.89 +// at some later offset. Scopes can be nested. Given an offset, the 1.90 +// BlockScopeNote containing that offset whose with the highest start value 1.91 +// indicates the block scope. The block scope list is sorted by increasing 1.92 +// start value. 1.93 +// 1.94 +// It is possible to leave a scope nonlocally, for example via a "break" 1.95 +// statement, so there may be short bytecode ranges in a block scope in which we 1.96 +// are popping the block chain in preparation for a goto. These exits are also 1.97 +// nested with respect to outer scopes. The scopes in these exits are indicated 1.98 +// by the "index" field, just like any other block. If a nonlocal exit pops the 1.99 +// last block scope, the index will be NoBlockScopeIndex. 1.100 +// 1.101 +struct BlockScopeNote { 1.102 + static const uint32_t NoBlockScopeIndex = UINT32_MAX; 1.103 + 1.104 + uint32_t index; // Index of NestedScopeObject in the object 1.105 + // array, or NoBlockScopeIndex if there is no 1.106 + // block scope in this range. 1.107 + uint32_t start; // Bytecode offset at which this scope starts, 1.108 + // from script->main(). 1.109 + uint32_t length; // Bytecode length of scope. 1.110 + uint32_t parent; // Index of parent block scope in notes, or UINT32_MAX. 1.111 +}; 1.112 + 1.113 +struct ConstArray { 1.114 + js::HeapValue *vector; /* array of indexed constant values */ 1.115 + uint32_t length; 1.116 +}; 1.117 + 1.118 +struct ObjectArray { 1.119 + js::HeapPtrObject *vector; // Array of indexed objects. 1.120 + uint32_t length; // Count of indexed objects. 1.121 +}; 1.122 + 1.123 +struct TryNoteArray { 1.124 + JSTryNote *vector; // Array of indexed try notes. 1.125 + uint32_t length; // Count of indexed try notes. 1.126 +}; 1.127 + 1.128 +struct BlockScopeArray { 1.129 + BlockScopeNote *vector; // Array of indexed BlockScopeNote records. 1.130 + uint32_t length; // Count of indexed try notes. 1.131 +}; 1.132 + 1.133 +class Binding 1.134 +{ 1.135 + // One JSScript stores one Binding per formal/variable so we use a 1.136 + // packed-word representation. 1.137 + uintptr_t bits_; 1.138 + 1.139 + static const uintptr_t KIND_MASK = 0x3; 1.140 + static const uintptr_t ALIASED_BIT = 0x4; 1.141 + static const uintptr_t NAME_MASK = ~(KIND_MASK | ALIASED_BIT); 1.142 + 1.143 + public: 1.144 + // A "binding" is a formal, 'var', or 'const' declaration. A function's 1.145 + // lexical scope is composed of these three kinds of bindings. 1.146 + enum Kind { ARGUMENT, VARIABLE, CONSTANT }; 1.147 + 1.148 + explicit Binding() : bits_(0) {} 1.149 + 1.150 + Binding(PropertyName *name, Kind kind, bool aliased) { 1.151 + JS_STATIC_ASSERT(CONSTANT <= KIND_MASK); 1.152 + JS_ASSERT((uintptr_t(name) & ~NAME_MASK) == 0); 1.153 + JS_ASSERT((uintptr_t(kind) & ~KIND_MASK) == 0); 1.154 + bits_ = uintptr_t(name) | uintptr_t(kind) | (aliased ? ALIASED_BIT : 0); 1.155 + } 1.156 + 1.157 + PropertyName *name() const { 1.158 + return (PropertyName *)(bits_ & NAME_MASK); 1.159 + } 1.160 + 1.161 + Kind kind() const { 1.162 + return Kind(bits_ & KIND_MASK); 1.163 + } 1.164 + 1.165 + bool aliased() const { 1.166 + return bool(bits_ & ALIASED_BIT); 1.167 + } 1.168 +}; 1.169 + 1.170 +JS_STATIC_ASSERT(sizeof(Binding) == sizeof(uintptr_t)); 1.171 + 1.172 +class Bindings; 1.173 +typedef InternalHandle<Bindings *> InternalBindingsHandle; 1.174 + 1.175 +/* 1.176 + * Formal parameters and local variables are stored in a shape tree 1.177 + * path encapsulated within this class. This class represents bindings for 1.178 + * both function and top-level scripts (the latter is needed to track names in 1.179 + * strict mode eval code, to give such code its own lexical environment). 1.180 + */ 1.181 +class Bindings 1.182 +{ 1.183 + friend class BindingIter; 1.184 + friend class AliasedFormalIter; 1.185 + 1.186 + HeapPtr<Shape> callObjShape_; 1.187 + uintptr_t bindingArrayAndFlag_; 1.188 + uint16_t numArgs_; 1.189 + uint16_t numBlockScoped_; 1.190 + uint32_t numVars_; 1.191 + 1.192 + /* 1.193 + * During parsing, bindings are allocated out of a temporary LifoAlloc. 1.194 + * After parsing, a JSScript object is created and the bindings are 1.195 + * permanently transferred to it. On error paths, the JSScript object may 1.196 + * end up with bindings that still point to the (new released) LifoAlloc 1.197 + * memory. To avoid tracing these bindings during GC, we keep track of 1.198 + * whether the bindings are temporary or permanent in the low bit of 1.199 + * bindingArrayAndFlag_. 1.200 + */ 1.201 + static const uintptr_t TEMPORARY_STORAGE_BIT = 0x1; 1.202 + bool bindingArrayUsingTemporaryStorage() const { 1.203 + return bindingArrayAndFlag_ & TEMPORARY_STORAGE_BIT; 1.204 + } 1.205 + 1.206 + public: 1.207 + 1.208 + Binding *bindingArray() const { 1.209 + return reinterpret_cast<Binding *>(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT); 1.210 + } 1.211 + 1.212 + inline Bindings(); 1.213 + 1.214 + /* 1.215 + * Initialize a Bindings with a pointer into temporary storage. 1.216 + * bindingArray must have length numArgs+numVars. Before the temporary 1.217 + * storage is release, switchToScriptStorage must be called, providing a 1.218 + * pointer into the Binding array stored in script->data. 1.219 + */ 1.220 + static bool initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self, 1.221 + unsigned numArgs, uint32_t numVars, 1.222 + Binding *bindingArray, unsigned numBlockScoped); 1.223 + 1.224 + // CompileScript parses and compiles one statement at a time, but the result 1.225 + // is one Script object. There will be no vars or bindings, because those 1.226 + // go on the global, but there may be block-scoped locals, and the number of 1.227 + // block-scoped locals may increase as we parse more expressions. This 1.228 + // helper updates the number of block scoped variables in a script as it is 1.229 + // being parsed. 1.230 + void updateNumBlockScoped(unsigned numBlockScoped) { 1.231 + JS_ASSERT(!callObjShape_); 1.232 + JS_ASSERT(numVars_ == 0); 1.233 + JS_ASSERT(numBlockScoped < LOCALNO_LIMIT); 1.234 + JS_ASSERT(numBlockScoped >= numBlockScoped_); 1.235 + numBlockScoped_ = numBlockScoped; 1.236 + } 1.237 + 1.238 + uint8_t *switchToScriptStorage(Binding *newStorage); 1.239 + 1.240 + /* 1.241 + * Clone srcScript's bindings (as part of js::CloneScript). dstScriptData 1.242 + * is the pointer to what will eventually be dstScript->data. 1.243 + */ 1.244 + static bool clone(JSContext *cx, InternalBindingsHandle self, uint8_t *dstScriptData, 1.245 + HandleScript srcScript); 1.246 + 1.247 + unsigned numArgs() const { return numArgs_; } 1.248 + uint32_t numVars() const { return numVars_; } 1.249 + unsigned numBlockScoped() const { return numBlockScoped_; } 1.250 + uint32_t numLocals() const { return numVars() + numBlockScoped(); } 1.251 + 1.252 + // Return the size of the bindingArray. 1.253 + uint32_t count() const { return numArgs() + numVars(); } 1.254 + 1.255 + /* Return the initial shape of call objects created for this scope. */ 1.256 + Shape *callObjShape() const { return callObjShape_; } 1.257 + 1.258 + /* Convenience method to get the var index of 'arguments'. */ 1.259 + static uint32_t argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle); 1.260 + 1.261 + /* Return whether the binding at bindingIndex is aliased. */ 1.262 + bool bindingIsAliased(uint32_t bindingIndex); 1.263 + 1.264 + /* Return whether this scope has any aliased bindings. */ 1.265 + bool hasAnyAliasedBindings() const { 1.266 + if (!callObjShape_) 1.267 + return false; 1.268 + 1.269 + return !callObjShape_->isEmptyShape(); 1.270 + } 1.271 + 1.272 + void trace(JSTracer *trc); 1.273 +}; 1.274 + 1.275 +template <> 1.276 +struct GCMethods<Bindings> { 1.277 + static Bindings initial(); 1.278 + static ThingRootKind kind() { return THING_ROOT_BINDINGS; } 1.279 + static bool poisoned(const Bindings &bindings) { 1.280 + return IsPoisonedPtr(static_cast<Shape *>(bindings.callObjShape())); 1.281 + } 1.282 +}; 1.283 + 1.284 +class ScriptCounts 1.285 +{ 1.286 + friend class ::JSScript; 1.287 + friend struct ScriptAndCounts; 1.288 + 1.289 + /* 1.290 + * This points to a single block that holds an array of PCCounts followed 1.291 + * by an array of doubles. Each element in the PCCounts array has a 1.292 + * pointer into the array of doubles. 1.293 + */ 1.294 + PCCounts *pcCountsVector; 1.295 + 1.296 + /* Information about any Ion compilations for the script. */ 1.297 + jit::IonScriptCounts *ionCounts; 1.298 + 1.299 + public: 1.300 + ScriptCounts() : pcCountsVector(nullptr), ionCounts(nullptr) { } 1.301 + 1.302 + inline void destroy(FreeOp *fop); 1.303 + 1.304 + void set(js::ScriptCounts counts) { 1.305 + pcCountsVector = counts.pcCountsVector; 1.306 + ionCounts = counts.ionCounts; 1.307 + } 1.308 +}; 1.309 + 1.310 +typedef HashMap<JSScript *, 1.311 + ScriptCounts, 1.312 + DefaultHasher<JSScript *>, 1.313 + SystemAllocPolicy> ScriptCountsMap; 1.314 + 1.315 +class DebugScript 1.316 +{ 1.317 + friend class ::JSScript; 1.318 + 1.319 + /* 1.320 + * When non-zero, compile script in single-step mode. The top bit is set and 1.321 + * cleared by setStepMode, as used by JSD. The lower bits are a count, 1.322 + * adjusted by changeStepModeCount, used by the Debugger object. Only 1.323 + * when the bit is clear and the count is zero may we compile the script 1.324 + * without single-step support. 1.325 + */ 1.326 + uint32_t stepMode; 1.327 + 1.328 + /* Number of breakpoint sites at opcodes in the script. */ 1.329 + uint32_t numSites; 1.330 + 1.331 + /* 1.332 + * Array with all breakpoints installed at opcodes in the script, indexed 1.333 + * by the offset of the opcode into the script. 1.334 + */ 1.335 + BreakpointSite *breakpoints[1]; 1.336 +}; 1.337 + 1.338 +typedef HashMap<JSScript *, 1.339 + DebugScript *, 1.340 + DefaultHasher<JSScript *>, 1.341 + SystemAllocPolicy> DebugScriptMap; 1.342 + 1.343 +class ScriptSource; 1.344 + 1.345 +class SourceDataCache 1.346 +{ 1.347 + typedef HashMap<ScriptSource *, 1.348 + const jschar *, 1.349 + DefaultHasher<ScriptSource *>, 1.350 + SystemAllocPolicy> Map; 1.351 + 1.352 + public: 1.353 + // Hold an entry in the source data cache and prevent it from being purged on GC. 1.354 + class AutoHoldEntry 1.355 + { 1.356 + SourceDataCache *cache_; 1.357 + ScriptSource *source_; 1.358 + const jschar *charsToFree_; 1.359 + public: 1.360 + explicit AutoHoldEntry(); 1.361 + ~AutoHoldEntry(); 1.362 + private: 1.363 + void holdEntry(SourceDataCache *cache, ScriptSource *source); 1.364 + void deferDelete(const jschar *chars); 1.365 + ScriptSource *source() const { return source_; } 1.366 + friend class SourceDataCache; 1.367 + }; 1.368 + 1.369 + private: 1.370 + Map *map_; 1.371 + AutoHoldEntry *holder_; 1.372 + 1.373 + public: 1.374 + SourceDataCache() : map_(nullptr), holder_(nullptr) {} 1.375 + 1.376 + const jschar *lookup(ScriptSource *ss, AutoHoldEntry &asp); 1.377 + bool put(ScriptSource *ss, const jschar *chars, AutoHoldEntry &asp); 1.378 + 1.379 + void purge(); 1.380 + 1.381 + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); 1.382 + 1.383 + private: 1.384 + void holdEntry(AutoHoldEntry &holder, ScriptSource *ss); 1.385 + void releaseEntry(AutoHoldEntry &holder); 1.386 +}; 1.387 + 1.388 +class ScriptSource 1.389 +{ 1.390 + friend class SourceCompressionTask; 1.391 + 1.392 + // A note on concurrency: 1.393 + // 1.394 + // The source may be compressed by a worker thread during parsing. (See 1.395 + // SourceCompressionTask.) When compression is running in the background, 1.396 + // ready() returns false. The compression thread touches the |data| union 1.397 + // and |compressedLength_|. Therefore, it is not safe to read these members 1.398 + // unless ready() is true. With that said, users of the public ScriptSource 1.399 + // API should be fine. 1.400 + 1.401 + union { 1.402 + // Before setSourceCopy or setSource are successfully called, this union 1.403 + // has a nullptr pointer. When the script source is ready, 1.404 + // compressedLength_ != 0 implies compressed holds the compressed data; 1.405 + // otherwise, source holds the uncompressed source. There is a special 1.406 + // pointer |emptySource| for source code for length 0. 1.407 + // 1.408 + // The only function allowed to malloc, realloc, or free the pointers in 1.409 + // this union is adjustDataSize(). Don't do it elsewhere. 1.410 + jschar *source; 1.411 + unsigned char *compressed; 1.412 + } data; 1.413 + uint32_t refs; 1.414 + uint32_t length_; 1.415 + uint32_t compressedLength_; 1.416 + char *filename_; 1.417 + jschar *displayURL_; 1.418 + jschar *sourceMapURL_; 1.419 + JSPrincipals *originPrincipals_; 1.420 + 1.421 + // bytecode offset in caller script that generated this code. 1.422 + // This is present for eval-ed code, as well as "new Function(...)"-introduced 1.423 + // scripts. 1.424 + uint32_t introductionOffset_; 1.425 + 1.426 + // If this ScriptSource was generated by a code-introduction mechanism such as |eval| 1.427 + // or |new Function|, the debugger needs access to the "raw" filename of the top-level 1.428 + // script that contains the eval-ing code. To keep track of this, we must preserve 1.429 + // the original outermost filename (of the original introducer script), so that instead 1.430 + // of a filename of "foo.js line 30 > eval line 10 > Function", we can obtain the 1.431 + // original raw filename of "foo.js". 1.432 + char *introducerFilename_; 1.433 + 1.434 + // A string indicating how this source code was introduced into the system. 1.435 + // This accessor returns one of the following values: 1.436 + // "eval" for code passed to |eval|. 1.437 + // "Function" for code passed to the |Function| constructor. 1.438 + // "Worker" for code loaded by calling the Web worker constructor—the worker's main script. 1.439 + // "importScripts" for code by calling |importScripts| in a web worker. 1.440 + // "handler" for code assigned to DOM elements' event handler IDL attributes. 1.441 + // "scriptElement" for code belonging to <script> elements. 1.442 + // undefined if the implementation doesn't know how the code was introduced. 1.443 + // This is a constant, statically allocated C string, so does not need 1.444 + // memory management. 1.445 + const char *introductionType_; 1.446 + 1.447 + // True if we can call JSRuntime::sourceHook to load the source on 1.448 + // demand. If sourceRetrievable_ and hasSourceData() are false, it is not 1.449 + // possible to get source at all. 1.450 + bool sourceRetrievable_:1; 1.451 + bool argumentsNotIncluded_:1; 1.452 + bool ready_:1; 1.453 + bool hasIntroductionOffset_:1; 1.454 + 1.455 + public: 1.456 + explicit ScriptSource() 1.457 + : refs(0), 1.458 + length_(0), 1.459 + compressedLength_(0), 1.460 + filename_(nullptr), 1.461 + displayURL_(nullptr), 1.462 + sourceMapURL_(nullptr), 1.463 + originPrincipals_(nullptr), 1.464 + introductionOffset_(0), 1.465 + introducerFilename_(nullptr), 1.466 + introductionType_(nullptr), 1.467 + sourceRetrievable_(false), 1.468 + argumentsNotIncluded_(false), 1.469 + ready_(true), 1.470 + hasIntroductionOffset_(false) 1.471 + { 1.472 + data.source = nullptr; 1.473 + } 1.474 + void incref() { refs++; } 1.475 + void decref() { 1.476 + JS_ASSERT(refs != 0); 1.477 + if (--refs == 0) 1.478 + destroy(); 1.479 + } 1.480 + bool initFromOptions(ExclusiveContext *cx, const ReadOnlyCompileOptions &options); 1.481 + bool setSourceCopy(ExclusiveContext *cx, 1.482 + JS::SourceBufferHolder &srcBuf, 1.483 + bool argumentsNotIncluded, 1.484 + SourceCompressionTask *tok); 1.485 + void setSource(const jschar *src, size_t length); 1.486 + bool ready() const { return ready_; } 1.487 + void setSourceRetrievable() { sourceRetrievable_ = true; } 1.488 + bool sourceRetrievable() const { return sourceRetrievable_; } 1.489 + bool hasSourceData() const { return !ready() || !!data.source; } 1.490 + uint32_t length() const { 1.491 + JS_ASSERT(hasSourceData()); 1.492 + return length_; 1.493 + } 1.494 + bool argumentsNotIncluded() const { 1.495 + JS_ASSERT(hasSourceData()); 1.496 + return argumentsNotIncluded_; 1.497 + } 1.498 + const jschar *chars(JSContext *cx, SourceDataCache::AutoHoldEntry &asp); 1.499 + JSFlatString *substring(JSContext *cx, uint32_t start, uint32_t stop); 1.500 + void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, 1.501 + JS::ScriptSourceInfo *info) const; 1.502 + 1.503 + // XDR handling 1.504 + template <XDRMode mode> 1.505 + bool performXDR(XDRState<mode> *xdr); 1.506 + 1.507 + bool setFilename(ExclusiveContext *cx, const char *filename); 1.508 + const char *introducerFilename() const { 1.509 + return introducerFilename_; 1.510 + } 1.511 + bool hasIntroductionType() const { 1.512 + return introductionType_; 1.513 + } 1.514 + const char *introductionType() const { 1.515 + JS_ASSERT(hasIntroductionType()); 1.516 + return introductionType_; 1.517 + } 1.518 + const char *filename() const { 1.519 + return filename_; 1.520 + } 1.521 + 1.522 + // Display URLs 1.523 + bool setDisplayURL(ExclusiveContext *cx, const jschar *displayURL); 1.524 + const jschar *displayURL(); 1.525 + bool hasDisplayURL() const { return displayURL_ != nullptr; } 1.526 + 1.527 + // Source maps 1.528 + bool setSourceMapURL(ExclusiveContext *cx, const jschar *sourceMapURL); 1.529 + const jschar *sourceMapURL(); 1.530 + bool hasSourceMapURL() const { return sourceMapURL_ != nullptr; } 1.531 + 1.532 + JSPrincipals *originPrincipals() const { return originPrincipals_; } 1.533 + 1.534 + bool hasIntroductionOffset() const { return hasIntroductionOffset_; } 1.535 + uint32_t introductionOffset() const { 1.536 + JS_ASSERT(hasIntroductionOffset()); 1.537 + return introductionOffset_; 1.538 + } 1.539 + void setIntroductionOffset(uint32_t offset) { 1.540 + JS_ASSERT(!hasIntroductionOffset()); 1.541 + JS_ASSERT(offset <= (uint32_t)INT32_MAX); 1.542 + introductionOffset_ = offset; 1.543 + hasIntroductionOffset_ = true; 1.544 + } 1.545 + 1.546 + private: 1.547 + void destroy(); 1.548 + bool compressed() const { return compressedLength_ != 0; } 1.549 + size_t computedSizeOfData() const { 1.550 + return compressed() ? compressedLength_ : sizeof(jschar) * length_; 1.551 + } 1.552 + bool adjustDataSize(size_t nbytes); 1.553 + const jschar *getOffThreadCompressionChars(ExclusiveContext *cx); 1.554 +}; 1.555 + 1.556 +class ScriptSourceHolder 1.557 +{ 1.558 + ScriptSource *ss; 1.559 + public: 1.560 + explicit ScriptSourceHolder(ScriptSource *ss) 1.561 + : ss(ss) 1.562 + { 1.563 + ss->incref(); 1.564 + } 1.565 + ~ScriptSourceHolder() 1.566 + { 1.567 + ss->decref(); 1.568 + } 1.569 +}; 1.570 + 1.571 +class ScriptSourceObject : public JSObject 1.572 +{ 1.573 + public: 1.574 + static const Class class_; 1.575 + 1.576 + static void trace(JSTracer *trc, JSObject *obj); 1.577 + static void finalize(FreeOp *fop, JSObject *obj); 1.578 + static ScriptSourceObject *create(ExclusiveContext *cx, ScriptSource *source, 1.579 + const ReadOnlyCompileOptions &options); 1.580 + 1.581 + ScriptSource *source() { 1.582 + return static_cast<ScriptSource *>(getReservedSlot(SOURCE_SLOT).toPrivate()); 1.583 + } 1.584 + 1.585 + void setSource(ScriptSource *source); 1.586 + 1.587 + JSObject *element() const; 1.588 + void initElement(HandleObject element); 1.589 + const Value &elementAttributeName() const; 1.590 + 1.591 + JSScript *introductionScript() const { 1.592 + void *untyped = getReservedSlot(INTRODUCTION_SCRIPT_SLOT).toPrivate(); 1.593 + return static_cast<JSScript *>(untyped); 1.594 + } 1.595 + void initIntroductionScript(JSScript *script); 1.596 + 1.597 + private: 1.598 + static const uint32_t SOURCE_SLOT = 0; 1.599 + static const uint32_t ELEMENT_SLOT = 1; 1.600 + static const uint32_t ELEMENT_PROPERTY_SLOT = 2; 1.601 + static const uint32_t INTRODUCTION_SCRIPT_SLOT = 3; 1.602 + static const uint32_t RESERVED_SLOTS = 4; 1.603 +}; 1.604 + 1.605 +enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator }; 1.606 + 1.607 +static inline unsigned 1.608 +GeneratorKindAsBits(GeneratorKind generatorKind) { 1.609 + return static_cast<unsigned>(generatorKind); 1.610 +} 1.611 + 1.612 +static inline GeneratorKind 1.613 +GeneratorKindFromBits(unsigned val) { 1.614 + JS_ASSERT(val <= StarGenerator); 1.615 + return static_cast<GeneratorKind>(val); 1.616 +} 1.617 + 1.618 +/* 1.619 + * NB: after a successful XDR_DECODE, XDRScript callers must do any required 1.620 + * subsequent set-up of owning function or script object and then call 1.621 + * js_CallNewScriptHook. 1.622 + */ 1.623 +template<XDRMode mode> 1.624 +bool 1.625 +XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript, 1.626 + HandleFunction fun, MutableHandleScript scriptp); 1.627 + 1.628 +JSScript * 1.629 +CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, HandleScript script, 1.630 + NewObjectKind newKind = GenericObject); 1.631 + 1.632 +template<XDRMode mode> 1.633 +bool 1.634 +XDRLazyScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript, 1.635 + HandleFunction fun, MutableHandle<LazyScript *> lazy); 1.636 + 1.637 +/* 1.638 + * Code any constant value. 1.639 + */ 1.640 +template<XDRMode mode> 1.641 +bool 1.642 +XDRScriptConst(XDRState<mode> *xdr, MutableHandleValue vp); 1.643 + 1.644 +} /* namespace js */ 1.645 + 1.646 +class JSScript : public js::gc::BarrieredCell<JSScript> 1.647 +{ 1.648 + static const uint32_t stepFlagMask = 0x80000000U; 1.649 + static const uint32_t stepCountMask = 0x7fffffffU; 1.650 + 1.651 + template <js::XDRMode mode> 1.652 + friend 1.653 + bool 1.654 + js::XDRScript(js::XDRState<mode> *xdr, js::HandleObject enclosingScope, js::HandleScript enclosingScript, 1.655 + js::HandleFunction fun, js::MutableHandleScript scriptp); 1.656 + 1.657 + friend JSScript * 1.658 + js::CloneScript(JSContext *cx, js::HandleObject enclosingScope, js::HandleFunction fun, js::HandleScript src, 1.659 + js::NewObjectKind newKind); 1.660 + 1.661 + public: 1.662 + // 1.663 + // We order fields according to their size in order to avoid wasting space 1.664 + // for alignment. 1.665 + // 1.666 + 1.667 + // Larger-than-word-sized fields. 1.668 + 1.669 + public: 1.670 + js::Bindings bindings; /* names of top-level variables in this script 1.671 + (and arguments if this is a function script) */ 1.672 + 1.673 + bool hasAnyAliasedBindings() const { 1.674 + return bindings.hasAnyAliasedBindings(); 1.675 + } 1.676 + 1.677 + js::Binding *bindingArray() const { 1.678 + return bindings.bindingArray(); 1.679 + } 1.680 + 1.681 + unsigned numArgs() const { 1.682 + return bindings.numArgs(); 1.683 + } 1.684 + 1.685 + js::Shape *callObjShape() const { 1.686 + return bindings.callObjShape(); 1.687 + } 1.688 + 1.689 + // Word-sized fields. 1.690 + 1.691 + private: 1.692 + jsbytecode *code_; /* bytecodes and their immediate operands */ 1.693 + public: 1.694 + uint8_t *data; /* pointer to variable-length data array (see 1.695 + comment above Create() for details) */ 1.696 + 1.697 + js::HeapPtrAtom *atoms; /* maps immediate index to literal struct */ 1.698 + 1.699 + JSCompartment *compartment_; 1.700 + 1.701 + /* Persistent type information retained across GCs. */ 1.702 + js::types::TypeScript *types; 1.703 + 1.704 + private: 1.705 + // This script's ScriptSourceObject, or a CCW thereof. 1.706 + // 1.707 + // (When we clone a JSScript into a new compartment, we don't clone its 1.708 + // source object. Instead, the clone refers to a wrapper.) 1.709 + js::HeapPtrObject sourceObject_; 1.710 + 1.711 + js::HeapPtrFunction function_; 1.712 + 1.713 + // For callsite clones, which cannot have enclosing scopes, the original 1.714 + // function; otherwise the enclosing scope 1.715 + js::HeapPtrObject enclosingScopeOrOriginalFunction_; 1.716 + 1.717 + /* Information attached by Baseline/Ion for sequential mode execution. */ 1.718 + js::jit::IonScript *ion; 1.719 + js::jit::BaselineScript *baseline; 1.720 + 1.721 + /* Information attached by Ion for parallel mode execution */ 1.722 + js::jit::IonScript *parallelIon; 1.723 + 1.724 + /* Information used to re-lazify a lazily-parsed interpreted function. */ 1.725 + js::LazyScript *lazyScript; 1.726 + 1.727 + /* 1.728 + * Pointer to either baseline->method()->raw() or ion->method()->raw(), or 1.729 + * nullptr if there's no Baseline or Ion script. 1.730 + */ 1.731 + uint8_t *baselineOrIonRaw; 1.732 + uint8_t *baselineOrIonSkipArgCheck; 1.733 + 1.734 + // 32-bit fields. 1.735 + 1.736 + uint32_t length_; /* length of code vector */ 1.737 + uint32_t dataSize_; /* size of the used part of the data array */ 1.738 + 1.739 + uint32_t lineno_; /* base line number of script */ 1.740 + uint32_t column_; /* base column of script, optionally set */ 1.741 + 1.742 + uint32_t mainOffset_;/* offset of main entry point from code, after 1.743 + predef'ing prolog */ 1.744 + 1.745 + uint32_t natoms_; /* length of atoms array */ 1.746 + uint32_t nslots_; /* vars plus maximum stack depth */ 1.747 + 1.748 + /* Range of characters in scriptSource which contains this script's source. */ 1.749 + uint32_t sourceStart_; 1.750 + uint32_t sourceEnd_; 1.751 + 1.752 + uint32_t useCount; /* Number of times the script has been called 1.753 + * or has had backedges taken. When running in 1.754 + * ion, also increased for any inlined scripts. 1.755 + * Reset if the script's JIT code is forcibly 1.756 + * discarded. */ 1.757 + 1.758 +#ifdef DEBUG 1.759 + // Unique identifier within the compartment for this script, used for 1.760 + // printing analysis information. 1.761 + uint32_t id_; 1.762 + uint32_t idpad; 1.763 +#endif 1.764 + 1.765 + // 16-bit fields. 1.766 + 1.767 + uint16_t version; /* JS version under which script was compiled */ 1.768 + 1.769 + uint16_t funLength_; /* ES6 function length */ 1.770 + 1.771 + uint16_t nTypeSets_; /* number of type sets used in this script for 1.772 + dynamic type monitoring */ 1.773 + 1.774 + uint16_t staticLevel_;/* static level for display maintenance */ 1.775 + 1.776 + // Bit fields. 1.777 + 1.778 + public: 1.779 + // The kinds of the optional arrays. 1.780 + enum ArrayKind { 1.781 + CONSTS, 1.782 + OBJECTS, 1.783 + REGEXPS, 1.784 + TRYNOTES, 1.785 + BLOCK_SCOPES, 1.786 + ARRAY_KIND_BITS 1.787 + }; 1.788 + 1.789 + private: 1.790 + // The bits in this field indicate the presence/non-presence of several 1.791 + // optional arrays in |data|. See the comments above Create() for details. 1.792 + uint8_t hasArrayBits:ARRAY_KIND_BITS; 1.793 + 1.794 + // The GeneratorKind of the script. 1.795 + uint8_t generatorKindBits_:2; 1.796 + 1.797 + // 1-bit fields. 1.798 + 1.799 + // No need for result value of last expression statement. 1.800 + bool noScriptRval_:1; 1.801 + 1.802 + // Can call getCallerFunction(). 1.803 + bool savedCallerFun_:1; 1.804 + 1.805 + // Code is in strict mode. 1.806 + bool strict_:1; 1.807 + 1.808 + // Code has "use strict"; explicitly. 1.809 + bool explicitUseStrict_:1; 1.810 + 1.811 + // See Parser::compileAndGo. 1.812 + bool compileAndGo_:1; 1.813 + 1.814 + // see Parser::selfHostingMode. 1.815 + bool selfHosted_:1; 1.816 + 1.817 + // See FunctionContextFlags. 1.818 + bool bindingsAccessedDynamically_:1; 1.819 + bool funHasExtensibleScope_:1; 1.820 + bool funNeedsDeclEnvObject_:1; 1.821 + 1.822 + // True if any formalIsAliased(i). 1.823 + bool funHasAnyAliasedFormal_:1; 1.824 + 1.825 + // Have warned about uses of undefined properties in this script. 1.826 + bool warnedAboutUndefinedProp_:1; 1.827 + 1.828 + // Script has singleton objects. 1.829 + bool hasSingletons_:1; 1.830 + 1.831 + // Script is a lambda to treat as running once. 1.832 + bool treatAsRunOnce_:1; 1.833 + 1.834 + // If treatAsRunOnce, whether script has executed. 1.835 + bool hasRunOnce_:1; 1.836 + 1.837 + // Script has been reused for a clone. 1.838 + bool hasBeenCloned_:1; 1.839 + 1.840 + // Script has been inlined at least once, and can't be relazified. 1.841 + bool hasBeenInlined_:1; 1.842 + 1.843 + // Script came from eval(), and is still active. 1.844 + bool isActiveEval_:1; 1.845 + 1.846 + // Script came from eval(), and is in eval cache. 1.847 + bool isCachedEval_:1; 1.848 + 1.849 + // Set for functions defined at the top level within an 'eval' script. 1.850 + bool directlyInsideEval_:1; 1.851 + 1.852 + // Both 'arguments' and f.apply() are used. This is likely to be a wrapper. 1.853 + bool usesArgumentsAndApply_:1; 1.854 + 1.855 + /* script is attempted to be cloned anew at each callsite. This is 1.856 + temporarily needed for ParallelArray selfhosted code until type 1.857 + information can be made context sensitive. See discussion in 1.858 + bug 826148. */ 1.859 + bool shouldCloneAtCallsite_:1; 1.860 + bool isCallsiteClone_:1; /* is a callsite clone; has a link to the original function */ 1.861 + bool shouldInline_:1; /* hint to inline when possible */ 1.862 + 1.863 + // IonMonkey compilation hints. 1.864 + bool failedBoundsCheck_:1; /* script has had hoisted bounds checks fail */ 1.865 + bool failedShapeGuard_:1; /* script has had hoisted shape guard fail */ 1.866 + bool hadFrequentBailouts_:1; 1.867 + bool uninlineable_:1; /* explicitly marked as uninlineable */ 1.868 + 1.869 + // Idempotent cache has triggered invalidation. 1.870 + bool invalidatedIdempotentCache_:1; 1.871 + 1.872 + // If the generator was created implicitly via a generator expression, 1.873 + // isGeneratorExp will be true. 1.874 + bool isGeneratorExp_:1; 1.875 + 1.876 + // Script has an entry in JSCompartment::scriptCountsMap. 1.877 + bool hasScriptCounts_:1; 1.878 + 1.879 + // Script has an entry in JSCompartment::debugScriptMap. 1.880 + bool hasDebugScript_:1; 1.881 + 1.882 + // Freeze constraints for stack type sets have been generated. 1.883 + bool hasFreezeConstraints_:1; 1.884 + 1.885 + /* See comments below. */ 1.886 + bool argsHasVarBinding_:1; 1.887 + bool needsArgsAnalysis_:1; 1.888 + bool needsArgsObj_:1; 1.889 + 1.890 + // 1.891 + // End of fields. Start methods. 1.892 + // 1.893 + 1.894 + public: 1.895 + static JSScript *Create(js::ExclusiveContext *cx, 1.896 + js::HandleObject enclosingScope, bool savedCallerFun, 1.897 + const JS::ReadOnlyCompileOptions &options, unsigned staticLevel, 1.898 + js::HandleObject sourceObject, uint32_t sourceStart, 1.899 + uint32_t sourceEnd); 1.900 + 1.901 + void initCompartment(js::ExclusiveContext *cx); 1.902 + 1.903 + // Three ways ways to initialize a JSScript. Callers of partiallyInit() 1.904 + // and fullyInitTrivial() are responsible for notifying the debugger after 1.905 + // successfully creating any kind (function or other) of new JSScript. 1.906 + // However, callers of fullyInitFromEmitter() do not need to do this. 1.907 + static bool partiallyInit(js::ExclusiveContext *cx, JS::Handle<JSScript*> script, 1.908 + uint32_t nconsts, uint32_t nobjects, uint32_t nregexps, 1.909 + uint32_t ntrynotes, uint32_t nblockscopes, 1.910 + uint32_t nTypeSets); 1.911 + static bool fullyInitFromEmitter(js::ExclusiveContext *cx, JS::Handle<JSScript*> script, 1.912 + js::frontend::BytecodeEmitter *bce); 1.913 + // Initialize a no-op script. 1.914 + static bool fullyInitTrivial(js::ExclusiveContext *cx, JS::Handle<JSScript*> script); 1.915 + 1.916 + inline JSPrincipals *principals(); 1.917 + 1.918 + JSCompartment *compartment() const { return compartment_; } 1.919 + 1.920 + void setVersion(JSVersion v) { version = v; } 1.921 + 1.922 + // Script bytecode is immutable after creation. 1.923 + jsbytecode *code() const { 1.924 + return code_; 1.925 + } 1.926 + size_t length() const { 1.927 + return length_; 1.928 + } 1.929 + 1.930 + void setCode(jsbytecode *code) { code_ = code; } 1.931 + void setLength(size_t length) { length_ = length; } 1.932 + 1.933 + jsbytecode *codeEnd() const { return code() + length(); } 1.934 + 1.935 + bool containsPC(const jsbytecode *pc) const { 1.936 + return pc >= code() && pc < codeEnd(); 1.937 + } 1.938 + 1.939 + size_t pcToOffset(const jsbytecode *pc) const { 1.940 + JS_ASSERT(containsPC(pc)); 1.941 + return size_t(pc - code()); 1.942 + } 1.943 + 1.944 + jsbytecode *offsetToPC(size_t offset) const { 1.945 + JS_ASSERT(offset < length()); 1.946 + return code() + offset; 1.947 + } 1.948 + 1.949 + size_t mainOffset() const { 1.950 + return mainOffset_; 1.951 + } 1.952 + 1.953 + size_t lineno() const { 1.954 + return lineno_; 1.955 + } 1.956 + 1.957 + size_t column() const { 1.958 + return column_; 1.959 + } 1.960 + 1.961 + void setColumn(size_t column) { column_ = column; } 1.962 + 1.963 + // The fixed part of a stack frame is comprised of vars (in function code) 1.964 + // and block-scoped locals (in all kinds of code). 1.965 + size_t nfixed() const { 1.966 + return function_ ? bindings.numLocals() : bindings.numBlockScoped(); 1.967 + } 1.968 + 1.969 + // Number of fixed slots reserved for vars. Only nonzero for function code. 1.970 + size_t nfixedvars() const { 1.971 + return function_ ? bindings.numVars() : 0; 1.972 + } 1.973 + 1.974 + size_t nslots() const { 1.975 + return nslots_; 1.976 + } 1.977 + 1.978 + size_t staticLevel() const { 1.979 + return staticLevel_; 1.980 + } 1.981 + 1.982 + size_t nTypeSets() const { 1.983 + return nTypeSets_; 1.984 + } 1.985 + 1.986 + size_t funLength() const { 1.987 + return funLength_; 1.988 + } 1.989 + 1.990 + size_t sourceStart() const { 1.991 + return sourceStart_; 1.992 + } 1.993 + 1.994 + size_t sourceEnd() const { 1.995 + return sourceEnd_; 1.996 + } 1.997 + 1.998 + bool noScriptRval() const { 1.999 + return noScriptRval_; 1.1000 + } 1.1001 + 1.1002 + bool savedCallerFun() const { return savedCallerFun_; } 1.1003 + 1.1004 + bool strict() const { 1.1005 + return strict_; 1.1006 + } 1.1007 + 1.1008 + bool explicitUseStrict() const { return explicitUseStrict_; } 1.1009 + 1.1010 + bool compileAndGo() const { 1.1011 + return compileAndGo_; 1.1012 + } 1.1013 + 1.1014 + bool selfHosted() const { return selfHosted_; } 1.1015 + bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; } 1.1016 + bool funHasExtensibleScope() const { 1.1017 + return funHasExtensibleScope_; 1.1018 + } 1.1019 + bool funNeedsDeclEnvObject() const { 1.1020 + return funNeedsDeclEnvObject_; 1.1021 + } 1.1022 + bool funHasAnyAliasedFormal() const { 1.1023 + return funHasAnyAliasedFormal_; 1.1024 + } 1.1025 + 1.1026 + bool hasSingletons() const { return hasSingletons_; } 1.1027 + bool treatAsRunOnce() const { 1.1028 + return treatAsRunOnce_; 1.1029 + } 1.1030 + bool hasRunOnce() const { return hasRunOnce_; } 1.1031 + bool hasBeenCloned() const { return hasBeenCloned_; } 1.1032 + bool hasBeenInlined() const { return hasBeenInlined_; } 1.1033 + 1.1034 + void setTreatAsRunOnce() { treatAsRunOnce_ = true; } 1.1035 + void setHasRunOnce() { hasRunOnce_ = true; } 1.1036 + void setHasBeenCloned() { hasBeenCloned_ = true; } 1.1037 + void setHasBeenInlined() { hasBeenInlined_ = true; } 1.1038 + 1.1039 + bool isActiveEval() const { return isActiveEval_; } 1.1040 + bool isCachedEval() const { return isCachedEval_; } 1.1041 + bool directlyInsideEval() const { return directlyInsideEval_; } 1.1042 + 1.1043 + void cacheForEval() { 1.1044 + JS_ASSERT(isActiveEval() && !isCachedEval()); 1.1045 + isActiveEval_ = false; 1.1046 + isCachedEval_ = true; 1.1047 + } 1.1048 + 1.1049 + void uncacheForEval() { 1.1050 + JS_ASSERT(isCachedEval() && !isActiveEval()); 1.1051 + isCachedEval_ = false; 1.1052 + isActiveEval_ = true; 1.1053 + } 1.1054 + 1.1055 + void setActiveEval() { isActiveEval_ = true; } 1.1056 + void setDirectlyInsideEval() { directlyInsideEval_ = true; } 1.1057 + 1.1058 + bool usesArgumentsAndApply() const { 1.1059 + return usesArgumentsAndApply_; 1.1060 + } 1.1061 + void setUsesArgumentsAndApply() { usesArgumentsAndApply_ = true; } 1.1062 + 1.1063 + bool shouldCloneAtCallsite() const { 1.1064 + return shouldCloneAtCallsite_; 1.1065 + } 1.1066 + bool shouldInline() const { 1.1067 + return shouldInline_; 1.1068 + } 1.1069 + 1.1070 + void setShouldCloneAtCallsite() { shouldCloneAtCallsite_ = true; } 1.1071 + void setShouldInline() { shouldInline_ = true; } 1.1072 + 1.1073 + bool isCallsiteClone() const { 1.1074 + return isCallsiteClone_; 1.1075 + } 1.1076 + bool isGeneratorExp() const { return isGeneratorExp_; } 1.1077 + 1.1078 + bool failedBoundsCheck() const { 1.1079 + return failedBoundsCheck_; 1.1080 + } 1.1081 + bool failedShapeGuard() const { 1.1082 + return failedShapeGuard_; 1.1083 + } 1.1084 + bool hadFrequentBailouts() const { 1.1085 + return hadFrequentBailouts_; 1.1086 + } 1.1087 + bool uninlineable() const { 1.1088 + return uninlineable_; 1.1089 + } 1.1090 + bool invalidatedIdempotentCache() const { 1.1091 + return invalidatedIdempotentCache_; 1.1092 + } 1.1093 + 1.1094 + void setFailedBoundsCheck() { failedBoundsCheck_ = true; } 1.1095 + void setFailedShapeGuard() { failedShapeGuard_ = true; } 1.1096 + void setHadFrequentBailouts() { hadFrequentBailouts_ = true; } 1.1097 + void setUninlineable() { uninlineable_ = true; } 1.1098 + void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; } 1.1099 + 1.1100 + bool hasScriptCounts() const { return hasScriptCounts_; } 1.1101 + 1.1102 + bool hasFreezeConstraints() const { return hasFreezeConstraints_; } 1.1103 + void setHasFreezeConstraints() { hasFreezeConstraints_ = true; } 1.1104 + void clearHasFreezeConstraints() { hasFreezeConstraints_ = false; } 1.1105 + 1.1106 + bool warnedAboutUndefinedProp() const { return warnedAboutUndefinedProp_; } 1.1107 + void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; } 1.1108 + 1.1109 + /* See ContextFlags::funArgumentsHasLocalBinding comment. */ 1.1110 + bool argumentsHasVarBinding() const { 1.1111 + return argsHasVarBinding_; 1.1112 + } 1.1113 + jsbytecode *argumentsBytecode() const { JS_ASSERT(code()[0] == JSOP_ARGUMENTS); return code(); } 1.1114 + void setArgumentsHasVarBinding(); 1.1115 + bool argumentsAliasesFormals() const { 1.1116 + return argumentsHasVarBinding() && !strict(); 1.1117 + } 1.1118 + 1.1119 + js::GeneratorKind generatorKind() const { 1.1120 + return js::GeneratorKindFromBits(generatorKindBits_); 1.1121 + } 1.1122 + bool isGenerator() const { return generatorKind() != js::NotGenerator; } 1.1123 + bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; } 1.1124 + bool isStarGenerator() const { return generatorKind() == js::StarGenerator; } 1.1125 + void setGeneratorKind(js::GeneratorKind kind) { 1.1126 + // A script only gets its generator kind set as part of initialization, 1.1127 + // so it can only transition from not being a generator. 1.1128 + JS_ASSERT(!isGenerator()); 1.1129 + generatorKindBits_ = GeneratorKindAsBits(kind); 1.1130 + } 1.1131 + 1.1132 + /* 1.1133 + * As an optimization, even when argsHasLocalBinding, the function prologue 1.1134 + * may not need to create an arguments object. This is determined by 1.1135 + * needsArgsObj which is set by AnalyzeArgumentsUsage before running 1.1136 + * the script the first time. When !needsArgsObj, the prologue may simply 1.1137 + * write MagicValue(JS_OPTIMIZED_ARGUMENTS) to 'arguments's slot and any 1.1138 + * uses of 'arguments' will be guaranteed to handle this magic value. 1.1139 + * So avoid spurious arguments object creation, we maintain the invariant 1.1140 + * that needsArgsObj is only called after the script has been analyzed. 1.1141 + */ 1.1142 + bool analyzedArgsUsage() const { return !needsArgsAnalysis_; } 1.1143 + inline bool ensureHasAnalyzedArgsUsage(JSContext *cx); 1.1144 + bool needsArgsObj() const { 1.1145 + JS_ASSERT(analyzedArgsUsage()); 1.1146 + return needsArgsObj_; 1.1147 + } 1.1148 + void setNeedsArgsObj(bool needsArgsObj); 1.1149 + static bool argumentsOptimizationFailed(JSContext *cx, js::HandleScript script); 1.1150 + 1.1151 + /* 1.1152 + * Arguments access (via JSOP_*ARG* opcodes) must access the canonical 1.1153 + * location for the argument. If an arguments object exists AND this is a 1.1154 + * non-strict function (where 'arguments' aliases formals), then all access 1.1155 + * must go through the arguments object. Otherwise, the local slot is the 1.1156 + * canonical location for the arguments. Note: if a formal is aliased 1.1157 + * through the scope chain, then script->formalIsAliased and JSOP_*ARG* 1.1158 + * opcodes won't be emitted at all. 1.1159 + */ 1.1160 + bool argsObjAliasesFormals() const { 1.1161 + return needsArgsObj() && !strict(); 1.1162 + } 1.1163 + 1.1164 + bool hasAnyIonScript() const { 1.1165 + return hasIonScript() || hasParallelIonScript(); 1.1166 + } 1.1167 + 1.1168 + bool hasIonScript() const { 1.1169 + bool res = ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT; 1.1170 + MOZ_ASSERT_IF(res, baseline); 1.1171 + return res; 1.1172 + } 1.1173 + bool canIonCompile() const { 1.1174 + return ion != ION_DISABLED_SCRIPT; 1.1175 + } 1.1176 + 1.1177 + bool isIonCompilingOffThread() const { 1.1178 + return ion == ION_COMPILING_SCRIPT; 1.1179 + } 1.1180 + 1.1181 + js::jit::IonScript *ionScript() const { 1.1182 + JS_ASSERT(hasIonScript()); 1.1183 + return ion; 1.1184 + } 1.1185 + js::jit::IonScript *maybeIonScript() const { 1.1186 + return ion; 1.1187 + } 1.1188 + js::jit::IonScript *const *addressOfIonScript() const { 1.1189 + return &ion; 1.1190 + } 1.1191 + void setIonScript(js::jit::IonScript *ionScript) { 1.1192 + if (hasIonScript()) 1.1193 + js::jit::IonScript::writeBarrierPre(tenuredZone(), ion); 1.1194 + ion = ionScript; 1.1195 + MOZ_ASSERT_IF(hasIonScript(), hasBaselineScript()); 1.1196 + updateBaselineOrIonRaw(); 1.1197 + } 1.1198 + 1.1199 + bool hasBaselineScript() const { 1.1200 + bool res = baseline && baseline != BASELINE_DISABLED_SCRIPT; 1.1201 + MOZ_ASSERT_IF(!res, !ion || ion == ION_DISABLED_SCRIPT); 1.1202 + return res; 1.1203 + } 1.1204 + bool canBaselineCompile() const { 1.1205 + return baseline != BASELINE_DISABLED_SCRIPT; 1.1206 + } 1.1207 + js::jit::BaselineScript *baselineScript() const { 1.1208 + JS_ASSERT(hasBaselineScript()); 1.1209 + return baseline; 1.1210 + } 1.1211 + inline void setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript); 1.1212 + 1.1213 + void updateBaselineOrIonRaw(); 1.1214 + 1.1215 + bool hasParallelIonScript() const { 1.1216 + return parallelIon && parallelIon != ION_DISABLED_SCRIPT && parallelIon != ION_COMPILING_SCRIPT; 1.1217 + } 1.1218 + 1.1219 + bool canParallelIonCompile() const { 1.1220 + return parallelIon != ION_DISABLED_SCRIPT; 1.1221 + } 1.1222 + 1.1223 + bool isParallelIonCompilingOffThread() const { 1.1224 + return parallelIon == ION_COMPILING_SCRIPT; 1.1225 + } 1.1226 + 1.1227 + js::jit::IonScript *parallelIonScript() const { 1.1228 + JS_ASSERT(hasParallelIonScript()); 1.1229 + return parallelIon; 1.1230 + } 1.1231 + js::jit::IonScript *maybeParallelIonScript() const { 1.1232 + return parallelIon; 1.1233 + } 1.1234 + void setParallelIonScript(js::jit::IonScript *ionScript) { 1.1235 + if (hasParallelIonScript()) 1.1236 + js::jit::IonScript::writeBarrierPre(tenuredZone(), parallelIon); 1.1237 + parallelIon = ionScript; 1.1238 + } 1.1239 + 1.1240 + static size_t offsetOfBaselineScript() { 1.1241 + return offsetof(JSScript, baseline); 1.1242 + } 1.1243 + static size_t offsetOfIonScript() { 1.1244 + return offsetof(JSScript, ion); 1.1245 + } 1.1246 + static size_t offsetOfParallelIonScript() { 1.1247 + return offsetof(JSScript, parallelIon); 1.1248 + } 1.1249 + static size_t offsetOfBaselineOrIonRaw() { 1.1250 + return offsetof(JSScript, baselineOrIonRaw); 1.1251 + } 1.1252 + static size_t offsetOfBaselineOrIonSkipArgCheck() { 1.1253 + return offsetof(JSScript, baselineOrIonSkipArgCheck); 1.1254 + } 1.1255 + 1.1256 + bool isRelazifiable() const { 1.1257 + return (selfHosted() || lazyScript) && 1.1258 + !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() && !hasBeenInlined(); 1.1259 + } 1.1260 + void setLazyScript(js::LazyScript *lazy) { 1.1261 + lazyScript = lazy; 1.1262 + } 1.1263 + js::LazyScript *maybeLazyScript() { 1.1264 + return lazyScript; 1.1265 + } 1.1266 + 1.1267 + /* 1.1268 + * Original compiled function for the script, if it has a function. 1.1269 + * nullptr for global and eval scripts. 1.1270 + * The delazifying variant ensures that the function isn't lazy. The 1.1271 + * non-delazifying variant must only be used after earlier code has 1.1272 + * called ensureNonLazyCanonicalFunction and while the function can't 1.1273 + * have been relazified. 1.1274 + */ 1.1275 + inline JSFunction *functionDelazifying() const; 1.1276 + JSFunction *functionNonDelazifying() const { 1.1277 + return function_; 1.1278 + } 1.1279 + inline void setFunction(JSFunction *fun); 1.1280 + /* 1.1281 + * De-lazifies the canonical function. Must be called before entering code 1.1282 + * that expects the function to be non-lazy. 1.1283 + */ 1.1284 + inline void ensureNonLazyCanonicalFunction(JSContext *cx); 1.1285 + 1.1286 + /* 1.1287 + * Donor provided itself to callsite clone; null if this is non-clone. 1.1288 + */ 1.1289 + JSFunction *donorFunction() const; 1.1290 + void setIsCallsiteClone(JSObject *fun); 1.1291 + 1.1292 + JSFlatString *sourceData(JSContext *cx); 1.1293 + 1.1294 + static bool loadSource(JSContext *cx, js::ScriptSource *ss, bool *worked); 1.1295 + 1.1296 + void setSourceObject(JSObject *object); 1.1297 + JSObject *sourceObject() const { 1.1298 + return sourceObject_; 1.1299 + } 1.1300 + js::ScriptSourceObject &scriptSourceUnwrap() const; 1.1301 + js::ScriptSource *scriptSource() const; 1.1302 + JSPrincipals *originPrincipals() const { return scriptSource()->originPrincipals(); } 1.1303 + const char *filename() const { return scriptSource()->filename(); } 1.1304 + 1.1305 + public: 1.1306 + 1.1307 + /* Return whether this script was compiled for 'eval' */ 1.1308 + bool isForEval() { return isCachedEval() || isActiveEval(); } 1.1309 + 1.1310 +#ifdef DEBUG 1.1311 + unsigned id(); 1.1312 +#else 1.1313 + unsigned id() { return 0; } 1.1314 +#endif 1.1315 + 1.1316 + /* Ensure the script has a TypeScript. */ 1.1317 + inline bool ensureHasTypes(JSContext *cx); 1.1318 + 1.1319 + inline js::GlobalObject &global() const; 1.1320 + js::GlobalObject &uninlinedGlobal() const; 1.1321 + 1.1322 + /* See StaticScopeIter comment. */ 1.1323 + JSObject *enclosingStaticScope() const { 1.1324 + if (isCallsiteClone()) 1.1325 + return nullptr; 1.1326 + return enclosingScopeOrOriginalFunction_; 1.1327 + } 1.1328 + 1.1329 + private: 1.1330 + bool makeTypes(JSContext *cx); 1.1331 + 1.1332 + public: 1.1333 + uint32_t getUseCount() const { 1.1334 + return useCount; 1.1335 + } 1.1336 + uint32_t incUseCount(uint32_t amount = 1) { return useCount += amount; } 1.1337 + uint32_t *addressOfUseCount() { return &useCount; } 1.1338 + static size_t offsetOfUseCount() { return offsetof(JSScript, useCount); } 1.1339 + void resetUseCount() { useCount = 0; } 1.1340 + 1.1341 + public: 1.1342 + bool initScriptCounts(JSContext *cx); 1.1343 + js::PCCounts getPCCounts(jsbytecode *pc); 1.1344 + void addIonCounts(js::jit::IonScriptCounts *ionCounts); 1.1345 + js::jit::IonScriptCounts *getIonCounts(); 1.1346 + js::ScriptCounts releaseScriptCounts(); 1.1347 + void destroyScriptCounts(js::FreeOp *fop); 1.1348 + 1.1349 + jsbytecode *main() { 1.1350 + return code() + mainOffset(); 1.1351 + } 1.1352 + 1.1353 + /* 1.1354 + * computedSizeOfData() is the in-use size of all the data sections. 1.1355 + * sizeOfData() is the size of the block allocated to hold all the data 1.1356 + * sections (which can be larger than the in-use size). 1.1357 + */ 1.1358 + size_t computedSizeOfData() const; 1.1359 + size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const; 1.1360 + size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const; 1.1361 + 1.1362 + uint32_t numNotes(); /* Number of srcnote slots in the srcnotes section */ 1.1363 + 1.1364 + /* Script notes are allocated right after the code. */ 1.1365 + jssrcnote *notes() { return (jssrcnote *)(code() + length()); } 1.1366 + 1.1367 + bool hasArray(ArrayKind kind) { 1.1368 + return hasArrayBits & (1 << kind); 1.1369 + } 1.1370 + void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); } 1.1371 + void cloneHasArray(JSScript *script) { hasArrayBits = script->hasArrayBits; } 1.1372 + 1.1373 + bool hasConsts() { return hasArray(CONSTS); } 1.1374 + bool hasObjects() { return hasArray(OBJECTS); } 1.1375 + bool hasRegexps() { return hasArray(REGEXPS); } 1.1376 + bool hasTrynotes() { return hasArray(TRYNOTES); } 1.1377 + bool hasBlockScopes() { return hasArray(BLOCK_SCOPES); } 1.1378 + 1.1379 + #define OFF(fooOff, hasFoo, t) (fooOff() + (hasFoo() ? sizeof(t) : 0)) 1.1380 + 1.1381 + size_t constsOffset() { return 0; } 1.1382 + size_t objectsOffset() { return OFF(constsOffset, hasConsts, js::ConstArray); } 1.1383 + size_t regexpsOffset() { return OFF(objectsOffset, hasObjects, js::ObjectArray); } 1.1384 + size_t trynotesOffset() { return OFF(regexpsOffset, hasRegexps, js::ObjectArray); } 1.1385 + size_t blockScopesOffset(){ return OFF(trynotesOffset, hasTrynotes, js::TryNoteArray); } 1.1386 + 1.1387 + size_t dataSize() const { return dataSize_; } 1.1388 + 1.1389 + js::ConstArray *consts() { 1.1390 + JS_ASSERT(hasConsts()); 1.1391 + return reinterpret_cast<js::ConstArray *>(data + constsOffset()); 1.1392 + } 1.1393 + 1.1394 + js::ObjectArray *objects() { 1.1395 + JS_ASSERT(hasObjects()); 1.1396 + return reinterpret_cast<js::ObjectArray *>(data + objectsOffset()); 1.1397 + } 1.1398 + 1.1399 + js::ObjectArray *regexps() { 1.1400 + JS_ASSERT(hasRegexps()); 1.1401 + return reinterpret_cast<js::ObjectArray *>(data + regexpsOffset()); 1.1402 + } 1.1403 + 1.1404 + js::TryNoteArray *trynotes() { 1.1405 + JS_ASSERT(hasTrynotes()); 1.1406 + return reinterpret_cast<js::TryNoteArray *>(data + trynotesOffset()); 1.1407 + } 1.1408 + 1.1409 + js::BlockScopeArray *blockScopes() { 1.1410 + JS_ASSERT(hasBlockScopes()); 1.1411 + return reinterpret_cast<js::BlockScopeArray *>(data + blockScopesOffset()); 1.1412 + } 1.1413 + 1.1414 + bool hasLoops(); 1.1415 + 1.1416 + size_t natoms() const { return natoms_; } 1.1417 + 1.1418 + js::HeapPtrAtom &getAtom(size_t index) const { 1.1419 + JS_ASSERT(index < natoms()); 1.1420 + return atoms[index]; 1.1421 + } 1.1422 + 1.1423 + js::HeapPtrAtom &getAtom(jsbytecode *pc) const { 1.1424 + JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t))); 1.1425 + return getAtom(GET_UINT32_INDEX(pc)); 1.1426 + } 1.1427 + 1.1428 + js::PropertyName *getName(size_t index) { 1.1429 + return getAtom(index)->asPropertyName(); 1.1430 + } 1.1431 + 1.1432 + js::PropertyName *getName(jsbytecode *pc) const { 1.1433 + JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t))); 1.1434 + return getAtom(GET_UINT32_INDEX(pc))->asPropertyName(); 1.1435 + } 1.1436 + 1.1437 + JSObject *getObject(size_t index) { 1.1438 + js::ObjectArray *arr = objects(); 1.1439 + JS_ASSERT(index < arr->length); 1.1440 + return arr->vector[index]; 1.1441 + } 1.1442 + 1.1443 + size_t innerObjectsStart() { 1.1444 + // The first object contains the caller if savedCallerFun is used. 1.1445 + return savedCallerFun() ? 1 : 0; 1.1446 + } 1.1447 + 1.1448 + JSObject *getObject(jsbytecode *pc) { 1.1449 + JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t))); 1.1450 + return getObject(GET_UINT32_INDEX(pc)); 1.1451 + } 1.1452 + 1.1453 + JSVersion getVersion() const { 1.1454 + return JSVersion(version); 1.1455 + } 1.1456 + 1.1457 + inline JSFunction *getFunction(size_t index); 1.1458 + inline JSFunction *getCallerFunction(); 1.1459 + inline JSFunction *functionOrCallerFunction(); 1.1460 + 1.1461 + inline js::RegExpObject *getRegExp(size_t index); 1.1462 + inline js::RegExpObject *getRegExp(jsbytecode *pc); 1.1463 + 1.1464 + const js::Value &getConst(size_t index) { 1.1465 + js::ConstArray *arr = consts(); 1.1466 + JS_ASSERT(index < arr->length); 1.1467 + return arr->vector[index]; 1.1468 + } 1.1469 + 1.1470 + js::NestedScopeObject *getStaticScope(jsbytecode *pc); 1.1471 + 1.1472 + /* 1.1473 + * The isEmpty method tells whether this script has code that computes any 1.1474 + * result (not return value, result AKA normal completion value) other than 1.1475 + * JSVAL_VOID, or any other effects. 1.1476 + */ 1.1477 + bool isEmpty() const { 1.1478 + if (length() > 3) 1.1479 + return false; 1.1480 + 1.1481 + jsbytecode *pc = code(); 1.1482 + if (noScriptRval() && JSOp(*pc) == JSOP_FALSE) 1.1483 + ++pc; 1.1484 + return JSOp(*pc) == JSOP_RETRVAL; 1.1485 + } 1.1486 + 1.1487 + bool varIsAliased(uint32_t varSlot); 1.1488 + bool formalIsAliased(unsigned argSlot); 1.1489 + bool formalLivesInArgumentsObject(unsigned argSlot); 1.1490 + 1.1491 + private: 1.1492 + /* Change this->stepMode to |newValue|. */ 1.1493 + void setNewStepMode(js::FreeOp *fop, uint32_t newValue); 1.1494 + 1.1495 + bool ensureHasDebugScript(JSContext *cx); 1.1496 + js::DebugScript *debugScript(); 1.1497 + js::DebugScript *releaseDebugScript(); 1.1498 + void destroyDebugScript(js::FreeOp *fop); 1.1499 + 1.1500 + public: 1.1501 + bool hasBreakpointsAt(jsbytecode *pc); 1.1502 + bool hasAnyBreakpointsOrStepMode() { return hasDebugScript_; } 1.1503 + 1.1504 + js::BreakpointSite *getBreakpointSite(jsbytecode *pc) 1.1505 + { 1.1506 + return hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr; 1.1507 + } 1.1508 + 1.1509 + js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc); 1.1510 + 1.1511 + void destroyBreakpointSite(js::FreeOp *fop, jsbytecode *pc); 1.1512 + 1.1513 + void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JSObject *handler); 1.1514 + void clearTraps(js::FreeOp *fop); 1.1515 + 1.1516 + void markTrapClosures(JSTracer *trc); 1.1517 + 1.1518 + /* 1.1519 + * Set or clear the single-step flag. If the flag is set or the count 1.1520 + * (adjusted by changeStepModeCount) is non-zero, then the script is in 1.1521 + * single-step mode. (JSD uses an on/off-style interface; Debugger uses a 1.1522 + * count-style interface.) 1.1523 + */ 1.1524 + bool setStepModeFlag(JSContext *cx, bool step); 1.1525 + 1.1526 + /* 1.1527 + * Increment or decrement the single-step count. If the count is non-zero or 1.1528 + * the flag (set by setStepModeFlag) is set, then the script is in 1.1529 + * single-step mode. (JSD uses an on/off-style interface; Debugger uses a 1.1530 + * count-style interface.) 1.1531 + * 1.1532 + * Only incrementing is fallible, as it could allocate a DebugScript. 1.1533 + */ 1.1534 + bool incrementStepModeCount(JSContext *cx); 1.1535 + void decrementStepModeCount(js::FreeOp *fop); 1.1536 + 1.1537 + bool stepModeEnabled() { return hasDebugScript_ && !!debugScript()->stepMode; } 1.1538 + 1.1539 +#ifdef DEBUG 1.1540 + uint32_t stepModeCount() { return hasDebugScript_ ? (debugScript()->stepMode & stepCountMask) : 0; } 1.1541 +#endif 1.1542 + 1.1543 + void finalize(js::FreeOp *fop); 1.1544 + 1.1545 + static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SCRIPT; } 1.1546 + 1.1547 + void markChildren(JSTracer *trc); 1.1548 +}; 1.1549 + 1.1550 +/* If this fails, add/remove padding within JSScript. */ 1.1551 +static_assert(sizeof(JSScript) % js::gc::CellSize == 0, 1.1552 + "Size of JSScript must be an integral multiple of js::gc::CellSize"); 1.1553 + 1.1554 +namespace js { 1.1555 + 1.1556 +/* 1.1557 + * Iterator over a script's bindings (formals and variables). 1.1558 + * The order of iteration is: 1.1559 + * - first, formal arguments, from index 0 to numArgs 1.1560 + * - next, variables, from index 0 to numLocals 1.1561 + */ 1.1562 +class BindingIter 1.1563 +{ 1.1564 + const InternalBindingsHandle bindings_; 1.1565 + uint32_t i_; 1.1566 + 1.1567 + friend class Bindings; 1.1568 + 1.1569 + public: 1.1570 + explicit BindingIter(const InternalBindingsHandle &bindings) : bindings_(bindings), i_(0) {} 1.1571 + explicit BindingIter(const HandleScript &script) : bindings_(script, &script->bindings), i_(0) {} 1.1572 + 1.1573 + bool done() const { return i_ == bindings_->count(); } 1.1574 + operator bool() const { return !done(); } 1.1575 + void operator++(int) { JS_ASSERT(!done()); i_++; } 1.1576 + BindingIter &operator++() { (*this)++; return *this; } 1.1577 + 1.1578 + uint32_t frameIndex() const { 1.1579 + JS_ASSERT(!done()); 1.1580 + return i_ < bindings_->numArgs() ? i_ : i_ - bindings_->numArgs(); 1.1581 + } 1.1582 + 1.1583 + const Binding &operator*() const { JS_ASSERT(!done()); return bindings_->bindingArray()[i_]; } 1.1584 + const Binding *operator->() const { JS_ASSERT(!done()); return &bindings_->bindingArray()[i_]; } 1.1585 +}; 1.1586 + 1.1587 +/* 1.1588 + * This helper function fills the given BindingVector with the sequential 1.1589 + * values of BindingIter. 1.1590 + */ 1.1591 + 1.1592 +typedef Vector<Binding, 32> BindingVector; 1.1593 + 1.1594 +extern bool 1.1595 +FillBindingVector(HandleScript fromScript, BindingVector *vec); 1.1596 + 1.1597 +/* 1.1598 + * Iterator over the aliased formal bindings in ascending index order. This can 1.1599 + * be veiwed as a filtering of BindingIter with predicate 1.1600 + * bi->aliased() && bi->kind() == Binding::ARGUMENT 1.1601 + */ 1.1602 +class AliasedFormalIter 1.1603 +{ 1.1604 + const Binding *begin_, *p_, *end_; 1.1605 + unsigned slot_; 1.1606 + 1.1607 + void settle() { 1.1608 + while (p_ != end_ && !p_->aliased()) 1.1609 + p_++; 1.1610 + } 1.1611 + 1.1612 + public: 1.1613 + explicit inline AliasedFormalIter(JSScript *script); 1.1614 + 1.1615 + bool done() const { return p_ == end_; } 1.1616 + operator bool() const { return !done(); } 1.1617 + void operator++(int) { JS_ASSERT(!done()); p_++; slot_++; settle(); } 1.1618 + 1.1619 + const Binding &operator*() const { JS_ASSERT(!done()); return *p_; } 1.1620 + const Binding *operator->() const { JS_ASSERT(!done()); return p_; } 1.1621 + unsigned frameIndex() const { JS_ASSERT(!done()); return p_ - begin_; } 1.1622 + unsigned scopeSlot() const { JS_ASSERT(!done()); return slot_; } 1.1623 +}; 1.1624 + 1.1625 +// Information about a script which may be (or has been) lazily compiled to 1.1626 +// bytecode from its source. 1.1627 +class LazyScript : public gc::BarrieredCell<LazyScript> 1.1628 +{ 1.1629 + // If non-nullptr, the script has been compiled and this is a forwarding 1.1630 + // pointer to the result. 1.1631 + HeapPtrScript script_; 1.1632 + 1.1633 + // Original function with which the lazy script is associated. 1.1634 + HeapPtrFunction function_; 1.1635 + 1.1636 + // Function or block chain in which the script is nested, or nullptr. 1.1637 + HeapPtrObject enclosingScope_; 1.1638 + 1.1639 + // ScriptSourceObject, or nullptr if the script in which this is nested 1.1640 + // has not been compiled yet. This is never a CCW; we don't clone 1.1641 + // LazyScripts into other compartments. 1.1642 + HeapPtrObject sourceObject_; 1.1643 + 1.1644 + // Heap allocated table with any free variables or inner functions. 1.1645 + void *table_; 1.1646 + 1.1647 +#if JS_BITS_PER_WORD == 32 1.1648 + uint32_t padding; 1.1649 +#endif 1.1650 + 1.1651 + struct PackedView { 1.1652 + // Assorted bits that should really be in ScriptSourceObject. 1.1653 + uint32_t version : 8; 1.1654 + 1.1655 + uint32_t numFreeVariables : 24; 1.1656 + uint32_t numInnerFunctions : 23; 1.1657 + 1.1658 + uint32_t generatorKindBits : 2; 1.1659 + 1.1660 + // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC. 1.1661 + uint32_t strict : 1; 1.1662 + uint32_t bindingsAccessedDynamically : 1; 1.1663 + uint32_t hasDebuggerStatement : 1; 1.1664 + uint32_t directlyInsideEval : 1; 1.1665 + uint32_t usesArgumentsAndApply : 1; 1.1666 + uint32_t hasBeenCloned : 1; 1.1667 + uint32_t treatAsRunOnce : 1; 1.1668 + }; 1.1669 + 1.1670 + union { 1.1671 + PackedView p_; 1.1672 + uint64_t packedFields_; 1.1673 + }; 1.1674 + 1.1675 + // Source location for the script. 1.1676 + uint32_t begin_; 1.1677 + uint32_t end_; 1.1678 + uint32_t lineno_; 1.1679 + uint32_t column_; 1.1680 + 1.1681 + LazyScript(JSFunction *fun, void *table, uint64_t packedFields, 1.1682 + uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); 1.1683 + 1.1684 + // Create a LazyScript without initializing the freeVariables and the 1.1685 + // innerFunctions. To be GC-safe, the caller must initialize both vectors 1.1686 + // with valid atoms and functions. 1.1687 + static LazyScript *CreateRaw(ExclusiveContext *cx, HandleFunction fun, 1.1688 + uint64_t packedData, uint32_t begin, uint32_t end, 1.1689 + uint32_t lineno, uint32_t column); 1.1690 + 1.1691 + public: 1.1692 + // Create a LazyScript without initializing the freeVariables and the 1.1693 + // innerFunctions. To be GC-safe, the caller must initialize both vectors 1.1694 + // with valid atoms and functions. 1.1695 + static LazyScript *CreateRaw(ExclusiveContext *cx, HandleFunction fun, 1.1696 + uint32_t numFreeVariables, uint32_t numInnerFunctions, 1.1697 + JSVersion version, uint32_t begin, uint32_t end, 1.1698 + uint32_t lineno, uint32_t column); 1.1699 + 1.1700 + // Create a LazyScript and initialize the freeVariables and the 1.1701 + // innerFunctions with dummy values to be replaced in a later initialization 1.1702 + // phase. 1.1703 + static LazyScript *Create(ExclusiveContext *cx, HandleFunction fun, 1.1704 + uint64_t packedData, uint32_t begin, uint32_t end, 1.1705 + uint32_t lineno, uint32_t column); 1.1706 + 1.1707 + void initRuntimeFields(uint64_t packedFields); 1.1708 + 1.1709 + inline JSFunction *functionDelazifying(JSContext *cx) const; 1.1710 + JSFunction *functionNonDelazifying() const { 1.1711 + return function_; 1.1712 + } 1.1713 + 1.1714 + void initScript(JSScript *script); 1.1715 + void resetScript(); 1.1716 + JSScript *maybeScript() { 1.1717 + return script_; 1.1718 + } 1.1719 + 1.1720 + JSObject *enclosingScope() const { 1.1721 + return enclosingScope_; 1.1722 + } 1.1723 + ScriptSourceObject *sourceObject() const; 1.1724 + ScriptSource *scriptSource() const { 1.1725 + return sourceObject()->source(); 1.1726 + } 1.1727 + JSPrincipals *originPrincipals() const { 1.1728 + return scriptSource()->originPrincipals(); 1.1729 + } 1.1730 + JSVersion version() const { 1.1731 + JS_STATIC_ASSERT(JSVERSION_UNKNOWN == -1); 1.1732 + return (p_.version == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(p_.version); 1.1733 + } 1.1734 + 1.1735 + void setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject); 1.1736 + 1.1737 + uint32_t numFreeVariables() const { 1.1738 + return p_.numFreeVariables; 1.1739 + } 1.1740 + HeapPtrAtom *freeVariables() { 1.1741 + return (HeapPtrAtom *)table_; 1.1742 + } 1.1743 + 1.1744 + uint32_t numInnerFunctions() const { 1.1745 + return p_.numInnerFunctions; 1.1746 + } 1.1747 + HeapPtrFunction *innerFunctions() { 1.1748 + return (HeapPtrFunction *)&freeVariables()[numFreeVariables()]; 1.1749 + } 1.1750 + 1.1751 + GeneratorKind generatorKind() const { return GeneratorKindFromBits(p_.generatorKindBits); } 1.1752 + 1.1753 + bool isGenerator() const { return generatorKind() != NotGenerator; } 1.1754 + 1.1755 + bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; } 1.1756 + 1.1757 + bool isStarGenerator() const { return generatorKind() == StarGenerator; } 1.1758 + 1.1759 + void setGeneratorKind(GeneratorKind kind) { 1.1760 + // A script only gets its generator kind set as part of initialization, 1.1761 + // so it can only transition from NotGenerator. 1.1762 + JS_ASSERT(!isGenerator()); 1.1763 + // Legacy generators cannot currently be lazy. 1.1764 + JS_ASSERT(kind != LegacyGenerator); 1.1765 + p_.generatorKindBits = GeneratorKindAsBits(kind); 1.1766 + } 1.1767 + 1.1768 + bool strict() const { 1.1769 + return p_.strict; 1.1770 + } 1.1771 + void setStrict() { 1.1772 + p_.strict = true; 1.1773 + } 1.1774 + 1.1775 + bool bindingsAccessedDynamically() const { 1.1776 + return p_.bindingsAccessedDynamically; 1.1777 + } 1.1778 + void setBindingsAccessedDynamically() { 1.1779 + p_.bindingsAccessedDynamically = true; 1.1780 + } 1.1781 + 1.1782 + bool hasDebuggerStatement() const { 1.1783 + return p_.hasDebuggerStatement; 1.1784 + } 1.1785 + void setHasDebuggerStatement() { 1.1786 + p_.hasDebuggerStatement = true; 1.1787 + } 1.1788 + 1.1789 + bool directlyInsideEval() const { 1.1790 + return p_.directlyInsideEval; 1.1791 + } 1.1792 + void setDirectlyInsideEval() { 1.1793 + p_.directlyInsideEval = true; 1.1794 + } 1.1795 + 1.1796 + bool usesArgumentsAndApply() const { 1.1797 + return p_.usesArgumentsAndApply; 1.1798 + } 1.1799 + void setUsesArgumentsAndApply() { 1.1800 + p_.usesArgumentsAndApply = true; 1.1801 + } 1.1802 + 1.1803 + bool hasBeenCloned() const { 1.1804 + return p_.hasBeenCloned; 1.1805 + } 1.1806 + void setHasBeenCloned() { 1.1807 + p_.hasBeenCloned = true; 1.1808 + } 1.1809 + 1.1810 + bool treatAsRunOnce() const { 1.1811 + return p_.treatAsRunOnce; 1.1812 + } 1.1813 + void setTreatAsRunOnce() { 1.1814 + p_.treatAsRunOnce = true; 1.1815 + } 1.1816 + 1.1817 + ScriptSource *source() const { 1.1818 + return sourceObject()->source(); 1.1819 + } 1.1820 + uint32_t begin() const { 1.1821 + return begin_; 1.1822 + } 1.1823 + uint32_t end() const { 1.1824 + return end_; 1.1825 + } 1.1826 + uint32_t lineno() const { 1.1827 + return lineno_; 1.1828 + } 1.1829 + uint32_t column() const { 1.1830 + return column_; 1.1831 + } 1.1832 + 1.1833 + bool hasUncompiledEnclosingScript() const; 1.1834 + uint32_t staticLevel(JSContext *cx) const; 1.1835 + 1.1836 + void markChildren(JSTracer *trc); 1.1837 + void finalize(js::FreeOp *fop); 1.1838 + 1.1839 + static inline js::ThingRootKind rootKind() { return js::THING_ROOT_LAZY_SCRIPT; } 1.1840 + 1.1841 + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) 1.1842 + { 1.1843 + return mallocSizeOf(table_); 1.1844 + } 1.1845 + 1.1846 + uint64_t packedFields() const { 1.1847 + return packedFields_; 1.1848 + } 1.1849 +}; 1.1850 + 1.1851 +/* If this fails, add/remove padding within LazyScript. */ 1.1852 +JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0); 1.1853 + 1.1854 +/* 1.1855 + * New-script-hook calling is factored from JSScript::fullyInitFromEmitter() so 1.1856 + * that it and callers of XDRScript() can share this code. In the case of 1.1857 + * callers of XDRScript(), the hook should be invoked only after successful 1.1858 + * decode of any owning function (the fun parameter) or script object (null 1.1859 + * fun). 1.1860 + */ 1.1861 +extern void 1.1862 +CallNewScriptHook(JSContext *cx, JS::HandleScript script, JS::HandleFunction fun); 1.1863 + 1.1864 +extern void 1.1865 +CallDestroyScriptHook(FreeOp *fop, JSScript *script); 1.1866 + 1.1867 +struct SharedScriptData 1.1868 +{ 1.1869 + uint32_t length; 1.1870 + uint32_t natoms; 1.1871 + bool marked; 1.1872 + jsbytecode data[1]; 1.1873 + 1.1874 + static SharedScriptData *new_(ExclusiveContext *cx, uint32_t codeLength, 1.1875 + uint32_t srcnotesLength, uint32_t natoms); 1.1876 + 1.1877 + HeapPtrAtom *atoms() { 1.1878 + if (!natoms) 1.1879 + return nullptr; 1.1880 + return reinterpret_cast<HeapPtrAtom *>(data + length - sizeof(JSAtom *) * natoms); 1.1881 + } 1.1882 + 1.1883 + static SharedScriptData *fromBytecode(const jsbytecode *bytecode) { 1.1884 + return (SharedScriptData *)(bytecode - offsetof(SharedScriptData, data)); 1.1885 + } 1.1886 + 1.1887 + private: 1.1888 + SharedScriptData() MOZ_DELETE; 1.1889 + SharedScriptData(const SharedScriptData&) MOZ_DELETE; 1.1890 +}; 1.1891 + 1.1892 +struct ScriptBytecodeHasher 1.1893 +{ 1.1894 + struct Lookup 1.1895 + { 1.1896 + jsbytecode *code; 1.1897 + uint32_t length; 1.1898 + 1.1899 + Lookup(SharedScriptData *ssd) : code(ssd->data), length(ssd->length) {} 1.1900 + }; 1.1901 + static HashNumber hash(const Lookup &l) { return mozilla::HashBytes(l.code, l.length); } 1.1902 + static bool match(SharedScriptData *entry, const Lookup &lookup) { 1.1903 + if (entry->length != lookup.length) 1.1904 + return false; 1.1905 + return mozilla::PodEqual<jsbytecode>(entry->data, lookup.code, lookup.length); 1.1906 + } 1.1907 +}; 1.1908 + 1.1909 +typedef HashSet<SharedScriptData*, 1.1910 + ScriptBytecodeHasher, 1.1911 + SystemAllocPolicy> ScriptDataTable; 1.1912 + 1.1913 +extern void 1.1914 +UnmarkScriptData(JSRuntime *rt); 1.1915 + 1.1916 +extern void 1.1917 +SweepScriptData(JSRuntime *rt); 1.1918 + 1.1919 +extern void 1.1920 +FreeScriptData(JSRuntime *rt); 1.1921 + 1.1922 +struct ScriptAndCounts 1.1923 +{ 1.1924 + /* This structure is stored and marked from the JSRuntime. */ 1.1925 + JSScript *script; 1.1926 + ScriptCounts scriptCounts; 1.1927 + 1.1928 + PCCounts &getPCCounts(jsbytecode *pc) const { 1.1929 + return scriptCounts.pcCountsVector[script->pcToOffset(pc)]; 1.1930 + } 1.1931 + 1.1932 + jit::IonScriptCounts *getIonCounts() const { 1.1933 + return scriptCounts.ionCounts; 1.1934 + } 1.1935 +}; 1.1936 + 1.1937 +struct GSNCache; 1.1938 + 1.1939 +jssrcnote * 1.1940 +GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc); 1.1941 + 1.1942 +} /* namespace js */ 1.1943 + 1.1944 +extern jssrcnote * 1.1945 +js_GetSrcNote(JSContext *cx, JSScript *script, jsbytecode *pc); 1.1946 + 1.1947 +extern jsbytecode * 1.1948 +js_LineNumberToPC(JSScript *script, unsigned lineno); 1.1949 + 1.1950 +extern JS_FRIEND_API(unsigned) 1.1951 +js_GetScriptLineExtent(JSScript *script); 1.1952 + 1.1953 +namespace js { 1.1954 + 1.1955 +extern unsigned 1.1956 +PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp = nullptr); 1.1957 + 1.1958 +extern unsigned 1.1959 +PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc, 1.1960 + unsigned *columnp = nullptr); 1.1961 + 1.1962 +/* 1.1963 + * This function returns the file and line number of the script currently 1.1964 + * executing on cx. If there is no current script executing on cx (e.g., a 1.1965 + * native called directly through JSAPI (e.g., by setTimeout)), nullptr and 0 1.1966 + * are returned as the file and line. Additionally, this function avoids the 1.1967 + * full linear scan to compute line number when the caller guarantees that the 1.1968 + * script compilation occurs at a JSOP_EVAL/JSOP_SPREADEVAL. 1.1969 + */ 1.1970 + 1.1971 +enum LineOption { 1.1972 + CALLED_FROM_JSOP_EVAL, 1.1973 + NOT_CALLED_FROM_JSOP_EVAL 1.1974 +}; 1.1975 + 1.1976 +extern void 1.1977 +DescribeScriptedCallerForCompilation(JSContext *cx, MutableHandleScript maybeScript, 1.1978 + const char **file, unsigned *linenop, 1.1979 + uint32_t *pcOffset, JSPrincipals **origin, 1.1980 + LineOption opt = NOT_CALLED_FROM_JSOP_EVAL); 1.1981 + 1.1982 +bool 1.1983 +CloneFunctionScript(JSContext *cx, HandleFunction original, HandleFunction clone, 1.1984 + NewObjectKind newKind = GenericObject); 1.1985 + 1.1986 +/* 1.1987 + * JSAPI clients are allowed to leave CompileOptions.originPrincipals nullptr in 1.1988 + * which case the JS engine sets options.originPrincipals = origin.principals. 1.1989 + * This normalization step must occur before the originPrincipals get stored in 1.1990 + * the JSScript/ScriptSource. 1.1991 + */ 1.1992 + 1.1993 +static inline JSPrincipals * 1.1994 +NormalizeOriginPrincipals(JSPrincipals *principals, JSPrincipals *originPrincipals) 1.1995 +{ 1.1996 + return originPrincipals ? originPrincipals : principals; 1.1997 +} 1.1998 + 1.1999 +} /* namespace js */ 1.2000 + 1.2001 +#endif /* jsscript_h */