gecko/js/src/jstracer.cpp

1679 lines
34 KiB
C++
Raw Normal View History

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=79:
*
* ***** 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
* Brendan Eich <brendan@mozilla.org>
*
* Contributor(s):
* Andreas Gal <gal@mozilla.com>
*
* 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 ***** */
#include <math.h>
#include "nanojit/avmplus.h"
#include "nanojit/nanojit.h"
#include "jstracer.h"
#include "jscntxt.h"
#include "jsscript.h"
#include "jsprf.h"
using namespace avmplus;
using namespace nanojit;
static GC gc = GC();
static avmplus::AvmCore* core = new (&gc) avmplus::AvmCore();
2008-06-26 20:44:23 -07:00
Tracker::Tracker()
{
pagelist = 0;
}
2008-06-26 20:44:23 -07:00
Tracker::~Tracker()
{
clear();
}
2008-06-26 20:44:23 -07:00
long
Tracker::getPageBase(const void* v) const
{
return ((long)v) & (~(NJ_PAGE_SIZE-1));
2008-06-04 00:09:57 -07:00
}
2008-06-11 11:29:35 -07:00
2008-06-26 20:44:23 -07:00
struct Tracker::Page*
Tracker::findPage(const void* v) const
2008-06-11 11:29:35 -07:00
{
long base = getPageBase(v);
struct Tracker::Page* p = pagelist;
while (p) {
if (p->base == base) {
return p;
}
p = p->next;
}
return 0;
}
2008-06-26 20:44:23 -07:00
struct Tracker::Page*
Tracker::addPage(const void* v) {
long base = getPageBase(v);
2008-06-26 20:44:23 -07:00
struct Tracker::Page* p = (struct Tracker::Page*)
GC::Alloc(sizeof(struct Tracker::Page) + (NJ_PAGE_SIZE >> 2) * sizeof(LInsp));
p->base = base;
p->next = pagelist;
pagelist = p;
return p;
2008-06-11 11:29:35 -07:00
}
2008-06-26 20:44:23 -07:00
void
Tracker::clear()
2008-06-11 11:29:35 -07:00
{
while (pagelist) {
Page* p = pagelist;
pagelist = pagelist->next;
GC::Free(p);
}
2008-06-11 11:29:35 -07:00
}
2008-06-26 20:44:23 -07:00
LIns*
Tracker::get(const void* v) const
{
2008-06-26 20:44:23 -07:00
struct Tracker::Page* p = findPage(v);
JS_ASSERT(p != 0); /* we must have a page for the slot we are looking for */
2008-06-26 20:44:23 -07:00
LIns* i = p->map[(((long)v) & 0xfff) >> 2];
JS_ASSERT(i != 0);
return i;
}
2008-06-26 20:44:23 -07:00
void
Tracker::set(const void* v, LIns* ins)
{
struct Tracker::Page* p = findPage(v);
2008-06-22 23:42:54 -07:00
if (!p)
p = addPage(v);
2008-06-26 20:44:23 -07:00
p->map[(((long)v) & 0xfff) >> 2] = ins;
}
#define LO ARGSIZE_LO
#define F ARGSIZE_F
#define Q ARGSIZE_Q
#ifdef DEBUG
#define NAME(op) ,#op
#else
#define NAME(op)
#endif
#define builtin_DoubleToECMAInt32 js_DoubleToECMAInt32
#define builtin_DoubleToECMAUint32 js_DoubleToECMAUint32
#define builtin_CompareStrings js_CompareStrings
jsint builtin_StringLength(JSString* s)
{
return JSSTRING_LENGTH(s);
}
jsdouble builtin_dmod(jsdouble a, jsdouble b)
{
if (b == 0.0) {
jsdpun u;
u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
u.s.lo = 0xffffffff;
return u.d;
}
jsdouble r;
#ifdef XP_WIN
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
if (!(JSDOUBLE_IS_FINITE(a) && JSDOUBLE_IS_INFINITE(b)))
r = a;
else
#endif
r = fmod(a, b);
return r;
}
#define builtin_DOUBLE_IS_INT builtin_unimplemented
#define builtin_StringToDouble builtin_unimplemented
#define builtin_ObjectToDouble builtin_unimplemented
/* the following primitives are just placeholders and need to be broken down
further (we need a concrete specialization, not "value") */
#define builtin_ValueToNumber builtin_unimplemented
#define builtin_ValueToNonNullObject builtin_unimplemented
#define builtin_obj_default_value builtin_unimplemented
void builtin_unimplemented(void)
{
JS_ASSERT(0);
}
#define BUILTIN1(op, at0, atr, tr, t0, cse, fold) \
{ (intptr_t)&builtin_##op, (at0 << 2) | atr, cse, fold NAME(op) },
#define BUILTIN2(op, at0, at1, atr, tr, t0, t1, cse, fold) \
{ (intptr_t)&builtin_##op, (at0 << 4) | (at1 << 2) | atr, cse, fold NAME(op) },
#define BUILTIN3(op, at0, at1, at2, atr, tr, t0, t1, t2, cse, fold) \
{ (intptr_t)&builtin_##op, (at0 << 6) | (at1 << 4) | (at2 << 2) | atr, cse, fold NAME(op) },
static struct CallInfo builtins[] = {
#include "builtins.tbl"
2008-06-22 23:42:54 -07:00
};
2008-06-22 23:42:54 -07:00
#undef NAME
#undef BUILTIN1
#undef BUILTIN2
2008-06-22 23:42:54 -07:00
#undef BUILTIN3
static void
buildTypeMap(JSStackFrame* entryFrame, JSStackFrame* fp, JSFrameRegs& regs, char* m);
TraceRecorder::TraceRecorder(JSContext* cx, Fragmento* fragmento, Fragment* _fragment)
{
this->cx = cx;
this->fragment = _fragment;
entryFrame = cx->fp;
entryRegs = *(entryFrame->regs);
fragment->calldepth = 0;
lirbuf = new (&gc) LirBuffer(fragmento, builtins);
fragment->lirbuf = lirbuf;
lir = lir_buf_writer = new (&gc) LirBufWriter(lirbuf);
#ifdef DEBUG
lirbuf->names = new (&gc) LirNameMap(&gc, builtins, fragmento->labels);
lir = verbose_filter = new (&gc) VerboseWriter(&gc, lir, lirbuf->names);
#endif
lir = cse_filter = new (&gc) CseFilter(lir, &gc);
lir = expr_filter = new (&gc) ExprFilter(lir);
lir->ins0(LIR_trace);
/* generate the entry map and stash it in the trace */
entryNativeFrameSlots = nativeFrameSlots(entryFrame, entryRegs);
maxNativeFrameSlots = entryNativeFrameSlots;
LIns* data = lir_buf_writer->skip(sizeof(VMFragmentInfo) + entryNativeFrameSlots * sizeof(char));
VMFragmentInfo* fi = (VMFragmentInfo*)data->payload();
buildTypeMap(entryFrame, entryFrame, entryRegs, fi->typeMap);
entryTypeMap = fi->typeMap;
fragment->vmprivate = fi;
fragment->param0 = lir->insImm8(LIR_param, Assembler::argRegs[0], 0);
fragment->param1 = lir->insImm8(LIR_param, Assembler::argRegs[1], 0);
fragment->sp = lir->insLoadi(fragment->param0, offsetof(InterpState, sp));
cx_ins = lir->insLoadi(fragment->param0, offsetof(InterpState, f));
#ifdef DEBUG
lirbuf->names->addName(fragment->param0, "state");
lirbuf->names->addName(fragment->sp, "sp");
lirbuf->names->addName(cx_ins, "cx");
#endif
JSStackFrame* fp = cx->fp;
unsigned n;
for (n = 0; n < fp->argc; ++n)
import(&fp->argv[n], "arg", n);
for (n = 0; n < fp->nvars; ++n)
import(&fp->vars[n], "var", n);
for (n = 0; n < (unsigned)(fp->regs->sp - fp->spbase); ++n)
import(&fp->spbase[n], "stack", n);
}
TraceRecorder::~TraceRecorder()
{
#ifdef DEBUG
delete lirbuf->names;
delete verbose_filter;
#endif
delete cse_filter;
delete expr_filter;
delete lir_buf_writer;
}
/* Determine the current call depth (starting with the entry frame.) */
unsigned
TraceRecorder::calldepth() const
{
JSStackFrame* fp = cx->fp;
unsigned depth = 0;
while (fp != entryFrame) {
++depth;
fp = fp->down;
}
return depth;
}
/* Find the frame that this address belongs to (if any). */
JSStackFrame*
TraceRecorder::findFrame(void* p) const
{
JSStackFrame* fp = cx->fp;
while (1) {
if ((p >= &fp->argv[0] && p < &fp->argv[fp->argc]) ||
(p >= &fp->vars[0] && p < &fp->vars[fp->nvars]) ||
(p >= &fp->spbase[0] && p < &fp->spbase[fp->script->depth]))
return fp;
if (fp == entryFrame)
return NULL;
fp = fp->down;
}
}
/* Determine whether an address is part of a currently active frame. */
bool
TraceRecorder::onFrame(void* p) const
{
return findFrame(p) != NULL;
}
/* 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. */
unsigned
TraceRecorder::nativeFrameSlots(JSStackFrame* fp, JSFrameRegs& regs) const
{
unsigned size = 0;
while (1) {
size += fp->argc + fp->nvars + (regs.sp - fp->spbase);
if (fp == entryFrame)
return size;
fp = fp->down;
}
}
/* Determine the offset in the native frame (marshal) for an address
that is part of a currently active frame. */
unsigned
TraceRecorder::nativeFrameOffset(void* p) const
{
JSStackFrame* fp = findFrame(p);
JS_ASSERT(fp != NULL); // must be on the frame somewhere
unsigned offset = 0;
if (p >= &fp->argv[0] && p < &fp->argv[fp->argc])
offset = unsigned((jsval*)p - &fp->argv[0]);
else if (p >= &fp->vars[0] && p < &fp->vars[fp->nvars])
offset = (fp->argc + unsigned((jsval*)p - &fp->vars[0]));
else {
JS_ASSERT((p >= &fp->spbase[0] && p < &fp->spbase[fp->script->depth]));
offset = (fp->argc + fp->nvars + unsigned((jsval*)p - &fp->spbase[0]));
}
if (fp != entryFrame)
offset += nativeFrameSlots(fp->down, *fp->regs);
return offset * sizeof(double);
}
/* Track the maximum number of native frame slots we need during
execution. */
void
TraceRecorder::trackNativeFrameUse(unsigned slots)
{
if (slots > maxNativeFrameSlots)
maxNativeFrameSlots = slots;
}
/* Return the tag of a jsval. Doubles are checked whether they actually
represent an int, in which case we treat them as JSVAL_INT. */
static inline int gettag(jsval v)
{
if (JSVAL_IS_INT(v))
return JSVAL_INT;
return JSVAL_TAG(v);
}
2008-06-28 18:19:21 -07:00
/* Write out a type map for the current scopes and all outer scopes,
up until the entry scope. */
static void
buildTypeMap(JSStackFrame* entryFrame, JSStackFrame* fp, JSFrameRegs& regs, char* m)
2008-06-28 18:19:21 -07:00
{
if (fp != entryFrame)
buildTypeMap(entryFrame, fp->down, *fp->down->regs, m);
2008-06-28 18:19:21 -07:00
for (unsigned n = 0; n < fp->argc; ++n)
*m++ = gettag(fp->argv[n]);
2008-06-28 18:19:21 -07:00
for (unsigned n = 0; n < fp->nvars; ++n)
*m++ = gettag(fp->vars[n]);
for (jsval* sp = fp->spbase; sp < regs.sp; ++sp)
*m++ = gettag(*sp);
2008-06-28 18:19:21 -07:00
}
/* Make sure that all loop-carrying values have a stable type. */
static bool
verifyTypeStability(JSStackFrame* entryFrame, JSStackFrame* fp, JSFrameRegs& regs, char* m)
{
if (fp != entryFrame)
verifyTypeStability(entryFrame, fp->down, *fp->down->regs, m);
for (unsigned n = 0; n < fp->argc; ++n)
if (*m++ != gettag(fp->argv[n]))
return false;
for (unsigned n = 0; n < fp->nvars; ++n)
if (*m++ != gettag(fp->vars[n]))
return false;
for (jsval* sp = fp->spbase; sp < regs.sp; ++sp)
if (*m++ != gettag(*sp))
return false;
return true;
}
/* Unbox a jsval into a slot. Slots are wide enough to hold double values
directly (instead of storing a pointer to them). */
static bool
unbox_jsval(jsval v, int t, double* slot)
{
if (t != gettag(v))
return false;
switch (t) {
case JSVAL_BOOLEAN:
*(bool*)slot = JSVAL_TO_BOOLEAN(v);
break;
case JSVAL_INT:
*(jsint*)slot = JSVAL_TO_INT(v);
break;
case JSVAL_DOUBLE:
*(jsdouble*)slot = *JSVAL_TO_DOUBLE(v);
break;
case JSVAL_STRING:
*(JSString**)slot = JSVAL_TO_STRING(v);
break;
default:
JS_ASSERT(JSVAL_IS_GCTHING(v));
*(void**)slot = JSVAL_TO_GCTHING(v);
}
return true;
}
/* 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. */
static bool
box_jsval(JSContext* cx, jsval* vp, int t, double* slot)
{
switch (t) {
case JSVAL_BOOLEAN:
*vp = BOOLEAN_TO_JSVAL(*(bool*)slot);
break;
case JSVAL_INT:
jsint i = *(jsint*)slot;
JS_ASSERT(INT_FITS_IN_JSVAL(i));
*vp = INT_TO_JSVAL(i);
break;
case JSVAL_DOUBLE:
return js_NewDoubleInRootedValue(cx, *slot, vp);
case JSVAL_STRING:
*vp = STRING_TO_JSVAL(*(JSString**)slot);
break;
default:
JS_ASSERT(t == JSVAL_OBJECT);
*vp = OBJECT_TO_JSVAL(*(JSObject**)slot);
break;
}
return true;
}
/* Attempt to unbox the given JS frame into a native frame, checking
along the way that the supplied typemap holds. */
static bool
unbox(JSStackFrame* fp, JSFrameRegs& regs, char* m, double* native)
{
jsval* vp;
for (vp = fp->argv; vp < fp->argv + fp->argc; ++vp)
if (!unbox_jsval(*vp, (JSType)*m++, native++))
return false;
for (vp = fp->vars; vp < fp->vars + fp->nvars; ++vp)
if (!unbox_jsval(*vp, (JSType)*m++, native++))
return false;
for (vp = fp->spbase; vp < regs.sp; ++vp)
if (!unbox_jsval(*vp, (JSType)*m++, native++))
return false;
return true;
}
/* Attempt to unbox the given JS frame into a native frame, checking
along the way that the supplied typemap holds. */
static bool
box(JSContext* cx, JSStackFrame* fp, JSFrameRegs& regs, char* m, double* native)
{
jsval* vp;
for (vp = fp->argv; vp < fp->argv + fp->argc; ++vp)
if (!box_jsval(cx, vp, (JSType)*m++, native++))
return false;
for (vp = fp->vars; vp < fp->vars + fp->nvars; ++vp)
if (!box_jsval(cx, vp, (JSType)*m++, native++))
return false;
for (vp = fp->spbase; vp < regs.sp; ++vp)
if (!box_jsval(cx, vp, (JSType)*m++, native++))
return false;
return true;
}
/* Emit load instructions onto the trace that read the initial stack state. */
void
TraceRecorder::import(jsval* p, char *prefix, int index)
{
JS_ASSERT(onFrame(p));
LIns *ins = lir->insLoad(JSVAL_IS_DOUBLE(*p) ? LIR_ldq : LIR_ld,
fragment->sp, nativeFrameOffset(p));
tracker.set(p, ins);
#ifdef DEBUG
if (prefix) {
char name[16];
JS_ASSERT(strlen(prefix) < 10);
2008-07-01 15:58:47 -07:00
JS_snprintf(name, sizeof name, "$%s%d", prefix, index);
lirbuf->names->addName(ins, name);
}
#endif
}
/* Update the tracker. If the value is part of any argv/vars/stack of any
currently active frame (onFrame), then issue a write back store. */
void
TraceRecorder::set(void* p, LIns* i)
{
tracker.set(p, i);
if (onFrame(p))
lir->insStorei(i, fragment->sp, nativeFrameOffset(p));
}
LIns*
TraceRecorder::get(void* p)
{
if (p == cx)
return cx_ins;
return tracker.get(p);
}
void
TraceRecorder::copy(void* a, void* v)
{
set(v, get(a));
}
void
TraceRecorder::imm(jsint i, void* v)
{
set(v, lir->insImm(i));
}
void
TraceRecorder::imm(jsdouble d, void* v)
{
set(v, lir->insImmq(*(uint64_t*)&d));
}
void
TraceRecorder::unary(LOpcode op, void* a, void* v)
{
set(v, lir->ins1(op, get(a)));
}
void
TraceRecorder::binary(LOpcode op, void* a, void* b, void* v)
{
set(v, lir->ins2(op, get(a), get(b)));
}
void
TraceRecorder::binary0(LOpcode op, void* a, void* v)
{
set(v, lir->ins2i(op, get(a), 0));
}
void
TraceRecorder::choose(void* cond, void* iftrue, void* iffalse, void* v)
{
set(v, lir->ins_choose(get(cond), get(iftrue), get(iffalse), true));
}
void
TraceRecorder::choose_eqi(void* a, int32_t b, void* iftrue, void* iffalse, void* v)
{
set(v, lir->ins_choose(lir->ins2i(LIR_eq, get(a), b), get(iftrue), get(iffalse), true));
}
void
TraceRecorder::call(int id, void* a, void* v)
{
LInsp args[] = { get(a) };
set(v, lir->insCall(id, args));
}
void
TraceRecorder::call(int id, void* a, void* b, void* v)
{
LInsp args[] = { get(a), get(b) };
set(v, lir->insCall(id, args));
}
void
TraceRecorder::call(int id, void* a, void* b, void* c, void* v)
{
LInsp args[] = { get(a), get(b), get(c) };
set(v, lir->insCall(id, args));
}
void
TraceRecorder::iinc(void* a, int incr, void* v)
{
LIns* ov = lir->ins2(LIR_add, get(a), lir->insImm(incr));
// This check is actually supposed to happen before iinc, however,
// we arrive at iinc only if CAN_DO_INC_DEC passed, so we know that the
// inverse of it (overflow check) must evaluate to false in the trace.
// We delay setting v to the result of the calculation until after the
// guard to make sure the result is not communicated to the interpreter
// in case this guard fails (as it was supposed to execute _before_ the
// add, not after.)
guard_ov(false, a);
set(v, ov);
}
SideExit*
TraceRecorder::snapshot()
{
/* generate the entry map and stash it in the trace */
unsigned slots = nativeFrameSlots(cx->fp, *cx->fp->regs);
trackNativeFrameUse(slots);
LIns* data = lir_buf_writer->skip(sizeof(VMSideExitInfo) + slots * sizeof(char));
VMSideExitInfo* si = (VMSideExitInfo*)data->payload();
buildTypeMap(entryFrame, cx->fp, *cx->fp->regs, si->typeMap);
/* setup side exit structure */
memset(&exit, 0, sizeof(exit));
#ifdef DEBUG
exit.from = fragment;
#endif
exit.calldepth = calldepth();
exit.sp_adj = (cx->fp->regs->sp - entryRegs.sp + 1) * sizeof(double);
exit.ip_adj = cx->fp->regs->pc - entryRegs.pc;
exit.vmprivate = si;
return &exit;
}
void
TraceRecorder::guard_0(bool expected, void* a)
{
lir->insGuard(expected ? LIR_xf : LIR_xt,
get(a),
snapshot());
}
void
TraceRecorder::guard_h(bool expected, void* a)
{
lir->insGuard(expected ? LIR_xf : LIR_xt,
lir->ins1(LIR_callh, get(a)),
snapshot());
}
void
TraceRecorder::guard_ov(bool expected, void* a)
{
lir->insGuard(expected ? LIR_xf : LIR_xt,
lir->ins1(LIR_ov, get(a)),
snapshot());
}
void
TraceRecorder::guard_eq(bool expected, void* a, void* b)
{
lir->insGuard(expected ? LIR_xf : LIR_xt,
lir->ins2(LIR_eq, get(a), get(b)),
snapshot());
}
void
TraceRecorder::guard_eqi(bool expected, void* a, int i)
{
lir->insGuard(expected ? LIR_xf : LIR_xt,
lir->ins2i(LIR_eq, get(a), i),
snapshot());
}
void
TraceRecorder::load(void* a, int32_t i, void* v)
{
set(v, lir->insLoadi(get(a), i));
}
void
TraceRecorder::closeLoop(Fragmento* fragmento)
{
if (!verifyTypeStability(entryFrame, entryFrame, entryRegs, entryTypeMap)) {
#ifdef DEBUG
printf("Trace rejected: unstable loop variables.\n");
#endif
return;
}
fragment->lastIns = lir->ins0(LIR_loop);
((VMFragmentInfo*)fragment->vmprivate)->maxNativeFrameSlots = maxNativeFrameSlots;
compile(fragmento->assm(), fragment);
}
bool
TraceRecorder::loopEdge(JSContext* cx, jsbytecode* pc)
{
if (pc == entryRegs.pc) {
closeLoop(JS_TRACE_MONITOR(cx).fragmento);
return false; /* done recording */
}
return false; /* abort recording */
}
void
js_DeleteRecorder(JSContext* cx)
{
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
delete tm->recorder;
tm->recorder = NULL;
}
bool
js_LoopEdge(JSContext* cx, jsbytecode* pc)
{
2008-06-22 23:42:54 -07:00
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
/* is the recorder currently active? */
if (tm->recorder) {
if (tm->recorder->loopEdge(cx, pc))
return true; /* keep recording */
js_DeleteRecorder(cx);
return false; /* done recording */
}
if (!tm->fragmento) {
Fragmento* fragmento = new (&gc) Fragmento(core);
#ifdef DEBUG
fragmento->labels = new (&gc) LabelMap(core, NULL);
#endif
fragmento->assm()->setCallTable(builtins);
tm->fragmento = fragmento;
2008-06-22 23:42:54 -07:00
}
InterpState state;
state.ip = (FOpcodep)pc;
Fragment* f = tm->fragmento->getLoop(state);
if (!f->code()) {
tm->recorder = new (&gc) TraceRecorder(cx, tm->fragmento, f);
return true; /* start recording */
}
/* execute previously recorded race */
VMFragmentInfo* fi = (VMFragmentInfo*)f->vmprivate;
double native[fi->maxNativeFrameSlots+1];
#ifdef DEBUG
*(uint64*)&native[fi->maxNativeFrameSlots] = 0xdeadbeefdeadbeefLL;
#endif
unbox(cx->fp, *cx->fp->regs, fi->typeMap, native);
state.sp = native;
state.rp = NULL;
state.f = (void*)cx;
union { NIns *code; GuardRecord* (FASTCALL *func)(InterpState*, Fragment*); } u;
u.code = f->code();
GuardRecord* lr = u.func(&state, NULL);
cx->fp->regs->sp += (((double*)state.sp - native) - 1);
cx->fp->regs->pc = (jsbytecode*)state.ip;
box(cx, cx->fp, *cx->fp->regs, ((VMSideExitInfo*)lr->vmprivate)->typeMap, native);
#ifdef DEBUG
JS_ASSERT(*(uint64*)&native[fi->maxNativeFrameSlots] == 0xdeadbeefdeadbeefLL);
#endif
return false; /* continue with regular interpreter */
}
2008-06-28 18:19:21 -07:00
void
js_AbortRecording(JSContext* cx)
{
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
JS_ASSERT(tm->recorder != NULL);
js_DeleteRecorder(cx);
2008-06-28 18:19:21 -07:00
}
bool TraceRecorder::JSOP_INTERRUPT()
{
return false;
}
bool TraceRecorder::JSOP_PUSH()
{
return false;
}
bool TraceRecorder::JSOP_POPV()
{
return false;
}
bool TraceRecorder::JSOP_ENTERWITH()
{
return false;
}
bool TraceRecorder::JSOP_LEAVEWITH()
{
return false;
}
bool TraceRecorder::JSOP_RETURN()
{
return false;
}
bool TraceRecorder::JSOP_GOTO()
{
return false;
}
bool TraceRecorder::JSOP_IFEQ()
{
return false;
}
bool TraceRecorder::JSOP_IFNE()
{
return false;
}
bool TraceRecorder::JSOP_ARGUMENTS()
{
return false;
}
bool TraceRecorder::JSOP_FORARG()
{
return false;
}
bool TraceRecorder::JSOP_FORVAR()
{
return false;
}
bool TraceRecorder::JSOP_DUP()
{
return false;
}
bool TraceRecorder::JSOP_DUP2()
{
return false;
}
bool TraceRecorder::JSOP_SETCONST()
{
return false;
}
bool TraceRecorder::JSOP_BITOR()
{
return false;
}
bool TraceRecorder::JSOP_BITXOR()
{
return false;
}
bool TraceRecorder::JSOP_BITAND()
{
return false;
}
bool TraceRecorder::JSOP_EQ()
{
return false;
}
bool TraceRecorder::JSOP_NE()
{
return false;
}
bool TraceRecorder::JSOP_LT()
{
return false;
}
bool TraceRecorder::JSOP_LE()
{
return false;
}
bool TraceRecorder::JSOP_GT()
{
return false;
}
bool TraceRecorder::JSOP_GE()
{
return false;
}
bool TraceRecorder::JSOP_LSH()
{
return false;
}
bool TraceRecorder::JSOP_RSH()
{
return false;
}
bool TraceRecorder::JSOP_URSH()
{
return false;
}
bool TraceRecorder::JSOP_ADD()
{
return false;
}
bool TraceRecorder::JSOP_SUB()
{
return false;
}
bool TraceRecorder::JSOP_MUL()
{
return false;
}
bool TraceRecorder::JSOP_DIV()
{
return false;
}
bool TraceRecorder::JSOP_MOD()
{
return false;
}
bool TraceRecorder::JSOP_NOT()
{
return false;
}
bool TraceRecorder::JSOP_BITNOT()
{
return false;
}
bool TraceRecorder::JSOP_NEG()
{
return false;
}
bool TraceRecorder::JSOP_NEW()
{
return false;
}
bool TraceRecorder::JSOP_DELNAME()
{
return false;
}
bool TraceRecorder::JSOP_DELPROP()
{
return false;
}
bool TraceRecorder::JSOP_DELELEM()
{
return false;
}
bool TraceRecorder::JSOP_TYPEOF()
{
return false;
}
bool TraceRecorder::JSOP_VOID()
{
return false;
}
bool TraceRecorder::JSOP_INCNAME()
{
return false;
}
bool TraceRecorder::JSOP_INCPROP()
{
return false;
}
bool TraceRecorder::JSOP_INCELEM()
{
return false;
}
bool TraceRecorder::JSOP_DECNAME()
{
return false;
}
bool TraceRecorder::JSOP_DECPROP()
{
return false;
}
bool TraceRecorder::JSOP_DECELEM()
{
return false;
}
bool TraceRecorder::JSOP_NAMEINC()
{
return false;
}
bool TraceRecorder::JSOP_PROPINC()
{
return false;
}
bool TraceRecorder::JSOP_ELEMINC()
{
return false;
}
bool TraceRecorder::JSOP_NAMEDEC()
{
return false;
}
bool TraceRecorder::JSOP_PROPDEC()
{
return false;
}
bool TraceRecorder::JSOP_ELEMDEC()
{
return false;
}
bool TraceRecorder::JSOP_GETPROP()
{
return false;
}
bool TraceRecorder::JSOP_SETPROP()
{
return false;
}
bool TraceRecorder::JSOP_GETELEM()
{
return false;
}
bool TraceRecorder::JSOP_SETELEM()
{
return false;
}
bool TraceRecorder::JSOP_CALLNAME()
{
return false;
}
bool TraceRecorder::JSOP_CALL()
{
return false;
}
bool TraceRecorder::JSOP_NAME()
{
return false;
}
bool TraceRecorder::JSOP_DOUBLE()
{
return false;
}
bool TraceRecorder::JSOP_STRING()
{
return false;
}
bool TraceRecorder::JSOP_ZERO()
{
return false;
}
bool TraceRecorder::JSOP_ONE()
{
return false;
}
bool TraceRecorder::JSOP_NULL()
{
return false;
}
bool TraceRecorder::JSOP_THIS()
{
return false;
}
bool TraceRecorder::JSOP_FALSE()
{
return false;
}
bool TraceRecorder::JSOP_TRUE()
{
return false;
}
bool TraceRecorder::JSOP_OR()
{
return false;
}
bool TraceRecorder::JSOP_AND()
{
return false;
}
bool TraceRecorder::JSOP_TABLESWITCH()
{
return false;
}
bool TraceRecorder::JSOP_LOOKUPSWITCH()
{
return false;
}
bool TraceRecorder::JSOP_STRICTEQ()
{
return false;
}
bool TraceRecorder::JSOP_STRICTNE()
{
return false;
}
bool TraceRecorder::JSOP_CLOSURE()
{
return false;
}
bool TraceRecorder::JSOP_EXPORTALL()
{
return false;
}
bool TraceRecorder::JSOP_EXPORTNAME()
{
return false;
}
bool TraceRecorder::JSOP_IMPORTALL()
{
return false;
}
bool TraceRecorder::JSOP_IMPORTPROP()
{
return false;
}
bool TraceRecorder::JSOP_IMPORTELEM()
{
return false;
}
bool TraceRecorder::JSOP_OBJECT()
{
return false;
}
bool TraceRecorder::JSOP_POP()
{
return false;
}
bool TraceRecorder::JSOP_POS()
{
return false;
}
bool TraceRecorder::JSOP_TRAP()
{
return false;
}
bool TraceRecorder::JSOP_GETARG()
{
return false;
}
bool TraceRecorder::JSOP_SETARG()
{
return false;
}
bool TraceRecorder::JSOP_GETVAR()
{
return false;
}
bool TraceRecorder::JSOP_SETVAR()
{
return false;
}
bool TraceRecorder::JSOP_UINT16()
{
return false;
}
bool TraceRecorder::JSOP_NEWINIT()
{
return false;
}
bool TraceRecorder::JSOP_ENDINIT()
{
return false;
}
bool TraceRecorder::JSOP_INITPROP()
{
return false;
}
bool TraceRecorder::JSOP_INITELEM()
{
return false;
}
bool TraceRecorder::JSOP_DEFSHARP()
{
return false;
}
bool TraceRecorder::JSOP_USESHARP()
{
return false;
}
bool TraceRecorder::JSOP_INCARG()
{
return false;
}
bool TraceRecorder::JSOP_INCVAR()
{
return false;
}
bool TraceRecorder::JSOP_DECARG()
{
return false;
}
bool TraceRecorder::JSOP_DECVAR()
{
return false;
}
bool TraceRecorder::JSOP_ARGINC()
{
return false;
}
bool TraceRecorder::JSOP_VARINC()
{
return false;
}
bool TraceRecorder::JSOP_ARGDEC()
{
return false;
}
bool TraceRecorder::JSOP_VARDEC()
{
return false;
}
bool TraceRecorder::JSOP_ITER()
{
return false;
}
bool TraceRecorder::JSOP_FORNAME()
{
return false;
}
bool TraceRecorder::JSOP_FORPROP()
{
return false;
}
bool TraceRecorder::JSOP_FORELEM()
{
return false;
}
bool TraceRecorder::JSOP_POPN()
{
return false;
}
bool TraceRecorder::JSOP_BINDNAME()
{
return false;
}
bool TraceRecorder::JSOP_SETNAME()
{
return false;
}
bool TraceRecorder::JSOP_THROW()
{
return false;
}
bool TraceRecorder::JSOP_IN()
{
return false;
}
bool TraceRecorder::JSOP_INSTANCEOF()
{
return false;
}
bool TraceRecorder::JSOP_DEBUGGER()
{
return false;
}
bool TraceRecorder::JSOP_GOSUB()
{
return false;
}
bool TraceRecorder::JSOP_RETSUB()
{
return false;
}
bool TraceRecorder::JSOP_EXCEPTION()
{
return false;
}
bool TraceRecorder::JSOP_LINENO()
{
return false;
}
bool TraceRecorder::JSOP_CONDSWITCH()
{
return false;
}
bool TraceRecorder::JSOP_CASE()
{
return false;
}
bool TraceRecorder::JSOP_DEFAULT()
{
return false;
}
bool TraceRecorder::JSOP_EVAL()
{
return false;
}
bool TraceRecorder::JSOP_ENUMELEM()
{
return false;
}
bool TraceRecorder::JSOP_GETTER()
{
return false;
}
bool TraceRecorder::JSOP_SETTER()
{
return false;
}
bool TraceRecorder::JSOP_DEFFUN()
{
return false;
}
bool TraceRecorder::JSOP_DEFCONST()
{
return false;
}
bool TraceRecorder::JSOP_DEFVAR()
{
return false;
}
bool TraceRecorder::JSOP_ANONFUNOBJ()
{
return false;
}
bool TraceRecorder::JSOP_NAMEDFUNOBJ()
{
return false;
}
bool TraceRecorder::JSOP_SETLOCALPOP()
{
return false;
}
bool TraceRecorder::JSOP_GROUP()
{
return false;
}
bool TraceRecorder::JSOP_SETCALL()
{
return false;
}
bool TraceRecorder::JSOP_TRY()
{
return false;
}
bool TraceRecorder::JSOP_FINALLY()
{
return false;
}
bool TraceRecorder::JSOP_NOP()
{
return false;
}
bool TraceRecorder::JSOP_ARGSUB()
{
return false;
}
bool TraceRecorder::JSOP_ARGCNT()
{
return false;
}
bool TraceRecorder::JSOP_DEFLOCALFUN()
{
return false;
}
bool TraceRecorder::JSOP_GOTOX()
{
return false;
}
bool TraceRecorder::JSOP_IFEQX()
{
return false;
}
bool TraceRecorder::JSOP_IFNEX()
{
return false;
}
bool TraceRecorder::JSOP_ORX()
{
return false;
}
bool TraceRecorder::JSOP_ANDX()
{
return false;
}
bool TraceRecorder::JSOP_GOSUBX()
{
return false;
}
bool TraceRecorder::JSOP_CASEX()
{
return false;
}
bool TraceRecorder::JSOP_DEFAULTX()
{
return false;
}
bool TraceRecorder::JSOP_TABLESWITCHX()
{
return false;
}
bool TraceRecorder::JSOP_LOOKUPSWITCHX()
{
return false;
}
bool TraceRecorder::JSOP_BACKPATCH()
{
return false;
}
bool TraceRecorder::JSOP_BACKPATCH_POP()
{
return false;
}
bool TraceRecorder::JSOP_THROWING()
{
return false;
}
bool TraceRecorder::JSOP_SETRVAL()
{
return false;
}
bool TraceRecorder::JSOP_RETRVAL()
{
return false;
}
bool TraceRecorder::JSOP_GETGVAR()
{
return false;
}
bool TraceRecorder::JSOP_SETGVAR()
{
return false;
}
bool TraceRecorder::JSOP_INCGVAR()
{
return false;
}
bool TraceRecorder::JSOP_DECGVAR()
{
return false;
}
bool TraceRecorder::JSOP_GVARINC()
{
return false;
}
bool TraceRecorder::JSOP_GVARDEC()
{
return false;
}
bool TraceRecorder::JSOP_REGEXP()
{
return false;
}
bool TraceRecorder::JSOP_DEFXMLNS()
{
return false;
}
bool TraceRecorder::JSOP_ANYNAME()
{
return false;
}
bool TraceRecorder::JSOP_QNAMEPART()
{
return false;
}
bool TraceRecorder::JSOP_QNAMECONST()
{
return false;
}
bool TraceRecorder::JSOP_QNAME()
{
return false;
}
bool TraceRecorder::JSOP_TOATTRNAME()
{
return false;
}
bool TraceRecorder::JSOP_TOATTRVAL()
{
return false;
}
bool TraceRecorder::JSOP_ADDATTRNAME()
{
return false;
}
bool TraceRecorder::JSOP_ADDATTRVAL()
{
return false;
}
bool TraceRecorder::JSOP_BINDXMLNAME()
{
return false;
}
bool TraceRecorder::JSOP_SETXMLNAME()
{
return false;
}
bool TraceRecorder::JSOP_XMLNAME()
{
return false;
}
bool TraceRecorder::JSOP_DESCENDANTS()
{
return false;
}
bool TraceRecorder::JSOP_FILTER()
{
return false;
}
bool TraceRecorder::JSOP_ENDFILTER()
{
return false;
}
bool TraceRecorder::JSOP_TOXML()
{
return false;
}
bool TraceRecorder::JSOP_TOXMLLIST()
{
return false;
}
bool TraceRecorder::JSOP_XMLTAGEXPR()
{
return false;
}
bool TraceRecorder::JSOP_XMLELTEXPR()
{
return false;
}
bool TraceRecorder::JSOP_XMLOBJECT()
{
return false;
}
bool TraceRecorder::JSOP_XMLCDATA()
{
return false;
}
bool TraceRecorder::JSOP_XMLCOMMENT()
{
return false;
}
bool TraceRecorder::JSOP_XMLPI()
{
return false;
}
bool TraceRecorder::JSOP_CALLPROP()
{
return false;
}
bool TraceRecorder::JSOP_GETFUNNS()
{
return false;
}
bool TraceRecorder::JSOP_UNUSED186()
{
return false;
}
bool TraceRecorder::JSOP_DELDESC()
{
return false;
}
bool TraceRecorder::JSOP_UINT24()
{
return false;
}
bool TraceRecorder::JSOP_INDEXBASE()
{
return false;
}
bool TraceRecorder::JSOP_RESETBASE()
{
return false;
}
bool TraceRecorder::JSOP_RESETBASE0()
{
return false;
}
bool TraceRecorder::JSOP_STARTXML()
{
return false;
}
bool TraceRecorder::JSOP_STARTXMLEXPR()
{
return false;
}
bool TraceRecorder::JSOP_CALLELEM()
{
return false;
}
bool TraceRecorder::JSOP_STOP()
{
return false;
}
bool TraceRecorder::JSOP_GETXPROP()
{
return false;
}
bool TraceRecorder::JSOP_CALLXMLNAME()
{
return false;
}
bool TraceRecorder::JSOP_TYPEOFEXPR()
{
return false;
}
bool TraceRecorder::JSOP_ENTERBLOCK()
{
return false;
}
bool TraceRecorder::JSOP_LEAVEBLOCK()
{
return false;
}
bool TraceRecorder::JSOP_GETLOCAL()
{
return false;
}
bool TraceRecorder::JSOP_SETLOCAL()
{
return false;
}
bool TraceRecorder::JSOP_INCLOCAL()
{
return false;
}
bool TraceRecorder::JSOP_DECLOCAL()
{
return false;
}
bool TraceRecorder::JSOP_LOCALINC()
{
return false;
}
bool TraceRecorder::JSOP_LOCALDEC()
{
return false;
}
bool TraceRecorder::JSOP_FORLOCAL()
{
return false;
}
bool TraceRecorder::JSOP_FORCONST()
{
return false;
}
bool TraceRecorder::JSOP_ENDITER()
{
return false;
}
bool TraceRecorder::JSOP_GENERATOR()
{
return false;
}
bool TraceRecorder::JSOP_YIELD()
{
return false;
}
bool TraceRecorder::JSOP_ARRAYPUSH()
{
return false;
}
bool TraceRecorder::JSOP_UNUSED213()
{
return false;
}
bool TraceRecorder::JSOP_ENUMCONSTELEM()
{
return false;
}
bool TraceRecorder::JSOP_LEAVEBLOCKEXPR()
{
return false;
}
bool TraceRecorder::JSOP_GETTHISPROP()
{
return false;
}
bool TraceRecorder::JSOP_GETARGPROP()
{
return false;
}
bool TraceRecorder::JSOP_GETVARPROP()
{
return false;
}
bool TraceRecorder::JSOP_GETLOCALPROP()
{
return false;
}
bool TraceRecorder::JSOP_INDEXBASE1()
{
return false;
}
bool TraceRecorder::JSOP_INDEXBASE2()
{
return false;
}
bool TraceRecorder::JSOP_INDEXBASE3()
{
return false;
}
bool TraceRecorder::JSOP_CALLGVAR()
{
return false;
}
bool TraceRecorder::JSOP_CALLVAR()
{
return false;
}
bool TraceRecorder::JSOP_CALLARG()
{
return false;
}
bool TraceRecorder::JSOP_CALLLOCAL()
{
return false;
}
bool TraceRecorder::JSOP_INT8()
{
return false;
}
bool TraceRecorder::JSOP_INT32()
{
return false;
}
bool TraceRecorder::JSOP_LENGTH()
{
return false;
}
bool TraceRecorder::JSOP_NEWARRAY()
{
return false;
}
bool TraceRecorder::JSOP_HOLE()
{
return false;
}