1 // Copyright 2021 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_BASELINE_BASELINE_ASSEMBLER_H_ 6 #define V8_BASELINE_BASELINE_ASSEMBLER_H_ 7 8 // TODO(v8:11421): Remove #if once baseline compiler is ported to other 9 // architectures. 10 #include "src/flags/flags.h" 11 #if ENABLE_SPARKPLUG 12 13 #include "src/codegen/macro-assembler.h" 14 #include "src/objects/tagged-index.h" 15 16 namespace v8 { 17 namespace internal { 18 namespace baseline { 19 20 enum class Condition : uint32_t; 21 22 class BaselineAssembler { 23 public: 24 class ScratchRegisterScope; 25 BaselineAssembler(MacroAssembler * masm)26 explicit BaselineAssembler(MacroAssembler* masm) : masm_(masm) {} 27 inline static MemOperand RegisterFrameOperand( 28 interpreter::Register interpreter_register); 29 inline MemOperand ContextOperand(); 30 inline MemOperand FunctionOperand(); 31 inline MemOperand FeedbackVectorOperand(); 32 33 inline void GetCode(Isolate* isolate, CodeDesc* desc); 34 inline int pc_offset() const; 35 inline void CodeEntry() const; 36 inline void ExceptionHandler() const; 37 V8_INLINE void RecordComment(const char* string); 38 inline void Trap(); 39 inline void DebugBreak(); 40 41 inline void Bind(Label* label); 42 // Binds the label without marking it as a valid jump target. 43 // This is only useful, when the position is already marked as a valid jump 44 // target (i.e. at the beginning of the bytecode). 45 inline void BindWithoutJumpTarget(Label* label); 46 // Marks the current position as a valid jump target on CFI enabled 47 // architectures. 48 inline void JumpTarget(); 49 inline void Jump(Label* target, Label::Distance distance = Label::kFar); 50 inline void JumpIfRoot(Register value, RootIndex index, Label* target, 51 Label::Distance distance = Label::kFar); 52 inline void JumpIfNotRoot(Register value, RootIndex index, Label* target, 53 Label ::Distance distance = Label::kFar); 54 inline void JumpIfSmi(Register value, Label* target, 55 Label::Distance distance = Label::kFar); 56 inline void JumpIfNotSmi(Register value, Label* target, 57 Label::Distance distance = Label::kFar); 58 59 inline void TestAndBranch(Register value, int mask, Condition cc, 60 Label* target, 61 Label::Distance distance = Label::kFar); 62 63 inline void JumpIf(Condition cc, Register lhs, const Operand& rhs, 64 Label* target, Label::Distance distance = Label::kFar); 65 inline void JumpIfObjectType(Condition cc, Register object, 66 InstanceType instance_type, Register map, 67 Label* target, 68 Label::Distance distance = Label::kFar); 69 inline void JumpIfInstanceType(Condition cc, Register map, 70 InstanceType instance_type, Label* target, 71 Label::Distance distance = Label::kFar); 72 inline void JumpIfPointer(Condition cc, Register value, MemOperand operand, 73 Label* target, 74 Label::Distance distance = Label::kFar); 75 inline Condition CheckSmi(Register value); 76 inline void JumpIfSmi(Condition cc, Register value, Smi smi, Label* target, 77 Label::Distance distance = Label::kFar); 78 inline void JumpIfSmi(Condition cc, Register lhs, Register rhs, Label* target, 79 Label::Distance distance = Label::kFar); 80 inline void JumpIfTagged(Condition cc, Register value, MemOperand operand, 81 Label* target, 82 Label::Distance distance = Label::kFar); 83 inline void JumpIfTagged(Condition cc, MemOperand operand, Register value, 84 Label* target, 85 Label::Distance distance = Label::kFar); 86 inline void JumpIfByte(Condition cc, Register value, int32_t byte, 87 Label* target, Label::Distance distance = Label::kFar); 88 89 inline void LoadMap(Register output, Register value); 90 inline void LoadRoot(Register output, RootIndex index); 91 inline void LoadNativeContextSlot(Register output, uint32_t index); 92 93 inline void Move(Register output, Register source); 94 inline void Move(Register output, MemOperand operand); 95 inline void Move(Register output, Smi value); 96 inline void Move(Register output, TaggedIndex value); 97 inline void Move(Register output, interpreter::Register source); 98 inline void Move(interpreter::Register output, Register source); 99 inline void Move(Register output, RootIndex source); 100 inline void Move(MemOperand output, Register source); 101 inline void Move(Register output, ExternalReference reference); 102 inline void Move(Register output, Handle<HeapObject> value); 103 inline void Move(Register output, int32_t immediate); 104 inline void MoveMaybeSmi(Register output, Register source); 105 inline void MoveSmi(Register output, Register source); 106 107 // Push the given values, in the given order. If the stack needs alignment 108 // (looking at you Arm64), the stack is padded from the front (i.e. before the 109 // first value is pushed). 110 // 111 // This supports pushing a RegisterList as the last value -- the list is 112 // iterated and each interpreter Register is pushed. 113 // 114 // The total number of values pushed is returned. Note that this might be 115 // different from sizeof(T...), specifically if there was a RegisterList. 116 template <typename... T> 117 inline int Push(T... vals); 118 119 // Like Push(vals...), but pushes in reverse order, to support our reversed 120 // order argument JS calling convention. Doesn't return the number of 121 // arguments pushed though. 122 // 123 // Note that padding is still inserted before the first pushed value (i.e. the 124 // last value). 125 template <typename... T> 126 inline void PushReverse(T... vals); 127 128 // Pop values off the stack into the given registers. 129 // 130 // Note that this inserts into registers in the given order, i.e. in reverse 131 // order if the registers were pushed. This means that to spill registers, 132 // push and pop have to be in reverse order, e.g. 133 // 134 // Push(r1, r2, ..., rN); 135 // ClobberRegisters(); 136 // Pop(rN, ..., r2, r1); 137 // 138 // On stack-alignment architectures, any padding is popped off after the last 139 // register. This the behaviour of Push, which means that the above code still 140 // works even if the number of registers doesn't match stack alignment. 141 template <typename... T> 142 inline void Pop(T... registers); 143 144 inline void CallBuiltin(Builtin builtin); 145 inline void TailCallBuiltin(Builtin builtin); 146 inline void CallRuntime(Runtime::FunctionId function, int nargs); 147 148 inline void LoadTaggedPointerField(Register output, Register source, 149 int offset); 150 inline void LoadTaggedSignedField(Register output, Register source, 151 int offset); 152 inline void LoadTaggedAnyField(Register output, Register source, int offset); 153 inline void LoadByteField(Register output, Register source, int offset); 154 inline void StoreTaggedSignedField(Register target, int offset, Smi value); 155 inline void StoreTaggedFieldWithWriteBarrier(Register target, int offset, 156 Register value); 157 inline void StoreTaggedFieldNoWriteBarrier(Register target, int offset, 158 Register value); 159 inline void LoadFixedArrayElement(Register output, Register array, 160 int32_t index); 161 inline void LoadPrototype(Register prototype, Register object); 162 163 // Loads the feedback cell from the function, and sets flags on add so that 164 // we can compare afterward. 165 inline void AddToInterruptBudgetAndJumpIfNotExceeded( 166 int32_t weight, Label* skip_interrupt_label); 167 inline void AddToInterruptBudgetAndJumpIfNotExceeded( 168 Register weight, Label* skip_interrupt_label); 169 170 inline void AddSmi(Register lhs, Smi rhs); 171 inline void SmiUntag(Register value); 172 inline void SmiUntag(Register output, Register value); 173 174 inline void Switch(Register reg, int case_value_base, Label** labels, 175 int num_labels); 176 177 // Register operands. 178 inline void LoadRegister(Register output, interpreter::Register source); 179 inline void StoreRegister(interpreter::Register output, Register value); 180 181 // Frame values 182 inline void LoadFunction(Register output); 183 inline void LoadContext(Register output); 184 inline void StoreContext(Register context); 185 186 inline static void EmitReturn(MacroAssembler* masm); 187 masm()188 MacroAssembler* masm() { return masm_; } 189 190 private: 191 MacroAssembler* masm_; 192 ScratchRegisterScope* scratch_register_scope_ = nullptr; 193 }; 194 195 class SaveAccumulatorScope final { 196 public: 197 inline explicit SaveAccumulatorScope(BaselineAssembler* assembler); 198 199 inline ~SaveAccumulatorScope(); 200 201 private: 202 BaselineAssembler* assembler_; 203 }; 204 205 class EnsureAccumulatorPreservedScope final { 206 public: 207 inline explicit EnsureAccumulatorPreservedScope(BaselineAssembler* assembler); 208 209 inline ~EnsureAccumulatorPreservedScope(); 210 211 private: 212 inline void AssertEqualToAccumulator(Register reg); 213 214 BaselineAssembler* assembler_; 215 #ifdef V8_CODE_COMMENTS 216 Assembler::CodeComment comment_; 217 #endif 218 }; 219 220 } // namespace baseline 221 } // namespace internal 222 } // namespace v8 223 224 #endif 225 226 #endif // V8_BASELINE_BASELINE_ASSEMBLER_H_ 227