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/x86/Lowering-x86.h"
9 #include "jit/MIR.h"
10 #include "jit/x86/Assembler-x86.h"
12 #include "jit/shared/Lowering-shared-inl.h"
14 using namespace js;
15 using namespace js::jit;
17 LDefinition
18 LIRGeneratorX86::tempForDispatchCache(MIRType outputType)
19 {
20 // x86 doesn't have a scratch register and we need one for the
21 // indirect jump for dispatch-style ICs.
22 //
23 // Note that currently we only install dispatch-style ICs for parallel
24 // execution. If this assumption changes, please change it here.
25 if (gen->info().executionMode() != ParallelExecution)
26 return LDefinition::BogusTemp();
28 // If we don't have an output register, we need a temp.
29 if (outputType == MIRType_None)
30 return temp();
32 // If we have a double output register, we need a temp.
33 if (outputType == MIRType_Double)
34 return temp();
36 // Otherwise we have a non-double output register and we can reuse it.
37 return LDefinition::BogusTemp();
38 }
40 bool
41 LIRGeneratorX86::useBox(LInstruction *lir, size_t n, MDefinition *mir,
42 LUse::Policy policy, bool useAtStart)
43 {
44 JS_ASSERT(mir->type() == MIRType_Value);
46 if (!ensureDefined(mir))
47 return false;
48 lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart));
49 lir->setOperand(n + 1, LUse(VirtualRegisterOfPayload(mir), policy, useAtStart));
50 return true;
51 }
53 bool
54 LIRGeneratorX86::useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1,
55 Register reg2)
56 {
57 JS_ASSERT(mir->type() == MIRType_Value);
58 JS_ASSERT(reg1 != reg2);
60 if (!ensureDefined(mir))
61 return false;
62 lir->setOperand(n, LUse(reg1, mir->virtualRegister()));
63 lir->setOperand(n + 1, LUse(reg2, VirtualRegisterOfPayload(mir)));
64 return true;
65 }
67 LAllocation
68 LIRGeneratorX86::useByteOpRegister(MDefinition *mir)
69 {
70 return useFixed(mir, eax);
71 }
73 LAllocation
74 LIRGeneratorX86::useByteOpRegisterOrNonDoubleConstant(MDefinition *mir)
75 {
76 return useFixed(mir, eax);
77 }
79 bool
80 LIRGeneratorX86::visitBox(MBox *box)
81 {
82 MDefinition *inner = box->getOperand(0);
84 // If the box wrapped a double, it needs a new register.
85 if (IsFloatingPointType(inner->type()))
86 return defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner), tempCopy(inner, 0),
87 inner->type()), box);
89 if (box->canEmitAtUses())
90 return emitAtUses(box);
92 if (inner->isConstant())
93 return defineBox(new(alloc()) LValue(inner->toConstant()->value()), box);
95 LBox *lir = new(alloc()) LBox(use(inner), inner->type());
97 // Otherwise, we should not define a new register for the payload portion
98 // of the output, so bypass defineBox().
99 uint32_t vreg = getVirtualRegister();
100 if (vreg >= MAX_VIRTUAL_REGISTERS)
101 return false;
103 // Note that because we're using PASSTHROUGH, we do not change the type of
104 // the definition. We also do not define the first output as "TYPE",
105 // because it has no corresponding payload at (vreg + 1). Also note that
106 // although we copy the input's original type for the payload half of the
107 // definition, this is only for clarity. PASSTHROUGH definitions are
108 // ignored.
109 lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
110 lir->setDef(1, LDefinition(inner->virtualRegister(), LDefinition::TypeFrom(inner->type()),
111 LDefinition::PASSTHROUGH));
112 box->setVirtualRegister(vreg);
113 return add(lir);
114 }
116 bool
117 LIRGeneratorX86::visitUnbox(MUnbox *unbox)
118 {
119 // An unbox on x86 reads in a type tag (either in memory or a register) and
120 // a payload. Unlike most instructions conusming a box, we ask for the type
121 // second, so that the result can re-use the first input.
122 MDefinition *inner = unbox->getOperand(0);
124 if (!ensureDefined(inner))
125 return false;
127 if (IsFloatingPointType(unbox->type())) {
128 LUnboxFloatingPoint *lir = new(alloc()) LUnboxFloatingPoint(unbox->type());
129 if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
130 return false;
131 if (!useBox(lir, LUnboxFloatingPoint::Input, inner))
132 return false;
133 return define(lir, unbox);
134 }
136 // Swap the order we use the box pieces so we can re-use the payload register.
137 LUnbox *lir = new(alloc()) LUnbox;
138 lir->setOperand(0, usePayloadInRegisterAtStart(inner));
139 lir->setOperand(1, useType(inner, LUse::ANY));
141 if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
142 return false;
144 // Note that PASSTHROUGH here is illegal, since types and payloads form two
145 // separate intervals. If the type becomes dead before the payload, it
146 // could be used as a Value without the type being recoverable. Unbox's
147 // purpose is to eagerly kill the definition of a type tag, so keeping both
148 // alive (for the purpose of gcmaps) is unappealing. Instead, we create a
149 // new virtual register.
150 return defineReuseInput(lir, unbox, 0);
151 }
153 bool
154 LIRGeneratorX86::visitReturn(MReturn *ret)
155 {
156 MDefinition *opd = ret->getOperand(0);
157 JS_ASSERT(opd->type() == MIRType_Value);
159 LReturn *ins = new(alloc()) LReturn;
160 ins->setOperand(0, LUse(JSReturnReg_Type));
161 ins->setOperand(1, LUse(JSReturnReg_Data));
162 return fillBoxUses(ins, 0, opd) && add(ins);
163 }
165 bool
166 LIRGeneratorX86::defineUntypedPhi(MPhi *phi, size_t lirIndex)
167 {
168 LPhi *type = current->getPhi(lirIndex + VREG_TYPE_OFFSET);
169 LPhi *payload = current->getPhi(lirIndex + VREG_DATA_OFFSET);
171 uint32_t typeVreg = getVirtualRegister();
172 if (typeVreg >= MAX_VIRTUAL_REGISTERS)
173 return false;
175 phi->setVirtualRegister(typeVreg);
177 uint32_t payloadVreg = getVirtualRegister();
178 if (payloadVreg >= MAX_VIRTUAL_REGISTERS)
179 return false;
180 JS_ASSERT(typeVreg + 1 == payloadVreg);
182 type->setDef(0, LDefinition(typeVreg, LDefinition::TYPE));
183 payload->setDef(0, LDefinition(payloadVreg, LDefinition::PAYLOAD));
184 annotate(type);
185 annotate(payload);
186 return true;
187 }
189 void
190 LIRGeneratorX86::lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex)
191 {
192 MDefinition *operand = phi->getOperand(inputPosition);
193 LPhi *type = block->getPhi(lirIndex + VREG_TYPE_OFFSET);
194 LPhi *payload = block->getPhi(lirIndex + VREG_DATA_OFFSET);
195 type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET, LUse::ANY));
196 payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY));
197 }
199 bool
200 LIRGeneratorX86::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins)
201 {
202 JS_ASSERT(ins->input()->type() == MIRType_Int32);
203 LAsmJSUInt32ToDouble *lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input()), temp());
204 return define(lir, ins);
205 }
207 bool
208 LIRGeneratorX86::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins)
209 {
210 JS_ASSERT(ins->input()->type() == MIRType_Int32);
211 LAsmJSUInt32ToFloat32 *lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input()), temp());
212 return define(lir, ins);
213 }
215 bool
216 LIRGeneratorX86::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
217 {
218 MDefinition *ptr = ins->ptr();
219 LAllocation ptrAlloc;
220 JS_ASSERT(ptr->type() == MIRType_Int32);
222 // For the x86 it is best to keep the 'ptr' in a register if a bounds check is needed.
223 if (ptr->isConstant() && ins->skipBoundsCheck()) {
224 int32_t ptrValue = ptr->toConstant()->value().toInt32();
225 // A bounds check is only skipped for a positive index.
226 JS_ASSERT(ptrValue >= 0);
227 ptrAlloc = LAllocation(ptr->toConstant()->vp());
228 } else {
229 ptrAlloc = useRegisterAtStart(ptr);
230 }
231 LAsmJSLoadHeap *lir = new(alloc()) LAsmJSLoadHeap(ptrAlloc);
232 return define(lir, ins);
233 }
235 bool
236 LIRGeneratorX86::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
237 {
238 MDefinition *ptr = ins->ptr();
239 LAsmJSStoreHeap *lir;
240 JS_ASSERT(ptr->type() == MIRType_Int32);
242 if (ptr->isConstant() && ins->skipBoundsCheck()) {
243 int32_t ptrValue = ptr->toConstant()->value().toInt32();
244 JS_ASSERT(ptrValue >= 0);
245 LAllocation ptrAlloc = LAllocation(ptr->toConstant()->vp());
246 switch (ins->viewType()) {
247 case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8:
248 // See comment below.
249 lir = new(alloc()) LAsmJSStoreHeap(ptrAlloc, useFixed(ins->value(), eax));
250 break;
251 case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16:
252 case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32:
253 case ArrayBufferView::TYPE_FLOAT32: case ArrayBufferView::TYPE_FLOAT64:
254 // See comment below.
255 lir = new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value()));
256 break;
257 default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
258 }
259 return add(lir, ins);
260 }
262 switch (ins->viewType()) {
263 case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8:
264 // See comment for LIRGeneratorX86::useByteOpRegister.
265 lir = new(alloc()) LAsmJSStoreHeap(useRegister(ins->ptr()), useFixed(ins->value(), eax));
266 break;
267 case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16:
268 case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32:
269 case ArrayBufferView::TYPE_FLOAT32: case ArrayBufferView::TYPE_FLOAT64:
270 // For now, don't allow constant values. The immediate operand
271 // affects instruction layout which affects patching.
272 lir = new(alloc()) LAsmJSStoreHeap(useRegisterAtStart(ptr), useRegisterAtStart(ins->value()));
273 break;
274 default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
275 }
277 return add(lir, ins);
278 }
280 bool
281 LIRGeneratorX86::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
282 {
283 // The code generated for StoreTypedArrayElementStatic is identical to that
284 // for AsmJSStoreHeap, and the same concerns apply.
285 LStoreTypedArrayElementStatic *lir;
286 switch (ins->viewType()) {
287 case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8:
288 case ArrayBufferView::TYPE_UINT8_CLAMPED:
289 lir = new(alloc()) LStoreTypedArrayElementStatic(useRegister(ins->ptr()),
290 useFixed(ins->value(), eax));
291 break;
292 case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16:
293 case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32:
294 case ArrayBufferView::TYPE_FLOAT32: case ArrayBufferView::TYPE_FLOAT64:
295 lir = new(alloc()) LStoreTypedArrayElementStatic(useRegisterAtStart(ins->ptr()),
296 useRegisterAtStart(ins->value()));
297 break;
298 default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
299 }
301 return add(lir, ins);
302 }
304 bool
305 LIRGeneratorX86::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins)
306 {
307 return define(new(alloc()) LAsmJSLoadFuncPtr(useRegisterAtStart(ins->index())), ins);
308 }