4b3438637071ce6f5e17828881e567b44ca37bbc
[WebKit-https.git] / Source / JavaScriptCore / bytecode / InstructionStream.h
1 /*
2  * Copyright (C) 2018 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
27 #pragma once
28
29 #include "Instruction.h"
30 #include <wtf/Vector.h>
31
32 namespace JSC {
33
34 struct Instruction;
35
36 class InstructionStream {
37     WTF_MAKE_FAST_ALLOCATED;
38
39     using InstructionBuffer = Vector<uint8_t, 0, UnsafeVectorOverflow>;
40
41     friend class InstructionStreamWriter;
42 public:
43     size_t sizeInBytes() const;
44
45     using Offset = unsigned;
46
47 private:
48     template<class InstructionBuffer>
49     class BaseRef {
50         WTF_MAKE_FAST_ALLOCATED;
51
52         friend class InstructionStream;
53
54     public:
55         BaseRef(const BaseRef<InstructionBuffer>& other)
56             : m_instructions(other.m_instructions)
57             ,  m_index(other.m_index)
58         { }
59
60         void operator=(const BaseRef<InstructionBuffer>& other)
61         {
62             m_instructions = other.m_instructions;
63             m_index = other.m_index;
64         }
65
66         inline const Instruction* operator->() const { return unwrap(); }
67         inline const Instruction* ptr() const { return unwrap(); }
68
69         bool operator!=(const BaseRef<InstructionBuffer>& other) const
70         {
71             return &m_instructions != &other.m_instructions || m_index != other.m_index;
72         }
73
74         BaseRef next() const
75         {
76             return BaseRef { m_instructions, m_index + ptr()->size() };
77         }
78
79         inline Offset offset() const
80         {
81             return m_index;
82         }
83
84         bool isValid() const
85         {
86             return m_index < m_instructions.size();
87         }
88
89     private:
90         inline const Instruction* unwrap() const { return reinterpret_cast<const Instruction*>(&m_instructions[m_index]); }
91
92     protected:
93         BaseRef(InstructionBuffer& instructions, size_t index)
94             : m_instructions(instructions)
95             , m_index(index)
96         { }
97
98         InstructionBuffer& m_instructions;
99         Offset m_index;
100     };
101
102 public:
103     using Ref = BaseRef<const InstructionBuffer>;
104
105     class MutableRef : public BaseRef<InstructionBuffer> {
106         friend class InstructionStreamWriter;
107
108     protected:
109         using BaseRef<InstructionBuffer>::BaseRef;
110
111     public:
112         Ref freeze() const  { return Ref { m_instructions, m_index }; }
113         inline Instruction* operator->() { return unwrap(); }
114         inline Instruction* ptr() { return unwrap(); }
115         inline operator Ref()
116         {
117             return Ref { m_instructions, m_index };
118         }
119
120     private:
121         inline Instruction* unwrap() { return reinterpret_cast<Instruction*>(&m_instructions[m_index]); }
122     };
123
124 private:
125     class iterator : public Ref {
126         friend class InstructionStream;
127
128     public:
129         using Ref::Ref;
130
131         Ref& operator*()
132         {
133             return *this;
134         }
135
136         iterator operator++()
137         {
138             m_index += ptr()->size();
139             return *this;
140         }
141     };
142
143 public:
144     inline iterator begin() const
145     {
146         return iterator { m_instructions, 0 };
147     }
148
149     inline iterator end() const
150     {
151         return iterator { m_instructions, m_instructions.size() };
152     }
153
154     inline const Ref at(Offset offset) const
155     {
156         ASSERT(offset < m_instructions.size());
157         return Ref { m_instructions, offset };
158     }
159
160     inline size_t size() const
161     {
162         return m_instructions.size();
163     }
164
165 protected:
166     explicit InstructionStream(InstructionBuffer&&);
167
168     InstructionBuffer m_instructions;
169 };
170
171 class InstructionStreamWriter : public InstructionStream {
172     friend class BytecodeRewriter;
173 public:
174     InstructionStreamWriter()
175         : InstructionStream({ })
176     { }
177
178     inline MutableRef ref(Offset offset)
179     {
180         ASSERT(offset < m_instructions.size());
181         return MutableRef { m_instructions, offset };
182     }
183
184     void seek(unsigned position)
185     {
186         ASSERT(position <= m_instructions.size());
187         m_position = position;
188     }
189
190     unsigned position()
191     {
192         return m_position;
193     }
194
195     void write(uint8_t byte)
196     {
197         ASSERT(!m_finalized);
198         if (m_position < m_instructions.size())
199             m_instructions[m_position++] = byte;
200         else {
201             m_instructions.append(byte);
202             m_position++;
203         }
204     }
205     void write(uint32_t i)
206     {
207         ASSERT(!m_finalized);
208         union {
209             uint32_t i;
210             uint8_t bytes[4];
211         } u { i };
212 #if CPU(BIG_ENDIAN)
213         write(u.bytes[3]);
214         write(u.bytes[2]);
215         write(u.bytes[1]);
216         write(u.bytes[0]);
217 #else // !CPU(BIG_ENDIAN)
218         write(u.bytes[0]);
219         write(u.bytes[1]);
220         write(u.bytes[2]);
221         write(u.bytes[3]);
222 #endif // !CPU(BIG_ENDIAN)
223     }
224
225     void rewind(MutableRef& ref)
226     {
227         ASSERT(ref.offset() < m_instructions.size());
228         m_instructions.shrink(ref.offset());
229         m_position = ref.offset();
230     }
231
232     std::unique_ptr<InstructionStream> finalize()
233     {
234         m_finalized = true;
235         m_instructions.shrinkToFit();
236         return std::unique_ptr<InstructionStream> { new InstructionStream(WTFMove(m_instructions)) };
237     }
238
239     MutableRef ref()
240     {
241         return MutableRef { m_instructions, m_position };
242     }
243
244     void swap(InstructionStreamWriter& other)
245     {
246         std::swap(m_finalized, other.m_finalized);
247         std::swap(m_position, other.m_position);
248         m_instructions.swap(other.m_instructions);
249     }
250
251 private:
252     class iterator : public MutableRef {
253         friend class InstructionStreamWriter;
254
255     protected:
256         using MutableRef::MutableRef;
257
258     public:
259         MutableRef& operator*()
260         {
261             return *this;
262         }
263
264         iterator operator++()
265         {
266             m_index += ptr()->size();
267             return *this;
268         }
269     };
270
271 public:
272     iterator begin()
273     {
274         return iterator { m_instructions, 0 };
275     }
276
277     iterator end()
278     {
279         return iterator { m_instructions, m_instructions.size() };
280     }
281
282 private:
283     unsigned m_position { 0 };
284     bool m_finalized { false };
285 };
286
287
288 } // namespace JSC