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 134254 : ImmutableSync::ImmutableSync()
51 134254 : : cx(NULL), entries(NULL), frame(NULL), avail(Registers::AvailRegs), generation(0)
52 : {
53 134254 : }
54 :
55 134254 : ImmutableSync::~ImmutableSync()
56 : {
57 134254 : if (cx)
58 129049 : cx->free_(entries);
59 134254 : }
60 :
61 : bool
62 129049 : ImmutableSync::init(JSContext *cx, const FrameState &frame, uint32_t nentries)
63 : {
64 129049 : this->cx = cx;
65 129049 : this->frame = &frame;
66 :
67 129049 : entries = (SyncEntry *)OffTheBooks::calloc_(sizeof(SyncEntry) * nentries);
68 129049 : return !!entries;
69 : }
70 :
71 : void
72 171245 : ImmutableSync::reset(Assembler *masm, Registers avail, FrameEntry *top, FrameEntry *bottom)
73 : {
74 171245 : this->avail = avail;
75 171245 : this->masm = masm;
76 171245 : this->top = top;
77 171245 : this->bottom = bottom;
78 171245 : this->generation++;
79 171245 : memset(regs, 0, sizeof(regs));
80 171245 : }
81 :
82 : inline JSC::MacroAssembler::RegisterID
83 279944 : ImmutableSync::doAllocReg()
84 : {
85 279944 : if (!avail.empty())
86 222136 : return avail.takeAnyReg().reg();
87 :
88 57808 : uint32_t lastResort = FrameState::InvalidIndex;
89 57808 : uint32_t evictFromFrame = FrameState::InvalidIndex;
90 :
91 : /* Find something to evict. */
92 129672 : for (uint32_t i = 0; i < Registers::TotalRegisters; i++) {
93 127474 : RegisterID reg = RegisterID(i);
94 127474 : if (!(Registers::maskReg(reg) & Registers::AvailRegs))
95 8712 : continue;
96 :
97 118762 : if (frame->regstate(reg).isPinned())
98 2303 : continue;
99 :
100 116459 : lastResort = i;
101 :
102 116459 : if (!regs[i]) {
103 : /* If the frame does not own this register, take it! */
104 73605 : FrameEntry *fe = frame->regstate(reg).usedBy();
105 73605 : if (!fe)
106 23311 : return reg;
107 :
108 50294 : 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 50294 : if (!fe->isCopied())
115 32299 : break;
116 : }
117 : }
118 :
119 34497 : if (evictFromFrame != FrameState::InvalidIndex) {
120 33851 : RegisterID evict = RegisterID(evictFromFrame);
121 33851 : FrameEntry *fe = frame->regstate(evict).usedBy();
122 33851 : SyncEntry &e = entryFor(fe);
123 33851 : if (frame->regstate(evict).type() == RematInfo::TYPE) {
124 13891 : JS_ASSERT(!e.typeClobbered);
125 13891 : e.typeClobbered = true;
126 : } else {
127 19960 : JS_ASSERT(!e.dataClobbered);
128 19960 : e.dataClobbered = true;
129 : }
130 33851 : 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 279944 : ImmutableSync::allocReg()
151 : {
152 279944 : RegisterID reg = doAllocReg();
153 279944 : JS_ASSERT(!frame->regstate(reg).isPinned());
154 279944 : return reg;
155 : }
156 :
157 : void
158 596036 : ImmutableSync::freeReg(JSC::MacroAssembler::RegisterID reg)
159 : {
160 596036 : if (!frame->regstate(reg).isPinned())
161 593838 : avail.putReg(reg);
162 596036 : }
163 :
164 : inline ImmutableSync::SyncEntry &
165 839381 : ImmutableSync::entryFor(FrameEntry *fe)
166 : {
167 839381 : JS_ASSERT(fe <= top || frame->isTemporary(fe));
168 839381 : SyncEntry &e = entries[fe - frame->entries];
169 839381 : if (e.generation != generation)
170 556725 : e.reset(generation);
171 839381 : return e;
172 : }
173 :
174 : void
175 805530 : ImmutableSync::sync(FrameEntry *fe)
176 : {
177 805530 : if (fe->isCopy())
178 248843 : syncCopy(fe);
179 : else
180 556687 : syncNormal(fe);
181 805530 : }
182 :
183 : bool
184 499910 : ImmutableSync::shouldSyncType(FrameEntry *fe, SyncEntry &e)
185 : {
186 : /* Registers are synced up-front. */
187 499910 : return !fe->type.synced() && !fe->type.inRegister();
188 : }
189 :
190 : bool
191 556687 : ImmutableSync::shouldSyncData(FrameEntry *fe, SyncEntry &e)
192 : {
193 : /* Registers are synced up-front. */
194 556687 : return !fe->data.synced() && !fe->data.inRegister();
195 : }
196 :
197 : JSC::MacroAssembler::RegisterID
198 164521 : ImmutableSync::ensureTypeReg(FrameEntry *fe, SyncEntry &e)
199 : {
200 164521 : if (fe->type.inRegister() && !e.typeClobbered)
201 84185 : return fe->type.reg();
202 80336 : if (e.hasTypeReg)
203 2337 : return e.typeReg;
204 77999 : e.typeReg = allocReg();
205 77999 : e.hasTypeReg = true;
206 77999 : regs[e.typeReg] = &e;
207 77999 : masm->loadTypeTag(frame->addressOf(fe), e.typeReg);
208 77999 : return e.typeReg;
209 : }
210 :
211 : JSC::MacroAssembler::RegisterID
212 247022 : ImmutableSync::ensureDataReg(FrameEntry *fe, SyncEntry &e)
213 : {
214 247022 : if (fe->data.inRegister() && !e.dataClobbered)
215 37097 : return fe->data.reg();
216 209925 : if (e.hasDataReg)
217 7980 : return e.dataReg;
218 201945 : e.dataReg = allocReg();
219 201945 : e.hasDataReg = true;
220 201945 : regs[e.dataReg] = &e;
221 201945 : masm->loadPayload(frame->addressOf(fe), e.dataReg);
222 201945 : return e.dataReg;
223 : }
224 :
225 : void
226 248843 : ImmutableSync::syncCopy(FrameEntry *fe)
227 : {
228 248843 : JS_ASSERT(fe >= bottom);
229 :
230 248843 : FrameEntry *backing = fe->copyOf();
231 248843 : SyncEntry &e = entryFor(backing);
232 :
233 248843 : JS_ASSERT(!backing->isConstant());
234 :
235 248843 : Address addr = frame->addressOf(fe);
236 :
237 248843 : if (fe->isTypeKnown() && !fe->isType(JSVAL_TYPE_DOUBLE) && !e.learnedType) {
238 77197 : e.learnedType = true;
239 77197 : e.type = fe->getKnownType();
240 : }
241 :
242 248843 : if (!fe->data.synced())
243 246786 : masm->storePayload(ensureDataReg(backing, e), addr);
244 :
245 248843 : if (!fe->type.synced()) {
246 246758 : if (e.learnedType)
247 82473 : masm->storeTypeTag(ImmType(e.type), addr);
248 : else
249 164285 : masm->storeTypeTag(ensureTypeReg(backing, e), addr);
250 : }
251 248843 : }
252 :
253 : void
254 556687 : ImmutableSync::syncNormal(FrameEntry *fe)
255 : {
256 556687 : SyncEntry &e = entryFor(fe);
257 :
258 556687 : Address addr = frame->addressOf(fe);
259 :
260 556687 : if (fe->isTypeKnown() && !fe->isType(JSVAL_TYPE_DOUBLE)) {
261 187188 : e.learnedType = true;
262 187188 : e.type = fe->getKnownType();
263 : }
264 :
265 556687 : if (shouldSyncData(fe, e)) {
266 57013 : if (fe->isConstant()) {
267 56777 : masm->storeValue(fe->getValue(), addr);
268 56777 : return;
269 : }
270 236 : masm->storePayload(ensureDataReg(fe, e), addr);
271 : }
272 :
273 499910 : if (shouldSyncType(fe, e)) {
274 37603 : if (e.learnedType)
275 37367 : masm->storeTypeTag(ImmType(e.type), addr);
276 : else
277 236 : masm->storeTypeTag(ensureTypeReg(fe, e), addr);
278 : }
279 :
280 499910 : if (e.hasDataReg) {
281 201556 : freeReg(e.dataReg);
282 201556 : regs[e.dataReg] = NULL;
283 720001 : } else if (!e.dataClobbered &&
284 278454 : fe->data.inRegister() &&
285 143193 : frame->regstate(fe->data.reg()).usedBy()) {
286 143193 : freeReg(fe->data.reg());
287 : }
288 :
289 499910 : if (e.hasTypeReg) {
290 77708 : freeReg(e.typeReg);
291 77708 : regs[e.typeReg] = NULL;
292 1004246 : } else if (!e.typeClobbered &&
293 408465 : fe->type.inRegister() &&
294 173579 : frame->regstate(fe->type.reg()).usedBy()) {
295 173579 : freeReg(fe->type.reg());
296 : }
297 : }
298 :
299 : #endif /* JS_NUNBOX32 */
300 :
|