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 
9 // Helper types to make boolean flag easier to read at call-site.
10 enum InvokeFlag {
11   CALL_FUNCTION,
12   JUMP_FUNCTION
13 };
14 
15 
16 // Flags used for the AllocateInNewSpace functions.
17 enum AllocationFlags {
18   // No special flags.
19   NO_ALLOCATION_FLAGS = 0,
20   // Return the pointer to the allocated already tagged as a heap object.
21   TAG_OBJECT = 1 << 0,
22   // The content of the result register already contains the allocation top in
23   // new space.
24   RESULT_CONTAINS_TOP = 1 << 1,
25   // Specify that the requested size of the space to allocate is specified in
26   // words instead of bytes.
27   SIZE_IN_WORDS = 1 << 2,
28   // Align the allocation to a multiple of kDoubleSize
29   DOUBLE_ALIGNMENT = 1 << 3,
30   // Directly allocate in old pointer space
31   PRETENURE_OLD_POINTER_SPACE = 1 << 4,
32   // Directly allocate in old data space
33   PRETENURE_OLD_DATA_SPACE = 1 << 5
34 };
35 
36 
37 // Invalid depth in prototype chain.
38 const int kInvalidProtoDepth = -1;
39 
40 #if V8_TARGET_ARCH_IA32
41 #include "src/assembler.h"
42 #include "src/ia32/assembler-ia32.h"
43 #include "src/ia32/assembler-ia32-inl.h"
44 #include "src/code.h"  // NOLINT, must be after assembler_*.h
45 #include "src/ia32/macro-assembler-ia32.h"
46 #elif V8_TARGET_ARCH_X64
47 #include "src/assembler.h"
48 #include "src/x64/assembler-x64.h"
49 #include "src/x64/assembler-x64-inl.h"
50 #include "src/code.h"  // NOLINT, must be after assembler_*.h
51 #include "src/x64/macro-assembler-x64.h"
52 #elif V8_TARGET_ARCH_ARM64
53 #include "src/arm64/constants-arm64.h"
54 #include "src/assembler.h"
55 #include "src/arm64/assembler-arm64.h"  // NOLINT
56 #include "src/arm64/assembler-arm64-inl.h"
57 #include "src/code.h"  // NOLINT, must be after assembler_*.h
58 #include "src/arm64/macro-assembler-arm64.h"  // NOLINT
59 #include "src/arm64/macro-assembler-arm64-inl.h"
60 #elif V8_TARGET_ARCH_ARM
61 #include "src/arm/constants-arm.h"
62 #include "src/assembler.h"
63 #include "src/arm/assembler-arm.h"  // NOLINT
64 #include "src/arm/assembler-arm-inl.h"
65 #include "src/code.h"                     // NOLINT, must be after assembler_*.h
66 #include "src/arm/macro-assembler-arm.h"  // NOLINT
67 #elif V8_TARGET_ARCH_MIPS
68 #include "src/mips/constants-mips.h"
69 #include "src/assembler.h"            // NOLINT
70 #include "src/mips/assembler-mips.h"  // NOLINT
71 #include "src/mips/assembler-mips-inl.h"
72 #include "src/code.h"  // NOLINT, must be after assembler_*.h
73 #include "src/mips/macro-assembler-mips.h"
74 #elif V8_TARGET_ARCH_MIPS64
75 #include "src/mips64/constants-mips64.h"
76 #include "src/assembler.h"                // NOLINT
77 #include "src/mips64/assembler-mips64.h"  // NOLINT
78 #include "src/mips64/assembler-mips64-inl.h"
79 #include "src/code.h"  // NOLINT, must be after assembler_*.h
80 #include "src/mips64/macro-assembler-mips64.h"
81 #elif V8_TARGET_ARCH_X87
82 #include "src/assembler.h"
83 #include "src/x87/assembler-x87.h"
84 #include "src/x87/assembler-x87-inl.h"
85 #include "src/code.h"  // NOLINT, must be after assembler_*.h
86 #include "src/x87/macro-assembler-x87.h"
87 #else
88 #error Unsupported target architecture.
89 #endif
90 
91 namespace v8 {
92 namespace internal {
93 
94 class FrameScope {
95  public:
FrameScope(MacroAssembler * masm,StackFrame::Type type)96   explicit FrameScope(MacroAssembler* masm, StackFrame::Type type)
97       : masm_(masm), type_(type), old_has_frame_(masm->has_frame()) {
98     masm->set_has_frame(true);
99     if (type != StackFrame::MANUAL && type_ != StackFrame::NONE) {
100       masm->EnterFrame(type);
101     }
102   }
103 
~FrameScope()104   ~FrameScope() {
105     if (type_ != StackFrame::MANUAL && type_ != StackFrame::NONE) {
106       masm_->LeaveFrame(type_);
107     }
108     masm_->set_has_frame(old_has_frame_);
109   }
110 
111   // Normally we generate the leave-frame code when this object goes
112   // out of scope.  Sometimes we may need to generate the code somewhere else
113   // in addition.  Calling this will achieve that, but the object stays in
114   // scope, the MacroAssembler is still marked as being in a frame scope, and
115   // the code will be generated again when it goes out of scope.
GenerateLeaveFrame()116   void GenerateLeaveFrame() {
117     DCHECK(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
118     masm_->LeaveFrame(type_);
119   }
120 
121  private:
122   MacroAssembler* masm_;
123   StackFrame::Type type_;
124   bool old_has_frame_;
125 };
126 
127 
128 class AllowExternalCallThatCantCauseGC: public FrameScope {
129  public:
AllowExternalCallThatCantCauseGC(MacroAssembler * masm)130   explicit AllowExternalCallThatCantCauseGC(MacroAssembler* masm)
131       : FrameScope(masm, StackFrame::NONE) { }
132 };
133 
134 
135 class NoCurrentFrameScope {
136  public:
NoCurrentFrameScope(MacroAssembler * masm)137   explicit NoCurrentFrameScope(MacroAssembler* masm)
138       : masm_(masm), saved_(masm->has_frame()) {
139     masm->set_has_frame(false);
140   }
141 
~NoCurrentFrameScope()142   ~NoCurrentFrameScope() {
143     masm_->set_has_frame(saved_);
144   }
145 
146  private:
147   MacroAssembler* masm_;
148   bool saved_;
149 };
150 
151 
152 // Support for "structured" code comments.
153 #ifdef DEBUG
154 
155 class Comment {
156  public:
157   Comment(MacroAssembler* masm, const char* msg);
158   ~Comment();
159 
160  private:
161   MacroAssembler* masm_;
162   const char* msg_;
163 };
164 
165 #else
166 
167 class Comment {
168  public:
Comment(MacroAssembler *,const char *)169   Comment(MacroAssembler*, const char*)  {}
170 };
171 
172 #endif  // DEBUG
173 
174 
175 class AllocationUtils {
176  public:
GetAllocationTopReference(Isolate * isolate,AllocationFlags flags)177   static ExternalReference GetAllocationTopReference(
178       Isolate* isolate, AllocationFlags flags) {
179     if ((flags & PRETENURE_OLD_POINTER_SPACE) != 0) {
180       return ExternalReference::old_pointer_space_allocation_top_address(
181           isolate);
182     } else if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
183       return ExternalReference::old_data_space_allocation_top_address(isolate);
184     }
185     return ExternalReference::new_space_allocation_top_address(isolate);
186   }
187 
188 
GetAllocationLimitReference(Isolate * isolate,AllocationFlags flags)189   static ExternalReference GetAllocationLimitReference(
190       Isolate* isolate, AllocationFlags flags) {
191     if ((flags & PRETENURE_OLD_POINTER_SPACE) != 0) {
192       return ExternalReference::old_pointer_space_allocation_limit_address(
193           isolate);
194     } else if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
195       return ExternalReference::old_data_space_allocation_limit_address(
196           isolate);
197     }
198     return ExternalReference::new_space_allocation_limit_address(isolate);
199   }
200 };
201 
202 
203 } }  // namespace v8::internal
204 
205 #endif  // V8_MACRO_ASSEMBLER_H_
206