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/assembler.h"
9 
10 
11 // Helper types to make boolean flag easier to read at call-site.
12 enum InvokeFlag {
13   CALL_FUNCTION,
14   JUMP_FUNCTION
15 };
16 
17 
18 // Flags used for the AllocateInNewSpace functions.
19 enum AllocationFlags {
20   // No special flags.
21   NO_ALLOCATION_FLAGS = 0,
22   // Return the pointer to the allocated already tagged as a heap object.
23   TAG_OBJECT = 1 << 0,
24   // The content of the result register already contains the allocation top in
25   // new space.
26   RESULT_CONTAINS_TOP = 1 << 1,
27   // Specify that the requested size of the space to allocate is specified in
28   // words instead of bytes.
29   SIZE_IN_WORDS = 1 << 2,
30   // Align the allocation to a multiple of kDoubleSize
31   DOUBLE_ALIGNMENT = 1 << 3,
32   // Directly allocate in old space
33   PRETENURE = 1 << 4,
34 };
35 
36 
37 #if V8_TARGET_ARCH_IA32
38 #include "src/ia32/assembler-ia32.h"
39 #include "src/ia32/assembler-ia32-inl.h"
40 #include "src/ia32/macro-assembler-ia32.h"
41 #elif V8_TARGET_ARCH_X64
42 #include "src/x64/assembler-x64.h"
43 #include "src/x64/assembler-x64-inl.h"
44 #include "src/x64/macro-assembler-x64.h"
45 #elif V8_TARGET_ARCH_ARM64
46 #include "src/arm64/assembler-arm64.h"
47 #include "src/arm64/assembler-arm64-inl.h"
48 #include "src/arm64/constants-arm64.h"
49 #include "src/arm64/macro-assembler-arm64.h"
50 #include "src/arm64/macro-assembler-arm64-inl.h"
51 #elif V8_TARGET_ARCH_ARM
52 #include "src/arm/assembler-arm.h"
53 #include "src/arm/assembler-arm-inl.h"
54 #include "src/arm/constants-arm.h"
55 #include "src/arm/macro-assembler-arm.h"
56 #elif V8_TARGET_ARCH_PPC
57 #include "src/ppc/assembler-ppc.h"
58 #include "src/ppc/assembler-ppc-inl.h"
59 #include "src/ppc/constants-ppc.h"
60 #include "src/ppc/macro-assembler-ppc.h"
61 #elif V8_TARGET_ARCH_MIPS
62 #include "src/mips/assembler-mips.h"
63 #include "src/mips/assembler-mips-inl.h"
64 #include "src/mips/constants-mips.h"
65 #include "src/mips/macro-assembler-mips.h"
66 #elif V8_TARGET_ARCH_MIPS64
67 #include "src/mips64/assembler-mips64.h"
68 #include "src/mips64/assembler-mips64-inl.h"
69 #include "src/mips64/constants-mips64.h"
70 #include "src/mips64/macro-assembler-mips64.h"
71 #elif V8_TARGET_ARCH_X87
72 #include "src/x87/assembler-x87.h"
73 #include "src/x87/assembler-x87-inl.h"
74 #include "src/x87/macro-assembler-x87.h"
75 #else
76 #error Unsupported target architecture.
77 #endif
78 
79 namespace v8 {
80 namespace internal {
81 
82 class FrameScope {
83  public:
FrameScope(MacroAssembler * masm,StackFrame::Type type)84   explicit FrameScope(MacroAssembler* masm, StackFrame::Type type)
85       : masm_(masm), type_(type), old_has_frame_(masm->has_frame()) {
86     masm->set_has_frame(true);
87     if (type != StackFrame::MANUAL && type_ != StackFrame::NONE) {
88       masm->EnterFrame(type);
89     }
90   }
91 
~FrameScope()92   ~FrameScope() {
93     if (type_ != StackFrame::MANUAL && type_ != StackFrame::NONE) {
94       masm_->LeaveFrame(type_);
95     }
96     masm_->set_has_frame(old_has_frame_);
97   }
98 
99   // Normally we generate the leave-frame code when this object goes
100   // out of scope.  Sometimes we may need to generate the code somewhere else
101   // in addition.  Calling this will achieve that, but the object stays in
102   // scope, the MacroAssembler is still marked as being in a frame scope, and
103   // the code will be generated again when it goes out of scope.
GenerateLeaveFrame()104   void GenerateLeaveFrame() {
105     DCHECK(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
106     masm_->LeaveFrame(type_);
107   }
108 
109  private:
110   MacroAssembler* masm_;
111   StackFrame::Type type_;
112   bool old_has_frame_;
113 };
114 
115 class FrameAndConstantPoolScope {
116  public:
FrameAndConstantPoolScope(MacroAssembler * masm,StackFrame::Type type)117   FrameAndConstantPoolScope(MacroAssembler* masm, StackFrame::Type type)
118       : masm_(masm),
119         type_(type),
120         old_has_frame_(masm->has_frame()),
121         old_constant_pool_available_(FLAG_enable_embedded_constant_pool &&
122                                      masm->is_constant_pool_available()) {
123     masm->set_has_frame(true);
124     if (FLAG_enable_embedded_constant_pool) {
125       masm->set_constant_pool_available(true);
126     }
127     if (type_ != StackFrame::MANUAL && type_ != StackFrame::NONE) {
128       masm->EnterFrame(type, !old_constant_pool_available_);
129     }
130   }
131 
~FrameAndConstantPoolScope()132   ~FrameAndConstantPoolScope() {
133     masm_->LeaveFrame(type_);
134     masm_->set_has_frame(old_has_frame_);
135     if (FLAG_enable_embedded_constant_pool) {
136       masm_->set_constant_pool_available(old_constant_pool_available_);
137     }
138   }
139 
140   // Normally we generate the leave-frame code when this object goes
141   // out of scope.  Sometimes we may need to generate the code somewhere else
142   // in addition.  Calling this will achieve that, but the object stays in
143   // scope, the MacroAssembler is still marked as being in a frame scope, and
144   // the code will be generated again when it goes out of scope.
GenerateLeaveFrame()145   void GenerateLeaveFrame() {
146     DCHECK(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
147     masm_->LeaveFrame(type_);
148   }
149 
150  private:
151   MacroAssembler* masm_;
152   StackFrame::Type type_;
153   bool old_has_frame_;
154   bool old_constant_pool_available_;
155 
156   DISALLOW_IMPLICIT_CONSTRUCTORS(FrameAndConstantPoolScope);
157 };
158 
159 // Class for scoping the the unavailability of constant pool access.
160 class ConstantPoolUnavailableScope {
161  public:
ConstantPoolUnavailableScope(MacroAssembler * masm)162   explicit ConstantPoolUnavailableScope(MacroAssembler* masm)
163       : masm_(masm),
164         old_constant_pool_available_(FLAG_enable_embedded_constant_pool &&
165                                      masm->is_constant_pool_available()) {
166     if (FLAG_enable_embedded_constant_pool) {
167       masm_->set_constant_pool_available(false);
168     }
169   }
~ConstantPoolUnavailableScope()170   ~ConstantPoolUnavailableScope() {
171     if (FLAG_enable_embedded_constant_pool) {
172       masm_->set_constant_pool_available(old_constant_pool_available_);
173     }
174   }
175 
176  private:
177   MacroAssembler* masm_;
178   int old_constant_pool_available_;
179 
180   DISALLOW_IMPLICIT_CONSTRUCTORS(ConstantPoolUnavailableScope);
181 };
182 
183 
184 class AllowExternalCallThatCantCauseGC: public FrameScope {
185  public:
AllowExternalCallThatCantCauseGC(MacroAssembler * masm)186   explicit AllowExternalCallThatCantCauseGC(MacroAssembler* masm)
187       : FrameScope(masm, StackFrame::NONE) { }
188 };
189 
190 
191 class NoCurrentFrameScope {
192  public:
NoCurrentFrameScope(MacroAssembler * masm)193   explicit NoCurrentFrameScope(MacroAssembler* masm)
194       : masm_(masm), saved_(masm->has_frame()) {
195     masm->set_has_frame(false);
196   }
197 
~NoCurrentFrameScope()198   ~NoCurrentFrameScope() {
199     masm_->set_has_frame(saved_);
200   }
201 
202  private:
203   MacroAssembler* masm_;
204   bool saved_;
205 };
206 
207 
208 // Support for "structured" code comments.
209 #ifdef DEBUG
210 
211 class Comment {
212  public:
213   Comment(MacroAssembler* masm, const char* msg);
214   ~Comment();
215 
216  private:
217   MacroAssembler* masm_;
218   const char* msg_;
219 };
220 
221 #else
222 
223 class Comment {
224  public:
Comment(MacroAssembler *,const char *)225   Comment(MacroAssembler*, const char*)  {}
226 };
227 
228 #endif  // DEBUG
229 
230 
231 // Wrapper class for passing expected and actual parameter counts as
232 // either registers or immediate values. Used to make sure that the
233 // caller provides exactly the expected number of parameters to the
234 // callee.
235 class ParameterCount BASE_EMBEDDED {
236  public:
ParameterCount(Register reg)237   explicit ParameterCount(Register reg) : reg_(reg), immediate_(0) {}
ParameterCount(int imm)238   explicit ParameterCount(int imm) : reg_(no_reg), immediate_(imm) {}
239 
is_reg()240   bool is_reg() const { return !reg_.is(no_reg); }
is_immediate()241   bool is_immediate() const { return !is_reg(); }
242 
reg()243   Register reg() const {
244     DCHECK(is_reg());
245     return reg_;
246   }
immediate()247   int immediate() const {
248     DCHECK(is_immediate());
249     return immediate_;
250   }
251 
252  private:
253   const Register reg_;
254   const int immediate_;
255 
256   DISALLOW_IMPLICIT_CONSTRUCTORS(ParameterCount);
257 };
258 
259 
260 class AllocationUtils {
261  public:
GetAllocationTopReference(Isolate * isolate,AllocationFlags flags)262   static ExternalReference GetAllocationTopReference(
263       Isolate* isolate, AllocationFlags flags) {
264     if ((flags & PRETENURE) != 0) {
265       return ExternalReference::old_space_allocation_top_address(isolate);
266     }
267     return ExternalReference::new_space_allocation_top_address(isolate);
268   }
269 
270 
GetAllocationLimitReference(Isolate * isolate,AllocationFlags flags)271   static ExternalReference GetAllocationLimitReference(
272       Isolate* isolate, AllocationFlags flags) {
273     if ((flags & PRETENURE) != 0) {
274       return ExternalReference::old_space_allocation_limit_address(isolate);
275     }
276     return ExternalReference::new_space_allocation_limit_address(isolate);
277   }
278 };
279 
280 
281 }  // namespace internal
282 }  // namespace v8
283 
284 #endif  // V8_MACRO_ASSEMBLER_H_
285