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