Out of bounds read in IdentifierArena::makeIdentifier
[WebKit-https.git] / Source / JavaScriptCore / parser / ParserArena.h
1 /*
2  * Copyright (C) 2009 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef ParserArena_h
27 #define ParserArena_h
28
29 #include "CommonIdentifiers.h"
30 #include "Identifier.h"
31 #include <array>
32 #include <wtf/SegmentedVector.h>
33
34 namespace JSC {
35
36     class ParserArenaDeletable;
37
38     class IdentifierArena {
39         WTF_MAKE_FAST_ALLOCATED;
40     public:
41         IdentifierArena()
42         {
43             clear();
44         }
45
46         template <typename T>
47         ALWAYS_INLINE const Identifier& makeIdentifier(VM*, const T* characters, size_t length);
48         ALWAYS_INLINE const Identifier& makeIdentifierLCharFromUChar(VM*, const UChar* characters, size_t length);
49
50         const Identifier& makeNumericIdentifier(VM*, double number);
51
52     public:
53         static const int MaximumCachableCharacter = 128;
54         typedef SegmentedVector<Identifier, 64> IdentifierVector;
55         void clear()
56         {
57             m_identifiers.clear();
58             for (int i = 0; i < MaximumCachableCharacter; i++)
59                 m_shortIdentifiers[i] = 0;
60             for (int i = 0; i < MaximumCachableCharacter; i++)
61                 m_recentIdentifiers[i] = 0;
62         }
63
64     private:
65         IdentifierVector m_identifiers;
66         std::array<Identifier*, MaximumCachableCharacter> m_shortIdentifiers;
67         std::array<Identifier*, MaximumCachableCharacter> m_recentIdentifiers;
68     };
69
70     template <typename T>
71     ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifier(VM* vm, const T* characters, size_t length)
72     {
73         if (!length)
74             return vm->propertyNames->emptyIdentifier;
75         if (characters[0] >= MaximumCachableCharacter) {
76             m_identifiers.append(Identifier(vm, characters, length));
77             return m_identifiers.last();
78         }
79         if (length == 1) {
80             if (Identifier* ident = m_shortIdentifiers[characters[0]])
81                 return *ident;
82             m_identifiers.append(Identifier(vm, characters, length));
83             m_shortIdentifiers[characters[0]] = &m_identifiers.last();
84             return m_identifiers.last();
85         }
86         Identifier* ident = m_recentIdentifiers[characters[0]];
87         if (ident && Identifier::equal(ident->impl(), characters, length))
88             return *ident;
89         m_identifiers.append(Identifier(vm, characters, length));
90         m_recentIdentifiers[characters[0]] = &m_identifiers.last();
91         return m_identifiers.last();
92     }
93
94     ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifierLCharFromUChar(VM* vm, const UChar* characters, size_t length)
95     {
96         if (!length)
97             return vm->propertyNames->emptyIdentifier;
98         if (characters[0] >= MaximumCachableCharacter) {
99             m_identifiers.append(Identifier::createLCharFromUChar(vm, characters, length));
100             return m_identifiers.last();
101         }
102         if (length == 1) {
103             if (Identifier* ident = m_shortIdentifiers[characters[0]])
104                 return *ident;
105             m_identifiers.append(Identifier(vm, characters, length));
106             m_shortIdentifiers[characters[0]] = &m_identifiers.last();
107             return m_identifiers.last();
108         }
109         Identifier* ident = m_recentIdentifiers[characters[0]];
110         if (ident && Identifier::equal(ident->impl(), characters, length))
111             return *ident;
112         m_identifiers.append(Identifier::createLCharFromUChar(vm, characters, length));
113         m_recentIdentifiers[characters[0]] = &m_identifiers.last();
114         return m_identifiers.last();
115     }
116     
117     inline const Identifier& IdentifierArena::makeNumericIdentifier(VM* vm, double number)
118     {
119         m_identifiers.append(Identifier(vm, String::numberToStringECMAScript(number)));
120         return m_identifiers.last();
121     }
122
123     class ParserArena {
124         WTF_MAKE_NONCOPYABLE(ParserArena);
125     public:
126         ParserArena();
127         ~ParserArena();
128
129         void swap(ParserArena& otherArena)
130         {
131             std::swap(m_freeableMemory, otherArena.m_freeableMemory);
132             std::swap(m_freeablePoolEnd, otherArena.m_freeablePoolEnd);
133             m_identifierArena.swap(otherArena.m_identifierArena);
134             m_freeablePools.swap(otherArena.m_freeablePools);
135             m_deletableObjects.swap(otherArena.m_deletableObjects);
136         }
137
138         void* allocateFreeable(size_t size)
139         {
140             ASSERT(size);
141             ASSERT(size <= freeablePoolSize);
142             size_t alignedSize = alignSize(size);
143             ASSERT(alignedSize <= freeablePoolSize);
144             if (UNLIKELY(static_cast<size_t>(m_freeablePoolEnd - m_freeableMemory) < alignedSize))
145                 allocateFreeablePool();
146             void* block = m_freeableMemory;
147             m_freeableMemory += alignedSize;
148             return block;
149         }
150
151         void* allocateDeletable(size_t size)
152         {
153             ParserArenaDeletable* deletable = static_cast<ParserArenaDeletable*>(allocateFreeable(size));
154             m_deletableObjects.append(deletable);
155             return deletable;
156         }
157
158         IdentifierArena& identifierArena()
159         {
160             if (UNLIKELY (!m_identifierArena))
161                 m_identifierArena = std::make_unique<IdentifierArena>();
162             return *m_identifierArena;
163         }
164
165     private:
166         static const size_t freeablePoolSize = 8000;
167
168         static size_t alignSize(size_t size)
169         {
170             return (size + sizeof(WTF::AllocAlignmentInteger) - 1) & ~(sizeof(WTF::AllocAlignmentInteger) - 1);
171         }
172
173         void* freeablePool();
174         void allocateFreeablePool();
175         void deallocateObjects();
176
177         char* m_freeableMemory;
178         char* m_freeablePoolEnd;
179
180         std::unique_ptr<IdentifierArena> m_identifierArena;
181         Vector<void*> m_freeablePools;
182         Vector<ParserArenaDeletable*> m_deletableObjects;
183     };
184
185 }
186
187 #endif