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-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
|
|
|
|
#define ABORT_TRACE(msg) do { fprintf(stderr, "abort: %d: %s\n", __LINE__, msg); return false; } while(0)
|
|
|
|
#else
|
|
|
|
#define ABORT_TRACE(msg) return false
|
|
|
|
#endif
|
|
|
|
|
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-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-06-21 14:55:32 -07:00
|
|
|
JS_ASSERT(p != 0); /* 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-06-22 19:58:24 -07:00
|
|
|
JS_ASSERT(i != 0);
|
|
|
|
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);
|
|
|
|
return d == (jsint)d;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isPromoteInt(LIns *i)
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
|
|
static bool isPromoteUint(LIns *i)
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
|
|
static bool isPromote(LIns *i)
|
|
|
|
{
|
|
|
|
return isPromoteInt(i) || isPromoteUint(i);;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-07 00:43:40 -07:00
|
|
|
FuncFilter(LirWriter *out, TraceRecorder& _recorder):
|
|
|
|
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-10 21:55:09 -07:00
|
|
|
case LIR_i2f:
|
2008-07-16 23:38:39 -07:00
|
|
|
if (s0->oprnd1()->isCall() && s0->oprnd1()->fid() == F_doubleToInt32)
|
|
|
|
return callArgN(s0->oprnd1(), 0);
|
2008-07-06 17:43:08 -07:00
|
|
|
break;
|
2008-07-10 21:55:09 -07:00
|
|
|
case LIR_u2f:
|
2008-07-16 23:38:39 -07:00
|
|
|
if (s0->oprnd1()->isCall() && s0->oprnd1()->fid() == F_doubleToUint32)
|
|
|
|
return callArgN(s0->oprnd1(), 0);
|
2008-07-06 17:43:08 -07:00
|
|
|
break;
|
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
|
|
|
|
|
|
|
LInsp ins2(LOpcode v, LInsp s1, LInsp s0)
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
return out->ins2(v, demote(out, s1), demote(out, s0));
|
|
|
|
} 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
|
|
|
|
return out->ins2(v, demote(out, s1), demote(out, s0));
|
|
|
|
}
|
2008-07-07 00:43:40 -07:00
|
|
|
} else if (v == LIR_fadd || v == LIR_fsub || v == LIR_fmul) {
|
|
|
|
if (isPromoteInt(s0) && isPromoteInt(s1)) {
|
|
|
|
// demote fop to op
|
|
|
|
v = (LOpcode)((int)v & ~LIR64);
|
|
|
|
LIns* result = out->ins2(v, demote(out, s1), demote(out, s0));
|
|
|
|
out->insGuard(LIR_xt, out->ins1(LIR_ov, result), recorder.snapshot());
|
|
|
|
return out->ins1(LIR_i2f, result);
|
|
|
|
}
|
2008-07-05 22:20:35 -07:00
|
|
|
}
|
|
|
|
return out->ins2(v, s1, s0);
|
|
|
|
}
|
|
|
|
|
|
|
|
LInsp insCall(int32_t fid, LInsp args[])
|
|
|
|
{
|
2008-07-06 20:27:50 -07:00
|
|
|
LInsp s0 = args[0];
|
2008-07-06 16:38:54 -07:00
|
|
|
switch (fid) {
|
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-15 01:53:39 -07:00
|
|
|
#define FORALL_SLOTS_IN_PENDING_FRAMES(cx, ngslots, gslots, entryFrame, currentFrame, 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
|
|
|
} \
|
|
|
|
/* count the number of pending frames */ \
|
|
|
|
unsigned frames = 0; \
|
|
|
|
JSStackFrame* fp = currentFrame; \
|
2008-07-08 20:06:54 -07:00
|
|
|
for (;; fp = fp->down) { ++frames; if (fp == entryFrame) break; }; \
|
2008-07-08 16:29:23 -07:00
|
|
|
/* stack them up since we want forward order (this should be fast */ \
|
|
|
|
/* now, since the previous loop prefetched everything for us and */ \
|
2008-07-08 22:40:07 -07:00
|
|
|
/* the list tends to be short anyway [1-3 frames]). */ \
|
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-08 17:14:01 -07:00
|
|
|
vp = &f->argv[0]; vpstop = &f->argv[f->argc]; \
|
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-06 11:48:41 -07:00
|
|
|
class ExitFilter: public LirWriter
|
|
|
|
{
|
2008-07-15 01:27:14 -07:00
|
|
|
JSContext* _cx;
|
|
|
|
JSStackFrame* _entryFrame;
|
|
|
|
Fragment* _fragment;
|
|
|
|
Tracker* _tracker;
|
2008-07-06 11:48:41 -07:00
|
|
|
public:
|
2008-07-15 10:26:15 -07:00
|
|
|
ExitFilter(LirWriter *out, JSContext* cx, JSStackFrame* entryFrame,
|
2008-07-15 01:27:14 -07:00
|
|
|
Fragment* fragment, Tracker* tracker):
|
2008-07-15 10:26:15 -07:00
|
|
|
LirWriter(out), _cx(cx),
|
|
|
|
_entryFrame(entryFrame),
|
2008-07-15 01:53:39 -07:00
|
|
|
_fragment(fragment), _tracker(tracker)
|
2008-07-06 11:48:41 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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-15 16:04:08 -07:00
|
|
|
uint8 getStoreType(jsval& v) {
|
2008-07-15 01:27:14 -07:00
|
|
|
LIns* i = _tracker->get(&v);
|
2008-07-07 02:21:04 -07:00
|
|
|
int t = isNumber(v)
|
2008-07-11 13:18:29 -07:00
|
|
|
? (isPromoteInt(i) ? JSVAL_INT : JSVAL_DOUBLE)
|
2008-07-09 17:10:42 -07:00
|
|
|
: JSVAL_TAG(v);
|
2008-07-06 15:55:04 -07:00
|
|
|
return t;
|
2008-07-06 11:48:41 -07:00
|
|
|
}
|
2008-07-07 02:21:04 -07:00
|
|
|
|
2008-07-06 11:48:41 -07:00
|
|
|
/* Write out a type map for the current scopes and all outer scopes,
|
|
|
|
up until the entry scope. */
|
|
|
|
virtual LInsp insGuard(LOpcode v, LIns *c, SideExit *x) {
|
2008-07-15 01:27:14 -07:00
|
|
|
uint8* m = x->typeMap;
|
2008-07-15 01:53:39 -07:00
|
|
|
unsigned _ngslots = ((VMFragmentInfo*)_fragment->vmprivate)->ngslots;
|
|
|
|
uint16* _gslots = ((VMFragmentInfo*)_fragment->vmprivate)->gslots;
|
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(_cx, _ngslots, _gslots, _entryFrame, _cx->fp,
|
2008-07-15 01:27:14 -07:00
|
|
|
*m++ = getStoreType(*vp));
|
2008-07-06 11:48:41 -07:00
|
|
|
return out->insGuard(v, c, x);
|
|
|
|
}
|
2008-07-07 00:10:22 -07:00
|
|
|
|
|
|
|
/* Sink all type casts into 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. */
|
|
|
|
virtual LInsp insStore(LIns* value, LIns* base, LIns* disp) {
|
2008-07-16 14:21:31 -07:00
|
|
|
if (base == _fragment->lirbuf->sp && isPromoteInt(value))
|
2008-07-07 01:05:53 -07:00
|
|
|
value = demote(out, value);
|
2008-07-07 00:10:22 -07:00
|
|
|
return out->insStore(value, base, disp);
|
|
|
|
}
|
2008-07-07 02:21:04 -07:00
|
|
|
|
2008-07-07 00:10:22 -07:00
|
|
|
virtual LInsp insStorei(LIns* value, LIns* base, int32_t d) {
|
2008-07-16 14:21:31 -07:00
|
|
|
if (base == _fragment->lirbuf->sp && isPromoteInt(value))
|
2008-07-07 01:05:53 -07:00
|
|
|
value = demote(out, value);
|
2008-07-07 00:10:22 -07:00
|
|
|
return out->insStorei(value, base, d);
|
|
|
|
}
|
2008-07-06 11:48:41 -07:00
|
|
|
};
|
|
|
|
|
2008-07-16 21:49:42 -07:00
|
|
|
TraceRecorder::TraceRecorder(JSContext* cx, 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-02 17:19:07 -07:00
|
|
|
this->fragment = _fragment;
|
2008-07-16 21:41:03 -07:00
|
|
|
this->lirbuf = _fragment->lirbuf;
|
2008-06-28 18:47:12 -07:00
|
|
|
entryFrame = cx->fp;
|
2008-07-04 15:07:05 -07:00
|
|
|
entryRegs.pc = entryFrame->regs->pc;
|
2008-07-04 03:06:18 -07:00
|
|
|
entryRegs.sp = entryFrame->regs->sp;
|
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-15 10:26:15 -07:00
|
|
|
printf("recording starting from %s:%u\n", cx->fp->script->filename,
|
2008-07-11 17:59:10 -07:00
|
|
|
js_PCToLineNumber(cx, cx->fp->script, entryRegs.pc));
|
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-15 10:26:15 -07:00
|
|
|
lir = exit_filter = new (&gc) ExitFilter(lir, cx,
|
2008-07-15 01:53:39 -07:00
|
|
|
entryFrame, fragment, &tracker);
|
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-16 21:41:03 -07:00
|
|
|
JS_ASSERT(fragment->vmprivate != NULL);
|
|
|
|
fragmentInfo = (VMFragmentInfo*)fragment->vmprivate;
|
2008-07-15 10:26:15 -07:00
|
|
|
|
2008-07-16 21:41:03 -07:00
|
|
|
lirbuf->state = lir->insParam(0);
|
|
|
|
lirbuf->param1 = lir->insParam(1);
|
|
|
|
lirbuf->sp = lir->insLoadi(lirbuf->state, offsetof(InterpState, sp));
|
|
|
|
lirbuf->rp = lir->insLoadi(lirbuf->state, offsetof(InterpState, rp));
|
|
|
|
cx_ins = lir->insLoadi(lirbuf->state, offsetof(InterpState, cx));
|
2008-07-01 05:06:02 -07:00
|
|
|
#ifdef DEBUG
|
2008-07-16 21:41:03 -07:00
|
|
|
lirbuf->names->addName(lirbuf->state, "state");
|
|
|
|
lirbuf->names->addName(lirbuf->sp, "sp");
|
|
|
|
lirbuf->names->addName(lirbuf->rp, "rp");
|
2008-07-02 14:38:12 -07:00
|
|
|
lirbuf->names->addName(cx_ins, "cx");
|
2008-07-01 05:06:02 -07:00
|
|
|
#endif
|
2008-07-05 10:41:35 -07:00
|
|
|
|
2008-07-07 00:10:22 -07:00
|
|
|
uint8* m = fragmentInfo->typeMap;
|
2008-07-15 01:53:39 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, fragmentInfo->ngslots, fragmentInfo->gslots,
|
|
|
|
entryFrame, entryFrame,
|
2008-07-13 21:14:34 -07:00
|
|
|
import(vp, *m, vpname, vpnum);
|
2008-07-08 16:29:23 -07:00
|
|
|
m++
|
|
|
|
);
|
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-06 11:48:41 -07:00
|
|
|
delete exit_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-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-06-28 18:47:12 -07:00
|
|
|
JSStackFrame* fp = cx->fp;
|
2008-06-28 17:14:06 -07:00
|
|
|
unsigned depth = 0;
|
|
|
|
while (fp != entryFrame) {
|
|
|
|
++depth;
|
|
|
|
fp = fp->down;
|
|
|
|
}
|
|
|
|
return depth;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the frame that this address belongs to (if any). */
|
|
|
|
JSStackFrame*
|
2008-07-09 00:29:23 -07:00
|
|
|
TraceRecorder::findFrame(jsval* p) const
|
2008-06-28 17:14:06 -07:00
|
|
|
{
|
2008-07-05 11:18:26 -07:00
|
|
|
jsval* vp = (jsval*) p;
|
2008-06-28 18:47:12 -07:00
|
|
|
JSStackFrame* fp = cx->fp;
|
2008-07-05 11:29:28 -07:00
|
|
|
for (;;) {
|
2008-07-05 11:18:26 -07:00
|
|
|
// FIXME: fixing bug 441686 collapses the last two tests here
|
2008-07-08 23:48:06 -07:00
|
|
|
if (vp == p ||
|
|
|
|
size_t(vp - fp->argv) < fp->argc ||
|
2008-07-05 11:18:26 -07:00
|
|
|
size_t(vp - fp->vars) < fp->nvars ||
|
|
|
|
size_t(vp - fp->spbase) < fp->script->depth) {
|
2008-06-28 17:14:06 -07:00
|
|
|
return fp;
|
2008-07-05 11:18:26 -07:00
|
|
|
}
|
2008-06-28 17:14:06 -07:00
|
|
|
if (fp == entryFrame)
|
2008-07-05 11:29:28 -07:00
|
|
|
return NULL;
|
2008-06-28 17:14:06 -07:00
|
|
|
fp = fp->down;
|
|
|
|
}
|
2008-07-05 11:29:28 -07:00
|
|
|
JS_NOT_REACHED("findFrame");
|
2008-06-28 17:14:06 -07:00
|
|
|
}
|
|
|
|
|
2008-07-07 15:15:56 -07:00
|
|
|
/* Determine whether an address is part of a currently active frame (or the global scope). */
|
2008-06-28 17:14:06 -07:00
|
|
|
bool
|
2008-07-09 00:29:23 -07:00
|
|
|
TraceRecorder::onFrame(jsval* p) const
|
2008-06-28 17:14:06 -07:00
|
|
|
{
|
2008-07-07 18:35:38 -07:00
|
|
|
return isGlobal(p) || findFrame(p) != NULL;
|
2008-07-07 15:15:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine whether an address points to a global variable (gvar). */
|
|
|
|
bool
|
2008-07-09 00:29:23 -07:00
|
|
|
TraceRecorder::isGlobal(jsval* p) const
|
2008-07-07 15:15:56 -07:00
|
|
|
{
|
|
|
|
/* has to be in either one of the fslots or dslots of varobj */
|
2008-07-14 16:40:38 -07:00
|
|
|
if (size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS)
|
2008-07-07 15:15:56 -07:00
|
|
|
return true;
|
2008-07-14 16:40:38 -07:00
|
|
|
return globalObj->dslots &&
|
|
|
|
size_t(p - globalObj->dslots) < size_t(globalObj->dslots[-1] - JS_INITIAL_NSLOTS);
|
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;
|
|
|
|
for (n = 0; n < natoms; ++n) {
|
|
|
|
JSAtom* atom = atoms[n];
|
|
|
|
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-16 21:41:03 -07:00
|
|
|
static unsigned nativeFrameSlots(unsigned ngslots, JSStackFrame* entryFrame,
|
|
|
|
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-16 14:36:50 -07:00
|
|
|
slots += 1/*this*/ + fp->argc + fp->nvars;
|
2008-07-09 11:42:31 -07:00
|
|
|
if (fp == entryFrame)
|
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-15 01:53:39 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, fragmentInfo->ngslots, fragmentInfo->gslots,
|
|
|
|
entryFrame, currentFrame,
|
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-06 20:25:49 -07:00
|
|
|
if (slots > fragmentInfo->maxNativeFrameSlots)
|
|
|
|
fragmentInfo->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) {
|
|
|
|
verbose_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-14 17:52:38 -07:00
|
|
|
verbose_only(printf("int != tag%lu(value=%lu) ", JSVAL_TAG(v), v);)
|
2008-07-15 06:07:54 -07:00
|
|
|
ABORT_TRACE("tagged int but not int or double? aroo?");
|
2008-07-10 21:23:32 -07:00
|
|
|
}
|
2008-07-13 21:53:35 -07:00
|
|
|
verbose_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-14 17:52:38 -07:00
|
|
|
verbose_only(printf("double != tag%lu ", JSVAL_TAG(v));)
|
2008-07-15 06:07:54 -07:00
|
|
|
ABORT_TRACE("tagged double, but not int or double? aroo?");
|
2008-07-10 21:23:32 -07:00
|
|
|
}
|
2008-07-07 01:05:53 -07:00
|
|
|
*(jsdouble*)slot = d;
|
2008-07-09 17:09:22 -07:00
|
|
|
verbose_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-14 17:52:38 -07:00
|
|
|
verbose_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-09 17:09:22 -07:00
|
|
|
verbose_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-09 17:09:22 -07:00
|
|
|
verbose_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-10 21:55:09 -07:00
|
|
|
verbose_only(printf("object<%p:%s> ", JSVAL_TO_OBJECT(v),
|
|
|
|
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) {
|
|
|
|
verbose_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-09 17:09:22 -07:00
|
|
|
verbose_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-09 17:09:22 -07:00
|
|
|
verbose_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-09 17:09:22 -07:00
|
|
|
verbose_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-09 17:09:22 -07:00
|
|
|
verbose_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-09 17:09:22 -07:00
|
|
|
verbose_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-15 10:26:15 -07:00
|
|
|
unbox(JSContext* cx, unsigned ngslots, uint16* gslots,
|
2008-07-15 01:53:39 -07:00
|
|
|
JSStackFrame* entryFrame, JSStackFrame* currentFrame, uint8* map, double* native)
|
2008-06-29 20:56:06 -07:00
|
|
|
{
|
2008-07-09 17:09:22 -07:00
|
|
|
verbose_only(printf("unbox native@%p ", native);)
|
2008-07-10 13:24:49 -07:00
|
|
|
double* np = native;
|
|
|
|
uint8* mp = map;
|
2008-07-15 01:53:39 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, ngslots, gslots, entryFrame, currentFrame,
|
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-09 17:09:22 -07:00
|
|
|
verbose_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-15 01:53:39 -07:00
|
|
|
box(JSContext* cx, unsigned ngslots, uint16* gslots,
|
|
|
|
JSStackFrame* entryFrame, JSStackFrame* currentFrame, uint8* map, double* native)
|
2008-06-29 23:02:22 -07:00
|
|
|
{
|
2008-07-09 17:09:22 -07:00
|
|
|
verbose_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-15 01:53:39 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, ngslots, gslots, entryFrame, currentFrame,
|
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-15 01:53:39 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, ngslots, gslots, entryFrame, currentFrame,
|
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-09 17:09:22 -07:00
|
|
|
verbose_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-15 16:04:08 -07:00
|
|
|
TraceRecorder::import(jsval* p, uint8& t, const char *prefix, int index)
|
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-06-28 17:14:06 -07:00
|
|
|
JS_ASSERT(onFrame(p));
|
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-10 19:17:41 -07:00
|
|
|
ptrdiff_t offset = -fragmentInfo->nativeStackBase + nativeFrameOffset(p) + 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-16 21:41:03 -07:00
|
|
|
ins = lir->ins1(LIR_i2f, lir->insLoadi(lirbuf->sp, offset));
|
2008-07-07 00:10:22 -07:00
|
|
|
} else {
|
|
|
|
JS_ASSERT(isNumber(*p) == (TYPEMAP_GET_TYPE(t) == JSVAL_DOUBLE));
|
2008-07-16 21:41:03 -07:00
|
|
|
ins = lir->insLoad(t == JSVAL_DOUBLE ? LIR_ldq : LIR_ld, lirbuf->sp, offset);
|
2008-07-07 00:10:22 -07:00
|
|
|
}
|
2008-07-01 05:06:02 -07:00
|
|
|
tracker.set(p, ins);
|
|
|
|
#ifdef DEBUG
|
2008-07-10 16:55:37 -07:00
|
|
|
char name[16];
|
|
|
|
JS_ASSERT(strlen(prefix) < 10);
|
|
|
|
JS_snprintf(name, sizeof name, "$%s%d", prefix, index);
|
|
|
|
lirbuf->names->addName(ins, name);
|
|
|
|
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-05 10:41:35 -07:00
|
|
|
/* Update the tracker. If the value is part of any argv/vars/stack of any
|
2008-06-30 09:36:10 -07:00
|
|
|
currently active frame (onFrame), then issue a write back store. */
|
2008-07-05 10:41:35 -07:00
|
|
|
void
|
2008-07-09 00:29:23 -07:00
|
|
|
TraceRecorder::set(jsval* p, LIns* i)
|
2008-06-26 22:41:10 -07:00
|
|
|
{
|
2008-06-30 09:36:10 -07:00
|
|
|
tracker.set(p, i);
|
2008-07-05 10:41:35 -07:00
|
|
|
if (onFrame(p))
|
2008-07-16 21:41:03 -07:00
|
|
|
lir->insStorei(i, lirbuf->sp, -fragmentInfo->nativeStackBase + nativeFrameOffset(p) + 8);
|
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-16 21:41:03 -07:00
|
|
|
unsigned slots = nativeFrameSlots(fragmentInfo->ngslots, entryFrame, cx->fp, *cx->fp->regs);
|
2008-07-02 17:19:07 -07:00
|
|
|
trackNativeFrameUse(slots);
|
2008-07-06 11:48:41 -07:00
|
|
|
/* reserve space for the type map, ExitFilter will write it out for us */
|
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-03 23:57:57 -07:00
|
|
|
exit.ip_adj = cx->fp->regs->pc - entryRegs.pc;
|
2008-07-14 19:12:50 -07:00
|
|
|
exit.sp_adj = (cx->fp->regs->sp - entryRegs.sp) * sizeof(double);
|
|
|
|
exit.rp_adj = exit.calldepth;
|
2008-07-08 17:16:51 -07:00
|
|
|
exit.typeMap = (uint8 *)data->payload();
|
2008-07-01 19:43:10 -07:00
|
|
|
return &exit;
|
|
|
|
}
|
|
|
|
|
2008-06-27 00:22:16 -07:00
|
|
|
void
|
2008-07-04 13:23:42 -07:00
|
|
|
TraceRecorder::guard(bool expected, LIns* cond)
|
2008-06-27 00:22:16 -07:00
|
|
|
{
|
2008-07-05 10:41:35 -07:00
|
|
|
lir->insGuard(expected ? LIR_xf : LIR_xt,
|
|
|
|
cond,
|
|
|
|
snapshot());
|
2008-06-27 00:22:16 -07:00
|
|
|
}
|
|
|
|
|
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-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-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-08 16:29:23 -07:00
|
|
|
TraceRecorder::verifyTypeStability(JSStackFrame* entryFrame, JSStackFrame* currentFrame, uint8* m)
|
2008-07-05 23:21:53 -07:00
|
|
|
{
|
2008-07-15 01:53:39 -07:00
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, fragmentInfo->ngslots, fragmentInfo->gslots,
|
|
|
|
entryFrame, currentFrame,
|
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
|
|
|
|
TraceRecorder::closeLoop(Fragmento* fragmento)
|
|
|
|
{
|
2008-07-08 16:29:23 -07:00
|
|
|
if (!verifyTypeStability(entryFrame, cx->fp, fragmentInfo->typeMap)) {
|
2008-07-02 15:14:43 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("Trace rejected: unstable loop variables.\n");
|
2008-07-05 10:41:35 -07:00
|
|
|
#endif
|
2008-07-02 15:31:40 -07:00
|
|
|
return;
|
2008-07-02 15:14:43 -07:00
|
|
|
}
|
2008-07-08 17:16:51 -07:00
|
|
|
fragment->lastIns = lir->insGuard(LIR_loop, lir->insImm(1), snapshot());
|
2008-06-27 18:06:50 -07:00
|
|
|
compile(fragmento->assm(), fragment);
|
|
|
|
}
|
|
|
|
|
2008-07-04 00:51:30 -07:00
|
|
|
bool
|
2008-07-05 19:15:00 -07:00
|
|
|
TraceRecorder::loopEdge()
|
2008-06-27 20:58:06 -07:00
|
|
|
{
|
2008-07-04 15:07:05 -07:00
|
|
|
if (cx->fp->regs->pc == entryRegs.pc) {
|
2008-07-04 00:51:30 -07:00
|
|
|
closeLoop(JS_TRACE_MONITOR(cx).fragmento);
|
|
|
|
return false; /* done recording */
|
|
|
|
}
|
2008-07-17 00:48:10 -07:00
|
|
|
/* make sure the type map gets trashed if this was the root fragment that didn't complete */
|
|
|
|
stop();
|
2008-07-04 00:51:30 -07:00
|
|
|
return false; /* abort recording */
|
|
|
|
}
|
|
|
|
|
2008-07-05 19:15:00 -07:00
|
|
|
void
|
|
|
|
TraceRecorder::stop()
|
|
|
|
{
|
|
|
|
fragment->blacklist();
|
2008-07-17 00:48:10 -07:00
|
|
|
if (fragment->root == fragment) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("Root fragment aborted, trashing the type map.\n");
|
|
|
|
#endif
|
|
|
|
JS_ASSERT(fragmentInfo->typeMap);
|
|
|
|
fragmentInfo->typeMap = NULL;
|
|
|
|
}
|
2008-07-05 19:15:00 -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();
|
|
|
|
rec->calldepth = exit->calldepth;
|
|
|
|
rec->exit = exit;
|
|
|
|
verbose_only(rec->sid = exit->sid);
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
SideExit *exit;
|
|
|
|
|
|
|
|
exit = guard->exit();
|
|
|
|
|
2008-07-10 22:29:06 -07:00
|
|
|
#if defined(NANOJIT_IA32)
|
2008-07-14 19:12:50 -07:00
|
|
|
if (exit->ip_adj)
|
|
|
|
ADDmi((int32_t)offsetof(InterpState, ip), state, (int32_t)exit->ip_adj);
|
|
|
|
|
2008-07-08 17:16:51 -07:00
|
|
|
if (exit->sp_adj)
|
2008-07-14 17:52:38 -07:00
|
|
|
ADDmi((int32_t)offsetof(InterpState, sp), state, (int32_t)exit->sp_adj);
|
2008-07-08 17:16:51 -07:00
|
|
|
|
2008-07-14 19:12:50 -07:00
|
|
|
if (exit->rp_adj)
|
|
|
|
ADDmi((int32_t)offsetof(InterpState, rp), state, (int32_t)exit->rp_adj);
|
|
|
|
|
2008-07-10 22:29:06 -07:00
|
|
|
#elif defined(NANOJIT_ARM)
|
2008-07-10 22:35:06 -07:00
|
|
|
NanoAssert(offsetof(avmplus::InterpState,ip) == 0);
|
|
|
|
NanoAssert(offsetof(avmplus::InterpState,sp) == 4);
|
2008-07-14 19:12:50 -07:00
|
|
|
NanoAssert(offsetof(avmplus::InterpState,rp) == 8);
|
2008-07-11 00:46:44 -07:00
|
|
|
RegisterMask ptrs = 0xe; // { R1-R3 }
|
2008-07-10 22:29:06 -07:00
|
|
|
|
2008-07-11 00:46:44 -07:00
|
|
|
SUBi(state,12);
|
2008-07-10 22:29:06 -07:00
|
|
|
STMIA(state,ptrs);
|
|
|
|
|
2008-07-14 19:12:50 -07:00
|
|
|
if (exit->rp_adj) ADDi(R3, exit->rp_adj);
|
2008-07-10 22:35:06 -07:00
|
|
|
if (exit->sp_adj) ADDi(R2, exit->sp_adj);
|
|
|
|
if (exit->ip_adj) ADDi(R1, exit->ip_adj);
|
2008-07-10 22:29:06 -07:00
|
|
|
|
2008-07-11 00:46:44 -07:00
|
|
|
SUBi(state,12);
|
2008-07-10 22:29:06 -07:00
|
|
|
LDMIA(state,ptrs);
|
2008-07-08 17:16:51 -07:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
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-06-27 20:58:06 -07:00
|
|
|
}
|
|
|
|
|
2008-07-05 23:21:53 -07:00
|
|
|
#define HOTLOOP1 10
|
|
|
|
#define HOTLOOP2 13
|
|
|
|
#define HOTLOOP3 37
|
2008-07-05 19:15:00 -07:00
|
|
|
|
2008-07-04 00:51:30 -07:00
|
|
|
bool
|
2008-07-04 15:07:05 -07:00
|
|
|
js_LoopEdge(JSContext* cx)
|
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-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-05 19:15:00 -07:00
|
|
|
if (tm->recorder->loopEdge())
|
2008-07-04 00:51:30 -07:00
|
|
|
return true; /* keep recording */
|
|
|
|
js_DeleteRecorder(cx);
|
|
|
|
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-05 23:21:53 -07:00
|
|
|
int hits = ++f->hits();
|
2008-07-06 06:56:25 -07:00
|
|
|
if (!f->isBlacklisted() && hits >= HOTLOOP1) {
|
2008-07-05 23:21:53 -07:00
|
|
|
if (hits == HOTLOOP1 || hits == HOTLOOP2 || hits == HOTLOOP3) {
|
2008-07-16 21:41:03 -07:00
|
|
|
f->calldepth = 0;
|
|
|
|
/* allocate space to store the LIR for this tree */
|
|
|
|
if (!f->lirbuf) {
|
|
|
|
f->lirbuf = new (&gc) LirBuffer(tm->fragmento, builtins);
|
|
|
|
#ifdef DEBUG
|
|
|
|
f->lirbuf->names = new (&gc) LirNameMap(&gc, builtins, tm->fragmento->labels);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/* create the tree anchor structure */
|
2008-07-16 21:49:42 -07:00
|
|
|
VMFragmentInfo* fi = (VMFragmentInfo*)f->vmprivate;
|
|
|
|
if (!fi) {
|
2008-07-16 21:41:03 -07:00
|
|
|
/* setup the VM-private FragmentInfo structure for this fragment */
|
2008-07-16 21:49:42 -07:00
|
|
|
fi = new VMFragmentInfo(); // TODO: deallocate when fragment dies
|
2008-07-16 21:41:03 -07:00
|
|
|
f->vmprivate = fi;
|
2008-07-16 23:33:04 -07:00
|
|
|
|
2008-07-16 21:41:03 -07:00
|
|
|
/* create the list of global properties we want to intern */
|
|
|
|
int internableGlobals = findInternableGlobals(cx, cx->fp, NULL);
|
|
|
|
if (internableGlobals < 0)
|
|
|
|
return false;
|
|
|
|
fi->gslots = (uint16*)malloc(sizeof(uint16) * internableGlobals);
|
|
|
|
if ((fi->ngslots = findInternableGlobals(cx, cx->fp, fi->gslots)) < 0)
|
|
|
|
return false;
|
|
|
|
fi->globalShape = OBJ_SCOPE(JS_GetGlobalForObject(cx,
|
2008-07-16 23:33:04 -07:00
|
|
|
cx->fp->scopeChain))->shape;
|
|
|
|
|
2008-07-16 21:41:03 -07:00
|
|
|
/* determine the native frame layout at the entry point */
|
|
|
|
unsigned entryNativeFrameSlots = nativeFrameSlots(fi->ngslots,
|
|
|
|
cx->fp, cx->fp, *cx->fp->regs);
|
|
|
|
fi->entryNativeFrameSlots = entryNativeFrameSlots;
|
|
|
|
fi->nativeStackBase = (entryNativeFrameSlots -
|
|
|
|
(cx->fp->regs->sp - cx->fp->spbase)) * sizeof(double);
|
|
|
|
fi->maxNativeFrameSlots = entryNativeFrameSlots;
|
|
|
|
fi->maxCallDepth = 0;
|
2008-07-17 00:48:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* capture the entry type map if we don't have one yet (or we threw it away) */
|
|
|
|
if (!fi->typeMap) {
|
2008-07-16 21:41:03 -07:00
|
|
|
fi->typeMap = (uint8*)malloc(fi->entryNativeFrameSlots * sizeof(uint8));
|
|
|
|
uint8* m = fi->typeMap;
|
2008-07-16 23:33:04 -07:00
|
|
|
|
2008-07-16 21:41:03 -07:00
|
|
|
/* remember the coerced type of each active slot in the type map */
|
|
|
|
FORALL_SLOTS_IN_PENDING_FRAMES(cx, fi->ngslots, fi->gslots, cx->fp, cx->fp,
|
|
|
|
*m++ = getCoercedType(*vp)
|
|
|
|
);
|
|
|
|
}
|
2008-07-17 00:48:10 -07:00
|
|
|
|
2008-07-16 21:49:42 -07:00
|
|
|
tm->recorder = new (&gc) TraceRecorder(cx, f, fi->typeMap);
|
2008-07-15 10:26:15 -07:00
|
|
|
|
|
|
|
/* start recording if no exception during construction */
|
|
|
|
return !cx->throwing;
|
2008-07-05 23:21:53 -07:00
|
|
|
}
|
|
|
|
if (hits > HOTLOOP3)
|
|
|
|
f->blacklist();
|
2008-07-05 19:15:00 -07:00
|
|
|
}
|
|
|
|
return false;
|
2008-07-04 00:51:30 -07:00
|
|
|
}
|
|
|
|
|
2008-07-08 22:40:07 -07:00
|
|
|
/* execute previously recorded trace */
|
2008-07-02 17:19:07 -07:00
|
|
|
VMFragmentInfo* fi = (VMFragmentInfo*)f->vmprivate;
|
2008-07-15 01:08:13 -07:00
|
|
|
if (OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->shape != fi->globalShape) {
|
|
|
|
verbose_only(printf("global shape mismatch, skipping trace.\n");)
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-15 10:26:15 -07:00
|
|
|
|
2008-07-10 13:48:42 -07:00
|
|
|
double* native = (double *)alloca((fi->maxNativeFrameSlots+1) * sizeof(double));
|
2008-07-02 17:19:07 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
*(uint64*)&native[fi->maxNativeFrameSlots] = 0xdeadbeefdeadbeefLL;
|
2008-07-05 10:41:35 -07:00
|
|
|
#endif
|
2008-07-15 01:53:39 -07:00
|
|
|
if (!unbox(cx, fi->ngslots, fi->gslots, cx->fp, cx->fp, fi->typeMap, native)) {
|
2008-07-06 15:55:04 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("typemap mismatch, skipping trace.\n");
|
2008-07-07 02:21:04 -07:00
|
|
|
#endif
|
2008-07-06 15:55:04 -07:00
|
|
|
return false;
|
|
|
|
}
|
2008-07-07 02:21:04 -07:00
|
|
|
double* entry_sp = &native[fi->nativeStackBase/sizeof(double) +
|
2008-07-05 14:05:25 -07:00
|
|
|
(cx->fp->regs->sp - cx->fp->spbase - 1)];
|
2008-07-16 15:01:55 -07:00
|
|
|
JSObject** callstack = (JSObject**)alloca(fi->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-15 10:26:15 -07:00
|
|
|
printf("entering trace at %s:%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),
|
|
|
|
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-11 17:59:10 -07:00
|
|
|
cx->fp->regs->sp += (double*)state.sp - entry_sp;
|
2008-07-11 13:57:16 -07:00
|
|
|
cx->fp->regs->pc = (jsbytecode*)state.ip;
|
2008-07-15 13:06:05 -07:00
|
|
|
#if defined(DEBUG) && defined(NANOJIT_IA32)
|
2008-07-15 10:26:15 -07:00
|
|
|
printf("leaving trace at %s:%u, sp=%p, cycles=%llu\n",
|
|
|
|
cx->fp->script->filename, js_PCToLineNumber(cx, cx->fp->script, cx->fp->regs->pc),
|
2008-07-11 17:59:10 -07:00
|
|
|
state.sp,
|
|
|
|
(rdtsc() - start));
|
2008-07-07 02:21:04 -07:00
|
|
|
#endif
|
2008-07-15 01:53:39 -07:00
|
|
|
box(cx, fi->ngslots, fi->gslots, cx->fp, cx->fp, lr->exit->typeMap, native);
|
2008-07-02 17:19:07 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
JS_ASSERT(*(uint64*)&native[fi->maxNativeFrameSlots] == 0xdeadbeefdeadbeefLL);
|
2008-07-05 10:41:35 -07:00
|
|
|
#endif
|
|
|
|
|
2008-07-04 00:51:30 -07:00
|
|
|
return false; /* continue with regular interpreter */
|
2008-07-01 02:37:07 -07:00
|
|
|
}
|
|
|
|
|
2008-06-28 18:19:21 -07:00
|
|
|
void
|
2008-07-04 01:10:57 -07:00
|
|
|
js_AbortRecording(JSContext* cx, const char* reason)
|
2008-06-28 18:19:21 -07:00
|
|
|
{
|
2008-07-04 01:10:57 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("Abort recording: %s.\n", reason);
|
2008-07-05 10:41:35 -07:00
|
|
|
#endif
|
2008-07-05 19:15:00 -07:00
|
|
|
JS_TRACE_MONITOR(cx).recorder->stop();
|
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-05 19:15:00 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
fragmento->labels = new (&gc) LabelMap(core, NULL);
|
|
|
|
#endif
|
|
|
|
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-04 03:06:18 -07:00
|
|
|
jsval&
|
|
|
|
TraceRecorder::argval(unsigned n) const
|
|
|
|
{
|
2008-07-08 18:12:22 -07:00
|
|
|
JS_ASSERT(n < cx->fp->argc);
|
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
|
|
|
{
|
|
|
|
set(&stackval(n), i);
|
|
|
|
}
|
|
|
|
|
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-05 22:23:34 -07:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-04 03:06:18 -07:00
|
|
|
bool
|
|
|
|
TraceRecorder::inc(jsval& v, jsint incr, bool pre)
|
|
|
|
{
|
2008-07-06 15:55:04 -07:00
|
|
|
if (isNumber(v)) {
|
2008-07-04 03:06:18 -07:00
|
|
|
LIns* before = get(&v);
|
2008-07-07 00:10:22 -07:00
|
|
|
LIns* after;
|
2008-07-14 15:22:05 -07:00
|
|
|
jsdpun u;
|
|
|
|
u.d = (jsdouble)incr;
|
|
|
|
after = lir->ins2(LIR_fadd, before, lir->insImmq(u.u64));
|
2008-07-04 03:06:18 -07:00
|
|
|
set(&v, after);
|
2008-07-09 15:15:32 -07:00
|
|
|
|
|
|
|
const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
|
|
|
|
JS_ASSERT(cs.ndefs == 1);
|
|
|
|
stack(cs.nuses, pre ? after : before);
|
2008-07-04 03:06:18 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-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);
|
|
|
|
/* 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
|
|
|
{
|
|
|
|
LIns* ops = lir->insLoadi(map_ins, offsetof(JSObjectMap, ops));
|
|
|
|
if (map->ops == &js_ObjectOps) {
|
2008-07-05 13:44:48 -07:00
|
|
|
guard(true, lir->ins2(LIR_eq, ops, lir->insImmPtr(&js_ObjectOps)));
|
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-12 21:09:24 -07:00
|
|
|
guard(true, lir->ins2(LIR_eq, n, lir->insImmPtr((void*)js_ObjectOps.newObjectMap)));
|
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
|
|
|
|
TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2,
|
|
|
|
JSPropCacheEntry*& entry)
|
|
|
|
{
|
|
|
|
LIns* map_ins = lir->insLoadi(obj_ins, offsetof(JSObject, map));
|
|
|
|
if (!map_is_native(obj->map, map_ins))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
JSAtom* atom;
|
|
|
|
PROPERTY_CACHE_TEST(cx, cx->fp->regs->pc, obj, obj2, entry, atom);
|
2008-07-06 10:38:55 -07:00
|
|
|
if (atom)
|
2008-07-11 17:59:10 -07:00
|
|
|
ABORT_TRACE("PC miss");
|
2008-07-06 10:38:55 -07:00
|
|
|
|
|
|
|
if (PCVCAP_TAG(entry->vcap == 1))
|
2008-07-11 17:59:10 -07:00
|
|
|
ABORT_TRACE("PC hit in prototype"); // need to look in the prototype, NYI
|
2008-07-06 10:38:55 -07:00
|
|
|
|
|
|
|
if (OBJ_SCOPE(obj)->object != obj)
|
2008-07-11 17:59:10 -07:00
|
|
|
ABORT_TRACE("obj not scope owner"); // need to normalize to the owner of the shared scope, NYI
|
2008-07-07 02:21:04 -07:00
|
|
|
|
2008-07-15 01:08:13 -07:00
|
|
|
if (obj != globalObj) { // shape of global object is guarded by unboxing
|
|
|
|
LIns* shape_ins = lir->insLoadi(map_ins, offsetof(JSScope, shape));
|
2008-07-06 10:58:59 -07:00
|
|
|
#ifdef DEBUG
|
2008-07-15 01:08:13 -07:00
|
|
|
lirbuf->names->addName(shape_ins, "shape");
|
2008-07-06 10:58:59 -07:00
|
|
|
#endif
|
2008-07-15 01:08:13 -07:00
|
|
|
guard(true, lir->ins2i(LIR_eq, shape_ins, OBJ_SCOPE(obj)->shape));
|
|
|
|
}
|
2008-07-06 09:15:55 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-09 11:42:31 -07:00
|
|
|
bool
|
|
|
|
TraceRecorder::test_property_cache_direct_slot(JSObject* obj, LIns* obj_ins, uint32& slot)
|
|
|
|
{
|
|
|
|
JSObject* obj2;
|
|
|
|
JSPropCacheEntry* entry;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Property cache ensures that we are dealing with an existing property,
|
|
|
|
* and guards the shape for us.
|
|
|
|
*/
|
|
|
|
if (!test_property_cache(obj, obj_ins, obj2, entry))
|
|
|
|
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-09 16:37:31 -07:00
|
|
|
if (PCVAL_IS_SPROP(entry->vword)) {
|
|
|
|
JS_ASSERT(js_CodeSpec[*cx->fp->regs->pc].format & JOF_SET);
|
|
|
|
JSScopeProperty* sprop = PCVAL_TO_SPROP(entry->vword);
|
|
|
|
|
|
|
|
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 {
|
|
|
|
if (!PCVAL_IS_SLOT(entry->vword))
|
2008-07-11 17:59:10 -07:00
|
|
|
ABORT_TRACE("PCE is not a slot");
|
2008-07-09 16:37:31 -07:00
|
|
|
slot = PCVAL_TO_SLOT(entry->vword);
|
|
|
|
}
|
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-07 02:21:04 -07:00
|
|
|
lir->insStorei(v_ins,
|
2008-07-07 02:55:03 -07:00
|
|
|
obj_ins,
|
|
|
|
offsetof(JSObject, fslots) + slot * sizeof(jsval));
|
|
|
|
} else {
|
2008-07-05 13:44:48 -07:00
|
|
|
if (!dslots_ins)
|
|
|
|
dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
|
2008-07-07 02:21:04 -07:00
|
|
|
lir->insStorei(v_ins,
|
2008-07-07 02:55:03 -07:00
|
|
|
dslots_ins,
|
|
|
|
(slot - JS_INITIAL_NSLOTS) * sizeof(jsval));
|
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
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-16 17:44:44 -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)
|
|
|
|
guard(true, lir->ins_eq0(
|
|
|
|
lir->ins_eq0(
|
2008-07-07 02:21:04 -07:00
|
|
|
lir->ins2(LIR_and, v_ins,
|
2008-07-06 16:18:45 -07:00
|
|
|
lir->insImmPtr((void*)(JSVAL_INT | JSVAL_DOUBLE))))));
|
|
|
|
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,
|
|
|
|
lir->ins2(LIR_and, v_ins, lir->insImmPtr((void*)~JSVAL_TRUE)),
|
|
|
|
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,
|
|
|
|
lir->ins2(LIR_and, v_ins, lir->insImmPtr((void*)~JSVAL_TRUE)),
|
|
|
|
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-16 15:01:55 -07:00
|
|
|
if (getCallDepth() <= 0)
|
|
|
|
return false;
|
|
|
|
// this only works if we have a contiguous stack, which CALL enforces
|
|
|
|
set(&cx->fp->argv[-2], stack(-1));
|
|
|
|
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
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
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-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INCPROP()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_INCELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_DECELEM()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_ELEMINC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2008-07-10 21:55:09 -07:00
|
|
|
|
|
|
|
bool TraceRecorder::record_JSOP_ELEMDEC()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
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-05 13:44:48 -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-05 06:47:59 -07:00
|
|
|
return false;
|
2008-07-05 13:44:48 -07:00
|
|
|
JSObject* obj = JSVAL_TO_OBJECT(l);
|
|
|
|
LIns* obj_ins = get(&l);
|
|
|
|
/* 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 */
|
2008-07-06 15:55:04 -07:00
|
|
|
jsint idx = JSVAL_TO_INT(r);
|
|
|
|
LIns* idx_ins = f2i(get(&r));
|
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 13:44:48 -07:00
|
|
|
if (!guardDenseArrayIndexWithinBounds(obj, idx, obj_ins, dslots_ins, idx_ins))
|
|
|
|
return false;
|
|
|
|
jsval v = obj->dslots[idx];
|
|
|
|
/* load the value, check the type (need to check JSVAL_HOLE only for booleans) */
|
2008-07-15 10:26:15 -07:00
|
|
|
LIns* v_ins = lir->insLoad(LIR_ld,
|
|
|
|
lir->ins2(LIR_add, dslots_ins,
|
2008-07-10 17:41:24 -07:00
|
|
|
lir->ins2i(LIR_lsh, idx_ins, sizeof(jsval) == 4 ? 2 : 3)), 0);
|
2008-07-06 10:38:55 -07:00
|
|
|
if (!unbox_jsval(v, v_ins))
|
|
|
|
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-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);
|
|
|
|
/* 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-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-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-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-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;
|
|
|
|
JSPropCacheEntry* entry;
|
|
|
|
if (!test_property_cache(obj, obj_ins, obj2, entry))
|
|
|
|
ABORT_TRACE("missed prop");
|
|
|
|
|
|
|
|
if (!PCVAL_IS_OBJECT(entry->vword))
|
|
|
|
ABORT_TRACE("PCE not object");
|
|
|
|
|
|
|
|
stack(0, lir->insImmPtr(PCVAL_TO_OBJECT(entry->vword)));
|
|
|
|
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();
|
|
|
|
lir->insStorei(lir->insImmPtr(JSVAL_TO_OBJECT(fval)),
|
|
|
|
lirbuf->rp, callDepth * sizeof(JSObject*));
|
|
|
|
if (callDepth+1 > fragmentInfo->maxCallDepth)
|
|
|
|
fragmentInfo->maxCallDepth = callDepth+1;
|
|
|
|
return true;
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
JSStackFrame* fp = cx->fp;
|
|
|
|
LIns* void_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
|
|
|
set(&fp->rval, void_ins);
|
|
|
|
unsigned n;
|
2008-07-16 23:04:50 -07:00
|
|
|
for (n = 0; n < fp->nvars; ++n)
|
|
|
|
set(&fp->vars[n], void_ins);
|
2008-07-16 22:58:06 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-15 10:17:51 -07:00
|
|
|
bool
|
2008-07-16 14:36:50 -07:00
|
|
|
TraceRecorder::getProp(JSObject* obj, LIns* obj_ins)
|
2008-07-15 10:17:51 -07:00
|
|
|
{
|
|
|
|
uint32 slot;
|
|
|
|
if (!test_property_cache_direct_slot(obj, obj_ins, slot))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
jsval& v = STOBJ_GET_SLOT(obj, slot);
|
2008-07-15 10:40:11 -07:00
|
|
|
LIns* dslots_ins = NULL;
|
2008-07-15 10:17:51 -07:00
|
|
|
LIns* v_ins = stobj_get_slot(obj_ins, slot, dslots_ins);
|
|
|
|
if (!unbox_jsval(v, v_ins))
|
|
|
|
ABORT_TRACE("unboxing");
|
|
|
|
stack(0, v_ins);
|
|
|
|
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-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-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;
|
|
|
|
JSPropCacheEntry* entry;
|
|
|
|
if (!test_property_cache(obj, obj_ins, obj2, entry))
|
|
|
|
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-10 21:55:09 -07:00
|
|
|
bool TraceRecorder::record_JSOP_DEFLOCALFUN()
|
2008-07-03 23:57:57 -07:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
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;
|
|
|
|
JSPropCacheEntry* entry;
|
|
|
|
if (!test_property_cache(obj, obj_ins, obj2, entry))
|
|
|
|
ABORT_TRACE("missed prop");
|
|
|
|
|
|
|
|
if (!PCVAL_IS_OBJECT(entry->vword))
|
|
|
|
ABORT_TRACE("PCE not object");
|
|
|
|
|
|
|
|
stack(-1, lir->insImmPtr(PCVAL_TO_OBJECT(entry->vword)));
|
|
|
|
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-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_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?");
|
|
|
|
|
|
|
|
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;
|
|
|
|
/* its safe to just use cx->fp->thisp here because getThis() returns false if thisp
|
|
|
|
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
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
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
|
|
|
}
|