2008-05-28 19:07:25 -07:00
|
|
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
2008-07-05 11:18:26 -07:00
|
|
|
* vim: set ts=8 sw=4 et tw=99:
|
2008-05-28 19:07:25 -07:00
|
|
|
*
|
|
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
|
|
|
* May 28, 2008.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
2008-06-28 09:58:15 -07:00
|
|
|
* Brendan Eich <brendan@mozilla.org>
|
2008-05-28 19:07:25 -07:00
|
|
|
*
|
|
|
|
* Contributor(s):
|
2008-06-28 09:58:15 -07:00
|
|
|
* Andreas Gal <gal@mozilla.com>
|
2008-07-15 15:05:16 -07:00
|
|
|
* Mike Shaver <shaver@mozilla.org>
|
|
|
|
* David Anderson <danderson@mozilla.com>
|
2008-05-28 19:07:25 -07:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
2008-07-15 10:26:15 -07:00
|
|
|
#include "jsstddef.h" // always first
|
|
|
|
#include "jsprf.h" // low-level (NSPR-based) headers next
|
|
|
|
#include <math.h> // standard headers next
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#include <malloc.h>
|
|
|
|
#define alloca _alloca
|
|
|
|
#endif
|
2008-05-28 19:07:25 -07:00
|
|
|
|
2008-07-15 10:26:15 -07:00
|
|
|
#include "nanojit/avmplus.h" // nanojit
|
2008-06-21 14:55:32 -07:00
|
|
|
#include "nanojit/nanojit.h"
|
2008-07-15 10:26:15 -07:00
|
|
|
#include "jsarray.h" // higher-level library and API headers
|
2008-07-05 06:47:59 -07:00
|
|
|
#include "jsbool.h"
|
2008-07-03 22:08:13 -07:00
|
|
|
#include "jscntxt.h"
|
2008-07-11 17:59:10 -07:00
|
|
|
#include "jsfun.h"
|
2008-07-04 23:53:29 -07:00
|
|
|
#include "jsinterp.h"
|
2008-07-15 10:26:15 -07:00
|
|
|
#include "jsobj.h"
|
2008-07-11 17:59:10 -07:00
|
|
|
#include "jsscript.h"
|
2008-07-04 23:53:29 -07:00
|
|
|
#include "jsscope.h"
|
2008-07-17 14:58:09 -07:00
|
|
|
#include "jsemit.h"
|
2008-07-22 17:24:29 -07:00
|
|
|
#include "jsdbgapi.h"
|
2008-07-11 17:59:10 -07:00
|
|
|
#include "jstracer.h"
|
2008-06-21 14:55:32 -07:00
|
|
|
|
2008-07-15 10:26:15 -07:00
|
|
|
#include "jsautooplen.h" // generated headers last
|
2008-07-10 18:37:49 -07:00
|
|
|
|
2008-07-11 17:59:10 -07:00
|
|
|
#ifdef DEBUG
|
2008-07-18 14:13:31 -07:00
|
|
|
#define ABORT_TRACE(msg) do { fprintf(stdout, "abort: %d: %s\n", __LINE__, msg); return false; } while(0)
|
2008-07-11 17:59:10 -07:00
|
|
|
#else
|
|
|
|
#define ABORT_TRACE(msg) return false
|
|
|
|
#endif
|
|
|
|
|
2008-07-17 10:22:40 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
static struct {
|
|
|
|
uint64 recorderStarted, recorderAborted, traceCompleted, sideExitIntoInterpreter,
|
2008-07-19 00:15:22 -07:00
|
|
|
typeMapMismatchAtEntry, returnToDifferentLoopHeader, traceTriggered,
|
2008-07-17 10:22:40 -07:00
|
|
|
globalShapeMismatchAtEntry, typeMapTrashed, slotDemoted, slotPromoted, unstableLoopVariable;
|
|
|
|
} stat = { 0LL, };
|
|
|
|
#define AUDIT(x) (stat.x++)
|
|
|
|
#else
|
|
|
|
#define AUDIT(x) ((void)0)
|
|
|
|
#endif DEBUG
|
|
|
|
|
2008-07-03 23:57:57 -07:00
|
|
|
using namespace avmplus;
|
2008-06-21 14:55:32 -07:00
|
|
|
using namespace nanojit;
|
|
|
|
|
2008-07-03 23:57:57 -07:00
|
|
|
static GC gc = GC();
|
|
|
|
static avmplus::AvmCore* core = new (&gc) avmplus::AvmCore();
|
2008-05-30 10:11:56 -07:00
|
|
|
|
2008-07-10 18:42:04 -07:00
|
|
|
Tracker::Tracker()
|
2008-06-03 21:01:23 -07:00
|
|
|
{
|
2008-06-21 14:55:32 -07:00
|
|
|
pagelist = 0;
|
|
|
|
}
|
2008-06-10 21:40:47 -07:00
|
|
|
|
2008-07-10 18:42:04 -07:00
|
|
|
Tracker::~Tracker()
|
2008-06-21 14:55:32 -07:00
|
|
|
{
|
|
|
|
clear();
|
2008-06-03 21:01:23 -07:00
|
|
|
}
|
|
|
|
|
2008-07-10 18:42:04 -07:00
|
|
|
jsuword
|
|
|
|
Tracker::getPageBase(const void* v) const
|
2008-06-03 21:01:23 -07:00
|
|
|
{
|
2008-07-05 11:18:26 -07:00
|
|
|
return jsuword(v) & ~jsuword(NJ_PAGE_SIZE-1);
|
2008-06-04 00:09:57 -07:00
|
|
|
}
|
2008-06-11 11:29:35 -07:00
|
|
|
|
2008-07-10 18:42:04 -07:00
|
|
|
struct Tracker::Page*
|
|
|
|
Tracker::findPage(const void* v) const
|
2008-06-11 11:29:35 -07:00
|
|
|
{
|
2008-07-05 11:18:26 -07:00
|
|
|
jsuword base = getPageBase(v);
|
2008-07-10 18:42:04 -07:00
|
|
|
struct Tracker::Page* p = pagelist;
|
2008-06-21 14:55:32 -07:00
|
|
|
while (p) {
|
2008-06-29 13:53:40 -07:00
|
|
|
if (p->base == base) {
|
2008-06-21 14:55:32 -07:00
|
|
|
return p;
|
2008-06-29 13:53:40 -07:00
|
|
|
}
|
2008-06-21 14:55:32 -07:00
|
|
|
p = p->next;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-10 18:42:04 -07:00
|
|
|
struct Tracker::Page*
|
|
|
|
Tracker::addPage(const void* v) {
|
2008-07-05 11:18:26 -07:00
|
|
|
jsuword base = getPageBase(v);
|
2008-06-26 20:44:23 -07:00
|
|
|
struct Tracker::Page* p = (struct Tracker::Page*)
|
2008-07-10 18:42:04 -07:00
|
|
|
GC::Alloc(sizeof(*p) - sizeof(p->map) + (NJ_PAGE_SIZE >> 2) * sizeof(LIns*));
|
2008-06-21 14:55:32 -07:00
|
|
|
p->base = base;
|
|
|
|
p->next = pagelist;
|
|
|
|
pagelist = p;
|
|
|
|
return p;
|
2008-06-11 11:29:35 -07:00
|
|
|
}
|
|
|
|
|
2008-07-10 18:42:04 -07:00
|
|
|
void
|
|
|
|
Tracker::clear()
|
2008-06-11 11:29:35 -07:00
|
|
|
{
|
2008-06-21 14:55:32 -07:00
|
|
|
while (pagelist) {
|
|
|
|
Page* p = pagelist;
|
|
|
|
pagelist = pagelist->next;
|
|
|
|
GC::Free(p);
|
|
|
|
}
|
2008-06-11 11:29:35 -07:00
|
|
|
}
|
2008-06-11 17:59:28 -07:00
|
|
|
|
2008-07-20 14:23:39 -07:00
|
|
|
bool
|
|
|
|
Tracker::has(const void *v) const
|
|
|
|
{
|
|
|
|
struct Tracker::Page* p = findPage(v);
|
|
|
|
if (!p)
|
|
|
|
return false;
|
2008-07-20 16:09:08 -07:00
|
|
|
return p->map[(jsuword(v) & 0xfff) >> 2] != NULL;
|
2008-07-20 14:23:39 -07:00
|
|
|
}
|
|
|
|
|
2008-07-15 10:26:15 -07:00
|
|
|
LIns*
|
2008-07-10 18:42:04 -07:00
|
|
|
Tracker::get(const void* v) const
|
2008-06-21 14:55:32 -07:00
|
|
|
{
|
2008-07-10 18:42:04 -07:00
|
|
|
struct Tracker::Page* p = findPage(v);
|
2008-07-20 16:09:08 -07:00
|
|
|
JS_ASSERT(p); /* we must have a page for the slot we are looking for */
|
2008-07-10 18:42:04 -07:00
|
|
|
LIns* i = p->map[(jsuword(v) & 0xfff) >> 2];
|
2008-07-20 16:09:08 -07:00
|
|
|
JS_ASSERT(i);
|
2008-06-22 19:58:24 -07:00
|
|
|
return i;
|
2008-06-21 14:55:32 -07:00
|
|
|
}
|
|
|
|
|
2008-07-10 18:42:04 -07:00
|
|
|
void
|
|
|
|
Tracker::set(const void* v, LIns* i)
|
2008-06-11 20:22:00 -07:00
|
|
|
{
|
2008-07-10 18:42:04 -07:00
|
|
|
struct Tracker::Page* p = findPage(v);
|
2008-06-22 23:42:54 -07:00
|
|
|
if (!p)
|
2008-06-21 14:55:32 -07:00
|
|
|
p = addPage(v);
|
2008-07-08 00:46:53 -07:00
|
|
|
p->map[(jsuword(v) & 0xfff) >> 2] = i;
|
2008-06-11 20:22:00 -07:00
|
|
|
}
|
|
|
|
|
2008-07-06 19:39:02 -07:00
|
|
|
/*
|
|
|
|
* Return the coerced type of a value. If it's a number, we always return JSVAL_DOUBLE, no matter
|
|
|
|
* whether it's represented as an int or as a double.
|
|
|
|
*/
|
2008-07-06 15:55:04 -07:00
|
|
|
static inline int getCoercedType(jsval v)
|
2008-07-06 11:48:41 -07:00
|
|
|
{
|
|
|
|
if (JSVAL_IS_INT(v))
|
2008-07-06 15:55:04 -07:00
|
|
|
return JSVAL_DOUBLE;
|
2008-07-06 11:48:41 -07:00
|
|
|
return JSVAL_TAG(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool isNumber(jsval v)
|
|
|
|
{
|
|
|
|
return JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline jsdouble asNumber(jsval v)
|
|
|
|
{
|
|
|
|
JS_ASSERT(isNumber(v));
|
|
|
|
if (JSVAL_IS_DOUBLE(v))
|
|
|
|
return *JSVAL_TO_DOUBLE(v);
|
|
|
|
return (jsdouble)JSVAL_TO_INT(v);
|
|
|
|
}
|
|
|
|
|
2008-07-06 22:35:19 -07:00
|
|
|
static inline bool isInt32(jsval v)
|
|
|
|
{
|
|
|
|
if (!isNumber(v))
|
|
|
|
return false;
|
|
|
|
jsdouble d = asNumber(v);
|
2008-07-19 00:27:45 -07:00
|
|
|
jsint i;
|
|
|
|
return JSDOUBLE_IS_INT(d, i);
|
2008-07-06 22:35:19 -07:00
|
|
|
}
|
|
|
|
|
2008-07-05 22:20:35 -07:00
|
|
|
static LIns* demote(LirWriter *out, LInsp i)
|
|
|
|
{
|
|
|
|
if (i->isCall())
|
|
|
|
return callArgN(i,0);
|
|
|
|
if (i->isop(LIR_i2f) || i->isop(LIR_u2f))
|
|
|
|
return i->oprnd1();
|
|
|
|
AvmAssert(i->isconstq());
|
|
|
|
double cf = i->constvalf();
|
|
|
|
int32_t ci = cf > 0x7fffffff ? uint32_t(cf) : int32_t(cf);
|
|
|
|
return out->insImm(ci);
|
|
|
|
}
|
|
|
|
|
2008-07-20 17:36:11 -07:00
|
|
|
static bool isPromoteInt(LIns* i)
|
2008-07-05 22:20:35 -07:00
|
|
|
{
|
2008-07-07 12:58:28 -07:00
|
|
|
jsdouble d;
|
2008-07-08 18:12:22 -07:00
|
|
|
return i->isop(LIR_i2f) || (i->isconstq() && ((d = i->constvalf()) == (jsdouble)(jsint)d));
|
2008-07-05 22:20:35 -07:00
|
|
|
}
|
|
|
|
|
2008-07-20 17:36:11 -07:00
|
|
|
static bool isPromoteUint(LIns* i)
|
2008-07-05 22:20:35 -07:00
|
|
|
{
|
2008-07-07 12:58:28 -07:00
|
|
|
jsdouble d;
|
|
|
|
return i->isop(LIR_u2f) || (i->isconstq() && ((d = i->constvalf()) == (jsdouble)(jsuint)d));
|
2008-07-05 22:20:35 -07:00
|
|
|
}
|
|
|
|
|
2008-07-20 17:36:11 -07:00
|
|
|
static bool isPromote(LIns* i)
|
2008-07-05 22:20:35 -07:00
|
|
|
{
|
2008-07-19 00:15:22 -07:00
|
|
|
return isPromoteInt(i) || isPromoteUint(i);
|
2008-07-05 22:20:35 -07:00
|
|
|
}
|
|
|
|
|
2008-07-21 19:37:43 -07:00
|
|
|
static bool isconst(LIns* i, int32_t c)
|
|
|
|
{
|
|
|
|
return i->isconst() && i->constval() == c;
|
|
|
|
}
|
|
|
|
|
2008-07-21 17:50:17 -07:00
|
|
|
static bool overflowSafe(LIns* i)
|
|
|
|
{
|
|
|
|
LIns* c;
|
|
|
|
return (i->isop(LIR_and) && ((c = i->oprnd2())->isconst()) &&
|
|
|
|
((c->constval() & 0xc0000000) == 0)) ||
|
|
|
|
(i->isop(LIR_rsh) && ((c = i->oprnd2())->isconst()) &&
|
|
|
|
((c->constval() > 0)));
|
|
|
|
}
|
|
|
|
|
2008-07-05 22:20:35 -07:00
|
|
|
class FuncFilter: public LirWriter
|
|
|
|
{
|
2008-07-07 00:43:40 -07:00
|
|
|
TraceRecorder& recorder;
|
2008-07-05 22:20:35 -07:00
|
|
|
public:
|
2008-07-20 17:36:11 -07:00
|
|
|
FuncFilter(LirWriter* out, TraceRecorder& _recorder):
|
2008-07-07 00:43:40 -07:00
|
|
|
LirWriter(out), recorder(_recorder)
|
2008-07-05 22:20:35 -07:00
|
|
|
{
|
|
|
|
}
|
2008-07-07 02:21:04 -07:00
|
|
|
|
2008-07-06 17:43:08 -07:00
|
|
|
LInsp ins1(LOpcode v, LInsp s0)
|
|
|
|
{
|
|
|
|
switch (v) {
|
2008-07-12 00:34:10 -07:00
|
|
|
case LIR_fneg:
|
|
|
|
if (isPromoteInt(s0)) {
|
|
|
|
LIns* result = out->ins1(LIR_neg, demote(out, s0));
|
|
|
|
out->insGuard(LIR_xt, out->ins1(LIR_ov, result), recorder.snapshot());
|
|
|
|
return out->ins1(LIR_i2f, result);
|
2008-07-15 10:26:15 -07:00
|
|
|
}
|
2008-07-12 00:34:10 -07:00
|
|
|
break;
|
2008-07-10 21:55:09 -07:00
|
|
|
default:;
|
2008-07-06 17:43:08 -07:00
|
|
|
}
|
|
|
|
return out->ins1(v, s0);
|
|
|
|
}
|
2008-07-05 22:20:35 -07:00
|
|
|
|
2008-07-21 17:59:42 -07:00
|
|
|
LInsp ins2(LOpcode v, LInsp s0, LInsp s1)
|
2008-07-05 22:20:35 -07:00
|
|
|
{
|
|
|
|
if (s0 == s1 && v == LIR_feq) {
|
|
|
|
if (isPromote(s0)) {
|
|
|
|
// double(int) and double(uint) cannot be nan
|
|
|
|
return insImm(1);
|
|
|
|
}
|
|
|
|
if (s0->isop(LIR_fmul) || s0->isop(LIR_fsub) || s0->isop(LIR_fadd)) {
|
|
|
|
LInsp lhs = s0->oprnd1();
|
|
|
|
LInsp rhs = s0->oprnd2();
|
|
|
|
if (isPromote(lhs) && isPromote(rhs)) {
|
|
|
|
// add/sub/mul promoted ints can't be nan
|
|
|
|
return insImm(1);
|
|
|
|
}
|
|
|
|
}
|
2008-07-09 09:59:51 -07:00
|
|
|
} else if (LIR_feq <= v && v <= LIR_fge) {
|
2008-07-05 22:20:35 -07:00
|
|
|
if (isPromoteInt(s0) && isPromoteInt(s1)) {
|
|
|
|
// demote fcmp to cmp
|
|
|
|
v = LOpcode(v + (LIR_eq - LIR_feq));
|
2008-07-21 17:59:42 -07:00
|
|
|
return out->ins2(v, demote(out, s0), demote(out, s1));
|
2008-07-05 22:20:35 -07:00
|
|
|
} else if (isPromoteUint(s0) && isPromoteUint(s1)) {
|
|
|
|
// uint compare
|
|
|
|
v = LOpcode(v + (LIR_eq - LIR_feq));
|
|
|
|
if (v != LIR_eq)
|
|
|
|
v = LOpcode(v + (LIR_ult - LIR_lt)); // cmp -> ucmp
|
2008-07-21 17:59:42 -07:00
|
|
|
return out->ins2(v, demote(out, s0), demote(out, s1));
|
2008-07-05 22:20:35 -07:00
|
|
|
}
|
2008-07-19 00:27:45 -07:00
|
|
|
} else if (v == LIR_fadd || v == LIR_fsub) {
|
|
|
|
/* demoting multiplication seems to be tricky since it can quickly overflow the
|
|
|
|
value range of int32 */
|
2008-07-07 00:43:40 -07:00
|
|
|
if (isPromoteInt(s0) && isPromoteInt(s1)) {
|
|
|
|
// demote fop to op
|
|
|
|
v = (LOpcode)((int)v & ~LIR64);
|
2008-07-21 17:50:17 -07:00
|
|
|
LIns* d0;
|
|
|
|
LIns* d1;
|
2008-07-21 17:59:42 -07:00
|
|
|
LIns* result = out->ins2(v, d0 = demote(out, s0), d1 = demote(out, s1));
|
2008-07-21 17:50:17 -07:00
|
|
|
if (!overflowSafe(d0) || !overflowSafe(d1))
|
|
|
|
out->insGuard(LIR_xt, out->ins1(LIR_ov, result), recorder.snapshot());
|
2008-07-07 00:43:40 -07:00
|
|
|
return out->ins1(LIR_i2f, result);
|
|
|
|
}
|
2008-07-21 19:37:43 -07:00
|
|
|
} else if (v == LIR_or &&
|
|
|
|
s0->isop(LIR_lsh) && isconst(s0->oprnd2(), 16) &&
|
|
|
|
s1->isop(LIR_and) && isconst(s1->oprnd2(), 0xffff)) {
|
|
|
|
LIns* msw = s0->oprnd1();
|
|
|
|
LIns* lsw = s1->oprnd1();
|
|
|
|
LIns* x;
|
|
|
|
LIns* y;
|
|
|
|
if (lsw->isop(LIR_add) &&
|
|
|
|
lsw->oprnd1()->isop(LIR_and) &&
|
|
|
|
lsw->oprnd2()->isop(LIR_and) &&
|
|
|
|
isconst(lsw->oprnd1()->oprnd2(), 0xffff) &&
|
|
|
|
isconst(lsw->oprnd2()->oprnd2(), 0xffff) &&
|
|
|
|
msw->isop(LIR_add) &&
|
|
|
|
msw->oprnd1()->isop(LIR_add) &&
|
|
|
|
msw->oprnd2()->isop(LIR_rsh) &&
|
|
|
|
msw->oprnd1()->oprnd1()->isop(LIR_rsh) &&
|
|
|
|
msw->oprnd1()->oprnd2()->isop(LIR_rsh) &&
|
|
|
|
isconst(msw->oprnd2()->oprnd2(), 16) &&
|
|
|
|
isconst(msw->oprnd1()->oprnd1()->oprnd2(), 16) &&
|
|
|
|
isconst(msw->oprnd1()->oprnd2()->oprnd2(), 16) &&
|
|
|
|
(x = lsw->oprnd1()->oprnd1()) == msw->oprnd1()->oprnd1()->oprnd1() &&
|
|
|
|
(y = lsw->oprnd2()->oprnd1()) == msw->oprnd1()->oprnd2()->oprnd1() &&
|
|
|
|
lsw == msw->oprnd2()->oprnd1()) {
|
|
|
|
return out->ins2(LIR_add, x, y);
|
|
|
|
}
|
2008-07-05 22:20:35 -07:00
|
|
|
}
|
2008-07-21 17:59:42 -07:00
|
|
|
return out->ins2(v, s0, s1);
|
2008-07-05 22:20:35 -07:00
|
|
|
}
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-17 03:24:17 -07:00
|
|
|
LInsp insCall(uint32_t fid, LInsp args[])
|
2008-07-05 22:20:35 -07:00
|
|
|
{
|
2008-07-06 20:27:50 -07:00
|
|
|
LInsp s0 = args[0];
|
2008-07-06 16:38:54 -07:00
|
|
|
switch (fid) {
|
2008-07-20 17:36:11 -07:00
|
|
|
case F_doubleToUint32:
|
|
|
|
if (s0->isconstq())
|
|
|
|
return out->insImm(js_DoubleToECMAUint32(s0->constvalf()));
|
|
|
|
if (s0->isop(LIR_i2f) || s0->isop(LIR_u2f)) {
|
|
|
|
return s0->oprnd1();
|
|
|
|
}
|
|
|
|
break;
|
2008-07-10 21:55:09 -07:00
|
|
|
case F_doubleToInt32:
|
2008-07-10 16:55:37 -07:00
|
|
|
if (s0->isconstq())
|
|
|
|
return out->insImm(js_DoubleToECMAInt32(s0->constvalf()));
|
2008-07-05 22:20:35 -07:00
|
|
|
if (s0->isop(LIR_fadd) || s0->isop(LIR_fsub) || s0->isop(LIR_fmul)) {
|
|
|
|
LInsp lhs = s0->oprnd1();
|
|
|
|
LInsp rhs = s0->oprnd2();
|
|
|
|
if (isPromote(lhs) && isPromote(rhs)) {
|
|
|
|
LOpcode op = LOpcode(s0->opcode() & ~LIR64);
|
|
|
|
return out->ins2(op, demote(out, lhs), demote(out, rhs));
|
|
|
|
}
|
|
|
|
}
|
2008-07-06 17:32:21 -07:00
|
|
|
if (s0->isop(LIR_i2f) || s0->isop(LIR_u2f)) {
|
|
|
|
return s0->oprnd1();
|
|
|
|
}
|
2008-07-06 16:38:54 -07:00
|
|
|
break;
|
2008-07-10 21:55:09 -07:00
|
|
|
case F_BoxDouble:
|
2008-07-10 17:03:59 -07:00
|
|
|
JS_ASSERT(s0->isQuad());
|
2008-07-06 20:27:50 -07:00
|
|
|
if (s0->isop(LIR_i2f)) {
|
2008-07-10 17:03:59 -07:00
|
|
|
LIns* args2[] = { s0->oprnd1(), args[1] };
|
|
|
|
return out->insCall(F_BoxInt32, args2);
|
2008-07-06 16:38:54 -07:00
|
|
|
}
|
|
|
|
break;
|
2008-07-05 22:20:35 -07:00
|
|
|
}
|
|
|
|
return out->insCall(fid, args);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-07-08 16:29:23 -07:00
|
|
|
/* In debug mode vpname contains a textual description of the type of the
|
|
|
|
slot during the forall iteration over al slots. */
|
|
|
|
#ifdef DEBUG
|
2008-07-15 16:04:08 -07:00
|
|
|
#define DEF_VPNAME const char* vpname; unsigned vpnum
|
2008-07-08 16:29:23 -07:00
|
|
|
#define SET_VPNAME(name) do { vpname = name; vpnum = 0; } while(0)
|
|
|
|
#define INC_VPNUM() do { ++vpnum; } while(0)
|
|
|
|
#else
|
2008-07-08 22:40:07 -07:00
|
|
|
#define DEF_VPNAME do {} while (0)
|
|
|
|
#define vpname ""
|
|
|
|
#define vpnum 0
|
2008-07-08 16:29:23 -07:00
|
|
|
#define SET_VPNAME(name) ((void)0)
|
|
|
|
#define INC_VPNUM() ((void)0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* This macro can be used to iterate over all slots in currently pending
|
|
|
|
frames that make up the native frame, including global variables and
|
|
|
|
frames consisting of rval, args, vars, and stack (except for the top-
|
|
|
|
level frame which does not have args or vars. */
|
2008-07-21 16:19:38 -07:00
|
|
|
#define FORALL_SLOTS_IN_PENDING_FRAMES(cx, ngslots, gslots, callDepth, code) \
|
2008-07-08 16:29:23 -07:00
|
|
|
JS_BEGIN_MACRO \
|
2008-07-08 22:40:07 -07:00
|
|
|
DEF_VPNAME; \
|
2008-07-14 16:40:38 -07:00
|
|
|
JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); \
|
2008-07-08 16:29:23 -07:00
|
|
|
unsigned n; \
|
|
|
|
jsval* vp; \
|
2008-07-13 21:14:34 -07:00
|
|
|
SET_VPNAME("global"); \
|
2008-07-15 01:53:39 -07:00
|
|
|
for (n = 0; n < ngslots; ++n) { \
|
|
|
|
vp = &STOBJ_GET_SLOT(globalObj, gslots[n]); \
|
|
|
|
{ code; } \
|
|
|
|
INC_VPNUM(); \
|
2008-07-08 16:29:23 -07:00
|
|
|
} \
|
2008-07-21 16:19:38 -07:00
|
|
|
JSStackFrame* currentFrame = cx->fp; \
|
|
|
|
JSStackFrame* entryFrame; \
|
2008-07-08 16:29:23 -07:00
|
|
|
JSStackFrame* fp = currentFrame; \
|
2008-07-21 16:19:38 -07:00
|
|
|
for (n = 0; n < callDepth; ++n) { fp = fp->down; } \
|
|
|
|
entryFrame = fp; \
|
|
|
|
unsigned frames = callDepth+1; \
|
2008-07-10 13:48:42 -07:00
|
|
|
JSStackFrame** fstack = (JSStackFrame **)alloca(frames * sizeof (JSStackFrame *)); \
|
2008-07-08 16:29:23 -07:00
|
|
|
JSStackFrame** fspstop = &fstack[frames]; \
|
|
|
|
JSStackFrame** fsp = fspstop-1; \
|
|
|
|
fp = currentFrame; \
|
2008-07-08 20:06:54 -07:00
|
|
|
for (;; fp = fp->down) { *fsp-- = fp; if (fp == entryFrame) break; } \
|
2008-07-08 16:29:23 -07:00
|
|
|
for (fsp = fstack; fsp < fspstop; ++fsp) { \
|
|
|
|
JSStackFrame* f = *fsp; \
|
|
|
|
jsval* vpstop; \
|
2008-07-09 00:26:01 -07:00
|
|
|
SET_VPNAME("rval"); \
|
|
|
|
vp = &f->rval; code; \
|
2008-07-09 17:10:42 -07:00
|
|
|
if (f->callee) { \
|
2008-07-16 14:36:50 -07:00
|
|
|
SET_VPNAME("this"); \
|
|
|
|
vp = &f->argv[-1]; \
|
|
|
|
code; \
|
2008-07-08 16:29:23 -07:00
|
|
|
SET_VPNAME("argv"); \
|
2008-07-21 19:31:08 -07:00
|
|
|
vp = &f->argv[0]; vpstop = &f->argv[f->fun->nargs]; \
|
2008-07-08 16:29:23 -07:00
|
|
|
while (vp < vpstop) { code; ++vp; INC_VPNUM(); } \
|
|
|
|
SET_VPNAME("vars"); \
|
2008-07-08 17:14:01 -07:00
|
|
|
vp = &f->vars[0]; vpstop = &f->vars[f->nvars]; \
|
2008-07-08 16:29:23 -07:00
|
|
|
while (vp < vpstop) { code; ++vp; INC_VPNUM(); } \
|
|
|
|
} \
|
|
|
|
SET_VPNAME("stack"); \
|
|
|
|
vp = f->spbase; vpstop = f->regs->sp; \
|
|
|
|
while (vp < vpstop) { code; ++vp; INC_VPNUM(); } \
|
|
|
|
} \
|
2008-07-09 15:15:32 -07:00
|
|
|
JS_END_MACRO
|
2008-07-08 16:29:23 -07:00
|
|
|
|
2008-07-19 00:15:22 -07:00
|
|
|
TraceRecorder::TraceRecorder(JSContext* cx, GuardRecord* _anchor,
|
2008-07-17 17:12:28 -07:00
|
|
|
Fragment* _fragment, uint8* typeMap)
|
2008-06-26 22:33:33 -07:00
|
|
|
{
|
2008-06-28 18:47:12 -07:00
|
|
|
this->cx = cx;
|
2008-07-14 16:40:38 -07:00
|
|
|
this->globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain);
|
2008-07-17 17:12:28 -07:00
|
|
|
this->anchor = _anchor;
|
2008-07-02 17:19:07 -07:00
|
|
|
this->fragment = _fragment;
|
2008-07-16 21:41:03 -07:00
|
|
|
this->lirbuf = _fragment->lirbuf;
|
2008-07-21 12:41:43 -07:00
|
|
|
this->treeInfo = (TreeInfo*)_fragment->root->vmprivate;
|
|
|
|
JS_ASSERT(treeInfo);
|
|
|
|
this->entryRegs = &treeInfo->entryRegs;
|
2008-07-21 13:18:08 -07:00
|
|
|
this->callDepth = _fragment->calldepth;
|
|
|
|
JS_ASSERT(!_anchor || _anchor->calldepth == _fragment->calldepth);
|
2008-07-10 21:55:09 -07:00
|
|
|
this->atoms = cx->fp->script->atomMap.vector;
|
2008-07-01 02:37:07 -07:00
|
|
|
|
2008-07-07 02:21:04 -07:00
|
|
|
#ifdef DEBUG
|
2008-07-20 12:42:19 -07:00
|
|
|
printf("recording starting from %s:%u@%u\n", cx->fp->script->filename,
|
|
|
|
js_PCToLineNumber(cx, cx->fp->script, entryRegs->pc),
|
|
|
|
entryRegs->pc - cx->fp->script->code);
|
2008-07-05 16:28:03 -07:00
|
|
|
#endif
|
2008-07-07 02:21:04 -07:00
|
|
|
|
2008-06-30 18:08:32 -07:00
|
|
|
lir = lir_buf_writer = new (&gc) LirBufWriter(lirbuf);
|
2008-07-05 10:41:35 -07:00
|
|
|
#ifdef DEBUG
|
2008-06-30 18:08:32 -07:00
|
|
|
lir = verbose_filter = new (&gc) VerboseWriter(&gc, lir, lirbuf->names);
|
2008-07-05 10:41:35 -07:00
|
|
|
#endif
|
2008-06-30 18:08:32 -07:00
|
|
|
lir = cse_filter = new (&gc) CseFilter(lir, &gc);
|
|
|
|
lir = expr_filter = new (&gc) ExprFilter(lir);
|
2008-07-07 00:43:40 -07:00
|
|
|
lir = func_filter = new (&gc) FuncFilter(lir, *this);
|
2008-06-27 18:06:50 -07:00
|
|
|
lir->ins0(LIR_trace);
|
2008-07-15 10:26:15 -07:00
|
|
|
|
2008-07-17 02:00:23 -07:00
|
|
|
lirbuf->state = addName(lir->insParam(0), "state");
|
|
|
|
lirbuf->param1 = addName(lir->insParam(1), "param1");
|
|
|
|
lirbuf->sp = addName(lir->insLoadi(lirbuf->state, offsetof(InterpState, sp)), "sp");
|
|
|
|
lirbuf->rp = addName(lir->insLoadi(lirbuf->state, offsetof(InterpState, rp)), "rp");
|
|
|
|
cx_ins = addName(lir->insLoadi(lirbuf->state, offsetof(InterpState, cx)), "cx");
|
2008-07-05 10:41:35 -07:00
|
|
|
|
2008-07-17 17:12:28 -07:00
|
|
|
uint8* m = typeMap;
|
2008-07-17 15:09:48 -07:00
|
|
|
jsuword* localNames = NULL;
|
|
|
|
#ifdef DEBUG
|
|
|
|
void* mark = NULL;
|
|
|
|
if (cx->fp->fun) {
|
|
|
|
mark = JS_ARENA_MARK(&cx->tempPool);
|
|
|
|
localNames = js_GetLocalNameArray(cx, cx->fp->fun, &cx->tempPool);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
localNames = NULL;
|
|
|
|
#endif
|
2008-07-22 17:24:29 -07:00
|
|
|
unsigned slot = 0;
|
2008-07-21 16:19:38 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, treeInfo->ngslots, treeInfo->gslots, callDepth,
|
2008-07-22 17:24:29 -07:00
|
|
|
import(lirbuf->sp, slot++, vp, *m, vpname, vpnum, localNames); m++
|
2008-07-08 16:29:23 -07:00
|
|
|
);
|
2008-07-17 15:09:48 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
|
|
|
#endif
|
2008-07-07 02:21:04 -07:00
|
|
|
|
2008-07-06 22:35:19 -07:00
|
|
|
recompileFlag = false;
|
2008-06-27 18:06:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
TraceRecorder::~TraceRecorder()
|
|
|
|
{
|
2008-06-30 18:08:32 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
delete verbose_filter;
|
2008-07-05 10:41:35 -07:00
|
|
|
#endif
|
2008-06-30 18:08:32 -07:00
|
|
|
delete cse_filter;
|
|
|
|
delete expr_filter;
|
2008-07-05 23:21:53 -07:00
|
|
|
delete func_filter;
|
2008-06-30 18:08:32 -07:00
|
|
|
delete lir_buf_writer;
|
2008-06-26 22:33:33 -07:00
|
|
|
}
|
|
|
|
|
2008-07-17 02:02:48 -07:00
|
|
|
/* Add debug information to a LIR instruction as we emit it. */
|
|
|
|
inline LIns*
|
|
|
|
TraceRecorder::addName(LIns* ins, const char* name)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
lirbuf->names->addName(ins, name);
|
|
|
|
#endif
|
|
|
|
return ins;
|
|
|
|
}
|
|
|
|
|
2008-06-28 17:14:06 -07:00
|
|
|
/* Determine the current call depth (starting with the entry frame.) */
|
|
|
|
unsigned
|
2008-07-05 19:15:00 -07:00
|
|
|
TraceRecorder::getCallDepth() const
|
2008-06-28 17:14:06 -07:00
|
|
|
{
|
2008-07-21 13:18:08 -07:00
|
|
|
return callDepth;
|
2008-06-28 17:14:06 -07:00
|
|
|
}
|
|
|
|
|
2008-07-16 21:41:03 -07:00
|
|
|
static int
|
|
|
|
findInternableGlobals(JSContext* cx, JSStackFrame* fp, uint16* slots)
|
2008-07-15 01:03:49 -07:00
|
|
|
{
|
2008-07-16 21:41:03 -07:00
|
|
|
JSObject* globalObj = JS_GetGlobalForObject(cx, fp->scopeChain);
|
2008-07-15 01:03:49 -07:00
|
|
|
unsigned count = 0;
|
|
|
|
unsigned n;
|
|
|
|
JSAtom** atoms = fp->script->atomMap.vector;
|
|
|
|
unsigned natoms = fp->script->atomMap.length;
|
2008-07-20 16:21:45 -07:00
|
|
|
bool FIXME_bug445262_sawMath = false;
|
2008-07-20 14:23:39 -07:00
|
|
|
for (n = 0; n < natoms + 1; ++n) {
|
|
|
|
JSAtom* atom;
|
|
|
|
if (n < natoms) {
|
|
|
|
atom = atoms[n];
|
|
|
|
if (atom == CLASS_ATOM(cx, Math))
|
2008-07-20 16:21:45 -07:00
|
|
|
FIXME_bug445262_sawMath = true;
|
2008-07-20 14:23:39 -07:00
|
|
|
} else {
|
2008-07-20 16:21:45 -07:00
|
|
|
if (FIXME_bug445262_sawMath)
|
2008-07-20 14:23:39 -07:00
|
|
|
break;
|
|
|
|
atom = CLASS_ATOM(cx, Math);
|
|
|
|
}
|
2008-07-15 01:03:49 -07:00
|
|
|
if (!ATOM_IS_STRING(atom))
|
|
|
|
continue;
|
|
|
|
jsid id = ATOM_TO_JSID(atom);
|
|
|
|
JSObject* pobj;
|
|
|
|
JSProperty *prop;
|
|
|
|
JSScopeProperty* sprop;
|
|
|
|
if (!js_LookupProperty(cx, globalObj, id, &pobj, &prop))
|
2008-07-15 10:26:15 -07:00
|
|
|
return -1;
|
2008-07-15 01:03:49 -07:00
|
|
|
if (!prop)
|
|
|
|
continue; /* property not found -- string constant? */
|
|
|
|
if (pobj == globalObj) {
|
|
|
|
sprop = (JSScopeProperty*) prop;
|
|
|
|
unsigned slot;
|
|
|
|
if (SPROP_HAS_STUB_GETTER(sprop) &&
|
|
|
|
SPROP_HAS_STUB_SETTER(sprop) &&
|
2008-07-16 15:48:51 -07:00
|
|
|
((slot = sprop->slot) == (uint16)slot) &&
|
|
|
|
!VALUE_IS_FUNCTION(cx, STOBJ_GET_SLOT(globalObj, slot))) {
|
2008-07-15 01:03:49 -07:00
|
|
|
if (slots)
|
|
|
|
*slots++ = slot;
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
JS_UNLOCK_OBJ(cx, pobj);
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2008-06-30 09:36:10 -07:00
|
|
|
/* Calculate the total number of native frame slots we need from this frame
|
|
|
|
all the way back to the entry frame, including the current stack usage. */
|
2008-07-21 14:55:41 -07:00
|
|
|
static unsigned nativeFrameSlots(unsigned ngslots, unsigned callDepth,
|
2008-07-16 21:41:03 -07:00
|
|
|
JSStackFrame* fp, JSFrameRegs& regs)
|
2008-06-28 17:14:06 -07:00
|
|
|
{
|
2008-07-16 21:41:03 -07:00
|
|
|
unsigned slots = ngslots;
|
2008-07-05 11:29:28 -07:00
|
|
|
for (;;) {
|
2008-07-15 20:20:53 -07:00
|
|
|
slots += 1/*rval*/ + (regs.sp - fp->spbase);
|
2008-07-09 17:10:42 -07:00
|
|
|
if (fp->callee)
|
2008-07-21 19:31:08 -07:00
|
|
|
slots += 1/*this*/ + fp->fun->nargs + fp->nvars;
|
2008-07-21 14:55:41 -07:00
|
|
|
if (callDepth-- == 0)
|
2008-07-05 11:29:28 -07:00
|
|
|
return slots;
|
2008-06-28 17:14:06 -07:00
|
|
|
fp = fp->down;
|
2008-07-05 10:41:35 -07:00
|
|
|
}
|
2008-07-05 11:29:28 -07:00
|
|
|
JS_NOT_REACHED("nativeFrameSlots");
|
2008-06-28 17:14:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine the offset in the native frame (marshal) for an address
|
|
|
|
that is part of a currently active frame. */
|
2008-07-05 11:18:26 -07:00
|
|
|
size_t
|
2008-07-09 00:29:23 -07:00
|
|
|
TraceRecorder::nativeFrameOffset(jsval* p) const
|
2008-06-28 17:14:06 -07:00
|
|
|
{
|
2008-07-08 16:29:23 -07:00
|
|
|
JSStackFrame* currentFrame = cx->fp;
|
|
|
|
size_t offset = 0;
|
2008-07-21 16:19:38 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, treeInfo->ngslots, treeInfo->gslots, callDepth,
|
2008-07-08 18:12:22 -07:00
|
|
|
if (vp == p) return offset;
|
2008-07-08 16:29:23 -07:00
|
|
|
offset += sizeof(double)
|
|
|
|
);
|
|
|
|
/* if its not in a pending frame, it must be on the stack of the current frame above
|
|
|
|
sp but below script->depth */
|
2008-07-09 09:59:51 -07:00
|
|
|
JS_ASSERT(size_t(p - currentFrame->regs->sp) < currentFrame->script->depth);
|
|
|
|
offset += size_t(p - currentFrame->regs->sp) * sizeof(double);
|
2008-07-08 16:29:23 -07:00
|
|
|
return offset;
|
2008-06-28 17:14:06 -07:00
|
|
|
}
|
|
|
|
|
2008-07-05 10:41:35 -07:00
|
|
|
/* Track the maximum number of native frame slots we need during
|
2008-07-02 17:19:07 -07:00
|
|
|
execution. */
|
|
|
|
void
|
|
|
|
TraceRecorder::trackNativeFrameUse(unsigned slots)
|
|
|
|
{
|
2008-07-21 12:41:43 -07:00
|
|
|
if (slots > treeInfo->maxNativeFrameSlots)
|
|
|
|
treeInfo->maxNativeFrameSlots = slots;
|
2008-07-02 17:19:07 -07:00
|
|
|
}
|
|
|
|
|
2008-07-05 10:41:35 -07:00
|
|
|
/* Unbox a jsval into a slot. Slots are wide enough to hold double values
|
2008-06-30 09:36:10 -07:00
|
|
|
directly (instead of storing a pointer to them). */
|
2008-07-02 17:19:07 -07:00
|
|
|
static bool
|
2008-07-07 01:37:40 -07:00
|
|
|
unbox_jsval(jsval v, uint8 t, double* slot)
|
2008-06-29 20:56:06 -07:00
|
|
|
{
|
2008-07-07 01:05:53 -07:00
|
|
|
jsuint type = TYPEMAP_GET_TYPE(t);
|
2008-07-09 17:09:22 -07:00
|
|
|
if (type == TYPEMAP_TYPE_ANY) {
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("any ");)
|
2008-07-07 17:21:54 -07:00
|
|
|
return true;
|
2008-07-09 17:09:22 -07:00
|
|
|
}
|
2008-07-07 01:05:53 -07:00
|
|
|
if (type == JSVAL_INT) {
|
|
|
|
jsint i;
|
|
|
|
if (JSVAL_IS_INT(v))
|
|
|
|
*(jsint*)slot = JSVAL_TO_INT(v);
|
2008-07-10 21:23:32 -07:00
|
|
|
else if (JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_INT(*JSVAL_TO_DOUBLE(v), i))
|
2008-07-07 01:05:53 -07:00
|
|
|
*(jsint*)slot = i;
|
2008-07-10 21:23:32 -07:00
|
|
|
else {
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("int != tag%lu(value=%lu) ", JSVAL_TAG(v), v);)
|
2008-07-19 00:27:45 -07:00
|
|
|
return false;
|
2008-07-10 21:23:32 -07:00
|
|
|
}
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("int<%d> ", *(jsint*)slot);)
|
2008-07-07 01:05:53 -07:00
|
|
|
return true;
|
2008-07-06 15:55:04 -07:00
|
|
|
}
|
2008-07-07 01:05:53 -07:00
|
|
|
if (type == JSVAL_DOUBLE) {
|
|
|
|
jsdouble d;
|
|
|
|
if (JSVAL_IS_INT(v))
|
|
|
|
d = JSVAL_TO_INT(v);
|
|
|
|
else if (JSVAL_IS_DOUBLE(v))
|
|
|
|
d = *JSVAL_TO_DOUBLE(v);
|
2008-07-10 21:23:32 -07:00
|
|
|
else {
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("double != tag%lu ", JSVAL_TAG(v));)
|
2008-07-19 00:27:45 -07:00
|
|
|
return false;
|
2008-07-10 21:23:32 -07:00
|
|
|
}
|
2008-07-07 01:05:53 -07:00
|
|
|
*(jsdouble*)slot = d;
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("double<%g> ", d);)
|
2008-07-07 01:05:53 -07:00
|
|
|
return true;
|
2008-07-07 02:21:04 -07:00
|
|
|
}
|
2008-07-10 21:23:32 -07:00
|
|
|
if (JSVAL_TAG(v) != type) {
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("%d != tag%lu ", type, JSVAL_TAG(v));)
|
2008-07-15 06:07:54 -07:00
|
|
|
ABORT_TRACE("type mismatch");
|
2008-07-10 21:23:32 -07:00
|
|
|
}
|
2008-07-06 15:55:04 -07:00
|
|
|
switch (JSVAL_TAG(v)) {
|
2008-07-10 21:55:09 -07:00
|
|
|
case JSVAL_BOOLEAN:
|
2008-06-29 20:56:06 -07:00
|
|
|
*(bool*)slot = JSVAL_TO_BOOLEAN(v);
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("boolean<%d> ", *(bool*)slot);)
|
2008-07-02 02:53:24 -07:00
|
|
|
break;
|
2008-07-10 21:55:09 -07:00
|
|
|
case JSVAL_STRING:
|
2008-07-02 02:53:24 -07:00
|
|
|
*(JSString**)slot = JSVAL_TO_STRING(v);
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("string<%p> ", *(JSString**)slot);)
|
2008-07-02 02:53:24 -07:00
|
|
|
break;
|
2008-07-10 21:55:09 -07:00
|
|
|
default:
|
2008-07-09 17:09:22 -07:00
|
|
|
JS_ASSERT(JSVAL_IS_OBJECT(v));
|
|
|
|
*(JSObject**)slot = JSVAL_TO_OBJECT(v);
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("object<%p:%s> ", JSVAL_TO_OBJECT(v),
|
2008-07-10 21:55:09 -07:00
|
|
|
JSVAL_IS_NULL(v)
|
|
|
|
? "null"
|
|
|
|
: STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v))->name);)
|
2008-06-29 20:56:06 -07:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-02 02:53:24 -07:00
|
|
|
/* Box a value from the native stack back into the jsval format. Integers
|
|
|
|
that are too large to fit into a jsval are automatically boxed into
|
|
|
|
heap-allocated doubles. */
|
2008-07-05 10:41:35 -07:00
|
|
|
static bool
|
2008-07-07 15:15:56 -07:00
|
|
|
box_jsval(JSContext* cx, jsval& v, uint8 t, double* slot)
|
2008-06-29 23:02:22 -07:00
|
|
|
{
|
2008-07-07 17:21:54 -07:00
|
|
|
jsuint type = TYPEMAP_GET_TYPE(t);
|
2008-07-09 17:09:22 -07:00
|
|
|
if (type == TYPEMAP_TYPE_ANY) {
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("any ");)
|
2008-07-07 17:21:54 -07:00
|
|
|
return true;
|
2008-07-09 17:09:22 -07:00
|
|
|
}
|
2008-07-07 01:37:40 -07:00
|
|
|
jsint i;
|
2008-07-06 15:55:04 -07:00
|
|
|
jsdouble d;
|
2008-07-07 17:21:54 -07:00
|
|
|
switch (type) {
|
2008-07-05 10:41:35 -07:00
|
|
|
case JSVAL_BOOLEAN:
|
2008-07-07 15:15:56 -07:00
|
|
|
v = BOOLEAN_TO_JSVAL(*(bool*)slot);
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("boolean<%d> ", *(bool*)slot);)
|
2008-07-02 14:38:12 -07:00
|
|
|
break;
|
2008-07-05 10:41:35 -07:00
|
|
|
case JSVAL_INT:
|
2008-07-07 01:37:40 -07:00
|
|
|
i = *(jsint*)slot;
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("int<%d> ", i);)
|
2008-07-07 01:37:40 -07:00
|
|
|
store_int:
|
2008-07-06 15:55:04 -07:00
|
|
|
if (INT_FITS_IN_JSVAL(i)) {
|
2008-07-07 15:15:56 -07:00
|
|
|
v = INT_TO_JSVAL(i);
|
2008-07-06 15:55:04 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
d = (jsdouble)i;
|
2008-07-07 01:37:40 -07:00
|
|
|
goto store_double;
|
2008-07-05 10:41:35 -07:00
|
|
|
case JSVAL_DOUBLE:
|
2008-07-06 15:55:04 -07:00
|
|
|
d = *slot;
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("double<%g> ", d);)
|
2008-07-07 01:37:40 -07:00
|
|
|
if (JSDOUBLE_IS_INT(d, i))
|
|
|
|
goto store_int;
|
|
|
|
store_double:
|
2008-07-10 13:24:49 -07:00
|
|
|
/* Its safe to trigger the GC here since we rooted all strings/objects and all the
|
|
|
|
doubles we already processed. */
|
2008-07-07 15:15:56 -07:00
|
|
|
return js_NewDoubleInRootedValue(cx, d, &v);
|
2008-07-05 10:41:35 -07:00
|
|
|
case JSVAL_STRING:
|
2008-07-07 15:15:56 -07:00
|
|
|
v = STRING_TO_JSVAL(*(JSString**)slot);
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("string<%p> ", *(JSString**)slot);)
|
2008-07-02 14:38:12 -07:00
|
|
|
break;
|
2008-07-05 10:41:35 -07:00
|
|
|
default:
|
2008-06-29 23:02:22 -07:00
|
|
|
JS_ASSERT(t == JSVAL_OBJECT);
|
2008-07-07 15:15:56 -07:00
|
|
|
v = OBJECT_TO_JSVAL(*(JSObject**)slot);
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("object<%p> ", *(JSObject**)slot);)
|
2008-07-02 14:38:12 -07:00
|
|
|
break;
|
2008-06-29 23:02:22 -07:00
|
|
|
}
|
2008-07-02 14:38:12 -07:00
|
|
|
return true;
|
2008-06-29 23:02:22 -07:00
|
|
|
}
|
|
|
|
|
2008-07-07 02:21:04 -07:00
|
|
|
/* Attempt to unbox the given JS frame into a native frame, checking along the way that the
|
2008-07-06 15:55:04 -07:00
|
|
|
supplied typemap holds. */
|
2008-07-02 17:19:07 -07:00
|
|
|
static bool
|
2008-07-21 16:19:38 -07:00
|
|
|
unbox(JSContext* cx, unsigned ngslots, uint16* gslots, unsigned callDepth,
|
|
|
|
uint8* map, double* native)
|
2008-06-29 20:56:06 -07:00
|
|
|
{
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("unbox native@%p ", native);)
|
2008-07-10 13:24:49 -07:00
|
|
|
double* np = native;
|
|
|
|
uint8* mp = map;
|
2008-07-21 16:19:38 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, ngslots, gslots, callDepth,
|
2008-07-13 21:14:34 -07:00
|
|
|
if (!unbox_jsval(*vp, *mp, np))
|
2008-06-29 20:56:06 -07:00
|
|
|
return false;
|
2008-07-10 13:24:49 -07:00
|
|
|
++mp; ++np;
|
2008-07-08 16:29:23 -07:00
|
|
|
);
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("\n");)
|
2008-06-29 20:56:06 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-07 02:21:04 -07:00
|
|
|
/* Box the given native frame into a JS frame. This only fails due to a hard error
|
2008-07-06 15:55:04 -07:00
|
|
|
(out of memory for example). */
|
2008-07-02 17:19:07 -07:00
|
|
|
static bool
|
2008-07-21 16:19:38 -07:00
|
|
|
box(JSContext* cx, unsigned ngslots, uint16* gslots, unsigned callDepth,
|
|
|
|
uint8* map, double* native)
|
2008-06-29 23:02:22 -07:00
|
|
|
{
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("box native@%p ", native);)
|
2008-07-10 13:24:49 -07:00
|
|
|
double* np = native;
|
|
|
|
uint8* mp = map;
|
|
|
|
/* Root all string and object references first (we don't need to call the GC for this). */
|
2008-07-21 16:19:38 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, ngslots, gslots, callDepth,
|
2008-07-13 21:14:34 -07:00
|
|
|
if ((*mp == JSVAL_STRING || *mp == JSVAL_OBJECT) && !box_jsval(cx, *vp, *mp, np))
|
2008-06-29 23:02:22 -07:00
|
|
|
return false;
|
2008-07-10 13:24:49 -07:00
|
|
|
++mp; ++np
|
|
|
|
);
|
|
|
|
/* Now do this again but this time for all values (properly quicker than actually checking
|
|
|
|
the type and excluding strings and objects). The GC might kick in when we store doubles,
|
|
|
|
but everything is rooted now (all strings/objects and all doubles we already boxed). */
|
|
|
|
np = native;
|
|
|
|
mp = map;
|
2008-07-21 16:19:38 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, ngslots, gslots, callDepth,
|
2008-07-13 21:14:34 -07:00
|
|
|
if (!box_jsval(cx, *vp, *mp, np))
|
2008-07-10 13:24:49 -07:00
|
|
|
return false;
|
|
|
|
++mp; ++np
|
2008-07-08 16:29:23 -07:00
|
|
|
);
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(printf("\n");)
|
2008-06-29 23:02:22 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-06-30 09:36:10 -07:00
|
|
|
/* Emit load instructions onto the trace that read the initial stack state. */
|
2008-07-05 10:41:35 -07:00
|
|
|
void
|
2008-07-22 17:24:29 -07:00
|
|
|
TraceRecorder::import(LIns* base, unsigned slot, jsval* p, uint8& t,
|
|
|
|
const char *prefix, int index, jsuword *localNames)
|
2008-06-26 22:19:11 -07:00
|
|
|
{
|
2008-07-07 19:20:40 -07:00
|
|
|
JS_ASSERT(TYPEMAP_GET_TYPE(t) != TYPEMAP_TYPE_ANY);
|
2008-07-07 00:10:22 -07:00
|
|
|
LIns* ins;
|
|
|
|
/* Calculate the offset of this slot relative to the entry stack-pointer value of the
|
|
|
|
native stack. Arguments and locals are to the left of the stack pointer (offset
|
|
|
|
less than 0). Stack cells start at offset 0. Ed defined the semantics of the stack,
|
|
|
|
not me, so don't blame the messenger. */
|
2008-07-22 17:24:29 -07:00
|
|
|
ptrdiff_t offset = -treeInfo->nativeStackBase + slot*sizeof(double) + 8;
|
2008-07-07 01:05:53 -07:00
|
|
|
if (TYPEMAP_GET_TYPE(t) == JSVAL_INT) { /* demoted */
|
|
|
|
JS_ASSERT(isInt32(*p));
|
2008-07-07 00:10:22 -07:00
|
|
|
/* Ok, we have a valid demotion attempt pending, so insert an integer
|
|
|
|
read and promote it to double since all arithmetic operations expect
|
2008-07-07 02:21:04 -07:00
|
|
|
to see doubles on entry. The first op to use this slot will emit a
|
2008-07-07 00:10:22 -07:00
|
|
|
f2i cast which will cancel out the i2f we insert here. */
|
2008-07-22 17:54:04 -07:00
|
|
|
ins = lir->insLoadi(base, offset);
|
|
|
|
stackTracker.set(p, ins);
|
|
|
|
ins = lir->ins1(LIR_i2f, ins);
|
2008-07-07 00:10:22 -07:00
|
|
|
} else {
|
|
|
|
JS_ASSERT(isNumber(*p) == (TYPEMAP_GET_TYPE(t) == JSVAL_DOUBLE));
|
2008-07-22 17:24:29 -07:00
|
|
|
ins = lir->insLoad(t == JSVAL_DOUBLE ? LIR_ldq : LIR_ld, base, offset);
|
2008-07-22 17:54:04 -07:00
|
|
|
stackTracker.set(p, ins);
|
2008-07-07 00:10:22 -07:00
|
|
|
}
|
2008-07-01 05:06:02 -07:00
|
|
|
tracker.set(p, ins);
|
|
|
|
#ifdef DEBUG
|
2008-07-17 15:09:48 -07:00
|
|
|
char name[64];
|
2008-07-10 16:55:37 -07:00
|
|
|
JS_ASSERT(strlen(prefix) < 10);
|
2008-07-17 15:09:48 -07:00
|
|
|
if (!strcmp(prefix, "argv")) {
|
|
|
|
JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(localNames[index]);
|
|
|
|
JS_snprintf(name, sizeof name, "$%s.%s", js_AtomToPrintableString(cx, cx->fp->fun->atom),
|
|
|
|
js_AtomToPrintableString(cx, atom));
|
|
|
|
} else if (!strcmp(prefix, "vars")) {
|
|
|
|
JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(localNames[index + cx->fp->fun->nargs]);
|
|
|
|
JS_snprintf(name, sizeof name, "$%s.%s", js_AtomToPrintableString(cx, cx->fp->fun->atom),
|
|
|
|
js_AtomToPrintableString(cx, atom));
|
|
|
|
} else {
|
|
|
|
JS_snprintf(name, sizeof name, "$%s%d", prefix, index);
|
|
|
|
}
|
2008-07-17 02:00:23 -07:00
|
|
|
addName(ins, name);
|
2008-07-17 15:09:48 -07:00
|
|
|
|
2008-07-10 16:55:37 -07:00
|
|
|
static const char* typestr[] = {
|
2008-07-15 10:26:15 -07:00
|
|
|
"object", "int", "double", "3", "string", "5", "boolean", "any"
|
|
|
|
};
|
2008-07-14 17:52:38 -07:00
|
|
|
printf("import vp=%p name=%s type=%s flags=%d\n", p, name, typestr[t & 7], t >> 3);
|
2008-07-01 05:06:02 -07:00
|
|
|
#endif
|
2008-06-26 22:19:11 -07:00
|
|
|
}
|
|
|
|
|
2008-07-21 12:57:02 -07:00
|
|
|
/* Update the tracker, then issue a write back store. */
|
2008-07-05 10:41:35 -07:00
|
|
|
void
|
2008-07-21 12:57:02 -07:00
|
|
|
TraceRecorder::set(jsval* p, LIns* i, bool initializing)
|
2008-06-26 22:41:10 -07:00
|
|
|
{
|
2008-07-21 12:57:02 -07:00
|
|
|
JS_ASSERT(initializing || tracker.has(p));
|
2008-06-30 09:36:10 -07:00
|
|
|
tracker.set(p, i);
|
2008-07-21 15:01:47 -07:00
|
|
|
/* Sink all type casts targeting the stack into the side exit by simply storing the original
|
|
|
|
(uncasted) value. Each guard generates the side exit map based on the types of the
|
|
|
|
last stores to every stack location, so its safe to not perform them on-trace. */
|
|
|
|
if (isPromoteInt(i))
|
|
|
|
i = ::demote(lir, i);
|
2008-07-22 17:54:04 -07:00
|
|
|
/* If we are writing to this location for the first time, calculate the offset into the
|
|
|
|
native frame manually, otherwise just look up the last load or store associated with
|
|
|
|
the same source address (p) and use the same offset/base. */
|
|
|
|
if (initializing) {
|
|
|
|
stackTracker.set(p, lir->insStorei(i, lirbuf->sp,
|
|
|
|
-treeInfo->nativeStackBase + nativeFrameOffset(p) + 8));
|
|
|
|
} else {
|
|
|
|
LIns* q = stackTracker.get(p);
|
|
|
|
if (q->isop(LIR_ld) || q->isop(LIR_ldq)) {
|
|
|
|
JS_ASSERT(q->oprnd1() == lirbuf->sp);
|
|
|
|
lir->insStorei(i, q->oprnd1(), q->oprnd2()->constval());
|
|
|
|
} else {
|
|
|
|
JS_ASSERT(q->isop(LIR_sti) || q->isop(LIR_stqi));
|
|
|
|
JS_ASSERT(q->oprnd2() == lirbuf->sp);
|
|
|
|
lir->insStorei(i, q->oprnd2(), q->immdisp());
|
|
|
|
}
|
|
|
|
}
|
2008-06-26 22:41:10 -07:00
|
|
|
}
|
|
|
|
|
2008-07-05 10:41:35 -07:00
|
|
|
LIns*
|
2008-07-09 00:29:23 -07:00
|
|
|
TraceRecorder::get(jsval* p)
|
2008-06-26 22:41:10 -07:00
|
|
|
{
|
|
|
|
return tracker.get(p);
|
|
|
|
}
|
|
|
|
|
2008-07-01 19:43:10 -07:00
|
|
|
SideExit*
|
|
|
|
TraceRecorder::snapshot()
|
|
|
|
{
|
|
|
|
/* generate the entry map and stash it in the trace */
|
2008-07-21 14:55:41 -07:00
|
|
|
unsigned slots = nativeFrameSlots(treeInfo->ngslots, callDepth, cx->fp, *cx->fp->regs);
|
2008-07-02 17:19:07 -07:00
|
|
|
trackNativeFrameUse(slots);
|
2008-07-21 15:09:19 -07:00
|
|
|
/* reserve space for the type map */
|
2008-07-08 17:16:51 -07:00
|
|
|
LIns* data = lir_buf_writer->skip(slots * sizeof(uint8));
|
2008-07-01 19:43:10 -07:00
|
|
|
/* setup side exit structure */
|
|
|
|
memset(&exit, 0, sizeof(exit));
|
|
|
|
exit.from = fragment;
|
2008-07-05 19:15:00 -07:00
|
|
|
exit.calldepth = getCallDepth();
|
2008-07-18 16:21:22 -07:00
|
|
|
exit.ip_adj = cx->fp->regs->pc - entryRegs->pc;
|
|
|
|
exit.sp_adj = (cx->fp->regs->sp - entryRegs->sp) * sizeof(double);
|
2008-07-14 19:12:50 -07:00
|
|
|
exit.rp_adj = exit.calldepth;
|
2008-07-21 15:09:19 -07:00
|
|
|
uint8* m = exit.typeMap = (uint8 *)data->payload();
|
|
|
|
TreeInfo* ti = (TreeInfo*)fragment->root->vmprivate;
|
|
|
|
/* Determine the type of a store by looking at the current type of the actual value the
|
|
|
|
interpreter is using. For numbers we have to check what kind of store we used last
|
|
|
|
(integer or double) to figure out what the side exit show reflect in its typemap. */
|
2008-07-21 16:19:38 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, ti->ngslots, ti->gslots, callDepth,
|
2008-07-21 15:09:19 -07:00
|
|
|
LIns* i = get(vp);
|
|
|
|
*m++ = isNumber(*vp)
|
|
|
|
? (isPromoteInt(i) ? JSVAL_INT : JSVAL_DOUBLE)
|
|
|
|
: JSVAL_TAG(*vp);
|
|
|
|
);
|
2008-07-01 19:43:10 -07:00
|
|
|
return &exit;
|
|
|
|
}
|
|
|
|
|
2008-07-17 02:00:23 -07:00
|
|
|
LIns*
|
2008-07-04 13:23:42 -07:00
|
|
|
TraceRecorder::guard(bool expected, LIns* cond)
|
2008-06-27 00:22:16 -07:00
|
|
|
{
|
2008-07-17 02:00:23 -07:00
|
|
|
return lir->insGuard(expected ? LIR_xf : LIR_xt,
|
|
|
|
cond,
|
|
|
|
snapshot());
|
|
|
|
}
|
|
|
|
|
2008-07-05 23:21:53 -07:00
|
|
|
bool
|
2008-07-06 22:35:19 -07:00
|
|
|
TraceRecorder::checkType(jsval& v, uint8& t)
|
2008-07-05 23:21:53 -07:00
|
|
|
{
|
2008-07-08 01:30:29 -07:00
|
|
|
if (t == TYPEMAP_TYPE_ANY) /* ignore unused slots */
|
|
|
|
return true;
|
2008-07-06 22:35:19 -07:00
|
|
|
if (isNumber(v)) {
|
|
|
|
/* Initially we start out all numbers as JSVAL_DOUBLE in the type map. If we still
|
2008-07-07 02:21:04 -07:00
|
|
|
see a number in v, its a valid trace but we might want to ask to demote the
|
2008-07-06 22:35:19 -07:00
|
|
|
slot if we know or suspect that its integer. */
|
2008-07-06 17:32:21 -07:00
|
|
|
LIns* i = get(&v);
|
2008-07-07 01:05:53 -07:00
|
|
|
if (TYPEMAP_GET_TYPE(t) == JSVAL_DOUBLE) {
|
2008-07-08 18:12:22 -07:00
|
|
|
if (isInt32(v) && !TYPEMAP_GET_FLAG(t, TYPEMAP_FLAG_DONT_DEMOTE)) {
|
2008-07-06 22:35:19 -07:00
|
|
|
/* If the value associated with v via the tracker comes from a i2f operation,
|
|
|
|
we can be sure it will always be an int. If we see INCVAR, we similarly
|
|
|
|
speculate that the result will be int, even though this is not
|
|
|
|
guaranteed and this might cause the entry map to mismatch and thus
|
|
|
|
the trace never to be entered. */
|
2008-07-07 02:21:04 -07:00
|
|
|
if (i->isop(LIR_i2f) ||
|
|
|
|
(i->isop(LIR_fadd) && i->oprnd2()->isconstq() &&
|
2008-07-06 22:35:19 -07:00
|
|
|
fabs(i->oprnd2()->constvalf()) == 1.0)) {
|
|
|
|
#ifdef DEBUG
|
2008-07-14 17:52:38 -07:00
|
|
|
printf("demoting type of an entry slot #%ld, triggering re-compilation\n",
|
2008-07-06 22:35:19 -07:00
|
|
|
nativeFrameOffset(&v));
|
2008-07-07 02:21:04 -07:00
|
|
|
#endif
|
2008-07-07 00:10:22 -07:00
|
|
|
JS_ASSERT(!TYPEMAP_GET_FLAG(t, TYPEMAP_FLAG_DEMOTE) ||
|
|
|
|
TYPEMAP_GET_FLAG(t, TYPEMAP_FLAG_DONT_DEMOTE));
|
2008-07-06 22:35:19 -07:00
|
|
|
TYPEMAP_SET_FLAG(t, TYPEMAP_FLAG_DEMOTE);
|
2008-07-07 01:05:53 -07:00
|
|
|
TYPEMAP_SET_TYPE(t, JSVAL_INT);
|
2008-07-17 10:22:40 -07:00
|
|
|
AUDIT(slotDemoted);
|
2008-07-06 22:35:19 -07:00
|
|
|
recompileFlag = true;
|
|
|
|
return true; /* keep going */
|
|
|
|
}
|
|
|
|
}
|
2008-07-07 02:21:04 -07:00
|
|
|
return true;
|
|
|
|
}
|
2008-07-06 22:35:19 -07:00
|
|
|
/* Looks like we are compiling an integer slot. The recorder always casts to doubles
|
|
|
|
after each integer operation, or emits an operation that produces a double right
|
|
|
|
away. If we started with an integer, we must arrive here pointing at a i2f cast.
|
|
|
|
If not, than demoting the slot didn't work out. Flag the slot to be not
|
|
|
|
demoted again. */
|
2008-07-07 01:05:53 -07:00
|
|
|
JS_ASSERT(TYPEMAP_GET_TYPE(t) == JSVAL_INT &&
|
2008-07-07 00:10:22 -07:00
|
|
|
TYPEMAP_GET_FLAG(t, TYPEMAP_FLAG_DEMOTE) &&
|
|
|
|
!TYPEMAP_GET_FLAG(t, TYPEMAP_FLAG_DONT_DEMOTE));
|
2008-07-06 22:35:19 -07:00
|
|
|
if (!i->isop(LIR_i2f)) {
|
2008-07-17 10:22:40 -07:00
|
|
|
AUDIT(slotPromoted);
|
2008-07-07 02:21:04 -07:00
|
|
|
#ifdef DEBUG
|
2008-07-14 17:52:38 -07:00
|
|
|
printf("demoting type of a slot #%ld failed, locking it and re-compiling\n",
|
2008-07-06 22:35:19 -07:00
|
|
|
nativeFrameOffset(&v));
|
|
|
|
#endif
|
|
|
|
TYPEMAP_SET_FLAG(t, TYPEMAP_FLAG_DONT_DEMOTE);
|
2008-07-07 01:05:53 -07:00
|
|
|
TYPEMAP_SET_TYPE(t, JSVAL_DOUBLE);
|
2008-07-06 22:35:19 -07:00
|
|
|
recompileFlag = true;
|
|
|
|
return true; /* keep going, recompileFlag will trigger error when we are done with
|
|
|
|
all the slots */
|
2008-07-07 02:21:04 -07:00
|
|
|
|
2008-07-06 17:32:21 -07:00
|
|
|
}
|
2008-07-06 22:35:19 -07:00
|
|
|
JS_ASSERT(isInt32(v));
|
|
|
|
/* Looks like we got the final LIR_i2f as we expected. Overwrite the value in that
|
|
|
|
slot with the argument of i2f since we want the integer store to flow along
|
|
|
|
the loop edge, not the casted value. */
|
|
|
|
set(&v, i->oprnd1());
|
2008-07-05 23:21:53 -07:00
|
|
|
return true;
|
2008-07-06 17:32:21 -07:00
|
|
|
}
|
2008-07-06 22:35:19 -07:00
|
|
|
/* for non-number types we expect a precise match of the type */
|
2008-07-07 20:51:56 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (JSVAL_TAG(v) != TYPEMAP_GET_TYPE(t)) {
|
|
|
|
printf("Type mismatch: val %c, map %c ", "OID?S?B"[JSVAL_TAG(v)],
|
|
|
|
"OID?S?B"[t]);
|
|
|
|
}
|
|
|
|
#endif
|
2008-07-06 22:35:19 -07:00
|
|
|
return JSVAL_TAG(v) == TYPEMAP_GET_TYPE(t);
|
2008-07-05 23:21:53 -07:00
|
|
|
}
|
|
|
|
|
2008-07-06 22:35:19 -07:00
|
|
|
/* Make sure that the current values in the given stack frame and all stack frames
|
|
|
|
up and including entryFrame are type-compatible with the entry map. */
|
2008-07-05 23:21:53 -07:00
|
|
|
bool
|
2008-07-21 13:21:00 -07:00
|
|
|
TraceRecorder::verifyTypeStability(uint8* m)
|
2008-07-05 23:21:53 -07:00
|
|
|
{
|
2008-07-21 16:19:38 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, treeInfo->ngslots, treeInfo->gslots, callDepth,
|
2008-07-13 21:14:34 -07:00
|
|
|
if (!checkType(*vp, *m))
|
2008-07-05 23:21:53 -07:00
|
|
|
return false;
|
2008-07-08 16:29:23 -07:00
|
|
|
++m
|
|
|
|
);
|
2008-07-06 22:35:19 -07:00
|
|
|
return !recompileFlag;
|
2008-07-05 23:21:53 -07:00
|
|
|
}
|
|
|
|
|
2008-06-27 18:06:50 -07:00
|
|
|
void
|
2008-07-18 14:11:01 -07:00
|
|
|
TraceRecorder::closeLoop(Fragmento* fragmento)
|
2008-06-27 18:06:50 -07:00
|
|
|
{
|
2008-07-21 13:21:00 -07:00
|
|
|
if (!verifyTypeStability(treeInfo->typeMap)) {
|
2008-07-17 10:22:40 -07:00
|
|
|
AUDIT(unstableLoopVariable);
|
|
|
|
debug_only(printf("Trace rejected: unstable loop variables.\n");)
|
2008-07-02 15:31:40 -07:00
|
|
|
return;
|
2008-07-02 15:14:43 -07:00
|
|
|
}
|
2008-07-18 10:33:17 -07:00
|
|
|
SideExit *exit = snapshot();
|
2008-07-18 14:11:01 -07:00
|
|
|
exit->target = fragment->root;
|
|
|
|
if (fragment == fragment->root) {
|
2008-07-18 10:33:17 -07:00
|
|
|
fragment->lastIns = lir->insGuard(LIR_loop, lir->insImm(1), exit);
|
|
|
|
} else {
|
|
|
|
fragment->lastIns = lir->insGuard(LIR_x, lir->insImm(1), exit);
|
2008-07-17 17:12:28 -07:00
|
|
|
}
|
2008-06-27 18:06:50 -07:00
|
|
|
compile(fragmento->assm(), fragment);
|
2008-07-18 14:11:01 -07:00
|
|
|
if (anchor) {
|
2008-07-20 14:28:56 -07:00
|
|
|
fragment->addLink(anchor);
|
2008-07-17 17:12:28 -07:00
|
|
|
fragmento->assm()->patch(anchor);
|
2008-07-18 14:11:01 -07:00
|
|
|
}
|
2008-07-17 16:20:13 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
char* label;
|
2008-07-19 00:15:22 -07:00
|
|
|
asprintf(&label, "%s:%u", cx->fp->script->filename,
|
|
|
|
js_PCToLineNumber(cx, cx->fp->script, cx->fp->regs->pc));
|
2008-07-17 16:20:13 -07:00
|
|
|
fragmento->labels->add(fragment, sizeof(Fragment), 0, label);
|
2008-07-19 00:15:22 -07:00
|
|
|
#endif
|
2008-06-27 18:06:50 -07:00
|
|
|
}
|
|
|
|
|
2008-07-08 17:16:51 -07:00
|
|
|
int
|
|
|
|
nanojit::StackFilter::getTop(LInsp guard)
|
|
|
|
{
|
2008-07-16 14:21:31 -07:00
|
|
|
if (sp == frag->lirbuf->sp)
|
2008-07-14 19:12:50 -07:00
|
|
|
return guard->exit()->sp_adj + 8;
|
2008-07-16 14:21:31 -07:00
|
|
|
JS_ASSERT(sp == frag->lirbuf->rp);
|
2008-07-14 19:12:50 -07:00
|
|
|
return guard->exit()->rp_adj + 4;
|
2008-07-08 17:16:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined NJ_VERBOSE
|
|
|
|
void
|
|
|
|
nanojit::LirNameMap::formatGuard(LIns *i, char *out)
|
|
|
|
{
|
|
|
|
uint32_t ip;
|
|
|
|
SideExit *x;
|
|
|
|
|
|
|
|
x = (SideExit *)i->exit();
|
|
|
|
ip = intptr_t(x->from->ip) + x->ip_adj;
|
2008-07-08 18:12:22 -07:00
|
|
|
sprintf(out,
|
2008-07-14 19:12:50 -07:00
|
|
|
"%s: %s %s -> %s sp%+ld rp%+ld",
|
2008-07-08 17:16:51 -07:00
|
|
|
formatRef(i),
|
|
|
|
lirNames[i->opcode()],
|
|
|
|
i->oprnd1()->isCond() ? formatRef(i->oprnd1()) : "",
|
|
|
|
labels->format((void *)ip),
|
2008-07-14 19:12:50 -07:00
|
|
|
x->sp_adj,
|
|
|
|
x->rp_adj
|
2008-07-08 17:16:51 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
|
|
|
nanojit::Assembler::initGuardRecord(LIns *guard, GuardRecord *rec)
|
|
|
|
{
|
|
|
|
SideExit *exit;
|
|
|
|
|
|
|
|
exit = guard->exit();
|
2008-07-17 16:20:13 -07:00
|
|
|
rec->guard = guard;
|
2008-07-08 17:16:51 -07:00
|
|
|
rec->calldepth = exit->calldepth;
|
|
|
|
rec->exit = exit;
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(rec->sid = exit->sid);
|
2008-07-08 17:16:51 -07:00
|
|
|
}
|
|
|
|
|
2008-07-08 18:12:22 -07:00
|
|
|
void
|
2008-07-08 17:16:51 -07:00
|
|
|
nanojit::Assembler::asm_bailout(LIns *guard, Register state)
|
|
|
|
{
|
2008-07-18 15:35:59 -07:00
|
|
|
/* we adjust ip/sp/rp when exiting from the tree in the recovery code */
|
2008-07-08 17:16:51 -07:00
|
|
|
}
|
|
|
|
|
2008-07-05 10:41:35 -07:00
|
|
|
void
|
2008-07-04 00:51:30 -07:00
|
|
|
js_DeleteRecorder(JSContext* cx)
|
|
|
|
{
|
|
|
|
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
|
|
|
|
delete tm->recorder;
|
|
|
|
tm->recorder = NULL;
|
2008-07-22 17:24:29 -07:00
|
|
|
#ifdef MOZ_SHARK
|
|
|
|
JS_StopChudRemote();
|
|
|
|
#endif
|
2008-06-27 20:58:06 -07:00
|
|
|
}
|
|
|
|
|
2008-07-17 16:20:13 -07:00
|
|
|
bool
|
2008-07-17 17:12:28 -07:00
|
|
|
js_StartRecorder(JSContext* cx, GuardRecord* anchor, Fragment* f, uint8* typeMap)
|
2008-07-17 16:20:13 -07:00
|
|
|
{
|
2008-07-22 17:24:29 -07:00
|
|
|
#ifdef MOZ_SHARK
|
|
|
|
JS_StartChudRemote();
|
|
|
|
#endif
|
2008-07-17 16:20:13 -07:00
|
|
|
/* start recording if no exception during construction */
|
2008-07-17 17:12:28 -07:00
|
|
|
JS_TRACE_MONITOR(cx).recorder = new (&gc) TraceRecorder(cx, anchor, f, typeMap);
|
2008-07-17 16:20:13 -07:00
|
|
|
if (cx->throwing) {
|
2008-07-20 12:42:19 -07:00
|
|
|
js_AbortRecording(cx, NULL, "setting up recorder failed");
|
2008-07-17 16:20:13 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-17 14:58:09 -07:00
|
|
|
static bool
|
|
|
|
js_IsLoopExit(JSContext* cx, JSScript* script, jsbytecode* pc)
|
|
|
|
{
|
2008-07-17 16:20:13 -07:00
|
|
|
switch (*pc) {
|
2008-07-20 14:54:16 -07:00
|
|
|
case JSOP_LT:
|
|
|
|
case JSOP_GT:
|
|
|
|
case JSOP_LE:
|
|
|
|
case JSOP_GE:
|
|
|
|
case JSOP_NE:
|
|
|
|
case JSOP_EQ:
|
|
|
|
JS_ASSERT(js_CodeSpec[*pc].length == 1);
|
|
|
|
pc++;
|
|
|
|
/* FALL THROUGH */
|
2008-07-20 16:11:52 -07:00
|
|
|
|
2008-07-19 10:52:24 -07:00
|
|
|
case JSOP_IFNE:
|
2008-07-20 16:11:52 -07:00
|
|
|
case JSOP_IFNEX:
|
|
|
|
return GET_JUMP_OFFSET(pc) < 0;
|
|
|
|
|
2008-07-20 14:54:16 -07:00
|
|
|
default:;
|
2008-07-17 14:58:09 -07:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-07-22 18:31:44 -07:00
|
|
|
#define HOTLOOP 2
|
2008-07-20 14:28:56 -07:00
|
|
|
#define HOTEXIT 0
|
2008-07-05 19:15:00 -07:00
|
|
|
|
2008-07-04 00:51:30 -07:00
|
|
|
bool
|
2008-07-20 12:42:19 -07:00
|
|
|
js_LoopEdge(JSContext* cx, jsbytecode* oldpc)
|
2008-06-11 20:22:00 -07:00
|
|
|
{
|
2008-06-22 23:42:54 -07:00
|
|
|
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
|
2008-07-05 10:41:35 -07:00
|
|
|
|
2008-07-10 05:05:25 -07:00
|
|
|
/* is the recorder currently active? */
|
|
|
|
if (tm->recorder) {
|
2008-07-17 01:29:41 -07:00
|
|
|
TraceRecorder* r = tm->recorder;
|
2008-07-08 18:12:22 -07:00
|
|
|
#ifdef JS_THREADSAFE
|
2008-07-10 05:05:25 -07:00
|
|
|
/* XXX should this test not be earlier, to avoid even recording? */
|
2008-07-14 16:40:38 -07:00
|
|
|
if (OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->title.ownercx != cx) {
|
2008-07-08 18:12:22 -07:00
|
|
|
#ifdef DEBUG
|
2008-07-10 05:05:25 -07:00
|
|
|
printf("Global object not owned by this context.\n");
|
2008-07-08 18:12:22 -07:00
|
|
|
#endif
|
2008-07-10 05:05:25 -07:00
|
|
|
return false; /* we stay away from shared global objects */
|
|
|
|
}
|
2008-07-08 18:12:22 -07:00
|
|
|
#endif
|
2008-07-17 17:12:28 -07:00
|
|
|
if (cx->fp->regs->pc == r->getFragment()->root->ip) { /* did we hit the start point? */
|
2008-07-17 10:22:40 -07:00
|
|
|
AUDIT(traceCompleted);
|
2008-07-18 14:11:01 -07:00
|
|
|
r->closeLoop(JS_TRACE_MONITOR(cx).fragmento);
|
2008-07-17 01:29:41 -07:00
|
|
|
js_DeleteRecorder(cx);
|
2008-07-17 10:22:40 -07:00
|
|
|
} else {
|
|
|
|
AUDIT(returnToDifferentLoopHeader);
|
2008-07-20 12:42:19 -07:00
|
|
|
debug_only(printf("loop edge %d -> %d, header %d\n",
|
|
|
|
oldpc - cx->fp->script->code,
|
|
|
|
cx->fp->regs->pc - cx->fp->script->code,
|
|
|
|
(jsbytecode*)r->getFragment()->root->ip - cx->fp->script->code));
|
|
|
|
js_AbortRecording(cx, oldpc, "Loop edge does not return to header");
|
2008-07-17 10:22:40 -07:00
|
|
|
}
|
2008-07-04 00:51:30 -07:00
|
|
|
return false; /* done recording */
|
|
|
|
}
|
2008-07-05 10:41:35 -07:00
|
|
|
|
2008-07-07 02:47:40 -07:00
|
|
|
Fragment* f = tm->fragmento->getLoop(cx->fp->regs->pc);
|
2008-07-04 00:51:30 -07:00
|
|
|
if (!f->code()) {
|
2008-07-20 14:28:56 -07:00
|
|
|
if (++f->hits() >= HOTLOOP) {
|
2008-07-17 13:42:58 -07:00
|
|
|
AUDIT(recorderStarted);
|
|
|
|
f->calldepth = 0;
|
2008-07-17 16:20:13 -07:00
|
|
|
f->root = f;
|
2008-07-17 13:42:58 -07:00
|
|
|
/* allocate space to store the LIR for this tree */
|
|
|
|
if (!f->lirbuf) {
|
|
|
|
f->lirbuf = new (&gc) LirBuffer(tm->fragmento, builtins);
|
2008-07-19 00:15:22 -07:00
|
|
|
#ifdef DEBUG
|
2008-07-17 13:42:58 -07:00
|
|
|
f->lirbuf->names = new (&gc) LirNameMap(&gc, builtins, tm->fragmento->labels);
|
2008-07-16 21:41:03 -07:00
|
|
|
#endif
|
2008-07-17 13:42:58 -07:00
|
|
|
}
|
|
|
|
/* create the tree anchor structure */
|
2008-07-21 12:43:51 -07:00
|
|
|
TreeInfo* ti = (TreeInfo*)f->vmprivate;
|
|
|
|
if (!ti) {
|
2008-07-21 12:41:43 -07:00
|
|
|
/* setup the VM-private treeInfo structure for this fragment */
|
2008-07-21 12:43:51 -07:00
|
|
|
ti = new TreeInfo(); // TODO: deallocate when fragment dies
|
|
|
|
f->vmprivate = ti;
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-17 13:42:58 -07:00
|
|
|
/* create the list of global properties we want to intern */
|
|
|
|
int internableGlobals = findInternableGlobals(cx, cx->fp, NULL);
|
|
|
|
if (internableGlobals < 0)
|
|
|
|
return false;
|
2008-07-21 12:43:51 -07:00
|
|
|
ti->gslots = (uint16*)malloc(sizeof(uint16) * internableGlobals);
|
|
|
|
if ((ti->ngslots = findInternableGlobals(cx, cx->fp, ti->gslots)) < 0)
|
2008-07-17 13:42:58 -07:00
|
|
|
return false;
|
2008-07-21 12:43:51 -07:00
|
|
|
JS_ASSERT(ti->ngslots == (unsigned) internableGlobals);
|
|
|
|
ti->globalShape = OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->shape;
|
2008-07-17 13:42:58 -07:00
|
|
|
|
|
|
|
/* determine the native frame layout at the entry point */
|
2008-07-21 12:43:51 -07:00
|
|
|
unsigned entryNativeFrameSlots = nativeFrameSlots(ti->ngslots,
|
2008-07-21 14:55:41 -07:00
|
|
|
0/*callDepth*/, cx->fp, *cx->fp->regs);
|
2008-07-21 12:43:51 -07:00
|
|
|
ti->entryRegs = *cx->fp->regs;
|
|
|
|
ti->entryNativeFrameSlots = entryNativeFrameSlots;
|
|
|
|
ti->nativeStackBase = (entryNativeFrameSlots -
|
2008-07-17 13:42:58 -07:00
|
|
|
(cx->fp->regs->sp - cx->fp->spbase)) * sizeof(double);
|
2008-07-21 12:43:51 -07:00
|
|
|
ti->maxNativeFrameSlots = entryNativeFrameSlots;
|
|
|
|
ti->maxCallDepth = 0;
|
2008-07-17 13:42:58 -07:00
|
|
|
}
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-17 13:42:58 -07:00
|
|
|
/* capture the entry type map if we don't have one yet (or we threw it away) */
|
2008-07-21 12:43:51 -07:00
|
|
|
if (!ti->typeMap) {
|
|
|
|
ti->typeMap = (uint8*)malloc(ti->entryNativeFrameSlots * sizeof(uint8));
|
|
|
|
uint8* m = ti->typeMap;
|
2008-07-17 13:42:58 -07:00
|
|
|
|
|
|
|
/* remember the coerced type of each active slot in the type map */
|
2008-07-21 16:19:38 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, ti->ngslots, ti->gslots, 0/*callDepth*/,
|
2008-07-17 13:42:58 -07:00
|
|
|
*m++ = getCoercedType(*vp)
|
|
|
|
);
|
2008-07-05 23:21:53 -07:00
|
|
|
}
|
2008-07-17 16:20:13 -07:00
|
|
|
/* recording primary trace */
|
2008-07-21 12:43:51 -07:00
|
|
|
return js_StartRecorder(cx, NULL, f, ti->typeMap);
|
2008-07-05 19:15:00 -07:00
|
|
|
}
|
|
|
|
return false;
|
2008-07-04 00:51:30 -07:00
|
|
|
}
|
|
|
|
|
2008-07-17 10:22:40 -07:00
|
|
|
AUDIT(traceTriggered);
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-08 22:40:07 -07:00
|
|
|
/* execute previously recorded trace */
|
2008-07-21 12:43:51 -07:00
|
|
|
TreeInfo* ti = (TreeInfo*)f->vmprivate;
|
|
|
|
if (OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->shape != ti->globalShape) {
|
2008-07-17 10:22:40 -07:00
|
|
|
AUDIT(globalShapeMismatchAtEntry);
|
2008-07-20 12:42:19 -07:00
|
|
|
debug_only(printf("global shape mismatch, discarding trace (started pc %u line %u).\n",
|
|
|
|
(jsbytecode*)f->root->ip - cx->fp->script->code,
|
|
|
|
js_PCToLineNumber(cx, cx->fp->script, (jsbytecode*)f->root->ip));)
|
2008-07-19 22:32:45 -07:00
|
|
|
f->releaseCode(tm->fragmento);
|
2008-07-15 01:08:13 -07:00
|
|
|
return false;
|
|
|
|
}
|
2008-07-15 10:26:15 -07:00
|
|
|
|
2008-07-21 12:43:51 -07:00
|
|
|
double* native = (double *)alloca((ti->maxNativeFrameSlots+1) * sizeof(double));
|
|
|
|
debug_only(*(uint64*)&native[ti->maxNativeFrameSlots] = 0xdeadbeefdeadbeefLL;)
|
2008-07-21 16:19:38 -07:00
|
|
|
if (!unbox(cx, ti->ngslots, ti->gslots, 0 /*callDepth*/, ti->typeMap, native)) {
|
2008-07-17 10:22:40 -07:00
|
|
|
AUDIT(typeMapMismatchAtEntry);
|
|
|
|
debug_only(printf("type-map mismatch, skipping trace.\n");)
|
2008-07-06 15:55:04 -07:00
|
|
|
return false;
|
|
|
|
}
|
2008-07-21 12:43:51 -07:00
|
|
|
double* entry_sp = &native[ti->nativeStackBase/sizeof(double) +
|
2008-07-05 14:05:25 -07:00
|
|
|
(cx->fp->regs->sp - cx->fp->spbase - 1)];
|
2008-07-21 12:43:51 -07:00
|
|
|
JSObject** callstack = (JSObject**)alloca(ti->maxCallDepth * sizeof(JSObject*));
|
2008-07-07 02:47:40 -07:00
|
|
|
InterpState state;
|
|
|
|
state.ip = cx->fp->regs->pc;
|
2008-07-04 13:23:42 -07:00
|
|
|
state.sp = (void*)entry_sp;
|
2008-07-14 19:12:50 -07:00
|
|
|
state.rp = callstack;
|
2008-07-04 16:24:42 -07:00
|
|
|
state.cx = cx;
|
2008-07-02 17:19:07 -07:00
|
|
|
union { NIns *code; GuardRecord* (FASTCALL *func)(InterpState*, Fragment*); } u;
|
|
|
|
u.code = f->code();
|
2008-07-15 13:06:05 -07:00
|
|
|
#if defined(DEBUG) && defined(NANOJIT_IA32)
|
2008-07-20 12:42:19 -07:00
|
|
|
printf("entering trace at %s:%u@%u, sp=%p\n",
|
2008-07-11 17:59:10 -07:00
|
|
|
cx->fp->script->filename, js_PCToLineNumber(cx, cx->fp->script, cx->fp->regs->pc),
|
2008-07-20 12:42:19 -07:00
|
|
|
cx->fp->regs->pc - cx->fp->script->code,
|
2008-07-11 17:59:10 -07:00
|
|
|
state.sp);
|
2008-07-05 17:10:58 -07:00
|
|
|
uint64 start = rdtsc();
|
2008-07-07 02:21:04 -07:00
|
|
|
#endif
|
2008-07-02 17:19:07 -07:00
|
|
|
GuardRecord* lr = u.func(&state, NULL);
|
2008-07-16 15:01:55 -07:00
|
|
|
JS_ASSERT(lr->calldepth == 0);
|
2008-07-18 15:35:59 -07:00
|
|
|
cx->fp->regs->sp += (lr->exit->sp_adj / sizeof(double));
|
|
|
|
cx->fp->regs->pc += lr->exit->ip_adj;
|
2008-07-15 13:06:05 -07:00
|
|
|
#if defined(DEBUG) && defined(NANOJIT_IA32)
|
2008-07-20 12:42:19 -07:00
|
|
|
printf("leaving trace at %s:%u@%u, sp=%p, ip=%p, cycles=%llu\n",
|
2008-07-15 10:26:15 -07:00
|
|
|
cx->fp->script->filename, js_PCToLineNumber(cx, cx->fp->script, cx->fp->regs->pc),
|
2008-07-20 12:42:19 -07:00
|
|
|
cx->fp->regs->pc - cx->fp->script->code,
|
|
|
|
state.sp, lr->jmp,
|
2008-07-11 17:59:10 -07:00
|
|
|
(rdtsc() - start));
|
2008-07-07 02:21:04 -07:00
|
|
|
#endif
|
2008-07-21 16:19:38 -07:00
|
|
|
box(cx, ti->ngslots, ti->gslots, lr->calldepth, lr->exit->typeMap, native);
|
2008-07-21 12:43:51 -07:00
|
|
|
JS_ASSERT(*(uint64*)&native[ti->maxNativeFrameSlots] == 0xdeadbeefdeadbeefLL);
|
2008-07-05 10:41:35 -07:00
|
|
|
|
2008-07-17 10:22:40 -07:00
|
|
|
AUDIT(sideExitIntoInterpreter);
|
2008-07-20 16:09:08 -07:00
|
|
|
|
2008-07-17 16:20:13 -07:00
|
|
|
/* if the side exit terminates the loop, don't try to attach a trace here */
|
2008-07-19 00:15:22 -07:00
|
|
|
if (js_IsLoopExit(cx, cx->fp->script, cx->fp->regs->pc))
|
2008-07-17 16:20:13 -07:00
|
|
|
return false;
|
2008-07-17 14:58:09 -07:00
|
|
|
|
2008-07-17 16:20:13 -07:00
|
|
|
debug_only(printf("trying to attach another branch to the tree\n");)
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-20 14:28:56 -07:00
|
|
|
Fragment* c;
|
|
|
|
if (!(c = lr->target)) {
|
|
|
|
c = tm->fragmento->createBranch(lr, lr->exit);
|
|
|
|
c->spawnedFrom = lr->guard;
|
|
|
|
c->parent = f;
|
2008-07-20 14:56:04 -07:00
|
|
|
lr->exit->target = c;
|
2008-07-20 14:28:56 -07:00
|
|
|
lr->target = c;
|
|
|
|
c->root = f;
|
|
|
|
c->calldepth = lr->calldepth;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (++c->hits() >= HOTEXIT) {
|
|
|
|
/* start tracing secondary trace from this point */
|
|
|
|
c->lirbuf = f->lirbuf;
|
|
|
|
return js_StartRecorder(cx, lr, c, lr->guard->exit()->typeMap);
|
|
|
|
}
|
|
|
|
return false;
|
2008-07-01 02:37:07 -07:00
|
|
|
}
|
|
|
|
|
2008-06-28 18:19:21 -07:00
|
|
|
void
|
2008-07-20 12:42:19 -07:00
|
|
|
js_AbortRecording(JSContext* cx, jsbytecode* abortpc, const char* reason)
|
2008-06-28 18:19:21 -07:00
|
|
|
{
|
2008-07-17 10:22:40 -07:00
|
|
|
AUDIT(recorderAborted);
|
2008-07-20 12:42:19 -07:00
|
|
|
debug_only(if (!abortpc) abortpc = cx->fp->regs->pc;
|
|
|
|
printf("Abort recording (line %d, pc %d): %s.\n",
|
|
|
|
js_PCToLineNumber(cx, cx->fp->script, abortpc),
|
|
|
|
abortpc - cx->fp->script->code, reason);)
|
2008-07-17 01:29:41 -07:00
|
|
|
JS_ASSERT(JS_TRACE_MONITOR(cx).recorder != NULL);
|
|
|
|
Fragment* f = JS_TRACE_MONITOR(cx).recorder->getFragment();
|
|
|
|
f->blacklist();
|
|
|
|
if (f->root == f) {
|
2008-07-17 10:22:40 -07:00
|
|
|
AUDIT(typeMapTrashed);
|
|
|
|
debug_only(printf("Root fragment aborted, trashing the type map.\n");)
|
2008-07-21 12:43:51 -07:00
|
|
|
TreeInfo* ti = (TreeInfo*)f->vmprivate;
|
|
|
|
JS_ASSERT(ti->typeMap);
|
|
|
|
ti->typeMap = NULL;
|
2008-07-17 01:29:41 -07:00
|
|
|
}
|
2008-07-01 02:37:07 -07:00
|
|
|
js_DeleteRecorder(cx);
|
2008-06-28 18:19:21 -07:00
|
|
|
}
|
|
|
|
|
2008-07-05 19:15:00 -07:00
|
|
|
extern void
|
|
|
|
js_InitJIT(JSContext* cx)
|
|
|
|
{
|
|
|
|
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
|
|
|
|
if (!tm->fragmento) {
|
2008-07-16 23:47:57 -07:00
|
|
|
Fragmento* fragmento = new (&gc) Fragmento(core, 24);
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(fragmento->labels = new (&gc) LabelMap(core, NULL);)
|
2008-07-05 19:15:00 -07:00
|
|
|
fragmento->assm()->setCallTable(builtins);
|
2008-07-09 23:47:17 -07:00
|
|
|
fragmento->pageFree(fragmento->pageAlloc()); // FIXME: prime page cache
|
2008-07-05 19:15:00 -07:00
|
|
|
tm->fragmento = fragmento;
|
|
|
|
}
|
2008-07-17 10:22:40 -07:00
|
|
|
debug_only(memset(&stat, 0, sizeof(stat)));
|
|
|
|
}
|
|
|
|
|
2008-07-19 00:15:22 -07:00
|
|
|
extern void
|
2008-07-17 10:22:40 -07:00
|
|
|
js_DestroyJIT(JSContext* cx)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("recorder: started(%llu), aborted(%llu), completed(%llu), different header(%llu), "
|
|
|
|
"type map trashed(%llu), slot demoted(%llu), slot promoted(%llu), "
|
|
|
|
"unstable loop variable(%llu)\n", stat.recorderStarted, stat.recorderAborted,
|
|
|
|
stat.traceCompleted, stat.returnToDifferentLoopHeader, stat.typeMapTrashed,
|
|
|
|
stat.slotDemoted, stat.slotPromoted, stat.unstableLoopVariable);
|
2008-07-17 13:42:58 -07:00
|
|
|
printf("monitor: triggered(%llu), exits (%llu), type mismatch(%llu), "
|
2008-07-17 10:22:40 -07:00
|
|
|
"global mismatch(%llu)\n", stat.traceTriggered, stat.sideExitIntoInterpreter,
|
2008-07-17 13:42:58 -07:00
|
|
|
stat.typeMapMismatchAtEntry, stat.globalShapeMismatchAtEntry);
|
2008-07-19 00:15:22 -07:00
|
|
|
#endif
|
2008-07-05 19:15:00 -07:00
|
|
|
}
|
|
|
|
|
2008-07-04 03:06:18 -07:00
|
|
|
jsval&
|
|
|
|
TraceRecorder::argval(unsigned n) const
|
|
|
|
{
|
2008-07-21 19:31:08 -07:00
|
|
|
JS_ASSERT(n < cx->fp->fun->nargs);
|
2008-07-04 03:06:18 -07:00
|
|
|
return cx->fp->argv[n];
|
|
|
|
}
|
|
|
|
|
|
|
|
jsval&
|
|
|
|
TraceRecorder::varval(unsigned n) const
|
|
|
|
{
|
2008-07-08 18:12:22 -07:00
|
|
|
JS_ASSERT(n < cx->fp->nvars);
|
2008-07-04 03:06:18 -07:00
|
|
|
return cx->fp->vars[n];
|
|
|
|
}
|
|
|
|
|
|
|
|
jsval&
|
|
|
|
TraceRecorder::stackval(int n) const
|
|
|
|
{
|
2008-07-08 18:12:22 -07:00
|
|
|
jsval* sp = cx->fp->regs->sp;
|
|
|
|
JS_ASSERT(size_t((sp + n) - cx->fp->spbase) < cx->fp->script->depth);
|
|
|
|
return sp[n];
|
2008-07-04 03:06:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
LIns*
|
2008-07-05 10:41:35 -07:00
|
|
|
TraceRecorder::arg(unsigned n)
|
2008-07-04 03:06:18 -07:00
|
|
|
{
|
|
|
|
return get(&argval(n));
|
|
|
|
}
|
|
|
|
|
2008-07-04 15:21:56 -07:00
|
|
|
void
|
|
|
|
TraceRecorder::arg(unsigned n, LIns* i)
|
|
|
|
{
|
|
|
|
set(&argval(n), i);
|
|
|
|
}
|
|
|
|
|
2008-07-04 03:06:18 -07:00
|
|
|
LIns*
|
2008-07-05 10:41:35 -07:00
|
|
|
TraceRecorder::var(unsigned n)
|
2008-07-04 03:06:18 -07:00
|
|
|
{
|
|
|
|
return get(&varval(n));
|
|
|
|
}
|
|
|
|
|
2008-07-04 15:21:56 -07:00
|
|
|
void
|
|
|
|
TraceRecorder::var(unsigned n, LIns* i)
|
|
|
|
{
|
|
|
|
set(&varval(n), i);
|
|
|
|
}
|
|
|
|
|
2008-07-04 03:06:18 -07:00
|
|
|
LIns*
|
|
|
|
TraceRecorder::stack(int n)
|
|
|
|
{
|
|
|
|
return get(&stackval(n));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-07-05 10:41:35 -07:00
|
|
|
TraceRecorder::stack(int n, LIns* i)
|
2008-07-04 03:06:18 -07:00
|
|
|
{
|
2008-07-21 12:57:02 -07:00
|
|
|
set(&stackval(n), i, n >= 0);
|
2008-07-04 03:06:18 -07:00
|
|
|
}
|
|
|
|
|
2008-07-06 15:55:04 -07:00
|
|
|
LIns* TraceRecorder::f2i(LIns* f)
|
|
|
|
{
|
|
|
|
return lir->insCall(F_doubleToInt32, &f);
|
|
|
|
}
|
|
|
|
|
2008-07-10 20:35:19 -07:00
|
|
|
bool TraceRecorder::ifop()
|
2008-07-05 22:23:34 -07:00
|
|
|
{
|
|
|
|
jsval& v = stackval(-1);
|
2008-07-06 12:16:55 -07:00
|
|
|
if (JSVAL_IS_BOOLEAN(v)) {
|
2008-07-10 20:35:19 -07:00
|
|
|
guard(!JSVAL_TO_BOOLEAN(v), lir->ins_eq0(get(&v)));
|
2008-07-18 08:01:51 -07:00
|
|
|
} else if (JSVAL_IS_OBJECT(v)) {
|
|
|
|
guard(!JSVAL_IS_NULL(v), lir->ins_eq0(get(&v)));
|
|
|
|
} else if (isNumber(v)) {
|
|
|
|
jsdouble d = asNumber(v);
|
|
|
|
jsdpun u;
|
|
|
|
u.d = 0;
|
|
|
|
/* XXX need to handle NaN! */
|
|
|
|
guard(d == 0, lir->ins2(LIR_feq, get(&v), lir->insImmq(u.u64)));
|
|
|
|
} else if (JSVAL_IS_STRING(v)) {
|
|
|
|
ABORT_TRACE("strings not supported");
|
2008-07-05 22:23:34 -07:00
|
|
|
} else {
|
2008-07-18 08:01:51 -07:00
|
|
|
ABORT_TRACE("unknown type, wtf");
|
2008-07-05 22:23:34 -07:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-04 03:06:18 -07:00
|
|
|
bool
|
|
|
|
TraceRecorder::inc(jsval& v, jsint incr, bool pre)
|
|
|
|
{
|
2008-07-19 10:24:10 -07:00
|
|
|
LIns* v_ins = get(&v);
|
|
|
|
if (!inc(v, v_ins, incr, pre))
|
|
|
|
return false;
|
|
|
|
set(&v, v_ins);
|
|
|
|
return true;
|
2008-07-19 00:15:22 -07:00
|
|
|
}
|
2008-07-09 15:15:32 -07:00
|
|
|
|
2008-07-19 10:24:10 -07:00
|
|
|
/*
|
|
|
|
* On exit, v_ins is the incremented unboxed value, and the appropriate
|
|
|
|
* value (pre- or post-increment as described by pre) is stacked.
|
|
|
|
*/
|
2008-07-19 00:15:22 -07:00
|
|
|
bool
|
2008-07-19 10:24:10 -07:00
|
|
|
TraceRecorder::inc(jsval& v, LIns*& v_ins, jsint incr, bool pre)
|
2008-07-19 00:15:22 -07:00
|
|
|
{
|
|
|
|
if (!isNumber(v))
|
2008-07-19 10:24:10 -07:00
|
|
|
ABORT_TRACE("can only inc numbers");
|
2008-07-19 00:15:22 -07:00
|
|
|
|
|
|
|
jsdpun u;
|
|
|
|
u.d = jsdouble(incr);
|
|
|
|
|
2008-07-19 10:24:10 -07:00
|
|
|
LIns* v_after = lir->ins2(LIR_fadd, v_ins, lir->insImmq(u.u64));
|
2008-07-19 00:15:22 -07:00
|
|
|
|
|
|
|
const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
|
|
|
|
JS_ASSERT(cs.ndefs == 1);
|
2008-07-19 10:24:10 -07:00
|
|
|
stack(-cs.nuses, pre ? v_after : v_ins);
|
|
|
|
v_ins = v_after;
|
2008-07-19 00:15:22 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
TraceRecorder::incProp(jsint incr, bool pre)
|
|
|
|
{
|
|
|
|
jsval& l = stackval(-1);
|
|
|
|
if (JSVAL_IS_PRIMITIVE(l))
|
|
|
|
ABORT_TRACE("incProp on primitive");
|
|
|
|
|
|
|
|
JSObject* obj = JSVAL_TO_OBJECT(l);
|
|
|
|
LIns* obj_ins = get(&l);
|
|
|
|
|
2008-07-19 10:24:28 -07:00
|
|
|
uint32 slot;
|
2008-07-19 00:15:22 -07:00
|
|
|
LIns* v_ins;
|
2008-07-19 10:24:28 -07:00
|
|
|
if (!prop(obj, obj_ins, slot, v_ins))
|
2008-07-19 00:15:22 -07:00
|
|
|
return false;
|
2008-07-19 10:24:28 -07:00
|
|
|
|
|
|
|
jsval& v = STOBJ_GET_SLOT(obj, slot);
|
|
|
|
if (!inc(v, v_ins, incr, pre))
|
|
|
|
return false;
|
|
|
|
|
2008-07-19 10:24:10 -07:00
|
|
|
if (!box_jsval(v, v_ins))
|
2008-07-19 10:24:28 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
LIns* dslots_ins = NULL;
|
2008-07-19 10:24:10 -07:00
|
|
|
stobj_set_slot(obj_ins, slot, dslots_ins, v_ins);
|
2008-07-19 10:24:28 -07:00
|
|
|
return true;
|
2008-07-19 00:15:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
TraceRecorder::incElem(jsint incr, bool pre)
|
|
|
|
{
|
|
|
|
jsval& r = stackval(-1);
|
|
|
|
jsval& l = stackval(-2);
|
|
|
|
jsval* vp;
|
|
|
|
LIns* v_ins;
|
2008-07-19 10:24:10 -07:00
|
|
|
LIns* addr_ins;
|
|
|
|
if (!elem(l, r, vp, v_ins, addr_ins))
|
|
|
|
return false;
|
|
|
|
if (!inc(*vp, v_ins, incr, pre))
|
2008-07-19 00:15:22 -07:00
|
|
|
return false;
|
2008-07-19 10:24:10 -07:00
|
|
|
if (!box_jsval(*vp, v_ins))
|
|
|
|
return false;
|
|
|
|
lir->insStorei(v_ins, addr_ins, 0);
|
|
|
|
return true;
|
2008-07-04 03:06:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
TraceRecorder::cmp(LOpcode op, bool negate)
|
|
|
|
{
|
|
|
|
jsval& r = stackval(-1);
|
|
|
|
jsval& l = stackval(-2);
|
2008-07-06 15:55:04 -07:00
|
|
|
if (isNumber(l) && isNumber(r)) {
|
2008-07-04 03:06:18 -07:00
|
|
|
LIns* x = lir->ins2(op, get(&l), get(&r));
|
|
|
|
if (negate)
|
2008-07-06 15:55:04 -07:00
|
|
|
x = lir->ins_eq0(x);
|
2008-07-04 03:06:18 -07:00
|
|
|
bool cond;
|
|
|
|
switch (op) {
|
2008-07-06 15:55:04 -07:00
|
|
|
case LIR_flt:
|
|
|
|
cond = asNumber(l) < asNumber(r);
|
2008-07-04 03:06:18 -07:00
|
|
|
break;
|
2008-07-06 15:55:04 -07:00
|
|
|
case LIR_fgt:
|
|
|
|
cond = asNumber(l) > asNumber(r);
|
2008-07-04 03:06:18 -07:00
|
|
|
break;
|
2008-07-06 15:55:04 -07:00
|
|
|
case LIR_fle:
|
|
|
|
cond = asNumber(l) <= asNumber(r);
|
2008-07-04 03:06:18 -07:00
|
|
|
break;
|
2008-07-06 15:55:04 -07:00
|
|
|
case LIR_fge:
|
|
|
|
cond = asNumber(l) >= asNumber(r);
|
2008-07-04 03:06:18 -07:00
|
|
|
break;
|
2008-07-05 10:41:35 -07:00
|
|
|
default:
|
2008-07-09 10:05:59 -07:00
|
|
|
JS_ASSERT(op == LIR_feq);
|
2008-07-12 00:27:21 -07:00
|
|
|
cond = (asNumber(l) == asNumber(r)) ^ negate;
|
2008-07-04 03:06:18 -07:00
|
|
|
break;
|
|
|
|
}
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-04 13:23:42 -07:00
|
|
|
/* The interpreter fuses comparisons and the following branch,
|
2008-07-04 03:06:18 -07:00
|
|
|
so we have to do that here as well. */
|
2008-07-10 21:55:09 -07:00
|
|
|
if (cx->fp->regs->pc[1] == JSOP_IFEQ || cx->fp->regs->pc[1] == JSOP_IFNE)
|
2008-07-04 13:23:42 -07:00
|
|
|
guard(cond, x);
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-04 13:23:42 -07:00
|
|
|
/* We update the stack after the guard. This is safe since
|
|
|
|
the guard bails out at the comparison and the interpreter
|
|
|
|
will this re-execute the comparison. This way the
|
|
|
|
value of the condition doesn't have to be calculated and
|
|
|
|
saved on the stack in most cases. */
|
|
|
|
set(&l, x);
|
2008-07-04 03:06:18 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-07-05 11:35:55 -07:00
|
|
|
bool
|
2008-07-06 13:16:34 -07:00
|
|
|
TraceRecorder::unary(LOpcode op)
|
2008-07-05 11:35:55 -07:00
|
|
|
{
|
|
|
|
jsval& v = stackval(-1);
|
2008-07-06 13:16:34 -07:00
|
|
|
bool intop = !(op & LIR64);
|
2008-07-05 22:04:58 -07:00
|
|
|
if (isNumber(v)) {
|
2008-07-06 13:16:34 -07:00
|
|
|
LIns* a = get(&v);
|
|
|
|
if (intop)
|
2008-07-06 15:55:04 -07:00
|
|
|
a = f2i(a);
|
2008-07-06 13:16:34 -07:00
|
|
|
a = lir->ins1(op, a);
|
|
|
|
if (intop)
|
|
|
|
a = lir->ins1(LIR_i2f, a);
|
|
|
|
set(&v, a);
|
2008-07-05 11:35:55 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-07-04 15:21:56 -07:00
|
|
|
bool
|
2008-07-06 13:16:34 -07:00
|
|
|
TraceRecorder::binary(LOpcode op)
|
2008-07-04 15:21:56 -07:00
|
|
|
{
|
|
|
|
jsval& r = stackval(-1);
|
|
|
|
jsval& l = stackval(-2);
|
2008-07-06 13:16:34 -07:00
|
|
|
bool intop = !(op & LIR64);
|
|
|
|
if (isNumber(l) && isNumber(r)) {
|
|
|
|
LIns* a = get(&l);
|
|
|
|
LIns* b = get(&r);
|
|
|
|
if (intop) {
|
|
|
|
a = lir->insCall(op == LIR_ush ? F_doubleToUint32 : F_doubleToInt32, &a);
|
2008-07-06 15:55:04 -07:00
|
|
|
b = f2i(b);
|
2008-07-06 13:16:34 -07:00
|
|
|
}
|
|
|
|
a = lir->ins2(op, a, b);
|
|
|
|
if (intop)
|
|
|
|
a = lir->ins1(op == LIR_ush ? LIR_u2f : LIR_i2f, a);
|
|
|
|
set(&l, a);
|
2008-07-04 15:21:56 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-07-04 23:53:29 -07:00
|
|
|
bool
|
2008-07-06 09:15:55 -07:00
|
|
|
TraceRecorder::map_is_native(JSObjectMap* map, LIns* map_ins)
|
2008-07-04 23:53:29 -07:00
|
|
|
{
|
2008-07-17 02:00:23 -07:00
|
|
|
LIns* ops = addName(lir->insLoadi(map_ins, offsetof(JSObjectMap, ops)), "ops");
|
2008-07-04 23:53:29 -07:00
|
|
|
if (map->ops == &js_ObjectOps) {
|
2008-07-17 02:00:23 -07:00
|
|
|
guard(true, addName(lir->ins2(LIR_eq, ops, lir->insImmPtr(&js_ObjectOps)),
|
|
|
|
"guard(native-ops)"));
|
2008-07-04 23:53:29 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
LIns* n = lir->insLoadi(ops, offsetof(JSObjectOps, newObjectMap));
|
|
|
|
if (map->ops->newObjectMap == js_ObjectOps.newObjectMap) {
|
2008-07-17 02:00:23 -07:00
|
|
|
guard(true, addName(lir->ins2(LIR_eq, n, lir->insImmPtr((void*)js_ObjectOps.newObjectMap)),
|
|
|
|
"guard(native-map)"));
|
2008-07-04 23:53:29 -07:00
|
|
|
return true;
|
|
|
|
}
|
2008-07-11 17:59:10 -07:00
|
|
|
ABORT_TRACE("non-native map");
|
2008-07-04 23:53:29 -07:00
|
|
|
}
|
|
|
|
|
2008-07-06 09:15:55 -07:00
|
|
|
bool
|
2008-07-17 23:57:56 -07:00
|
|
|
TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, jsuword& pcval)
|
2008-07-06 09:15:55 -07:00
|
|
|
{
|
|
|
|
LIns* map_ins = lir->insLoadi(obj_ins, offsetof(JSObject, map));
|
|
|
|
if (!map_is_native(obj->map, map_ins))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
JSAtom* atom;
|
2008-07-17 23:57:56 -07:00
|
|
|
JSPropCacheEntry* entry;
|
2008-07-06 09:15:55 -07:00
|
|
|
PROPERTY_CACHE_TEST(cx, cx->fp->regs->pc, obj, obj2, entry, atom);
|
2008-07-17 23:57:56 -07:00
|
|
|
if (!atom) {
|
|
|
|
pcval = entry->vword;
|
|
|
|
return true;
|
|
|
|
}
|
2008-07-06 10:38:55 -07:00
|
|
|
|
2008-07-18 00:46:18 -07:00
|
|
|
JSProperty* prop;
|
|
|
|
JSScopeProperty* sprop;
|
2008-07-17 23:57:56 -07:00
|
|
|
jsid id = ATOM_TO_JSID(atom);
|
2008-07-18 00:46:18 -07:00
|
|
|
if (JOF_OPMODE(*cx->fp->regs->pc) == JOF_NAME) {
|
|
|
|
if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
|
|
|
|
ABORT_TRACE("failed to find name");
|
|
|
|
} else {
|
|
|
|
if (!js_LookupProperty(cx, obj, id, &obj2, &prop))
|
|
|
|
ABORT_TRACE("failed to lookup property");
|
|
|
|
}
|
2008-07-07 02:21:04 -07:00
|
|
|
|
2008-07-18 00:46:18 -07:00
|
|
|
sprop = (JSScopeProperty*)prop;
|
|
|
|
JSScope* scope = OBJ_SCOPE(obj2);
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-18 00:46:18 -07:00
|
|
|
jsval v;
|
|
|
|
const JSCodeSpec *cs = &js_CodeSpec[*cx->fp->regs->pc];
|
|
|
|
|
|
|
|
if (cs->format & JOF_CALLOP) {
|
|
|
|
if (SPROP_HAS_STUB_GETTER(sprop) && SPROP_HAS_VALID_SLOT(sprop, scope) &&
|
|
|
|
VALUE_IS_FUNCTION(cx, (v = STOBJ_GET_SLOT(obj2, sprop->slot))) &&
|
|
|
|
SCOPE_IS_BRANDED(scope)) {
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-18 00:46:18 -07:00
|
|
|
/* Call op, "pure" sprop, function value, branded scope: cache method. */
|
|
|
|
pcval = JSVAL_OBJECT_TO_PCVAL(v);
|
|
|
|
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
|
|
return true;
|
|
|
|
}
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-18 00:46:18 -07:00
|
|
|
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
2008-07-18 08:01:51 -07:00
|
|
|
ABORT_TRACE("can't fast method value for call op");
|
2008-07-18 00:46:18 -07:00
|
|
|
}
|
|
|
|
|
2008-07-19 00:15:22 -07:00
|
|
|
if ((((cs->format & JOF_SET) && SPROP_HAS_STUB_SETTER(sprop)) ||
|
|
|
|
SPROP_HAS_STUB_GETTER(sprop)) &&
|
2008-07-18 00:46:18 -07:00
|
|
|
SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
|
|
|
|
|
|
|
/* Stub accessor of appropriate form and valid slot: cache slot. */
|
|
|
|
pcval = SLOT_TO_PCVAL(sprop->slot);
|
|
|
|
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ABORT_TRACE("not cacheable property find");
|
2008-07-06 09:15:55 -07:00
|
|
|
}
|
|
|
|
|
2008-07-09 11:42:31 -07:00
|
|
|
bool
|
|
|
|
TraceRecorder::test_property_cache_direct_slot(JSObject* obj, LIns* obj_ins, uint32& slot)
|
|
|
|
{
|
|
|
|
JSObject* obj2;
|
2008-07-17 23:57:56 -07:00
|
|
|
jsuword pcval;
|
2008-07-09 11:42:31 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Property cache ensures that we are dealing with an existing property,
|
|
|
|
* and guards the shape for us.
|
|
|
|
*/
|
2008-07-17 23:57:56 -07:00
|
|
|
if (!test_property_cache(obj, obj_ins, obj2, pcval))
|
2008-07-09 11:42:31 -07:00
|
|
|
return false;
|
|
|
|
|
2008-07-09 15:15:32 -07:00
|
|
|
/* Handle only gets and sets on the directly addressed object. */
|
2008-07-09 11:42:31 -07:00
|
|
|
if (obj2 != obj)
|
2008-07-11 17:59:10 -07:00
|
|
|
ABORT_TRACE("PC hit on prototype chain");
|
2008-07-09 11:42:31 -07:00
|
|
|
|
|
|
|
/* Don't trace setter calls, our caller wants a direct slot. */
|
2008-07-17 23:57:56 -07:00
|
|
|
if (PCVAL_IS_SPROP(pcval)) {
|
2008-07-09 16:37:31 -07:00
|
|
|
JS_ASSERT(js_CodeSpec[*cx->fp->regs->pc].format & JOF_SET);
|
2008-07-17 23:57:56 -07:00
|
|
|
JSScopeProperty* sprop = PCVAL_TO_SPROP(pcval);
|
2008-07-09 16:37:31 -07:00
|
|
|
|
|
|
|
if (!SPROP_HAS_STUB_SETTER(sprop))
|
2008-07-11 17:59:10 -07:00
|
|
|
ABORT_TRACE("non-stub setter");
|
2008-07-09 16:37:31 -07:00
|
|
|
if (!SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)))
|
2008-07-11 17:59:10 -07:00
|
|
|
ABORT_TRACE("no valid slot");
|
2008-07-09 16:37:31 -07:00
|
|
|
slot = sprop->slot;
|
|
|
|
} else {
|
2008-07-17 23:57:56 -07:00
|
|
|
if (!PCVAL_IS_SLOT(pcval))
|
2008-07-11 17:59:10 -07:00
|
|
|
ABORT_TRACE("PCE is not a slot");
|
2008-07-17 23:57:56 -07:00
|
|
|
slot = PCVAL_TO_SLOT(pcval);
|
2008-07-09 16:37:31 -07:00
|
|
|
}
|
2008-07-09 11:42:31 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-05 13:44:48 -07:00
|
|
|
void
|
|
|
|
TraceRecorder::stobj_set_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins, LIns* v_ins)
|
2008-07-05 11:35:55 -07:00
|
|
|
{
|
2008-07-07 02:55:03 -07:00
|
|
|
if (slot < JS_INITIAL_NSLOTS) {
|
2008-07-17 02:00:23 -07:00
|
|
|
addName(lir->insStorei(v_ins, obj_ins,
|
|
|
|
offsetof(JSObject, fslots) + slot * sizeof(jsval)),
|
|
|
|
"set_slot(fslots)");
|
2008-07-07 02:55:03 -07:00
|
|
|
} else {
|
2008-07-05 13:44:48 -07:00
|
|
|
if (!dslots_ins)
|
|
|
|
dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
|
2008-07-17 02:00:23 -07:00
|
|
|
addName(lir->insStorei(v_ins, dslots_ins,
|
|
|
|
(slot - JS_INITIAL_NSLOTS) * sizeof(jsval)),
|
|
|
|
"set_slot(dslots");
|
2008-07-05 13:44:48 -07:00
|
|
|
}
|
2008-07-07 02:21:04 -07:00
|
|
|
}
|
2008-07-05 11:35:55 -07:00
|
|
|
|
2008-07-06 09:15:55 -07:00
|
|
|
LIns*
|
|
|
|
TraceRecorder::stobj_get_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins)
|
2008-07-05 11:35:55 -07:00
|
|
|
{
|
2008-07-06 09:15:55 -07:00
|
|
|
if (slot < JS_INITIAL_NSLOTS) {
|
2008-07-07 02:21:04 -07:00
|
|
|
return lir->insLoadi(obj_ins,
|
2008-07-06 09:15:55 -07:00
|
|
|
offsetof(JSObject, fslots) + slot * sizeof(jsval));
|
2008-07-07 02:21:04 -07:00
|
|
|
}
|
2008-07-06 09:15:55 -07:00
|
|
|
|
|
|
|
if (!dslots_ins)
|
|
|
|
dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
|
|
|
|
return lir->insLoadi(dslots_ins, (slot - JS_INITIAL_NSLOTS) * sizeof(jsval));
|
2008-07-07 02:21:04 -07:00
|
|
|
}
|
2008-07-05 11:35:55 -07:00
|
|
|
|
|
|
|
bool
|
2008-07-05 13:44:48 -07:00
|
|
|
TraceRecorder::native_set(LIns* obj_ins, JSScopeProperty* sprop, LIns*& dslots_ins, LIns* v_ins)
|
2008-07-05 11:35:55 -07:00
|
|
|
{
|
|
|
|
if (SPROP_HAS_STUB_SETTER(sprop) && sprop->slot != SPROP_INVALID_SLOT) {
|
2008-07-05 13:44:48 -07:00
|
|
|
stobj_set_slot(obj_ins, sprop->slot, dslots_ins, v_ins);
|
|
|
|
return true;
|
2008-07-05 11:35:55 -07:00
|
|
|
}
|
2008-07-17 02:00:23 -07:00
|
|
|
ABORT_TRACE("unallocated or non-stub sprop");
|
2008-07-05 11:35:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2008-07-07 02:21:04 -07:00
|
|
|
TraceRecorder::native_get(LIns* obj_ins, LIns* pobj_ins, JSScopeProperty* sprop,
|
2008-07-05 13:44:48 -07:00
|
|
|
LIns*& dslots_ins, LIns*& v_ins)
|
2008-07-05 11:35:55 -07:00
|
|
|
{
|
2008-07-06 09:15:55 -07:00
|
|
|
if (!SPROP_HAS_STUB_GETTER(sprop))
|
|
|
|
return false;
|
|
|
|
|
2008-07-07 02:21:04 -07:00
|
|
|
if (sprop->slot != SPROP_INVALID_SLOT)
|
2008-07-06 09:15:55 -07:00
|
|
|
v_ins = stobj_get_slot(pobj_ins, sprop->slot, dslots_ins);
|
|
|
|
else
|
2008-07-19 00:15:22 -07:00
|
|
|
v_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
2008-07-06 09:15:55 -07:00
|
|
|
return true;
|
2008-07-07 02:21:04 -07:00
|
|
|
}
|
2008-07-05 11:35:55 -07:00
|
|
|
|
2008-07-06 13:59:59 -07:00
|
|
|
bool
|
|
|
|
TraceRecorder::box_jsval(jsval v, LIns*& v_ins)
|
|
|
|
{
|
2008-07-06 16:18:45 -07:00
|
|
|
if (isNumber(v)) {
|
2008-07-06 20:25:49 -07:00
|
|
|
LIns* args[] = { v_ins, cx_ins };
|
2008-07-06 16:18:45 -07:00
|
|
|
v_ins = lir->insCall(F_BoxDouble, args);
|
|
|
|
guard(false, lir->ins2(LIR_eq, v_ins, lir->insImmPtr((void*)JSVAL_ERROR_COOKIE)));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
switch (JSVAL_TAG(v)) {
|
2008-07-10 21:55:09 -07:00
|
|
|
case JSVAL_BOOLEAN:
|
2008-07-06 16:18:45 -07:00
|
|
|
v_ins = lir->ins2i(LIR_or, lir->ins2i(LIR_lsh, v_ins, JSVAL_TAGBITS), JSVAL_BOOLEAN);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2008-07-06 13:59:59 -07:00
|
|
|
}
|
|
|
|
|
2008-07-06 10:38:55 -07:00
|
|
|
bool
|
|
|
|
TraceRecorder::unbox_jsval(jsval v, LIns*& v_ins)
|
|
|
|
{
|
2008-07-06 16:18:45 -07:00
|
|
|
if (isNumber(v)) {
|
|
|
|
// JSVAL_IS_NUMBER(v)
|
2008-07-19 00:15:22 -07:00
|
|
|
guard(false,
|
|
|
|
lir->ins_eq0(lir->ins2(LIR_or,
|
|
|
|
lir->ins2(LIR_and, v_ins, lir->insImmPtr((void*)JSVAL_INT)),
|
|
|
|
lir->ins2i(LIR_eq,
|
|
|
|
lir->ins2(LIR_and, v_ins,
|
|
|
|
lir->insImmPtr((void*)JSVAL_TAGMASK)),
|
|
|
|
JSVAL_DOUBLE))));
|
2008-07-06 16:18:45 -07:00
|
|
|
v_ins = lir->insCall(F_UnboxDouble, &v_ins);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
switch (JSVAL_TAG(v)) {
|
2008-07-09 11:42:31 -07:00
|
|
|
case JSVAL_BOOLEAN:
|
|
|
|
guard(true,
|
|
|
|
lir->ins2i(LIR_eq,
|
2008-07-19 00:15:22 -07:00
|
|
|
lir->ins2(LIR_and, v_ins, lir->insImmPtr((void*)JSVAL_TAGMASK)),
|
2008-07-09 11:42:31 -07:00
|
|
|
JSVAL_BOOLEAN));
|
2008-07-07 02:21:04 -07:00
|
|
|
v_ins = lir->ins2i(LIR_ush, v_ins, JSVAL_TAGBITS);
|
2008-07-06 16:18:45 -07:00
|
|
|
return true;
|
2008-07-11 17:59:10 -07:00
|
|
|
case JSVAL_OBJECT:
|
|
|
|
guard(true,
|
|
|
|
lir->ins2i(LIR_eq,
|
2008-07-19 00:15:22 -07:00
|
|
|
lir->ins2(LIR_and, v_ins, lir->insImmPtr((void*)JSVAL_TAGMASK)),
|
2008-07-11 17:59:10 -07:00
|
|
|
JSVAL_OBJECT));
|
|
|
|
return true;
|
2008-07-15 10:26:15 -07:00
|
|
|
|
2008-07-06 16:18:45 -07:00
|
|
|
}
|
|
|
|
return false;
|
2008-07-06 10:38:55 -07:00
|
|
|
}
|
|
|
|
|
2008-07-16 14:36:50 -07:00
|
|
|
bool
|
|
|
|
TraceRecorder::getThis(LIns*& this_ins)
|
|
|
|
{
|
|
|
|
if (cx->fp->callee) { /* in a function */
|
|
|
|
if (JSVAL_IS_NULL(cx->fp->argv[-1]))
|
|
|
|
return false;
|
|
|
|
this_ins = get(&cx->fp->argv[-1]);
|
|
|
|
guard(false, lir->ins_eq0(this_ins));
|
|
|
|
} else { /* in global code */
|
|
|
|
JS_ASSERT(!JSVAL_IS_NULL(cx->fp->argv[-1]));
|
|
|
|
this_ins = lir->insLoadi(lir->insLoadi(cx_ins, offsetof(JSContext, fp)),
|
|
|
|
offsetof(JSStackFrame, thisp));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-11 17:59:10 -07:00
|
|
|
bool
|
|
|
|
TraceRecorder::guardThatObjectHasClass(JSObject* obj, LIns* obj_ins,
|
|
|
|
JSClass* cls, LIns*& dslots_ins)
|
2008-07-05 13:44:48 -07:00
|
|
|
{
|
2008-07-11 17:59:10 -07:00
|
|
|
if (STOBJ_GET_CLASS(obj) != cls)
|
2008-07-05 13:44:48 -07:00
|
|
|
return false;
|
2008-07-06 09:15:55 -07:00
|
|
|
LIns* class_ins = stobj_get_slot(obj_ins, JSSLOT_CLASS, dslots_ins);
|
2008-07-05 13:44:48 -07:00
|
|
|
class_ins = lir->ins2(LIR_and, class_ins, lir->insImmPtr((void*)~3));
|
2008-07-11 17:59:10 -07:00
|
|
|
guard(true, lir->ins2(LIR_eq, class_ins, lir->insImmPtr(cls)));
|
2008-07-05 13:44:48 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-11 17:59:10 -07:00
|
|
|
bool TraceRecorder::guardThatObjectIsDenseArray(JSObject* obj, LIns* obj_ins, LIns*& dslots_ins)
|
|
|
|
{
|
|
|
|
return guardThatObjectHasClass(obj, obj_ins, &js_ArrayClass, dslots_ins);
|
|
|
|
}
|
|
|
|
|
2008-07-07 02:21:04 -07:00
|
|
|
bool TraceRecorder::guardDenseArrayIndexWithinBounds(JSObject* obj, jsint idx,
|
2008-07-05 13:44:48 -07:00
|
|
|
LIns* obj_ins, LIns*& dslots_ins, LIns* idx_ins)
|
|
|
|
{
|
|
|
|
jsuint length = ARRAY_DENSE_LENGTH(obj);
|
|
|
|
if (!((jsuint)idx < length && idx < obj->fslots[JSSLOT_ARRAY_LENGTH]))
|
|
|
|
return false;
|
|
|
|
if (!dslots_ins)
|
|
|
|
dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
|
2008-07-06 09:15:55 -07:00
|
|
|
LIns* length_ins = stobj_get_slot(obj_ins, JSSLOT_ARRAY_LENGTH, dslots_ins);
|
2008-07-12 06:04:58 -07:00
|
|
|
// guard(index >= 0)
|
|
|
|
guard(true, lir->ins2i(LIR_ge, idx_ins, 0));
|
2008-07-05 13:44:48 -07:00
|
|
|
// guard(index < length)
|
|
|
|
guard(true, lir->ins2(LIR_lt, idx_ins, length_ins));
|
|
|
|
// guard(index < capacity)
|
|
|
|
guard(false, lir->ins_eq0(dslots_ins));
|
2008-07-07 02:21:04 -07:00
|
|
|
guard(true, lir->ins2(LIR_lt, idx_ins,
|
2008-07-12 06:04:58 -07:00
|
|
|
lir->insLoadi(dslots_ins, -sizeof(jsval))));
|
2008-07-05 13:44:48 -07:00
|
|
|
return true;
|
2008-07-05 11:45:53 -07:00
|
|
|
}
|
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INTERRUPT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_PUSH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 17:44:44 -07:00
|
|
|
stack(0, lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID)));
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_POPV()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-08 19:21:25 -07:00
|
|
|
jsval& v = stackval(-1);
|
|
|
|
set(&cx->fp->rval, get(&v));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ENTERWITH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_LEAVEWITH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_RETURN()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-21 16:19:38 -07:00
|
|
|
if (callDepth <= 0)
|
2008-07-16 15:01:55 -07:00
|
|
|
return false;
|
|
|
|
// this only works if we have a contiguous stack, which CALL enforces
|
|
|
|
set(&cx->fp->argv[-2], stack(-1));
|
2008-07-21 16:19:38 -07:00
|
|
|
--callDepth; // must not decrement callDepth until after the set
|
2008-07-19 06:29:56 -07:00
|
|
|
atoms = cx->fp->down->script->atomMap.vector;
|
2008-07-16 15:01:55 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GOTO()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 13:35:17 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_IFEQ()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 20:35:19 -07:00
|
|
|
return ifop();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_IFNE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 20:35:19 -07:00
|
|
|
return ifop();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ARGUMENTS()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_FORARG()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_FORVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DUP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-05 20:47:24 -07:00
|
|
|
stack(0, get(&stackval(-1)));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DUP2()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-05 20:47:24 -07:00
|
|
|
stack(0, get(&stackval(-2)));
|
|
|
|
stack(1, get(&stackval(-1)));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SETCONST()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_BITOR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return binary(LIR_or);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_BITXOR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return binary(LIR_xor);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_BITAND()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return binary(LIR_and);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_EQ()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return cmp(LIR_feq);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_NE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return cmp(LIR_feq, true);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_LT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return cmp(LIR_flt);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_LE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return cmp(LIR_fle);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return cmp(LIR_fgt);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return cmp(LIR_fge);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_LSH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return binary(LIR_lsh);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_RSH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return binary(LIR_rsh);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_URSH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return binary(LIR_ush);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ADD()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return binary(LIR_fadd);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SUB()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return binary(LIR_fsub);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_MUL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return binary(LIR_fmul);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DIV()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return binary(LIR_fdiv);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_MOD()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-15 20:19:29 -07:00
|
|
|
jsval& r = stackval(-1);
|
|
|
|
jsval& l = stackval(-2);
|
|
|
|
if (isNumber(l) && isNumber(r)) {
|
|
|
|
LIns* args[] = { get(&r), get(&l) };
|
|
|
|
set(&l, lir->insCall(F_dmod, args));
|
|
|
|
return true;
|
|
|
|
}
|
2008-07-03 23:57:57 -07:00
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_NOT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-05 17:26:00 -07:00
|
|
|
jsval& v = stackval(-1);
|
2008-07-06 12:16:55 -07:00
|
|
|
if (JSVAL_IS_BOOLEAN(v)) {
|
2008-07-05 17:26:00 -07:00
|
|
|
set(&v, lir->ins_eq0(get(&v)));
|
|
|
|
return true;
|
|
|
|
}
|
2008-07-03 23:57:57 -07:00
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_BITNOT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
return unary(LIR_not);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_NEG()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-11 21:20:48 -07:00
|
|
|
return unary(LIR_fneg);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_NEW()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DELNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DELPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DELELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_TYPEOF()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_VOID()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-20 13:28:53 -07:00
|
|
|
stack(0, lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID)));
|
2008-07-17 02:00:23 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INCNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INCPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-19 00:15:22 -07:00
|
|
|
return incProp(1);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INCELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-19 00:15:22 -07:00
|
|
|
return incElem(1);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DECNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_DECPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-19 00:15:22 -07:00
|
|
|
return incProp(-1);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_DECELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-19 00:15:22 -07:00
|
|
|
return incElem(-1);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_NAMEINC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_PROPINC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-19 00:15:22 -07:00
|
|
|
return incProp(1, false);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
2008-07-19 00:15:22 -07:00
|
|
|
// XXX consolidate with record_JSOP_GETELEM code...
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ELEMINC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-19 00:15:22 -07:00
|
|
|
return incElem(1, false);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_NAMEDEC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_PROPDEC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-19 00:15:22 -07:00
|
|
|
return incProp(-1, false);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_ELEMDEC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-19 00:15:22 -07:00
|
|
|
return incElem(-1, false);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_GETPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 14:36:50 -07:00
|
|
|
return getProp(stackval(-1));
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_SETPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-17 02:00:23 -07:00
|
|
|
jsval& r = stackval(-1);
|
|
|
|
jsval& l = stackval(-2);
|
|
|
|
|
|
|
|
if (JSVAL_IS_PRIMITIVE(l))
|
|
|
|
ABORT_TRACE("primitive this for SETPROP");
|
|
|
|
|
|
|
|
JSObject* obj = JSVAL_TO_OBJECT(l);
|
|
|
|
|
|
|
|
if (obj->map->ops->setProperty != js_SetProperty)
|
|
|
|
ABORT_TRACE("non-native setProperty");
|
|
|
|
|
|
|
|
LIns* obj_ins = get(&l);
|
|
|
|
|
|
|
|
JSPropertyCache* cache = &JS_PROPERTY_CACHE(cx);
|
|
|
|
uint32 kshape = OBJ_SCOPE(obj)->shape;
|
|
|
|
jsbytecode* pc = cx->fp->regs->pc;
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-17 02:00:23 -07:00
|
|
|
JSPropCacheEntry* entry = &cache->table[PROPERTY_CACHE_HASH_PC(pc, kshape)];
|
|
|
|
if (entry->kpc != pc || entry->kshape != kshape)
|
|
|
|
ABORT_TRACE("cache miss");
|
|
|
|
|
|
|
|
/* XXX share with test_property_cache */
|
|
|
|
LIns* map_ins = lir->insLoadi(obj_ins, offsetof(JSObject, map));
|
|
|
|
if (!map_is_native(obj->map, map_ins))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* XXX share with test_property_cache */
|
|
|
|
if (obj != globalObj) { // global object's shape is guarded at trace entry
|
|
|
|
LIns* shape_ins = addName(lir->insLoadi(map_ins, offsetof(JSScope, shape)), "shape");
|
|
|
|
guard(true, addName(lir->ins2i(LIR_eq, shape_ins, kshape), "guard(shape)"));
|
|
|
|
}
|
|
|
|
|
|
|
|
JSScope* scope = OBJ_SCOPE(obj);
|
|
|
|
if (scope->object != obj)
|
|
|
|
ABORT_TRACE("not scope owner");
|
|
|
|
|
|
|
|
JSScopeProperty* sprop = PCVAL_TO_SPROP(entry->vword);
|
|
|
|
if (!SCOPE_HAS_PROPERTY(scope, sprop))
|
|
|
|
ABORT_TRACE("sprop not in scope");
|
|
|
|
|
|
|
|
LIns* dslots_ins = NULL;
|
|
|
|
LIns* v_ins = get(&r);
|
|
|
|
LIns* boxed_ins = v_ins;
|
|
|
|
if (!box_jsval(r, boxed_ins))
|
|
|
|
return false;
|
|
|
|
if (!native_set(obj_ins, sprop, dslots_ins, boxed_ins))
|
|
|
|
return false;
|
|
|
|
if (pc[JSOP_SETPROP_LENGTH] != JSOP_POP)
|
|
|
|
stack(-2, v_ins);
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_GETELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-05 06:47:59 -07:00
|
|
|
jsval& r = stackval(-1);
|
|
|
|
jsval& l = stackval(-2);
|
2008-07-19 00:15:22 -07:00
|
|
|
jsval* vp;
|
|
|
|
LIns* v_ins;
|
2008-07-19 10:24:10 -07:00
|
|
|
LIns* addr_ins;
|
|
|
|
if (!elem(l, r, vp, v_ins, addr_ins))
|
2008-07-06 10:38:55 -07:00
|
|
|
return false;
|
2008-07-05 13:44:48 -07:00
|
|
|
set(&l, v_ins);
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_SETELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-05 06:47:59 -07:00
|
|
|
jsval& v = stackval(-1);
|
|
|
|
jsval& r = stackval(-2);
|
|
|
|
jsval& l = stackval(-3);
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-05 14:00:32 -07:00
|
|
|
/* no guards for type checks, trace specialized this already */
|
2008-07-06 15:55:04 -07:00
|
|
|
if (!JSVAL_IS_INT(r) || JSVAL_IS_PRIMITIVE(l))
|
2008-07-15 06:07:54 -07:00
|
|
|
ABORT_TRACE("not array[int]");
|
2008-07-05 14:00:32 -07:00
|
|
|
JSObject* obj = JSVAL_TO_OBJECT(l);
|
|
|
|
LIns* obj_ins = get(&l);
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-05 14:00:32 -07:00
|
|
|
/* make sure the object is actually a dense array */
|
|
|
|
LIns* dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
|
|
|
|
if (!guardThatObjectIsDenseArray(obj, obj_ins, dslots_ins))
|
2008-07-15 06:07:54 -07:00
|
|
|
ABORT_TRACE("not a dense array");
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-05 14:00:32 -07:00
|
|
|
/* check that the index is within bounds */
|
2008-07-06 15:55:04 -07:00
|
|
|
jsint idx = JSVAL_TO_INT(r);
|
|
|
|
LIns* idx_ins = f2i(get(&r));
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-06 16:38:54 -07:00
|
|
|
/* we have to check that its really an integer, but this check will to go away
|
|
|
|
once we peel the loop type down to integer for this slot */
|
|
|
|
guard(true, lir->ins2(LIR_feq, get(&r), lir->ins1(LIR_i2f, idx_ins)));
|
2008-07-05 14:00:32 -07:00
|
|
|
if (!guardDenseArrayIndexWithinBounds(obj, idx, obj_ins, dslots_ins, idx_ins))
|
2008-07-15 06:07:54 -07:00
|
|
|
ABORT_TRACE("index out of bounds");
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-05 14:00:32 -07:00
|
|
|
/* get us the address of the array slot */
|
2008-07-07 02:21:04 -07:00
|
|
|
LIns* addr = lir->ins2(LIR_add, dslots_ins,
|
2008-07-05 19:39:34 -07:00
|
|
|
lir->ins2i(LIR_lsh, idx_ins, JS_BYTES_PER_WORD_LOG2));
|
2008-07-05 14:00:32 -07:00
|
|
|
LIns* oldval = lir->insLoad(LIR_ld, addr, 0);
|
2008-07-05 18:50:54 -07:00
|
|
|
LIns* isHole = lir->ins2(LIR_eq, oldval, lir->insImmPtr((void*)JSVAL_HOLE));
|
|
|
|
LIns* count = lir->insLoadi(obj_ins,
|
|
|
|
offsetof(JSObject, fslots[JSSLOT_ARRAY_COUNT]));
|
|
|
|
lir->insStorei(lir->ins2(LIR_add, count, isHole), obj_ins,
|
|
|
|
offsetof(JSObject, fslots[JSSLOT_ARRAY_COUNT]));
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-05 14:00:32 -07:00
|
|
|
/* ok, box the value we are storing, store it and we are done */
|
|
|
|
LIns* v_ins = get(&v);
|
2008-07-06 16:38:54 -07:00
|
|
|
LIns* boxed_ins = v_ins;
|
2008-07-06 13:59:59 -07:00
|
|
|
if (!box_jsval(v, boxed_ins))
|
|
|
|
return false;
|
2008-07-05 19:39:34 -07:00
|
|
|
lir->insStorei(boxed_ins, addr, 0);
|
2008-07-05 14:00:32 -07:00
|
|
|
set(&l, v_ins);
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_CALLNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 15:40:35 -07:00
|
|
|
JSObject* obj = cx->fp->scopeChain;
|
|
|
|
if (obj != globalObj)
|
2008-07-16 19:00:14 -07:00
|
|
|
ABORT_TRACE("fp->scopeChain is not global object");
|
2008-07-16 15:40:35 -07:00
|
|
|
|
|
|
|
LIns* obj_ins = lir->insLoadi(lir->insLoadi(cx_ins, offsetof(JSContext, fp)),
|
|
|
|
offsetof(JSStackFrame, scopeChain));
|
|
|
|
JSObject* obj2;
|
2008-07-17 23:57:56 -07:00
|
|
|
jsuword pcval;
|
|
|
|
if (!test_property_cache(obj, obj_ins, obj2, pcval))
|
2008-07-16 15:40:35 -07:00
|
|
|
ABORT_TRACE("missed prop");
|
|
|
|
|
2008-07-17 23:57:56 -07:00
|
|
|
if (!PCVAL_IS_OBJECT(pcval))
|
2008-07-16 15:40:35 -07:00
|
|
|
ABORT_TRACE("PCE not object");
|
|
|
|
|
2008-07-17 23:57:56 -07:00
|
|
|
stack(0, lir->insImmPtr(PCVAL_TO_OBJECT(pcval)));
|
2008-07-16 15:40:35 -07:00
|
|
|
stack(1, obj_ins);
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
2008-07-11 19:59:09 -07:00
|
|
|
JSBool
|
2008-07-12 12:35:36 -07:00
|
|
|
js_math_sin(JSContext *cx, uintN argc, jsval *vp);
|
2008-07-11 19:59:09 -07:00
|
|
|
|
2008-07-11 21:03:33 -07:00
|
|
|
JSBool
|
2008-07-12 12:35:36 -07:00
|
|
|
js_math_cos(JSContext *cx, uintN argc, jsval *vp);
|
2008-07-11 21:03:33 -07:00
|
|
|
|
|
|
|
JSBool
|
2008-07-12 12:35:36 -07:00
|
|
|
js_math_pow(JSContext *cx, uintN argc, jsval *vp);
|
2008-07-11 21:03:33 -07:00
|
|
|
|
2008-07-14 15:22:05 -07:00
|
|
|
JSBool
|
|
|
|
js_math_sqrt(JSContext *cx, uintN argc, jsval *vp);
|
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_CALL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-11 19:59:09 -07:00
|
|
|
uintN argc = GET_ARGC(cx->fp->regs->pc);
|
|
|
|
jsval& fval = stackval(-(argc + 2));
|
|
|
|
|
|
|
|
if (!VALUE_IS_FUNCTION(cx, fval))
|
|
|
|
ABORT_TRACE("CALL on non-function");
|
|
|
|
|
|
|
|
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(fval));
|
2008-07-16 15:01:55 -07:00
|
|
|
if (FUN_INTERPRETED(fun)) {
|
|
|
|
// TODO: make sure args are not copied, or track the copying via the tracker
|
|
|
|
if (fun->nargs != argc)
|
|
|
|
ABORT_TRACE("can't trace function calls with arity mismatch");
|
|
|
|
unsigned callDepth = getCallDepth();
|
2008-07-19 00:15:22 -07:00
|
|
|
lir->insStorei(lir->insImmPtr(JSVAL_TO_OBJECT(fval)),
|
2008-07-16 15:01:55 -07:00
|
|
|
lirbuf->rp, callDepth * sizeof(JSObject*));
|
2008-07-21 12:41:43 -07:00
|
|
|
if (callDepth+1 > treeInfo->maxCallDepth)
|
|
|
|
treeInfo->maxCallDepth = callDepth+1;
|
2008-07-19 06:29:56 -07:00
|
|
|
atoms = fun->u.i.script->atomMap.vector;
|
2008-07-16 15:01:55 -07:00
|
|
|
return true;
|
2008-07-19 00:15:22 -07:00
|
|
|
}
|
2008-07-11 19:59:09 -07:00
|
|
|
|
2008-07-13 21:28:31 -07:00
|
|
|
if (FUN_SLOW_NATIVE(fun))
|
|
|
|
ABORT_TRACE("slow native");
|
|
|
|
|
|
|
|
struct JSTraceableNative {
|
|
|
|
JSFastNative native;
|
|
|
|
int builtin;
|
|
|
|
intN argc;
|
|
|
|
const char *argtypes;
|
|
|
|
} knownNatives[] = {
|
2008-07-14 15:22:05 -07:00
|
|
|
{ js_math_sin, F_Math_sin, 1, "d" },
|
|
|
|
{ js_math_cos, F_Math_cos, 1, "d" },
|
|
|
|
{ js_math_pow, F_Math_pow, 2, "dd" },
|
|
|
|
{ js_math_sqrt, F_Math_sqrt, 1, "d" }
|
2008-07-13 21:28:31 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
for (uintN i = 0; i < JS_ARRAY_LENGTH(knownNatives); i++) {
|
|
|
|
JSTraceableNative* known = &knownNatives[i];
|
|
|
|
if ((JSFastNative)fun->u.n.native != known->native)
|
|
|
|
continue;
|
2008-07-15 10:26:15 -07:00
|
|
|
|
2008-07-13 21:28:31 -07:00
|
|
|
LIns* args[5];
|
|
|
|
LIns** argp = &args[argc-1];
|
|
|
|
switch (known->argc) {
|
|
|
|
case 2:
|
|
|
|
JS_ASSERT(known->argtypes[1] == 'd');
|
|
|
|
if (!isNumber(stackval(-2)))
|
|
|
|
ABORT_TRACE("2nd arg must be numeric");
|
|
|
|
*argp = get(&stackval(-2));
|
|
|
|
argp--;
|
|
|
|
/* FALL THROUGH */
|
|
|
|
case 1:
|
|
|
|
JS_ASSERT(known->argtypes[0] == 'd');
|
|
|
|
if (!isNumber(stackval(-1)))
|
|
|
|
ABORT_TRACE("1st arg must be numeric");
|
|
|
|
*argp = get(&stackval(-1));
|
|
|
|
/* FALL THROUGH */
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
JS_ASSERT(0 && "illegal number of args to traceable native");
|
|
|
|
}
|
2008-07-15 10:26:15 -07:00
|
|
|
|
2008-07-13 21:28:31 -07:00
|
|
|
set(&fval, lir->insCall(known->builtin, args));
|
|
|
|
return true;
|
2008-07-11 21:03:33 -07:00
|
|
|
}
|
2008-07-13 21:28:31 -07:00
|
|
|
|
|
|
|
/* Didn't find it. */
|
|
|
|
ABORT_TRACE("unknown native");
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-09 11:42:31 -07:00
|
|
|
|
2008-07-16 22:58:06 -07:00
|
|
|
bool
|
2008-07-16 23:00:59 -07:00
|
|
|
TraceRecorder::record_EnterFrame()
|
2008-07-16 22:58:06 -07:00
|
|
|
{
|
2008-07-21 13:18:08 -07:00
|
|
|
++callDepth;
|
2008-07-16 22:58:06 -07:00
|
|
|
JSStackFrame* fp = cx->fp;
|
|
|
|
LIns* void_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
2008-07-21 12:57:02 -07:00
|
|
|
set(&fp->rval, void_ins, true);
|
2008-07-16 22:58:06 -07:00
|
|
|
unsigned n;
|
2008-07-16 23:04:50 -07:00
|
|
|
for (n = 0; n < fp->nvars; ++n)
|
2008-07-21 12:57:02 -07:00
|
|
|
set(&fp->vars[n], void_ins, true);
|
2008-07-16 22:58:06 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-15 10:17:51 -07:00
|
|
|
bool
|
2008-07-19 10:24:28 -07:00
|
|
|
TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
|
2008-07-15 10:17:51 -07:00
|
|
|
{
|
2008-07-19 00:15:22 -07:00
|
|
|
/*
|
|
|
|
* Can't specialize to assert obj != global, must guard to avoid aliasing
|
|
|
|
* stale homes of stacked global variables.
|
|
|
|
*/
|
|
|
|
if (obj == globalObj)
|
|
|
|
ABORT_TRACE("prop op aliases global");
|
|
|
|
guard(false, lir->ins2(LIR_eq, obj_ins, lir->insImmPtr((void*)globalObj)));
|
|
|
|
|
2008-07-15 10:17:51 -07:00
|
|
|
if (!test_property_cache_direct_slot(obj, obj_ins, slot))
|
|
|
|
return false;
|
|
|
|
|
2008-07-15 10:40:11 -07:00
|
|
|
LIns* dslots_ins = NULL;
|
2008-07-19 00:15:22 -07:00
|
|
|
v_ins = stobj_get_slot(obj_ins, slot, dslots_ins);
|
2008-07-19 10:24:28 -07:00
|
|
|
if (!unbox_jsval(STOBJ_GET_SLOT(obj, slot), v_ins))
|
2008-07-15 10:17:51 -07:00
|
|
|
ABORT_TRACE("unboxing");
|
2008-07-19 00:15:22 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2008-07-19 10:24:10 -07:00
|
|
|
TraceRecorder::elem(jsval& l, jsval& r, jsval*& vp, LIns*& v_ins, LIns*& addr_ins)
|
2008-07-19 00:15:22 -07:00
|
|
|
{
|
|
|
|
/* no guards for type checks, trace specialized this already */
|
|
|
|
if (!JSVAL_IS_INT(r) || JSVAL_IS_PRIMITIVE(l))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Can't specialize to assert obj != global, must guard to avoid aliasing
|
|
|
|
* stale homes of stacked global variables.
|
|
|
|
*/
|
|
|
|
JSObject* obj = JSVAL_TO_OBJECT(l);
|
|
|
|
if (obj == globalObj)
|
|
|
|
ABORT_TRACE("elem op aliases global");
|
|
|
|
LIns* obj_ins = get(&l);
|
|
|
|
guard(false, lir->ins2(LIR_eq, obj_ins, lir->insImmPtr((void*)globalObj)));
|
|
|
|
|
|
|
|
/* make sure the object is actually a dense array */
|
|
|
|
LIns* dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
|
|
|
|
if (!guardThatObjectIsDenseArray(obj, obj_ins, dslots_ins))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* check that the index is within bounds */
|
|
|
|
jsint idx = JSVAL_TO_INT(r);
|
|
|
|
LIns* idx_ins = f2i(get(&r));
|
|
|
|
|
|
|
|
/* we have to check that its really an integer, but this check will to go away
|
|
|
|
once we peel the loop type down to integer for this slot */
|
|
|
|
guard(true, lir->ins2(LIR_feq, get(&r), lir->ins1(LIR_i2f, idx_ins)));
|
|
|
|
if (!guardDenseArrayIndexWithinBounds(obj, idx, obj_ins, dslots_ins, idx_ins))
|
|
|
|
return false;
|
|
|
|
vp = &obj->dslots[idx];
|
|
|
|
|
2008-07-19 10:24:10 -07:00
|
|
|
addr_ins = lir->ins2(LIR_add, dslots_ins,
|
|
|
|
lir->ins2i(LIR_lsh, idx_ins, sizeof(jsval) == 4 ? 2 : 3));
|
2008-07-19 00:15:22 -07:00
|
|
|
/* load the value, check the type (need to check JSVAL_HOLE only for booleans) */
|
2008-07-19 10:24:10 -07:00
|
|
|
v_ins = lir->insLoad(LIR_ld, addr_ins, 0);
|
2008-07-19 00:15:22 -07:00
|
|
|
return unbox_jsval(*vp, v_ins);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
TraceRecorder::getProp(JSObject* obj, LIns* obj_ins)
|
|
|
|
{
|
2008-07-19 10:24:28 -07:00
|
|
|
uint32 slot;
|
2008-07-19 00:15:22 -07:00
|
|
|
LIns* v_ins;
|
2008-07-19 10:24:28 -07:00
|
|
|
if (!prop(obj, obj_ins, slot, v_ins))
|
2008-07-19 00:15:22 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
|
|
|
|
JS_ASSERT(cs.ndefs == 1);
|
|
|
|
stack(-cs.nuses, v_ins);
|
2008-07-15 10:17:51 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2008-07-16 14:36:50 -07:00
|
|
|
TraceRecorder::getProp(jsval& v)
|
2008-07-15 10:17:51 -07:00
|
|
|
{
|
|
|
|
if (JSVAL_IS_PRIMITIVE(v))
|
|
|
|
ABORT_TRACE("primitive lhs");
|
|
|
|
|
2008-07-16 14:36:50 -07:00
|
|
|
return getProp(JSVAL_TO_OBJECT(v), get(&v));
|
2008-07-15 10:17:51 -07:00
|
|
|
}
|
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_NAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-09 15:15:32 -07:00
|
|
|
JSObject* obj = cx->fp->scopeChain;
|
2008-07-14 16:40:38 -07:00
|
|
|
if (obj != globalObj)
|
2008-07-06 09:15:55 -07:00
|
|
|
return false;
|
|
|
|
|
2008-07-09 11:42:31 -07:00
|
|
|
LIns* obj_ins = lir->insLoadi(lir->insLoadi(cx_ins, offsetof(JSContext, fp)),
|
|
|
|
offsetof(JSStackFrame, scopeChain));
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-16 14:36:50 -07:00
|
|
|
/* Can't use getProp here, because we don't want unboxing. */
|
2008-07-09 11:42:31 -07:00
|
|
|
uint32 slot;
|
|
|
|
if (!test_property_cache_direct_slot(obj, obj_ins, slot))
|
2008-07-06 09:15:55 -07:00
|
|
|
return false;
|
2008-07-06 10:38:55 -07:00
|
|
|
|
2008-07-20 14:23:39 -07:00
|
|
|
if (!tracker.has(&STOBJ_GET_SLOT(obj, slot)))
|
|
|
|
ABORT_TRACE("JSOP_NAME on non-interned global: save us, upvar!");
|
|
|
|
|
2008-07-13 21:14:34 -07:00
|
|
|
stack(0, get(&STOBJ_GET_SLOT(obj, slot)));
|
2008-07-06 09:15:55 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-09 11:42:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DOUBLE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
jsval v = jsval(atoms[GET_INDEX(cx->fp->regs->pc)]);
|
2008-07-14 15:22:05 -07:00
|
|
|
jsdpun u;
|
|
|
|
u.d = *JSVAL_TO_DOUBLE(v);
|
|
|
|
stack(0, lir->insImmq(u.u64));
|
2008-07-05 23:21:53 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_STRING()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ZERO()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-14 15:22:05 -07:00
|
|
|
jsdpun u;
|
|
|
|
u.d = 0.0;
|
|
|
|
stack(0, lir->insImmq(u.u64));
|
2008-07-05 06:15:33 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ONE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-14 15:22:05 -07:00
|
|
|
jsdpun u;
|
|
|
|
u.d = 1.0;
|
|
|
|
stack(0, lir->insImmq(u.u64));
|
2008-07-05 06:15:33 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_NULL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-05 17:26:00 -07:00
|
|
|
stack(0, lir->insImmPtr(NULL));
|
2008-07-05 06:15:33 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_THIS()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 14:36:50 -07:00
|
|
|
LIns* this_ins;
|
|
|
|
if (!getThis(this_ins))
|
|
|
|
return false;
|
|
|
|
stack(0, this_ins);
|
2008-07-15 18:37:00 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_FALSE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-05 06:15:33 -07:00
|
|
|
stack(0, lir->insImm(0));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_TRUE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-05 06:15:33 -07:00
|
|
|
stack(0, lir->insImm(1));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_OR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 13:16:34 -07:00
|
|
|
return false;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_AND()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 13:16:34 -07:00
|
|
|
return false;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_TABLESWITCH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_LOOKUPSWITCH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_STRICTEQ()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_STRICTNE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_CLOSURE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_EXPORTALL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_EXPORTNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_IMPORTALL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_IMPORTPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_IMPORTELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_OBJECT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_POP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_POS()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_TRAP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GETARG()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-04 03:06:18 -07:00
|
|
|
stack(0, arg(GET_ARGNO(cx->fp->regs->pc)));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SETARG()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-04 15:21:56 -07:00
|
|
|
arg(GET_ARGNO(cx->fp->regs->pc), stack(-1));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GETVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-04 03:06:18 -07:00
|
|
|
stack(0, var(GET_VARNO(cx->fp->regs->pc)));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SETVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-04 15:21:56 -07:00
|
|
|
var(GET_VARNO(cx->fp->regs->pc), stack(-1));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_UINT16()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-14 15:22:05 -07:00
|
|
|
jsdpun u;
|
|
|
|
u.d = (jsdouble)GET_UINT16(cx->fp->regs->pc);
|
|
|
|
stack(0, lir->insImmq(u.u64));
|
2008-07-04 03:06:18 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_NEWINIT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ENDINIT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INITPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INITELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DEFSHARP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_USESHARP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INCARG()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-09 15:15:32 -07:00
|
|
|
return inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INCVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-09 15:15:32 -07:00
|
|
|
return inc(varval(GET_VARNO(cx->fp->regs->pc)), 1);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DECARG()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-09 15:15:32 -07:00
|
|
|
return inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DECVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-09 15:15:32 -07:00
|
|
|
return inc(varval(GET_VARNO(cx->fp->regs->pc)), -1);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ARGINC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-04 03:06:18 -07:00
|
|
|
return inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1, false);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_VARINC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-04 03:06:18 -07:00
|
|
|
return inc(varval(GET_VARNO(cx->fp->regs->pc)), 1, false);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ARGDEC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-04 03:06:18 -07:00
|
|
|
return inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1, false);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_VARDEC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-04 03:06:18 -07:00
|
|
|
return inc(varval(GET_VARNO(cx->fp->regs->pc)), -1, false);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ITER()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_FORNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_FORPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_FORELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_POPN()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_BINDNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-09 15:15:32 -07:00
|
|
|
JSObject* obj = cx->fp->scopeChain;
|
2008-07-14 16:40:38 -07:00
|
|
|
if (obj != globalObj)
|
2008-07-09 15:15:32 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
LIns* obj_ins = lir->insLoadi(lir->insLoadi(cx_ins, offsetof(JSContext, fp)),
|
|
|
|
offsetof(JSStackFrame, scopeChain));
|
|
|
|
JSObject* obj2;
|
2008-07-17 23:57:56 -07:00
|
|
|
jsuword pcval;
|
|
|
|
if (!test_property_cache(obj, obj_ins, obj2, pcval))
|
2008-07-09 15:15:32 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
stack(0, obj_ins);
|
2008-07-04 23:53:29 -07:00
|
|
|
return true;
|
2008-07-05 10:41:35 -07:00
|
|
|
}
|
2008-07-09 11:42:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SETNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-09 16:37:31 -07:00
|
|
|
jsval& r = stackval(-1);
|
|
|
|
jsval& l = stackval(-2);
|
2008-07-09 09:59:51 -07:00
|
|
|
|
2008-07-08 18:07:27 -07:00
|
|
|
if (JSVAL_IS_PRIMITIVE(l))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
2008-07-09 11:42:31 -07:00
|
|
|
* Trace cases that are global code or in lightweight functions scoped by
|
|
|
|
* the global object only.
|
2008-07-08 18:07:27 -07:00
|
|
|
*/
|
2008-07-09 11:42:31 -07:00
|
|
|
JSObject* obj = JSVAL_TO_OBJECT(l);
|
2008-07-14 16:40:38 -07:00
|
|
|
if (obj != cx->fp->scopeChain || obj != globalObj)
|
2008-07-08 18:07:27 -07:00
|
|
|
return false;
|
|
|
|
|
2008-07-09 11:42:31 -07:00
|
|
|
LIns* obj_ins = get(&l);
|
|
|
|
uint32 slot;
|
|
|
|
if (!test_property_cache_direct_slot(obj, obj_ins, slot))
|
2008-07-08 18:07:27 -07:00
|
|
|
return false;
|
2008-07-09 09:59:51 -07:00
|
|
|
|
2008-07-09 11:42:31 -07:00
|
|
|
LIns* r_ins = get(&r);
|
2008-07-13 21:14:34 -07:00
|
|
|
set(&STOBJ_GET_SLOT(obj, slot), r_ins);
|
2008-07-09 09:59:51 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
if (cx->fp->regs->pc[JSOP_SETNAME_LENGTH] != JSOP_POP)
|
2008-07-09 11:42:31 -07:00
|
|
|
stack(-2, r_ins);
|
2008-07-08 18:07:27 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-08 18:07:27 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_THROW()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_IN()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INSTANCEOF()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DEBUGGER()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GOSUB()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_RETSUB()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_EXCEPTION()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_LINENO()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_CONDSWITCH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_CASE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DEFAULT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_EVAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ENUMELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GETTER()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SETTER()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DEFFUN()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DEFCONST()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DEFVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ANONFUNOBJ()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_NAMEDFUNOBJ()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SETLOCALPOP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GROUP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-05 06:15:33 -07:00
|
|
|
return true; // no-op
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SETCALL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_TRY()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_FINALLY()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_NOP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ARGSUB()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ARGCNT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-19 15:42:31 -07:00
|
|
|
|
2008-07-19 06:29:56 -07:00
|
|
|
/*
|
|
|
|
* XXX could hoist out to jsinterp.h and share with jsinterp.cpp, but
|
|
|
|
* XXX jsopcode.cpp has different definitions of same-named macros.
|
|
|
|
*/
|
|
|
|
#define GET_FULL_INDEX(PCOFF) \
|
|
|
|
(atoms - script->atomMap.vector + GET_INDEX(regs.pc + PCOFF))
|
|
|
|
|
|
|
|
#define LOAD_FUNCTION(PCOFF) \
|
|
|
|
JS_GET_SCRIPT_FUNCTION(script, GET_FULL_INDEX(PCOFF), fun)
|
2008-07-19 15:42:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DEFLOCALFUN()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-19 06:29:56 -07:00
|
|
|
JSFunction* fun;
|
|
|
|
JSFrameRegs& regs = *cx->fp->regs;
|
|
|
|
JSScript* script = cx->fp->script;
|
|
|
|
LOAD_FUNCTION(VARNO_LEN);
|
|
|
|
|
|
|
|
JSObject* obj = FUN_OBJECT(fun);
|
|
|
|
if (OBJ_GET_PARENT(cx, obj) != cx->fp->scopeChain)
|
|
|
|
ABORT_TRACE("can't trace with activation object on scopeChain");
|
|
|
|
|
|
|
|
var(GET_VARNO(regs.pc), lir->insImmPtr(obj));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-19 15:42:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GOTOX()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_IFEQX()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
return record_JSOP_IFEQ();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_IFNEX()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
return record_JSOP_IFNE();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ORX()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
return record_JSOP_OR();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ANDX()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
return record_JSOP_AND();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GOSUBX()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
return record_JSOP_GOSUB();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_CASEX()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
return record_JSOP_CASE();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DEFAULTX()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
return record_JSOP_DEFAULT();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_TABLESWITCHX()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
return record_JSOP_TABLESWITCH();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_LOOKUPSWITCHX()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
return record_JSOP_LOOKUPSWITCH();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_BACKPATCH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_BACKPATCH_POP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_THROWING()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SETRVAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_RETRVAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GETGVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 13:59:59 -07:00
|
|
|
jsval slotval = cx->fp->vars[GET_VARNO(cx->fp->regs->pc)];
|
|
|
|
if (JSVAL_IS_NULL(slotval))
|
|
|
|
return true; // We will see JSOP_NAME from the interpreter's jump, so no-op here.
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-06 13:59:59 -07:00
|
|
|
uint32 slot = JSVAL_TO_INT(slotval);
|
2008-07-13 21:14:34 -07:00
|
|
|
stack(0, get(&STOBJ_GET_SLOT(cx->fp->scopeChain, slot)));
|
2008-07-06 13:59:59 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SETGVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-07 17:21:54 -07:00
|
|
|
jsval slotval = cx->fp->vars[GET_VARNO(cx->fp->regs->pc)];
|
|
|
|
if (JSVAL_IS_NULL(slotval))
|
|
|
|
return true; // We will see JSOP_NAME from the interpreter's jump, so no-op here.
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-07 17:21:54 -07:00
|
|
|
uint32 slot = JSVAL_TO_INT(slotval);
|
2008-07-13 21:14:34 -07:00
|
|
|
set(&STOBJ_GET_SLOT(cx->fp->scopeChain, slot), stack(-1));
|
2008-07-07 17:21:54 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INCGVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-06 13:59:59 -07:00
|
|
|
jsval slotval = cx->fp->vars[GET_VARNO(cx->fp->regs->pc)];
|
|
|
|
if (JSVAL_IS_NULL(slotval))
|
|
|
|
return true; // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-06 13:59:59 -07:00
|
|
|
uint32 slot = JSVAL_TO_INT(slotval);
|
2008-07-13 21:14:34 -07:00
|
|
|
return inc(STOBJ_GET_SLOT(cx->fp->scopeChain, slot), 1);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DECGVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-07 17:21:54 -07:00
|
|
|
jsval slotval = cx->fp->vars[GET_VARNO(cx->fp->regs->pc)];
|
|
|
|
if (JSVAL_IS_NULL(slotval))
|
|
|
|
return true; // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-07 17:21:54 -07:00
|
|
|
uint32 slot = JSVAL_TO_INT(slotval);
|
2008-07-13 21:14:34 -07:00
|
|
|
return inc(STOBJ_GET_SLOT(cx->fp->scopeChain, slot), -1);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GVARINC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-07 17:21:54 -07:00
|
|
|
jsval slotval = cx->fp->vars[GET_VARNO(cx->fp->regs->pc)];
|
|
|
|
if (JSVAL_IS_NULL(slotval))
|
|
|
|
return true; // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-07 17:21:54 -07:00
|
|
|
uint32 slot = JSVAL_TO_INT(slotval);
|
2008-07-13 21:14:34 -07:00
|
|
|
return inc(STOBJ_GET_SLOT(cx->fp->scopeChain, slot), 1, false);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GVARDEC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-07 17:21:54 -07:00
|
|
|
jsval slotval = cx->fp->vars[GET_VARNO(cx->fp->regs->pc)];
|
|
|
|
if (JSVAL_IS_NULL(slotval))
|
|
|
|
return true; // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-07 17:21:54 -07:00
|
|
|
uint32 slot = JSVAL_TO_INT(slotval);
|
2008-07-13 21:14:34 -07:00
|
|
|
return inc(STOBJ_GET_SLOT(cx->fp->scopeChain, slot), -1, false);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-09 16:37:31 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_REGEXP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DEFXMLNS()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ANYNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_QNAMEPART()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_QNAMECONST()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_QNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_TOATTRNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_TOATTRVAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ADDATTRNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ADDATTRVAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_BINDXMLNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_SETXMLNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_XMLNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DESCENDANTS()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_FILTER()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_ENDFILTER()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_TOXML()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_TOXMLLIST()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_XMLTAGEXPR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_XMLELTEXPR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_XMLOBJECT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_XMLCDATA()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_XMLCOMMENT()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_XMLPI()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-12 12:35:36 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_CALLPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-11 17:59:10 -07:00
|
|
|
jsval& l = stackval(-1);
|
|
|
|
if (JSVAL_IS_PRIMITIVE(l))
|
|
|
|
ABORT_TRACE("CALLPROP on primitive");
|
|
|
|
|
2008-07-11 19:59:09 -07:00
|
|
|
JSObject* obj = JSVAL_TO_OBJECT(l);
|
2008-07-11 17:59:10 -07:00
|
|
|
LIns* obj_ins = get(&l);
|
2008-07-11 19:59:09 -07:00
|
|
|
JSObject* obj2;
|
2008-07-17 23:57:56 -07:00
|
|
|
jsuword pcval;
|
|
|
|
if (!test_property_cache(obj, obj_ins, obj2, pcval))
|
2008-07-11 19:59:09 -07:00
|
|
|
ABORT_TRACE("missed prop");
|
|
|
|
|
2008-07-17 23:57:56 -07:00
|
|
|
if (!PCVAL_IS_OBJECT(pcval))
|
2008-07-11 19:59:09 -07:00
|
|
|
ABORT_TRACE("PCE not object");
|
|
|
|
|
2008-07-17 23:57:56 -07:00
|
|
|
stack(-1, lir->insImmPtr(PCVAL_TO_OBJECT(pcval)));
|
2008-07-11 19:59:09 -07:00
|
|
|
stack(0, obj_ins);
|
2008-07-11 17:59:10 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-12 12:35:36 -07:00
|
|
|
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_GETFUNNS()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_UNUSED186()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DELDESC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_UINT24()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-14 15:22:05 -07:00
|
|
|
jsdpun u;
|
|
|
|
u.d = (jsdouble)GET_UINT24(cx->fp->regs->pc);
|
|
|
|
stack(0, lir->insImmq(u.u64));
|
2008-07-04 03:06:18 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INDEXBASE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
atoms += GET_INDEXBASE(cx->fp->regs->pc);
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_RESETBASE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
atoms = cx->fp->script->atomMap.vector;
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_RESETBASE0()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
atoms = cx->fp->script->atomMap.vector;
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_STARTXML()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_STARTXMLEXPR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_CALLELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_STOP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-21 13:18:08 -07:00
|
|
|
return (callDepth-- > 0);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_GETXPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 10:10:17 -07:00
|
|
|
jsval& l = stackval(-1);
|
|
|
|
if (JSVAL_IS_PRIMITIVE(l))
|
|
|
|
ABORT_TRACE("primitive-this for GETXPROP?");
|
2008-07-19 00:15:22 -07:00
|
|
|
|
2008-07-16 10:10:17 -07:00
|
|
|
JSObject* obj = JSVAL_TO_OBJECT(l);
|
|
|
|
JS_ASSERT(obj == cx->fp->scopeChain);
|
|
|
|
LIns* obj_ins = get(&l);
|
|
|
|
|
|
|
|
/* Can't use get_prop here, because we don't want unboxing. */
|
|
|
|
uint32 slot;
|
|
|
|
if (!test_property_cache_direct_slot(obj, obj_ins, slot))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
stack(-1, get(&STOBJ_GET_SLOT(obj, slot)));
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_CALLXMLNAME()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_TYPEOFEXPR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_ENTERBLOCK()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_LEAVEBLOCK()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_GETLOCAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_SETLOCAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_INCLOCAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_DECLOCAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_LOCALINC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_LOCALDEC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_FORLOCAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_FORCONST()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_ENDITER()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_GENERATOR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_YIELD()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_ARRAYPUSH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_UNUSED213()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_ENUMCONSTELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_LEAVEBLOCKEXPR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_GETTHISPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 14:36:50 -07:00
|
|
|
LIns* this_ins;
|
2008-07-19 00:15:22 -07:00
|
|
|
|
|
|
|
/* its safe to just use cx->fp->thisp here because getThis() returns false if thisp
|
2008-07-16 14:36:50 -07:00
|
|
|
is not available */
|
|
|
|
return getThis(this_ins) && getProp(cx->fp->thisp, this_ins);
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_GETARGPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 14:36:50 -07:00
|
|
|
return getProp(argval(GET_ARGNO(cx->fp->regs->pc)));
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_GETVARPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 14:36:50 -07:00
|
|
|
return getProp(varval(GET_VARNO(cx->fp->regs->pc)));
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_GETLOCALPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_INDEXBASE1()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
atoms += 1 << 16;
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_INDEXBASE2()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
atoms += 2 << 16;
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_INDEXBASE3()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-10 21:55:09 -07:00
|
|
|
atoms += 3 << 16;
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_CALLGVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-17 02:00:23 -07:00
|
|
|
return record_JSOP_GETGVAR();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_CALLVAR()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 15:13:27 -07:00
|
|
|
stack(1, lir->insImmPtr(0));
|
2008-07-15 20:37:57 -07:00
|
|
|
return record_JSOP_GETVAR();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_CALLARG()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 15:13:27 -07:00
|
|
|
stack(1, lir->insImmPtr(0));
|
2008-07-15 20:37:57 -07:00
|
|
|
return record_JSOP_GETARG();
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_CALLLOCAL()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_INT8()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-14 15:22:05 -07:00
|
|
|
jsdpun u;
|
|
|
|
u.d = (jsdouble)GET_INT8(cx->fp->regs->pc);
|
|
|
|
stack(0, lir->insImmq(u.u64));
|
2008-07-04 03:06:18 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_INT32()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-14 15:22:05 -07:00
|
|
|
jsdpun u;
|
|
|
|
u.d = (jsdouble)GET_INT32(cx->fp->regs->pc);
|
|
|
|
stack(0, lir->insImmq(u.u64));
|
2008-07-04 03:06:18 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_LENGTH()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 23:53:14 -07:00
|
|
|
jsval& l = stackval(-1);
|
|
|
|
JSObject *obj;
|
|
|
|
if (JSVAL_IS_PRIMITIVE(l) || !OBJ_IS_DENSE_ARRAY(cx, (obj = JSVAL_TO_OBJECT(l))))
|
|
|
|
ABORT_TRACE("only dense arrays supported");
|
|
|
|
LIns* dslots_ins;
|
|
|
|
if (!guardThatObjectIsDenseArray(obj, get(&l), dslots_ins))
|
|
|
|
ABORT_TRACE("OBJ_IS_DENSE_ARRAY but not?!?");
|
|
|
|
LIns* v_ins = lir->ins1(LIR_i2f, stobj_get_slot(get(&l), JSSLOT_ARRAY_LENGTH, dslots_ins));
|
|
|
|
set(&l, v_ins);
|
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_NEWARRAY()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_HOLE()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
2008-07-16 22:25:56 -07:00
|
|
|
stack(0, lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_HOLE)));
|
2008-07-06 06:52:50 -07:00
|
|
|
return true;
|
2008-07-03 23:57:57 -07:00
|
|
|
}
|