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 jsjaeger_framestate_inl_h__ && defined JS_METHODJIT
41 : #define jsjaeger_framestate_inl_h__
42 :
43 : #include "methodjit/LoopState.h"
44 :
45 : namespace js {
46 : namespace mjit {
47 :
48 : inline void
49 2611607 : FrameState::addToTracker(FrameEntry *fe)
50 : {
51 2611607 : JS_ASSERT(!fe->isTracked());
52 2611607 : fe->track(tracker.nentries);
53 2611607 : tracker.add(fe);
54 2611607 : }
55 :
56 : inline FrameEntry *
57 18442423 : FrameState::peek(int32_t depth)
58 : {
59 18442423 : JS_ASSERT(depth < 0);
60 18442423 : JS_ASSERT(a->sp + depth >= a->spBase);
61 18442423 : FrameEntry *fe = a->sp + depth;
62 18442423 : if (!fe->isTracked()) {
63 125094 : addToTracker(fe);
64 125094 : fe->resetSynced();
65 : }
66 18442423 : return fe;
67 : }
68 :
69 : inline void
70 2324671 : FrameState::popn(uint32_t n)
71 : {
72 6875392 : for (uint32_t i = 0; i < n; i++)
73 4550721 : pop();
74 2324671 : }
75 :
76 : inline bool
77 744463 : FrameState::haveSameBacking(FrameEntry *lhs, FrameEntry *rhs)
78 : {
79 744463 : if (lhs->isCopy())
80 275070 : lhs = lhs->copyOf();
81 744463 : if (rhs->isCopy())
82 22050 : rhs = rhs->copyOf();
83 744463 : return lhs == rhs;
84 : }
85 :
86 : inline FrameEntry *
87 18975 : FrameState::getTemporary(uint32_t which)
88 : {
89 18975 : JS_ASSERT(which < TEMPORARY_LIMIT);
90 :
91 18975 : FrameEntry *fe = temporaries + which;
92 18975 : JS_ASSERT(fe < temporariesTop);
93 :
94 18975 : return getOrTrack(uint32_t(fe - entries));
95 : }
96 :
97 : inline AnyRegisterID
98 5718787 : FrameState::allocReg(uint32_t mask)
99 : {
100 5718787 : if (freeRegs.hasRegInMask(mask)) {
101 5602082 : AnyRegisterID reg = freeRegs.takeAnyReg(mask);
102 5602082 : modifyReg(reg);
103 5602082 : return reg;
104 : }
105 :
106 116705 : AnyRegisterID reg = evictSomeReg(mask);
107 116705 : modifyReg(reg);
108 116705 : return reg;
109 : }
110 :
111 : inline JSC::MacroAssembler::RegisterID
112 4351894 : FrameState::allocReg()
113 : {
114 4351894 : return allocReg(Registers::AvailRegs).reg();
115 : }
116 :
117 : inline JSC::MacroAssembler::FPRegisterID
118 1338075 : FrameState::allocFPReg()
119 : {
120 1338075 : return allocReg(Registers::AvailFPRegs).fpreg();
121 : }
122 :
123 : inline AnyRegisterID
124 2056813 : FrameState::allocAndLoadReg(FrameEntry *fe, bool fp, RematInfo::RematType type)
125 : {
126 2056813 : AnyRegisterID reg;
127 2056813 : uint32_t mask = fp ? (uint32_t) Registers::AvailFPRegs : (uint32_t) Registers::AvailRegs;
128 :
129 : /*
130 : * Decide whether to retroactively mark a register as holding the entry
131 : * at the start of the current loop. We can do this if (a) the register has
132 : * not been touched since the start of the loop (it is in loopRegs), (b)
133 : * the entry has also not been written to or already had a loop register
134 : * assigned, and (c) we are not in an inline call with multiple callees or
135 : * exit points --- we won't pick up the new loop register when restoring.
136 : */
137 2110335 : if (loop && freeRegs.hasRegInMask(loop->getLoopRegs() & mask) &&
138 37031 : type == RematInfo::DATA && isOuterSlot(fe) && !cc.activeFrameHasMultipleExits() &&
139 16491 : fe->lastLoop < loop->headOffset()) {
140 16190 : reg = freeRegs.takeAnyReg(loop->getLoopRegs() & mask);
141 16190 : regstate(reg).associate(fe, RematInfo::DATA);
142 16190 : fe->lastLoop = loop->headOffset();
143 16190 : loop->setLoopReg(reg, fe);
144 16190 : return reg;
145 : }
146 :
147 2040623 : if (!freeRegs.empty(mask))
148 1983003 : reg = freeRegs.takeAnyReg(mask);
149 : else
150 57620 : reg = evictSomeReg(mask);
151 2040623 : modifyReg(reg);
152 :
153 2040623 : if (fp)
154 1106 : masm.loadDouble(addressOf(fe), reg.fpreg());
155 2039517 : else if (type == RematInfo::TYPE)
156 1190942 : masm.loadTypeTag(addressOf(fe), reg.reg());
157 : else
158 848575 : masm.loadPayload(addressOf(fe), reg.reg());
159 :
160 2040623 : regstate(reg).associate(fe, type);
161 2040623 : return reg;
162 : }
163 :
164 : inline void
165 8551092 : FrameState::modifyReg(AnyRegisterID reg)
166 : {
167 8551092 : if (loop)
168 862693 : loop->clearLoopReg(reg);
169 8551092 : }
170 :
171 : inline void
172 11413 : FrameState::convertInt32ToDouble(Assembler &masm, FrameEntry *fe, FPRegisterID fpreg) const
173 : {
174 11413 : JS_ASSERT(!fe->isConstant());
175 :
176 11413 : if (fe->isCopy())
177 2295 : fe = fe->copyOf();
178 :
179 11413 : if (fe->data.inRegister())
180 9402 : masm.convertInt32ToDouble(fe->data.reg(), fpreg);
181 : else
182 2011 : masm.convertInt32ToDouble(masm.payloadOf(addressOf(fe)), fpreg);
183 11413 : }
184 :
185 : inline bool
186 0 : FrameState::peekTypeInRegister(FrameEntry *fe) const
187 : {
188 0 : if (fe->isCopy())
189 0 : fe = fe->copyOf();
190 0 : return fe->type.inRegister();
191 : }
192 :
193 : inline void
194 8868050 : FrameState::pop()
195 : {
196 8868050 : JS_ASSERT(a->sp > a->spBase);
197 :
198 8868050 : FrameEntry *fe = --a->sp;
199 8868050 : if (!fe->isTracked())
200 63068 : return;
201 :
202 8804982 : forgetAllRegs(fe);
203 8804982 : fe->type.invalidate();
204 8804982 : fe->data.invalidate();
205 8804982 : fe->clear();
206 :
207 8804982 : extraArray[fe - entries].reset();
208 : }
209 :
210 : inline void
211 1886492 : FrameState::freeReg(AnyRegisterID reg)
212 : {
213 1886492 : JS_ASSERT(!regstate(reg).usedBy());
214 :
215 1886492 : freeRegs.putReg(reg);
216 1886492 : }
217 :
218 : inline void
219 6352481 : FrameState::forgetReg(AnyRegisterID reg)
220 : {
221 : /*
222 : * Important: Do not touch the fe here. We can peephole optimize away
223 : * loads and stores by re-using the contents of old FEs.
224 : */
225 6352481 : JS_ASSERT_IF(regstate(reg).fe(), !regstate(reg).fe()->isCopy());
226 :
227 6352481 : if (!regstate(reg).isPinned()) {
228 5971623 : regstate(reg).forget();
229 5971623 : freeRegs.putReg(reg);
230 : }
231 6352481 : }
232 :
233 : inline FrameEntry *
234 8931761 : FrameState::rawPush()
235 : {
236 8931761 : JS_ASSERT(a->sp < temporaries);
237 8931761 : FrameEntry *fe = a->sp++;
238 :
239 8931761 : if (!fe->isTracked())
240 1751924 : addToTracker(fe);
241 8931761 : fe->type.invalidate();
242 8931761 : fe->data.invalidate();
243 8931761 : fe->clear();
244 :
245 8931761 : extraArray[fe - entries].reset();
246 :
247 8931761 : return fe;
248 : }
249 :
250 : inline void
251 1705328 : FrameState::push(const Value &v)
252 : {
253 1705328 : FrameEntry *fe = rawPush();
254 1705328 : fe->setConstant(v);
255 1705328 : }
256 :
257 : inline void
258 2726192 : FrameState::pushSynced(JSValueType type)
259 : {
260 2726192 : FrameEntry *fe = rawPush();
261 :
262 2726192 : fe->resetSynced();
263 2726192 : if (type != JSVAL_TYPE_UNKNOWN) {
264 95342 : fe->setType(type);
265 95342 : if (type == JSVAL_TYPE_DOUBLE)
266 257 : masm.ensureInMemoryDouble(addressOf(fe));
267 : }
268 2726192 : }
269 :
270 : inline void
271 : FrameState::pushSynced(JSValueType type, RegisterID reg)
272 : {
273 : FrameEntry *fe = rawPush();
274 :
275 : fe->resetUnsynced();
276 : fe->type.sync();
277 : fe->data.sync();
278 : fe->setType(type);
279 : fe->data.setRegister(reg);
280 : regstate(reg).associate(fe, RematInfo::DATA);
281 : }
282 :
283 : inline void
284 411799 : FrameState::loadIntoRegisters(Address address, bool reuseBase,
285 : RegisterID *ptypeReg, RegisterID *pdataReg)
286 : {
287 :
288 : #ifdef JS_PUNBOX64
289 :
290 : // It's okay if either of these clobbers address.base, since we guarantee
291 : // eviction will not physically clobber. It's also safe, on x64, for
292 : // loadValueAsComponents() to take either type or data regs as address.base.
293 : RegisterID typeReg = allocReg();
294 : RegisterID dataReg = reuseBase ? address.base : allocReg();
295 : masm.loadValueAsComponents(address, typeReg, dataReg);
296 :
297 : #elif JS_NUNBOX32
298 :
299 : // Prevent us from clobbering this reg.
300 411799 : bool free = freeRegs.hasReg(address.base);
301 411799 : bool needsPin = !free && regstate(address.base).fe();
302 411799 : if (free)
303 2071 : freeRegs.takeReg(address.base);
304 411799 : if (needsPin)
305 3685 : pinReg(address.base);
306 :
307 411799 : RegisterID typeReg = allocReg();
308 :
309 411799 : masm.loadTypeTag(address, typeReg);
310 :
311 : // Allow re-use of the base register. This could avoid a spill, and
312 : // is safe because the following allocReg() won't actually emit any
313 : // writes to the register.
314 411799 : if (free)
315 2071 : freeRegs.putReg(address.base);
316 411799 : if (needsPin)
317 3685 : unpinReg(address.base);
318 :
319 411799 : RegisterID dataReg = reuseBase ? address.base : allocReg();
320 411799 : masm.loadPayload(address, dataReg);
321 :
322 : #endif
323 :
324 411799 : *ptypeReg = typeReg;
325 411799 : *pdataReg = dataReg;
326 411799 : }
327 :
328 : inline void
329 381983 : FrameState::push(Address address, JSValueType knownType, bool reuseBase)
330 : {
331 381983 : if (knownType == JSVAL_TYPE_DOUBLE) {
332 1044 : FPRegisterID fpreg = allocFPReg();
333 1044 : masm.moveInt32OrDouble(address, fpreg);
334 1044 : pushDouble(fpreg);
335 1044 : if (reuseBase)
336 696 : freeReg(address.base);
337 1044 : return;
338 : }
339 :
340 380939 : if (knownType != JSVAL_TYPE_UNKNOWN) {
341 60629 : RegisterID dataReg = reuseBase ? address.base : allocReg();
342 60629 : masm.loadPayload(address, dataReg);
343 60629 : pushTypedPayload(knownType, dataReg);
344 60629 : return;
345 : }
346 :
347 : RegisterID typeReg, dataReg;
348 320310 : loadIntoRegisters(address, reuseBase, &typeReg, &dataReg);
349 :
350 320310 : pushRegs(typeReg, dataReg, JSVAL_TYPE_UNKNOWN);
351 : }
352 :
353 : inline void
354 0 : FrameState::pushWord(Address address, JSValueType knownType, bool reuseBase)
355 : {
356 0 : JS_ASSERT(knownType != JSVAL_TYPE_DOUBLE);
357 0 : JS_ASSERT(knownType != JSVAL_TYPE_UNKNOWN);
358 :
359 0 : RegisterID dataReg = reuseBase ? address.base : allocReg();
360 0 : masm.loadPtr(address, dataReg);
361 0 : pushTypedPayload(knownType, dataReg);
362 0 : }
363 :
364 : inline JSC::MacroAssembler::FPRegisterID
365 1905357 : FrameState::storeRegs(int32_t depth, RegisterID type, RegisterID data, JSValueType knownType)
366 : {
367 1905357 : FrameEntry *fe = peek(depth);
368 1905357 : forgetEntry(fe);
369 1905357 : fe->resetUnsynced();
370 :
371 : /*
372 : * Even if the type or data gets freed due to knownType or a double result,
373 : * neither register should be clobbered (see Compiler::testBarrier).
374 : */
375 1905357 : JS_ASSERT(!freeRegs.hasReg(type) && !freeRegs.hasReg(data));
376 :
377 1905357 : if (knownType == JSVAL_TYPE_UNKNOWN) {
378 1785479 : fe->type.setRegister(type);
379 1785479 : fe->data.setRegister(data);
380 1785479 : regstate(type).associate(fe, RematInfo::TYPE);
381 1785479 : regstate(data).associate(fe, RematInfo::DATA);
382 1785479 : return Registers::FPConversionTemp;
383 : }
384 :
385 119878 : if (knownType == JSVAL_TYPE_DOUBLE) {
386 9851 : FPRegisterID fpreg = allocFPReg();
387 9851 : masm.moveInt32OrDouble(data, type, addressOf(fe), fpreg);
388 9851 : fe->setType(JSVAL_TYPE_DOUBLE);
389 9851 : fe->data.setFPRegister(fpreg);
390 9851 : regstate(fpreg).associate(fe, RematInfo::DATA);
391 9851 : freeReg(type);
392 9851 : freeReg(data);
393 9851 : return fpreg;
394 : }
395 :
396 110027 : freeReg(type);
397 110027 : fe->setType(knownType);
398 110027 : fe->data.setRegister(data);
399 110027 : regstate(data).associate(fe, RematInfo::DATA);
400 110027 : return Registers::FPConversionTemp;
401 : }
402 :
403 : inline JSC::MacroAssembler::FPRegisterID
404 1905357 : FrameState::pushRegs(RegisterID type, RegisterID data, JSValueType knownType)
405 : {
406 1905357 : pushSynced(JSVAL_TYPE_UNKNOWN);
407 1905357 : return storeRegs(-1, type, data, knownType);
408 : }
409 :
410 : inline void
411 147709 : FrameState::reloadEntry(Assembler &masm, Address address, FrameEntry *fe)
412 : {
413 147709 : if (fe->data.inRegister()) {
414 146880 : if (fe->type.inRegister()) {
415 119079 : masm.loadValueAsComponents(address, fe->type.reg(), fe->data.reg());
416 : } else {
417 27801 : JS_ASSERT(fe->isTypeKnown());
418 27801 : masm.loadPayload(address, fe->data.reg());
419 : }
420 : } else {
421 829 : JS_ASSERT(fe->data.inFPRegister());
422 829 : masm.moveInt32OrDouble(address, fe->data.fpreg());
423 : }
424 147709 : }
425 :
426 : inline void
427 295683 : FrameState::pushTypedPayload(JSValueType type, RegisterID payload)
428 : {
429 295683 : JS_ASSERT(type != JSVAL_TYPE_DOUBLE);
430 295683 : JS_ASSERT(!freeRegs.hasReg(payload));
431 :
432 295683 : FrameEntry *fe = rawPush();
433 :
434 295683 : fe->resetUnsynced();
435 295683 : fe->setType(type);
436 295683 : fe->data.setRegister(payload);
437 295683 : regstate(payload).associate(fe, RematInfo::DATA);
438 295683 : }
439 :
440 : inline void
441 563361 : FrameState::pushNumber(RegisterID payload, bool asInt32)
442 : {
443 563361 : JS_ASSERT(!freeRegs.hasReg(payload));
444 :
445 563361 : FrameEntry *fe = rawPush();
446 :
447 563361 : if (asInt32) {
448 560289 : if (!fe->type.synced())
449 252146 : masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
450 560289 : fe->type.setMemory();
451 : } else {
452 3072 : fe->type.setMemory();
453 : }
454 :
455 563361 : fe->data.unsync();
456 563361 : fe->data.setRegister(payload);
457 563361 : regstate(payload).associate(fe, RematInfo::DATA);
458 563361 : }
459 :
460 : inline void
461 : FrameState::pushInt32(RegisterID payload)
462 : {
463 : FrameEntry *fe = rawPush();
464 :
465 : masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
466 : fe->type.setMemory();
467 :
468 : fe->data.unsync();
469 : fe->data.setRegister(payload);
470 : regstate(payload).associate(fe, RematInfo::DATA);
471 : }
472 :
473 : inline void
474 4645 : FrameState::pushUntypedPayload(JSValueType type, RegisterID payload)
475 : {
476 4645 : JS_ASSERT(!freeRegs.hasReg(payload));
477 :
478 4645 : FrameEntry *fe = rawPush();
479 :
480 4645 : masm.storeTypeTag(ImmType(type), addressOf(fe));
481 :
482 : /* The forceful type sync will assert otherwise. */
483 : #ifdef DEBUG
484 4645 : fe->type.unsync();
485 : #endif
486 4645 : fe->type.setMemory();
487 4645 : fe->data.unsync();
488 4645 : fe->data.setRegister(payload);
489 4645 : regstate(payload).associate(fe, RematInfo::DATA);
490 4645 : }
491 :
492 : inline void
493 : FrameState::pushUntypedValue(const Value &v)
494 : {
495 : FrameEntry *fe = rawPush();
496 :
497 : masm.storeValue(v, addressOf(fe));
498 :
499 : /* The forceful type sync will assert otherwise. */
500 : #ifdef DEBUG
501 : fe->type.unsync();
502 : #endif
503 : fe->type.setMemory();
504 : fe->data.unsync();
505 : fe->data.setMemory();
506 : }
507 :
508 : inline JSC::MacroAssembler::RegisterID
509 : FrameState::tempRegForType(FrameEntry *fe, RegisterID fallback)
510 : {
511 : JS_ASSERT(!regstate(fallback).fe());
512 : if (fe->isCopy())
513 : fe = fe->copyOf();
514 :
515 : JS_ASSERT(!fe->type.isConstant());
516 :
517 : if (fe->type.inRegister())
518 : return fe->type.reg();
519 :
520 : /* :XXX: X86 */
521 :
522 : masm.loadTypeTag(addressOf(fe), fallback);
523 : return fallback;
524 : }
525 :
526 :
527 : inline JSC::MacroAssembler::RegisterID
528 3300999 : FrameState::tempRegForType(FrameEntry *fe)
529 : {
530 3300999 : if (fe->isCopy())
531 416263 : fe = fe->copyOf();
532 :
533 3300999 : JS_ASSERT(!fe->type.isConstant());
534 :
535 3300999 : if (fe->type.inRegister())
536 2111628 : return fe->type.reg();
537 :
538 : /* :XXX: X86 */
539 :
540 1189371 : RegisterID reg = allocAndLoadReg(fe, false, RematInfo::TYPE).reg();
541 1189371 : fe->type.setRegister(reg);
542 1189371 : return reg;
543 : }
544 :
545 : inline void
546 0 : FrameState::loadTypeIntoReg(const FrameEntry *fe, RegisterID reg)
547 : {
548 0 : if (fe->isCopy())
549 0 : fe = fe->copyOf();
550 :
551 0 : JS_ASSERT(!fe->type.isConstant());
552 :
553 0 : if (fe->type.inRegister()) {
554 0 : if (fe->type.reg() == reg)
555 0 : return;
556 0 : masm.move(fe->type.reg(), reg);
557 0 : return;
558 : }
559 :
560 0 : masm.loadTypeTag(addressOf(fe), reg);
561 : }
562 :
563 : inline void
564 : FrameState::loadDataIntoReg(const FrameEntry *fe, RegisterID reg)
565 : {
566 : if (fe->isCopy())
567 : fe = fe->copyOf();
568 :
569 : JS_ASSERT(!fe->data.isConstant());
570 :
571 : if (fe->data.inRegister()) {
572 : if (fe->data.reg() == reg)
573 : return;
574 : masm.move(fe->data.reg(), reg);
575 : return;
576 : }
577 :
578 : masm.loadPayload(addressOf(fe), reg);
579 : }
580 :
581 : inline JSC::MacroAssembler::RegisterID
582 2998919 : FrameState::tempRegForData(FrameEntry *fe)
583 : {
584 2998919 : JS_ASSERT(!fe->isConstant());
585 2998919 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
586 :
587 2998919 : if (fe->isCopy())
588 307663 : fe = fe->copyOf();
589 :
590 2998919 : if (fe->data.inRegister())
591 2136722 : return fe->data.reg();
592 :
593 862197 : RegisterID reg = allocAndLoadReg(fe, false, RematInfo::DATA).reg();
594 862197 : fe->data.setRegister(reg);
595 862197 : return reg;
596 : }
597 :
598 : inline void
599 1099474 : FrameState::forgetMismatchedObject(FrameEntry *fe)
600 : {
601 1099474 : if (fe->isNotType(JSVAL_TYPE_OBJECT)) {
602 1055 : if (fe->isCopied()) {
603 1 : syncFe(fe);
604 1 : uncopy(fe);
605 1 : fe->resetSynced();
606 : } else {
607 1054 : syncAndForgetFe(fe);
608 : }
609 1055 : fe->clear();
610 : }
611 :
612 1099474 : if (fe->isConstant()) {
613 32264 : RegisterID reg = allocReg();
614 32264 : regstate(reg).associate(fe, RematInfo::DATA);
615 :
616 32264 : masm.move(JSC::MacroAssembler::ImmPtr(&fe->getValue().toObject()), reg);
617 32264 : fe->data.setRegister(reg);
618 : }
619 1099474 : }
620 :
621 : inline JSC::MacroAssembler::FPRegisterID
622 22746 : FrameState::tempFPRegForData(FrameEntry *fe)
623 : {
624 22746 : JS_ASSERT(!fe->isConstant());
625 22746 : JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
626 :
627 22746 : if (fe->isCopy())
628 1441 : fe = fe->copyOf();
629 :
630 22746 : JS_ASSERT(!fe->data.inRegister());
631 :
632 22746 : if (fe->data.inFPRegister())
633 21498 : return fe->data.fpreg();
634 :
635 1248 : FPRegisterID reg = allocAndLoadReg(fe, true, RematInfo::DATA).fpreg();
636 1248 : fe->data.setFPRegister(reg);
637 1248 : return reg;
638 : }
639 :
640 : inline AnyRegisterID
641 5011 : FrameState::tempRegInMaskForData(FrameEntry *fe, uint32_t mask)
642 : {
643 5011 : JS_ASSERT(!fe->isConstant());
644 5011 : JS_ASSERT_IF(fe->isType(JSVAL_TYPE_DOUBLE), !(mask & ~Registers::AvailFPRegs));
645 5011 : JS_ASSERT_IF(!fe->isType(JSVAL_TYPE_DOUBLE), !(mask & ~Registers::AvailRegs));
646 :
647 5011 : if (fe->isCopy())
648 544 : fe = fe->copyOf();
649 :
650 5011 : AnyRegisterID reg;
651 5011 : if (fe->data.inRegister() || fe->data.inFPRegister()) {
652 4289 : AnyRegisterID old;
653 4289 : if (fe->data.inRegister())
654 4235 : old = fe->data.reg();
655 : else
656 54 : old = fe->data.fpreg();
657 4289 : if (Registers::maskReg(old) & mask)
658 2473 : return old;
659 :
660 : /* Keep the old register pinned. */
661 1816 : regstate(old).forget();
662 1816 : reg = allocReg(mask);
663 1816 : if (reg.isReg())
664 1816 : masm.move(old.reg(), reg.reg());
665 : else
666 0 : masm.moveDouble(old.fpreg(), reg.fpreg());
667 1816 : freeReg(old);
668 : } else {
669 722 : reg = allocReg(mask);
670 722 : if (reg.isReg())
671 722 : masm.loadPayload(addressOf(fe), reg.reg());
672 : else
673 0 : masm.loadDouble(addressOf(fe), reg.fpreg());
674 : }
675 2538 : regstate(reg).associate(fe, RematInfo::DATA);
676 2538 : if (reg.isReg())
677 2538 : fe->data.setRegister(reg.reg());
678 : else
679 0 : fe->data.setFPRegister(reg.fpreg());
680 2538 : return reg;
681 : }
682 :
683 : inline JSC::MacroAssembler::RegisterID
684 : FrameState::tempRegForData(FrameEntry *fe, RegisterID reg, Assembler &masm) const
685 : {
686 : JS_ASSERT(!fe->data.isConstant());
687 :
688 : if (fe->isCopy())
689 : fe = fe->copyOf();
690 :
691 : JS_ASSERT(!fe->data.inFPRegister());
692 :
693 : if (fe->data.inRegister()) {
694 : JS_ASSERT(fe->data.reg() != reg);
695 : return fe->data.reg();
696 : } else {
697 : masm.loadPayload(addressOf(fe), reg);
698 : return reg;
699 : }
700 : }
701 :
702 : inline bool
703 409162 : FrameState::shouldAvoidTypeRemat(FrameEntry *fe)
704 : {
705 409162 : return !fe->isCopy() && fe->type.inMemory();
706 : }
707 :
708 : inline bool
709 43545 : FrameState::shouldAvoidDataRemat(FrameEntry *fe)
710 : {
711 43545 : return !fe->isCopy() && fe->data.inMemory();
712 : }
713 :
714 : inline void
715 55469 : FrameState::ensureFeSynced(const FrameEntry *fe, Assembler &masm) const
716 : {
717 55469 : Address to = addressOf(fe);
718 55469 : const FrameEntry *backing = fe;
719 55469 : if (fe->isCopy())
720 2485 : backing = fe->copyOf();
721 :
722 55469 : if (backing->isType(JSVAL_TYPE_DOUBLE)) {
723 51247 : if (fe->data.synced()) {
724 : /* Entries representing known doubles can't be partially synced. */
725 6146 : JS_ASSERT(fe->type.synced());
726 6146 : return;
727 : }
728 45101 : if (backing->isConstant()) {
729 11308 : masm.storeValue(backing->getValue(), to);
730 33793 : } else if (backing->data.inFPRegister()) {
731 32906 : masm.storeDouble(backing->data.fpreg(), to);
732 : } else {
733 : /* Use a temporary so the entry can be synced without allocating a register. */
734 887 : JS_ASSERT(backing->data.inMemory() && backing != fe);
735 887 : masm.loadDouble(addressOf(backing), Registers::FPConversionTemp);
736 887 : masm.storeDouble(Registers::FPConversionTemp, to);
737 : }
738 45101 : return;
739 : }
740 :
741 : #if defined JS_PUNBOX64
742 : /* If we can, sync the type and data in one go. */
743 : if (!fe->data.synced() && !fe->type.synced()) {
744 : if (backing->isConstant())
745 : masm.storeValue(backing->getValue(), to);
746 : else if (backing->isTypeKnown())
747 : masm.storeValueFromComponents(ImmType(backing->getKnownType()), backing->data.reg(), to);
748 : else
749 : masm.storeValueFromComponents(backing->type.reg(), backing->data.reg(), to);
750 : return;
751 : }
752 : #endif
753 :
754 : /*
755 : * On x86_64, only one of the following two calls will have output,
756 : * and a load will only occur if necessary.
757 : */
758 4222 : ensureDataSynced(fe, masm);
759 4222 : ensureTypeSynced(fe, masm);
760 : }
761 :
762 : inline void
763 15520668 : FrameState::ensureTypeSynced(const FrameEntry *fe, Assembler &masm) const
764 : {
765 15520668 : if (fe->type.synced())
766 7211084 : return;
767 :
768 8309584 : Address to = addressOf(fe);
769 8309584 : const FrameEntry *backing = fe;
770 8309584 : if (fe->isCopy())
771 1265222 : backing = fe->copyOf();
772 :
773 : #if defined JS_PUNBOX64
774 : /* Attempt to store the entire Value, to prevent a load. */
775 : if (backing->isConstant()) {
776 : masm.storeValue(backing->getValue(), to);
777 : return;
778 : }
779 :
780 : if (backing->data.inRegister()) {
781 : RegisterID dreg = backing->data.reg();
782 : if (backing->isTypeKnown())
783 : masm.storeValueFromComponents(ImmType(backing->getKnownType()), dreg, to);
784 : else
785 : masm.storeValueFromComponents(backing->type.reg(), dreg, to);
786 : return;
787 : }
788 : #endif
789 :
790 : /* Store a double's type bits, even though !isTypeKnown(). */
791 8309584 : if (backing->isConstant())
792 2380295 : masm.storeTypeTag(ImmTag(backing->getKnownTag()), to);
793 5929289 : else if (backing->isTypeKnown())
794 960233 : masm.storeTypeTag(ImmType(backing->getKnownType()), to);
795 : else
796 4969056 : masm.storeTypeTag(backing->type.reg(), to);
797 : }
798 :
799 : inline void
800 15729426 : FrameState::ensureDataSynced(const FrameEntry *fe, Assembler &masm) const
801 : {
802 15729426 : if (fe->data.synced())
803 6565850 : return;
804 :
805 9163576 : Address to = addressOf(fe);
806 9163576 : const FrameEntry *backing = fe;
807 9163576 : if (fe->isCopy())
808 1265450 : backing = fe->copyOf();
809 :
810 : #if defined JS_PUNBOX64
811 : if (backing->isConstant())
812 : masm.storeValue(backing->getValue(), to);
813 : else if (backing->isTypeKnown())
814 : masm.storeValueFromComponents(ImmType(backing->getKnownType()), backing->data.reg(), to);
815 : else if (backing->type.inRegister())
816 : masm.storeValueFromComponents(backing->type.reg(), backing->data.reg(), to);
817 : else
818 : masm.storePayload(backing->data.reg(), to);
819 : #elif defined JS_NUNBOX32
820 9163576 : if (backing->isConstant())
821 2380545 : masm.storePayload(ImmPayload(backing->getPayload()), to);
822 : else
823 6783031 : masm.storePayload(backing->data.reg(), to);
824 : #endif
825 : }
826 :
827 : inline void
828 6538262 : FrameState::syncFe(FrameEntry *fe)
829 : {
830 6538262 : if (fe->type.synced() && fe->data.synced())
831 4545589 : return;
832 :
833 1992673 : FrameEntry *backing = fe;
834 1992673 : if (fe->isCopy())
835 325395 : backing = fe->copyOf();
836 :
837 1992673 : if (backing->isType(JSVAL_TYPE_DOUBLE)) {
838 11962 : if (!backing->isConstant())
839 7586 : tempFPRegForData(backing);
840 11962 : ensureFeSynced(fe, masm);
841 :
842 11962 : if (!fe->type.synced())
843 11962 : fe->type.sync();
844 11962 : if (!fe->data.synced())
845 11962 : fe->data.sync();
846 11962 : return;
847 : }
848 :
849 1980711 : bool needTypeReg = !fe->type.synced() && backing->type.inMemory();
850 1980711 : bool needDataReg = !fe->data.synced() && backing->data.inMemory();
851 :
852 : #if defined JS_NUNBOX32
853 : /* Determine an ordering that won't spill known regs. */
854 1980711 : if (needTypeReg && !needDataReg) {
855 2734 : syncData(fe);
856 2734 : syncType(fe);
857 : } else {
858 1977977 : syncType(fe);
859 1977977 : syncData(fe);
860 : }
861 : #elif defined JS_PUNBOX64
862 : if (JS_UNLIKELY(needTypeReg && needDataReg)) {
863 : /* Memory-to-memory moves can only occur for copies backed by memory. */
864 : JS_ASSERT(backing != fe);
865 :
866 : /* Use ValueReg to do a whole-Value mem-to-mem move. */
867 : masm.loadValue(addressOf(backing), Registers::ValueReg);
868 : masm.storeValue(Registers::ValueReg, addressOf(fe));
869 : } else {
870 : /* Store in case unpinning is necessary. */
871 : MaybeRegisterID pairReg;
872 :
873 : /* Get a register if necessary, without clobbering its pair. */
874 : if (needTypeReg) {
875 : if (backing->data.inRegister() && !regstate(backing->data.reg()).isPinned()) {
876 : pairReg = backing->data.reg();
877 : pinReg(backing->data.reg());
878 : }
879 : tempRegForType(backing);
880 : } else if (needDataReg) {
881 : if (backing->type.inRegister() && !regstate(backing->type.reg()).isPinned()) {
882 : pairReg = backing->type.reg();
883 : pinReg(backing->type.reg());
884 : }
885 : tempRegForData(backing);
886 : }
887 :
888 : ensureFeSynced(fe, masm);
889 :
890 : if (pairReg.isSet())
891 : unpinReg(pairReg.reg());
892 : }
893 :
894 : if (!fe->type.synced())
895 : fe->type.sync();
896 : if (!fe->data.synced())
897 : fe->data.sync();
898 : #endif
899 : }
900 :
901 : inline void
902 3562 : FrameState::syncAndForgetFe(FrameEntry *fe, bool markSynced)
903 : {
904 3562 : if (markSynced) {
905 2204 : if (!fe->type.synced())
906 1799 : fe->type.sync();
907 2204 : if (!fe->data.synced())
908 1799 : fe->data.sync();
909 : }
910 :
911 3562 : syncFe(fe);
912 3562 : forgetAllRegs(fe);
913 3562 : fe->type.setMemory();
914 3562 : fe->data.setMemory();
915 3562 : }
916 :
917 : inline JSC::MacroAssembler::Address
918 28543 : FrameState::loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access, RegisterID reg)
919 : {
920 28543 : JS_ASSERT(access.script && access.nesting);
921 :
922 28543 : masm.move(ImmPtr(access.basePointer()), reg);
923 28543 : masm.loadPtr(Address(reg), reg);
924 :
925 28543 : return Address(reg, access.index * sizeof(Value));
926 : }
927 :
928 : inline JSC::MacroAssembler::Address
929 28033 : FrameState::loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access)
930 : {
931 28033 : RegisterID reg = allocReg();
932 28033 : return loadNameAddress(access, reg);
933 : }
934 :
935 : inline void
936 10579 : FrameState::forgetLoopReg(FrameEntry *fe)
937 : {
938 : /*
939 : * Don't use a loop register for fe in the active loop, as its underlying
940 : * representation may have changed since the start of the loop.
941 : */
942 10579 : if (loop)
943 8706 : fe->lastLoop = loop->headOffset();
944 10579 : }
945 :
946 : inline void
947 3224324 : FrameState::syncType(FrameEntry *fe)
948 : {
949 3224324 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
950 :
951 3224324 : FrameEntry *backing = fe;
952 3224324 : if (fe->isCopy())
953 324621 : backing = fe->copyOf();
954 :
955 3224324 : if (!fe->type.synced() && backing->type.inMemory())
956 64338 : tempRegForType(backing);
957 :
958 3224324 : ensureTypeSynced(fe, masm);
959 :
960 3224324 : if (!fe->type.synced())
961 3029006 : fe->type.sync();
962 3224324 : }
963 :
964 : inline void
965 3435405 : FrameState::syncData(FrameEntry *fe)
966 : {
967 3435405 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
968 :
969 3435405 : FrameEntry *backing = fe;
970 3435405 : if (fe->isCopy())
971 324621 : backing = fe->copyOf();
972 :
973 3435405 : if (!fe->data.synced() && backing->data.inMemory())
974 82883 : tempRegForData(backing);
975 :
976 3435405 : ensureDataSynced(fe, masm);
977 :
978 3435405 : if (!fe->data.synced())
979 3029781 : fe->data.sync();
980 3435405 : }
981 :
982 : inline void
983 40813 : FrameState::fakeSync(FrameEntry *fe)
984 : {
985 : /*
986 : * If a frame entry's value will no longer be used, we can mark it as being
987 : * synced without actually performing the sync: the value is not observed.
988 : */
989 40813 : if (!fe->data.synced())
990 904 : fe->data.sync();
991 40813 : if (!fe->type.synced())
992 681 : fe->type.sync();
993 40813 : }
994 :
995 : inline void
996 303 : FrameState::forgetType(FrameEntry *fe)
997 : {
998 : /*
999 : * The type may have been forgotten with an intervening storeLocal in the
1000 : * presence of eval or closed variables. For defense in depth and to make
1001 : * callers' lives simpler, bail out if the type is not known.
1002 : */
1003 303 : if (!fe->isTypeKnown())
1004 0 : return;
1005 :
1006 : /*
1007 : * Likewise, storeLocal() may have set this FE, with a known type,
1008 : * to be a copy of another FE, which has an unknown type.
1009 : */
1010 303 : if (fe->isCopy()) {
1011 0 : syncFe(fe);
1012 0 : fe->clear();
1013 0 : fe->resetSynced();
1014 0 : return;
1015 : }
1016 :
1017 303 : ensureTypeSynced(fe, masm);
1018 303 : fe->type.setMemory();
1019 : }
1020 :
1021 : inline void
1022 128803 : FrameState::learnType(FrameEntry *fe, JSValueType type, bool unsync)
1023 : {
1024 128803 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
1025 128803 : JS_ASSERT(type != JSVAL_TYPE_UNKNOWN);
1026 :
1027 128803 : if (fe->isCopy())
1028 0 : fe = fe->copyOf();
1029 :
1030 128803 : if (type == JSVAL_TYPE_DOUBLE)
1031 792 : JS_ASSERT(!fe->data.inRegister());
1032 : else
1033 128011 : JS_ASSERT(!fe->data.inFPRegister());
1034 :
1035 128803 : if (fe->type.inRegister())
1036 29978 : forgetReg(fe->type.reg());
1037 128803 : fe->setType(type);
1038 128803 : if (unsync)
1039 29548 : fe->type.unsync();
1040 128803 : }
1041 :
1042 : inline void
1043 6033 : FrameState::learnType(FrameEntry *fe, JSValueType type, RegisterID data)
1044 : {
1045 6033 : JS_ASSERT(!fe->isCopied());
1046 6033 : JS_ASSERT(type != JSVAL_TYPE_UNKNOWN && type != JSVAL_TYPE_DOUBLE);
1047 :
1048 6033 : forgetAllRegs(fe);
1049 6033 : fe->clear();
1050 :
1051 6033 : fe->type.setConstant();
1052 6033 : fe->knownType = type;
1053 :
1054 6033 : fe->data.setRegister(data);
1055 6033 : regstate(data).associate(fe, RematInfo::DATA);
1056 :
1057 6033 : fe->data.unsync();
1058 6033 : fe->type.unsync();
1059 6033 : }
1060 :
1061 : inline int32_t
1062 27552914 : FrameState::frameOffset(const FrameEntry *fe, ActiveFrame *a) const
1063 : {
1064 : /*
1065 : * The stored frame offsets for analysis temporaries are immediately above
1066 : * the script's normal slots (and will thus be clobbered should a C++ or
1067 : * scripted call push another frame). There must be enough room in the
1068 : * reserved stack space.
1069 : */
1070 : JS_STATIC_ASSERT(StackSpace::STACK_JIT_EXTRA >= TEMPORARY_LIMIT);
1071 :
1072 : /* Note: fe == a->sp is allowed for addressOfTop */
1073 27552914 : JS_ASSERT(fe >= a->callee_ && fe <= a->sp);
1074 :
1075 27552914 : if (fe >= a->locals)
1076 26437597 : return StackFrame::offsetOfFixed(uint32_t(fe - a->locals));
1077 1115317 : if (fe >= a->args)
1078 626154 : return StackFrame::offsetOfFormalArg(a->script->function(), uint32_t(fe - a->args));
1079 489163 : if (fe == a->this_)
1080 462232 : return StackFrame::offsetOfThis(a->script->function());
1081 26931 : if (fe == a->callee_)
1082 26931 : return StackFrame::offsetOfCallee(a->script->function());
1083 0 : JS_NOT_REACHED("Bad fe");
1084 : return 0;
1085 : }
1086 :
1087 : inline JSC::MacroAssembler::Address
1088 27581192 : FrameState::addressOf(const FrameEntry *fe) const
1089 : {
1090 27581192 : if (isTemporary(fe)) {
1091 : /*
1092 : * Temporary addresses are common to the outermost loop, and are shared
1093 : * by all active frames.
1094 : */
1095 28278 : return Address(JSFrameReg, (loop->temporariesStart + fe - temporaries) * sizeof(Value));
1096 : }
1097 :
1098 27552914 : ActiveFrame *na = a;
1099 55284730 : while (fe < na->callee_)
1100 178902 : na = na->parent;
1101 :
1102 27552914 : int32_t offset = frameOffset(fe, na);
1103 27552914 : return Address(JSFrameReg, offset + (na->depth * sizeof(Value)));
1104 : }
1105 :
1106 : inline uint32_t
1107 627092 : FrameState::frameSlot(ActiveFrame *a, const FrameEntry *fe) const
1108 : {
1109 627092 : if (isTemporary(fe))
1110 2511 : return fe - entries;
1111 :
1112 624581 : JS_ASSERT(fe >= a->callee_ && fe < a->sp);
1113 :
1114 624581 : if (fe >= a->locals)
1115 589066 : return analyze::LocalSlot(a->script, fe - a->locals);
1116 35515 : if (fe >= a->args)
1117 30526 : return analyze::ArgSlot(fe - a->args);
1118 4989 : if (fe == a->this_)
1119 4989 : return analyze::ThisSlot();
1120 0 : if (fe == a->callee_)
1121 0 : return analyze::CalleeSlot();
1122 0 : JS_NOT_REACHED("Bad fe");
1123 : return 0;
1124 : }
1125 :
1126 : inline JSC::MacroAssembler::Address
1127 209 : FrameState::addressForInlineReturn()
1128 : {
1129 209 : if (a->callee_->isTracked())
1130 27 : discardFe(a->callee_);
1131 209 : return addressOf(a->callee_);
1132 : }
1133 :
1134 : inline JSC::MacroAssembler::Address
1135 11432 : FrameState::addressForDataRemat(const FrameEntry *fe) const
1136 : {
1137 11432 : if (fe->isCopy() && !fe->data.synced())
1138 4031 : fe = fe->copyOf();
1139 11432 : JS_ASSERT(fe->data.synced());
1140 11432 : return addressOf(fe);
1141 : }
1142 :
1143 : inline JSC::MacroAssembler::Jump
1144 : FrameState::testNull(Assembler::Condition cond, FrameEntry *fe)
1145 : {
1146 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1147 : if (shouldAvoidTypeRemat(fe))
1148 : return masm.testNull(cond, addressOf(fe));
1149 : return masm.testNull(cond, tempRegForType(fe));
1150 : }
1151 :
1152 : inline JSC::MacroAssembler::Jump
1153 : FrameState::testUndefined(Assembler::Condition cond, FrameEntry *fe)
1154 : {
1155 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1156 : if (shouldAvoidTypeRemat(fe))
1157 : return masm.testUndefined(cond, addressOf(fe));
1158 : return masm.testUndefined(cond, tempRegForType(fe));
1159 : }
1160 :
1161 : inline JSC::MacroAssembler::Jump
1162 47270 : FrameState::testInt32(Assembler::Condition cond, FrameEntry *fe)
1163 : {
1164 47270 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1165 47270 : if (shouldAvoidTypeRemat(fe))
1166 4567 : return masm.testInt32(cond, addressOf(fe));
1167 42703 : return masm.testInt32(cond, tempRegForType(fe));
1168 : }
1169 :
1170 : inline JSC::MacroAssembler::Jump
1171 4507 : FrameState::testPrimitive(Assembler::Condition cond, FrameEntry *fe)
1172 : {
1173 4507 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1174 4507 : if (shouldAvoidTypeRemat(fe))
1175 333 : return masm.testPrimitive(cond, addressOf(fe));
1176 4174 : return masm.testPrimitive(cond, tempRegForType(fe));
1177 : }
1178 :
1179 : inline JSC::MacroAssembler::Jump
1180 69397 : FrameState::testObject(Assembler::Condition cond, FrameEntry *fe)
1181 : {
1182 69397 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1183 69397 : if (shouldAvoidTypeRemat(fe))
1184 4306 : return masm.testObject(cond, addressOf(fe));
1185 65091 : return masm.testObject(cond, tempRegForType(fe));
1186 : }
1187 :
1188 : inline JSC::MacroAssembler::Jump
1189 : FrameState::testGCThing(FrameEntry *fe)
1190 : {
1191 : if (shouldAvoidTypeRemat(fe))
1192 : return masm.testGCThing(addressOf(fe));
1193 : return masm.testGCThing(tempRegForType(fe));
1194 : }
1195 :
1196 : inline JSC::MacroAssembler::Jump
1197 8957 : FrameState::testDouble(Assembler::Condition cond, FrameEntry *fe)
1198 : {
1199 8957 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1200 8957 : if (shouldAvoidTypeRemat(fe))
1201 0 : return masm.testDouble(cond, addressOf(fe));
1202 8957 : return masm.testDouble(cond, tempRegForType(fe));
1203 : }
1204 :
1205 : inline JSC::MacroAssembler::Jump
1206 70817 : FrameState::testBoolean(Assembler::Condition cond, FrameEntry *fe)
1207 : {
1208 70817 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1209 70817 : if (shouldAvoidTypeRemat(fe))
1210 68762 : return masm.testBoolean(cond, addressOf(fe));
1211 2055 : return masm.testBoolean(cond, tempRegForType(fe));
1212 : }
1213 :
1214 : inline JSC::MacroAssembler::Jump
1215 1054 : FrameState::testString(Assembler::Condition cond, FrameEntry *fe)
1216 : {
1217 1054 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1218 1054 : if (shouldAvoidTypeRemat(fe))
1219 7 : return masm.testString(cond, addressOf(fe));
1220 1047 : return masm.testString(cond, tempRegForType(fe));
1221 : }
1222 :
1223 : inline FrameEntry *
1224 3259936 : FrameState::getOrTrack(uint32_t index)
1225 : {
1226 3259936 : FrameEntry *fe = &entries[index];
1227 3259936 : if (!fe->isTracked()) {
1228 731491 : addToTracker(fe);
1229 731491 : fe->resetSynced();
1230 : }
1231 3259936 : return fe;
1232 : }
1233 :
1234 : inline FrameEntry *
1235 1739858 : FrameState::getStack(uint32_t slot)
1236 : {
1237 1739858 : if (slot >= uint32_t(a->sp - a->spBase))
1238 3453 : return NULL;
1239 1736405 : return getOrTrack(uint32_t(a->spBase + slot - entries));
1240 : }
1241 :
1242 : inline FrameEntry *
1243 720857 : FrameState::getLocal(uint32_t slot)
1244 : {
1245 720857 : JS_ASSERT(slot < a->script->nslots);
1246 720857 : return getOrTrack(uint32_t(a->locals + slot - entries));
1247 : }
1248 :
1249 : inline FrameEntry *
1250 198908 : FrameState::getArg(uint32_t slot)
1251 : {
1252 198908 : JS_ASSERT(slot < a->script->function()->nargs);
1253 198908 : return getOrTrack(uint32_t(a->args + slot - entries));
1254 : }
1255 :
1256 : inline FrameEntry *
1257 145831 : FrameState::getThis()
1258 : {
1259 145831 : return getOrTrack(uint32_t(a->this_ - entries));
1260 : }
1261 :
1262 : inline FrameEntry *
1263 222005 : FrameState::getSlotEntry(uint32_t slot)
1264 : {
1265 222005 : JS_ASSERT(slot < analyze::TotalSlots(a->script));
1266 222005 : return getOrTrack(uint32_t(a->callee_ + slot - entries));
1267 : }
1268 :
1269 : inline FrameEntry *
1270 3731 : FrameState::getCallee()
1271 : {
1272 : // Callee can only be used in function code, and it's always an object.
1273 3731 : JS_ASSERT(a->script->function());
1274 3731 : FrameEntry *fe = a->callee_;
1275 3731 : if (!fe->isTracked()) {
1276 3098 : addToTracker(fe);
1277 3098 : fe->resetSynced();
1278 3098 : fe->setType(JSVAL_TYPE_OBJECT);
1279 : }
1280 3731 : return fe;
1281 : }
1282 :
1283 : inline void
1284 345328 : FrameState::unpinKilledReg(AnyRegisterID reg)
1285 : {
1286 345328 : regstate(reg).unpinUnsafe();
1287 345328 : freeRegs.putReg(reg);
1288 345328 : }
1289 :
1290 : inline void
1291 12983857 : FrameState::forgetAllRegs(FrameEntry *fe)
1292 : {
1293 12983857 : if (fe->isCopy())
1294 4280049 : return;
1295 8703808 : if (fe->type.inRegister())
1296 1347761 : forgetReg(fe->type.reg());
1297 8703808 : if (fe->data.inRegister())
1298 1664777 : forgetReg(fe->data.reg());
1299 8703808 : if (fe->data.inFPRegister())
1300 11581 : forgetReg(fe->data.fpreg());
1301 : }
1302 :
1303 : inline void
1304 336986 : FrameState::swapInTracker(FrameEntry *lhs, FrameEntry *rhs)
1305 : {
1306 336986 : uint32_t li = lhs->trackerIndex();
1307 336986 : uint32_t ri = rhs->trackerIndex();
1308 336986 : JS_ASSERT(tracker[li] == lhs);
1309 336986 : JS_ASSERT(tracker[ri] == rhs);
1310 336986 : tracker.entries[ri] = lhs;
1311 336986 : tracker.entries[li] = rhs;
1312 336986 : lhs->index_ = ri;
1313 336986 : rhs->index_ = li;
1314 336986 : }
1315 :
1316 : inline void
1317 366613 : FrameState::dup()
1318 : {
1319 366613 : dupAt(-1);
1320 366613 : }
1321 :
1322 : inline void
1323 359773 : FrameState::dup2()
1324 : {
1325 359773 : FrameEntry *lhs = peek(-2);
1326 359773 : FrameEntry *rhs = peek(-1);
1327 359773 : pushCopyOf(lhs);
1328 359773 : pushCopyOf(rhs);
1329 359773 : }
1330 :
1331 : inline void
1332 2524260 : FrameState::dupAt(int32_t n)
1333 : {
1334 2524260 : JS_ASSERT(n < 0);
1335 2524260 : FrameEntry *fe = peek(n);
1336 2524260 : pushCopyOf(fe);
1337 2524260 : }
1338 :
1339 : inline void
1340 240 : FrameState::syncAt(int32_t n)
1341 : {
1342 240 : JS_ASSERT(n < 0);
1343 240 : FrameEntry *fe = peek(n);
1344 240 : syncFe(fe);
1345 240 : }
1346 :
1347 : inline void
1348 432754 : FrameState::pushLocal(uint32_t n)
1349 : {
1350 432754 : FrameEntry *fe = getLocal(n);
1351 432754 : if (!a->analysis->slotEscapes(analyze::LocalSlot(a->script, n))) {
1352 178710 : pushCopyOf(fe);
1353 : } else {
1354 : #ifdef DEBUG
1355 : /*
1356 : * We really want to assert on local variables, but in the presence of
1357 : * SETLOCAL equivocation of stack slots, and let expressions, just
1358 : * weakly assert on the fixed local vars.
1359 : */
1360 254044 : if (fe->isTracked() && n < a->script->nfixed)
1361 205280 : JS_ASSERT(fe->data.inMemory());
1362 : #endif
1363 254044 : if (n >= a->script->nfixed)
1364 48764 : syncFe(fe);
1365 254044 : JSValueType type = fe->isTypeKnown() ? fe->getKnownType() : JSVAL_TYPE_UNKNOWN;
1366 254044 : push(addressOf(fe), type);
1367 : }
1368 432754 : }
1369 :
1370 : inline void
1371 194204 : FrameState::pushArg(uint32_t n)
1372 : {
1373 194204 : FrameEntry *fe = getArg(n);
1374 194204 : if (!a->analysis->slotEscapes(analyze::ArgSlot(n))) {
1375 94395 : pushCopyOf(fe);
1376 : } else {
1377 : #ifdef DEBUG
1378 99809 : if (fe->isTracked())
1379 99809 : JS_ASSERT(fe->data.inMemory());
1380 : #endif
1381 99809 : JSValueType type = fe->isTypeKnown() ? fe->getKnownType() : JSVAL_TYPE_UNKNOWN;
1382 99809 : push(addressOf(fe), type);
1383 : }
1384 194204 : }
1385 :
1386 : inline void
1387 3731 : FrameState::pushCallee()
1388 : {
1389 3731 : FrameEntry *fe = getCallee();
1390 3731 : pushCopyOf(fe);
1391 3731 : }
1392 :
1393 : inline void
1394 107613 : FrameState::pushThis()
1395 : {
1396 107613 : FrameEntry *fe = getThis();
1397 107613 : pushCopyOf(fe);
1398 107613 : }
1399 :
1400 : void
1401 35409 : FrameState::learnThisIsObject(bool unsync)
1402 : {
1403 : // If the 'this' object is a copy, this must be an inline frame, in which
1404 : // case we will trigger recompilation if the 'this' entry isn't actually
1405 : // an object (thus, it is OK to modify the backing directly).
1406 35409 : FrameEntry *fe = getThis();
1407 35409 : if (fe->isCopy())
1408 41 : fe = fe->copyOf();
1409 35409 : learnType(fe, JSVAL_TYPE_OBJECT, unsync);
1410 35409 : }
1411 :
1412 : void
1413 160 : FrameState::setThis(RegisterID reg)
1414 : {
1415 160 : FrameEntry *fe = getThis();
1416 160 : JS_ASSERT(!fe->isCopy());
1417 160 : learnType(fe, JSVAL_TYPE_OBJECT, reg);
1418 160 : }
1419 :
1420 : void
1421 1845 : FrameState::syncThis()
1422 : {
1423 1845 : FrameEntry *fe = getThis();
1424 1845 : syncFe(fe);
1425 1845 : }
1426 :
1427 : inline bool
1428 368841 : FrameState::isConstructorThis(const FrameEntry *fe) const
1429 : {
1430 368841 : return isThis(fe) && cc.constructing();
1431 : }
1432 :
1433 : inline void
1434 28995 : FrameState::leaveBlock(uint32_t n)
1435 : {
1436 28995 : popn(n);
1437 28995 : }
1438 :
1439 : inline void
1440 21202 : FrameState::enterBlock(uint32_t n)
1441 : {
1442 : /* expect that tracker has 0 entries, for now. */
1443 21202 : JS_ASSERT(!tracker.nentries);
1444 21202 : JS_ASSERT(uint32_t(a->sp + n - a->locals) <= a->script->nslots);
1445 :
1446 21202 : a->sp += n;
1447 21202 : }
1448 :
1449 : inline void
1450 : FrameState::eviscerate(FrameEntry *fe)
1451 : {
1452 : forgetAllRegs(fe);
1453 : fe->resetUnsynced();
1454 : }
1455 :
1456 : inline StateRemat
1457 5707 : FrameState::dataRematInfo(const FrameEntry *fe) const
1458 : {
1459 5707 : if (fe->isCopy())
1460 2272 : fe = fe->copyOf();
1461 :
1462 5707 : if (fe->data.inRegister())
1463 4388 : return StateRemat::FromRegister(fe->data.reg());
1464 :
1465 1319 : JS_ASSERT(fe->data.synced());
1466 1319 : return StateRemat::FromAddress(addressOf(fe));
1467 : }
1468 :
1469 : inline void
1470 202110 : FrameState::giveOwnRegs(FrameEntry *fe)
1471 : {
1472 202110 : JS_ASSERT(!fe->isConstant());
1473 202110 : JS_ASSERT(fe == peek(-1));
1474 :
1475 202110 : if (!fe->isCopy())
1476 201978 : return;
1477 :
1478 132 : RegisterID data = copyDataIntoReg(fe);
1479 132 : if (fe->isTypeKnown()) {
1480 0 : JSValueType type = fe->getKnownType();
1481 0 : pop();
1482 0 : pushTypedPayload(type, data);
1483 : } else {
1484 132 : RegisterID type = copyTypeIntoReg(fe);
1485 132 : pop();
1486 132 : pushRegs(type, data, JSVAL_TYPE_UNKNOWN);
1487 : }
1488 : }
1489 :
1490 : inline void
1491 1300477 : FrameState::loadDouble(RegisterID t, RegisterID d, FrameEntry *fe, FPRegisterID fpreg,
1492 : Assembler &masm) const
1493 : {
1494 : #ifdef JS_CPU_X86
1495 1300477 : masm.fastLoadDouble(d, t, fpreg);
1496 : #else
1497 : loadDouble(fe, fpreg, masm);
1498 : #endif
1499 1300477 : }
1500 :
1501 : inline bool
1502 19858 : FrameState::tryFastDoubleLoad(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const
1503 : {
1504 : #ifdef JS_CPU_X86
1505 19858 : if (!fe->isCopy() && fe->type.inRegister() && fe->data.inRegister()) {
1506 12821 : masm.fastLoadDouble(fe->data.reg(), fe->type.reg(), fpReg);
1507 12821 : return true;
1508 : }
1509 : #endif
1510 7037 : return false;
1511 : }
1512 :
1513 : inline void
1514 17043 : FrameState::loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const
1515 : {
1516 17043 : if (fe->isCopy()) {
1517 2815 : FrameEntry *backing = fe->copyOf();
1518 2815 : if (tryFastDoubleLoad(fe, fpReg, masm))
1519 0 : return;
1520 2815 : fe = backing;
1521 : }
1522 :
1523 17043 : if (tryFastDoubleLoad(fe, fpReg, masm))
1524 12821 : return;
1525 :
1526 4222 : ensureFeSynced(fe, masm);
1527 4222 : masm.loadDouble(addressOf(fe), fpReg);
1528 : }
1529 :
1530 : class PinRegAcrossSyncAndKill
1531 : {
1532 : typedef JSC::MacroAssembler::RegisterID RegisterID;
1533 : FrameState &frame;
1534 : MaybeRegisterID maybeReg;
1535 : public:
1536 159520 : PinRegAcrossSyncAndKill(FrameState &frame, RegisterID reg)
1537 159520 : : frame(frame), maybeReg(reg)
1538 : {
1539 159520 : frame.pinReg(reg);
1540 159520 : }
1541 151114 : PinRegAcrossSyncAndKill(FrameState &frame, MaybeRegisterID maybeReg)
1542 151114 : : frame(frame), maybeReg(maybeReg)
1543 : {
1544 151114 : if (maybeReg.isSet())
1545 113274 : frame.pinReg(maybeReg.reg());
1546 151114 : }
1547 310634 : ~PinRegAcrossSyncAndKill() {
1548 310634 : if (maybeReg.isSet())
1549 272794 : frame.unpinKilledReg(maybeReg.reg());
1550 310634 : }
1551 : };
1552 :
1553 : } /* namespace mjit */
1554 : } /* namespace js */
1555 :
1556 : #endif /* include */
1557 :
|