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