Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 #include "jit/shared/MacroAssembler-x86-shared.h"
9 #include "jit/IonFrames.h"
10 #include "jit/IonMacroAssembler.h"
12 using namespace js;
13 using namespace js::jit;
15 void
16 MacroAssembler::PushRegsInMask(RegisterSet set)
17 {
18 int32_t diffF = set.fpus().size() * sizeof(double);
19 int32_t diffG = set.gprs().size() * sizeof(intptr_t);
21 // On x86, always use push to push the integer registers, as it's fast
22 // on modern hardware and it's a small instruction.
23 for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
24 diffG -= sizeof(intptr_t);
25 Push(*iter);
26 }
27 JS_ASSERT(diffG == 0);
29 reserveStack(diffF);
30 for (FloatRegisterBackwardIterator iter(set.fpus()); iter.more(); iter++) {
31 diffF -= sizeof(double);
32 storeDouble(*iter, Address(StackPointer, diffF));
33 }
34 JS_ASSERT(diffF == 0);
35 }
37 void
38 MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore)
39 {
40 int32_t diffG = set.gprs().size() * sizeof(intptr_t);
41 int32_t diffF = set.fpus().size() * sizeof(double);
42 const int32_t reservedG = diffG;
43 const int32_t reservedF = diffF;
45 for (FloatRegisterBackwardIterator iter(set.fpus()); iter.more(); iter++) {
46 diffF -= sizeof(double);
47 if (!ignore.has(*iter))
48 loadDouble(Address(StackPointer, diffF), *iter);
49 }
50 freeStack(reservedF);
51 JS_ASSERT(diffF == 0);
53 // On x86, use pop to pop the integer registers, if we're not going to
54 // ignore any slots, as it's fast on modern hardware and it's a small
55 // instruction.
56 if (ignore.empty(false)) {
57 for (GeneralRegisterForwardIterator iter(set.gprs()); iter.more(); iter++) {
58 diffG -= sizeof(intptr_t);
59 Pop(*iter);
60 }
61 } else {
62 for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
63 diffG -= sizeof(intptr_t);
64 if (!ignore.has(*iter))
65 loadPtr(Address(StackPointer, diffG), *iter);
66 }
67 freeStack(reservedG);
68 }
69 JS_ASSERT(diffG == 0);
70 }
72 // Note: this function clobbers the input register.
73 void
74 MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
75 {
76 JS_ASSERT(input != ScratchFloatReg);
77 Label positive, done;
79 // <= 0 or NaN --> 0
80 zeroDouble(ScratchFloatReg);
81 branchDouble(DoubleGreaterThan, input, ScratchFloatReg, &positive);
82 {
83 move32(Imm32(0), output);
84 jump(&done);
85 }
87 bind(&positive);
89 // Add 0.5 and truncate.
90 loadConstantDouble(0.5, ScratchFloatReg);
91 addDouble(ScratchFloatReg, input);
93 Label outOfRange;
95 // Truncate to int32 and ensure the result <= 255. This relies on the
96 // processor setting output to a value > 255 for doubles outside the int32
97 // range (for instance 0x80000000).
98 cvttsd2si(input, output);
99 branch32(Assembler::Above, output, Imm32(255), &outOfRange);
100 {
101 // Check if we had a tie.
102 convertInt32ToDouble(output, ScratchFloatReg);
103 branchDouble(DoubleNotEqual, input, ScratchFloatReg, &done);
105 // It was a tie. Mask out the ones bit to get an even value.
106 // See also js_TypedArray_uint8_clamp_double.
107 and32(Imm32(~1), output);
108 jump(&done);
109 }
111 // > 255 --> 255
112 bind(&outOfRange);
113 {
114 move32(Imm32(255), output);
115 }
117 bind(&done);
118 }
120 // Builds an exit frame on the stack, with a return address to an internal
121 // non-function. Returns offset to be passed to markSafepointAt().
122 bool
123 MacroAssemblerX86Shared::buildFakeExitFrame(const Register &scratch, uint32_t *offset)
124 {
125 mozilla::DebugOnly<uint32_t> initialDepth = framePushed();
127 CodeLabel cl;
128 mov(cl.dest(), scratch);
130 uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
131 Push(Imm32(descriptor));
132 Push(scratch);
134 bind(cl.src());
135 *offset = currentOffset();
137 JS_ASSERT(framePushed() == initialDepth + IonExitFrameLayout::Size());
138 return addCodeLabel(cl);
139 }
141 void
142 MacroAssemblerX86Shared::callWithExitFrame(JitCode *target)
143 {
144 uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
145 Push(Imm32(descriptor));
146 call(target);
147 }
149 bool
150 MacroAssemblerX86Shared::buildOOLFakeExitFrame(void *fakeReturnAddr)
151 {
152 uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
153 Push(Imm32(descriptor));
154 Push(ImmPtr(fakeReturnAddr));
155 return true;
156 }
158 void
159 MacroAssemblerX86Shared::branchNegativeZero(const FloatRegister ®,
160 const Register &scratch,
161 Label *label)
162 {
163 // Determines whether the low double contained in the XMM register reg
164 // is equal to -0.0.
166 #if defined(JS_CODEGEN_X86)
167 Label nonZero;
169 // Compare to zero. Lets through {0, -0}.
170 xorpd(ScratchFloatReg, ScratchFloatReg);
172 // If reg is non-zero, jump to nonZero.
173 branchDouble(DoubleNotEqual, reg, ScratchFloatReg, &nonZero);
175 // Input register is either zero or negative zero. Retrieve sign of input.
176 movmskpd(reg, scratch);
178 // If reg is 1 or 3, input is negative zero.
179 // If reg is 0 or 2, input is a normal zero.
180 branchTest32(NonZero, scratch, Imm32(1), label);
182 bind(&nonZero);
183 #elif defined(JS_CODEGEN_X64)
184 movq(reg, scratch);
185 cmpq(scratch, Imm32(1));
186 j(Overflow, label);
187 #endif
188 }
190 void
191 MacroAssemblerX86Shared::branchNegativeZeroFloat32(const FloatRegister ®,
192 const Register &scratch,
193 Label *label)
194 {
195 movd(reg, scratch);
196 cmpl(scratch, Imm32(1));
197 j(Overflow, label);
198 }