We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / runtime / SymbolTable.h
1 /*
2  * Copyright (C) 2007, 2008, 2012-2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #pragma once
30
31 #include "ConcurrentJSLock.h"
32 #include "ConstantMode.h"
33 #include "InferredValue.h"
34 #include "JSObject.h"
35 #include "ScopedArgumentsTable.h"
36 #include "TypeLocation.h"
37 #include "VarOffset.h"
38 #include "Watchpoint.h"
39 #include <memory>
40 #include <wtf/HashTraits.h>
41 #include <wtf/text/UniquedStringImpl.h>
42
43 namespace JSC {
44
45 class SymbolTable;
46
47 static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); }
48
49 // The bit twiddling in this class assumes that every register index is a
50 // reasonably small positive or negative number, and therefore has its high
51 // four bits all set or all unset.
52
53 // In addition to implementing semantics-mandated variable attributes and
54 // implementation-mandated variable indexing, this class also implements
55 // watchpoints to be used for JIT optimizations. Because watchpoints are
56 // meant to be relatively rare, this class optimizes heavily for the case
57 // that they are not being used. To that end, this class uses the thin-fat
58 // idiom: either it is thin, in which case it contains an in-place encoded
59 // word that consists of attributes, the index, and a bit saying that it is
60 // thin; or it is fat, in which case it contains a pointer to a malloc'd
61 // data structure and a bit saying that it is fat. The malloc'd data
62 // structure will be malloced a second time upon copy, to preserve the
63 // property that in-place edits to SymbolTableEntry do not manifest in any
64 // copies. However, the malloc'd FatEntry data structure contains a ref-
65 // counted pointer to a shared WatchpointSet. Thus, in-place edits of the
66 // WatchpointSet will manifest in all copies. Here's a picture:
67 //
68 // SymbolTableEntry --> FatEntry --> WatchpointSet
69 //
70 // If you make a copy of a SymbolTableEntry, you will have:
71 //
72 // original: SymbolTableEntry --> FatEntry --> WatchpointSet
73 // copy:     SymbolTableEntry --> FatEntry -----^
74
75 struct SymbolTableEntry {
76 private:
77     static VarOffset varOffsetFromBits(intptr_t bits)
78     {
79         VarKind kind;
80         intptr_t kindBits = bits & KindBitsMask;
81         if (kindBits <= UnwatchableScopeKindBits)
82             kind = VarKind::Scope;
83         else if (kindBits == StackKindBits)
84             kind = VarKind::Stack;
85         else
86             kind = VarKind::DirectArgument;
87         return VarOffset::assemble(kind, static_cast<int>(bits >> FlagBits));
88     }
89     
90     static ScopeOffset scopeOffsetFromBits(intptr_t bits)
91     {
92         ASSERT((bits & KindBitsMask) <= UnwatchableScopeKindBits);
93         return ScopeOffset(static_cast<int>(bits >> FlagBits));
94     }
95
96 public:
97     
98     // Use the SymbolTableEntry::Fast class, either via implicit cast or by calling
99     // getFast(), when you (1) only care about isNull(), getIndex(), and isReadOnly(),
100     // and (2) you are in a hot path where you need to minimize the number of times
101     // that you branch on isFat() when getting the bits().
102     class Fast {
103     public:
104         Fast()
105             : m_bits(SlimFlag)
106         {
107         }
108         
109         ALWAYS_INLINE Fast(const SymbolTableEntry& entry)
110             : m_bits(entry.bits())
111         {
112         }
113     
114         bool isNull() const
115         {
116             return !(m_bits & ~SlimFlag);
117         }
118
119         VarOffset varOffset() const
120         {
121             return varOffsetFromBits(m_bits);
122         }
123         
124         // Asserts if the offset is anything but a scope offset. This structures the assertions
125         // in a way that may result in better code, even in release, than doing
126         // varOffset().scopeOffset().
127         ScopeOffset scopeOffset() const
128         {
129             return scopeOffsetFromBits(m_bits);
130         }
131         
132         bool isReadOnly() const
133         {
134             return m_bits & ReadOnlyFlag;
135         }
136         
137         bool isDontEnum() const
138         {
139             return m_bits & DontEnumFlag;
140         }
141         
142         unsigned getAttributes() const
143         {
144             unsigned attributes = 0;
145             if (isReadOnly())
146                 attributes |= PropertyAttribute::ReadOnly;
147             if (isDontEnum())
148                 attributes |= PropertyAttribute::DontEnum;
149             return attributes;
150         }
151
152         bool isFat() const
153         {
154             return !(m_bits & SlimFlag);
155         }
156         
157     private:
158         friend struct SymbolTableEntry;
159         intptr_t m_bits;
160     };
161
162     SymbolTableEntry()
163         : m_bits(SlimFlag)
164     {
165     }
166
167     SymbolTableEntry(VarOffset offset)
168         : m_bits(SlimFlag)
169     {
170         ASSERT(isValidVarOffset(offset));
171         pack(offset, true, false, false);
172     }
173
174     SymbolTableEntry(VarOffset offset, unsigned attributes)
175         : m_bits(SlimFlag)
176     {
177         ASSERT(isValidVarOffset(offset));
178         pack(offset, true, attributes & PropertyAttribute::ReadOnly, attributes & PropertyAttribute::DontEnum);
179     }
180     
181     ~SymbolTableEntry()
182     {
183         freeFatEntry();
184     }
185     
186     SymbolTableEntry(const SymbolTableEntry& other)
187         : m_bits(SlimFlag)
188     {
189         *this = other;
190     }
191     
192     SymbolTableEntry& operator=(const SymbolTableEntry& other)
193     {
194         if (UNLIKELY(other.isFat()))
195             return copySlow(other);
196         freeFatEntry();
197         m_bits = other.m_bits;
198         return *this;
199     }
200     
201     SymbolTableEntry(SymbolTableEntry&& other)
202         : m_bits(SlimFlag)
203     {
204         swap(other);
205     }
206
207     SymbolTableEntry& operator=(SymbolTableEntry&& other)
208     {
209         swap(other);
210         return *this;
211     }
212
213     void swap(SymbolTableEntry& other)
214     {
215         std::swap(m_bits, other.m_bits);
216     }
217
218     bool isNull() const
219     {
220         return !(bits() & ~SlimFlag);
221     }
222
223     VarOffset varOffset() const
224     {
225         return varOffsetFromBits(bits());
226     }
227     
228     bool isWatchable() const
229     {
230         return (m_bits & KindBitsMask) == ScopeKindBits;
231     }
232     
233     // Asserts if the offset is anything but a scope offset. This structures the assertions
234     // in a way that may result in better code, even in release, than doing
235     // varOffset().scopeOffset().
236     ScopeOffset scopeOffset() const
237     {
238         return scopeOffsetFromBits(bits());
239     }
240     
241     ALWAYS_INLINE Fast getFast() const
242     {
243         return Fast(*this);
244     }
245     
246     ALWAYS_INLINE Fast getFast(bool& wasFat) const
247     {
248         Fast result;
249         wasFat = isFat();
250         if (wasFat)
251             result.m_bits = fatEntry()->m_bits | SlimFlag;
252         else
253             result.m_bits = m_bits;
254         return result;
255     }
256     
257     unsigned getAttributes() const
258     {
259         return getFast().getAttributes();
260     }
261     
262     void setAttributes(unsigned attributes)
263     {
264         pack(varOffset(), isWatchable(), attributes & PropertyAttribute::ReadOnly, attributes & PropertyAttribute::DontEnum);
265     }
266
267     bool isReadOnly() const
268     {
269         return bits() & ReadOnlyFlag;
270     }
271     
272     ConstantMode constantMode() const
273     {
274         return modeForIsConstant(isReadOnly());
275     }
276     
277     bool isDontEnum() const
278     {
279         return bits() & DontEnumFlag;
280     }
281     
282     void disableWatching(VM& vm)
283     {
284         if (WatchpointSet* set = watchpointSet())
285             set->invalidate(vm, "Disabling watching in symbol table");
286         if (varOffset().isScope())
287             pack(varOffset(), false, isReadOnly(), isDontEnum());
288     }
289     
290     void prepareToWatch();
291     
292     void addWatchpoint(Watchpoint*);
293     
294     // This watchpoint set is initialized clear, and goes through the following state transitions:
295     // 
296     // First write to this var, in any scope that has this symbol table: Clear->IsWatched.
297     //
298     // Second write to this var, in any scope that has this symbol table: IsWatched->IsInvalidated.
299     //
300     // We ensure that we touch the set (i.e. trigger its state transition) after we do the write. This
301     // means that if you're in the compiler thread, and you:
302     //
303     // 1) Observe that the set IsWatched and commit to adding your watchpoint.
304     // 2) Load a value from any scope that has this watchpoint set.
305     //
306     // Then you can be sure that that value is either going to be the correct value for that var forever,
307     // or the watchpoint set will invalidate and you'll get fired.
308     //
309     // It's possible to write a program that first creates multiple scopes with the same var, and then
310     // initializes that var in just one of them. This means that a compilation could constant-fold to one
311     // of the scopes that still has an undefined value for this variable. That's fine, because at that
312     // point any write to any of the instances of that variable would fire the watchpoint.
313     WatchpointSet* watchpointSet()
314     {
315         if (!isFat())
316             return 0;
317         return fatEntry()->m_watchpoints.get();
318     }
319     
320 private:
321     static const intptr_t SlimFlag = 0x1;
322     static const intptr_t ReadOnlyFlag = 0x2;
323     static const intptr_t DontEnumFlag = 0x4;
324     static const intptr_t NotNullFlag = 0x8;
325     static const intptr_t KindBitsMask = 0x30;
326     static const intptr_t ScopeKindBits = 0x00;
327     static const intptr_t UnwatchableScopeKindBits = 0x10;
328     static const intptr_t StackKindBits = 0x20;
329     static const intptr_t DirectArgumentKindBits = 0x30;
330     static const intptr_t FlagBits = 6;
331     
332     class FatEntry {
333         WTF_MAKE_FAST_ALLOCATED;
334     public:
335         FatEntry(intptr_t bits)
336             : m_bits(bits & ~SlimFlag)
337         {
338         }
339         
340         intptr_t m_bits; // always has FatFlag set and exactly matches what the bits would have been if this wasn't fat.
341         
342         RefPtr<WatchpointSet> m_watchpoints;
343     };
344     
345     SymbolTableEntry& copySlow(const SymbolTableEntry&);
346     JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue, const FireDetail&);
347     
348     bool isFat() const
349     {
350         return !(m_bits & SlimFlag);
351     }
352     
353     const FatEntry* fatEntry() const
354     {
355         ASSERT(isFat());
356         return bitwise_cast<const FatEntry*>(m_bits);
357     }
358     
359     FatEntry* fatEntry()
360     {
361         ASSERT(isFat());
362         return bitwise_cast<FatEntry*>(m_bits);
363     }
364     
365     FatEntry* inflate()
366     {
367         if (LIKELY(isFat()))
368             return fatEntry();
369         return inflateSlow();
370     }
371     
372     FatEntry* inflateSlow();
373     
374     ALWAYS_INLINE intptr_t bits() const
375     {
376         if (isFat())
377             return fatEntry()->m_bits;
378         return m_bits;
379     }
380     
381     ALWAYS_INLINE intptr_t& bits()
382     {
383         if (isFat())
384             return fatEntry()->m_bits;
385         return m_bits;
386     }
387     
388     void freeFatEntry()
389     {
390         if (LIKELY(!isFat()))
391             return;
392         freeFatEntrySlow();
393     }
394
395     JS_EXPORT_PRIVATE void freeFatEntrySlow();
396
397     void pack(VarOffset offset, bool isWatchable, bool readOnly, bool dontEnum)
398     {
399         ASSERT(!isFat());
400         intptr_t& bitsRef = bits();
401         bitsRef =
402             (static_cast<intptr_t>(offset.rawOffset()) << FlagBits) | NotNullFlag | SlimFlag;
403         if (readOnly)
404             bitsRef |= ReadOnlyFlag;
405         if (dontEnum)
406             bitsRef |= DontEnumFlag;
407         switch (offset.kind()) {
408         case VarKind::Scope:
409             if (isWatchable)
410                 bitsRef |= ScopeKindBits;
411             else
412                 bitsRef |= UnwatchableScopeKindBits;
413             break;
414         case VarKind::Stack:
415             bitsRef |= StackKindBits;
416             break;
417         case VarKind::DirectArgument:
418             bitsRef |= DirectArgumentKindBits;
419             break;
420         default:
421             RELEASE_ASSERT_NOT_REACHED();
422             break;
423         }
424     }
425     
426     static bool isValidVarOffset(VarOffset offset)
427     {
428         return ((static_cast<intptr_t>(offset.rawOffset()) << FlagBits) >> FlagBits) == static_cast<intptr_t>(offset.rawOffset());
429     }
430
431     intptr_t m_bits;
432 };
433
434 struct SymbolTableIndexHashTraits : HashTraits<SymbolTableEntry> {
435     static const bool needsDestruction = true;
436 };
437
438 class SymbolTable final : public JSCell {
439 public:
440     typedef JSCell Base;
441     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
442
443     typedef HashMap<RefPtr<UniquedStringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, SymbolTableIndexHashTraits> Map;
444     typedef HashMap<RefPtr<UniquedStringImpl>, GlobalVariableID, IdentifierRepHash> UniqueIDMap;
445     typedef HashMap<RefPtr<UniquedStringImpl>, RefPtr<TypeSet>, IdentifierRepHash> UniqueTypeSetMap;
446     typedef HashMap<VarOffset, RefPtr<UniquedStringImpl>> OffsetToVariableMap;
447     typedef Vector<SymbolTableEntry*> LocalToEntryVec;
448
449     static SymbolTable* create(VM& vm)
450     {
451         SymbolTable* symbolTable = new (NotNull, allocateCell<SymbolTable>(vm.heap)) SymbolTable(vm);
452         symbolTable->finishCreation(vm);
453         return symbolTable;
454     }
455     
456     static const bool needsDestruction = true;
457     static void destroy(JSCell*);
458
459     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
460     {
461         return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
462     }
463
464     // You must hold the lock until after you're done with the iterator.
465     Map::iterator find(const ConcurrentJSLocker&, UniquedStringImpl* key)
466     {
467         return m_map.find(key);
468     }
469     
470     Map::iterator find(const GCSafeConcurrentJSLocker&, UniquedStringImpl* key)
471     {
472         return m_map.find(key);
473     }
474     
475     SymbolTableEntry get(const ConcurrentJSLocker&, UniquedStringImpl* key)
476     {
477         return m_map.get(key);
478     }
479     
480     SymbolTableEntry get(UniquedStringImpl* key)
481     {
482         ConcurrentJSLocker locker(m_lock);
483         return get(locker, key);
484     }
485     
486     SymbolTableEntry inlineGet(const ConcurrentJSLocker&, UniquedStringImpl* key)
487     {
488         return m_map.inlineGet(key);
489     }
490     
491     SymbolTableEntry inlineGet(UniquedStringImpl* key)
492     {
493         ConcurrentJSLocker locker(m_lock);
494         return inlineGet(locker, key);
495     }
496     
497     Map::iterator begin(const ConcurrentJSLocker&)
498     {
499         return m_map.begin();
500     }
501     
502     Map::iterator end(const ConcurrentJSLocker&)
503     {
504         return m_map.end();
505     }
506     
507     Map::iterator end(const GCSafeConcurrentJSLocker&)
508     {
509         return m_map.end();
510     }
511     
512     size_t size(const ConcurrentJSLocker&) const
513     {
514         return m_map.size();
515     }
516     
517     size_t size() const
518     {
519         ConcurrentJSLocker locker(m_lock);
520         return size(locker);
521     }
522     
523     ScopeOffset maxScopeOffset() const
524     {
525         return m_maxScopeOffset;
526     }
527     
528     void didUseScopeOffset(ScopeOffset offset)
529     {
530         if (!m_maxScopeOffset || m_maxScopeOffset < offset)
531             m_maxScopeOffset = offset;
532     }
533     
534     void didUseVarOffset(VarOffset offset)
535     {
536         if (offset.isScope())
537             didUseScopeOffset(offset.scopeOffset());
538     }
539     
540     unsigned scopeSize() const
541     {
542         ScopeOffset maxScopeOffset = this->maxScopeOffset();
543         
544         // Do some calculation that relies on invalid scope offset plus one being zero.
545         unsigned fastResult = maxScopeOffset.offsetUnchecked() + 1;
546         
547         // Assert that this works.
548         ASSERT(fastResult == (!maxScopeOffset ? 0 : maxScopeOffset.offset() + 1));
549         
550         return fastResult;
551     }
552     
553     ScopeOffset nextScopeOffset() const
554     {
555         return ScopeOffset(scopeSize());
556     }
557     
558     ScopeOffset takeNextScopeOffset(const ConcurrentJSLocker&)
559     {
560         ScopeOffset result = nextScopeOffset();
561         m_maxScopeOffset = result;
562         return result;
563     }
564     
565     ScopeOffset takeNextScopeOffset()
566     {
567         ConcurrentJSLocker locker(m_lock);
568         return takeNextScopeOffset(locker);
569     }
570     
571     template<typename Entry>
572     void add(const ConcurrentJSLocker&, UniquedStringImpl* key, Entry&& entry)
573     {
574         RELEASE_ASSERT(!m_localToEntry);
575         didUseVarOffset(entry.varOffset());
576         Map::AddResult result = m_map.add(key, std::forward<Entry>(entry));
577         ASSERT_UNUSED(result, result.isNewEntry);
578     }
579     
580     template<typename Entry>
581     void add(UniquedStringImpl* key, Entry&& entry)
582     {
583         ConcurrentJSLocker locker(m_lock);
584         add(locker, key, std::forward<Entry>(entry));
585     }
586     
587     template<typename Entry>
588     void set(const ConcurrentJSLocker&, UniquedStringImpl* key, Entry&& entry)
589     {
590         RELEASE_ASSERT(!m_localToEntry);
591         didUseVarOffset(entry.varOffset());
592         m_map.set(key, std::forward<Entry>(entry));
593     }
594     
595     template<typename Entry>
596     void set(UniquedStringImpl* key, Entry&& entry)
597     {
598         ConcurrentJSLocker locker(m_lock);
599         set(locker, key, std::forward<Entry>(entry));
600     }
601     
602     bool contains(const ConcurrentJSLocker&, UniquedStringImpl* key)
603     {
604         return m_map.contains(key);
605     }
606     
607     bool contains(UniquedStringImpl* key)
608     {
609         ConcurrentJSLocker locker(m_lock);
610         return contains(locker, key);
611     }
612     
613     // The principle behind ScopedArgumentsTable modifications is that we will create one and
614     // leave it unlocked - thereby allowing in-place changes - until someone asks for a pointer to
615     // the table. Then, we will lock it. Then both our future changes and their future changes
616     // will first have to make a copy. This discipline means that usually when we create a
617     // ScopedArguments object, we don't have to make a copy of the ScopedArgumentsTable - instead
618     // we just take a reference to one that we already have.
619     
620     uint32_t argumentsLength() const
621     {
622         if (!m_arguments)
623             return 0;
624         return m_arguments->length();
625     }
626     
627     void setArgumentsLength(VM& vm, uint32_t length)
628     {
629         if (UNLIKELY(!m_arguments))
630             m_arguments.set(vm, this, ScopedArgumentsTable::create(vm));
631         m_arguments.set(vm, this, m_arguments->setLength(vm, length));
632     }
633     
634     ScopeOffset argumentOffset(uint32_t i) const
635     {
636         ASSERT_WITH_SECURITY_IMPLICATION(m_arguments);
637         return m_arguments->get(i);
638     }
639     
640     void setArgumentOffset(VM& vm, uint32_t i, ScopeOffset offset)
641     {
642         ASSERT_WITH_SECURITY_IMPLICATION(m_arguments);
643         m_arguments.set(vm, this, m_arguments->set(vm, i, offset));
644     }
645     
646     ScopedArgumentsTable* arguments() const
647     {
648         if (!m_arguments)
649             return nullptr;
650         m_arguments->lock();
651         return m_arguments.get();
652     }
653     
654     const LocalToEntryVec& localToEntry(const ConcurrentJSLocker&);
655     SymbolTableEntry* entryFor(const ConcurrentJSLocker&, ScopeOffset);
656     
657     GlobalVariableID uniqueIDForVariable(const ConcurrentJSLocker&, UniquedStringImpl* key, VM&);
658     GlobalVariableID uniqueIDForOffset(const ConcurrentJSLocker&, VarOffset, VM&);
659     RefPtr<TypeSet> globalTypeSetForOffset(const ConcurrentJSLocker&, VarOffset, VM&);
660     RefPtr<TypeSet> globalTypeSetForVariable(const ConcurrentJSLocker&, UniquedStringImpl* key, VM&);
661
662     bool usesNonStrictEval() const { return m_usesNonStrictEval; }
663     void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; }
664
665     bool isNestedLexicalScope() const { return m_nestedLexicalScope; }
666     void markIsNestedLexicalScope() { ASSERT(scopeType() == LexicalScope); m_nestedLexicalScope = true; }
667
668     enum ScopeType {
669         VarScope,
670         GlobalLexicalScope,
671         LexicalScope,
672         CatchScope,
673         FunctionNameScope
674     };
675     void setScopeType(ScopeType type) { m_scopeType = type; }
676     ScopeType scopeType() const { return static_cast<ScopeType>(m_scopeType); }
677
678     SymbolTable* cloneScopePart(VM&);
679
680     void prepareForTypeProfiling(const ConcurrentJSLocker&);
681
682     CodeBlock* rareDataCodeBlock();
683     void setRareDataCodeBlock(CodeBlock*);
684     
685     InferredValue* singletonScope() { return m_singletonScope.get(); }
686
687     static void visitChildren(JSCell*, SlotVisitor&);
688
689     DECLARE_EXPORT_INFO;
690
691 private:
692     JS_EXPORT_PRIVATE SymbolTable(VM&);
693     ~SymbolTable();
694     
695     JS_EXPORT_PRIVATE void finishCreation(VM&);
696
697     Map m_map;
698     ScopeOffset m_maxScopeOffset;
699 public:
700     mutable ConcurrentJSLock m_lock;
701 private:
702     unsigned m_usesNonStrictEval : 1;
703     unsigned m_nestedLexicalScope : 1; // Non-function LexicalScope.
704     unsigned m_scopeType : 3; // ScopeType
705     
706     struct SymbolTableRareData {
707         UniqueIDMap m_uniqueIDMap;
708         OffsetToVariableMap m_offsetToVariableMap;
709         UniqueTypeSetMap m_uniqueTypeSetMap;
710         WriteBarrier<CodeBlock> m_codeBlock;
711     };
712     std::unique_ptr<SymbolTableRareData> m_rareData;
713
714     WriteBarrier<ScopedArgumentsTable> m_arguments;
715     WriteBarrier<InferredValue> m_singletonScope;
716     
717     std::unique_ptr<LocalToEntryVec> m_localToEntry;
718 };
719
720 } // namespace JSC