|
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 #include "jit/shared/Lowering-shared-inl.h" |
|
8 |
|
9 #include "jit/LIR.h" |
|
10 #include "jit/MIR.h" |
|
11 |
|
12 using namespace js; |
|
13 using namespace jit; |
|
14 |
|
15 bool |
|
16 LIRGeneratorShared::visitConstant(MConstant *ins) |
|
17 { |
|
18 const Value &v = ins->value(); |
|
19 switch (ins->type()) { |
|
20 case MIRType_Boolean: |
|
21 return define(new(alloc()) LInteger(v.toBoolean()), ins); |
|
22 case MIRType_Int32: |
|
23 return define(new(alloc()) LInteger(v.toInt32()), ins); |
|
24 case MIRType_String: |
|
25 return define(new(alloc()) LPointer(v.toString()), ins); |
|
26 case MIRType_Object: |
|
27 return define(new(alloc()) LPointer(&v.toObject()), ins); |
|
28 default: |
|
29 // Constants of special types (undefined, null) should never flow into |
|
30 // here directly. Operations blindly consuming them require a Box. |
|
31 JS_ASSERT(!"unexpected constant type"); |
|
32 return false; |
|
33 } |
|
34 } |
|
35 |
|
36 bool |
|
37 LIRGeneratorShared::defineTypedPhi(MPhi *phi, size_t lirIndex) |
|
38 { |
|
39 LPhi *lir = current->getPhi(lirIndex); |
|
40 |
|
41 uint32_t vreg = getVirtualRegister(); |
|
42 if (vreg >= MAX_VIRTUAL_REGISTERS) |
|
43 return false; |
|
44 |
|
45 phi->setVirtualRegister(vreg); |
|
46 lir->setDef(0, LDefinition(vreg, LDefinition::TypeFrom(phi->type()))); |
|
47 annotate(lir); |
|
48 return true; |
|
49 } |
|
50 |
|
51 void |
|
52 LIRGeneratorShared::lowerTypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex) |
|
53 { |
|
54 MDefinition *operand = phi->getOperand(inputPosition); |
|
55 LPhi *lir = block->getPhi(lirIndex); |
|
56 lir->setOperand(inputPosition, LUse(operand->virtualRegister(), LUse::ANY)); |
|
57 } |
|
58 |
|
59 LRecoverInfo * |
|
60 LIRGeneratorShared::getRecoverInfo(MResumePoint *rp) |
|
61 { |
|
62 if (cachedRecoverInfo_ && cachedRecoverInfo_->mir() == rp) |
|
63 return cachedRecoverInfo_; |
|
64 |
|
65 LRecoverInfo *recoverInfo = LRecoverInfo::New(gen, rp); |
|
66 if (!recoverInfo) |
|
67 return nullptr; |
|
68 |
|
69 cachedRecoverInfo_ = recoverInfo; |
|
70 return recoverInfo; |
|
71 } |
|
72 |
|
73 #ifdef JS_NUNBOX32 |
|
74 LSnapshot * |
|
75 LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) |
|
76 { |
|
77 LRecoverInfo *recover = getRecoverInfo(rp); |
|
78 if (!recover) |
|
79 return nullptr; |
|
80 |
|
81 LSnapshot *snapshot = LSnapshot::New(gen, recover, kind); |
|
82 if (!snapshot) |
|
83 return nullptr; |
|
84 |
|
85 size_t i = 0; |
|
86 for (MResumePoint **it = recover->begin(), **end = recover->end(); it != end; ++it) { |
|
87 MResumePoint *mir = *it; |
|
88 for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) { |
|
89 MDefinition *ins = mir->getOperand(j); |
|
90 |
|
91 LAllocation *type = snapshot->typeOfSlot(i); |
|
92 LAllocation *payload = snapshot->payloadOfSlot(i); |
|
93 |
|
94 if (ins->isBox()) |
|
95 ins = ins->toBox()->getOperand(0); |
|
96 |
|
97 // Guards should never be eliminated. |
|
98 JS_ASSERT_IF(ins->isUnused(), !ins->isGuard()); |
|
99 |
|
100 // Snapshot operands other than constants should never be |
|
101 // emitted-at-uses. Try-catch support depends on there being no |
|
102 // code between an instruction and the LOsiPoint that follows it. |
|
103 JS_ASSERT_IF(!ins->isConstant(), !ins->isEmittedAtUses()); |
|
104 |
|
105 // The register allocation will fill these fields in with actual |
|
106 // register/stack assignments. During code generation, we can restore |
|
107 // interpreter state with the given information. Note that for |
|
108 // constants, including known types, we record a dummy placeholder, |
|
109 // since we can recover the same information, much cleaner, from MIR. |
|
110 if (ins->isConstant() || ins->isUnused()) { |
|
111 *type = LConstantIndex::Bogus(); |
|
112 *payload = LConstantIndex::Bogus(); |
|
113 } else if (ins->type() != MIRType_Value) { |
|
114 *type = LConstantIndex::Bogus(); |
|
115 *payload = use(ins, LUse::KEEPALIVE); |
|
116 } else { |
|
117 *type = useType(ins, LUse::KEEPALIVE); |
|
118 *payload = usePayload(ins, LUse::KEEPALIVE); |
|
119 } |
|
120 } |
|
121 } |
|
122 |
|
123 return snapshot; |
|
124 } |
|
125 |
|
126 #elif JS_PUNBOX64 |
|
127 |
|
128 LSnapshot * |
|
129 LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) |
|
130 { |
|
131 LRecoverInfo *recover = getRecoverInfo(rp); |
|
132 if (!recover) |
|
133 return nullptr; |
|
134 |
|
135 LSnapshot *snapshot = LSnapshot::New(gen, recover, kind); |
|
136 if (!snapshot) |
|
137 return nullptr; |
|
138 |
|
139 size_t i = 0; |
|
140 for (MResumePoint **it = recover->begin(), **end = recover->end(); it != end; ++it) { |
|
141 MResumePoint *mir = *it; |
|
142 for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) { |
|
143 MDefinition *def = mir->getOperand(j); |
|
144 |
|
145 if (def->isBox()) |
|
146 def = def->toBox()->getOperand(0); |
|
147 |
|
148 // Guards should never be eliminated. |
|
149 JS_ASSERT_IF(def->isUnused(), !def->isGuard()); |
|
150 |
|
151 // Snapshot operands other than constants should never be |
|
152 // emitted-at-uses. Try-catch support depends on there being no |
|
153 // code between an instruction and the LOsiPoint that follows it. |
|
154 JS_ASSERT_IF(!def->isConstant(), !def->isEmittedAtUses()); |
|
155 |
|
156 LAllocation *a = snapshot->getEntry(i); |
|
157 |
|
158 if (def->isUnused()) { |
|
159 *a = LConstantIndex::Bogus(); |
|
160 continue; |
|
161 } |
|
162 |
|
163 *a = useKeepaliveOrConstant(def); |
|
164 } |
|
165 } |
|
166 |
|
167 return snapshot; |
|
168 } |
|
169 #endif |
|
170 |
|
171 bool |
|
172 LIRGeneratorShared::assignSnapshot(LInstruction *ins, BailoutKind kind) |
|
173 { |
|
174 // assignSnapshot must be called before define/add, since |
|
175 // it may add new instructions for emitted-at-use operands. |
|
176 JS_ASSERT(ins->id() == 0); |
|
177 |
|
178 LSnapshot *snapshot = buildSnapshot(ins, lastResumePoint_, kind); |
|
179 if (!snapshot) |
|
180 return false; |
|
181 |
|
182 ins->assignSnapshot(snapshot); |
|
183 return true; |
|
184 } |
|
185 |
|
186 bool |
|
187 LIRGeneratorShared::assignSafepoint(LInstruction *ins, MInstruction *mir) |
|
188 { |
|
189 JS_ASSERT(!osiPoint_); |
|
190 JS_ASSERT(!ins->safepoint()); |
|
191 |
|
192 ins->initSafepoint(alloc()); |
|
193 |
|
194 MResumePoint *mrp = mir->resumePoint() ? mir->resumePoint() : lastResumePoint_; |
|
195 LSnapshot *postSnapshot = buildSnapshot(ins, mrp, Bailout_Normal); |
|
196 if (!postSnapshot) |
|
197 return false; |
|
198 |
|
199 osiPoint_ = new(alloc()) LOsiPoint(ins->safepoint(), postSnapshot); |
|
200 |
|
201 return lirGraph_.noteNeedsSafepoint(ins); |
|
202 } |
|
203 |