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