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