1/*
2 * Copyright (C) 2019 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#include "BytecodeGeneratorBase.h"
27
28#include "RegisterID.h"
29#include "StackAlignment.h"
30
31namespace JSC {
32
33template<typename T>
34static inline void shrinkToFit(T& segmentedVector)
35{
36 while (segmentedVector.size() && !segmentedVector.last().refCount())
37 segmentedVector.removeLast();
38}
39
40template<typename Traits>
41BytecodeGeneratorBase<Traits>::BytecodeGeneratorBase(typename Traits::CodeBlock codeBlock, uint32_t virtualRegisterCountForCalleeSaves)
42 : m_codeBlock(WTFMove(codeBlock))
43{
44 allocateCalleeSaveSpace(virtualRegisterCountForCalleeSaves);
45}
46
47template<typename Traits>
48Ref<GenericLabel<Traits>> BytecodeGeneratorBase<Traits>::newLabel()
49{
50 shrinkToFit(m_labels);
51
52 // Allocate new label ID.
53 m_labels.append();
54 return m_labels.last();
55}
56
57template<typename Traits>
58Ref<GenericLabel<Traits>> BytecodeGeneratorBase<Traits>::newEmittedLabel()
59{
60 auto label = newLabel();
61 emitLabel(label.get());
62 return label;
63}
64
65template<typename Traits>
66void BytecodeGeneratorBase<Traits>::reclaimFreeRegisters()
67{
68 shrinkToFit(m_calleeLocals);
69}
70
71template<typename Traits>
72void BytecodeGeneratorBase<Traits>::emitLabel(GenericLabel<Traits>& label)
73{
74 unsigned newLabelIndex = m_writer.position();
75 label.setLocation(*this, newLabelIndex);
76
77 if (m_codeBlock->numberOfJumpTargets()) {
78 unsigned lastLabelIndex = m_codeBlock->lastJumpTarget();
79 ASSERT(lastLabelIndex <= newLabelIndex);
80 if (newLabelIndex == lastLabelIndex) {
81 // Peephole optimizations have already been disabled by emitting the last label
82 return;
83 }
84 }
85
86 m_codeBlock->addJumpTarget(newLabelIndex);
87
88 m_lastOpcodeID = Traits::opcodeForDisablingOptimizations;
89}
90
91template<typename Traits>
92void BytecodeGeneratorBase<Traits>::recordOpcode(typename Traits::OpcodeID opcodeID)
93{
94 ASSERT(m_lastOpcodeID == Traits::opcodeForDisablingOptimizations || (m_lastOpcodeID == m_lastInstruction->opcodeID<typename Traits::OpcodeTraits>() && m_writer.position() == m_lastInstruction.offset() + m_lastInstruction->size<typename Traits::OpcodeTraits>()));
95 m_lastInstruction = m_writer.ref();
96 m_lastOpcodeID = opcodeID;
97}
98
99template<typename Traits>
100void BytecodeGeneratorBase<Traits>::alignWideOpcode16()
101{
102#if CPU(NEEDS_ALIGNED_ACCESS)
103 while ((m_writer.position() + 1) % OpcodeSize::Wide16)
104 Traits::OpNop::template emit<OpcodeSize::Narrow>(this);
105#endif
106}
107
108template<typename Traits>
109void BytecodeGeneratorBase<Traits>::alignWideOpcode32()
110{
111#if CPU(NEEDS_ALIGNED_ACCESS)
112 while ((m_writer.position() + 1) % OpcodeSize::Wide32)
113 Traits::OpNop::template emit<OpcodeSize::Narrow>(this);
114#endif
115}
116
117template<typename Traits>
118void BytecodeGeneratorBase<Traits>::write(uint8_t b)
119{
120 m_writer.write(b);
121}
122
123
124template<typename Traits>
125void BytecodeGeneratorBase<Traits>::write(uint16_t h)
126{
127 m_writer.write(h);
128}
129
130template<typename Traits>
131void BytecodeGeneratorBase<Traits>::write(uint32_t i)
132{
133 m_writer.write(i);
134}
135
136template<typename Traits>
137void BytecodeGeneratorBase<Traits>::write(int8_t b)
138{
139 m_writer.write(static_cast<uint8_t>(b));
140}
141
142template<typename Traits>
143void BytecodeGeneratorBase<Traits>::write(int16_t h)
144{
145 m_writer.write(static_cast<uint16_t>(h));
146}
147
148template<typename Traits>
149void BytecodeGeneratorBase<Traits>::write(int32_t i)
150{
151 m_writer.write(static_cast<uint32_t>(i));
152}
153
154template<typename Traits>
155RegisterID* BytecodeGeneratorBase<Traits>::newRegister()
156{
157 m_calleeLocals.append(virtualRegisterForLocal(m_calleeLocals.size()));
158 int numCalleeLocals = std::max<int>(m_codeBlock->m_numCalleeLocals, m_calleeLocals.size());
159 numCalleeLocals = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numCalleeLocals);
160 m_codeBlock->m_numCalleeLocals = numCalleeLocals;
161 return &m_calleeLocals.last();
162}
163
164template<typename Traits>
165RegisterID* BytecodeGeneratorBase<Traits>::newTemporary()
166{
167 reclaimFreeRegisters();
168
169 RegisterID* result = newRegister();
170 result->setTemporary();
171 return result;
172}
173
174// Adds an anonymous local var slot. To give this slot a name, add it to symbolTable().
175template<typename Traits>
176RegisterID* BytecodeGeneratorBase<Traits>::addVar()
177{
178 ++m_codeBlock->m_numVars;
179 RegisterID* result = newRegister();
180 ASSERT(VirtualRegister(result->index()).toLocal() == m_codeBlock->m_numVars - 1);
181 result->ref(); // We should never free this slot.
182 return result;
183}
184
185template<typename Traits>
186void BytecodeGeneratorBase<Traits>::allocateCalleeSaveSpace(uint32_t virtualRegisterCountForCalleeSaves)
187{
188 for (size_t i = 0; i < virtualRegisterCountForCalleeSaves; i++)
189 addVar();
190}
191
192} // namespace JSC
193