1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 /* JS script descriptor. */
8
9 #ifndef jsscript_h
10 #define jsscript_h
11
12 #include "mozilla/Atomics.h"
13 #include "mozilla/MemoryReporting.h"
14 #include "mozilla/PodOperations.h"
15 #include "mozilla/UniquePtr.h"
16
17 #include "jsatom.h"
18 #include "jslock.h"
19 #include "jsopcode.h"
20 #include "jstypes.h"
21
22 #include "gc/Barrier.h"
23 #include "gc/Rooting.h"
24 #include "jit/IonCode.h"
25 #include "js/UbiNode.h"
26 #include "vm/NativeObject.h"
27 #include "vm/Shape.h"
28
29 namespace JS {
30 struct ScriptSourceInfo;
31 } // namespace JS
32
33 namespace js {
34
35 namespace jit {
36 struct BaselineScript;
37 struct IonScriptCounts;
38 } // namespace jit
39
40 # define ION_DISABLED_SCRIPT ((js::jit::IonScript*)0x1)
41 # define ION_COMPILING_SCRIPT ((js::jit::IonScript*)0x2)
42 # define ION_PENDING_SCRIPT ((js::jit::IonScript*)0x3)
43
44 # define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript*)0x1)
45
46 class BreakpointSite;
47 class BindingIter;
48 class Debugger;
49 class LazyScript;
50 class ModuleObject;
51 class NestedScopeObject;
52 class RegExpObject;
53 struct SourceCompressionTask;
54 class Shape;
55
56 namespace frontend {
57 struct BytecodeEmitter;
58 class UpvarCookie;
59 class FunctionBox;
60 class ModuleBox;
61 } // namespace frontend
62
63 namespace detail {
64
65 // Do not call this directly! It is exposed for the friend declarations in
66 // this file.
67 bool
68 CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScript src, HandleScript dst);
69
70 } // namespace detail
71
72 } // namespace js
73
74 /*
75 * Type of try note associated with each catch or finally block, and also with
76 * for-in and other kinds of loops. Non-for-in loops do not need these notes
77 * for exception unwinding, but storing their boundaries here is helpful for
78 * heuristics that need to know whether a given op is inside a loop.
79 */
80 enum JSTryNoteKind {
81 JSTRY_CATCH,
82 JSTRY_FINALLY,
83 JSTRY_FOR_IN,
84 JSTRY_FOR_OF,
85 JSTRY_LOOP
86 };
87
88 /*
89 * Exception handling record.
90 */
91 struct JSTryNote {
92 uint8_t kind; /* one of JSTryNoteKind */
93 uint32_t stackDepth; /* stack depth upon exception handler entry */
94 uint32_t start; /* start of the try statement or loop
95 relative to script->main */
96 uint32_t length; /* length of the try statement or loop */
97 };
98
99 namespace js {
100
101 // A block scope has a range in bytecode: it is entered at some offset, and left
102 // at some later offset. Scopes can be nested. Given an offset, the
103 // BlockScopeNote containing that offset whose with the highest start value
104 // indicates the block scope. The block scope list is sorted by increasing
105 // start value.
106 //
107 // It is possible to leave a scope nonlocally, for example via a "break"
108 // statement, so there may be short bytecode ranges in a block scope in which we
109 // are popping the block chain in preparation for a goto. These exits are also
110 // nested with respect to outer scopes. The scopes in these exits are indicated
111 // by the "index" field, just like any other block. If a nonlocal exit pops the
112 // last block scope, the index will be NoBlockScopeIndex.
113 //
114 struct BlockScopeNote {
115 static const uint32_t NoBlockScopeIndex = UINT32_MAX;
116
117 uint32_t index; // Index of NestedScopeObject in the object
118 // array, or NoBlockScopeIndex if there is no
119 // block scope in this range.
120 uint32_t start; // Bytecode offset at which this scope starts,
121 // from script->main().
122 uint32_t length; // Bytecode length of scope.
123 uint32_t parent; // Index of parent block scope in notes, or UINT32_MAX.
124 };
125
126 struct ConstArray {
127 js::HeapValue* vector; /* array of indexed constant values */
128 uint32_t length;
129 };
130
131 struct ObjectArray {
132 js::HeapPtrObject* vector; // Array of indexed objects.
133 uint32_t length; // Count of indexed objects.
134 };
135
136 struct TryNoteArray {
137 JSTryNote* vector; // Array of indexed try notes.
138 uint32_t length; // Count of indexed try notes.
139 };
140
141 struct BlockScopeArray {
142 BlockScopeNote* vector; // Array of indexed BlockScopeNote records.
143 uint32_t length; // Count of indexed try notes.
144 };
145
146 class YieldOffsetArray {
147 friend bool
148 detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScript src,
149 HandleScript dst);
150
151 uint32_t* vector_; // Array of bytecode offsets.
152 uint32_t length_; // Count of bytecode offsets.
153
154 public:
init(uint32_t * vector,uint32_t length)155 void init(uint32_t* vector, uint32_t length) {
156 vector_ = vector;
157 length_ = length;
158 }
159 uint32_t& operator[](uint32_t index) {
160 MOZ_ASSERT(index < length_);
161 return vector_[index];
162 }
length()163 uint32_t length() const {
164 return length_;
165 }
166 };
167
168 class Binding : public JS::Traceable
169 {
170 // One JSScript stores one Binding per formal/variable so we use a
171 // packed-word representation.
172 uintptr_t bits_;
173
174 static const uintptr_t KIND_MASK = 0x3;
175 static const uintptr_t ALIASED_BIT = 0x4;
176 static const uintptr_t NAME_MASK = ~(KIND_MASK | ALIASED_BIT);
177
178 public:
179 // A "binding" is a formal parameter, 'var' (also a stand in for
180 // body-level 'let' declarations), or 'const' declaration. A function's
181 // lexical scope is composed of these three kinds of bindings.
182 enum Kind { ARGUMENT, VARIABLE, CONSTANT };
183
Binding()184 explicit Binding() : bits_(0) {}
185
Binding(PropertyName * name,Kind kind,bool aliased)186 Binding(PropertyName* name, Kind kind, bool aliased) {
187 JS_STATIC_ASSERT(CONSTANT <= KIND_MASK);
188 MOZ_ASSERT((uintptr_t(name) & ~NAME_MASK) == 0);
189 MOZ_ASSERT((uintptr_t(kind) & ~KIND_MASK) == 0);
190 bits_ = uintptr_t(name) | uintptr_t(kind) | (aliased ? ALIASED_BIT : 0);
191 }
192
name()193 PropertyName* name() const {
194 return (PropertyName*)(bits_ & NAME_MASK);
195 }
196
kind()197 Kind kind() const {
198 return Kind(bits_ & KIND_MASK);
199 }
200
aliased()201 bool aliased() const {
202 return bool(bits_ & ALIASED_BIT);
203 }
204
trace(Binding * self,JSTracer * trc)205 static void trace(Binding* self, JSTracer* trc) { self->trace(trc); }
206 void trace(JSTracer* trc);
207 };
208
209 JS_STATIC_ASSERT(sizeof(Binding) == sizeof(uintptr_t));
210
211 /*
212 * Formal parameters and local variables are stored in a shape tree
213 * path encapsulated within this class. This class represents bindings for
214 * both function and top-level scripts (the latter is needed to track names in
215 * strict mode eval code, to give such code its own lexical environment).
216 */
217 class Bindings : public JS::Traceable
218 {
219 friend class BindingIter;
220 friend class AliasedFormalIter;
221 template <typename Outer> friend class BindingsOperations;
222 template <typename Outer> friend class MutableBindingsOperations;
223
224 RelocatablePtrShape callObjShape_;
225 uintptr_t bindingArrayAndFlag_;
226 uint16_t numArgs_;
227 uint16_t numBlockScoped_;
228 uint16_t numBodyLevelLexicals_;
229 uint16_t numUnaliasedBodyLevelLexicals_;
230 uint32_t aliasedBodyLevelLexicalBegin_;
231 uint32_t numVars_;
232 uint32_t numUnaliasedVars_;
233
234 #if JS_BITS_PER_WORD == 32
235 // Bindings is allocated inline inside JSScript, which needs to be
236 // gc::Cell aligned.
237 uint32_t padding_;
238 #endif
239
240 /*
241 * During parsing, bindings are allocated out of a temporary LifoAlloc.
242 * After parsing, a JSScript object is created and the bindings are
243 * permanently transferred to it. On error paths, the JSScript object may
244 * end up with bindings that still point to the (new released) LifoAlloc
245 * memory. To avoid tracing these bindings during GC, we keep track of
246 * whether the bindings are temporary or permanent in the low bit of
247 * bindingArrayAndFlag_.
248 */
249 static const uintptr_t TEMPORARY_STORAGE_BIT = 0x1;
bindingArrayUsingTemporaryStorage()250 bool bindingArrayUsingTemporaryStorage() const {
251 return bindingArrayAndFlag_ & TEMPORARY_STORAGE_BIT;
252 }
253
254 public:
255 static const uint32_t BLOCK_SCOPED_LIMIT = UINT16_LIMIT;
256
bindingArray()257 Binding* bindingArray() const {
258 return reinterpret_cast<Binding*>(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT);
259 }
260
Bindings()261 Bindings()
262 : callObjShape_(nullptr), bindingArrayAndFlag_(TEMPORARY_STORAGE_BIT),
263 numArgs_(0), numBlockScoped_(0),
264 numBodyLevelLexicals_(0), numUnaliasedBodyLevelLexicals_(0),
265 numVars_(0), numUnaliasedVars_(0)
266 {}
267
268 /*
269 * Initialize a Bindings with a pointer into temporary storage.
270 * bindingArray must have length numArgs + numVars +
271 * numBodyLevelLexicals. Before the temporary storage is release,
272 * switchToScriptStorage must be called, providing a pointer into the
273 * Binding array stored in script->data.
274 */
275 static bool initWithTemporaryStorage(ExclusiveContext* cx, MutableHandle<Bindings> self,
276 uint32_t numArgs,
277 uint32_t numVars,
278 uint32_t numBodyLevelLexicals,
279 uint32_t numBlockScoped,
280 uint32_t numUnaliasedVars,
281 uint32_t numUnaliasedBodyLevelLexicals,
282 const Binding* bindingArray,
283 bool isModule = false);
284
285 // Initialize a trivial Bindings with no slots and an empty callObjShape.
286 bool initTrivial(ExclusiveContext* cx);
287
288 // CompileScript parses and compiles one statement at a time, but the result
289 // is one Script object. There will be no vars or bindings, because those
290 // go on the global, but there may be block-scoped locals, and the number of
291 // block-scoped locals may increase as we parse more expressions. This
292 // helper updates the number of block scoped variables in a script as it is
293 // being parsed.
updateNumBlockScoped(unsigned numBlockScoped)294 void updateNumBlockScoped(unsigned numBlockScoped) {
295 MOZ_ASSERT(!callObjShape_);
296 MOZ_ASSERT(numVars_ == 0);
297 MOZ_ASSERT(numBlockScoped < LOCALNO_LIMIT);
298 MOZ_ASSERT(numBlockScoped >= numBlockScoped_);
299 numBlockScoped_ = numBlockScoped;
300 }
301
setAllLocalsAliased()302 void setAllLocalsAliased() {
303 numBlockScoped_ = 0;
304 }
305
306 uint8_t* switchToScriptStorage(Binding* newStorage);
307
308 /*
309 * Clone srcScript's bindings (as part of js::CloneScript). dstScriptData
310 * is the pointer to what will eventually be dstScript->data.
311 */
312 static bool clone(JSContext* cx, MutableHandle<Bindings> self, uint8_t* dstScriptData,
313 HandleScript srcScript);
314
numArgs()315 uint32_t numArgs() const { return numArgs_; }
numVars()316 uint32_t numVars() const { return numVars_; }
numBodyLevelLexicals()317 uint32_t numBodyLevelLexicals() const { return numBodyLevelLexicals_; }
numBlockScoped()318 uint32_t numBlockScoped() const { return numBlockScoped_; }
numBodyLevelLocals()319 uint32_t numBodyLevelLocals() const { return numVars_ + numBodyLevelLexicals_; }
numUnaliasedBodyLevelLocals()320 uint32_t numUnaliasedBodyLevelLocals() const { return numUnaliasedVars_ + numUnaliasedBodyLevelLexicals_; }
numAliasedBodyLevelLocals()321 uint32_t numAliasedBodyLevelLocals() const { return numBodyLevelLocals() - numUnaliasedBodyLevelLocals(); }
numLocals()322 uint32_t numLocals() const { return numVars() + numBodyLevelLexicals() + numBlockScoped(); }
numFixedLocals()323 uint32_t numFixedLocals() const { return numUnaliasedVars() + numUnaliasedBodyLevelLexicals() + numBlockScoped(); }
lexicalBegin()324 uint32_t lexicalBegin() const { return numArgs() + numVars(); }
aliasedBodyLevelLexicalBegin()325 uint32_t aliasedBodyLevelLexicalBegin() const { return aliasedBodyLevelLexicalBegin_; }
326
numUnaliasedVars()327 uint32_t numUnaliasedVars() const { return numUnaliasedVars_; }
numUnaliasedBodyLevelLexicals()328 uint32_t numUnaliasedBodyLevelLexicals() const { return numUnaliasedBodyLevelLexicals_; }
329
330 // Return the size of the bindingArray.
count()331 uint32_t count() const { return numArgs() + numVars() + numBodyLevelLexicals(); }
332
333 /* Return the initial shape of call objects created for this scope. */
callObjShape()334 Shape* callObjShape() const { return callObjShape_; }
335
336 /* Convenience method to get the var index of 'arguments' or 'this'. */
337 static BindingIter argumentsBinding(ExclusiveContext* cx, HandleScript script);
338 static BindingIter thisBinding(ExclusiveContext* cx, HandleScript script);
339
340 /* Return whether the binding at bindingIndex is aliased. */
341 bool bindingIsAliased(uint32_t bindingIndex);
342
343 /* Return whether this scope has any aliased bindings. */
hasAnyAliasedBindings()344 bool hasAnyAliasedBindings() const {
345 if (!callObjShape_)
346 return false;
347
348 return !callObjShape_->isEmptyShape();
349 }
350
begin()351 Binding* begin() const { return bindingArray(); }
end()352 Binding* end() const { return bindingArray() + count(); }
353
trace(Bindings * self,JSTracer * trc)354 static void trace(Bindings* self, JSTracer* trc) { self->trace(trc); }
355 void trace(JSTracer* trc);
356 };
357
358 // If this fails, add/remove padding within Bindings.
359 static_assert(sizeof(Bindings) % js::gc::CellSize == 0,
360 "Size of Bindings must be an integral multiple of js::gc::CellSize");
361
362 template <class Outer>
363 class BindingsOperations
364 {
bindings()365 const Bindings& bindings() const { return static_cast<const Outer*>(this)->get(); }
366
367 public:
368 // Direct data access to the underlying bindings.
callObjShape()369 const RelocatablePtrShape& callObjShape() const {
370 return bindings().callObjShape_;
371 }
numArgs()372 uint16_t numArgs() const {
373 return bindings().numArgs_;
374 }
numBlockScoped()375 uint16_t numBlockScoped() const {
376 return bindings().numBlockScoped_;
377 }
numBodyLevelLexicals()378 uint16_t numBodyLevelLexicals() const {
379 return bindings().numBodyLevelLexicals_;
380 }
aliasedBodyLevelLexicalBegin()381 uint16_t aliasedBodyLevelLexicalBegin() const {
382 return bindings().aliasedBodyLevelLexicalBegin_;
383 }
numUnaliasedBodyLevelLexicals()384 uint16_t numUnaliasedBodyLevelLexicals() const {
385 return bindings().numUnaliasedBodyLevelLexicals_;
386 }
numVars()387 uint32_t numVars() const {
388 return bindings().numVars_;
389 }
numUnaliasedVars()390 uint32_t numUnaliasedVars() const {
391 return bindings().numUnaliasedVars_;
392 }
393
394 // Binding array access.
bindingArrayUsingTemporaryStorage()395 bool bindingArrayUsingTemporaryStorage() const {
396 return bindings().bindingArrayUsingTemporaryStorage();
397 }
bindingArray()398 const Binding* bindingArray() const {
399 return bindings().bindingArray();
400 }
count()401 uint32_t count() const {
402 return bindings().count();
403 }
404
405 // Helpers.
numBodyLevelLocals()406 uint32_t numBodyLevelLocals() const {
407 return numVars() + numBodyLevelLexicals();
408 }
numUnaliasedBodyLevelLocals()409 uint32_t numUnaliasedBodyLevelLocals() const {
410 return numUnaliasedVars() + numUnaliasedBodyLevelLexicals();
411 }
numAliasedBodyLevelLocals()412 uint32_t numAliasedBodyLevelLocals() const {
413 return numBodyLevelLocals() - numUnaliasedBodyLevelLocals();
414 }
numLocals()415 uint32_t numLocals() const {
416 return numVars() + numBodyLevelLexicals() + numBlockScoped();
417 }
numFixedLocals()418 uint32_t numFixedLocals() const {
419 return numUnaliasedVars() + numUnaliasedBodyLevelLexicals() + numBlockScoped();
420 }
lexicalBegin()421 uint32_t lexicalBegin() const {
422 return numArgs() + numVars();
423 }
424 };
425
426 template <class Outer>
427 class MutableBindingsOperations : public BindingsOperations<Outer>
428 {
bindings()429 Bindings& bindings() { return static_cast<Outer*>(this)->get(); }
430
431 public:
setCallObjShape(HandleShape shape)432 void setCallObjShape(HandleShape shape) { bindings().callObjShape_ = shape; }
setBindingArray(const Binding * bindingArray,uintptr_t temporaryBit)433 void setBindingArray(const Binding* bindingArray, uintptr_t temporaryBit) {
434 bindings().bindingArrayAndFlag_ = uintptr_t(bindingArray) | temporaryBit;
435 }
setNumArgs(uint16_t num)436 void setNumArgs(uint16_t num) { bindings().numArgs_ = num; }
setNumVars(uint32_t num)437 void setNumVars(uint32_t num) { bindings().numVars_ = num; }
setNumBodyLevelLexicals(uint16_t num)438 void setNumBodyLevelLexicals(uint16_t num) { bindings().numBodyLevelLexicals_ = num; }
setNumBlockScoped(uint16_t num)439 void setNumBlockScoped(uint16_t num) { bindings().numBlockScoped_ = num; }
setNumUnaliasedVars(uint32_t num)440 void setNumUnaliasedVars(uint32_t num) { bindings().numUnaliasedVars_ = num; }
setNumUnaliasedBodyLevelLexicals(uint16_t num)441 void setNumUnaliasedBodyLevelLexicals(uint16_t num) {
442 bindings().numUnaliasedBodyLevelLexicals_ = num;
443 }
setAliasedBodyLevelLexicalBegin(uint32_t offset)444 void setAliasedBodyLevelLexicalBegin(uint32_t offset) {
445 bindings().aliasedBodyLevelLexicalBegin_ = offset;
446 }
switchToScriptStorage(Binding * permanentStorage)447 uint8_t* switchToScriptStorage(Binding* permanentStorage) {
448 return bindings().switchToScriptStorage(permanentStorage);
449 }
450 };
451
452 template <>
453 class HandleBase<Bindings> : public BindingsOperations<JS::Handle<Bindings>>
454 {};
455
456 template <>
457 class MutableHandleBase<Bindings>
458 : public MutableBindingsOperations<JS::MutableHandle<Bindings>>
459 {};
460
461 class ScriptCounts
462 {
463 public:
464 typedef mozilla::Vector<PCCounts, 0, SystemAllocPolicy> PCCountsVector;
465
466 inline ScriptCounts();
467 inline explicit ScriptCounts(PCCountsVector&& jumpTargets);
468 inline ScriptCounts(ScriptCounts&& src);
469 inline ~ScriptCounts();
470
471 inline ScriptCounts& operator=(ScriptCounts&& src);
472
473 // Return the counter used to count the number of visits. Returns null if
474 // the element is not found.
475 PCCounts* maybeGetPCCounts(size_t offset);
476 const PCCounts* maybeGetPCCounts(size_t offset) const;
477
478 // PCCounts are stored at jump-target offsets. This function looks for the
479 // previous PCCount which is in the same basic block as the current offset.
480 PCCounts* getImmediatePrecedingPCCounts(size_t offset);
481
482 // Return the counter used to count the number of throws. Returns null if
483 // the element is not found.
484 const PCCounts* maybeGetThrowCounts(size_t offset) const;
485
486 // Throw counts are stored at the location of each throwing
487 // instruction. This function looks for the previous throw count.
488 //
489 // Note: if the offset of the returned count is higher than the offset of
490 // the immediate preceding PCCount, then this throw happened in the same
491 // basic block.
492 const PCCounts* getImmediatePrecedingThrowCounts(size_t offset) const;
493
494 // Return the counter used to count the number of throws. Allocate it if
495 // none exists yet. Returns null if the allocation failed.
496 PCCounts* getThrowCounts(size_t offset);
497
498 private:
499 friend class ::JSScript;
500 friend struct ScriptAndCounts;
501
502 // This sorted array is used to map an offset to the number of times a
503 // branch got visited.
504 PCCountsVector pcCounts_;
505
506 // This sorted vector is used to map an offset to the number of times an
507 // instruction throw.
508 PCCountsVector throwCounts_;
509
510 // Information about any Ion compilations for the script.
511 jit::IonScriptCounts* ionCounts_;
512 };
513
514 // Note: The key of this hash map is a weak reference to a JSScript. We do not
515 // use the WeakMap implementation provided in jsweakmap.h because it would be
516 // collected at the beginning of the sweeping of the compartment, thus before
517 // the calls to the JSScript::finalize function which are used to aggregate code
518 // coverage results on the compartment.
519 typedef HashMap<JSScript*,
520 ScriptCounts,
521 DefaultHasher<JSScript*>,
522 SystemAllocPolicy> ScriptCountsMap;
523
524 class DebugScript
525 {
526 friend class ::JSScript;
527
528 /*
529 * When non-zero, compile script in single-step mode. The top bit is set and
530 * cleared by setStepMode, as used by JSD. The lower bits are a count,
531 * adjusted by changeStepModeCount, used by the Debugger object. Only
532 * when the bit is clear and the count is zero may we compile the script
533 * without single-step support.
534 */
535 uint32_t stepMode;
536
537 /*
538 * Number of breakpoint sites at opcodes in the script. This is the number
539 * of populated entries in DebugScript::breakpoints, below.
540 */
541 uint32_t numSites;
542
543 /*
544 * Breakpoints set in our script. For speed and simplicity, this array is
545 * parallel to script->code(): the BreakpointSite for the opcode at
546 * script->code()[offset] is debugScript->breakpoints[offset]. Naturally,
547 * this array's true length is script->length().
548 */
549 BreakpointSite* breakpoints[1];
550 };
551
552 typedef HashMap<JSScript*,
553 DebugScript*,
554 DefaultHasher<JSScript*>,
555 SystemAllocPolicy> DebugScriptMap;
556
557 class ScriptSource;
558
559 class UncompressedSourceCache
560 {
561 typedef HashMap<ScriptSource*,
562 const char16_t*,
563 DefaultHasher<ScriptSource*>,
564 SystemAllocPolicy> Map;
565
566 public:
567 // Hold an entry in the source data cache and prevent it from being purged on GC.
568 class AutoHoldEntry
569 {
570 UncompressedSourceCache* cache_;
571 ScriptSource* source_;
572 const char16_t* charsToFree_;
573 public:
574 explicit AutoHoldEntry();
575 ~AutoHoldEntry();
576 private:
577 void holdEntry(UncompressedSourceCache* cache, ScriptSource* source);
578 void deferDelete(const char16_t* chars);
source()579 ScriptSource* source() const { return source_; }
580 friend class UncompressedSourceCache;
581 };
582
583 private:
584 Map* map_;
585 AutoHoldEntry* holder_;
586
587 public:
UncompressedSourceCache()588 UncompressedSourceCache() : map_(nullptr), holder_(nullptr) {}
589
590 const char16_t* lookup(ScriptSource* ss, AutoHoldEntry& asp);
591 bool put(ScriptSource* ss, const char16_t* chars, AutoHoldEntry& asp);
592
593 void purge();
594
595 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
596
597 private:
598 void holdEntry(AutoHoldEntry& holder, ScriptSource* ss);
599 void releaseEntry(AutoHoldEntry& holder);
600 };
601
602 class ScriptSource
603 {
604 friend struct SourceCompressionTask;
605
606 uint32_t refs;
607
608 // Note: while ScriptSources may be compressed off thread, they are only
609 // modified by the main thread, and all members are always safe to access
610 // on the main thread.
611
612 // Indicate which field in the |data| union is active.
613 enum {
614 DataMissing,
615 DataUncompressed,
616 DataCompressed,
617 DataParent
618 } dataType;
619
620 union {
621 struct {
622 const char16_t* chars;
623 bool ownsChars;
624 } uncompressed;
625
626 struct {
627 void* raw;
628 size_t nbytes;
629 HashNumber hash;
630 } compressed;
631
632 ScriptSource* parent;
633 } data;
634
635 uint32_t length_;
636
637 // The filename of this script.
638 mozilla::UniquePtr<char[], JS::FreePolicy> filename_;
639
640 mozilla::UniquePtr<char16_t[], JS::FreePolicy> displayURL_;
641 mozilla::UniquePtr<char16_t[], JS::FreePolicy> sourceMapURL_;
642 bool mutedErrors_;
643
644 // bytecode offset in caller script that generated this code.
645 // This is present for eval-ed code, as well as "new Function(...)"-introduced
646 // scripts.
647 uint32_t introductionOffset_;
648
649 // If this ScriptSource was generated by a code-introduction mechanism such
650 // as |eval| or |new Function|, the debugger needs access to the "raw"
651 // filename of the top-level script that contains the eval-ing code. To
652 // keep track of this, we must preserve the original outermost filename (of
653 // the original introducer script), so that instead of a filename of
654 // "foo.js line 30 > eval line 10 > Function", we can obtain the original
655 // raw filename of "foo.js".
656 //
657 // In the case described above, this field will be non-null and will be the
658 // original raw filename from above. Otherwise this field will be null.
659 mozilla::UniquePtr<char[], JS::FreePolicy> introducerFilename_;
660
661 // A string indicating how this source code was introduced into the system.
662 // This accessor returns one of the following values:
663 // "eval" for code passed to |eval|.
664 // "Function" for code passed to the |Function| constructor.
665 // "Worker" for code loaded by calling the Web worker constructor—the worker's main script.
666 // "importScripts" for code by calling |importScripts| in a web worker.
667 // "handler" for code assigned to DOM elements' event handler IDL attributes.
668 // "scriptElement" for code belonging to <script> elements.
669 // undefined if the implementation doesn't know how the code was introduced.
670 // This is a constant, statically allocated C string, so does not need
671 // memory management.
672 const char* introductionType_;
673
674 // True if we can call JSRuntime::sourceHook to load the source on
675 // demand. If sourceRetrievable_ and hasSourceData() are false, it is not
676 // possible to get source at all.
677 bool sourceRetrievable_:1;
678 bool argumentsNotIncluded_:1;
679 bool hasIntroductionOffset_:1;
680
681 // Whether this is in the runtime's set of compressed ScriptSources.
682 bool inCompressedSourceSet:1;
683
684 public:
ScriptSource()685 explicit ScriptSource()
686 : refs(0),
687 dataType(DataMissing),
688 length_(0),
689 filename_(nullptr),
690 displayURL_(nullptr),
691 sourceMapURL_(nullptr),
692 mutedErrors_(false),
693 introductionOffset_(0),
694 introducerFilename_(nullptr),
695 introductionType_(nullptr),
696 sourceRetrievable_(false),
697 argumentsNotIncluded_(false),
698 hasIntroductionOffset_(false),
699 inCompressedSourceSet(false)
700 {
701 }
702 ~ScriptSource();
incref()703 void incref() { refs++; }
decref()704 void decref() {
705 MOZ_ASSERT(refs != 0);
706 if (--refs == 0)
707 js_delete(this);
708 }
709 bool initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
710 bool setSourceCopy(ExclusiveContext* cx,
711 JS::SourceBufferHolder& srcBuf,
712 bool argumentsNotIncluded,
713 SourceCompressionTask* tok);
setSourceRetrievable()714 void setSourceRetrievable() { sourceRetrievable_ = true; }
sourceRetrievable()715 bool sourceRetrievable() const { return sourceRetrievable_; }
hasSourceData()716 bool hasSourceData() const { return dataType != DataMissing; }
hasCompressedSource()717 bool hasCompressedSource() const { return dataType == DataCompressed; }
length()718 size_t length() const {
719 MOZ_ASSERT(hasSourceData());
720 return length_;
721 }
argumentsNotIncluded()722 bool argumentsNotIncluded() const {
723 MOZ_ASSERT(hasSourceData());
724 return argumentsNotIncluded_;
725 }
726 const char16_t* chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& asp);
727 JSFlatString* substring(JSContext* cx, uint32_t start, uint32_t stop);
728 JSFlatString* substringDontDeflate(JSContext* cx, uint32_t start, uint32_t stop);
729 void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
730 JS::ScriptSourceInfo* info) const;
731
uncompressedChars()732 const char16_t* uncompressedChars() const {
733 MOZ_ASSERT(dataType == DataUncompressed);
734 return data.uncompressed.chars;
735 }
736
ownsUncompressedChars()737 bool ownsUncompressedChars() const {
738 MOZ_ASSERT(dataType == DataUncompressed);
739 return data.uncompressed.ownsChars;
740 }
741
compressedData()742 void* compressedData() const {
743 MOZ_ASSERT(dataType == DataCompressed);
744 return data.compressed.raw;
745 }
746
compressedBytes()747 size_t compressedBytes() const {
748 MOZ_ASSERT(dataType == DataCompressed);
749 return data.compressed.nbytes;
750 }
751
compressedHash()752 HashNumber compressedHash() const {
753 MOZ_ASSERT(dataType == DataCompressed);
754 return data.compressed.hash;
755 }
756
parent()757 ScriptSource* parent() const {
758 MOZ_ASSERT(dataType == DataParent);
759 return data.parent;
760 }
761
762 void setSource(const char16_t* chars, size_t length, bool ownsChars = true);
763 void setCompressedSource(JSRuntime* maybert, void* raw, size_t nbytes, HashNumber hash);
764 void updateCompressedSourceSet(JSRuntime* rt);
765 bool ensureOwnsSource(ExclusiveContext* cx);
766
767 // XDR handling
768 template <XDRMode mode>
769 bool performXDR(XDRState<mode>* xdr);
770
771 bool setFilename(ExclusiveContext* cx, const char* filename);
introducerFilename()772 const char* introducerFilename() const {
773 return introducerFilename_ ? introducerFilename_.get() : filename_.get();
774 }
hasIntroductionType()775 bool hasIntroductionType() const {
776 return introductionType_;
777 }
introductionType()778 const char* introductionType() const {
779 MOZ_ASSERT(hasIntroductionType());
780 return introductionType_;
781 }
filename()782 const char* filename() const {
783 return filename_.get();
784 }
785
786 // Display URLs
787 bool setDisplayURL(ExclusiveContext* cx, const char16_t* displayURL);
hasDisplayURL()788 bool hasDisplayURL() const { return displayURL_ != nullptr; }
displayURL()789 const char16_t * displayURL() {
790 MOZ_ASSERT(hasDisplayURL());
791 return displayURL_.get();
792 }
793
794 // Source maps
795 bool setSourceMapURL(ExclusiveContext* cx, const char16_t* sourceMapURL);
hasSourceMapURL()796 bool hasSourceMapURL() const { return sourceMapURL_ != nullptr; }
sourceMapURL()797 const char16_t * sourceMapURL() {
798 MOZ_ASSERT(hasSourceMapURL());
799 return sourceMapURL_.get();
800 }
801
mutedErrors()802 bool mutedErrors() const { return mutedErrors_; }
803
hasIntroductionOffset()804 bool hasIntroductionOffset() const { return hasIntroductionOffset_; }
introductionOffset()805 uint32_t introductionOffset() const {
806 MOZ_ASSERT(hasIntroductionOffset());
807 return introductionOffset_;
808 }
setIntroductionOffset(uint32_t offset)809 void setIntroductionOffset(uint32_t offset) {
810 MOZ_ASSERT(!hasIntroductionOffset());
811 MOZ_ASSERT(offset <= (uint32_t)INT32_MAX);
812 introductionOffset_ = offset;
813 hasIntroductionOffset_ = true;
814 }
815
816 private:
817 size_t computedSizeOfData() const;
818 };
819
820 class ScriptSourceHolder
821 {
822 ScriptSource* ss;
823 public:
ScriptSourceHolder(ScriptSource * ss)824 explicit ScriptSourceHolder(ScriptSource* ss)
825 : ss(ss)
826 {
827 ss->incref();
828 }
~ScriptSourceHolder()829 ~ScriptSourceHolder()
830 {
831 ss->decref();
832 }
833 };
834
835 struct CompressedSourceHasher
836 {
837 typedef ScriptSource* Lookup;
838
computeHashCompressedSourceHasher839 static HashNumber computeHash(const void* data, size_t nbytes) {
840 return mozilla::HashBytes(data, nbytes);
841 }
842
hashCompressedSourceHasher843 static HashNumber hash(const ScriptSource* ss) {
844 return ss->compressedHash();
845 }
846
matchCompressedSourceHasher847 static bool match(const ScriptSource* a, const ScriptSource* b) {
848 return a->compressedBytes() == b->compressedBytes() &&
849 a->compressedHash() == b->compressedHash() &&
850 !memcmp(a->compressedData(), b->compressedData(), a->compressedBytes());
851 }
852 };
853
854 typedef HashSet<ScriptSource*, CompressedSourceHasher, SystemAllocPolicy> CompressedSourceSet;
855
856 class ScriptSourceObject : public NativeObject
857 {
858 public:
859 static const Class class_;
860
861 static void trace(JSTracer* trc, JSObject* obj);
862 static void finalize(FreeOp* fop, JSObject* obj);
863 static ScriptSourceObject* create(ExclusiveContext* cx, ScriptSource* source);
864
865 // Initialize those properties of this ScriptSourceObject whose values
866 // are provided by |options|, re-wrapping as necessary.
867 static bool initFromOptions(JSContext* cx, HandleScriptSource source,
868 const ReadOnlyCompileOptions& options);
869
source()870 ScriptSource* source() const {
871 return static_cast<ScriptSource*>(getReservedSlot(SOURCE_SLOT).toPrivate());
872 }
element()873 JSObject* element() const {
874 return getReservedSlot(ELEMENT_SLOT).toObjectOrNull();
875 }
elementAttributeName()876 const Value& elementAttributeName() const {
877 MOZ_ASSERT(!getReservedSlot(ELEMENT_PROPERTY_SLOT).isMagic());
878 return getReservedSlot(ELEMENT_PROPERTY_SLOT);
879 }
introductionScript()880 JSScript* introductionScript() const {
881 if (getReservedSlot(INTRODUCTION_SCRIPT_SLOT).isUndefined())
882 return nullptr;
883 void* untyped = getReservedSlot(INTRODUCTION_SCRIPT_SLOT).toPrivate();
884 MOZ_ASSERT(untyped);
885 return static_cast<JSScript*>(untyped);
886 }
887
888 private:
889 static const uint32_t SOURCE_SLOT = 0;
890 static const uint32_t ELEMENT_SLOT = 1;
891 static const uint32_t ELEMENT_PROPERTY_SLOT = 2;
892 static const uint32_t INTRODUCTION_SCRIPT_SLOT = 3;
893 static const uint32_t RESERVED_SLOTS = 4;
894 };
895
896 enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };
897
898 static inline unsigned
GeneratorKindAsBits(GeneratorKind generatorKind)899 GeneratorKindAsBits(GeneratorKind generatorKind) {
900 return static_cast<unsigned>(generatorKind);
901 }
902
903 static inline GeneratorKind
GeneratorKindFromBits(unsigned val)904 GeneratorKindFromBits(unsigned val) {
905 MOZ_ASSERT(val <= StarGenerator);
906 return static_cast<GeneratorKind>(val);
907 }
908
909 /*
910 * NB: after a successful XDR_DECODE, XDRScript callers must do any required
911 * subsequent set-up of owning function or script object and then call
912 * CallNewScriptHook.
913 */
914 template<XDRMode mode>
915 bool
916 XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
917 HandleFunction fun, MutableHandleScript scriptp);
918
919 template<XDRMode mode>
920 bool
921 XDRLazyScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
922 HandleFunction fun, MutableHandle<LazyScript*> lazy);
923
924 /*
925 * Code any constant value.
926 */
927 template<XDRMode mode>
928 bool
929 XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp);
930
931 } /* namespace js */
932
933 class JSScript : public js::gc::TenuredCell
934 {
935 template <js::XDRMode mode>
936 friend
937 bool
938 js::XDRScript(js::XDRState<mode>* xdr, js::HandleObject enclosingScope,
939 js::HandleScript enclosingScript,
940 js::HandleFunction fun, js::MutableHandleScript scriptp);
941
942 friend bool
943 js::detail::CopyScript(JSContext* cx, js::HandleObject scriptStaticScope, js::HandleScript src,
944 js::HandleScript dst);
945
946 public:
947 //
948 // We order fields according to their size in order to avoid wasting space
949 // for alignment.
950 //
951
952 // Larger-than-word-sized fields.
953
954 public:
955 js::Bindings bindings; /* names of top-level variables in this script
956 (and arguments if this is a function script) */
957
hasAnyAliasedBindings()958 bool hasAnyAliasedBindings() const {
959 return bindings.hasAnyAliasedBindings();
960 }
961
bindingArray()962 js::Binding* bindingArray() const {
963 return bindings.bindingArray();
964 }
965
numArgs()966 unsigned numArgs() const {
967 return bindings.numArgs();
968 }
969
callObjShape()970 js::Shape* callObjShape() const {
971 return bindings.callObjShape();
972 }
973
974 // Word-sized fields.
975
976 private:
977 jsbytecode* code_; /* bytecodes and their immediate operands */
978 public:
979 uint8_t* data; /* pointer to variable-length data array (see
980 comment above Create() for details) */
981
982 js::HeapPtrAtom* atoms; /* maps immediate index to literal struct */
983
984 JSCompartment* compartment_;
985
986 private:
987 /* Persistent type information retained across GCs. */
988 js::TypeScript* types_;
989
990 // This script's ScriptSourceObject, or a CCW thereof.
991 //
992 // (When we clone a JSScript into a new compartment, we don't clone its
993 // source object. Instead, the clone refers to a wrapper.)
994 js::HeapPtrObject sourceObject_;
995
996 js::HeapPtrFunction function_;
997 js::HeapPtr<js::ModuleObject*> module_;
998 js::HeapPtrObject enclosingStaticScope_;
999
1000 /*
1001 * Information attached by Ion. Nexto a valid IonScript this could be
1002 * ION_DISABLED_SCRIPT, ION_COMPILING_SCRIPT or ION_PENDING_SCRIPT.
1003 * The later is a ion compilation that is ready, but hasn't been linked
1004 * yet.
1005 */
1006 js::jit::IonScript* ion;
1007
1008 /* Information attached by Baseline. */
1009 js::jit::BaselineScript* baseline;
1010
1011 /* Information used to re-lazify a lazily-parsed interpreted function. */
1012 js::LazyScript* lazyScript;
1013
1014 /*
1015 * Pointer to either baseline->method()->raw() or ion->method()->raw(), or
1016 * nullptr if there's no Baseline or Ion script.
1017 */
1018 uint8_t* baselineOrIonRaw;
1019 uint8_t* baselineOrIonSkipArgCheck;
1020
1021 // 32-bit fields.
1022
1023 uint32_t length_; /* length of code vector */
1024 uint32_t dataSize_; /* size of the used part of the data array */
1025
1026 uint32_t lineno_; /* base line number of script */
1027 uint32_t column_; /* base column of script, optionally set */
1028
1029 uint32_t mainOffset_;/* offset of main entry point from code, after
1030 predef'ing prologue */
1031
1032 uint32_t natoms_; /* length of atoms array */
1033 uint32_t nslots_; /* vars plus maximum stack depth */
1034
1035 /* Range of characters in scriptSource which contains this script's source. */
1036 uint32_t sourceStart_;
1037 uint32_t sourceEnd_;
1038
1039 uint32_t warmUpCount; /* Number of times the script has been called
1040 * or has had backedges taken. When running in
1041 * ion, also increased for any inlined scripts.
1042 * Reset if the script's JIT code is forcibly
1043 * discarded. */
1044
1045 // 16-bit fields.
1046
1047 uint16_t warmUpResetCount; /* Number of times the |warmUpCount| was
1048 * forcibly discarded. The counter is reset when
1049 * a script is successfully jit-compiled. */
1050
1051 uint16_t version; /* JS version under which script was compiled */
1052
1053 uint16_t funLength_; /* ES6 function length */
1054
1055 uint16_t nTypeSets_; /* number of type sets used in this script for
1056 dynamic type monitoring */
1057
1058 // Bit fields.
1059
1060 public:
1061 // The kinds of the optional arrays.
1062 enum ArrayKind {
1063 CONSTS,
1064 OBJECTS,
1065 REGEXPS,
1066 TRYNOTES,
1067 BLOCK_SCOPES,
1068 ARRAY_KIND_BITS
1069 };
1070
1071 private:
1072 // The bits in this field indicate the presence/non-presence of several
1073 // optional arrays in |data|. See the comments above Create() for details.
1074 uint8_t hasArrayBits:ARRAY_KIND_BITS;
1075
1076 // The GeneratorKind of the script.
1077 uint8_t generatorKindBits_:2;
1078
1079 // 1-bit fields.
1080
1081 // No need for result value of last expression statement.
1082 bool noScriptRval_:1;
1083
1084 // Can call getCallerFunction().
1085 bool savedCallerFun_:1;
1086
1087 // Code is in strict mode.
1088 bool strict_:1;
1089
1090 // Code has "use strict"; explicitly.
1091 bool explicitUseStrict_:1;
1092
1093 // True if the script has a non-syntactic scope on its dynamic scope chain.
1094 // That is, there are objects about which we know nothing between the
1095 // outermost syntactic scope and the global.
1096 bool hasNonSyntacticScope_:1;
1097
1098 // see Parser::selfHostingMode.
1099 bool selfHosted_:1;
1100
1101 // See FunctionContextFlags.
1102 bool bindingsAccessedDynamically_:1;
1103 bool funHasExtensibleScope_:1;
1104 bool funNeedsDeclEnvObject_:1;
1105
1106 // True if any formalIsAliased(i).
1107 bool funHasAnyAliasedFormal_:1;
1108
1109 // Have warned about uses of undefined properties in this script.
1110 bool warnedAboutUndefinedProp_:1;
1111
1112 // Script has singleton objects.
1113 bool hasSingletons_:1;
1114
1115 // Script is a lambda to treat as running once or a global or eval script
1116 // that will only run once. Which one it is can be disambiguated by
1117 // checking whether function_ is null.
1118 bool treatAsRunOnce_:1;
1119
1120 // If treatAsRunOnce, whether script has executed.
1121 bool hasRunOnce_:1;
1122
1123 // Script has been reused for a clone.
1124 bool hasBeenCloned_:1;
1125
1126 // Script came from eval(), and is still active.
1127 bool isActiveEval_:1;
1128
1129 // Script came from eval(), and is in eval cache.
1130 bool isCachedEval_:1;
1131
1132 // 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
1133 bool isLikelyConstructorWrapper_:1;
1134
1135 // IonMonkey compilation hints.
1136 bool failedBoundsCheck_:1; /* script has had hoisted bounds checks fail */
1137 bool failedShapeGuard_:1; /* script has had hoisted shape guard fail */
1138 bool hadFrequentBailouts_:1;
1139 bool uninlineable_:1; /* explicitly marked as uninlineable */
1140
1141 // Idempotent cache has triggered invalidation.
1142 bool invalidatedIdempotentCache_:1;
1143
1144 // Lexical check did fail and bail out.
1145 bool failedLexicalCheck_:1;
1146
1147 // If the generator was created implicitly via a generator expression,
1148 // isGeneratorExp will be true.
1149 bool isGeneratorExp_:1;
1150
1151 // Script has an entry in JSCompartment::scriptCountsMap.
1152 bool hasScriptCounts_:1;
1153
1154 // Script has an entry in JSCompartment::debugScriptMap.
1155 bool hasDebugScript_:1;
1156
1157 // Freeze constraints for stack type sets have been generated.
1158 bool hasFreezeConstraints_:1;
1159
1160 /* See comments below. */
1161 bool argsHasVarBinding_:1;
1162 bool needsArgsAnalysis_:1;
1163 bool needsArgsObj_:1;
1164 bool functionHasThisBinding_:1;
1165
1166 // Whether the arguments object for this script, if it needs one, should be
1167 // mapped (alias formal parameters).
1168 bool hasMappedArgsObj_:1;
1169
1170 // Generation for this script's TypeScript. If out of sync with the
1171 // TypeZone's generation, the TypeScript needs to be swept.
1172 //
1173 // This should be a uint32 but is instead a bool so that MSVC packs it
1174 // correctly.
1175 bool typesGeneration_:1;
1176
1177 // Do not relazify this script. This is used by the relazify() testing
1178 // function for scripts that are on the stack and also by the AutoDelazify
1179 // RAII class. Usually we don't relazify functions in compartments with
1180 // scripts on the stack, but the relazify() testing function overrides that,
1181 // and sometimes we're working with a cross-compartment function and need to
1182 // keep it from relazifying.
1183 bool doNotRelazify_:1;
1184
1185 // Script contains inner functions. Used to check if we can relazify the
1186 // script.
1187 bool hasInnerFunctions_:1;
1188
1189 bool needsHomeObject_:1;
1190
1191 bool isDerivedClassConstructor_:1;
1192
1193 // Add padding so JSScript is gc::Cell aligned. Make padding protected
1194 // instead of private to suppress -Wunused-private-field compiler warnings.
1195 protected:
1196 #if JS_BITS_PER_WORD == 32
1197 // No padding currently required.
1198 #endif
1199
1200 //
1201 // End of fields. Start methods.
1202 //
1203
1204 public:
1205 static JSScript* Create(js::ExclusiveContext* cx,
1206 js::HandleObject enclosingScope, bool savedCallerFun,
1207 const JS::ReadOnlyCompileOptions& options,
1208 js::HandleObject sourceObject, uint32_t sourceStart,
1209 uint32_t sourceEnd);
1210
1211 void initCompartment(js::ExclusiveContext* cx);
1212
1213 // Three ways ways to initialize a JSScript. Callers of partiallyInit()
1214 // and fullyInitTrivial() are responsible for notifying the debugger after
1215 // successfully creating any kind (function or other) of new JSScript.
1216 // However, callers of fullyInitFromEmitter() do not need to do this.
1217 static bool partiallyInit(js::ExclusiveContext* cx, JS::Handle<JSScript*> script,
1218 uint32_t nconsts, uint32_t nobjects, uint32_t nregexps,
1219 uint32_t ntrynotes, uint32_t nblockscopes, uint32_t nyieldoffsets,
1220 uint32_t nTypeSets);
1221 static bool fullyInitFromEmitter(js::ExclusiveContext* cx, JS::Handle<JSScript*> script,
1222 js::frontend::BytecodeEmitter* bce);
1223 static void linkToFunctionFromEmitter(js::ExclusiveContext* cx, JS::Handle<JSScript*> script,
1224 js::frontend::FunctionBox* funbox);
1225 static void linkToModuleFromEmitter(js::ExclusiveContext* cx, JS::Handle<JSScript*> script,
1226 js::frontend::ModuleBox* funbox);
1227 // Initialize a no-op script.
1228 static bool fullyInitTrivial(js::ExclusiveContext* cx, JS::Handle<JSScript*> script);
1229
1230 inline JSPrincipals* principals();
1231
compartment()1232 JSCompartment* compartment() const { return compartment_; }
maybeCompartment()1233 JSCompartment* maybeCompartment() const { return compartment(); }
1234
setVersion(JSVersion v)1235 void setVersion(JSVersion v) { version = v; }
1236
1237 // Script bytecode is immutable after creation.
code()1238 jsbytecode* code() const {
1239 return code_;
1240 }
length()1241 size_t length() const {
1242 return length_;
1243 }
1244
setCode(jsbytecode * code)1245 void setCode(jsbytecode* code) { code_ = code; }
setLength(size_t length)1246 void setLength(size_t length) { length_ = length; }
1247
codeEnd()1248 jsbytecode* codeEnd() const { return code() + length(); }
1249
lastPC()1250 jsbytecode* lastPC() const {
1251 jsbytecode* pc = codeEnd() - js::JSOP_RETRVAL_LENGTH;
1252 MOZ_ASSERT(*pc == JSOP_RETRVAL);
1253 return pc;
1254 }
1255
containsPC(const jsbytecode * pc)1256 bool containsPC(const jsbytecode* pc) const {
1257 return pc >= code() && pc < codeEnd();
1258 }
1259
pcToOffset(const jsbytecode * pc)1260 size_t pcToOffset(const jsbytecode* pc) const {
1261 MOZ_ASSERT(containsPC(pc));
1262 return size_t(pc - code());
1263 }
1264
offsetToPC(size_t offset)1265 jsbytecode* offsetToPC(size_t offset) const {
1266 MOZ_ASSERT(offset < length());
1267 return code() + offset;
1268 }
1269
mainOffset()1270 size_t mainOffset() const {
1271 return mainOffset_;
1272 }
1273
lineno()1274 size_t lineno() const {
1275 return lineno_;
1276 }
1277
column()1278 size_t column() const {
1279 return column_;
1280 }
1281
setColumn(size_t column)1282 void setColumn(size_t column) { column_ = column; }
1283
1284 // The fixed part of a stack frame is comprised of vars (in function code)
1285 // and block-scoped locals (in all kinds of code).
nfixed()1286 size_t nfixed() const {
1287 return function_ ? bindings.numFixedLocals() : bindings.numBlockScoped();
1288 }
1289
1290 // Number of fixed slots reserved for vars. Only nonzero for function
1291 // code.
nfixedvars()1292 size_t nfixedvars() const {
1293 return function_ ? bindings.numUnaliasedVars() : 0;
1294 }
1295
1296 // Number of fixed slots reserved for body-level lexicals and vars. This
1297 // value minus nfixedvars() is the number of body-level lexicals. Only
1298 // nonzero for function code.
nbodyfixed()1299 size_t nbodyfixed() const {
1300 return function_ ? bindings.numUnaliasedBodyLevelLocals() : 0;
1301 }
1302
1303 // Calculate the number of fixed slots that are live at a particular bytecode.
1304 size_t calculateLiveFixed(jsbytecode* pc);
1305
1306 // Aliases for clarity when dealing with lexical slots.
fixedLexicalBegin()1307 size_t fixedLexicalBegin() const {
1308 return nfixedvars();
1309 }
1310
fixedLexicalEnd()1311 size_t fixedLexicalEnd() const {
1312 return nfixed();
1313 }
1314
nslots()1315 size_t nslots() const {
1316 return nslots_;
1317 }
1318
nTypeSets()1319 size_t nTypeSets() const {
1320 return nTypeSets_;
1321 }
1322
funLength()1323 size_t funLength() const {
1324 return funLength_;
1325 }
1326
sourceStart()1327 size_t sourceStart() const {
1328 return sourceStart_;
1329 }
1330
sourceEnd()1331 size_t sourceEnd() const {
1332 return sourceEnd_;
1333 }
1334
noScriptRval()1335 bool noScriptRval() const {
1336 return noScriptRval_;
1337 }
1338
savedCallerFun()1339 bool savedCallerFun() const { return savedCallerFun_; }
1340
strict()1341 bool strict() const {
1342 return strict_;
1343 }
1344
explicitUseStrict()1345 bool explicitUseStrict() const { return explicitUseStrict_; }
1346
hasNonSyntacticScope()1347 bool hasNonSyntacticScope() const {
1348 return hasNonSyntacticScope_;
1349 }
1350
selfHosted()1351 bool selfHosted() const { return selfHosted_; }
bindingsAccessedDynamically()1352 bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; }
funHasExtensibleScope()1353 bool funHasExtensibleScope() const {
1354 return funHasExtensibleScope_;
1355 }
funNeedsDeclEnvObject()1356 bool funNeedsDeclEnvObject() const {
1357 return funNeedsDeclEnvObject_;
1358 }
funHasAnyAliasedFormal()1359 bool funHasAnyAliasedFormal() const {
1360 return funHasAnyAliasedFormal_;
1361 }
1362
hasSingletons()1363 bool hasSingletons() const { return hasSingletons_; }
treatAsRunOnce()1364 bool treatAsRunOnce() const {
1365 return treatAsRunOnce_;
1366 }
hasRunOnce()1367 bool hasRunOnce() const { return hasRunOnce_; }
hasBeenCloned()1368 bool hasBeenCloned() const { return hasBeenCloned_; }
1369
setTreatAsRunOnce()1370 void setTreatAsRunOnce() { treatAsRunOnce_ = true; }
setHasRunOnce()1371 void setHasRunOnce() { hasRunOnce_ = true; }
setHasBeenCloned()1372 void setHasBeenCloned() { hasBeenCloned_ = true; }
1373
isActiveEval()1374 bool isActiveEval() const { return isActiveEval_; }
isCachedEval()1375 bool isCachedEval() const { return isCachedEval_; }
1376
cacheForEval()1377 void cacheForEval() {
1378 MOZ_ASSERT(isActiveEval() && !isCachedEval());
1379 isActiveEval_ = false;
1380 isCachedEval_ = true;
1381 // IsEvalCacheCandidate will make sure that there's nothing in this
1382 // script that would prevent reexecution even if isRunOnce is
1383 // true. So just pretend like we never ran this script.
1384 hasRunOnce_ = false;
1385 }
1386
uncacheForEval()1387 void uncacheForEval() {
1388 MOZ_ASSERT(isCachedEval() && !isActiveEval());
1389 isCachedEval_ = false;
1390 isActiveEval_ = true;
1391 }
1392
setActiveEval()1393 void setActiveEval() { isActiveEval_ = true; }
1394
isLikelyConstructorWrapper()1395 bool isLikelyConstructorWrapper() const {
1396 return isLikelyConstructorWrapper_;
1397 }
setLikelyConstructorWrapper()1398 void setLikelyConstructorWrapper() { isLikelyConstructorWrapper_ = true; }
1399
isGeneratorExp()1400 bool isGeneratorExp() const { return isGeneratorExp_; }
1401
failedBoundsCheck()1402 bool failedBoundsCheck() const {
1403 return failedBoundsCheck_;
1404 }
failedShapeGuard()1405 bool failedShapeGuard() const {
1406 return failedShapeGuard_;
1407 }
hadFrequentBailouts()1408 bool hadFrequentBailouts() const {
1409 return hadFrequentBailouts_;
1410 }
uninlineable()1411 bool uninlineable() const {
1412 return uninlineable_;
1413 }
invalidatedIdempotentCache()1414 bool invalidatedIdempotentCache() const {
1415 return invalidatedIdempotentCache_;
1416 }
failedLexicalCheck()1417 bool failedLexicalCheck() const {
1418 return failedLexicalCheck_;
1419 }
1420
setFailedBoundsCheck()1421 void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
setFailedShapeGuard()1422 void setFailedShapeGuard() { failedShapeGuard_ = true; }
setHadFrequentBailouts()1423 void setHadFrequentBailouts() { hadFrequentBailouts_ = true; }
setUninlineable()1424 void setUninlineable() { uninlineable_ = true; }
setInvalidatedIdempotentCache()1425 void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; }
setFailedLexicalCheck()1426 void setFailedLexicalCheck() { failedLexicalCheck_ = true; }
1427
hasScriptCounts()1428 bool hasScriptCounts() const { return hasScriptCounts_; }
1429
hasFreezeConstraints()1430 bool hasFreezeConstraints() const { return hasFreezeConstraints_; }
setHasFreezeConstraints()1431 void setHasFreezeConstraints() { hasFreezeConstraints_ = true; }
1432
warnedAboutUndefinedProp()1433 bool warnedAboutUndefinedProp() const { return warnedAboutUndefinedProp_; }
setWarnedAboutUndefinedProp()1434 void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; }
1435
1436 /* See ContextFlags::funArgumentsHasLocalBinding comment. */
argumentsHasVarBinding()1437 bool argumentsHasVarBinding() const {
1438 return argsHasVarBinding_;
1439 }
argumentsBytecode()1440 jsbytecode* argumentsBytecode() const { MOZ_ASSERT(code()[0] == JSOP_ARGUMENTS); return code(); }
1441 void setArgumentsHasVarBinding();
argumentsAliasesFormals()1442 bool argumentsAliasesFormals() const {
1443 return argumentsHasVarBinding() && hasMappedArgsObj();
1444 }
1445
generatorKind()1446 js::GeneratorKind generatorKind() const {
1447 return js::GeneratorKindFromBits(generatorKindBits_);
1448 }
isGenerator()1449 bool isGenerator() const { return generatorKind() != js::NotGenerator; }
isLegacyGenerator()1450 bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
isStarGenerator()1451 bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
setGeneratorKind(js::GeneratorKind kind)1452 void setGeneratorKind(js::GeneratorKind kind) {
1453 // A script only gets its generator kind set as part of initialization,
1454 // so it can only transition from not being a generator.
1455 MOZ_ASSERT(!isGenerator());
1456 generatorKindBits_ = GeneratorKindAsBits(kind);
1457 }
1458
setNeedsHomeObject()1459 void setNeedsHomeObject() {
1460 needsHomeObject_ = true;
1461 }
needsHomeObject()1462 bool needsHomeObject() const {
1463 return needsHomeObject_;
1464 }
1465
isDerivedClassConstructor()1466 bool isDerivedClassConstructor() const {
1467 return isDerivedClassConstructor_;
1468 }
1469
1470 /*
1471 * As an optimization, even when argsHasLocalBinding, the function prologue
1472 * may not need to create an arguments object. This is determined by
1473 * needsArgsObj which is set by AnalyzeArgumentsUsage. When !needsArgsObj,
1474 * the prologue may simply write MagicValue(JS_OPTIMIZED_ARGUMENTS) to
1475 * 'arguments's slot and any uses of 'arguments' will be guaranteed to
1476 * handle this magic value. To avoid spurious arguments object creation, we
1477 * maintain the invariant that needsArgsObj is only called after the script
1478 * has been analyzed.
1479 */
analyzedArgsUsage()1480 bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
1481 inline bool ensureHasAnalyzedArgsUsage(JSContext* cx);
needsArgsObj()1482 bool needsArgsObj() const {
1483 MOZ_ASSERT(analyzedArgsUsage());
1484 return needsArgsObj_;
1485 }
1486 void setNeedsArgsObj(bool needsArgsObj);
1487 static bool argumentsOptimizationFailed(JSContext* cx, js::HandleScript script);
1488
hasMappedArgsObj()1489 bool hasMappedArgsObj() const {
1490 return hasMappedArgsObj_;
1491 }
1492
functionHasThisBinding()1493 bool functionHasThisBinding() const {
1494 return functionHasThisBinding_;
1495 }
1496
1497 /*
1498 * Arguments access (via JSOP_*ARG* opcodes) must access the canonical
1499 * location for the argument. If an arguments object exists AND it's mapped
1500 * ('arguments' aliases formals), then all access must go through the
1501 * arguments object. Otherwise, the local slot is the canonical location for
1502 * the arguments. Note: if a formal is aliased through the scope chain, then
1503 * script->formalIsAliased and JSOP_*ARG* opcodes won't be emitted at all.
1504 */
argsObjAliasesFormals()1505 bool argsObjAliasesFormals() const {
1506 return needsArgsObj() && hasMappedArgsObj();
1507 }
1508
typesGeneration()1509 uint32_t typesGeneration() const {
1510 return (uint32_t) typesGeneration_;
1511 }
1512
setTypesGeneration(uint32_t generation)1513 void setTypesGeneration(uint32_t generation) {
1514 MOZ_ASSERT(generation <= 1);
1515 typesGeneration_ = (bool) generation;
1516 }
1517
setDoNotRelazify(bool b)1518 void setDoNotRelazify(bool b) {
1519 doNotRelazify_ = b;
1520 }
1521
setHasInnerFunctions(bool b)1522 void setHasInnerFunctions(bool b) {
1523 hasInnerFunctions_ = b;
1524 }
1525
hasInnerFunctions()1526 bool hasInnerFunctions() const {
1527 return hasInnerFunctions_;
1528 }
1529
hasAnyIonScript()1530 bool hasAnyIonScript() const {
1531 return hasIonScript();
1532 }
1533
hasIonScript()1534 bool hasIonScript() const {
1535 bool res = ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT &&
1536 ion != ION_PENDING_SCRIPT;
1537 MOZ_ASSERT_IF(res, baseline);
1538 return res;
1539 }
canIonCompile()1540 bool canIonCompile() const {
1541 return ion != ION_DISABLED_SCRIPT;
1542 }
isIonCompilingOffThread()1543 bool isIonCompilingOffThread() const {
1544 return ion == ION_COMPILING_SCRIPT;
1545 }
1546
ionScript()1547 js::jit::IonScript* ionScript() const {
1548 MOZ_ASSERT(hasIonScript());
1549 return ion;
1550 }
maybeIonScript()1551 js::jit::IonScript* maybeIonScript() const {
1552 return ion;
1553 }
addressOfIonScript()1554 js::jit::IonScript* const* addressOfIonScript() const {
1555 return &ion;
1556 }
1557 void setIonScript(JSContext* maybecx, js::jit::IonScript* ionScript);
1558
hasBaselineScript()1559 bool hasBaselineScript() const {
1560 bool res = baseline && baseline != BASELINE_DISABLED_SCRIPT;
1561 MOZ_ASSERT_IF(!res, !ion || ion == ION_DISABLED_SCRIPT);
1562 return res;
1563 }
canBaselineCompile()1564 bool canBaselineCompile() const {
1565 return baseline != BASELINE_DISABLED_SCRIPT;
1566 }
baselineScript()1567 js::jit::BaselineScript* baselineScript() const {
1568 MOZ_ASSERT(hasBaselineScript());
1569 return baseline;
1570 }
1571 inline void setBaselineScript(JSContext* maybecx, js::jit::BaselineScript* baselineScript);
1572
1573 void updateBaselineOrIonRaw(JSContext* maybecx);
1574
offsetOfBaselineScript()1575 static size_t offsetOfBaselineScript() {
1576 return offsetof(JSScript, baseline);
1577 }
offsetOfIonScript()1578 static size_t offsetOfIonScript() {
1579 return offsetof(JSScript, ion);
1580 }
offsetOfBaselineOrIonRaw()1581 static size_t offsetOfBaselineOrIonRaw() {
1582 return offsetof(JSScript, baselineOrIonRaw);
1583 }
baselineOrIonRawPointer()1584 uint8_t* baselineOrIonRawPointer() const {
1585 return baselineOrIonRaw;
1586 }
offsetOfBaselineOrIonSkipArgCheck()1587 static size_t offsetOfBaselineOrIonSkipArgCheck() {
1588 return offsetof(JSScript, baselineOrIonSkipArgCheck);
1589 }
1590
isRelazifiable()1591 bool isRelazifiable() const {
1592 return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ &&
1593 !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() &&
1594 !hasScriptCounts() && !doNotRelazify_;
1595 }
setLazyScript(js::LazyScript * lazy)1596 void setLazyScript(js::LazyScript* lazy) {
1597 lazyScript = lazy;
1598 }
maybeLazyScript()1599 js::LazyScript* maybeLazyScript() {
1600 return lazyScript;
1601 }
1602
1603 /*
1604 * Original compiled function for the script, if it has a function.
1605 * nullptr for global and eval scripts.
1606 * The delazifying variant ensures that the function isn't lazy. The
1607 * non-delazifying variant must only be used after earlier code has
1608 * called ensureNonLazyCanonicalFunction and while the function can't
1609 * have been relazified.
1610 */
1611 inline JSFunction* functionDelazifying() const;
functionNonDelazifying()1612 JSFunction* functionNonDelazifying() const {
1613 return function_;
1614 }
1615 inline void setFunction(JSFunction* fun);
1616 /*
1617 * De-lazifies the canonical function. Must be called before entering code
1618 * that expects the function to be non-lazy.
1619 */
1620 inline void ensureNonLazyCanonicalFunction(JSContext* cx);
1621
module()1622 js::ModuleObject* module() const {
1623 return module_;
1624 }
1625 inline void setModule(js::ModuleObject* module);
1626
1627 // Returns true if the script may read formal arguments on the stack
1628 // directly, via lazy arguments or a rest parameter.
1629 bool mayReadFrameArgsDirectly();
1630
1631 JSFlatString* sourceData(JSContext* cx);
1632
1633 static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
1634
1635 void setSourceObject(JSObject* object);
sourceObject()1636 JSObject* sourceObject() const {
1637 return sourceObject_;
1638 }
1639 js::ScriptSourceObject& scriptSourceUnwrap() const;
1640 js::ScriptSource* scriptSource() const;
1641 js::ScriptSource* maybeForwardedScriptSource() const;
mutedErrors()1642 bool mutedErrors() const { return scriptSource()->mutedErrors(); }
filename()1643 const char* filename() const { return scriptSource()->filename(); }
maybeForwardedFilename()1644 const char* maybeForwardedFilename() const { return maybeForwardedScriptSource()->filename(); }
1645
1646 public:
1647
1648 /* Return whether this script was compiled for 'eval' */
isForEval()1649 bool isForEval() { return isCachedEval() || isActiveEval(); }
1650
1651 /*
1652 * Return whether this script is a top-level script.
1653 *
1654 * If we evaluate some code which contains a syntax error, then we might
1655 * produce a JSScript which has no associated bytecode. Testing with
1656 * |code()| filters out this kind of scripts.
1657 *
1658 * If this script has a function associated to it, then it is not the
1659 * top-level of a file.
1660 */
isTopLevel()1661 bool isTopLevel() { return code() && !functionNonDelazifying(); }
1662
1663 /* Ensure the script has a TypeScript. */
1664 inline bool ensureHasTypes(JSContext* cx);
1665
1666 inline js::TypeScript* types();
1667
1668 void maybeSweepTypes(js::AutoClearTypeInferenceStateOnOOM* oom);
1669
1670 inline js::GlobalObject& global() const;
1671 js::GlobalObject& uninlinedGlobal() const;
1672
1673 /* See StaticScopeIter comment. */
enclosingStaticScope()1674 JSObject* enclosingStaticScope() const {
1675 return enclosingStaticScope_;
1676 }
1677
1678 // Switch the script over from the off-thread compartment's static
1679 // global lexical scope to the main thread compartment's.
1680 void fixEnclosingStaticGlobalLexicalScope();
1681
1682 private:
1683 bool makeTypes(JSContext* cx);
1684
1685 public:
getWarmUpCount()1686 uint32_t getWarmUpCount() const { return warmUpCount; }
1687 uint32_t incWarmUpCounter(uint32_t amount = 1) { return warmUpCount += amount; }
addressOfWarmUpCounter()1688 uint32_t* addressOfWarmUpCounter() { return &warmUpCount; }
offsetOfWarmUpCounter()1689 static size_t offsetOfWarmUpCounter() { return offsetof(JSScript, warmUpCount); }
resetWarmUpCounter()1690 void resetWarmUpCounter() { incWarmUpResetCounter(); warmUpCount = 0; }
1691
getWarmUpResetCount()1692 uint16_t getWarmUpResetCount() const { return warmUpResetCount; }
1693 uint16_t incWarmUpResetCounter(uint16_t amount = 1) { return warmUpResetCount += amount; }
resetWarmUpResetCounter()1694 void resetWarmUpResetCounter() { warmUpResetCount = 0; }
1695
1696 public:
1697 bool initScriptCounts(JSContext* cx);
1698 js::ScriptCounts& getScriptCounts();
1699 js::PCCounts* maybeGetPCCounts(jsbytecode* pc);
1700 const js::PCCounts* maybeGetThrowCounts(jsbytecode* pc);
1701 js::PCCounts* getThrowCounts(jsbytecode* pc);
1702 uint64_t getHitCount(jsbytecode* pc);
1703 void incHitCount(jsbytecode* pc); // Used when we bailout out of Ion.
1704 void addIonCounts(js::jit::IonScriptCounts* ionCounts);
1705 js::jit::IonScriptCounts* getIonCounts();
1706 void releaseScriptCounts(js::ScriptCounts* counts);
1707 void destroyScriptCounts(js::FreeOp* fop);
1708 // The entry should be removed after using this function.
1709 void takeOverScriptCountsMapEntry(js::ScriptCounts* entryValue);
1710
main()1711 jsbytecode* main() {
1712 return code() + mainOffset();
1713 }
1714
1715 /*
1716 * computedSizeOfData() is the in-use size of all the data sections.
1717 * sizeOfData() is the size of the block allocated to hold all the data
1718 * sections (which can be larger than the in-use size).
1719 */
1720 size_t computedSizeOfData() const;
1721 size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const;
1722 size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
1723
1724 uint32_t numNotes(); /* Number of srcnote slots in the srcnotes section */
1725
1726 /* Script notes are allocated right after the code. */
notes()1727 jssrcnote* notes() { return (jssrcnote*)(code() + length()); }
1728
hasArray(ArrayKind kind)1729 bool hasArray(ArrayKind kind) {
1730 return hasArrayBits & (1 << kind);
1731 }
setHasArray(ArrayKind kind)1732 void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
cloneHasArray(JSScript * script)1733 void cloneHasArray(JSScript* script) { hasArrayBits = script->hasArrayBits; }
1734
hasConsts()1735 bool hasConsts() { return hasArray(CONSTS); }
hasObjects()1736 bool hasObjects() { return hasArray(OBJECTS); }
hasRegexps()1737 bool hasRegexps() { return hasArray(REGEXPS); }
hasTrynotes()1738 bool hasTrynotes() { return hasArray(TRYNOTES); }
hasBlockScopes()1739 bool hasBlockScopes() { return hasArray(BLOCK_SCOPES); }
hasYieldOffsets()1740 bool hasYieldOffsets() { return isGenerator(); }
1741
1742 #define OFF(fooOff, hasFoo, t) (fooOff() + (hasFoo() ? sizeof(t) : 0))
1743
constsOffset()1744 size_t constsOffset() { return 0; }
objectsOffset()1745 size_t objectsOffset() { return OFF(constsOffset, hasConsts, js::ConstArray); }
regexpsOffset()1746 size_t regexpsOffset() { return OFF(objectsOffset, hasObjects, js::ObjectArray); }
trynotesOffset()1747 size_t trynotesOffset() { return OFF(regexpsOffset, hasRegexps, js::ObjectArray); }
blockScopesOffset()1748 size_t blockScopesOffset() { return OFF(trynotesOffset, hasTrynotes, js::TryNoteArray); }
yieldOffsetsOffset()1749 size_t yieldOffsetsOffset() { return OFF(blockScopesOffset, hasBlockScopes, js::BlockScopeArray); }
1750
dataSize()1751 size_t dataSize() const { return dataSize_; }
1752
consts()1753 js::ConstArray* consts() {
1754 MOZ_ASSERT(hasConsts());
1755 return reinterpret_cast<js::ConstArray*>(data + constsOffset());
1756 }
1757
objects()1758 js::ObjectArray* objects() {
1759 MOZ_ASSERT(hasObjects());
1760 return reinterpret_cast<js::ObjectArray*>(data + objectsOffset());
1761 }
1762
regexps()1763 js::ObjectArray* regexps() {
1764 MOZ_ASSERT(hasRegexps());
1765 return reinterpret_cast<js::ObjectArray*>(data + regexpsOffset());
1766 }
1767
trynotes()1768 js::TryNoteArray* trynotes() {
1769 MOZ_ASSERT(hasTrynotes());
1770 return reinterpret_cast<js::TryNoteArray*>(data + trynotesOffset());
1771 }
1772
blockScopes()1773 js::BlockScopeArray* blockScopes() {
1774 MOZ_ASSERT(hasBlockScopes());
1775 return reinterpret_cast<js::BlockScopeArray*>(data + blockScopesOffset());
1776 }
1777
yieldOffsets()1778 js::YieldOffsetArray& yieldOffsets() {
1779 MOZ_ASSERT(hasYieldOffsets());
1780 return *reinterpret_cast<js::YieldOffsetArray*>(data + yieldOffsetsOffset());
1781 }
1782
1783 bool hasLoops();
1784
natoms()1785 size_t natoms() const { return natoms_; }
1786
getAtom(size_t index)1787 js::HeapPtrAtom& getAtom(size_t index) const {
1788 MOZ_ASSERT(index < natoms());
1789 return atoms[index];
1790 }
1791
getAtom(jsbytecode * pc)1792 js::HeapPtrAtom& getAtom(jsbytecode* pc) const {
1793 MOZ_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
1794 return getAtom(GET_UINT32_INDEX(pc));
1795 }
1796
getName(size_t index)1797 js::PropertyName* getName(size_t index) {
1798 return getAtom(index)->asPropertyName();
1799 }
1800
getName(jsbytecode * pc)1801 js::PropertyName* getName(jsbytecode* pc) const {
1802 MOZ_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
1803 return getAtom(GET_UINT32_INDEX(pc))->asPropertyName();
1804 }
1805
getObject(size_t index)1806 JSObject* getObject(size_t index) {
1807 js::ObjectArray* arr = objects();
1808 MOZ_ASSERT(index < arr->length);
1809 MOZ_ASSERT(arr->vector[index]->isTenured());
1810 return arr->vector[index];
1811 }
1812
innerObjectsStart()1813 size_t innerObjectsStart() {
1814 // The first object contains the caller if savedCallerFun is used.
1815 return savedCallerFun() ? 1 : 0;
1816 }
1817
getObject(jsbytecode * pc)1818 JSObject* getObject(jsbytecode* pc) {
1819 MOZ_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
1820 return getObject(GET_UINT32_INDEX(pc));
1821 }
1822
getVersion()1823 JSVersion getVersion() const {
1824 return JSVersion(version);
1825 }
1826
1827 inline JSFunction* getFunction(size_t index);
1828 inline JSFunction* getCallerFunction();
1829 inline JSFunction* functionOrCallerFunction();
1830
1831 inline js::RegExpObject* getRegExp(size_t index);
1832 inline js::RegExpObject* getRegExp(jsbytecode* pc);
1833
getConst(size_t index)1834 const js::Value& getConst(size_t index) {
1835 js::ConstArray* arr = consts();
1836 MOZ_ASSERT(index < arr->length);
1837 return arr->vector[index];
1838 }
1839
1840 // The following 4 functions find the static scope just before the
1841 // execution of the instruction pointed to by pc.
1842
1843 js::NestedScopeObject* getStaticBlockScope(jsbytecode* pc);
1844
1845 // Returns the innermost static scope at pc if it falls within the extent
1846 // of the script. Returns nullptr otherwise.
1847 JSObject* innermostStaticScopeInScript(jsbytecode* pc);
1848
1849 // As innermostStaticScopeInScript, but returns the enclosing static scope
1850 // if the innermost static scope falls without the extent of the script.
1851 JSObject* innermostStaticScope(jsbytecode* pc);
1852
innermostStaticScope()1853 JSObject* innermostStaticScope() { return innermostStaticScope(main()); }
1854
1855 /*
1856 * The isEmpty method tells whether this script has code that computes any
1857 * result (not return value, result AKA normal completion value) other than
1858 * JSVAL_VOID, or any other effects.
1859 */
isEmpty()1860 bool isEmpty() const {
1861 if (length() > 3)
1862 return false;
1863
1864 jsbytecode* pc = code();
1865 if (noScriptRval() && JSOp(*pc) == JSOP_FALSE)
1866 ++pc;
1867 return JSOp(*pc) == JSOP_RETRVAL;
1868 }
1869
1870 bool bindingIsAliased(const js::BindingIter& bi);
1871 bool formalIsAliased(unsigned argSlot);
1872 bool formalLivesInArgumentsObject(unsigned argSlot);
1873 bool localIsAliased(unsigned localSlot);
1874
1875 private:
1876 /* Change this->stepMode to |newValue|. */
1877 void setNewStepMode(js::FreeOp* fop, uint32_t newValue);
1878
1879 bool ensureHasDebugScript(JSContext* cx);
1880 js::DebugScript* debugScript();
1881 js::DebugScript* releaseDebugScript();
1882 void destroyDebugScript(js::FreeOp* fop);
1883
1884 public:
1885 bool hasBreakpointsAt(jsbytecode* pc);
hasAnyBreakpointsOrStepMode()1886 bool hasAnyBreakpointsOrStepMode() { return hasDebugScript_; }
1887
1888 // See comment above 'debugMode' in jscompartment.h for explanation of
1889 // invariants of debuggee compartments, scripts, and frames.
1890 inline bool isDebuggee() const;
1891
getBreakpointSite(jsbytecode * pc)1892 js::BreakpointSite* getBreakpointSite(jsbytecode* pc)
1893 {
1894 return hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
1895 }
1896
1897 js::BreakpointSite* getOrCreateBreakpointSite(JSContext* cx, jsbytecode* pc);
1898
1899 void destroyBreakpointSite(js::FreeOp* fop, jsbytecode* pc);
1900
1901 void clearBreakpointsIn(js::FreeOp* fop, js::Debugger* dbg, JSObject* handler);
1902
1903 /*
1904 * Increment or decrement the single-step count. If the count is non-zero
1905 * then the script is in single-step mode.
1906 *
1907 * Only incrementing is fallible, as it could allocate a DebugScript.
1908 */
1909 bool incrementStepModeCount(JSContext* cx);
1910 void decrementStepModeCount(js::FreeOp* fop);
1911
stepModeEnabled()1912 bool stepModeEnabled() { return hasDebugScript_ && !!debugScript()->stepMode; }
1913
1914 #ifdef DEBUG
stepModeCount()1915 uint32_t stepModeCount() { return hasDebugScript_ ? debugScript()->stepMode : 0; }
1916 #endif
1917
1918 void finalize(js::FreeOp* fop);
fixupAfterMovingGC()1919 void fixupAfterMovingGC() {}
1920
rootKind()1921 static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SCRIPT; }
1922
1923 void traceChildren(JSTracer* trc);
1924
1925 // A helper class to prevent relazification of the given function's script
1926 // while it's holding on to it. This class automatically roots the script.
1927 class AutoDelazify;
1928 friend class AutoDelazify;
1929
1930 class AutoDelazify
1931 {
1932 JS::RootedScript script_;
1933 JSContext* cx_;
1934 bool oldDoNotRelazify_;
1935 public:
1936 explicit AutoDelazify(JSContext* cx, JS::HandleFunction fun = nullptr)
script_(cx)1937 : script_(cx)
1938 , cx_(cx)
1939 {
1940 holdScript(fun);
1941 }
1942
~AutoDelazify()1943 ~AutoDelazify()
1944 {
1945 dropScript();
1946 }
1947
1948 void operator=(JS::HandleFunction fun)
1949 {
1950 dropScript();
1951 holdScript(fun);
1952 }
1953
HandleScript()1954 operator JS::HandleScript() const { return script_; }
1955 explicit operator bool() const { return script_; }
1956
1957 private:
1958 void holdScript(JS::HandleFunction fun);
1959 void dropScript();
1960 };
1961 };
1962
1963 /* If this fails, add/remove padding within JSScript. */
1964 static_assert(sizeof(JSScript) % js::gc::CellSize == 0,
1965 "Size of JSScript must be an integral multiple of js::gc::CellSize");
1966
1967 namespace js {
1968
1969 /*
1970 * Iterator over a script's bindings (formals and variables).
1971 * The order of iteration is:
1972 * - first, formal arguments, from index 0 to numArgs
1973 * - next, variables, from index 0 to numLocals
1974 */
1975 class BindingIter
1976 {
1977 Handle<Bindings> bindings_;
1978 uint32_t i_;
1979 uint32_t unaliasedLocal_;
1980
1981 friend class ::JSScript;
1982 friend class Bindings;
1983
1984 public:
BindingIter(Handle<Bindings> bindings)1985 explicit BindingIter(Handle<Bindings> bindings)
1986 : bindings_(bindings), i_(0), unaliasedLocal_(0)
1987 {}
1988
BindingIter(const HandleScript & script)1989 explicit BindingIter(const HandleScript& script)
1990 : bindings_(Handle<Bindings>::fromMarkedLocation(&script->bindings)),
1991 i_(0), unaliasedLocal_(0)
1992 {}
1993
done()1994 bool done() const { return i_ == bindings_.count(); }
1995 explicit operator bool() const { return !done(); }
1996 BindingIter& operator++() { (*this)++; return *this; }
1997
1998 void operator++(int) {
1999 MOZ_ASSERT(!done());
2000 const Binding& binding = **this;
2001 if (binding.kind() != Binding::ARGUMENT && !binding.aliased())
2002 unaliasedLocal_++;
2003 i_++;
2004 }
2005
2006 // Stack slots are assigned to arguments (aliased and unaliased) and
2007 // unaliased locals. frameIndex() returns the slot index. It's invalid to
2008 // call this method when the iterator is stopped on an aliased local, as it
2009 // has no stack slot.
frameIndex()2010 uint32_t frameIndex() const {
2011 MOZ_ASSERT(!done());
2012 if (i_ < bindings_.numArgs())
2013 return i_;
2014 MOZ_ASSERT(!(*this)->aliased());
2015 return unaliasedLocal_;
2016 }
2017
2018 // If the current binding is an argument, argIndex() returns its index.
2019 // It returns the same value as frameIndex(), as slots are allocated for
2020 // both unaliased and aliased arguments.
argIndex()2021 uint32_t argIndex() const {
2022 MOZ_ASSERT(!done());
2023 MOZ_ASSERT(i_ < bindings_.numArgs());
2024 return i_;
2025 }
argOrLocalIndex()2026 uint32_t argOrLocalIndex() const {
2027 MOZ_ASSERT(!done());
2028 return i_ < bindings_.numArgs() ? i_ : i_ - bindings_.numArgs();
2029 }
localIndex()2030 uint32_t localIndex() const {
2031 MOZ_ASSERT(!done());
2032 MOZ_ASSERT(i_ >= bindings_.numArgs());
2033 return i_ - bindings_.numArgs();
2034 }
isBodyLevelLexical()2035 bool isBodyLevelLexical() const {
2036 MOZ_ASSERT(!done());
2037 const Binding& binding = **this;
2038 return binding.kind() != Binding::ARGUMENT;
2039 }
2040
2041 const Binding& operator*() const { MOZ_ASSERT(!done()); return bindings_.bindingArray()[i_]; }
2042 const Binding* operator->() const { MOZ_ASSERT(!done()); return &bindings_.bindingArray()[i_]; }
2043 };
2044
2045 /*
2046 * Iterator over the aliased formal bindings in ascending index order. This can
2047 * be veiwed as a filtering of BindingIter with predicate
2048 * bi->aliased() && bi->kind() == Binding::ARGUMENT
2049 */
2050 class AliasedFormalIter
2051 {
2052 const Binding* begin_;
2053 const Binding* p_;
2054 const Binding* end_;
2055 unsigned slot_;
2056
settle()2057 void settle() {
2058 while (p_ != end_ && !p_->aliased())
2059 p_++;
2060 }
2061
2062 public:
2063 explicit inline AliasedFormalIter(JSScript* script);
2064
done()2065 bool done() const { return p_ == end_; }
2066 explicit operator bool() const { return !done(); }
2067 void operator++(int) { MOZ_ASSERT(!done()); p_++; slot_++; settle(); }
2068
2069 const Binding& operator*() const { MOZ_ASSERT(!done()); return *p_; }
2070 const Binding* operator->() const { MOZ_ASSERT(!done()); return p_; }
frameIndex()2071 unsigned frameIndex() const { MOZ_ASSERT(!done()); return p_ - begin_; }
scopeSlot()2072 unsigned scopeSlot() const { MOZ_ASSERT(!done()); return slot_; }
2073 };
2074
2075 // Information about a script which may be (or has been) lazily compiled to
2076 // bytecode from its source.
2077 class LazyScript : public gc::TenuredCell
2078 {
2079 public:
2080 class FreeVariable
2081 {
2082 // Variable name is stored as a tagged JSAtom pointer.
2083 uintptr_t bits_;
2084
2085 static const uintptr_t HOISTED_USE_BIT = 0x1;
2086 static const uintptr_t MASK = ~HOISTED_USE_BIT;
2087
2088 public:
FreeVariable()2089 explicit FreeVariable()
2090 : bits_(0)
2091 { }
2092
FreeVariable(JSAtom * name)2093 explicit FreeVariable(JSAtom* name)
2094 : bits_(uintptr_t(name))
2095 {
2096 // We rely on not requiring any write barriers so we can tag the
2097 // pointer. This code needs to change if we start allocating
2098 // JSAtoms inside the nursery.
2099 MOZ_ASSERT(!IsInsideNursery(name));
2100 }
2101
atom()2102 JSAtom* atom() const { return (JSAtom*)(bits_ & MASK); }
setIsHoistedUse()2103 void setIsHoistedUse() { bits_ |= HOISTED_USE_BIT; }
isHoistedUse()2104 bool isHoistedUse() const { return bool(bits_ & HOISTED_USE_BIT); }
2105 };
2106
2107 private:
2108 // If non-nullptr, the script has been compiled and this is a forwarding
2109 // pointer to the result. This is a weak pointer: after relazification, we
2110 // can collect the script if there are no other pointers to it.
2111 WeakRef<JSScript*> script_;
2112
2113 // Original function with which the lazy script is associated.
2114 HeapPtrFunction function_;
2115
2116 // Function or block chain in which the script is nested, or nullptr.
2117 HeapPtrObject enclosingScope_;
2118
2119 // ScriptSourceObject, or nullptr if the script in which this is nested
2120 // has not been compiled yet. This is never a CCW; we don't clone
2121 // LazyScripts into other compartments.
2122 HeapPtrObject sourceObject_;
2123
2124 // Heap allocated table with any free variables or inner functions.
2125 void* table_;
2126
2127 // Add padding so LazyScript is gc::Cell aligned. Make padding protected
2128 // instead of private to suppress -Wunused-private-field compiler warnings.
2129 protected:
2130 #if JS_BITS_PER_WORD == 32
2131 uint32_t padding;
2132 #endif
2133 private:
2134
2135 struct PackedView {
2136 // Assorted bits that should really be in ScriptSourceObject.
2137 uint32_t version : 8;
2138
2139 uint32_t numFreeVariables : 24;
2140 uint32_t numInnerFunctions : 20;
2141
2142 uint32_t generatorKindBits : 2;
2143
2144 // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
2145 // If you add another boolean here, make sure to initialze it in
2146 // LazyScript::CreateRaw().
2147 uint32_t strict : 1;
2148 uint32_t bindingsAccessedDynamically : 1;
2149 uint32_t hasDebuggerStatement : 1;
2150 uint32_t hasDirectEval : 1;
2151 uint32_t isLikelyConstructorWrapper : 1;
2152 uint32_t hasBeenCloned : 1;
2153 uint32_t treatAsRunOnce : 1;
2154 uint32_t isDerivedClassConstructor : 1;
2155 uint32_t needsHomeObject : 1;
2156 };
2157
2158 union {
2159 PackedView p_;
2160 uint64_t packedFields_;
2161 };
2162
2163 // Source location for the script.
2164 uint32_t begin_;
2165 uint32_t end_;
2166 uint32_t lineno_;
2167 uint32_t column_;
2168
2169 LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
2170 uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column);
2171
2172 // Create a LazyScript without initializing the freeVariables and the
2173 // innerFunctions. To be GC-safe, the caller must initialize both vectors
2174 // with valid atoms and functions.
2175 static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun,
2176 uint64_t packedData, uint32_t begin, uint32_t end,
2177 uint32_t lineno, uint32_t column);
2178
2179 public:
2180 // Create a LazyScript without initializing the freeVariables and the
2181 // innerFunctions. To be GC-safe, the caller must initialize both vectors
2182 // with valid atoms and functions.
2183 static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun,
2184 uint32_t numFreeVariables, uint32_t numInnerFunctions,
2185 JSVersion version, uint32_t begin, uint32_t end,
2186 uint32_t lineno, uint32_t column);
2187
2188 // Create a LazyScript and initialize the freeVariables and the
2189 // innerFunctions with dummy values to be replaced in a later initialization
2190 // phase.
2191 //
2192 // The "script" argument to this function can be null. If it's non-null,
2193 // then this LazyScript should be associated with the given JSScript.
2194 //
2195 // The sourceObjectScript argument must be non-null and is the script that
2196 // should be used to get the sourceObject_ of this lazyScript.
2197 static LazyScript* Create(ExclusiveContext* cx, HandleFunction fun,
2198 HandleScript script, HandleObject enclosingScope,
2199 HandleScript sourceObjectScript,
2200 uint64_t packedData, uint32_t begin, uint32_t end,
2201 uint32_t lineno, uint32_t column);
2202
2203 void initRuntimeFields(uint64_t packedFields);
2204
2205 inline JSFunction* functionDelazifying(JSContext* cx) const;
functionNonDelazifying()2206 JSFunction* functionNonDelazifying() const {
2207 return function_;
2208 }
2209
2210 void initScript(JSScript* script);
2211 void resetScript();
2212
maybeScript()2213 JSScript* maybeScript() {
2214 return script_;
2215 }
maybeScriptUnbarriered()2216 const JSScript* maybeScriptUnbarriered() const {
2217 return script_.unbarrieredGet();
2218 }
hasScript()2219 bool hasScript() const {
2220 return bool(script_);
2221 }
2222
enclosingScope()2223 JSObject* enclosingScope() const {
2224 return enclosingScope_;
2225 }
2226
2227 // Switch the script over from the off-thread compartment's static
2228 // global lexical scope to the main thread compartment's.
2229 void fixEnclosingStaticGlobalLexicalScope();
2230
2231 ScriptSourceObject* sourceObject() const;
scriptSource()2232 ScriptSource* scriptSource() const {
2233 return sourceObject()->source();
2234 }
2235 ScriptSource* maybeForwardedScriptSource() const;
mutedErrors()2236 bool mutedErrors() const {
2237 return scriptSource()->mutedErrors();
2238 }
version()2239 JSVersion version() const {
2240 JS_STATIC_ASSERT(JSVERSION_UNKNOWN == -1);
2241 return (p_.version == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(p_.version);
2242 }
2243
2244 void setParent(JSObject* enclosingScope, ScriptSourceObject* sourceObject);
2245
numFreeVariables()2246 uint32_t numFreeVariables() const {
2247 return p_.numFreeVariables;
2248 }
freeVariables()2249 FreeVariable* freeVariables() {
2250 return (FreeVariable*)table_;
2251 }
2252
numInnerFunctions()2253 uint32_t numInnerFunctions() const {
2254 return p_.numInnerFunctions;
2255 }
innerFunctions()2256 HeapPtrFunction* innerFunctions() {
2257 return (HeapPtrFunction*)&freeVariables()[numFreeVariables()];
2258 }
2259
generatorKind()2260 GeneratorKind generatorKind() const { return GeneratorKindFromBits(p_.generatorKindBits); }
2261
isGenerator()2262 bool isGenerator() const { return generatorKind() != NotGenerator; }
2263
isLegacyGenerator()2264 bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
2265
isStarGenerator()2266 bool isStarGenerator() const { return generatorKind() == StarGenerator; }
2267
setGeneratorKind(GeneratorKind kind)2268 void setGeneratorKind(GeneratorKind kind) {
2269 // A script only gets its generator kind set as part of initialization,
2270 // so it can only transition from NotGenerator.
2271 MOZ_ASSERT(!isGenerator());
2272 // Legacy generators cannot currently be lazy.
2273 MOZ_ASSERT(kind != LegacyGenerator);
2274 p_.generatorKindBits = GeneratorKindAsBits(kind);
2275 }
2276
strict()2277 bool strict() const {
2278 return p_.strict;
2279 }
setStrict()2280 void setStrict() {
2281 p_.strict = true;
2282 }
2283
bindingsAccessedDynamically()2284 bool bindingsAccessedDynamically() const {
2285 return p_.bindingsAccessedDynamically;
2286 }
setBindingsAccessedDynamically()2287 void setBindingsAccessedDynamically() {
2288 p_.bindingsAccessedDynamically = true;
2289 }
2290
hasDebuggerStatement()2291 bool hasDebuggerStatement() const {
2292 return p_.hasDebuggerStatement;
2293 }
setHasDebuggerStatement()2294 void setHasDebuggerStatement() {
2295 p_.hasDebuggerStatement = true;
2296 }
2297
hasDirectEval()2298 bool hasDirectEval() const {
2299 return p_.hasDirectEval;
2300 }
setHasDirectEval()2301 void setHasDirectEval() {
2302 p_.hasDirectEval = true;
2303 }
2304
isLikelyConstructorWrapper()2305 bool isLikelyConstructorWrapper() const {
2306 return p_.isLikelyConstructorWrapper;
2307 }
setLikelyConstructorWrapper()2308 void setLikelyConstructorWrapper() {
2309 p_.isLikelyConstructorWrapper = true;
2310 }
2311
hasBeenCloned()2312 bool hasBeenCloned() const {
2313 return p_.hasBeenCloned;
2314 }
setHasBeenCloned()2315 void setHasBeenCloned() {
2316 p_.hasBeenCloned = true;
2317 }
2318
treatAsRunOnce()2319 bool treatAsRunOnce() const {
2320 return p_.treatAsRunOnce;
2321 }
setTreatAsRunOnce()2322 void setTreatAsRunOnce() {
2323 p_.treatAsRunOnce = true;
2324 }
2325
isDerivedClassConstructor()2326 bool isDerivedClassConstructor() const {
2327 return p_.isDerivedClassConstructor;
2328 }
setIsDerivedClassConstructor()2329 void setIsDerivedClassConstructor() {
2330 p_.isDerivedClassConstructor = true;
2331 }
2332
needsHomeObject()2333 bool needsHomeObject() const {
2334 return p_.needsHomeObject;
2335 }
setNeedsHomeObject()2336 void setNeedsHomeObject() {
2337 p_.needsHomeObject = true;
2338 }
2339
filename()2340 const char* filename() const {
2341 return scriptSource()->filename();
2342 }
begin()2343 uint32_t begin() const {
2344 return begin_;
2345 }
end()2346 uint32_t end() const {
2347 return end_;
2348 }
lineno()2349 uint32_t lineno() const {
2350 return lineno_;
2351 }
column()2352 uint32_t column() const {
2353 return column_;
2354 }
2355
2356 bool hasUncompiledEnclosingScript() const;
2357
2358 friend class GCMarker;
2359 void traceChildren(JSTracer* trc);
2360 void finalize(js::FreeOp* fop);
fixupAfterMovingGC()2361 void fixupAfterMovingGC() {}
2362
rootKind()2363 static inline js::ThingRootKind rootKind() { return js::THING_ROOT_LAZY_SCRIPT; }
2364
sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)2365 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
2366 {
2367 return mallocSizeOf(table_);
2368 }
2369
packedFields()2370 uint64_t packedFields() const {
2371 return packedFields_;
2372 }
2373 };
2374
2375 /* If this fails, add/remove padding within LazyScript. */
2376 JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0);
2377
2378 struct SharedScriptData
2379 {
2380 uint32_t length;
2381 uint32_t natoms;
2382 mozilla::Atomic<bool, mozilla::ReleaseAcquire> marked;
2383 jsbytecode data[1];
2384
2385 static SharedScriptData* new_(ExclusiveContext* cx, uint32_t codeLength,
2386 uint32_t srcnotesLength, uint32_t natoms);
2387
atomsSharedScriptData2388 HeapPtrAtom* atoms() {
2389 if (!natoms)
2390 return nullptr;
2391 return reinterpret_cast<HeapPtrAtom*>(data + length - sizeof(JSAtom*) * natoms);
2392 }
2393
fromBytecodeSharedScriptData2394 static SharedScriptData* fromBytecode(const jsbytecode* bytecode) {
2395 return (SharedScriptData*)(bytecode - offsetof(SharedScriptData, data));
2396 }
2397
2398 private:
2399 SharedScriptData() = delete;
2400 SharedScriptData(const SharedScriptData&) = delete;
2401 };
2402
2403 struct ScriptBytecodeHasher
2404 {
2405 struct Lookup
2406 {
2407 jsbytecode* code;
2408 uint32_t length;
2409
LookupScriptBytecodeHasher::Lookup2410 explicit Lookup(SharedScriptData* ssd) : code(ssd->data), length(ssd->length) {}
2411 };
hashScriptBytecodeHasher2412 static HashNumber hash(const Lookup& l) { return mozilla::HashBytes(l.code, l.length); }
matchScriptBytecodeHasher2413 static bool match(SharedScriptData* entry, const Lookup& lookup) {
2414 if (entry->length != lookup.length)
2415 return false;
2416 return mozilla::PodEqual<jsbytecode>(entry->data, lookup.code, lookup.length);
2417 }
2418 };
2419
2420 typedef HashSet<SharedScriptData*,
2421 ScriptBytecodeHasher,
2422 SystemAllocPolicy> ScriptDataTable;
2423
2424 extern void
2425 UnmarkScriptData(JSRuntime* rt);
2426
2427 extern void
2428 SweepScriptData(JSRuntime* rt);
2429
2430 extern void
2431 FreeScriptData(JSRuntime* rt);
2432
2433 struct ScriptAndCounts
2434 {
2435 /* This structure is stored and marked from the JSRuntime. */
2436 JSScript* script;
2437 ScriptCounts scriptCounts;
2438
2439 inline explicit ScriptAndCounts(JSScript* script);
2440 inline ScriptAndCounts(ScriptAndCounts&& sac);
2441
maybeGetPCCountsScriptAndCounts2442 const PCCounts* maybeGetPCCounts(jsbytecode* pc) const {
2443 return scriptCounts.maybeGetPCCounts(script->pcToOffset(pc));
2444 }
maybeGetThrowCountsScriptAndCounts2445 const PCCounts* maybeGetThrowCounts(jsbytecode* pc) const {
2446 return scriptCounts.maybeGetThrowCounts(script->pcToOffset(pc));
2447 }
2448
getIonCountsScriptAndCounts2449 jit::IonScriptCounts* getIonCounts() const {
2450 return scriptCounts.ionCounts_;
2451 }
2452
traceScriptAndCounts2453 void trace(JSTracer* trc) {
2454 TraceRoot(trc, &script, "ScriptAndCounts::script");
2455 }
2456 };
2457
2458 struct GSNCache;
2459
2460 jssrcnote*
2461 GetSrcNote(GSNCache& cache, JSScript* script, jsbytecode* pc);
2462
2463 extern jssrcnote*
2464 GetSrcNote(JSContext* cx, JSScript* script, jsbytecode* pc);
2465
2466 extern jsbytecode*
2467 LineNumberToPC(JSScript* script, unsigned lineno);
2468
2469 extern JS_FRIEND_API(unsigned)
2470 GetScriptLineExtent(JSScript* script);
2471
2472 } /* namespace js */
2473
2474 namespace js {
2475
2476 extern unsigned
2477 PCToLineNumber(JSScript* script, jsbytecode* pc, unsigned* columnp = nullptr);
2478
2479 extern unsigned
2480 PCToLineNumber(unsigned startLine, jssrcnote* notes, jsbytecode* code, jsbytecode* pc,
2481 unsigned* columnp = nullptr);
2482
2483 /*
2484 * This function returns the file and line number of the script currently
2485 * executing on cx. If there is no current script executing on cx (e.g., a
2486 * native called directly through JSAPI (e.g., by setTimeout)), nullptr and 0
2487 * are returned as the file and line. Additionally, this function avoids the
2488 * full linear scan to compute line number when the caller guarantees that the
2489 * script compilation occurs at a JSOP_EVAL/JSOP_SPREADEVAL.
2490 */
2491
2492 enum LineOption {
2493 CALLED_FROM_JSOP_EVAL,
2494 NOT_CALLED_FROM_JSOP_EVAL
2495 };
2496
2497 extern void
2498 DescribeScriptedCallerForCompilation(JSContext* cx, MutableHandleScript maybeScript,
2499 const char** file, unsigned* linenop,
2500 uint32_t* pcOffset, bool* mutedErrors,
2501 LineOption opt = NOT_CALLED_FROM_JSOP_EVAL);
2502
2503 JSScript*
2504 CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
2505 HandleScript src);
2506
2507 JSScript*
2508 CloneGlobalScript(JSContext* cx, Handle<ScopeObject*> enclosingScope, HandleScript src);
2509
2510 } /* namespace js */
2511
2512 // JS::ubi::Nodes can point to js::LazyScripts; they're js::gc::Cell instances
2513 // with no associated compartment.
2514 namespace JS {
2515 namespace ubi {
2516 template<>
2517 struct Concrete<js::LazyScript> : TracerConcrete<js::LazyScript> {
2518 CoarseType coarseType() const final { return CoarseType::Script; }
2519 Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
2520 const char* scriptFilename() const final;
2521
2522 protected:
2523 explicit Concrete(js::LazyScript *ptr) : TracerConcrete<js::LazyScript>(ptr) { }
2524
2525 public:
2526 static void construct(void *storage, js::LazyScript *ptr) { new (storage) Concrete(ptr); }
2527 };
2528 } // namespace ubi
2529 } // namespace JS
2530
2531 #endif /* jsscript_h */
2532