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 2606451 : FrameState::addToTracker(FrameEntry *fe)
50 : {
51 2606451 : JS_ASSERT(!fe->isTracked());
52 2606451 : fe->track(tracker.nentries);
53 2606451 : tracker.add(fe);
54 2606451 : }
55 :
56 : inline FrameEntry *
57 18389190 : FrameState::peek(int32_t depth)
58 : {
59 18389190 : JS_ASSERT(depth < 0);
60 18389190 : JS_ASSERT(a->sp + depth >= a->spBase);
61 18389190 : FrameEntry *fe = a->sp + depth;
62 18389190 : if (!fe->isTracked()) {
63 124678 : addToTracker(fe);
64 124678 : fe->resetSynced();
65 : }
66 18389190 : return fe;
67 : }
68 :
69 : inline void
70 2319276 : FrameState::popn(uint32_t n)
71 : {
72 6860189 : for (uint32_t i = 0; i < n; i++)
73 4540913 : pop();
74 2319276 : }
75 :
76 : inline bool
77 743618 : FrameState::haveSameBacking(FrameEntry *lhs, FrameEntry *rhs)
78 : {
79 743618 : if (lhs->isCopy())
80 274317 : lhs = lhs->copyOf();
81 743618 : if (rhs->isCopy())
82 22217 : rhs = rhs->copyOf();
83 743618 : return lhs == rhs;
84 : }
85 :
86 : inline FrameEntry *
87 18962 : FrameState::getTemporary(uint32_t which)
88 : {
89 18962 : JS_ASSERT(which < TEMPORARY_LIMIT);
90 :
91 18962 : FrameEntry *fe = temporaries + which;
92 18962 : JS_ASSERT(fe < temporariesTop);
93 :
94 18962 : return getOrTrack(uint32_t(fe - entries));
95 : }
96 :
97 : inline AnyRegisterID
98 5709435 : FrameState::allocReg(uint32_t mask)
99 : {
100 5709435 : if (freeRegs.hasRegInMask(mask)) {
101 5592855 : AnyRegisterID reg = freeRegs.takeAnyReg(mask);
102 5592855 : modifyReg(reg);
103 5592855 : return reg;
104 : }
105 :
106 116580 : AnyRegisterID reg = evictSomeReg(mask);
107 116580 : modifyReg(reg);
108 116580 : return reg;
109 : }
110 :
111 : inline JSC::MacroAssembler::RegisterID
112 4343970 : FrameState::allocReg()
113 : {
114 4343970 : return allocReg(Registers::AvailRegs).reg();
115 : }
116 :
117 : inline JSC::MacroAssembler::FPRegisterID
118 1336759 : FrameState::allocFPReg()
119 : {
120 1336759 : return allocReg(Registers::AvailFPRegs).fpreg();
121 : }
122 :
123 : inline AnyRegisterID
124 2053131 : FrameState::allocAndLoadReg(FrameEntry *fe, bool fp, RematInfo::RematType type)
125 : {
126 2053131 : AnyRegisterID reg;
127 2053131 : 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 2106672 : if (loop && freeRegs.hasRegInMask(loop->getLoopRegs() & mask) &&
138 37039 : type == RematInfo::DATA && isOuterSlot(fe) && !cc.activeFrameHasMultipleExits() &&
139 16502 : fe->lastLoop < loop->headOffset()) {
140 16201 : reg = freeRegs.takeAnyReg(loop->getLoopRegs() & mask);
141 16201 : regstate(reg).associate(fe, RematInfo::DATA);
142 16201 : fe->lastLoop = loop->headOffset();
143 16201 : loop->setLoopReg(reg, fe);
144 16201 : return reg;
145 : }
146 :
147 2036930 : if (!freeRegs.empty(mask))
148 1979369 : reg = freeRegs.takeAnyReg(mask);
149 : else
150 57561 : reg = evictSomeReg(mask);
151 2036930 : modifyReg(reg);
152 :
153 2036930 : if (fp)
154 1164 : masm.loadDouble(addressOf(fe), reg.fpreg());
155 2035766 : else if (type == RematInfo::TYPE)
156 1188299 : masm.loadTypeTag(addressOf(fe), reg.reg());
157 : else
158 847467 : masm.loadPayload(addressOf(fe), reg.reg());
159 :
160 2036930 : regstate(reg).associate(fe, type);
161 2036930 : return reg;
162 : }
163 :
164 : inline void
165 8536492 : FrameState::modifyReg(AnyRegisterID reg)
166 : {
167 8536492 : if (loop)
168 865512 : loop->clearLoopReg(reg);
169 8536492 : }
170 :
171 : inline void
172 11406 : FrameState::convertInt32ToDouble(Assembler &masm, FrameEntry *fe, FPRegisterID fpreg) const
173 : {
174 11406 : JS_ASSERT(!fe->isConstant());
175 :
176 11406 : if (fe->isCopy())
177 2294 : fe = fe->copyOf();
178 :
179 11406 : if (fe->data.inRegister())
180 9396 : masm.convertInt32ToDouble(fe->data.reg(), fpreg);
181 : else
182 2010 : masm.convertInt32ToDouble(masm.payloadOf(addressOf(fe)), fpreg);
183 11406 : }
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 8845808 : FrameState::pop()
195 : {
196 8845808 : JS_ASSERT(a->sp > a->spBase);
197 :
198 8845808 : FrameEntry *fe = --a->sp;
199 8845808 : if (!fe->isTracked())
200 62972 : return;
201 :
202 8782836 : forgetAllRegs(fe);
203 8782836 : fe->type.invalidate();
204 8782836 : fe->data.invalidate();
205 8782836 : fe->clear();
206 :
207 8782836 : extraArray[fe - entries].reset();
208 : }
209 :
210 : inline void
211 1885716 : FrameState::freeReg(AnyRegisterID reg)
212 : {
213 1885716 : JS_ASSERT(!regstate(reg).usedBy());
214 :
215 1885716 : freeRegs.putReg(reg);
216 1885716 : }
217 :
218 : inline void
219 6339139 : 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 6339139 : JS_ASSERT_IF(regstate(reg).fe(), !regstate(reg).fe()->isCopy());
226 :
227 6339139 : if (!regstate(reg).isPinned()) {
228 5959565 : regstate(reg).forget();
229 5959565 : freeRegs.putReg(reg);
230 : }
231 6339139 : }
232 :
233 : inline FrameEntry *
234 8909577 : FrameState::rawPush()
235 : {
236 8909577 : JS_ASSERT(a->sp < temporaries);
237 8909577 : FrameEntry *fe = a->sp++;
238 :
239 8909577 : if (!fe->isTracked())
240 1748169 : addToTracker(fe);
241 8909577 : fe->type.invalidate();
242 8909577 : fe->data.invalidate();
243 8909577 : fe->clear();
244 :
245 8909577 : extraArray[fe - entries].reset();
246 :
247 8909577 : return fe;
248 : }
249 :
250 : inline void
251 1701936 : FrameState::push(const Value &v)
252 : {
253 1701936 : FrameEntry *fe = rawPush();
254 1701936 : fe->setConstant(v);
255 1701936 : }
256 :
257 : inline void
258 2718445 : FrameState::pushSynced(JSValueType type)
259 : {
260 2718445 : FrameEntry *fe = rawPush();
261 :
262 2718445 : fe->resetSynced();
263 2718445 : if (type != JSVAL_TYPE_UNKNOWN) {
264 94421 : fe->setType(type);
265 94421 : if (type == JSVAL_TYPE_DOUBLE)
266 257 : masm.ensureInMemoryDouble(addressOf(fe));
267 : }
268 2718445 : }
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 410902 : 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 410902 : bool free = freeRegs.hasReg(address.base);
301 410902 : bool needsPin = !free && regstate(address.base).fe();
302 410902 : if (free)
303 2107 : freeRegs.takeReg(address.base);
304 410902 : if (needsPin)
305 3756 : pinReg(address.base);
306 :
307 410902 : RegisterID typeReg = allocReg();
308 :
309 410902 : 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 410902 : if (free)
315 2107 : freeRegs.putReg(address.base);
316 410902 : if (needsPin)
317 3756 : unpinReg(address.base);
318 :
319 410902 : RegisterID dataReg = reuseBase ? address.base : allocReg();
320 410902 : masm.loadPayload(address, dataReg);
321 :
322 : #endif
323 :
324 410902 : *ptypeReg = typeReg;
325 410902 : *pdataReg = dataReg;
326 410902 : }
327 :
328 : inline void
329 381621 : FrameState::push(Address address, JSValueType knownType, bool reuseBase)
330 : {
331 381621 : 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 380577 : if (knownType != JSVAL_TYPE_UNKNOWN) {
341 61335 : RegisterID dataReg = reuseBase ? address.base : allocReg();
342 61335 : masm.loadPayload(address, dataReg);
343 61335 : pushTypedPayload(knownType, dataReg);
344 61335 : return;
345 : }
346 :
347 : RegisterID typeReg, dataReg;
348 319242 : loadIntoRegisters(address, reuseBase, &typeReg, &dataReg);
349 :
350 319242 : 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 1899892 : FrameState::storeRegs(int32_t depth, RegisterID type, RegisterID data, JSValueType knownType)
366 : {
367 1899892 : FrameEntry *fe = peek(depth);
368 1899892 : forgetEntry(fe);
369 1899892 : 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 1899892 : JS_ASSERT(!freeRegs.hasReg(type) && !freeRegs.hasReg(data));
376 :
377 1899892 : if (knownType == JSVAL_TYPE_UNKNOWN) {
378 1780078 : fe->type.setRegister(type);
379 1780078 : fe->data.setRegister(data);
380 1780078 : regstate(type).associate(fe, RematInfo::TYPE);
381 1780078 : regstate(data).associate(fe, RematInfo::DATA);
382 1780078 : return Registers::FPConversionTemp;
383 : }
384 :
385 119814 : 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 109662 : freeReg(type);
397 109662 : fe->setType(knownType);
398 109662 : fe->data.setRegister(data);
399 109662 : regstate(data).associate(fe, RematInfo::DATA);
400 109662 : return Registers::FPConversionTemp;
401 : }
402 :
403 : inline JSC::MacroAssembler::FPRegisterID
404 1899892 : FrameState::pushRegs(RegisterID type, RegisterID data, JSValueType knownType)
405 : {
406 1899892 : pushSynced(JSVAL_TYPE_UNKNOWN);
407 1899892 : return storeRegs(-1, type, data, knownType);
408 : }
409 :
410 : inline void
411 147359 : FrameState::reloadEntry(Assembler &masm, Address address, FrameEntry *fe)
412 : {
413 147359 : if (fe->data.inRegister()) {
414 146527 : if (fe->type.inRegister()) {
415 118693 : masm.loadValueAsComponents(address, fe->type.reg(), fe->data.reg());
416 : } else {
417 27834 : JS_ASSERT(fe->isTypeKnown());
418 27834 : 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 147359 : }
425 :
426 : inline void
427 296829 : FrameState::pushTypedPayload(JSValueType type, RegisterID payload)
428 : {
429 296829 : JS_ASSERT(type != JSVAL_TYPE_DOUBLE);
430 296829 : JS_ASSERT(!freeRegs.hasReg(payload));
431 :
432 296829 : FrameEntry *fe = rawPush();
433 :
434 296829 : fe->resetUnsynced();
435 296829 : fe->setType(type);
436 296829 : fe->data.setRegister(payload);
437 296829 : regstate(payload).associate(fe, RematInfo::DATA);
438 296829 : }
439 :
440 : inline void
441 562451 : FrameState::pushNumber(RegisterID payload, bool asInt32)
442 : {
443 562451 : JS_ASSERT(!freeRegs.hasReg(payload));
444 :
445 562451 : FrameEntry *fe = rawPush();
446 :
447 562451 : if (asInt32) {
448 559387 : if (!fe->type.synced())
449 251273 : masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
450 559387 : fe->type.setMemory();
451 : } else {
452 3064 : fe->type.setMemory();
453 : }
454 :
455 562451 : fe->data.unsync();
456 562451 : fe->data.setRegister(payload);
457 562451 : regstate(payload).associate(fe, RematInfo::DATA);
458 562451 : }
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 4630 : FrameState::pushUntypedPayload(JSValueType type, RegisterID payload)
475 : {
476 4630 : JS_ASSERT(!freeRegs.hasReg(payload));
477 :
478 4630 : FrameEntry *fe = rawPush();
479 :
480 4630 : masm.storeTypeTag(ImmType(type), addressOf(fe));
481 :
482 : /* The forceful type sync will assert otherwise. */
483 : #ifdef DEBUG
484 4630 : fe->type.unsync();
485 : #endif
486 4630 : fe->type.setMemory();
487 4630 : fe->data.unsync();
488 4630 : fe->data.setRegister(payload);
489 4630 : regstate(payload).associate(fe, RematInfo::DATA);
490 4630 : }
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 3289407 : FrameState::tempRegForType(FrameEntry *fe)
529 : {
530 3289407 : if (fe->isCopy())
531 414748 : fe = fe->copyOf();
532 :
533 3289407 : JS_ASSERT(!fe->type.isConstant());
534 :
535 3289407 : if (fe->type.inRegister())
536 2102683 : return fe->type.reg();
537 :
538 : /* :XXX: X86 */
539 :
540 1186724 : RegisterID reg = allocAndLoadReg(fe, false, RematInfo::TYPE).reg();
541 1186724 : fe->type.setRegister(reg);
542 1186724 : 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 2991331 : FrameState::tempRegForData(FrameEntry *fe)
583 : {
584 2991331 : JS_ASSERT(!fe->isConstant());
585 2991331 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
586 :
587 2991331 : if (fe->isCopy())
588 307831 : fe = fe->copyOf();
589 :
590 2991331 : if (fe->data.inRegister())
591 2130214 : return fe->data.reg();
592 :
593 861117 : RegisterID reg = allocAndLoadReg(fe, false, RematInfo::DATA).reg();
594 861117 : fe->data.setRegister(reg);
595 861117 : return reg;
596 : }
597 :
598 : inline void
599 1096095 : FrameState::forgetMismatchedObject(FrameEntry *fe)
600 : {
601 1096095 : 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 1096095 : if (fe->isConstant()) {
613 32341 : RegisterID reg = allocReg();
614 32341 : regstate(reg).associate(fe, RematInfo::DATA);
615 :
616 32341 : masm.move(JSC::MacroAssembler::ImmPtr(&fe->getValue().toObject()), reg);
617 32341 : fe->data.setRegister(reg);
618 : }
619 1096095 : }
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 1630 : 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 5126 : FrameState::tempRegInMaskForData(FrameEntry *fe, uint32_t mask)
642 : {
643 5126 : JS_ASSERT(!fe->isConstant());
644 5126 : JS_ASSERT_IF(fe->isType(JSVAL_TYPE_DOUBLE), !(mask & ~Registers::AvailFPRegs));
645 5126 : JS_ASSERT_IF(!fe->isType(JSVAL_TYPE_DOUBLE), !(mask & ~Registers::AvailRegs));
646 :
647 5126 : if (fe->isCopy())
648 593 : fe = fe->copyOf();
649 :
650 5126 : AnyRegisterID reg;
651 5126 : if (fe->data.inRegister() || fe->data.inFPRegister()) {
652 4393 : AnyRegisterID old;
653 4393 : if (fe->data.inRegister())
654 4312 : old = fe->data.reg();
655 : else
656 81 : old = fe->data.fpreg();
657 4393 : if (Registers::maskReg(old) & mask)
658 2569 : return old;
659 :
660 : /* Keep the old register pinned. */
661 1824 : regstate(old).forget();
662 1824 : reg = allocReg(mask);
663 1824 : if (reg.isReg())
664 1824 : masm.move(old.reg(), reg.reg());
665 : else
666 0 : masm.moveDouble(old.fpreg(), reg.fpreg());
667 1824 : 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 2557 : regstate(reg).associate(fe, RematInfo::DATA);
676 2557 : if (reg.isReg())
677 2557 : fe->data.setRegister(reg.reg());
678 : else
679 0 : fe->data.setFPRegister(reg.fpreg());
680 2557 : 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 408044 : FrameState::shouldAvoidTypeRemat(FrameEntry *fe)
704 : {
705 408044 : return !fe->isCopy() && fe->type.inMemory();
706 : }
707 :
708 : inline bool
709 43275 : FrameState::shouldAvoidDataRemat(FrameEntry *fe)
710 : {
711 43275 : return !fe->isCopy() && fe->data.inMemory();
712 : }
713 :
714 : inline void
715 57314 : FrameState::ensureFeSynced(const FrameEntry *fe, Assembler &masm) const
716 : {
717 57314 : Address to = addressOf(fe);
718 57314 : const FrameEntry *backing = fe;
719 57314 : if (fe->isCopy())
720 2916 : backing = fe->copyOf();
721 :
722 57314 : if (backing->isType(JSVAL_TYPE_DOUBLE)) {
723 53093 : if (fe->data.synced()) {
724 : /* Entries representing known doubles can't be partially synced. */
725 6954 : JS_ASSERT(fe->type.synced());
726 6954 : return;
727 : }
728 46139 : if (backing->isConstant()) {
729 11296 : masm.storeValue(backing->getValue(), to);
730 34843 : } else if (backing->data.inFPRegister()) {
731 33902 : masm.storeDouble(backing->data.fpreg(), to);
732 : } else {
733 : /* Use a temporary so the entry can be synced without allocating a register. */
734 941 : JS_ASSERT(backing->data.inMemory() && backing != fe);
735 941 : masm.loadDouble(addressOf(backing), Registers::FPConversionTemp);
736 941 : masm.storeDouble(Registers::FPConversionTemp, to);
737 : }
738 46139 : 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 4221 : ensureDataSynced(fe, masm);
759 4221 : ensureTypeSynced(fe, masm);
760 : }
761 :
762 : inline void
763 15484618 : FrameState::ensureTypeSynced(const FrameEntry *fe, Assembler &masm) const
764 : {
765 15484618 : if (fe->type.synced())
766 7194530 : return;
767 :
768 8290088 : Address to = addressOf(fe);
769 8290088 : const FrameEntry *backing = fe;
770 8290088 : if (fe->isCopy())
771 1261348 : 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 8290088 : if (backing->isConstant())
792 2375091 : masm.storeTypeTag(ImmTag(backing->getKnownTag()), to);
793 5914997 : else if (backing->isTypeKnown())
794 961858 : masm.storeTypeTag(ImmType(backing->getKnownType()), to);
795 : else
796 4953139 : masm.storeTypeTag(backing->type.reg(), to);
797 : }
798 :
799 : inline void
800 15691826 : FrameState::ensureDataSynced(const FrameEntry *fe, Assembler &masm) const
801 : {
802 15691826 : if (fe->data.synced())
803 6549051 : return;
804 :
805 9142775 : Address to = addressOf(fe);
806 9142775 : const FrameEntry *backing = fe;
807 9142775 : if (fe->isCopy())
808 1261576 : 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 9142775 : if (backing->isConstant())
821 2375341 : masm.storePayload(ImmPayload(backing->getPayload()), to);
822 : else
823 6767434 : masm.storePayload(backing->data.reg(), to);
824 : #endif
825 : }
826 :
827 : inline void
828 6505789 : FrameState::syncFe(FrameEntry *fe)
829 : {
830 6505789 : if (fe->type.synced() && fe->data.synced())
831 4520153 : return;
832 :
833 1985636 : FrameEntry *backing = fe;
834 1985636 : if (fe->isCopy())
835 324682 : backing = fe->copyOf();
836 :
837 1985636 : if (backing->isType(JSVAL_TYPE_DOUBLE)) {
838 12119 : if (!backing->isConstant())
839 7757 : tempFPRegForData(backing);
840 12119 : ensureFeSynced(fe, masm);
841 :
842 12119 : if (!fe->type.synced())
843 12119 : fe->type.sync();
844 12119 : if (!fe->data.synced())
845 12119 : fe->data.sync();
846 12119 : return;
847 : }
848 :
849 1973517 : bool needTypeReg = !fe->type.synced() && backing->type.inMemory();
850 1973517 : 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 1973517 : if (needTypeReg && !needDataReg) {
855 2731 : syncData(fe);
856 2731 : syncType(fe);
857 : } else {
858 1970786 : syncType(fe);
859 1970786 : 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 3687 : FrameState::syncAndForgetFe(FrameEntry *fe, bool markSynced)
903 : {
904 3687 : if (markSynced) {
905 2319 : if (!fe->type.synced())
906 1911 : fe->type.sync();
907 2319 : if (!fe->data.synced())
908 1911 : fe->data.sync();
909 : }
910 :
911 3687 : syncFe(fe);
912 3687 : forgetAllRegs(fe);
913 3687 : fe->type.setMemory();
914 3687 : fe->data.setMemory();
915 3687 : }
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 10643 : 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 10643 : if (loop)
943 8750 : fe->lastLoop = loop->headOffset();
944 10643 : }
945 :
946 : inline void
947 3212742 : FrameState::syncType(FrameEntry *fe)
948 : {
949 3212742 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
950 :
951 3212742 : FrameEntry *backing = fe;
952 3212742 : if (fe->isCopy())
953 323874 : backing = fe->copyOf();
954 :
955 3212742 : if (!fe->type.synced() && backing->type.inMemory())
956 64303 : tempRegForType(backing);
957 :
958 3212742 : ensureTypeSynced(fe, masm);
959 :
960 3212742 : if (!fe->type.synced())
961 3017595 : fe->type.sync();
962 3212742 : }
963 :
964 : inline void
965 3422678 : FrameState::syncData(FrameEntry *fe)
966 : {
967 3422678 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
968 :
969 3422678 : FrameEntry *backing = fe;
970 3422678 : if (fe->isCopy())
971 323874 : backing = fe->copyOf();
972 :
973 3422678 : if (!fe->data.synced() && backing->data.inMemory())
974 82962 : tempRegForData(backing);
975 :
976 3422678 : ensureDataSynced(fe, masm);
977 :
978 3422678 : if (!fe->data.synced())
979 3018296 : fe->data.sync();
980 3422678 : }
981 :
982 : inline void
983 40950 : 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 40950 : if (!fe->data.synced())
990 909 : fe->data.sync();
991 40950 : if (!fe->type.synced())
992 686 : fe->type.sync();
993 40950 : }
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 128872 : FrameState::learnType(FrameEntry *fe, JSValueType type, bool unsync)
1023 : {
1024 128872 : JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
1025 128872 : JS_ASSERT(type != JSVAL_TYPE_UNKNOWN);
1026 :
1027 128872 : if (fe->isCopy())
1028 0 : fe = fe->copyOf();
1029 :
1030 128872 : if (type == JSVAL_TYPE_DOUBLE)
1031 810 : JS_ASSERT(!fe->data.inRegister());
1032 : else
1033 128062 : JS_ASSERT(!fe->data.inFPRegister());
1034 :
1035 128872 : if (fe->type.inRegister())
1036 29958 : forgetReg(fe->type.reg());
1037 128872 : fe->setType(type);
1038 128872 : if (unsync)
1039 29535 : fe->type.unsync();
1040 128872 : }
1041 :
1042 : inline void
1043 6032 : FrameState::learnType(FrameEntry *fe, JSValueType type, RegisterID data)
1044 : {
1045 6032 : JS_ASSERT(!fe->isCopied());
1046 6032 : JS_ASSERT(type != JSVAL_TYPE_UNKNOWN && type != JSVAL_TYPE_DOUBLE);
1047 :
1048 6032 : forgetAllRegs(fe);
1049 6032 : fe->clear();
1050 :
1051 6032 : fe->type.setConstant();
1052 6032 : fe->knownType = type;
1053 :
1054 6032 : fe->data.setRegister(data);
1055 6032 : regstate(data).associate(fe, RematInfo::DATA);
1056 :
1057 6032 : fe->data.unsync();
1058 6032 : fe->type.unsync();
1059 6032 : }
1060 :
1061 : inline int32_t
1062 27503474 : 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 27503474 : JS_ASSERT(fe >= a->callee_ && fe <= a->sp);
1074 :
1075 27503474 : if (fe >= a->locals)
1076 26380562 : return StackFrame::offsetOfFixed(uint32_t(fe - a->locals));
1077 1122912 : if (fe >= a->args)
1078 630070 : return StackFrame::offsetOfFormalArg(a->script->function(), uint32_t(fe - a->args));
1079 492842 : if (fe == a->this_)
1080 464242 : return StackFrame::offsetOfThis(a->script->function());
1081 28600 : if (fe == a->callee_)
1082 28600 : return StackFrame::offsetOfCallee(a->script->function());
1083 0 : JS_NOT_REACHED("Bad fe");
1084 : return 0;
1085 : }
1086 :
1087 : inline JSC::MacroAssembler::Address
1088 27531750 : FrameState::addressOf(const FrameEntry *fe) const
1089 : {
1090 27531750 : if (isTemporary(fe)) {
1091 : /*
1092 : * Temporary addresses are common to the outermost loop, and are shared
1093 : * by all active frames.
1094 : */
1095 28276 : return Address(JSFrameReg, (loop->temporariesStart + fe - temporaries) * sizeof(Value));
1096 : }
1097 :
1098 27503474 : ActiveFrame *na = a;
1099 55193273 : while (fe < na->callee_)
1100 186325 : na = na->parent;
1101 :
1102 27503474 : int32_t offset = frameOffset(fe, na);
1103 27503474 : return Address(JSFrameReg, offset + (na->depth * sizeof(Value)));
1104 : }
1105 :
1106 : inline uint32_t
1107 627305 : FrameState::frameSlot(ActiveFrame *a, const FrameEntry *fe) const
1108 : {
1109 627305 : if (isTemporary(fe))
1110 2511 : return fe - entries;
1111 :
1112 624794 : JS_ASSERT(fe >= a->callee_ && fe < a->sp);
1113 :
1114 624794 : if (fe >= a->locals)
1115 589256 : return analyze::LocalSlot(a->script, fe - a->locals);
1116 35538 : if (fe >= a->args)
1117 30539 : return analyze::ArgSlot(fe - a->args);
1118 4999 : if (fe == a->this_)
1119 4999 : 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 11394 : FrameState::addressForDataRemat(const FrameEntry *fe) const
1136 : {
1137 11394 : if (fe->isCopy() && !fe->data.synced())
1138 4043 : fe = fe->copyOf();
1139 11394 : JS_ASSERT(fe->data.synced());
1140 11394 : 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 47156 : FrameState::testInt32(Assembler::Condition cond, FrameEntry *fe)
1163 : {
1164 47156 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1165 47156 : if (shouldAvoidTypeRemat(fe))
1166 4565 : return masm.testInt32(cond, addressOf(fe));
1167 42591 : return masm.testInt32(cond, tempRegForType(fe));
1168 : }
1169 :
1170 : inline JSC::MacroAssembler::Jump
1171 4509 : FrameState::testPrimitive(Assembler::Condition cond, FrameEntry *fe)
1172 : {
1173 4509 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1174 4509 : if (shouldAvoidTypeRemat(fe))
1175 334 : return masm.testPrimitive(cond, addressOf(fe));
1176 4175 : return masm.testPrimitive(cond, tempRegForType(fe));
1177 : }
1178 :
1179 : inline JSC::MacroAssembler::Jump
1180 69429 : FrameState::testObject(Assembler::Condition cond, FrameEntry *fe)
1181 : {
1182 69429 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1183 69429 : if (shouldAvoidTypeRemat(fe))
1184 4296 : return masm.testObject(cond, addressOf(fe));
1185 65133 : 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 8942 : FrameState::testDouble(Assembler::Condition cond, FrameEntry *fe)
1198 : {
1199 8942 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1200 8942 : if (shouldAvoidTypeRemat(fe))
1201 0 : return masm.testDouble(cond, addressOf(fe));
1202 8942 : return masm.testDouble(cond, tempRegForType(fe));
1203 : }
1204 :
1205 : inline JSC::MacroAssembler::Jump
1206 70560 : FrameState::testBoolean(Assembler::Condition cond, FrameEntry *fe)
1207 : {
1208 70560 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1209 70560 : if (shouldAvoidTypeRemat(fe))
1210 68493 : return masm.testBoolean(cond, addressOf(fe));
1211 2067 : return masm.testBoolean(cond, tempRegForType(fe));
1212 : }
1213 :
1214 : inline JSC::MacroAssembler::Jump
1215 1057 : FrameState::testString(Assembler::Condition cond, FrameEntry *fe)
1216 : {
1217 1057 : JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
1218 1057 : if (shouldAvoidTypeRemat(fe))
1219 7 : return masm.testString(cond, addressOf(fe));
1220 1050 : return masm.testString(cond, tempRegForType(fe));
1221 : }
1222 :
1223 : inline FrameEntry *
1224 3261726 : FrameState::getOrTrack(uint32_t index)
1225 : {
1226 3261726 : FrameEntry *fe = &entries[index];
1227 3261726 : if (!fe->isTracked()) {
1228 730504 : addToTracker(fe);
1229 730504 : fe->resetSynced();
1230 : }
1231 3261726 : return fe;
1232 : }
1233 :
1234 : inline FrameEntry *
1235 1741192 : FrameState::getStack(uint32_t slot)
1236 : {
1237 1741192 : if (slot >= uint32_t(a->sp - a->spBase))
1238 3451 : return NULL;
1239 1737741 : return getOrTrack(uint32_t(a->spBase + slot - entries));
1240 : }
1241 :
1242 : inline FrameEntry *
1243 719887 : FrameState::getLocal(uint32_t slot)
1244 : {
1245 719887 : JS_ASSERT(slot < a->script->nslots);
1246 719887 : return getOrTrack(uint32_t(a->locals + slot - entries));
1247 : }
1248 :
1249 : inline FrameEntry *
1250 198993 : FrameState::getArg(uint32_t slot)
1251 : {
1252 198993 : JS_ASSERT(slot < a->script->function()->nargs);
1253 198993 : return getOrTrack(uint32_t(a->args + slot - entries));
1254 : }
1255 :
1256 : inline FrameEntry *
1257 146020 : FrameState::getThis()
1258 : {
1259 146020 : return getOrTrack(uint32_t(a->this_ - entries));
1260 : }
1261 :
1262 : inline FrameEntry *
1263 222912 : FrameState::getSlotEntry(uint32_t slot)
1264 : {
1265 222912 : JS_ASSERT(slot < analyze::TotalSlots(a->script));
1266 222912 : return getOrTrack(uint32_t(a->callee_ + slot - entries));
1267 : }
1268 :
1269 : inline FrameEntry *
1270 3733 : FrameState::getCallee()
1271 : {
1272 : // Callee can only be used in function code, and it's always an object.
1273 3733 : JS_ASSERT(a->script->function());
1274 3733 : FrameEntry *fe = a->callee_;
1275 3733 : if (!fe->isTracked()) {
1276 3100 : addToTracker(fe);
1277 3100 : fe->resetSynced();
1278 3100 : fe->setType(JSVAL_TYPE_OBJECT);
1279 : }
1280 3733 : return fe;
1281 : }
1282 :
1283 : inline void
1284 344290 : FrameState::unpinKilledReg(AnyRegisterID reg)
1285 : {
1286 344290 : regstate(reg).unpinUnsafe();
1287 344290 : freeRegs.putReg(reg);
1288 344290 : }
1289 :
1290 : inline void
1291 12949281 : FrameState::forgetAllRegs(FrameEntry *fe)
1292 : {
1293 12949281 : if (fe->isCopy())
1294 4265938 : return;
1295 8683343 : if (fe->type.inRegister())
1296 1345472 : forgetReg(fe->type.reg());
1297 8683343 : if (fe->data.inRegister())
1298 1664188 : forgetReg(fe->data.reg());
1299 8683343 : if (fe->data.inFPRegister())
1300 12105 : forgetReg(fe->data.fpreg());
1301 : }
1302 :
1303 : inline void
1304 336834 : FrameState::swapInTracker(FrameEntry *lhs, FrameEntry *rhs)
1305 : {
1306 336834 : uint32_t li = lhs->trackerIndex();
1307 336834 : uint32_t ri = rhs->trackerIndex();
1308 336834 : JS_ASSERT(tracker[li] == lhs);
1309 336834 : JS_ASSERT(tracker[ri] == rhs);
1310 336834 : tracker.entries[ri] = lhs;
1311 336834 : tracker.entries[li] = rhs;
1312 336834 : lhs->index_ = ri;
1313 336834 : rhs->index_ = li;
1314 336834 : }
1315 :
1316 : inline void
1317 365277 : FrameState::dup()
1318 : {
1319 365277 : dupAt(-1);
1320 365277 : }
1321 :
1322 : inline void
1323 358437 : FrameState::dup2()
1324 : {
1325 358437 : FrameEntry *lhs = peek(-2);
1326 358437 : FrameEntry *rhs = peek(-1);
1327 358437 : pushCopyOf(lhs);
1328 358437 : pushCopyOf(rhs);
1329 358437 : }
1330 :
1331 : inline void
1332 2514535 : FrameState::dupAt(int32_t n)
1333 : {
1334 2514535 : JS_ASSERT(n < 0);
1335 2514535 : FrameEntry *fe = peek(n);
1336 2514535 : pushCopyOf(fe);
1337 2514535 : }
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 432252 : FrameState::pushLocal(uint32_t n)
1349 : {
1350 432252 : FrameEntry *fe = getLocal(n);
1351 432252 : if (!a->analysis->slotEscapes(analyze::LocalSlot(a->script, n))) {
1352 178915 : 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 253337 : if (fe->isTracked() && n < a->script->nfixed)
1361 204581 : JS_ASSERT(fe->data.inMemory());
1362 : #endif
1363 253337 : if (n >= a->script->nfixed)
1364 48756 : syncFe(fe);
1365 253337 : JSValueType type = fe->isTypeKnown() ? fe->getKnownType() : JSVAL_TYPE_UNKNOWN;
1366 253337 : push(addressOf(fe), type);
1367 : }
1368 432252 : }
1369 :
1370 : inline void
1371 194234 : FrameState::pushArg(uint32_t n)
1372 : {
1373 194234 : FrameEntry *fe = getArg(n);
1374 194234 : if (!a->analysis->slotEscapes(analyze::ArgSlot(n))) {
1375 94802 : pushCopyOf(fe);
1376 : } else {
1377 : #ifdef DEBUG
1378 99432 : if (fe->isTracked())
1379 99432 : JS_ASSERT(fe->data.inMemory());
1380 : #endif
1381 99432 : JSValueType type = fe->isTypeKnown() ? fe->getKnownType() : JSVAL_TYPE_UNKNOWN;
1382 99432 : push(addressOf(fe), type);
1383 : }
1384 194234 : }
1385 :
1386 : inline void
1387 3733 : FrameState::pushCallee()
1388 : {
1389 3733 : FrameEntry *fe = getCallee();
1390 3733 : pushCopyOf(fe);
1391 3733 : }
1392 :
1393 : inline void
1394 107791 : FrameState::pushThis()
1395 : {
1396 107791 : FrameEntry *fe = getThis();
1397 107791 : pushCopyOf(fe);
1398 107791 : }
1399 :
1400 : void
1401 35416 : 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 35416 : FrameEntry *fe = getThis();
1407 35416 : if (fe->isCopy())
1408 41 : fe = fe->copyOf();
1409 35416 : learnType(fe, JSVAL_TYPE_OBJECT, unsync);
1410 35416 : }
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 1849 : FrameState::syncThis()
1422 : {
1423 1849 : FrameEntry *fe = getThis();
1424 1849 : syncFe(fe);
1425 1849 : }
1426 :
1427 : inline bool
1428 370299 : FrameState::isConstructorThis(const FrameEntry *fe) const
1429 : {
1430 370299 : return isThis(fe) && cc.constructing();
1431 : }
1432 :
1433 : inline void
1434 28996 : FrameState::leaveBlock(uint32_t n)
1435 : {
1436 28996 : popn(n);
1437 28996 : }
1438 :
1439 : inline void
1440 21204 : FrameState::enterBlock(uint32_t n)
1441 : {
1442 : /* expect that tracker has 0 entries, for now. */
1443 21204 : JS_ASSERT(!tracker.nentries);
1444 21204 : JS_ASSERT(uint32_t(a->sp + n - a->locals) <= a->script->nslots);
1445 :
1446 21204 : a->sp += n;
1447 21204 : }
1448 :
1449 : inline void
1450 : FrameState::eviscerate(FrameEntry *fe)
1451 : {
1452 : forgetAllRegs(fe);
1453 : fe->resetUnsynced();
1454 : }
1455 :
1456 : inline StateRemat
1457 5692 : FrameState::dataRematInfo(const FrameEntry *fe) const
1458 : {
1459 5692 : if (fe->isCopy())
1460 2272 : fe = fe->copyOf();
1461 :
1462 5692 : if (fe->data.inRegister())
1463 4373 : 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 201335 : FrameState::giveOwnRegs(FrameEntry *fe)
1471 : {
1472 201335 : JS_ASSERT(!fe->isConstant());
1473 201335 : JS_ASSERT(fe == peek(-1));
1474 :
1475 201335 : if (!fe->isCopy())
1476 201203 : 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 1299276 : FrameState::loadDouble(RegisterID t, RegisterID d, FrameEntry *fe, FPRegisterID fpreg,
1492 : Assembler &masm) const
1493 : {
1494 : #ifdef JS_CPU_X86
1495 1299276 : masm.fastLoadDouble(d, t, fpreg);
1496 : #else
1497 : loadDouble(fe, fpreg, masm);
1498 : #endif
1499 1299276 : }
1500 :
1501 : inline bool
1502 19837 : FrameState::tryFastDoubleLoad(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const
1503 : {
1504 : #ifdef JS_CPU_X86
1505 19837 : if (!fe->isCopy() && fe->type.inRegister() && fe->data.inRegister()) {
1506 12802 : masm.fastLoadDouble(fe->data.reg(), fe->type.reg(), fpReg);
1507 12802 : return true;
1508 : }
1509 : #endif
1510 7035 : return false;
1511 : }
1512 :
1513 : inline void
1514 17023 : FrameState::loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const
1515 : {
1516 17023 : if (fe->isCopy()) {
1517 2814 : FrameEntry *backing = fe->copyOf();
1518 2814 : if (tryFastDoubleLoad(fe, fpReg, masm))
1519 0 : return;
1520 2814 : fe = backing;
1521 : }
1522 :
1523 17023 : if (tryFastDoubleLoad(fe, fpReg, masm))
1524 12802 : return;
1525 :
1526 4221 : ensureFeSynced(fe, masm);
1527 4221 : 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 159020 : PinRegAcrossSyncAndKill(FrameState &frame, RegisterID reg)
1537 159020 : : frame(frame), maybeReg(reg)
1538 : {
1539 159020 : frame.pinReg(reg);
1540 159020 : }
1541 150768 : PinRegAcrossSyncAndKill(FrameState &frame, MaybeRegisterID maybeReg)
1542 150768 : : frame(frame), maybeReg(maybeReg)
1543 : {
1544 150768 : if (maybeReg.isSet())
1545 112852 : frame.pinReg(maybeReg.reg());
1546 150768 : }
1547 309788 : ~PinRegAcrossSyncAndKill() {
1548 309788 : if (maybeReg.isSet())
1549 271872 : frame.unpinKilledReg(maybeReg.reg());
1550 309788 : }
1551 : };
1552 :
1553 : } /* namespace mjit */
1554 : } /* namespace js */
1555 :
1556 : #endif /* include */
1557 :
|