Enable JIT on ARM/Linux
[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     const void* rawPointer() const
166     {
167         return m_instructions.data();
168     }
169
170     bool contains(Instruction *) const;
171
172 protected:
173     explicit InstructionStream(InstructionBuffer&&);
174
175     InstructionBuffer m_instructions;
176 };
177
178 class InstructionStreamWriter : public InstructionStream {
179     friend class BytecodeRewriter;
180 public:
181     InstructionStreamWriter()
182         : InstructionStream({ })
183     { }
184
185     inline MutableRef ref(Offset offset)
186     {
187         ASSERT(offset < m_instructions.size());
188         return MutableRef { m_instructions, offset };
189     }
190
191     void seek(unsigned position)
192     {
193         ASSERT(position <= m_instructions.size());
194         m_position = position;
195     }
196
197     unsigned position()
198     {
199         return m_position;
200     }
201
202     void write(uint8_t byte)
203     {
204         ASSERT(!m_finalized);
205         if (m_position < m_instructions.size())
206             m_instructions[m_position++] = byte;
207         else {
208             m_instructions.append(byte);
209             m_position++;
210         }
211     }
212     void write(uint32_t i)
213     {
214         ASSERT(!m_finalized);
215         union {
216             uint32_t i;
217             uint8_t bytes[4];
218         } u { i };
219 #if CPU(BIG_ENDIAN)
220         write(u.bytes[3]);
221         write(u.bytes[2]);
222         write(u.bytes[1]);
223         write(u.bytes[0]);
224 #else // !CPU(BIG_ENDIAN)
225         write(u.bytes[0]);
226         write(u.bytes[1]);
227         write(u.bytes[2]);
228         write(u.bytes[3]);
229 #endif // !CPU(BIG_ENDIAN)
230     }
231
232     void rewind(MutableRef& ref)
233     {
234         ASSERT(ref.offset() < m_instructions.size());
235         m_instructions.shrink(ref.offset());
236         m_position = ref.offset();
237     }
238
239     std::unique_ptr<InstructionStream> finalize()
240     {
241         m_finalized = true;
242         m_instructions.shrinkToFit();
243         return std::unique_ptr<InstructionStream> { new InstructionStream(WTFMove(m_instructions)) };
244     }
245
246     MutableRef ref()
247     {
248         return MutableRef { m_instructions, m_position };
249     }
250
251     void swap(InstructionStreamWriter& other)
252     {
253         std::swap(m_finalized, other.m_finalized);
254         std::swap(m_position, other.m_position);
255         m_instructions.swap(other.m_instructions);
256     }
257
258 private:
259     class iterator : public MutableRef {
260         friend class InstructionStreamWriter;
261
262     protected:
263         using MutableRef::MutableRef;
264
265     public:
266         MutableRef& operator*()
267         {
268             return *this;
269         }
270
271         iterator operator++()
272         {
273             m_index += ptr()->size();
274             return *this;
275         }
276     };
277
278 public:
279     iterator begin()
280     {
281         return iterator { m_instructions, 0 };
282     }
283
284     iterator end()
285     {
286         return iterator { m_instructions, m_instructions.size() };
287     }
288
289 private:
290     unsigned m_position { 0 };
291     bool m_finalized { false };
292 };
293
294
295 } // namespace JSC