js/src/jsscript.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:054664877028
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&mdash;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 */

mercurial