CodeGenerator-shared-inl.h (10884B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_shared_CodeGenerator_shared_inl_h 8 #define jit_shared_CodeGenerator_shared_inl_h 9 10 #include "jit/shared/CodeGenerator-shared.h" 11 12 #include "jit/JitFrames.h" 13 #include "jit/ScalarTypeUtils.h" 14 15 #include "jit/MacroAssembler-inl.h" 16 17 namespace js { 18 namespace jit { 19 20 static inline bool IsConstant(const LInt64Allocation& a) { 21 #if JS_BITS_PER_WORD == 32 22 if (a.high().isConstantValue()) { 23 return true; 24 } 25 if (a.high().isConstantIndex()) { 26 return true; 27 } 28 #else 29 if (a.value().isConstantValue()) { 30 return true; 31 } 32 if (a.value().isConstantIndex()) { 33 return true; 34 } 35 #endif 36 return false; 37 } 38 39 static inline int32_t ToInt32(const LAllocation* a) { 40 if (a->isConstantValue()) { 41 const MConstant* cst = a->toConstant(); 42 if (cst->type() == MIRType::Int32) { 43 return cst->toInt32(); 44 } 45 intptr_t val = cst->toIntPtr(); 46 MOZ_ASSERT(INT32_MIN <= val && val <= INT32_MAX); 47 return int32_t(val); 48 } 49 if (a->isConstantIndex()) { 50 return a->toConstantIndex()->index(); 51 } 52 MOZ_CRASH("this is not a constant!"); 53 } 54 55 static inline intptr_t ToIntPtr(const LAllocation* a) { 56 if (a->isConstantValue()) { 57 const MConstant* cst = a->toConstant(); 58 if (cst->type() == MIRType::Int32) { 59 return cst->toInt32(); 60 } 61 return cst->toIntPtr(); 62 } 63 if (a->isConstantIndex()) { 64 return a->toConstantIndex()->index(); 65 } 66 MOZ_CRASH("this is not a constant!"); 67 } 68 69 static inline int64_t ToInt64(const LAllocation* a) { 70 if (a->isConstantValue()) { 71 return a->toConstant()->toInt64(); 72 } 73 if (a->isConstantIndex()) { 74 return a->toConstantIndex()->index(); 75 } 76 MOZ_CRASH("this is not a constant!"); 77 } 78 79 static inline int64_t ToInt64(const LInt64Allocation& a) { 80 #if JS_BITS_PER_WORD == 32 81 if (a.high().isConstantValue()) { 82 return a.high().toConstant()->toInt64(); 83 } 84 if (a.high().isConstantIndex()) { 85 return a.high().toConstantIndex()->index(); 86 } 87 #else 88 if (a.value().isConstantValue()) { 89 return a.value().toConstant()->toInt64(); 90 } 91 if (a.value().isConstantIndex()) { 92 return a.value().toConstantIndex()->index(); 93 } 94 #endif 95 MOZ_CRASH("this is not a constant!"); 96 } 97 98 static inline double ToDouble(const LAllocation* a) { 99 return a->toConstant()->numberToDouble(); 100 } 101 102 static inline bool ToBoolean(const LAllocation* a) { 103 return a->toConstant()->toBoolean(); 104 } 105 106 static inline Register ToRegister(const LAllocation& a) { 107 MOZ_ASSERT(a.isGeneralReg()); 108 return a.toGeneralReg()->reg(); 109 } 110 111 static inline Register ToRegister(const LAllocation* a) { 112 return ToRegister(*a); 113 } 114 115 static inline Register ToRegister(const LDefinition* def) { 116 return ToRegister(*def->output()); 117 } 118 119 static inline Register64 ToOutRegister64(LInstruction* ins) { 120 #if JS_BITS_PER_WORD == 32 121 Register loReg = ToRegister(ins->getDef(INT64LOW_INDEX)); 122 Register hiReg = ToRegister(ins->getDef(INT64HIGH_INDEX)); 123 return Register64(hiReg, loReg); 124 #else 125 return Register64(ToRegister(ins->getDef(0))); 126 #endif 127 } 128 129 static inline bool IsRegister64(const LInt64Allocation& a) { 130 #if JS_BITS_PER_WORD == 32 131 MOZ_ASSERT(a.low().isGeneralReg() == a.high().isGeneralReg()); 132 return a.low().isGeneralReg(); 133 #else 134 return a.value().isGeneralReg(); 135 #endif 136 } 137 138 static inline Register64 ToRegister64(const LInt64Allocation& a) { 139 #if JS_BITS_PER_WORD == 32 140 return Register64(ToRegister(a.high()), ToRegister(a.low())); 141 #else 142 return Register64(ToRegister(a.value())); 143 #endif 144 } 145 146 static inline Register64 ToRegister64(const LInt64Definition& a) { 147 #if JS_BITS_PER_WORD == 32 148 return Register64(ToRegister(a.pointerHigh()), ToRegister(a.pointerLow())); 149 #else 150 return Register64(ToRegister(a.pointer())); 151 #endif 152 } 153 154 static inline Register ToTempRegisterOrInvalid(const LDefinition* def) { 155 if (def->isBogusTemp()) { 156 return InvalidReg; 157 } 158 return ToRegister(def); 159 } 160 161 static inline Register64 ToTempRegister64OrInvalid( 162 const LInt64Definition& def) { 163 if (def.isBogusTemp()) { 164 return Register64::Invalid(); 165 } 166 return ToRegister64(def); 167 } 168 169 static inline Register ToTempUnboxRegister(const LDefinition* def) { 170 return ToTempRegisterOrInvalid(def); 171 } 172 173 static inline FloatRegister ToFloatRegister(const LAllocation& a) { 174 MOZ_ASSERT(a.isFloatReg()); 175 return a.toFloatReg()->reg(); 176 } 177 178 static inline FloatRegister ToFloatRegister(const LAllocation* a) { 179 return ToFloatRegister(*a); 180 } 181 182 static inline FloatRegister ToFloatRegister(const LDefinition* def) { 183 return ToFloatRegister(*def->output()); 184 } 185 186 static inline FloatRegister ToTempFloatRegisterOrInvalid( 187 const LDefinition* def) { 188 if (def->isBogusTemp()) { 189 return InvalidFloatReg; 190 } 191 return ToFloatRegister(def); 192 } 193 194 static inline AnyRegister ToAnyRegister(const LAllocation& a) { 195 MOZ_ASSERT(a.isGeneralReg() || a.isFloatReg()); 196 if (a.isGeneralReg()) { 197 return AnyRegister(ToRegister(a)); 198 } 199 return AnyRegister(ToFloatRegister(a)); 200 } 201 202 static inline AnyRegister ToAnyRegister(const LAllocation* a) { 203 return ToAnyRegister(*a); 204 } 205 206 static inline AnyRegister ToAnyRegister(const LDefinition* def) { 207 return ToAnyRegister(def->output()); 208 } 209 210 static inline ValueOperand ToOutValue(LInstruction* ins) { 211 #if defined(JS_NUNBOX32) 212 return ValueOperand(ToRegister(ins->getDef(TYPE_INDEX)), 213 ToRegister(ins->getDef(PAYLOAD_INDEX))); 214 #elif defined(JS_PUNBOX64) 215 return ValueOperand(ToRegister(ins->getDef(0))); 216 #else 217 # error "Unknown" 218 #endif 219 } 220 221 static inline ValueOperand ToValue(const LBoxAllocation& a) { 222 #if defined(JS_NUNBOX32) 223 return ValueOperand(ToRegister(a.type()), ToRegister(a.payload())); 224 #elif defined(JS_PUNBOX64) 225 return ValueOperand(ToRegister(a.value())); 226 #else 227 # error "Unknown" 228 #endif 229 } 230 231 // For argument construction for calls. Argslots are Value-sized. 232 Address CodeGeneratorShared::AddressOfPassedArg(uint32_t slot) const { 233 MOZ_ASSERT(masm.framePushed() == frameSize()); 234 235 MOZ_ASSERT(slot > 0); 236 MOZ_ASSERT(slot <= graph.argumentSlotCount()); 237 238 uint32_t offsetFromBase = offsetOfPassedArgSlots_ + slot * sizeof(Value); 239 MOZ_ASSERT(offsetFromBase <= frameSize()); 240 241 // Space for passed arguments is reserved below a function's local stack 242 // storage. Note that passedArgSlotsOffset_ is aligned to at least 243 // sizeof(Value) to ensure proper alignment. 244 MOZ_ASSERT((offsetFromBase % sizeof(Value)) == 0); 245 246 if (JitOptions.baseRegForLocals == BaseRegForAddress::SP) { 247 return Address(masm.getStackPointer(), frameSize() - offsetFromBase); 248 } 249 MOZ_ASSERT(JitOptions.baseRegForLocals == BaseRegForAddress::FP); 250 return Address(FramePointer, -int32_t(offsetFromBase)); 251 } 252 253 uint32_t CodeGeneratorShared::UnusedStackBytesForCall( 254 uint32_t numArgSlots) const { 255 MOZ_ASSERT(masm.framePushed() == frameSize()); 256 MOZ_ASSERT(numArgSlots <= graph.argumentSlotCount()); 257 uint32_t unusedArgSlots = graph.argumentSlotCount() - numArgSlots; 258 return unusedArgSlots * sizeof(Value); 259 } 260 261 template <BaseRegForAddress Base> 262 Address CodeGeneratorShared::ToAddress(const LAllocation& a) const { 263 MOZ_ASSERT(a.isMemory() || a.isStackArea()); 264 MOZ_ASSERT(masm.framePushed() == frameSize()); 265 266 if (a.isArgument()) { 267 // Use the frame pointer, unless the caller explicitly requested a 268 // stack-pointer-relative address. 269 uint32_t offsetFromFP = offsetOfArgsFromFP_ + a.toArgument()->index(); 270 if constexpr (Base == BaseRegForAddress::SP) { 271 return Address(masm.getStackPointer(), frameSize() + offsetFromFP); 272 } else { 273 static_assert(Base == BaseRegForAddress::Default || 274 Base == BaseRegForAddress::FP); 275 return Address(FramePointer, offsetFromFP); 276 } 277 } 278 279 uint32_t slot = 280 a.isStackSlot() ? a.toStackSlot()->slot() : a.toStackArea()->base(); 281 MOZ_ASSERT(slot > 0 && slot <= graph.localSlotsSize()); 282 MOZ_ASSERT(slot <= frameSize()); 283 284 BaseRegForAddress base = Base; 285 if constexpr (Base == BaseRegForAddress::Default) { 286 base = JitOptions.baseRegForLocals; 287 } 288 289 if (base == BaseRegForAddress::FP) { 290 return Address(FramePointer, -int32_t(slot)); 291 } 292 MOZ_ASSERT(base == BaseRegForAddress::SP); 293 return Address(masm.getStackPointer(), frameSize() - slot); 294 } 295 296 template <BaseRegForAddress Base> 297 Address CodeGeneratorShared::ToAddress(const LAllocation* a) const { 298 return ToAddress<Base>(*a); 299 } 300 301 template <BaseRegForAddress Base> 302 Address CodeGeneratorShared::ToAddress(const LInt64Allocation& a) const { 303 #if JS_BITS_PER_WORD == 32 304 Address low = ToAddress<Base>(a.low()); 305 MOZ_ASSERT(HighWord(low) == ToAddress<Base>(a.high())); 306 return low; 307 #else 308 return ToAddress<Base>(a.value()); 309 #endif 310 } 311 312 // static 313 Address CodeGeneratorShared::ToAddress(Register elements, 314 const LAllocation* index, 315 Scalar::Type type) { 316 int32_t idx = ToInt32(index); 317 int32_t offset; 318 MOZ_ALWAYS_TRUE(ArrayOffsetFitsInInt32(idx, type, &offset)); 319 return Address(elements, offset); 320 } 321 322 void CodeGeneratorShared::saveLive(LInstruction* ins) { 323 MOZ_ASSERT(!ins->isCall()); 324 LSafepoint* safepoint = ins->safepoint(); 325 masm.PushRegsInMask(safepoint->liveRegs()); 326 } 327 328 void CodeGeneratorShared::restoreLive(LInstruction* ins) { 329 MOZ_ASSERT(!ins->isCall()); 330 LSafepoint* safepoint = ins->safepoint(); 331 masm.PopRegsInMask(safepoint->liveRegs()); 332 } 333 334 void CodeGeneratorShared::restoreLiveIgnore(LInstruction* ins, 335 LiveRegisterSet ignore) { 336 MOZ_ASSERT(!ins->isCall()); 337 LSafepoint* safepoint = ins->safepoint(); 338 masm.PopRegsInMaskIgnore(safepoint->liveRegs(), ignore); 339 } 340 341 LiveRegisterSet CodeGeneratorShared::liveVolatileRegs(LInstruction* ins) { 342 MOZ_ASSERT(!ins->isCall()); 343 LSafepoint* safepoint = ins->safepoint(); 344 LiveRegisterSet regs; 345 regs.set() = RegisterSet::Intersect(safepoint->liveRegs().set(), 346 RegisterSet::Volatile()); 347 return regs; 348 } 349 350 void CodeGeneratorShared::saveLiveVolatile(LInstruction* ins) { 351 LiveRegisterSet regs = liveVolatileRegs(ins); 352 masm.PushRegsInMask(regs); 353 } 354 355 void CodeGeneratorShared::restoreLiveVolatile(LInstruction* ins) { 356 LiveRegisterSet regs = liveVolatileRegs(ins); 357 masm.PopRegsInMask(regs); 358 } 359 360 inline bool CodeGeneratorShared::isGlobalObject(JSObject* object) { 361 // Calling object->is<GlobalObject>() is racy because this relies on 362 // checking the group and this can be changed while we are compiling off the 363 // main thread. Note that we only check for the script realm's global here. 364 return object == gen->realm->maybeGlobal(); 365 } 366 367 } // namespace jit 368 } // namespace js 369 370 #endif /* jit_shared_CodeGenerator_shared_inl_h */