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/MacroAssembler-inl.h"
13
14 namespace js {
15 namespace jit {
16
IsConstant(const LInt64Allocation & a)17 static inline bool IsConstant(const LInt64Allocation& a) {
18 #if JS_BITS_PER_WORD == 32
19 if (a.high().isConstantValue()) {
20 return true;
21 }
22 if (a.high().isConstantIndex()) {
23 return true;
24 }
25 #else
26 if (a.value().isConstantValue()) {
27 return true;
28 }
29 if (a.value().isConstantIndex()) {
30 return true;
31 }
32 #endif
33 return false;
34 }
35
ToInt32(const LAllocation * a)36 static inline int32_t ToInt32(const LAllocation* a) {
37 if (a->isConstantValue()) {
38 return a->toConstant()->toInt32();
39 }
40 if (a->isConstantIndex()) {
41 return a->toConstantIndex()->index();
42 }
43 MOZ_CRASH("this is not a constant!");
44 }
45
ToInt64(const LAllocation * a)46 static inline int64_t ToInt64(const LAllocation* a) {
47 if (a->isConstantValue()) {
48 return a->toConstant()->toInt64();
49 }
50 if (a->isConstantIndex()) {
51 return a->toConstantIndex()->index();
52 }
53 MOZ_CRASH("this is not a constant!");
54 }
55
ToInt64(const LInt64Allocation & a)56 static inline int64_t ToInt64(const LInt64Allocation& a) {
57 #if JS_BITS_PER_WORD == 32
58 if (a.high().isConstantValue()) {
59 return a.high().toConstant()->toInt64();
60 }
61 if (a.high().isConstantIndex()) {
62 return a.high().toConstantIndex()->index();
63 }
64 #else
65 if (a.value().isConstantValue()) {
66 return a.value().toConstant()->toInt64();
67 }
68 if (a.value().isConstantIndex()) {
69 return a.value().toConstantIndex()->index();
70 }
71 #endif
72 MOZ_CRASH("this is not a constant!");
73 }
74
ToDouble(const LAllocation * a)75 static inline double ToDouble(const LAllocation* a) {
76 return a->toConstant()->numberToDouble();
77 }
78
ToBoolean(const LAllocation * a)79 static inline bool ToBoolean(const LAllocation* a) {
80 return a->toConstant()->toBoolean();
81 }
82
ToRegister(const LAllocation & a)83 static inline Register ToRegister(const LAllocation& a) {
84 MOZ_ASSERT(a.isGeneralReg());
85 return a.toGeneralReg()->reg();
86 }
87
ToRegister(const LAllocation * a)88 static inline Register ToRegister(const LAllocation* a) {
89 return ToRegister(*a);
90 }
91
ToRegister(const LDefinition * def)92 static inline Register ToRegister(const LDefinition* def) {
93 return ToRegister(*def->output());
94 }
95
ToOutRegister64(LInstruction * ins)96 static inline Register64 ToOutRegister64(LInstruction* ins) {
97 #if JS_BITS_PER_WORD == 32
98 Register loReg = ToRegister(ins->getDef(INT64LOW_INDEX));
99 Register hiReg = ToRegister(ins->getDef(INT64HIGH_INDEX));
100 return Register64(hiReg, loReg);
101 #else
102 return Register64(ToRegister(ins->getDef(0)));
103 #endif
104 }
105
ToRegister64(const LInt64Allocation & a)106 static inline Register64 ToRegister64(const LInt64Allocation& a) {
107 #if JS_BITS_PER_WORD == 32
108 return Register64(ToRegister(a.high()), ToRegister(a.low()));
109 #else
110 return Register64(ToRegister(a.value()));
111 #endif
112 }
113
ToRegister64(const LInt64Definition & a)114 static inline Register64 ToRegister64(const LInt64Definition& a) {
115 #if JS_BITS_PER_WORD == 32
116 return Register64(ToRegister(a.pointerHigh()), ToRegister(a.pointerLow()));
117 #else
118 return Register64(ToRegister(a.pointer()));
119 #endif
120 }
121
ToTempRegisterOrInvalid(const LDefinition * def)122 static inline Register ToTempRegisterOrInvalid(const LDefinition* def) {
123 if (def->isBogusTemp()) {
124 return InvalidReg;
125 }
126 return ToRegister(def);
127 }
128
ToTempRegister64OrInvalid(const LInt64Definition & def)129 static inline Register64 ToTempRegister64OrInvalid(
130 const LInt64Definition& def) {
131 if (def.isBogusTemp()) {
132 return Register64::Invalid();
133 }
134 return ToRegister64(def);
135 }
136
ToTempUnboxRegister(const LDefinition * def)137 static inline Register ToTempUnboxRegister(const LDefinition* def) {
138 return ToTempRegisterOrInvalid(def);
139 }
140
ToRegisterOrInvalid(const LDefinition * a)141 static inline Register ToRegisterOrInvalid(const LDefinition* a) {
142 return a ? ToRegister(a) : InvalidReg;
143 }
144
ToFloatRegister(const LAllocation & a)145 static inline FloatRegister ToFloatRegister(const LAllocation& a) {
146 MOZ_ASSERT(a.isFloatReg());
147 return a.toFloatReg()->reg();
148 }
149
ToFloatRegister(const LAllocation * a)150 static inline FloatRegister ToFloatRegister(const LAllocation* a) {
151 return ToFloatRegister(*a);
152 }
153
ToFloatRegister(const LDefinition * def)154 static inline FloatRegister ToFloatRegister(const LDefinition* def) {
155 return ToFloatRegister(*def->output());
156 }
157
ToTempFloatRegisterOrInvalid(const LDefinition * def)158 static inline FloatRegister ToTempFloatRegisterOrInvalid(
159 const LDefinition* def) {
160 if (def->isBogusTemp()) {
161 return InvalidFloatReg;
162 }
163 return ToFloatRegister(def);
164 }
165
ToAnyRegister(const LAllocation & a)166 static inline AnyRegister ToAnyRegister(const LAllocation& a) {
167 MOZ_ASSERT(a.isGeneralReg() || a.isFloatReg());
168 if (a.isGeneralReg()) {
169 return AnyRegister(ToRegister(a));
170 }
171 return AnyRegister(ToFloatRegister(a));
172 }
173
ToAnyRegister(const LAllocation * a)174 static inline AnyRegister ToAnyRegister(const LAllocation* a) {
175 return ToAnyRegister(*a);
176 }
177
ToAnyRegister(const LDefinition * def)178 static inline AnyRegister ToAnyRegister(const LDefinition* def) {
179 return ToAnyRegister(def->output());
180 }
181
ToOutValue(LInstruction * ins)182 static inline ValueOperand ToOutValue(LInstruction* ins) {
183 #if defined(JS_NUNBOX32)
184 return ValueOperand(ToRegister(ins->getDef(TYPE_INDEX)),
185 ToRegister(ins->getDef(PAYLOAD_INDEX)));
186 #elif defined(JS_PUNBOX64)
187 return ValueOperand(ToRegister(ins->getDef(0)));
188 #else
189 # error "Unknown"
190 #endif
191 }
192
GetTempValue(Register type,Register payload)193 static inline ValueOperand GetTempValue(Register type, Register payload) {
194 #if defined(JS_NUNBOX32)
195 return ValueOperand(type, payload);
196 #elif defined(JS_PUNBOX64)
197 (void)type;
198 return ValueOperand(payload);
199 #else
200 # error "Unknown"
201 #endif
202 }
203
ArgToStackOffset(int32_t slot)204 int32_t CodeGeneratorShared::ArgToStackOffset(int32_t slot) const {
205 return masm.framePushed() +
206 (gen->compilingWasm() ? sizeof(wasm::Frame) : sizeof(JitFrameLayout)) +
207 slot;
208 }
209
SlotToStackOffset(int32_t slot)210 int32_t CodeGeneratorShared::SlotToStackOffset(int32_t slot) const {
211 MOZ_ASSERT(slot > 0 && slot <= int32_t(graph.localSlotCount()));
212 int32_t offset = masm.framePushed() - slot;
213 MOZ_ASSERT(offset >= 0);
214 return offset;
215 }
216
StackOffsetToSlot(int32_t offset)217 int32_t CodeGeneratorShared::StackOffsetToSlot(int32_t offset) const {
218 // See: SlotToStackOffset. This is used to convert pushed arguments
219 // to a slot index that safepoints can use.
220 //
221 // offset = framePushed - frameInitialAdjustment - slot
222 // offset + slot = framePushed - frameInitialAdjustment
223 // slot = framePushed - frameInitialAdjustement - offset
224 return masm.framePushed() - offset;
225 }
226
227 // For argument construction for calls. Argslots are Value-sized.
StackOffsetOfPassedArg(int32_t slot)228 int32_t CodeGeneratorShared::StackOffsetOfPassedArg(int32_t slot) const {
229 // A slot of 0 is permitted only to calculate %esp offset for calls.
230 MOZ_ASSERT(slot >= 0 && slot <= int32_t(graph.argumentSlotCount()));
231 int32_t offset = masm.framePushed() - graph.paddedLocalSlotsSize() -
232 (slot * sizeof(Value));
233
234 // Passed arguments go below A function's local stack storage.
235 // When arguments are being pushed, there is nothing important on the stack.
236 // Therefore, It is safe to push the arguments down arbitrarily. Pushing
237 // by sizeof(Value) is desirable since everything on the stack is a Value.
238 // Note that paddedLocalSlotCount() aligns to at least a Value boundary
239 // specifically to support this.
240 MOZ_ASSERT(offset >= 0);
241 MOZ_ASSERT(offset % sizeof(Value) == 0);
242 return offset;
243 }
244
ToStackOffset(LAllocation a)245 int32_t CodeGeneratorShared::ToStackOffset(LAllocation a) const {
246 if (a.isArgument()) {
247 return ArgToStackOffset(a.toArgument()->index());
248 }
249 return SlotToStackOffset(a.isStackSlot() ? a.toStackSlot()->slot()
250 : a.toStackArea()->base());
251 }
252
ToStackOffset(const LAllocation * a)253 int32_t CodeGeneratorShared::ToStackOffset(const LAllocation* a) const {
254 return ToStackOffset(*a);
255 }
256
ToAddress(const LAllocation & a)257 Address CodeGeneratorShared::ToAddress(const LAllocation& a) const {
258 MOZ_ASSERT(a.isMemory() || a.isStackArea());
259 if (useWasmStackArgumentAbi() && a.isArgument()) {
260 return Address(FramePointer, ToFramePointerOffset(a));
261 }
262 return Address(masm.getStackPointer(), ToStackOffset(&a));
263 }
264
ToAddress(const LAllocation * a)265 Address CodeGeneratorShared::ToAddress(const LAllocation* a) const {
266 return ToAddress(*a);
267 }
268
ToFramePointerOffset(LAllocation a)269 int32_t CodeGeneratorShared::ToFramePointerOffset(LAllocation a) const {
270 MOZ_ASSERT(useWasmStackArgumentAbi());
271 MOZ_ASSERT(a.isArgument());
272 return a.toArgument()->index() + sizeof(wasm::Frame);
273 }
274
ToFramePointerOffset(const LAllocation * a)275 int32_t CodeGeneratorShared::ToFramePointerOffset(const LAllocation* a) const {
276 return ToFramePointerOffset(*a);
277 }
278
saveLive(LInstruction * ins)279 void CodeGeneratorShared::saveLive(LInstruction* ins) {
280 MOZ_ASSERT(!ins->isCall());
281 LSafepoint* safepoint = ins->safepoint();
282 masm.PushRegsInMask(safepoint->liveRegs());
283 }
284
restoreLive(LInstruction * ins)285 void CodeGeneratorShared::restoreLive(LInstruction* ins) {
286 MOZ_ASSERT(!ins->isCall());
287 LSafepoint* safepoint = ins->safepoint();
288 masm.PopRegsInMask(safepoint->liveRegs());
289 }
290
restoreLiveIgnore(LInstruction * ins,LiveRegisterSet ignore)291 void CodeGeneratorShared::restoreLiveIgnore(LInstruction* ins,
292 LiveRegisterSet ignore) {
293 MOZ_ASSERT(!ins->isCall());
294 LSafepoint* safepoint = ins->safepoint();
295 masm.PopRegsInMaskIgnore(safepoint->liveRegs(), ignore);
296 }
297
saveLiveVolatile(LInstruction * ins)298 void CodeGeneratorShared::saveLiveVolatile(LInstruction* ins) {
299 MOZ_ASSERT(!ins->isCall());
300 LSafepoint* safepoint = ins->safepoint();
301 LiveRegisterSet regs;
302 regs.set() = RegisterSet::Intersect(safepoint->liveRegs().set(),
303 RegisterSet::Volatile());
304 masm.PushRegsInMask(regs);
305 }
306
restoreLiveVolatile(LInstruction * ins)307 void CodeGeneratorShared::restoreLiveVolatile(LInstruction* ins) {
308 MOZ_ASSERT(!ins->isCall());
309 LSafepoint* safepoint = ins->safepoint();
310 LiveRegisterSet regs;
311 regs.set() = RegisterSet::Intersect(safepoint->liveRegs().set(),
312 RegisterSet::Volatile());
313 masm.PopRegsInMask(regs);
314 }
315
isGlobalObject(JSObject * object)316 inline bool CodeGeneratorShared::isGlobalObject(JSObject* object) {
317 // Calling object->is<GlobalObject>() is racy because this relies on
318 // checking the group and this can be changed while we are compiling off the
319 // main thread. Note that we only check for the script realm's global here.
320 return object == gen->realm->maybeGlobal();
321 }
322
323 } // namespace jit
324 } // namespace js
325
326 #endif /* jit_shared_CodeGenerator_shared_inl_h */
327