1 | // Copyright 2012 the V8 project authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #ifndef V8_MACRO_ASSEMBLER_H_ |
6 | #define V8_MACRO_ASSEMBLER_H_ |
7 | |
8 | #include "src/frames.h" |
9 | #include "src/heap/heap.h" |
10 | #include "src/turbo-assembler.h" |
11 | |
12 | // Helper types to make boolean flag easier to read at call-site. |
13 | enum InvokeFlag { |
14 | CALL_FUNCTION, |
15 | JUMP_FUNCTION |
16 | }; |
17 | |
18 | |
19 | // Flags used for the AllocateInNewSpace functions. |
20 | enum AllocationFlags { |
21 | // No special flags. |
22 | NO_ALLOCATION_FLAGS = 0, |
23 | // The content of the result register already contains the allocation top in |
24 | // new space. |
25 | RESULT_CONTAINS_TOP = 1 << 0, |
26 | // Specify that the requested size of the space to allocate is specified in |
27 | // words instead of bytes. |
28 | SIZE_IN_WORDS = 1 << 1, |
29 | // Align the allocation to a multiple of kDoubleSize |
30 | DOUBLE_ALIGNMENT = 1 << 2, |
31 | // Directly allocate in old space |
32 | PRETENURE = 1 << 3, |
33 | }; |
34 | |
35 | // This is the only place allowed to include the platform-specific headers. |
36 | #define INCLUDED_FROM_MACRO_ASSEMBLER_H |
37 | #if V8_TARGET_ARCH_IA32 |
38 | #include "src/ia32/macro-assembler-ia32.h" |
39 | #elif V8_TARGET_ARCH_X64 |
40 | #include "src/x64/macro-assembler-x64.h" |
41 | #elif V8_TARGET_ARCH_ARM64 |
42 | #include "src/arm64/constants-arm64.h" |
43 | #include "src/arm64/macro-assembler-arm64.h" |
44 | #elif V8_TARGET_ARCH_ARM |
45 | #include "src/arm/constants-arm.h" |
46 | #include "src/arm/macro-assembler-arm.h" |
47 | #elif V8_TARGET_ARCH_PPC |
48 | #include "src/ppc/constants-ppc.h" |
49 | #include "src/ppc/macro-assembler-ppc.h" |
50 | #elif V8_TARGET_ARCH_MIPS |
51 | #include "src/mips/constants-mips.h" |
52 | #include "src/mips/macro-assembler-mips.h" |
53 | #elif V8_TARGET_ARCH_MIPS64 |
54 | #include "src/mips64/constants-mips64.h" |
55 | #include "src/mips64/macro-assembler-mips64.h" |
56 | #elif V8_TARGET_ARCH_S390 |
57 | #include "src/s390/constants-s390.h" |
58 | #include "src/s390/macro-assembler-s390.h" |
59 | #else |
60 | #error Unsupported target architecture. |
61 | #endif |
62 | #undef INCLUDED_FROM_MACRO_ASSEMBLER_H |
63 | |
64 | namespace v8 { |
65 | namespace internal { |
66 | |
67 | // Simulators only support C calls with up to kMaxCParameters parameters. |
68 | static constexpr int kMaxCParameters = 9; |
69 | |
70 | class FrameScope { |
71 | public: |
72 | explicit FrameScope(TurboAssembler* tasm, StackFrame::Type type) |
73 | : tasm_(tasm), type_(type), old_has_frame_(tasm->has_frame()) { |
74 | tasm->set_has_frame(true); |
75 | if (type != StackFrame::MANUAL && type_ != StackFrame::NONE) { |
76 | tasm->EnterFrame(type); |
77 | } |
78 | } |
79 | |
80 | ~FrameScope() { |
81 | if (type_ != StackFrame::MANUAL && type_ != StackFrame::NONE) { |
82 | tasm_->LeaveFrame(type_); |
83 | } |
84 | tasm_->set_has_frame(old_has_frame_); |
85 | } |
86 | |
87 | // Normally we generate the leave-frame code when this object goes |
88 | // out of scope. Sometimes we may need to generate the code somewhere else |
89 | // in addition. Calling this will achieve that, but the object stays in |
90 | // scope, the MacroAssembler is still marked as being in a frame scope, and |
91 | // the code will be generated again when it goes out of scope. |
92 | void GenerateLeaveFrame() { |
93 | DCHECK(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE); |
94 | tasm_->LeaveFrame(type_); |
95 | } |
96 | |
97 | private: |
98 | TurboAssembler* tasm_; |
99 | StackFrame::Type type_; |
100 | bool old_has_frame_; |
101 | }; |
102 | |
103 | class FrameAndConstantPoolScope { |
104 | public: |
105 | FrameAndConstantPoolScope(MacroAssembler* masm, StackFrame::Type type) |
106 | : masm_(masm), |
107 | type_(type), |
108 | old_has_frame_(masm->has_frame()), |
109 | old_constant_pool_available_(FLAG_enable_embedded_constant_pool && |
110 | masm->is_constant_pool_available()) { |
111 | masm->set_has_frame(true); |
112 | if (FLAG_enable_embedded_constant_pool) { |
113 | masm->set_constant_pool_available(true); |
114 | } |
115 | if (type_ != StackFrame::MANUAL && type_ != StackFrame::NONE) { |
116 | masm->EnterFrame(type, !old_constant_pool_available_); |
117 | } |
118 | } |
119 | |
120 | ~FrameAndConstantPoolScope() { |
121 | masm_->LeaveFrame(type_); |
122 | masm_->set_has_frame(old_has_frame_); |
123 | if (FLAG_enable_embedded_constant_pool) { |
124 | masm_->set_constant_pool_available(old_constant_pool_available_); |
125 | } |
126 | } |
127 | |
128 | // Normally we generate the leave-frame code when this object goes |
129 | // out of scope. Sometimes we may need to generate the code somewhere else |
130 | // in addition. Calling this will achieve that, but the object stays in |
131 | // scope, the MacroAssembler is still marked as being in a frame scope, and |
132 | // the code will be generated again when it goes out of scope. |
133 | void GenerateLeaveFrame() { |
134 | DCHECK(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE); |
135 | masm_->LeaveFrame(type_); |
136 | } |
137 | |
138 | private: |
139 | MacroAssembler* masm_; |
140 | StackFrame::Type type_; |
141 | bool old_has_frame_; |
142 | bool old_constant_pool_available_; |
143 | |
144 | DISALLOW_IMPLICIT_CONSTRUCTORS(FrameAndConstantPoolScope); |
145 | }; |
146 | |
147 | // Class for scoping the the unavailability of constant pool access. |
148 | class ConstantPoolUnavailableScope { |
149 | public: |
150 | explicit ConstantPoolUnavailableScope(Assembler* assembler) |
151 | : assembler_(assembler), |
152 | old_constant_pool_available_(FLAG_enable_embedded_constant_pool && |
153 | assembler->is_constant_pool_available()) { |
154 | if (FLAG_enable_embedded_constant_pool) { |
155 | assembler->set_constant_pool_available(false); |
156 | } |
157 | } |
158 | ~ConstantPoolUnavailableScope() { |
159 | if (FLAG_enable_embedded_constant_pool) { |
160 | assembler_->set_constant_pool_available(old_constant_pool_available_); |
161 | } |
162 | } |
163 | |
164 | private: |
165 | Assembler* assembler_; |
166 | int old_constant_pool_available_; |
167 | |
168 | DISALLOW_IMPLICIT_CONSTRUCTORS(ConstantPoolUnavailableScope); |
169 | }; |
170 | |
171 | |
172 | class AllowExternalCallThatCantCauseGC: public FrameScope { |
173 | public: |
174 | explicit AllowExternalCallThatCantCauseGC(MacroAssembler* masm) |
175 | : FrameScope(masm, StackFrame::NONE) { } |
176 | }; |
177 | |
178 | // Prevent the use of the RootArray during the lifetime of this |
179 | // scope object. |
180 | class NoRootArrayScope { |
181 | public: |
182 | explicit NoRootArrayScope(TurboAssembler* masm) |
183 | : masm_(masm), old_value_(masm->root_array_available()) { |
184 | masm->set_root_array_available(false); |
185 | } |
186 | |
187 | ~NoRootArrayScope() { masm_->set_root_array_available(old_value_); } |
188 | |
189 | private: |
190 | TurboAssembler* masm_; |
191 | bool old_value_; |
192 | }; |
193 | |
194 | // Wrapper class for passing expected and actual parameter counts as |
195 | // either registers or immediate values. Used to make sure that the |
196 | // caller provides exactly the expected number of parameters to the |
197 | // callee. |
198 | class ParameterCount { |
199 | public: |
200 | explicit ParameterCount(Register reg) : reg_(reg), immediate_(0) {} |
201 | explicit ParameterCount(uint16_t imm) : reg_(no_reg), immediate_(imm) {} |
202 | |
203 | bool is_reg() const { return reg_.is_valid(); } |
204 | bool is_immediate() const { return !is_reg(); } |
205 | |
206 | Register reg() const { |
207 | DCHECK(is_reg()); |
208 | return reg_; |
209 | } |
210 | uint16_t immediate() const { |
211 | DCHECK(is_immediate()); |
212 | return immediate_; |
213 | } |
214 | |
215 | private: |
216 | const Register reg_; |
217 | const uint16_t immediate_; |
218 | |
219 | DISALLOW_IMPLICIT_CONSTRUCTORS(ParameterCount); |
220 | }; |
221 | |
222 | } // namespace internal |
223 | } // namespace v8 |
224 | |
225 | #endif // V8_MACRO_ASSEMBLER_H_ |
226 | |