Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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 : #include "jit/Disassembler.h"
12 :
13 : #include "jit/MacroAssembler-inl.h"
14 :
15 : namespace js {
16 : namespace jit {
17 :
18 : static inline bool
19 0 : IsConstant(const LInt64Allocation& a)
20 : {
21 : #if JS_BITS_PER_WORD == 32
22 : if (a.high().isConstantValue())
23 : return true;
24 : if (a.high().isConstantIndex())
25 : return true;
26 : #else
27 0 : if (a.value().isConstantValue())
28 0 : return true;
29 0 : if (a.value().isConstantIndex())
30 0 : return true;
31 : #endif
32 0 : return false;
33 : }
34 :
35 : static inline int32_t
36 64 : ToInt32(const LAllocation* a)
37 : {
38 64 : if (a->isConstantValue())
39 64 : return a->toConstant()->toInt32();
40 0 : if (a->isConstantIndex())
41 0 : return a->toConstantIndex()->index();
42 0 : MOZ_CRASH("this is not a constant!");
43 : }
44 :
45 : static inline int64_t
46 : ToInt64(const LAllocation* a)
47 : {
48 : if (a->isConstantValue())
49 : return a->toConstant()->toInt64();
50 : if (a->isConstantIndex())
51 : return a->toConstantIndex()->index();
52 : MOZ_CRASH("this is not a constant!");
53 : }
54 :
55 : static inline int64_t
56 0 : ToInt64(const LInt64Allocation& a)
57 : {
58 : #if JS_BITS_PER_WORD == 32
59 : if (a.high().isConstantValue())
60 : return a.high().toConstant()->toInt64();
61 : if (a.high().isConstantIndex())
62 : return a.high().toConstantIndex()->index();
63 : #else
64 0 : if (a.value().isConstantValue())
65 0 : return a.value().toConstant()->toInt64();
66 0 : if (a.value().isConstantIndex())
67 0 : return a.value().toConstantIndex()->index();
68 : #endif
69 0 : MOZ_CRASH("this is not a constant!");
70 : }
71 :
72 : static inline double
73 : ToDouble(const LAllocation* a)
74 : {
75 : return a->toConstant()->numberToDouble();
76 : }
77 :
78 : static inline Register
79 3185 : ToRegister(const LAllocation& a)
80 : {
81 3185 : MOZ_ASSERT(a.isGeneralReg());
82 3185 : return a.toGeneralReg()->reg();
83 : }
84 :
85 : static inline Register
86 1455 : ToRegister(const LAllocation* a)
87 : {
88 1455 : return ToRegister(*a);
89 : }
90 :
91 : static inline Register
92 1090 : ToRegister(const LDefinition* def)
93 : {
94 1090 : return ToRegister(*def->output());
95 : }
96 :
97 : static inline Register64
98 0 : ToOutRegister64(LInstruction* ins)
99 : {
100 : #if JS_BITS_PER_WORD == 32
101 : Register loReg = ToRegister(ins->getDef(INT64LOW_INDEX));
102 : Register hiReg = ToRegister(ins->getDef(INT64HIGH_INDEX));
103 : return Register64(hiReg, loReg);
104 : #else
105 0 : return Register64(ToRegister(ins->getDef(0)));
106 : #endif
107 : }
108 :
109 : static inline Register64
110 0 : ToRegister64(const LInt64Allocation& a)
111 : {
112 : #if JS_BITS_PER_WORD == 32
113 : return Register64(ToRegister(a.high()), ToRegister(a.low()));
114 : #else
115 0 : return Register64(ToRegister(a.value()));
116 : #endif
117 : }
118 :
119 : static inline Register
120 70 : ToTempRegisterOrInvalid(const LDefinition* def)
121 : {
122 70 : if (def->isBogusTemp())
123 0 : return InvalidReg;
124 70 : return ToRegister(def);
125 : }
126 :
127 : static inline Register
128 0 : ToTempUnboxRegister(const LDefinition* def)
129 : {
130 0 : return ToTempRegisterOrInvalid(def);
131 : }
132 :
133 : static inline Register
134 0 : ToRegisterOrInvalid(const LDefinition* a)
135 : {
136 0 : return a ? ToRegister(a) : InvalidReg;
137 : }
138 :
139 : static inline FloatRegister
140 49 : ToFloatRegister(const LAllocation& a)
141 : {
142 49 : MOZ_ASSERT(a.isFloatReg());
143 49 : return a.toFloatReg()->reg();
144 : }
145 :
146 : static inline FloatRegister
147 2 : ToFloatRegister(const LAllocation* a)
148 : {
149 2 : return ToFloatRegister(*a);
150 : }
151 :
152 : static inline FloatRegister
153 46 : ToFloatRegister(const LDefinition* def)
154 : {
155 46 : return ToFloatRegister(*def->output());
156 : }
157 :
158 : static inline FloatRegister
159 12 : ToTempFloatRegisterOrInvalid(const LDefinition* def)
160 : {
161 12 : if (def->isBogusTemp())
162 0 : return InvalidFloatReg;
163 12 : return ToFloatRegister(def);
164 : }
165 :
166 : static inline AnyRegister
167 75 : ToAnyRegister(const LAllocation& a)
168 : {
169 75 : MOZ_ASSERT(a.isGeneralReg() || a.isFloatReg());
170 75 : if (a.isGeneralReg())
171 74 : return AnyRegister(ToRegister(a));
172 1 : return AnyRegister(ToFloatRegister(a));
173 : }
174 :
175 : static inline AnyRegister
176 75 : ToAnyRegister(const LAllocation* a)
177 : {
178 75 : return ToAnyRegister(*a);
179 : }
180 :
181 : static inline AnyRegister
182 20 : ToAnyRegister(const LDefinition* def)
183 : {
184 20 : return ToAnyRegister(def->output());
185 : }
186 :
187 : static inline RegisterOrInt32Constant
188 6 : ToRegisterOrInt32Constant(const LAllocation* a)
189 : {
190 6 : if (a->isConstant())
191 4 : return RegisterOrInt32Constant(ToInt32(a));
192 2 : return RegisterOrInt32Constant(ToRegister(a));
193 : }
194 :
195 : static inline ValueOperand
196 51 : GetValueOutput(LInstruction* ins)
197 : {
198 : #if defined(JS_NUNBOX32)
199 : return ValueOperand(ToRegister(ins->getDef(TYPE_INDEX)),
200 : ToRegister(ins->getDef(PAYLOAD_INDEX)));
201 : #elif defined(JS_PUNBOX64)
202 51 : return ValueOperand(ToRegister(ins->getDef(0)));
203 : #else
204 : #error "Unknown"
205 : #endif
206 : }
207 :
208 : static inline ValueOperand
209 : GetTempValue(Register type, Register payload)
210 : {
211 : #if defined(JS_NUNBOX32)
212 : return ValueOperand(type, payload);
213 : #elif defined(JS_PUNBOX64)
214 : (void)type;
215 : return ValueOperand(payload);
216 : #else
217 : #error "Unknown"
218 : #endif
219 : }
220 :
221 : int32_t
222 107 : CodeGeneratorShared::ArgToStackOffset(int32_t slot) const
223 : {
224 107 : return masm.framePushed() +
225 214 : (gen->compilingWasm() ? sizeof(wasm::Frame) : sizeof(JitFrameLayout)) +
226 107 : slot;
227 : }
228 :
229 : int32_t
230 539 : CodeGeneratorShared::SlotToStackOffset(int32_t slot) const
231 : {
232 539 : MOZ_ASSERT(slot > 0 && slot <= int32_t(graph.localSlotCount()));
233 539 : int32_t offset = masm.framePushed() - frameInitialAdjustment_ - slot;
234 539 : MOZ_ASSERT(offset >= 0);
235 539 : return offset;
236 : }
237 :
238 : int32_t
239 : CodeGeneratorShared::StackOffsetToSlot(int32_t offset) const
240 : {
241 : // See: SlotToStackOffset. This is used to convert pushed arguments
242 : // to a slot index that safepoints can use.
243 : //
244 : // offset = framePushed - frameInitialAdjustment - slot
245 : // offset + slot = framePushed - frameInitialAdjustment
246 : // slot = framePushed - frameInitialAdjustement - offset
247 : return masm.framePushed() - frameInitialAdjustment_ - offset;
248 : }
249 :
250 : // For argument construction for calls. Argslots are Value-sized.
251 : int32_t
252 98 : CodeGeneratorShared::StackOffsetOfPassedArg(int32_t slot) const
253 : {
254 : // A slot of 0 is permitted only to calculate %esp offset for calls.
255 98 : MOZ_ASSERT(slot >= 0 && slot <= int32_t(graph.argumentSlotCount()));
256 196 : int32_t offset = masm.framePushed() -
257 196 : graph.paddedLocalSlotsSize() -
258 98 : (slot * sizeof(Value));
259 :
260 : // Passed arguments go below A function's local stack storage.
261 : // When arguments are being pushed, there is nothing important on the stack.
262 : // Therefore, It is safe to push the arguments down arbitrarily. Pushing
263 : // by sizeof(Value) is desirable since everything on the stack is a Value.
264 : // Note that paddedLocalSlotCount() aligns to at least a Value boundary
265 : // specifically to support this.
266 98 : MOZ_ASSERT(offset >= 0);
267 98 : MOZ_ASSERT(offset % sizeof(Value) == 0);
268 98 : return offset;
269 : }
270 :
271 : int32_t
272 574 : CodeGeneratorShared::ToStackOffset(LAllocation a) const
273 : {
274 574 : if (a.isArgument())
275 35 : return ArgToStackOffset(a.toArgument()->index());
276 539 : return SlotToStackOffset(a.toStackSlot()->slot());
277 : }
278 :
279 : int32_t
280 32 : CodeGeneratorShared::ToStackOffset(const LAllocation* a) const
281 : {
282 32 : return ToStackOffset(*a);
283 : }
284 :
285 : Address
286 0 : CodeGeneratorShared::ToAddress(const LAllocation& a)
287 : {
288 0 : MOZ_ASSERT(a.isMemory());
289 0 : return Address(masm.getStackPointer(), ToStackOffset(&a));
290 : }
291 :
292 : Address
293 0 : CodeGeneratorShared::ToAddress(const LAllocation* a)
294 : {
295 0 : return ToAddress(*a);
296 : }
297 :
298 : void
299 91 : CodeGeneratorShared::saveLive(LInstruction* ins)
300 : {
301 91 : MOZ_ASSERT(!ins->isCall());
302 91 : LSafepoint* safepoint = ins->safepoint();
303 91 : masm.PushRegsInMask(safepoint->liveRegs());
304 91 : }
305 :
306 : void
307 18 : CodeGeneratorShared::restoreLive(LInstruction* ins)
308 : {
309 18 : MOZ_ASSERT(!ins->isCall());
310 18 : LSafepoint* safepoint = ins->safepoint();
311 18 : masm.PopRegsInMask(safepoint->liveRegs());
312 18 : }
313 :
314 : void
315 73 : CodeGeneratorShared::restoreLiveIgnore(LInstruction* ins, LiveRegisterSet ignore)
316 : {
317 73 : MOZ_ASSERT(!ins->isCall());
318 73 : LSafepoint* safepoint = ins->safepoint();
319 73 : masm.PopRegsInMaskIgnore(safepoint->liveRegs(), ignore);
320 73 : }
321 :
322 : void
323 2 : CodeGeneratorShared::saveLiveVolatile(LInstruction* ins)
324 : {
325 2 : MOZ_ASSERT(!ins->isCall());
326 2 : LSafepoint* safepoint = ins->safepoint();
327 2 : LiveRegisterSet regs;
328 2 : regs.set() = RegisterSet::Intersect(safepoint->liveRegs().set(), RegisterSet::Volatile());
329 2 : masm.PushRegsInMask(regs);
330 2 : }
331 :
332 : void
333 2 : CodeGeneratorShared::restoreLiveVolatile(LInstruction* ins)
334 : {
335 2 : MOZ_ASSERT(!ins->isCall());
336 2 : LSafepoint* safepoint = ins->safepoint();
337 2 : LiveRegisterSet regs;
338 2 : regs.set() = RegisterSet::Intersect(safepoint->liveRegs().set(), RegisterSet::Volatile());
339 2 : masm.PopRegsInMask(regs);
340 2 : }
341 :
342 : void
343 0 : CodeGeneratorShared::verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, bool isLoad,
344 : Scalar::Type type, Operand mem, LAllocation alloc)
345 : {
346 : #ifdef DEBUG
347 : using namespace Disassembler;
348 :
349 0 : Disassembler::HeapAccess::Kind kind = isLoad ? HeapAccess::Load : HeapAccess::Store;
350 0 : switch (type) {
351 : case Scalar::Int8:
352 : case Scalar::Int16:
353 0 : if (kind == HeapAccess::Load)
354 0 : kind = HeapAccess::LoadSext32;
355 0 : break;
356 : default:
357 0 : break;
358 : }
359 :
360 0 : OtherOperand op;
361 0 : switch (type) {
362 : case Scalar::Int8:
363 : case Scalar::Uint8:
364 : case Scalar::Int16:
365 : case Scalar::Uint16:
366 : case Scalar::Int32:
367 : case Scalar::Uint32:
368 0 : if (!alloc.isConstant()) {
369 0 : op = OtherOperand(ToRegister(alloc).encoding());
370 : } else {
371 : // x86 doesn't allow encoding an imm64 to memory move; the value
372 : // is wrapped anyways.
373 0 : int32_t i = ToInt32(&alloc);
374 :
375 : // Sign-extend the immediate value out to 32 bits. We do this even
376 : // for unsigned element types so that we match what the disassembly
377 : // code does, as it doesn't know about signedness of stores.
378 0 : unsigned shift = 32 - TypedArrayElemSize(type) * 8;
379 0 : i = i << shift >> shift;
380 0 : op = OtherOperand(i);
381 : }
382 0 : break;
383 : case Scalar::Int64:
384 : // Can't encode an imm64-to-memory move.
385 0 : op = OtherOperand(ToRegister(alloc).encoding());
386 0 : break;
387 : case Scalar::Float32:
388 : case Scalar::Float64:
389 : case Scalar::Float32x4:
390 : case Scalar::Int8x16:
391 : case Scalar::Int16x8:
392 : case Scalar::Int32x4:
393 0 : op = OtherOperand(ToFloatRegister(alloc).encoding());
394 0 : break;
395 : case Scalar::Uint8Clamped:
396 : case Scalar::MaxTypedArrayViewType:
397 0 : MOZ_CRASH("Unexpected array type");
398 : }
399 :
400 0 : HeapAccess access(kind, TypedArrayElemSize(type), ComplexAddress(mem), op);
401 0 : masm.verifyHeapAccessDisassembly(begin, end, access);
402 : #endif
403 0 : }
404 :
405 : void
406 0 : CodeGeneratorShared::verifyLoadDisassembly(uint32_t begin, uint32_t end, Scalar::Type type,
407 : Operand mem, LAllocation alloc)
408 : {
409 0 : verifyHeapAccessDisassembly(begin, end, true, type, mem, alloc);
410 0 : }
411 :
412 : void
413 0 : CodeGeneratorShared::verifyStoreDisassembly(uint32_t begin, uint32_t end, Scalar::Type type,
414 : Operand mem, LAllocation alloc)
415 : {
416 0 : verifyHeapAccessDisassembly(begin, end, false, type, mem, alloc);
417 0 : }
418 :
419 : inline bool
420 0 : CodeGeneratorShared::isGlobalObject(JSObject* object)
421 : {
422 : // Calling object->is<GlobalObject>() is racy because this relies on
423 : // checking the group and this can be changed while we are compiling off the
424 : // main thread.
425 0 : return object == gen->compartment->maybeGlobal();
426 : }
427 :
428 : } // namespace jit
429 : } // namespace js
430 :
431 : #endif /* jit_shared_CodeGenerator_shared_inl_h */
|