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