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_MacroAssembler_inl_h
8 : #define jit_MacroAssembler_inl_h
9 :
10 : #include "jit/MacroAssembler.h"
11 :
12 : #include "mozilla/MathAlgorithms.h"
13 :
14 : #if defined(JS_CODEGEN_X86)
15 : # include "jit/x86/MacroAssembler-x86-inl.h"
16 : #elif defined(JS_CODEGEN_X64)
17 : # include "jit/x64/MacroAssembler-x64-inl.h"
18 : #elif defined(JS_CODEGEN_ARM)
19 : # include "jit/arm/MacroAssembler-arm-inl.h"
20 : #elif defined(JS_CODEGEN_ARM64)
21 : # include "jit/arm64/MacroAssembler-arm64-inl.h"
22 : #elif defined(JS_CODEGEN_MIPS32)
23 : # include "jit/mips32/MacroAssembler-mips32-inl.h"
24 : #elif defined(JS_CODEGEN_MIPS64)
25 : # include "jit/mips64/MacroAssembler-mips64-inl.h"
26 : #elif !defined(JS_CODEGEN_NONE)
27 : # error "Unknown architecture!"
28 : #endif
29 :
30 : #include "wasm/WasmBuiltins.h"
31 :
32 : namespace js {
33 : namespace jit {
34 :
35 : //{{{ check_macroassembler_style
36 : // ===============================================================
37 : // Frame manipulation functions.
38 :
39 : uint32_t
40 36357 : MacroAssembler::framePushed() const
41 : {
42 36357 : return framePushed_;
43 : }
44 :
45 : void
46 227976 : MacroAssembler::setFramePushed(uint32_t framePushed)
47 : {
48 227976 : framePushed_ = framePushed;
49 227976 : }
50 :
51 : void
52 226808 : MacroAssembler::adjustFrame(int32_t value)
53 : {
54 226808 : MOZ_ASSERT_IF(value < 0, framePushed_ >= uint32_t(-value));
55 226808 : setFramePushed(framePushed_ + value);
56 226808 : }
57 :
58 : void
59 95038 : MacroAssembler::implicitPop(uint32_t bytes)
60 : {
61 95038 : MOZ_ASSERT(bytes % sizeof(intptr_t) == 0);
62 95038 : MOZ_ASSERT(bytes <= INT32_MAX);
63 95038 : adjustFrame(-int32_t(bytes));
64 95038 : }
65 :
66 : // ===============================================================
67 : // Stack manipulation functions.
68 :
69 : CodeOffset
70 1079 : MacroAssembler::PushWithPatch(ImmWord word)
71 : {
72 1079 : framePushed_ += sizeof(word.value);
73 1079 : return pushWithPatch(word);
74 : }
75 :
76 : CodeOffset
77 0 : MacroAssembler::PushWithPatch(ImmPtr imm)
78 : {
79 0 : return PushWithPatch(ImmWord(uintptr_t(imm.value)));
80 : }
81 :
82 : // ===============================================================
83 : // Simple call functions.
84 :
85 : void
86 0 : MacroAssembler::call(const wasm::CallSiteDesc& desc, const Register reg)
87 : {
88 0 : CodeOffset l = call(reg);
89 0 : append(desc, l);
90 0 : }
91 :
92 : void
93 0 : MacroAssembler::call(const wasm::CallSiteDesc& desc, uint32_t funcDefIndex)
94 : {
95 0 : CodeOffset l = callWithPatch();
96 0 : append(desc, l, funcDefIndex);
97 0 : }
98 :
99 : void
100 0 : MacroAssembler::call(const wasm::CallSiteDesc& desc, wasm::Trap trap)
101 : {
102 0 : CodeOffset l = callWithPatch();
103 0 : append(desc, l, trap);
104 0 : }
105 :
106 : void
107 0 : MacroAssembler::call(const wasm::CallSiteDesc& desc, wasm::SymbolicAddress imm)
108 : {
109 0 : MOZ_ASSERT(wasm::NeedsBuiltinThunk(imm), "only for functions which may appear in profiler");
110 0 : call(imm);
111 0 : append(desc, CodeOffset(currentOffset()));
112 0 : }
113 :
114 : // ===============================================================
115 : // ABI function calls.
116 :
117 : void
118 17356 : MacroAssembler::passABIArg(Register reg)
119 : {
120 17356 : passABIArg(MoveOperand(reg), MoveOp::GENERAL);
121 17356 : }
122 :
123 : void
124 1 : MacroAssembler::passABIArg(FloatRegister reg, MoveOp::Type type)
125 : {
126 1 : passABIArg(MoveOperand(reg), type);
127 1 : }
128 :
129 : template <typename T> void
130 13023 : MacroAssembler::callWithABI(const T& fun, MoveOp::Type result)
131 : {
132 26046 : AutoProfilerCallInstrumentation profiler(*this);
133 13023 : callWithABINoProfiler(fun, result);
134 13023 : }
135 :
136 : void
137 32619 : MacroAssembler::appendSignatureType(MoveOp::Type type)
138 : {
139 : #ifdef JS_SIMULATOR
140 : signature_ <<= ArgType_Shift;
141 : switch (type) {
142 : case MoveOp::GENERAL: signature_ |= ArgType_General; break;
143 : case MoveOp::DOUBLE: signature_ |= ArgType_Double; break;
144 : case MoveOp::FLOAT32: signature_ |= ArgType_Float32; break;
145 : default: MOZ_CRASH("Invalid argument type");
146 : }
147 : #endif
148 32619 : }
149 :
150 : ABIFunctionType
151 : MacroAssembler::signature() const
152 : {
153 : #ifdef JS_SIMULATOR
154 : #ifdef DEBUG
155 : switch (signature_) {
156 : case Args_General0:
157 : case Args_General1:
158 : case Args_General2:
159 : case Args_General3:
160 : case Args_General4:
161 : case Args_General5:
162 : case Args_General6:
163 : case Args_General7:
164 : case Args_General8:
165 : case Args_Double_None:
166 : case Args_Int_Double:
167 : case Args_Float32_Float32:
168 : case Args_Double_Double:
169 : case Args_Double_Int:
170 : case Args_Double_DoubleInt:
171 : case Args_Double_DoubleDouble:
172 : case Args_Double_IntDouble:
173 : case Args_Int_IntDouble:
174 : case Args_Int_DoubleIntInt:
175 : case Args_Int_IntDoubleIntInt:
176 : case Args_Double_DoubleDoubleDouble:
177 : case Args_Double_DoubleDoubleDoubleDouble:
178 : break;
179 : default:
180 : MOZ_CRASH("Unexpected type");
181 : }
182 : #endif // DEBUG
183 :
184 : return ABIFunctionType(signature_);
185 : #else
186 : // No simulator enabled.
187 : MOZ_CRASH("Only available for making calls within a simulator.");
188 : #endif
189 : }
190 :
191 : // ===============================================================
192 : // Jit Frames.
193 :
194 : uint32_t
195 94 : MacroAssembler::callJitNoProfiler(Register callee)
196 : {
197 : #ifdef JS_USE_LINK_REGISTER
198 : // The return address is pushed by the callee.
199 : call(callee);
200 : #else
201 94 : callAndPushReturnAddress(callee);
202 : #endif
203 94 : return currentOffset();
204 : }
205 :
206 : uint32_t
207 82 : MacroAssembler::callJit(Register callee)
208 : {
209 164 : AutoProfilerCallInstrumentation profiler(*this);
210 82 : uint32_t ret = callJitNoProfiler(callee);
211 164 : return ret;
212 : }
213 :
214 : uint32_t
215 120 : MacroAssembler::callJit(JitCode* callee)
216 : {
217 240 : AutoProfilerCallInstrumentation profiler(*this);
218 120 : call(callee);
219 240 : return currentOffset();
220 : }
221 :
222 : void
223 1644 : MacroAssembler::makeFrameDescriptor(Register frameSizeReg, FrameType type, uint32_t headerSize)
224 : {
225 : // See JitFrames.h for a description of the frame descriptor format.
226 : // The saved-frame bit is zero for new frames. See js::SavedStacks.
227 :
228 1644 : lshiftPtr(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
229 :
230 1644 : headerSize = EncodeFrameHeaderSize(headerSize);
231 1644 : orPtr(Imm32((headerSize << FRAME_HEADER_SIZE_SHIFT) | type), frameSizeReg);
232 1644 : }
233 :
234 : void
235 129 : MacroAssembler::pushStaticFrameDescriptor(FrameType type, uint32_t headerSize)
236 : {
237 129 : uint32_t descriptor = MakeFrameDescriptor(framePushed(), type, headerSize);
238 129 : Push(Imm32(descriptor));
239 129 : }
240 :
241 : void
242 71 : MacroAssembler::PushCalleeToken(Register callee, bool constructing)
243 : {
244 71 : if (constructing) {
245 6 : orPtr(Imm32(CalleeToken_FunctionConstructing), callee);
246 6 : Push(callee);
247 6 : andPtr(Imm32(uint32_t(CalleeTokenMask)), callee);
248 : } else {
249 : static_assert(CalleeToken_Function == 0, "Non-constructing call requires no tagging");
250 65 : Push(callee);
251 : }
252 71 : }
253 :
254 : void
255 636 : MacroAssembler::loadFunctionFromCalleeToken(Address token, Register dest)
256 : {
257 : #ifdef DEBUG
258 1272 : Label ok;
259 636 : loadPtr(token, dest);
260 636 : andPtr(Imm32(uint32_t(~CalleeTokenMask)), dest);
261 636 : branchPtr(Assembler::Equal, dest, Imm32(CalleeToken_Function), &ok);
262 636 : branchPtr(Assembler::Equal, dest, Imm32(CalleeToken_FunctionConstructing), &ok);
263 636 : assumeUnreachable("Unexpected CalleeToken tag");
264 636 : bind(&ok);
265 : #endif
266 636 : loadPtr(token, dest);
267 636 : andPtr(Imm32(uint32_t(CalleeTokenMask)), dest);
268 636 : }
269 :
270 : uint32_t
271 9 : MacroAssembler::buildFakeExitFrame(Register scratch)
272 : {
273 18 : mozilla::DebugOnly<uint32_t> initialDepth = framePushed();
274 :
275 9 : pushStaticFrameDescriptor(JitFrame_IonJS, ExitFrameLayout::Size());
276 9 : uint32_t retAddr = pushFakeReturnAddress(scratch);
277 :
278 9 : MOZ_ASSERT(framePushed() == initialDepth + ExitFrameLayout::Size());
279 18 : return retAddr;
280 : }
281 :
282 : // ===============================================================
283 : // Exit frame footer.
284 :
285 : void
286 1044 : MacroAssembler::PushStubCode()
287 : {
288 : // Make sure that we do not erase an existing self-reference.
289 1044 : MOZ_ASSERT(!hasSelfReference());
290 1044 : selfReferencePatch_ = PushWithPatch(ImmWord(-1));
291 1044 : }
292 :
293 : void
294 1040 : MacroAssembler::enterExitFrame(Register cxreg, Register scratch, const VMFunction* f)
295 : {
296 1040 : linkExitFrame(cxreg, scratch);
297 : // Push the JitCode pointer. (Keep the code alive, when on the stack)
298 1040 : PushStubCode();
299 : // Push VMFunction pointer, to mark arguments.
300 1040 : Push(ImmPtr(f));
301 1040 : }
302 :
303 : void
304 98 : MacroAssembler::enterFakeExitFrame(Register cxreg, Register scratch, enum ExitFrameTokenValues token)
305 : {
306 98 : linkExitFrame(cxreg, scratch);
307 98 : Push(Imm32(token));
308 98 : Push(ImmPtr(nullptr));
309 98 : }
310 :
311 : void
312 86 : MacroAssembler::enterFakeExitFrameForNative(Register cxreg, Register scratch, bool isConstructing)
313 : {
314 86 : enterFakeExitFrame(cxreg, scratch, isConstructing ? ConstructNativeExitFrameLayoutToken
315 86 : : CallNativeExitFrameLayoutToken);
316 86 : }
317 :
318 : void
319 1040 : MacroAssembler::leaveExitFrame(size_t extraFrame)
320 : {
321 1040 : freeStack(ExitFooterFrame::Size() + extraFrame);
322 1040 : }
323 :
324 : bool
325 5543 : MacroAssembler::hasSelfReference() const
326 : {
327 5543 : return selfReferencePatch_.bound();
328 : }
329 :
330 : // ===============================================================
331 : // Arithmetic functions
332 :
333 : void
334 0 : MacroAssembler::addPtr(ImmPtr imm, Register dest)
335 : {
336 0 : addPtr(ImmWord(uintptr_t(imm.value)), dest);
337 0 : }
338 :
339 : void
340 6 : MacroAssembler::inc32(RegisterOrInt32Constant* key)
341 : {
342 6 : if (key->isRegister())
343 2 : add32(Imm32(1), key->reg());
344 : else
345 4 : key->bumpConstant(1);
346 6 : }
347 :
348 : void
349 5 : MacroAssembler::dec32(RegisterOrInt32Constant* key)
350 : {
351 5 : if (key->isRegister())
352 1 : add32(Imm32(-1), key->reg());
353 : else
354 4 : key->bumpConstant(-1);
355 5 : }
356 :
357 : // ===============================================================
358 : // Branch functions
359 :
360 : void
361 0 : MacroAssembler::branch32(Condition cond, Register length, const RegisterOrInt32Constant& key,
362 : Label* label)
363 : {
364 0 : branch32Impl(cond, length, key, label);
365 0 : }
366 :
367 : void
368 5 : MacroAssembler::branch32(Condition cond, const Address& length, const RegisterOrInt32Constant& key,
369 : Label* label)
370 : {
371 5 : branch32Impl(cond, length, key, label);
372 5 : }
373 :
374 : template <typename T>
375 : void
376 5 : MacroAssembler::branch32Impl(Condition cond, const T& length, const RegisterOrInt32Constant& key,
377 : Label* label)
378 : {
379 5 : if (key.isRegister())
380 5 : branch32(cond, length, key.reg(), label);
381 : else
382 0 : branch32(cond, length, Imm32(key.constant()), label);
383 5 : }
384 :
385 : template <class L>
386 : void
387 153 : MacroAssembler::branchIfFalseBool(Register reg, L label)
388 : {
389 : // Note that C++ bool is only 1 byte, so ignore the higher-order bits.
390 153 : branchTest32(Assembler::Zero, reg, Imm32(0xFF), label);
391 153 : }
392 :
393 : void
394 6 : MacroAssembler::branchIfTrueBool(Register reg, Label* label)
395 : {
396 : // Note that C++ bool is only 1 byte, so ignore the higher-order bits.
397 6 : branchTest32(Assembler::NonZero, reg, Imm32(0xFF), label);
398 6 : }
399 :
400 : void
401 19 : MacroAssembler::branchIfRope(Register str, Label* label)
402 : {
403 19 : Address flags(str, JSString::offsetOfFlags());
404 : static_assert(JSString::ROPE_FLAGS == 0, "Rope type flags must be 0");
405 19 : branchTest32(Assembler::Zero, flags, Imm32(JSString::TYPE_FLAGS_MASK), label);
406 19 : }
407 :
408 : void
409 0 : MacroAssembler::branchIfRopeOrExternal(Register str, Register temp, Label* label)
410 : {
411 0 : Address flags(str, JSString::offsetOfFlags());
412 0 : move32(Imm32(JSString::TYPE_FLAGS_MASK), temp);
413 0 : and32(flags, temp);
414 :
415 : static_assert(JSString::ROPE_FLAGS == 0, "Rope type flags must be 0");
416 0 : branchTest32(Assembler::Zero, temp, temp, label);
417 :
418 0 : branch32(Assembler::Equal, temp, Imm32(JSString::EXTERNAL_FLAGS), label);
419 0 : }
420 :
421 : void
422 3 : MacroAssembler::branchIfNotRope(Register str, Label* label)
423 : {
424 3 : Address flags(str, JSString::offsetOfFlags());
425 : static_assert(JSString::ROPE_FLAGS == 0, "Rope type flags must be 0");
426 3 : branchTest32(Assembler::NonZero, flags, Imm32(JSString::TYPE_FLAGS_MASK), label);
427 3 : }
428 :
429 : void
430 11 : MacroAssembler::branchLatin1String(Register string, Label* label)
431 : {
432 22 : branchTest32(Assembler::NonZero, Address(string, JSString::offsetOfFlags()),
433 11 : Imm32(JSString::LATIN1_CHARS_BIT), label);
434 11 : }
435 :
436 : void
437 : MacroAssembler::branchTwoByteString(Register string, Label* label)
438 : {
439 : branchTest32(Assembler::Zero, Address(string, JSString::offsetOfFlags()),
440 : Imm32(JSString::LATIN1_CHARS_BIT), label);
441 : }
442 :
443 : void
444 78 : MacroAssembler::branchIfFunctionHasNoScript(Register fun, Label* label)
445 : {
446 : // 16-bit loads are slow and unaligned 32-bit loads may be too so
447 : // perform an aligned 32-bit load and adjust the bitmask accordingly.
448 78 : MOZ_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0);
449 78 : MOZ_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2);
450 78 : Address address(fun, JSFunction::offsetOfNargs());
451 78 : int32_t bit = IMM32_16ADJ(JSFunction::INTERPRETED);
452 78 : branchTest32(Assembler::Zero, address, Imm32(bit), label);
453 78 : }
454 :
455 : void
456 0 : MacroAssembler::branchIfInterpreted(Register fun, Label* label)
457 : {
458 : // 16-bit loads are slow and unaligned 32-bit loads may be too so
459 : // perform an aligned 32-bit load and adjust the bitmask accordingly.
460 0 : MOZ_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0);
461 0 : MOZ_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2);
462 0 : Address address(fun, JSFunction::offsetOfNargs());
463 0 : int32_t bit = IMM32_16ADJ(JSFunction::INTERPRETED);
464 0 : branchTest32(Assembler::NonZero, address, Imm32(bit), label);
465 0 : }
466 :
467 : void
468 45 : MacroAssembler::branchIfObjectEmulatesUndefined(Register objReg, Register scratch,
469 : Label* slowCheck, Label* label)
470 : {
471 : // The branches to out-of-line code here implement a conservative version
472 : // of the JSObject::isWrapper test performed in EmulatesUndefined.
473 45 : loadObjClass(objReg, scratch);
474 :
475 45 : branchTestClassIsProxy(true, scratch, slowCheck);
476 :
477 45 : Address flags(scratch, Class::offsetOfFlags());
478 45 : branchTest32(Assembler::NonZero, flags, Imm32(JSCLASS_EMULATES_UNDEFINED), label);
479 45 : }
480 :
481 : void
482 12 : MacroAssembler::branchFunctionKind(Condition cond, JSFunction::FunctionKind kind, Register fun,
483 : Register scratch, Label* label)
484 : {
485 : // 16-bit loads are slow and unaligned 32-bit loads may be too so
486 : // perform an aligned 32-bit load and adjust the bitmask accordingly.
487 12 : MOZ_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0);
488 12 : MOZ_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2);
489 12 : Address address(fun, JSFunction::offsetOfNargs());
490 12 : int32_t mask = IMM32_16ADJ(JSFunction::FUNCTION_KIND_MASK);
491 12 : int32_t bit = IMM32_16ADJ(kind << JSFunction::FUNCTION_KIND_SHIFT);
492 12 : load32(address, scratch);
493 12 : and32(Imm32(mask), scratch);
494 12 : branch32(cond, scratch, Imm32(bit), label);
495 12 : }
496 :
497 : void
498 43 : MacroAssembler::branchTestObjClass(Condition cond, Register obj, Register scratch, const js::Class* clasp,
499 : Label* label)
500 : {
501 43 : loadObjGroup(obj, scratch);
502 43 : branchPtr(cond, Address(scratch, ObjectGroup::offsetOfClasp()), ImmPtr(clasp), label);
503 43 : }
504 :
505 : void
506 22 : MacroAssembler::branchTestObjShape(Condition cond, Register obj, const Shape* shape, Label* label)
507 : {
508 22 : branchPtr(cond, Address(obj, ShapedObject::offsetOfShape()), ImmGCPtr(shape), label);
509 22 : }
510 :
511 : void
512 282 : MacroAssembler::branchTestObjShape(Condition cond, Register obj, Register shape, Label* label)
513 : {
514 282 : branchPtr(cond, Address(obj, ShapedObject::offsetOfShape()), shape, label);
515 282 : }
516 :
517 : void
518 0 : MacroAssembler::branchTestObjGroup(Condition cond, Register obj, ObjectGroup* group, Label* label)
519 : {
520 0 : branchPtr(cond, Address(obj, JSObject::offsetOfGroup()), ImmGCPtr(group), label);
521 0 : }
522 :
523 : void
524 61 : MacroAssembler::branchTestObjGroup(Condition cond, Register obj, Register group, Label* label)
525 : {
526 61 : branchPtr(cond, Address(obj, JSObject::offsetOfGroup()), group, label);
527 61 : }
528 :
529 : void
530 78 : MacroAssembler::branchTestClassIsProxy(bool proxy, Register clasp, Label* label)
531 : {
532 234 : branchTest32(proxy ? Assembler::NonZero : Assembler::Zero,
533 156 : Address(clasp, Class::offsetOfFlags()),
534 78 : Imm32(JSCLASS_IS_PROXY), label);
535 78 : }
536 :
537 : void
538 30 : MacroAssembler::branchTestObjectIsProxy(bool proxy, Register object, Register scratch, Label* label)
539 : {
540 30 : loadObjClass(object, scratch);
541 30 : branchTestClassIsProxy(proxy, scratch, label);
542 30 : }
543 :
544 : void
545 7 : MacroAssembler::branchTestProxyHandlerFamily(Condition cond, Register proxy, Register scratch,
546 : const void* handlerp, Label* label)
547 : {
548 7 : Address handlerAddr(proxy, ProxyObject::offsetOfHandler());
549 7 : loadPtr(handlerAddr, scratch);
550 7 : Address familyAddr(scratch, BaseProxyHandler::offsetOfFamily());
551 7 : branchPtr(cond, familyAddr, ImmPtr(handlerp), label);
552 7 : }
553 :
554 : template <typename Value>
555 : void
556 162 : MacroAssembler::branchTestMIRType(Condition cond, const Value& val, MIRType type, Label* label)
557 : {
558 162 : switch (type) {
559 3 : case MIRType::Null: return branchTestNull(cond, val, label);
560 69 : case MIRType::Undefined: return branchTestUndefined(cond, val, label);
561 49 : case MIRType::Boolean: return branchTestBoolean(cond, val, label);
562 9 : case MIRType::Int32: return branchTestInt32(cond, val, label);
563 21 : case MIRType::String: return branchTestString(cond, val, label);
564 0 : case MIRType::Symbol: return branchTestSymbol(cond, val, label);
565 11 : case MIRType::Object: return branchTestObject(cond, val, label);
566 0 : case MIRType::Double: return branchTestDouble(cond, val, label);
567 : case MIRType::MagicOptimizedArguments: // Fall through.
568 : case MIRType::MagicIsConstructing:
569 0 : case MIRType::MagicHole: return branchTestMagic(cond, val, label);
570 : default:
571 0 : MOZ_CRASH("Bad MIRType");
572 : }
573 : }
574 :
575 : void
576 247 : MacroAssembler::branchTestNeedsIncrementalBarrier(Condition cond, Label* label)
577 : {
578 247 : MOZ_ASSERT(cond == Zero || cond == NonZero);
579 247 : CompileZone* zone = GetJitContext()->compartment->zone();
580 247 : AbsoluteAddress needsBarrierAddr(zone->addressOfNeedsIncrementalBarrier());
581 247 : branchTest32(cond, needsBarrierAddr, Imm32(0x1), label);
582 247 : }
583 :
584 : void
585 89 : MacroAssembler::branchTestMagicValue(Condition cond, const ValueOperand& val, JSWhyMagic why,
586 : Label* label)
587 : {
588 89 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
589 89 : branchTestValue(cond, val, MagicValue(why), label);
590 89 : }
591 :
592 : void
593 : MacroAssembler::branchDoubleNotInInt64Range(Address src, Register temp, Label* fail)
594 : {
595 : // Tests if double is in [INT64_MIN; INT64_MAX] range
596 : uint32_t EXPONENT_MASK = 0x7ff00000;
597 : uint32_t EXPONENT_SHIFT = FloatingPoint<double>::kExponentShift - 32;
598 : uint32_t TOO_BIG_EXPONENT = (FloatingPoint<double>::kExponentBias + 63) << EXPONENT_SHIFT;
599 :
600 : load32(Address(src.base, src.offset + sizeof(int32_t)), temp);
601 : and32(Imm32(EXPONENT_MASK), temp);
602 : branch32(Assembler::GreaterThanOrEqual, temp, Imm32(TOO_BIG_EXPONENT), fail);
603 : }
604 :
605 : void
606 : MacroAssembler::branchDoubleNotInUInt64Range(Address src, Register temp, Label* fail)
607 : {
608 : // Note: returns failure on -0.0
609 : // Tests if double is in [0; UINT64_MAX] range
610 : // Take the sign also in the equation. That way we can compare in one test?
611 : uint32_t EXPONENT_MASK = 0xfff00000;
612 : uint32_t EXPONENT_SHIFT = FloatingPoint<double>::kExponentShift - 32;
613 : uint32_t TOO_BIG_EXPONENT = (FloatingPoint<double>::kExponentBias + 64) << EXPONENT_SHIFT;
614 :
615 : load32(Address(src.base, src.offset + sizeof(int32_t)), temp);
616 : and32(Imm32(EXPONENT_MASK), temp);
617 : branch32(Assembler::AboveOrEqual, temp, Imm32(TOO_BIG_EXPONENT), fail);
618 : }
619 :
620 : void
621 : MacroAssembler::branchFloat32NotInInt64Range(Address src, Register temp, Label* fail)
622 : {
623 : // Tests if float is in [INT64_MIN; INT64_MAX] range
624 : uint32_t EXPONENT_MASK = 0x7f800000;
625 : uint32_t EXPONENT_SHIFT = FloatingPoint<float>::kExponentShift;
626 : uint32_t TOO_BIG_EXPONENT = (FloatingPoint<float>::kExponentBias + 63) << EXPONENT_SHIFT;
627 :
628 : load32(src, temp);
629 : and32(Imm32(EXPONENT_MASK), temp);
630 : branch32(Assembler::GreaterThanOrEqual, temp, Imm32(TOO_BIG_EXPONENT), fail);
631 : }
632 :
633 : void
634 : MacroAssembler::branchFloat32NotInUInt64Range(Address src, Register temp, Label* fail)
635 : {
636 : // Note: returns failure on -0.0
637 : // Tests if float is in [0; UINT64_MAX] range
638 : // Take the sign also in the equation. That way we can compare in one test?
639 : uint32_t EXPONENT_MASK = 0xff800000;
640 : uint32_t EXPONENT_SHIFT = FloatingPoint<float>::kExponentShift;
641 : uint32_t TOO_BIG_EXPONENT = (FloatingPoint<float>::kExponentBias + 64) << EXPONENT_SHIFT;
642 :
643 : load32(src, temp);
644 : and32(Imm32(EXPONENT_MASK), temp);
645 : branch32(Assembler::AboveOrEqual, temp, Imm32(TOO_BIG_EXPONENT), fail);
646 : }
647 :
648 : // ========================================================================
649 : // Canonicalization primitives.
650 : void
651 0 : MacroAssembler::canonicalizeFloat(FloatRegister reg)
652 : {
653 0 : Label notNaN;
654 0 : branchFloat(DoubleOrdered, reg, reg, ¬NaN);
655 0 : loadConstantFloat32(float(JS::GenericNaN()), reg);
656 0 : bind(¬NaN);
657 0 : }
658 :
659 : void
660 0 : MacroAssembler::canonicalizeFloatIfDeterministic(FloatRegister reg)
661 : {
662 : #ifdef JS_MORE_DETERMINISTIC
663 : // See the comment in TypedArrayObjectTemplate::getIndexValue.
664 : canonicalizeFloat(reg);
665 : #endif // JS_MORE_DETERMINISTIC
666 0 : }
667 :
668 : void
669 0 : MacroAssembler::canonicalizeDouble(FloatRegister reg)
670 : {
671 0 : Label notNaN;
672 0 : branchDouble(DoubleOrdered, reg, reg, ¬NaN);
673 0 : loadConstantDouble(JS::GenericNaN(), reg);
674 0 : bind(¬NaN);
675 0 : }
676 :
677 : void
678 6 : MacroAssembler::canonicalizeDoubleIfDeterministic(FloatRegister reg)
679 : {
680 : #ifdef JS_MORE_DETERMINISTIC
681 : // See the comment in TypedArrayObjectTemplate::getIndexValue.
682 : canonicalizeDouble(reg);
683 : #endif // JS_MORE_DETERMINISTIC
684 6 : }
685 :
686 : // ========================================================================
687 : // Memory access primitives.
688 : template<class T> void
689 6 : MacroAssembler::storeDouble(FloatRegister src, const T& dest)
690 : {
691 6 : canonicalizeDoubleIfDeterministic(src);
692 6 : storeUncanonicalizedDouble(src, dest);
693 6 : }
694 :
695 : template void MacroAssembler::storeDouble(FloatRegister src, const Address& dest);
696 : template void MacroAssembler::storeDouble(FloatRegister src, const BaseIndex& dest);
697 :
698 : template<class T> void
699 0 : MacroAssembler::storeFloat32(FloatRegister src, const T& dest)
700 : {
701 0 : canonicalizeFloatIfDeterministic(src);
702 0 : storeUncanonicalizedFloat32(src, dest);
703 0 : }
704 :
705 : template void MacroAssembler::storeFloat32(FloatRegister src, const Address& dest);
706 : template void MacroAssembler::storeFloat32(FloatRegister src, const BaseIndex& dest);
707 :
708 : //}}} check_macroassembler_style
709 : // ===============================================================
710 :
711 : #ifndef JS_CODEGEN_ARM64
712 :
713 : template <typename T>
714 : void
715 13335 : MacroAssembler::branchTestStackPtr(Condition cond, T t, Label* label)
716 : {
717 13335 : branchTestPtr(cond, getStackPointer(), t, label);
718 13335 : }
719 :
720 : template <typename T>
721 : void
722 50 : MacroAssembler::branchStackPtr(Condition cond, T rhs, Label* label)
723 : {
724 50 : branchPtr(cond, getStackPointer(), rhs, label);
725 50 : }
726 :
727 : template <typename T>
728 : void
729 47 : MacroAssembler::branchStackPtrRhs(Condition cond, T lhs, Label* label)
730 : {
731 47 : branchPtr(cond, lhs, getStackPointer(), label);
732 47 : }
733 :
734 : template <typename T> void
735 32805 : MacroAssembler::addToStackPtr(T t)
736 : {
737 32805 : addPtr(t, getStackPointer());
738 32804 : }
739 :
740 : template <typename T> void
741 2 : MacroAssembler::addStackPtrTo(T t)
742 : {
743 2 : addPtr(getStackPointer(), t);
744 2 : }
745 :
746 : void
747 24649 : MacroAssembler::reserveStack(uint32_t amount)
748 : {
749 24649 : subFromStackPtr(Imm32(amount));
750 24649 : adjustFrame(amount);
751 24649 : }
752 : #endif // !JS_CODEGEN_ARM64
753 :
754 : template <typename T>
755 : void
756 0 : MacroAssembler::storeObjectOrNull(Register src, const T& dest)
757 : {
758 0 : Label notNull, done;
759 0 : branchTestPtr(Assembler::NonZero, src, src, ¬Null);
760 0 : storeValue(NullValue(), dest);
761 0 : jump(&done);
762 0 : bind(¬Null);
763 0 : storeValue(JSVAL_TYPE_OBJECT, src, dest);
764 0 : bind(&done);
765 0 : }
766 :
767 : void
768 13189 : MacroAssembler::assertStackAlignment(uint32_t alignment, int32_t offset /* = 0 */)
769 : {
770 : #ifdef DEBUG
771 26378 : Label ok, bad;
772 13189 : MOZ_ASSERT(mozilla::IsPowerOfTwo(alignment));
773 :
774 : // Wrap around the offset to be a non-negative number.
775 13189 : offset %= alignment;
776 13189 : if (offset < 0)
777 0 : offset += alignment;
778 :
779 : // Test if each bit from offset is set.
780 13189 : uint32_t off = offset;
781 13351 : while (off) {
782 81 : uint32_t lowestBit = 1 << mozilla::CountTrailingZeroes32(off);
783 81 : branchTestStackPtr(Assembler::Zero, Imm32(lowestBit), &bad);
784 81 : off ^= lowestBit;
785 : }
786 :
787 : // Check that all remaining bits are zero.
788 13189 : branchTestStackPtr(Assembler::Zero, Imm32((alignment - 1) ^ offset), &ok);
789 :
790 13189 : bind(&bad);
791 13189 : breakpoint();
792 13189 : bind(&ok);
793 : #endif
794 13189 : }
795 :
796 : void
797 0 : MacroAssembler::storeCallBoolResult(Register reg)
798 : {
799 0 : if (reg != ReturnReg)
800 0 : mov(ReturnReg, reg);
801 : // C++ compilers like to only use the bottom byte for bools, but we
802 : // need to maintain the entire register.
803 0 : and32(Imm32(0xFF), reg);
804 0 : }
805 :
806 : void
807 6 : MacroAssembler::storeCallResultValue(AnyRegister dest)
808 : {
809 6 : unboxValue(JSReturnOperand, dest);
810 6 : }
811 :
812 : void
813 23 : MacroAssembler::storeCallResultValue(TypedOrValueRegister dest)
814 : {
815 23 : if (dest.hasValue())
816 17 : storeCallResultValue(dest.valueReg());
817 : else
818 6 : storeCallResultValue(dest.typedReg());
819 23 : }
820 :
821 : } // namespace jit
822 : } // namespace js
823 :
824 : #endif /* jit_MacroAssembler_inl_h */
|