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: 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 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. 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: 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 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. 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: 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 } 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: 186 explicit AllowExternalCallThatCantCauseGC(MacroAssembler* masm) 187 : FrameScope(masm, StackFrame::NONE) { } 188 }; 189 190 191 class NoCurrentFrameScope { 192 public: 193 explicit NoCurrentFrameScope(MacroAssembler* masm) 194 : masm_(masm), saved_(masm->has_frame()) { 195 masm->set_has_frame(false); 196 } 197 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: 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: 237 explicit ParameterCount(Register reg) : reg_(reg), immediate_(0) {} 238 explicit ParameterCount(int imm) : reg_(no_reg), immediate_(imm) {} 239 240 bool is_reg() const { return !reg_.is(no_reg); } 241 bool is_immediate() const { return !is_reg(); } 242 243 Register reg() const { 244 DCHECK(is_reg()); 245 return reg_; 246 } 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: 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 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