1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=4 sw=4 et tw=99:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 : * May 28, 2008.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Brendan Eich <brendan@mozilla.org>
22 : *
23 : * Contributor(s):
24 : * David Anderson <danderson@mozilla.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #if defined JS_NUNBOX32
41 :
42 : #include "FrameEntry.h"
43 : #include "FrameState.h"
44 : #include "FrameState-inl.h"
45 : #include "ImmutableSync.h"
46 :
47 : using namespace js;
48 : using namespace js::mjit;
49 :
50 134091 : ImmutableSync::ImmutableSync()
51 134091 : : cx(NULL), entries(NULL), frame(NULL), avail(Registers::AvailRegs), generation(0)
52 : {
53 134091 : }
54 :
55 134091 : ImmutableSync::~ImmutableSync()
56 : {
57 134091 : if (cx)
58 128881 : cx->free_(entries);
59 134091 : }
60 :
61 : bool
62 128881 : ImmutableSync::init(JSContext *cx, const FrameState &frame, uint32_t nentries)
63 : {
64 128881 : this->cx = cx;
65 128881 : this->frame = &frame;
66 :
67 128881 : entries = (SyncEntry *)OffTheBooks::calloc_(sizeof(SyncEntry) * nentries);
68 128881 : return !!entries;
69 : }
70 :
71 : void
72 171297 : ImmutableSync::reset(Assembler *masm, Registers avail, FrameEntry *top, FrameEntry *bottom)
73 : {
74 171297 : this->avail = avail;
75 171297 : this->masm = masm;
76 171297 : this->top = top;
77 171297 : this->bottom = bottom;
78 171297 : this->generation++;
79 171297 : memset(regs, 0, sizeof(regs));
80 171297 : }
81 :
82 : inline JSC::MacroAssembler::RegisterID
83 280288 : ImmutableSync::doAllocReg()
84 : {
85 280288 : if (!avail.empty())
86 222590 : return avail.takeAnyReg().reg();
87 :
88 57698 : uint32_t lastResort = FrameState::InvalidIndex;
89 57698 : uint32_t evictFromFrame = FrameState::InvalidIndex;
90 :
91 : /* Find something to evict. */
92 129643 : for (uint32_t i = 0; i < Registers::TotalRegisters; i++) {
93 127445 : RegisterID reg = RegisterID(i);
94 127445 : if (!(Registers::maskReg(reg) & Registers::AvailRegs))
95 8708 : continue;
96 :
97 118737 : if (frame->regstate(reg).isPinned())
98 2305 : continue;
99 :
100 116432 : lastResort = i;
101 :
102 116432 : if (!regs[i]) {
103 : /* If the frame does not own this register, take it! */
104 73501 : FrameEntry *fe = frame->regstate(reg).usedBy();
105 73501 : if (!fe)
106 23227 : return reg;
107 :
108 50274 : evictFromFrame = i;
109 :
110 : /*
111 : * If not copied, we can sync and not have to load again later.
112 : * That's about as good as it gets, so just break out now.
113 : */
114 50274 : if (!fe->isCopied())
115 32273 : break;
116 : }
117 : }
118 :
119 34471 : if (evictFromFrame != FrameState::InvalidIndex) {
120 33825 : RegisterID evict = RegisterID(evictFromFrame);
121 33825 : FrameEntry *fe = frame->regstate(evict).usedBy();
122 33825 : SyncEntry &e = entryFor(fe);
123 33825 : if (frame->regstate(evict).type() == RematInfo::TYPE) {
124 13843 : JS_ASSERT(!e.typeClobbered);
125 13843 : e.typeClobbered = true;
126 : } else {
127 19982 : JS_ASSERT(!e.dataClobbered);
128 19982 : e.dataClobbered = true;
129 : }
130 33825 : return evict;
131 : }
132 :
133 646 : JS_ASSERT(lastResort != FrameState::InvalidIndex);
134 646 : JS_ASSERT(regs[lastResort]);
135 :
136 646 : SyncEntry *e = regs[lastResort];
137 646 : RegisterID reg = RegisterID(lastResort);
138 646 : if (e->hasDataReg && e->dataReg == reg) {
139 355 : e->hasDataReg = false;
140 291 : } else if (e->hasTypeReg && e->typeReg == reg) {
141 291 : e->hasTypeReg = false;
142 : } else {
143 0 : JS_NOT_REACHED("no way");
144 : }
145 :
146 646 : return reg;
147 : }
148 :
149 : JSC::MacroAssembler::RegisterID
150 280288 : ImmutableSync::allocReg()
151 : {
152 280288 : RegisterID reg = doAllocReg();
153 280288 : JS_ASSERT(!frame->regstate(reg).isPinned());
154 280288 : return reg;
155 : }
156 :
157 : void
158 595780 : ImmutableSync::freeReg(JSC::MacroAssembler::RegisterID reg)
159 : {
160 595780 : if (!frame->regstate(reg).isPinned())
161 593554 : avail.putReg(reg);
162 595780 : }
163 :
164 : inline ImmutableSync::SyncEntry &
165 840248 : ImmutableSync::entryFor(FrameEntry *fe)
166 : {
167 840248 : JS_ASSERT(fe <= top || frame->isTemporary(fe));
168 840248 : SyncEntry &e = entries[fe - frame->entries];
169 840248 : if (e.generation != generation)
170 557367 : e.reset(generation);
171 840248 : return e;
172 : }
173 :
174 : void
175 806423 : ImmutableSync::sync(FrameEntry *fe)
176 : {
177 806423 : if (fe->isCopy())
178 249094 : syncCopy(fe);
179 : else
180 557329 : syncNormal(fe);
181 806423 : }
182 :
183 : bool
184 500226 : ImmutableSync::shouldSyncType(FrameEntry *fe, SyncEntry &e)
185 : {
186 : /* Registers are synced up-front. */
187 500226 : return !fe->type.synced() && !fe->type.inRegister();
188 : }
189 :
190 : bool
191 557329 : ImmutableSync::shouldSyncData(FrameEntry *fe, SyncEntry &e)
192 : {
193 : /* Registers are synced up-front. */
194 557329 : return !fe->data.synced() && !fe->data.inRegister();
195 : }
196 :
197 : JSC::MacroAssembler::RegisterID
198 164496 : ImmutableSync::ensureTypeReg(FrameEntry *fe, SyncEntry &e)
199 : {
200 164496 : if (fe->type.inRegister() && !e.typeClobbered)
201 84113 : return fe->type.reg();
202 80383 : if (e.hasTypeReg)
203 2344 : return e.typeReg;
204 78039 : e.typeReg = allocReg();
205 78039 : e.hasTypeReg = true;
206 78039 : regs[e.typeReg] = &e;
207 78039 : masm->loadTypeTag(frame->addressOf(fe), e.typeReg);
208 78039 : return e.typeReg;
209 : }
210 :
211 : JSC::MacroAssembler::RegisterID
212 247283 : ImmutableSync::ensureDataReg(FrameEntry *fe, SyncEntry &e)
213 : {
214 247283 : if (fe->data.inRegister() && !e.dataClobbered)
215 37062 : return fe->data.reg();
216 210221 : if (e.hasDataReg)
217 7972 : return e.dataReg;
218 202249 : e.dataReg = allocReg();
219 202249 : e.hasDataReg = true;
220 202249 : regs[e.dataReg] = &e;
221 202249 : masm->loadPayload(frame->addressOf(fe), e.dataReg);
222 202249 : return e.dataReg;
223 : }
224 :
225 : void
226 249094 : ImmutableSync::syncCopy(FrameEntry *fe)
227 : {
228 249094 : JS_ASSERT(fe >= bottom);
229 :
230 249094 : FrameEntry *backing = fe->copyOf();
231 249094 : SyncEntry &e = entryFor(backing);
232 :
233 249094 : JS_ASSERT(!backing->isConstant());
234 :
235 249094 : Address addr = frame->addressOf(fe);
236 :
237 249094 : if (fe->isTypeKnown() && !fe->isType(JSVAL_TYPE_DOUBLE) && !e.learnedType) {
238 77531 : e.learnedType = true;
239 77531 : e.type = fe->getKnownType();
240 : }
241 :
242 249094 : if (!fe->data.synced())
243 247003 : masm->storePayload(ensureDataReg(backing, e), addr);
244 :
245 249094 : if (!fe->type.synced()) {
246 246975 : if (e.learnedType)
247 82759 : masm->storeTypeTag(ImmType(e.type), addr);
248 : else
249 164216 : masm->storeTypeTag(ensureTypeReg(backing, e), addr);
250 : }
251 249094 : }
252 :
253 : void
254 557329 : ImmutableSync::syncNormal(FrameEntry *fe)
255 : {
256 557329 : SyncEntry &e = entryFor(fe);
257 :
258 557329 : Address addr = frame->addressOf(fe);
259 :
260 557329 : if (fe->isTypeKnown() && !fe->isType(JSVAL_TYPE_DOUBLE)) {
261 187838 : e.learnedType = true;
262 187838 : e.type = fe->getKnownType();
263 : }
264 :
265 557329 : if (shouldSyncData(fe, e)) {
266 57383 : if (fe->isConstant()) {
267 57103 : masm->storeValue(fe->getValue(), addr);
268 57103 : return;
269 : }
270 280 : masm->storePayload(ensureDataReg(fe, e), addr);
271 : }
272 :
273 500226 : if (shouldSyncType(fe, e)) {
274 37405 : if (e.learnedType)
275 37125 : masm->storeTypeTag(ImmType(e.type), addr);
276 : else
277 280 : masm->storeTypeTag(ensureTypeReg(fe, e), addr);
278 : }
279 :
280 500226 : if (e.hasDataReg) {
281 201860 : freeReg(e.dataReg);
282 201860 : regs[e.dataReg] = NULL;
283 719527 : } else if (!e.dataClobbered &&
284 278444 : fe->data.inRegister() &&
285 142717 : frame->regstate(fe->data.reg()).usedBy()) {
286 142717 : freeReg(fe->data.reg());
287 : }
288 :
289 500226 : if (e.hasTypeReg) {
290 77748 : freeReg(e.typeReg);
291 77748 : regs[e.typeReg] = NULL;
292 1004722 : } else if (!e.typeClobbered &&
293 408789 : fe->type.inRegister() &&
294 173455 : frame->regstate(fe->type.reg()).usedBy()) {
295 173455 : freeReg(fe->type.reg());
296 : }
297 : }
298 :
299 : #endif /* JS_NUNBOX32 */
300 :
|