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 1392539 : FrameState::addToTracker(FrameEntry *fe)
50 : {
51 1392539 : JS_ASSERT(!fe->isTracked());
52 1392539 : fe->track(tracker.nentries);
53 1392539 : tracker.add(fe);
54 1392539 : }
55 :
56 : inline FrameEntry *
57 6343940 : FrameState::peek(int32_t depth)
58 : {
59 6343940 : JS_ASSERT(depth < 0);
60 6343940 : JS_ASSERT(a->sp + depth >= a->spBase);
61 6343940 : FrameEntry *fe = a->sp + depth;
62 6343940 : if (!fe->isTracked()) {
63 51996 : addToTracker(fe);
64 51996 : fe->resetSynced();
65 : }
66 6343940 : return fe;
67 : }
68 :
69 : inline void
70 914400 : FrameState::popn(uint32_t n)
71 : {
72 2895017 : for (uint32_t i = 0; i < n; i++)
73 1980617 : pop();
74 914400 : }
75 :
76 : inline bool
77 466293 : FrameState::haveSameBacking(FrameEntry *lhs, FrameEntry *rhs)
78 : {
79 466293 : if (lhs->isCopy())
80 56624 : lhs = lhs->copyOf();
81 466293 : if (rhs->isCopy())
82 12541 : rhs = rhs->copyOf();
83 466293 : return lhs == rhs;
84 : }
85 :
86 : inline FrameEntry *
87 19268 : FrameState::getTemporary(uint32_t which)
88 : {
89 19268 : JS_ASSERT(which < TEMPORARY_LIMIT);
90 :
91 19268 : FrameEntry *fe = temporaries + which;
92 19268 : JS_ASSERT(fe < temporariesTop);
93 :
94 19268 : return getOrTrack(uint32_t(fe - entries));
95 : }
96 :
97 : inline AnyRegisterID
98 3217690 : FrameState::allocReg(uint32_t mask)
99 : {
100 3217690 : if (freeRegs.hasRegInMask(mask)) {
101 3151881 : AnyRegisterID reg = freeRegs.takeAnyReg(mask);
102 3151881 : modifyReg(reg);
103 3151881 : return reg;
104 : }
105 :
106 65809 : AnyRegisterID reg = evictSomeReg(mask);
107 65809 : modifyReg(reg);
108 65809 : return reg;
109 : }
110 :
111 : inline JSC::MacroAssembler::RegisterID
112 2393614 : FrameState::allocReg()
113 : {
114 2393614 : return allocReg(Registers::AvailRegs).reg();
115 : }
116 :
117 : inline JSC::MacroAssembler::FPRegisterID
118 814982 : FrameState::allocFPReg()
119 : {
120 814982 : return allocReg(Registers::AvailFPRegs).fpreg();
121 : }
122 :
123 : inline AnyRegisterID
124 671477 : FrameState::allocAndLoadReg(FrameEntry *fe, bool fp, RematInfo::RematType type)
125 : {
126 671477 : AnyRegisterID reg;
127 671477 : 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 724720 : if (loop && freeRegs.hasRegInMask(loop->getLoopRegs() & mask) &&
138 36755 : type == RematInfo::DATA && isOuterSlot(fe) && !cc.activeFrameHasMultipleExits() &&
139 16488 : fe->lastLoop < loop->headOffset()) {
140 16187 : reg = freeRegs.takeAnyReg(loop->getLoopRegs() & mask);
141 16187 : regstate(reg).associate(fe, RematInfo::DATA);
142 16187 : fe->lastLoop = loop->headOffset();
143 16187 : loop->setLoopReg(reg, fe);
144 16187 : return reg;
145 : }
146 :
147 655290 : if (!freeRegs.empty(mask))
148 631348 : reg = freeRegs.takeAnyReg(mask);
149 : else
150 23942 : reg = evictSomeReg(mask);
151 655290 : modifyReg(reg);
152 :
153 655290 : if (fp)
154 1164 : masm.loadDouble(addressOf(fe), reg.fpreg());
155 654126 : else if (type == RematInfo::TYPE)
156 426286 : masm.loadTypeTag(addressOf(fe), reg.reg());
157 : else
158 227840 : masm.loadPayload(addressOf(fe), reg.reg());
159 :
160 655290 : regstate(reg).associate(fe, type);
161 655290 : return reg;
162 : }
163 :
164 : inline void
165 4437994 : FrameState::modifyReg(AnyRegisterID reg)
166 : {
167 4437994 : if (loop)
168 864688 : loop->clearLoopReg(reg);
169 4437994 : }
170 :
171 : inline void
172 5894 : FrameState::convertInt32ToDouble(Assembler &masm, FrameEntry *fe, FPRegisterID fpreg) const
173 : {
174 5894 : JS_ASSERT(!fe->isConstant());
175 :
176 5894 : if (fe->isCopy())
177 1020 : fe = fe->copyOf();
178 :
179 5894 : if (fe->data.inRegister())
180 5165 : masm.convertInt32ToDouble(fe->data.reg(), fpreg);
181 : else
182 729 : masm.convertInt32ToDouble(masm.payloadOf(addressOf(fe)), fpreg);
183 5894 : }
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 3590816 : FrameState::pop()
195 : {
196 3590816 : JS_ASSERT(a->sp > a->spBase);
197 :
198 3590816 : FrameEntry *fe = --a->sp;
199 3590816 : if (!fe->isTracked())
200 44547 : return;
201 :
202 3546269 : forgetAllRegs(fe);
203 3546269 : fe->type.invalidate();
204 3546269 : fe->data.invalidate();
205 3546269 : fe->clear();
206 :
207 3546269 : extraArray[fe - entries].reset();
208 : }
209 :
210 : inline void
211 1273100 : FrameState::freeReg(AnyRegisterID reg)
212 : {
213 1273100 : JS_ASSERT(!regstate(reg).usedBy());
214 :
215 1273100 : freeRegs.putReg(reg);
216 1273100 : }
217 :
218 : inline void
219 2963588 : 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 2963588 : JS_ASSERT_IF(regstate(reg).fe(), !regstate(reg).fe()->isCopy());
226 :
227 2963588 : if (!regstate(reg).isPinned()) {
228 2762925 : regstate(reg).forget();
229 2762925 : freeRegs.putReg(reg);
230 : }
231 2963588 : }
232 :
233 : inline FrameEntry *
234 3635895 : FrameState::rawPush()
235 : {
236 3635895 : JS_ASSERT(a->sp < temporaries);
237 3635895 : FrameEntry *fe = a->sp++;
238 :
239 3635895 : if (!fe->isTracked())
240 895340 : addToTracker(fe);
241 3635895 : fe->type.invalidate();
242 3635895 : fe->data.invalidate();
243 3635895 : fe->clear();
244 :
245 3635895 : extraArray[fe - entries].reset();
246 :
247 3635895 : return fe;
248 : }
249 :
250 : inline void
251 1194305 : FrameState::push(const Value &v)
252 : {
253 1194305 : FrameEntry *fe = rawPush();
254 1194305 : fe->setConstant(v);
255 1194305 : }
256 :
257 : inline void
258 1282938 : FrameState::pushSynced(JSValueType type)
259 : {
260 1282938 : FrameEntry *fe = rawPush();
261 :
262 1282938 : fe->resetSynced();
263 1282938 : if (type != JSVAL_TYPE_UNKNOWN) {
264 32360 : fe->setType(type);
265 32360 : if (type == JSVAL_TYPE_DOUBLE)
266 257 : masm.ensureInMemoryDouble(addressOf(fe));
267 : }
268 1282938 : }
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 263029 : 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 263029 : bool free = freeRegs.hasReg(address.base);
301 263029 : bool needsPin = !free && regstate(address.base).fe();
302 263029 : if (free)
303 2105 : freeRegs.takeReg(address.base);
304 263029 : if (needsPin)
305 3714 : pinReg(address.base);
306 :
307 263029 : RegisterID typeReg = allocReg();
308 :
309 263029 : 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 263029 : if (free)
315 2105 : freeRegs.putReg(address.base);
316 263029 : if (needsPin)
317 3714 : unpinReg(address.base);
318 :
319 263029 : RegisterID dataReg = reuseBase ? address.base : allocReg();
320 263029 : masm.loadPayload(address, dataReg);
321 :
322 : #endif
323 :
324 263029 : *ptypeReg = typeReg;
325 263029 : *pdataReg = dataReg;
326 263029 : }
327 :
328 : inline void
329 232500 : FrameState::push(Address address, JSValueType knownType, bool reuseBase)
330 : {
331 232500 : 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 231456 : if (knownType != JSVAL_TYPE_UNKNOWN) {
341 60180 : RegisterID dataReg = reuseBase ? address.base : allocReg();
342 60180 : masm.loadPayload(address, dataReg);
343 60180 : pushTypedPayload(knownType, dataReg);
344 60180 : return;
345 : }
346 :
347 : RegisterID typeReg, dataReg;
348 171276 : loadIntoRegisters(address, reuseBase, &typeReg, &dataReg);
349 :
350 171276 : 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 965278 : FrameState::storeRegs(int32_t depth, RegisterID type, RegisterID data, JSValueType knownType)
366 : {
367 965278 : FrameEntry *fe = peek(depth);
368 965278 : forgetEntry(fe);
369 965278 : 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 965278 : JS_ASSERT(!freeRegs.hasReg(type) && !freeRegs.hasReg(data));
376 :
377 965278 : if (knownType == JSVAL_TYPE_UNKNOWN) {
378 845086 : fe->type.setRegister(type);
379 845086 : fe->data.setRegister(data);
380 845086 : regstate(type).associate(fe, RematInfo::TYPE);
381 845086 : regstate(data).associate(fe, RematInfo::DATA);
382 845086 : return Registers::FPConversionTemp;
383 : }
384 :
385 120192 : if (knownType == JSVAL_TYPE_DOUBLE) {
386 10152 : FPRegisterID fpreg = allocFPReg();
387 10152 : masm.moveInt32OrDouble(data, type, addressOf(fe), fpreg);
388 10152 : fe->setType(JSVAL_TYPE_DOUBLE);
389 10152 : fe->data.setFPRegister(fpreg);
390 10152 : regstate(fpreg).associate(fe, RematInfo::DATA);
391 10152 : freeReg(type);
392 10152 : freeReg(data);
393 10152 : return fpreg;
394 : }
395 :
396 110040 : freeReg(type);
397 110040 : fe->setType(knownType);
398 110040 : fe->data.setRegister(data);
399 110040 : regstate(data).associate(fe, RematInfo::DATA);
400 110040 : return Registers::FPConversionTemp;
401 : }
402 :
403 : inline JSC::MacroAssembler::FPRegisterID
404 965278 : FrameState::pushRegs(RegisterID type, RegisterID data, JSValueType knownType)
405 : {
406 965278 : pushSynced(JSVAL_TYPE_UNKNOWN);
407 965278 : return storeRegs(-1, type, data, knownType);
408 : }
409 :
410 : inline void
411 90561 : FrameState::reloadEntry(Assembler &masm, Address address, FrameEntry *fe)
412 : {
413 90561 : if (fe->data.inRegister()) {
414 89729 : if (fe->type.inRegister()) {
415 61567 : masm.loadValueAsComponents(address, fe->type.reg(), fe->data.reg());
416 : } else {
417 28162 : JS_ASSERT(fe->isTypeKnown());
418 28162 : masm.loadPayload(address, fe->data.reg());
419 : }
420 : } else {
421 832 : JS_ASSERT(fe->data.inFPRegister());
422 832 : masm.moveInt32OrDouble(address, fe->data.fpreg());
423 : }
424 90561 : }
425 :
426 : inline void
427 300727 : FrameState::pushTypedPayload(JSValueType type, RegisterID payload)
428 : {
429 300727 : JS_ASSERT(type != JSVAL_TYPE_DOUBLE);
430 300727 : JS_ASSERT(!freeRegs.hasReg(payload));
431 :
432 300727 : FrameEntry *fe = rawPush();
433 :
434 300727 : fe->resetUnsynced();
435 300727 : fe->setType(type);
436 300727 : fe->data.setRegister(payload);
437 300727 : regstate(payload).associate(fe, RematInfo::DATA);
438 300727 : }
439 :
440 : inline void
441 334105 : FrameState::pushNumber(RegisterID payload, bool asInt32)
442 : {
443 334105 : JS_ASSERT(!freeRegs.hasReg(payload));
444 :
445 334105 : FrameEntry *fe = rawPush();
446 :
447 334105 : if (asInt32) {
448 333846 : if (!fe->type.synced())
449 32604 : masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
450 333846 : fe->type.setMemory();
451 : } else {
452 259 : fe->type.setMemory();
453 : }
454 :
455 334105 : fe->data.unsync();
456 334105 : fe->data.setRegister(payload);
457 334105 : regstate(payload).associate(fe, RematInfo::DATA);
458 334105 : }
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 4416 : FrameState::pushUntypedPayload(JSValueType type, RegisterID payload)
475 : {
476 4416 : JS_ASSERT(!freeRegs.hasReg(payload));
477 :
478 4416 : FrameEntry *fe = rawPush();
479 :
480 4416 : masm.storeTypeTag(ImmType(type), addressOf(fe));
481 :
482 : /* The forceful type sync will assert otherwise. */
483 : #ifdef DEBUG
484 4416 : fe->type.unsync();
485 : #endif
486 4416 : fe->type.setMemory();
487 4416 : fe->data.unsync();
488 4416 : fe->data.setRegister(payload);
489 4416 : regstate(payload).associate(fe, RematInfo::DATA);
490 4416 : }
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 659532 : FrameState::tempRegForType(FrameEntry *fe)
529 : {
530 659532 : if (fe->isCopy())
531 59325 : fe = fe->copyOf();
532 :
533 659532 : JS_ASSERT(!fe->type.isConstant());
534 :
535 659532 : if (fe->type.inRegister())
536 234392 : return fe->type.reg();
537 :
538 : /* :XXX: X86 */
539 :
540 425140 : RegisterID reg = allocAndLoadReg(fe, false, RematInfo::TYPE).reg();
541 425140 : fe->type.setRegister(reg);
542 425140 : 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 656099 : FrameState::tempRegForData(FrameEntry *fe)
583 : {
584 656099 : JS_ASSERT(!fe->isConstant());
585 656099 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
586 :
587 656099 : if (fe->isCopy())
588 76710 : fe = fe->copyOf();
589 :
590 656099 : if (fe->data.inRegister())
591 414293 : return fe->data.reg();
592 :
593 241806 : RegisterID reg = allocAndLoadReg(fe, false, RematInfo::DATA).reg();
594 241806 : fe->data.setRegister(reg);
595 241806 : return reg;
596 : }
597 :
598 : inline void
599 253715 : FrameState::forgetMismatchedObject(FrameEntry *fe)
600 : {
601 253715 : if (fe->isNotType(JSVAL_TYPE_OBJECT)) {
602 1360 : if (fe->isCopied()) {
603 1 : syncFe(fe);
604 1 : uncopy(fe);
605 1 : fe->resetSynced();
606 : } else {
607 1359 : syncAndForgetFe(fe);
608 : }
609 1360 : fe->clear();
610 : }
611 :
612 253715 : if (fe->isConstant()) {
613 33691 : RegisterID reg = allocReg();
614 33691 : regstate(reg).associate(fe, RematInfo::DATA);
615 :
616 33691 : masm.move(JSC::MacroAssembler::ImmPtr(&fe->getValue().toObject()), reg);
617 33691 : fe->data.setRegister(reg);
618 : }
619 253715 : }
620 :
621 : inline JSC::MacroAssembler::FPRegisterID
622 23617 : FrameState::tempFPRegForData(FrameEntry *fe)
623 : {
624 23617 : JS_ASSERT(!fe->isConstant());
625 23617 : JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
626 :
627 23617 : if (fe->isCopy())
628 1631 : fe = fe->copyOf();
629 :
630 23617 : JS_ASSERT(!fe->data.inRegister());
631 :
632 23617 : if (fe->data.inFPRegister())
633 22311 : return fe->data.fpreg();
634 :
635 1306 : FPRegisterID reg = allocAndLoadReg(fe, true, RematInfo::DATA).fpreg();
636 1306 : fe->data.setFPRegister(reg);
637 1306 : return reg;
638 : }
639 :
640 : inline AnyRegisterID
641 4970 : FrameState::tempRegInMaskForData(FrameEntry *fe, uint32_t mask)
642 : {
643 4970 : JS_ASSERT(!fe->isConstant());
644 4970 : JS_ASSERT_IF(fe->isType(JSVAL_TYPE_DOUBLE), !(mask & ~Registers::AvailFPRegs));
645 4970 : JS_ASSERT_IF(!fe->isType(JSVAL_TYPE_DOUBLE), !(mask & ~Registers::AvailRegs));
646 :
647 4970 : if (fe->isCopy())
648 593 : fe = fe->copyOf();
649 :
650 4970 : AnyRegisterID reg;
651 4970 : if (fe->data.inRegister() || fe->data.inFPRegister()) {
652 4237 : AnyRegisterID old;
653 4237 : if (fe->data.inRegister())
654 4156 : old = fe->data.reg();
655 : else
656 81 : old = fe->data.fpreg();
657 4237 : if (Registers::maskReg(old) & mask)
658 2508 : return old;
659 :
660 : /* Keep the old register pinned. */
661 1729 : regstate(old).forget();
662 1729 : reg = allocReg(mask);
663 1729 : if (reg.isReg())
664 1729 : masm.move(old.reg(), reg.reg());
665 : else
666 0 : masm.moveDouble(old.fpreg(), reg.fpreg());
667 1729 : freeReg(old);
668 : } else {
669 733 : reg = allocReg(mask);
670 733 : if (reg.isReg())
671 733 : masm.loadPayload(addressOf(fe), reg.reg());
672 : else
673 0 : masm.loadDouble(addressOf(fe), reg.fpreg());
674 : }
675 2462 : regstate(reg).associate(fe, RematInfo::DATA);
676 2462 : if (reg.isReg())
677 2462 : fe->data.setRegister(reg.reg());
678 : else
679 0 : fe->data.setFPRegister(reg.fpreg());
680 2462 : 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 110555 : FrameState::shouldAvoidTypeRemat(FrameEntry *fe)
704 : {
705 110555 : return !fe->isCopy() && fe->type.inMemory();
706 : }
707 :
708 : inline bool
709 14303 : FrameState::shouldAvoidDataRemat(FrameEntry *fe)
710 : {
711 14303 : return !fe->isCopy() && fe->data.inMemory();
712 : }
713 :
714 : inline void
715 55484 : FrameState::ensureFeSynced(const FrameEntry *fe, Assembler &masm) const
716 : {
717 55484 : Address to = addressOf(fe);
718 55484 : const FrameEntry *backing = fe;
719 55484 : if (fe->isCopy())
720 2862 : backing = fe->copyOf();
721 :
722 55484 : if (backing->isType(JSVAL_TYPE_DOUBLE)) {
723 52564 : if (fe->data.synced()) {
724 : /* Entries representing known doubles can't be partially synced. */
725 6886 : JS_ASSERT(fe->type.synced());
726 6886 : return;
727 : }
728 45678 : if (backing->isConstant()) {
729 10944 : masm.storeValue(backing->getValue(), to);
730 34734 : } else if (backing->data.inFPRegister()) {
731 33807 : masm.storeDouble(backing->data.fpreg(), to);
732 : } else {
733 : /* Use a temporary so the entry can be synced without allocating a register. */
734 927 : JS_ASSERT(backing->data.inMemory() && backing != fe);
735 927 : masm.loadDouble(addressOf(backing), Registers::FPConversionTemp);
736 927 : masm.storeDouble(Registers::FPConversionTemp, to);
737 : }
738 45678 : 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 2920 : ensureDataSynced(fe, masm);
759 2920 : ensureTypeSynced(fe, masm);
760 : }
761 :
762 : inline void
763 7074474 : FrameState::ensureTypeSynced(const FrameEntry *fe, Assembler &masm) const
764 : {
765 7074474 : if (fe->type.synced())
766 3184212 : return;
767 :
768 3890262 : Address to = addressOf(fe);
769 3890262 : const FrameEntry *backing = fe;
770 3890262 : if (fe->isCopy())
771 325652 : 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 3890262 : if (backing->isConstant())
792 1228329 : masm.storeTypeTag(ImmTag(backing->getKnownTag()), to);
793 2661933 : else if (backing->isTypeKnown())
794 764744 : masm.storeTypeTag(ImmType(backing->getKnownType()), to);
795 : else
796 1897189 : masm.storeTypeTag(backing->type.reg(), to);
797 : }
798 :
799 : inline void
800 7257695 : FrameState::ensureDataSynced(const FrameEntry *fe, Assembler &masm) const
801 : {
802 7257695 : if (fe->data.synced())
803 2441355 : return;
804 :
805 4816340 : Address to = addressOf(fe);
806 4816340 : const FrameEntry *backing = fe;
807 4816340 : if (fe->isCopy())
808 325880 : 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 4816340 : if (backing->isConstant())
821 1228493 : masm.storePayload(ImmPayload(backing->getPayload()), to);
822 : else
823 3587847 : masm.storePayload(backing->data.reg(), to);
824 : #endif
825 : }
826 :
827 : inline void
828 2881727 : FrameState::syncFe(FrameEntry *fe)
829 : {
830 2881727 : if (fe->type.synced() && fe->data.synced())
831 2132505 : return;
832 :
833 749222 : FrameEntry *backing = fe;
834 749222 : if (fe->isCopy())
835 80811 : backing = fe->copyOf();
836 :
837 749222 : if (backing->isType(JSVAL_TYPE_DOUBLE)) {
838 12142 : if (!backing->isConstant())
839 7754 : tempFPRegForData(backing);
840 12142 : ensureFeSynced(fe, masm);
841 :
842 12142 : if (!fe->type.synced())
843 12142 : fe->type.sync();
844 12142 : if (!fe->data.synced())
845 12142 : fe->data.sync();
846 12142 : return;
847 : }
848 :
849 737080 : bool needTypeReg = !fe->type.synced() && backing->type.inMemory();
850 737080 : 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 737080 : if (needTypeReg && !needDataReg) {
855 780 : syncData(fe);
856 780 : syncType(fe);
857 : } else {
858 736300 : syncType(fe);
859 736300 : 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 3929 : FrameState::syncAndForgetFe(FrameEntry *fe, bool markSynced)
903 : {
904 3929 : if (markSynced) {
905 2256 : if (!fe->type.synced())
906 1848 : fe->type.sync();
907 2256 : if (!fe->data.synced())
908 1848 : fe->data.sync();
909 : }
910 :
911 3929 : syncFe(fe);
912 3929 : forgetAllRegs(fe);
913 3929 : fe->type.setMemory();
914 3929 : fe->data.setMemory();
915 3929 : }
916 :
917 : inline JSC::MacroAssembler::Address
918 29343 : FrameState::loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access, RegisterID reg)
919 : {
920 29343 : JS_ASSERT(access.script && access.nesting);
921 :
922 29343 : masm.move(ImmPtr(access.basePointer()), reg);
923 29343 : masm.loadPtr(Address(reg), reg);
924 :
925 29343 : return Address(reg, access.index * sizeof(Value));
926 : }
927 :
928 : inline JSC::MacroAssembler::Address
929 28831 : FrameState::loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access)
930 : {
931 28831 : RegisterID reg = allocReg();
932 28831 : return loadNameAddress(access, reg);
933 : }
934 :
935 : inline void
936 10552 : 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 10552 : if (loop)
943 8659 : fe->lastLoop = loop->headOffset();
944 10552 : }
945 :
946 : inline void
947 1045852 : FrameState::syncType(FrameEntry *fe)
948 : {
949 1045852 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
950 :
951 1045852 : FrameEntry *backing = fe;
952 1045852 : if (fe->isCopy())
953 80003 : backing = fe->copyOf();
954 :
955 1045852 : if (!fe->type.synced() && backing->type.inMemory())
956 45340 : tempRegForType(backing);
957 :
958 1045852 : ensureTypeSynced(fe, masm);
959 :
960 1045852 : if (!fe->type.synced())
961 951724 : fe->type.sync();
962 1045852 : }
963 :
964 : inline void
965 1196944 : FrameState::syncData(FrameEntry *fe)
966 : {
967 1196944 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
968 :
969 1196944 : FrameEntry *backing = fe;
970 1196944 : if (fe->isCopy())
971 80003 : backing = fe->copyOf();
972 :
973 1196944 : if (!fe->data.synced() && backing->data.inMemory())
974 61110 : tempRegForData(backing);
975 :
976 1196944 : ensureDataSynced(fe, masm);
977 :
978 1196944 : if (!fe->data.synced())
979 964662 : fe->data.sync();
980 1196944 : }
981 :
982 : inline void
983 40501 : 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 40501 : if (!fe->data.synced())
990 911 : fe->data.sync();
991 40501 : if (!fe->type.synced())
992 688 : fe->type.sync();
993 40501 : }
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 101556 : FrameState::learnType(FrameEntry *fe, JSValueType type, bool unsync)
1023 : {
1024 101556 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
1025 101556 : JS_ASSERT(type != JSVAL_TYPE_UNKNOWN);
1026 :
1027 101556 : if (fe->isCopy())
1028 0 : fe = fe->copyOf();
1029 :
1030 101556 : if (type == JSVAL_TYPE_DOUBLE)
1031 810 : JS_ASSERT(!fe->data.inRegister());
1032 : else
1033 100746 : JS_ASSERT(!fe->data.inFPRegister());
1034 :
1035 101556 : if (fe->type.inRegister())
1036 2285 : forgetReg(fe->type.reg());
1037 101556 : fe->setType(type);
1038 101556 : if (unsync)
1039 1871 : fe->type.unsync();
1040 101556 : }
1041 :
1042 : inline void
1043 5249 : FrameState::learnType(FrameEntry *fe, JSValueType type, RegisterID data)
1044 : {
1045 5249 : JS_ASSERT(!fe->isCopied());
1046 5249 : JS_ASSERT(type != JSVAL_TYPE_UNKNOWN && type != JSVAL_TYPE_DOUBLE);
1047 :
1048 5249 : forgetAllRegs(fe);
1049 5249 : fe->clear();
1050 :
1051 5249 : fe->type.setConstant();
1052 5249 : fe->knownType = type;
1053 :
1054 5249 : fe->data.setRegister(data);
1055 5249 : regstate(data).associate(fe, RematInfo::DATA);
1056 :
1057 5249 : fe->data.unsync();
1058 5249 : fe->type.unsync();
1059 5249 : }
1060 :
1061 : inline int32_t
1062 14031378 : 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 14031378 : JS_ASSERT(fe >= a->callee_ && fe <= a->sp);
1074 :
1075 14031378 : if (fe >= a->locals)
1076 13475080 : return StackFrame::offsetOfFixed(uint32_t(fe - a->locals));
1077 556298 : if (fe >= a->args)
1078 376569 : return StackFrame::offsetOfFormalArg(a->script->function(), uint32_t(fe - a->args));
1079 179729 : if (fe == a->this_)
1080 158419 : return StackFrame::offsetOfThis(a->script->function());
1081 21310 : if (fe == a->callee_)
1082 21310 : return StackFrame::offsetOfCallee(a->script->function());
1083 0 : JS_NOT_REACHED("Bad fe");
1084 : return 0;
1085 : }
1086 :
1087 : inline JSC::MacroAssembler::Address
1088 14060167 : FrameState::addressOf(const FrameEntry *fe) const
1089 : {
1090 14060167 : if (isTemporary(fe)) {
1091 : /*
1092 : * Temporary addresses are common to the outermost loop, and are shared
1093 : * by all active frames.
1094 : */
1095 28789 : return Address(JSFrameReg, (loop->temporariesStart + fe - temporaries) * sizeof(Value));
1096 : }
1097 :
1098 14031378 : ActiveFrame *na = a;
1099 28248279 : while (fe < na->callee_)
1100 185523 : na = na->parent;
1101 :
1102 14031378 : int32_t offset = frameOffset(fe, na);
1103 14031378 : return Address(JSFrameReg, offset + (na->depth * sizeof(Value)));
1104 : }
1105 :
1106 : inline uint32_t
1107 535675 : FrameState::frameSlot(ActiveFrame *a, const FrameEntry *fe) const
1108 : {
1109 535675 : if (isTemporary(fe))
1110 2525 : return fe - entries;
1111 :
1112 533150 : JS_ASSERT(fe >= a->callee_ && fe < a->sp);
1113 :
1114 533150 : if (fe >= a->locals)
1115 499509 : return analyze::LocalSlot(a->script, fe - a->locals);
1116 33641 : if (fe >= a->args)
1117 28650 : return analyze::ArgSlot(fe - a->args);
1118 4991 : if (fe == a->this_)
1119 4991 : 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 4188 : FrameState::addressForDataRemat(const FrameEntry *fe) const
1136 : {
1137 4188 : if (fe->isCopy() && !fe->data.synced())
1138 1349 : fe = fe->copyOf();
1139 4188 : JS_ASSERT(fe->data.synced());
1140 4188 : 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 26918 : FrameState::testInt32(Assembler::Condition cond, FrameEntry *fe)
1163 : {
1164 26918 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1165 26918 : if (shouldAvoidTypeRemat(fe))
1166 4424 : return masm.testInt32(cond, addressOf(fe));
1167 22494 : return masm.testInt32(cond, tempRegForType(fe));
1168 : }
1169 :
1170 : inline JSC::MacroAssembler::Jump
1171 2913 : FrameState::testPrimitive(Assembler::Condition cond, FrameEntry *fe)
1172 : {
1173 2913 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1174 2913 : if (shouldAvoidTypeRemat(fe))
1175 261 : return masm.testPrimitive(cond, addressOf(fe));
1176 2652 : return masm.testPrimitive(cond, tempRegForType(fe));
1177 : }
1178 :
1179 : inline JSC::MacroAssembler::Jump
1180 40127 : FrameState::testObject(Assembler::Condition cond, FrameEntry *fe)
1181 : {
1182 40127 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1183 40127 : if (shouldAvoidTypeRemat(fe))
1184 4251 : return masm.testObject(cond, addressOf(fe));
1185 35876 : 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 3430 : FrameState::testDouble(Assembler::Condition cond, FrameEntry *fe)
1198 : {
1199 3430 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1200 3430 : if (shouldAvoidTypeRemat(fe))
1201 0 : return masm.testDouble(cond, addressOf(fe));
1202 3430 : return masm.testDouble(cond, tempRegForType(fe));
1203 : }
1204 :
1205 : inline JSC::MacroAssembler::Jump
1206 24920 : FrameState::testBoolean(Assembler::Condition cond, FrameEntry *fe)
1207 : {
1208 24920 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1209 24920 : if (shouldAvoidTypeRemat(fe))
1210 22860 : return masm.testBoolean(cond, addressOf(fe));
1211 2060 : return masm.testBoolean(cond, tempRegForType(fe));
1212 : }
1213 :
1214 : inline JSC::MacroAssembler::Jump
1215 158 : FrameState::testString(Assembler::Condition cond, FrameEntry *fe)
1216 : {
1217 158 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1218 158 : if (shouldAvoidTypeRemat(fe))
1219 2 : return masm.testString(cond, addressOf(fe));
1220 156 : return masm.testString(cond, tempRegForType(fe));
1221 : }
1222 :
1223 : inline FrameEntry *
1224 2919048 : FrameState::getOrTrack(uint32_t index)
1225 : {
1226 2919048 : FrameEntry *fe = &entries[index];
1227 2919048 : if (!fe->isTracked()) {
1228 444246 : addToTracker(fe);
1229 444246 : fe->resetSynced();
1230 : }
1231 2919048 : return fe;
1232 : }
1233 :
1234 : inline FrameEntry *
1235 1823022 : FrameState::getStack(uint32_t slot)
1236 : {
1237 1823022 : if (slot >= uint32_t(a->sp - a->spBase))
1238 3455 : return NULL;
1239 1819567 : return getOrTrack(uint32_t(a->spBase + slot - entries));
1240 : }
1241 :
1242 : inline FrameEntry *
1243 472232 : FrameState::getLocal(uint32_t slot)
1244 : {
1245 472232 : JS_ASSERT(slot < a->script->nslots);
1246 472232 : return getOrTrack(uint32_t(a->locals + slot - entries));
1247 : }
1248 :
1249 : inline FrameEntry *
1250 99695 : FrameState::getArg(uint32_t slot)
1251 : {
1252 99695 : JS_ASSERT(slot < a->script->function()->nargs);
1253 99695 : return getOrTrack(uint32_t(a->args + slot - entries));
1254 : }
1255 :
1256 : inline FrameEntry *
1257 68395 : FrameState::getThis()
1258 : {
1259 68395 : return getOrTrack(uint32_t(a->this_ - entries));
1260 : }
1261 :
1262 : inline FrameEntry *
1263 222659 : FrameState::getSlotEntry(uint32_t slot)
1264 : {
1265 222659 : JS_ASSERT(slot < analyze::TotalSlots(a->script));
1266 222659 : return getOrTrack(uint32_t(a->callee_ + slot - entries));
1267 : }
1268 :
1269 : inline FrameEntry *
1270 957 : FrameState::getCallee()
1271 : {
1272 : // Callee can only be used in function code, and it's always an object.
1273 957 : JS_ASSERT(a->script->function());
1274 957 : FrameEntry *fe = a->callee_;
1275 957 : if (!fe->isTracked()) {
1276 957 : addToTracker(fe);
1277 957 : fe->resetSynced();
1278 957 : fe->setType(JSVAL_TYPE_OBJECT);
1279 : }
1280 957 : return fe;
1281 : }
1282 :
1283 : inline void
1284 188209 : FrameState::unpinKilledReg(AnyRegisterID reg)
1285 : {
1286 188209 : regstate(reg).unpinUnsafe();
1287 188209 : freeRegs.putReg(reg);
1288 188209 : }
1289 :
1290 : inline void
1291 4895455 : FrameState::forgetAllRegs(FrameEntry *fe)
1292 : {
1293 4895455 : if (fe->isCopy())
1294 645393 : return;
1295 4250062 : if (fe->type.inRegister())
1296 921527 : forgetReg(fe->type.reg());
1297 4250062 : if (fe->data.inRegister())
1298 1221348 : forgetReg(fe->data.reg());
1299 4250062 : if (fe->data.inFPRegister())
1300 12107 : forgetReg(fe->data.fpreg());
1301 : }
1302 :
1303 : inline void
1304 66723 : FrameState::swapInTracker(FrameEntry *lhs, FrameEntry *rhs)
1305 : {
1306 66723 : uint32_t li = lhs->trackerIndex();
1307 66723 : uint32_t ri = rhs->trackerIndex();
1308 66723 : JS_ASSERT(tracker[li] == lhs);
1309 66723 : JS_ASSERT(tracker[ri] == rhs);
1310 66723 : tracker.entries[ri] = lhs;
1311 66723 : tracker.entries[li] = rhs;
1312 66723 : lhs->index_ = ri;
1313 66723 : rhs->index_ = li;
1314 66723 : }
1315 :
1316 : inline void
1317 89964 : FrameState::dup()
1318 : {
1319 89964 : dupAt(-1);
1320 89964 : }
1321 :
1322 : inline void
1323 84041 : FrameState::dup2()
1324 : {
1325 84041 : FrameEntry *lhs = peek(-2);
1326 84041 : FrameEntry *rhs = peek(-1);
1327 84041 : pushCopyOf(lhs);
1328 84041 : pushCopyOf(rhs);
1329 84041 : }
1330 :
1331 : inline void
1332 118555 : FrameState::dupAt(int32_t n)
1333 : {
1334 118555 : JS_ASSERT(n < 0);
1335 118555 : FrameEntry *fe = peek(n);
1336 118555 : pushCopyOf(fe);
1337 118555 : }
1338 :
1339 : inline void
1340 235 : FrameState::syncAt(int32_t n)
1341 : {
1342 235 : JS_ASSERT(n < 0);
1343 235 : FrameEntry *fe = peek(n);
1344 235 : syncFe(fe);
1345 235 : }
1346 :
1347 : inline void
1348 273627 : FrameState::pushLocal(uint32_t n)
1349 : {
1350 273627 : FrameEntry *fe = getLocal(n);
1351 273627 : if (!a->analysis->slotEscapes(analyze::LocalSlot(a->script, n))) {
1352 113653 : 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 159974 : if (fe->isTracked() && n < a->script->nfixed)
1361 123515 : JS_ASSERT(fe->data.inMemory());
1362 : #endif
1363 159974 : if (n >= a->script->nfixed)
1364 36459 : syncFe(fe);
1365 159974 : JSValueType type = fe->isTypeKnown() ? fe->getKnownType() : JSVAL_TYPE_UNKNOWN;
1366 159974 : push(addressOf(fe), type);
1367 : }
1368 273627 : }
1369 :
1370 : inline void
1371 96924 : FrameState::pushArg(uint32_t n)
1372 : {
1373 96924 : FrameEntry *fe = getArg(n);
1374 96924 : if (!a->analysis->slotEscapes(analyze::ArgSlot(n))) {
1375 50605 : pushCopyOf(fe);
1376 : } else {
1377 : #ifdef DEBUG
1378 46319 : if (fe->isTracked())
1379 46319 : JS_ASSERT(fe->data.inMemory());
1380 : #endif
1381 46319 : JSValueType type = fe->isTypeKnown() ? fe->getKnownType() : JSVAL_TYPE_UNKNOWN;
1382 46319 : push(addressOf(fe), type);
1383 : }
1384 96924 : }
1385 :
1386 : inline void
1387 957 : FrameState::pushCallee()
1388 : {
1389 957 : FrameEntry *fe = getCallee();
1390 957 : pushCopyOf(fe);
1391 957 : }
1392 :
1393 : inline void
1394 58906 : FrameState::pushThis()
1395 : {
1396 58906 : FrameEntry *fe = getThis();
1397 58906 : pushCopyOf(fe);
1398 58906 : }
1399 :
1400 : void
1401 7759 : 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 7759 : FrameEntry *fe = getThis();
1407 7759 : if (fe->isCopy())
1408 41 : fe = fe->copyOf();
1409 7759 : learnType(fe, JSVAL_TYPE_OBJECT, unsync);
1410 7759 : }
1411 :
1412 : void
1413 161 : FrameState::setThis(RegisterID reg)
1414 : {
1415 161 : FrameEntry *fe = getThis();
1416 161 : JS_ASSERT(!fe->isCopy());
1417 161 : learnType(fe, JSVAL_TYPE_OBJECT, reg);
1418 161 : }
1419 :
1420 : void
1421 1077 : FrameState::syncThis()
1422 : {
1423 1077 : FrameEntry *fe = getThis();
1424 1077 : syncFe(fe);
1425 1077 : }
1426 :
1427 : inline bool
1428 376716 : FrameState::isConstructorThis(const FrameEntry *fe) const
1429 : {
1430 376716 : return isThis(fe) && cc.constructing();
1431 : }
1432 :
1433 : inline void
1434 23335 : FrameState::leaveBlock(uint32_t n)
1435 : {
1436 23335 : popn(n);
1437 23335 : }
1438 :
1439 : inline void
1440 17698 : FrameState::enterBlock(uint32_t n)
1441 : {
1442 : /* expect that tracker has 0 entries, for now. */
1443 17698 : JS_ASSERT(!tracker.nentries);
1444 17698 : JS_ASSERT(uint32_t(a->sp + n - a->locals) <= a->script->nslots);
1445 :
1446 17698 : a->sp += n;
1447 17698 : }
1448 :
1449 : inline void
1450 : FrameState::eviscerate(FrameEntry *fe)
1451 : {
1452 : forgetAllRegs(fe);
1453 : fe->resetUnsynced();
1454 : }
1455 :
1456 : inline StateRemat
1457 5703 : FrameState::dataRematInfo(const FrameEntry *fe) const
1458 : {
1459 5703 : if (fe->isCopy())
1460 2272 : fe = fe->copyOf();
1461 :
1462 5703 : if (fe->data.inRegister())
1463 4378 : return StateRemat::FromRegister(fe->data.reg());
1464 :
1465 1325 : JS_ASSERT(fe->data.synced());
1466 1325 : return StateRemat::FromAddress(addressOf(fe));
1467 : }
1468 :
1469 : inline void
1470 7878 : FrameState::giveOwnRegs(FrameEntry *fe)
1471 : {
1472 7878 : JS_ASSERT(!fe->isConstant());
1473 7878 : JS_ASSERT(fe == peek(-1));
1474 :
1475 7878 : if (!fe->isCopy())
1476 7750 : return;
1477 :
1478 128 : RegisterID data = copyDataIntoReg(fe);
1479 128 : if (fe->isTypeKnown()) {
1480 0 : JSValueType type = fe->getKnownType();
1481 0 : pop();
1482 0 : pushTypedPayload(type, data);
1483 : } else {
1484 128 : RegisterID type = copyTypeIntoReg(fe);
1485 128 : pop();
1486 128 : pushRegs(type, data, JSVAL_TYPE_UNKNOWN);
1487 : }
1488 : }
1489 :
1490 : inline void
1491 988395 : FrameState::loadDouble(RegisterID t, RegisterID d, FrameEntry *fe, FPRegisterID fpreg,
1492 : Assembler &masm) const
1493 : {
1494 : #ifdef JS_CPU_X86
1495 988395 : masm.fastLoadDouble(d, t, fpreg);
1496 : #else
1497 : loadDouble(fe, fpreg, masm);
1498 : #endif
1499 988395 : }
1500 :
1501 : inline bool
1502 12212 : FrameState::tryFastDoubleLoad(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const
1503 : {
1504 : #ifdef JS_CPU_X86
1505 12212 : if (!fe->isCopy() && fe->type.inRegister() && fe->data.inRegister()) {
1506 7781 : masm.fastLoadDouble(fe->data.reg(), fe->type.reg(), fpReg);
1507 7781 : return true;
1508 : }
1509 : #endif
1510 4431 : return false;
1511 : }
1512 :
1513 : inline void
1514 10701 : FrameState::loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const
1515 : {
1516 10701 : if (fe->isCopy()) {
1517 1511 : FrameEntry *backing = fe->copyOf();
1518 1511 : if (tryFastDoubleLoad(fe, fpReg, masm))
1519 0 : return;
1520 1511 : fe = backing;
1521 : }
1522 :
1523 10701 : if (tryFastDoubleLoad(fe, fpReg, masm))
1524 7781 : return;
1525 :
1526 2920 : ensureFeSynced(fe, masm);
1527 2920 : 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 93225 : PinRegAcrossSyncAndKill(FrameState &frame, RegisterID reg)
1537 93225 : : frame(frame), maybeReg(reg)
1538 : {
1539 93225 : frame.pinReg(reg);
1540 93225 : }
1541 93333 : PinRegAcrossSyncAndKill(FrameState &frame, MaybeRegisterID maybeReg)
1542 93333 : : frame(frame), maybeReg(maybeReg)
1543 : {
1544 93333 : if (maybeReg.isSet())
1545 55144 : frame.pinReg(maybeReg.reg());
1546 93333 : }
1547 186558 : ~PinRegAcrossSyncAndKill() {
1548 186558 : if (maybeReg.isSet())
1549 148369 : frame.unpinKilledReg(maybeReg.reg());
1550 186558 : }
1551 : };
1552 :
1553 : } /* namespace mjit */
1554 : } /* namespace js */
1555 :
1556 : #endif /* include */
1557 :
|