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