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.
13enum InvokeFlag {
14 CALL_FUNCTION,
15 JUMP_FUNCTION
16};
17
18
19// Flags used for the AllocateInNewSpace functions.
20enum 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
64namespace v8 {
65namespace internal {
66
67// Simulators only support C calls with up to kMaxCParameters parameters.
68static constexpr int kMaxCParameters = 9;
69
70class 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
103class 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.
148class 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
172class 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.
180class 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.
198class 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