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 95862 : ImmutableSync::ImmutableSync()
51 95862 : : cx(NULL), entries(NULL), frame(NULL), avail(Registers::AvailRegs), generation(0)
52 : {
53 95862 : }
54 :
55 95862 : ImmutableSync::~ImmutableSync()
56 : {
57 95862 : if (cx)
58 93731 : cx->free_(entries);
59 95862 : }
60 :
61 : bool
62 93731 : ImmutableSync::init(JSContext *cx, const FrameState &frame, uint32_t nentries)
63 : {
64 93731 : this->cx = cx;
65 93731 : this->frame = &frame;
66 :
67 93731 : entries = (SyncEntry *)OffTheBooks::calloc_(sizeof(SyncEntry) * nentries);
68 93731 : return !!entries;
69 : }
70 :
71 : void
72 75565 : ImmutableSync::reset(Assembler *masm, Registers avail, FrameEntry *top, FrameEntry *bottom)
73 : {
74 75565 : this->avail = avail;
75 75565 : this->masm = masm;
76 75565 : this->top = top;
77 75565 : this->bottom = bottom;
78 75565 : this->generation++;
79 75565 : memset(regs, 0, sizeof(regs));
80 75565 : }
81 :
82 : inline JSC::MacroAssembler::RegisterID
83 133392 : ImmutableSync::doAllocReg()
84 : {
85 133392 : if (!avail.empty())
86 108228 : return avail.takeAnyReg().reg();
87 :
88 25164 : uint32_t lastResort = FrameState::InvalidIndex;
89 25164 : uint32_t evictFromFrame = FrameState::InvalidIndex;
90 :
91 : /* Find something to evict. */
92 64247 : for (uint32_t i = 0; i < Registers::TotalRegisters; i++) {
93 62147 : RegisterID reg = RegisterID(i);
94 62147 : if (!(Registers::maskReg(reg) & Registers::AvailRegs))
95 5442 : continue;
96 :
97 56705 : if (frame->regstate(reg).isPinned())
98 2305 : continue;
99 :
100 54400 : lastResort = i;
101 :
102 54400 : if (!regs[i]) {
103 : /* If the frame does not own this register, take it! */
104 30532 : FrameEntry *fe = frame->regstate(reg).usedBy();
105 30532 : if (!fe)
106 11151 : return reg;
107 :
108 19381 : 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 19381 : if (!fe->isCopied())
115 11913 : break;
116 : }
117 : }
118 :
119 14013 : if (evictFromFrame != FrameState::InvalidIndex) {
120 13416 : RegisterID evict = RegisterID(evictFromFrame);
121 13416 : FrameEntry *fe = frame->regstate(evict).usedBy();
122 13416 : SyncEntry &e = entryFor(fe);
123 13416 : if (frame->regstate(evict).type() == RematInfo::TYPE) {
124 6994 : JS_ASSERT(!e.typeClobbered);
125 6994 : e.typeClobbered = true;
126 : } else {
127 6422 : JS_ASSERT(!e.dataClobbered);
128 6422 : e.dataClobbered = true;
129 : }
130 13416 : return evict;
131 : }
132 :
133 597 : JS_ASSERT(lastResort != FrameState::InvalidIndex);
134 597 : JS_ASSERT(regs[lastResort]);
135 :
136 597 : SyncEntry *e = regs[lastResort];
137 597 : RegisterID reg = RegisterID(lastResort);
138 597 : if (e->hasDataReg && e->dataReg == reg) {
139 309 : e->hasDataReg = false;
140 288 : } else if (e->hasTypeReg && e->typeReg == reg) {
141 288 : e->hasTypeReg = false;
142 : } else {
143 0 : JS_NOT_REACHED("no way");
144 : }
145 :
146 597 : return reg;
147 : }
148 :
149 : JSC::MacroAssembler::RegisterID
150 133392 : ImmutableSync::allocReg()
151 : {
152 133392 : RegisterID reg = doAllocReg();
153 133392 : JS_ASSERT(!frame->regstate(reg).isPinned());
154 133392 : return reg;
155 : }
156 :
157 : void
158 261872 : ImmutableSync::freeReg(JSC::MacroAssembler::RegisterID reg)
159 : {
160 261872 : if (!frame->regstate(reg).isPinned())
161 259676 : avail.putReg(reg);
162 261872 : }
163 :
164 : inline ImmutableSync::SyncEntry &
165 438941 : ImmutableSync::entryFor(FrameEntry *fe)
166 : {
167 438941 : JS_ASSERT(fe <= top || frame->isTemporary(fe));
168 438941 : SyncEntry &e = entries[fe - frame->entries];
169 438941 : if (e.generation != generation)
170 297349 : e.reset(generation);
171 438941 : return e;
172 : }
173 :
174 : void
175 425525 : ImmutableSync::sync(FrameEntry *fe)
176 : {
177 425525 : if (fe->isCopy())
178 128214 : syncCopy(fe);
179 : else
180 297311 : syncNormal(fe);
181 425525 : }
182 :
183 : bool
184 246479 : ImmutableSync::shouldSyncType(FrameEntry *fe, SyncEntry &e)
185 : {
186 : /* Registers are synced up-front. */
187 246479 : return !fe->type.synced() && !fe->type.inRegister();
188 : }
189 :
190 : bool
191 297311 : ImmutableSync::shouldSyncData(FrameEntry *fe, SyncEntry &e)
192 : {
193 : /* Registers are synced up-front. */
194 297311 : return !fe->data.synced() && !fe->data.inRegister();
195 : }
196 :
197 : JSC::MacroAssembler::RegisterID
198 60479 : ImmutableSync::ensureTypeReg(FrameEntry *fe, SyncEntry &e)
199 : {
200 60479 : if (fe->type.inRegister() && !e.typeClobbered)
201 24012 : return fe->type.reg();
202 36467 : if (e.hasTypeReg)
203 2272 : return e.typeReg;
204 34195 : e.typeReg = allocReg();
205 34195 : e.hasTypeReg = true;
206 34195 : regs[e.typeReg] = &e;
207 34195 : masm->loadTypeTag(frame->addressOf(fe), e.typeReg);
208 34195 : return e.typeReg;
209 : }
210 :
211 : JSC::MacroAssembler::RegisterID
212 127684 : ImmutableSync::ensureDataReg(FrameEntry *fe, SyncEntry &e)
213 : {
214 127684 : if (fe->data.inRegister() && !e.dataClobbered)
215 22528 : return fe->data.reg();
216 105156 : if (e.hasDataReg)
217 5959 : return e.dataReg;
218 99197 : e.dataReg = allocReg();
219 99197 : e.hasDataReg = true;
220 99197 : regs[e.dataReg] = &e;
221 99197 : masm->loadPayload(frame->addressOf(fe), e.dataReg);
222 99197 : return e.dataReg;
223 : }
224 :
225 : void
226 128214 : ImmutableSync::syncCopy(FrameEntry *fe)
227 : {
228 128214 : JS_ASSERT(fe >= bottom);
229 :
230 128214 : FrameEntry *backing = fe->copyOf();
231 128214 : SyncEntry &e = entryFor(backing);
232 :
233 128214 : JS_ASSERT(!backing->isConstant());
234 :
235 128214 : Address addr = frame->addressOf(fe);
236 :
237 128214 : if (fe->isTypeKnown() && !fe->isType(JSVAL_TYPE_DOUBLE) && !e.learnedType) {
238 62134 : e.learnedType = true;
239 62134 : e.type = fe->getKnownType();
240 : }
241 :
242 128214 : if (!fe->data.synced())
243 127405 : masm->storePayload(ensureDataReg(backing, e), addr);
244 :
245 128214 : if (!fe->type.synced()) {
246 127377 : if (e.learnedType)
247 67177 : masm->storeTypeTag(ImmType(e.type), addr);
248 : else
249 60200 : masm->storeTypeTag(ensureTypeReg(backing, e), addr);
250 : }
251 128214 : }
252 :
253 : void
254 297311 : ImmutableSync::syncNormal(FrameEntry *fe)
255 : {
256 297311 : SyncEntry &e = entryFor(fe);
257 :
258 297311 : Address addr = frame->addressOf(fe);
259 :
260 297311 : if (fe->isTypeKnown() && !fe->isType(JSVAL_TYPE_DOUBLE)) {
261 157216 : e.learnedType = true;
262 157216 : e.type = fe->getKnownType();
263 : }
264 :
265 297311 : if (shouldSyncData(fe, e)) {
266 51111 : if (fe->isConstant()) {
267 50832 : masm->storeValue(fe->getValue(), addr);
268 50832 : return;
269 : }
270 279 : masm->storePayload(ensureDataReg(fe, e), addr);
271 : }
272 :
273 246479 : if (shouldSyncType(fe, e)) {
274 21194 : if (e.learnedType)
275 20915 : masm->storeTypeTag(ImmType(e.type), addr);
276 : else
277 279 : masm->storeTypeTag(ensureTypeReg(fe, e), addr);
278 : }
279 :
280 246479 : if (e.hasDataReg) {
281 98854 : freeReg(e.dataReg);
282 98854 : regs[e.dataReg] = NULL;
283 363277 : } else if (!e.dataClobbered &&
284 141220 : fe->data.inRegister() &&
285 74432 : frame->regstate(fe->data.reg()).usedBy()) {
286 74432 : freeReg(fe->data.reg());
287 : }
288 :
289 246479 : if (e.hasTypeReg) {
290 33907 : freeReg(e.typeReg);
291 33907 : regs[e.typeReg] = NULL;
292 472980 : } else if (!e.typeClobbered &&
293 205729 : fe->type.inRegister() &&
294 54679 : frame->regstate(fe->type.reg()).usedBy()) {
295 54679 : freeReg(fe->type.reg());
296 : }
297 : }
298 :
299 : #endif /* JS_NUNBOX32 */
300 :
|