Signal error from the boxing/unboxing using magic cookies since gcc seems to very seriously object to the use of uint64 return values during a fastcall (horribly inefficient code).
Signal error from the boxing/unboxing using magic cookies since gcc seems to very seriously object to the use of uint64 return values during a fastcall (horribly inefficient code).
--- a/js/src/Makefile.ref
+++ b/js/src/Makefile.ref
@@ -78,22 +78,26 @@ DEFINES += -DJS_USE_ONLY_NSPR_LOCKS
endif
ifdef JS_HAS_FILE_OBJECT
DEFINES += -DJS_HAS_FILE_OBJECT
endif
DEFINES += -DFEATURE_NANOJIT -DAVMPLUS_IA32 -DTRACEMONKEY
+INTERP_OPTIMIZER = -O3 -fstrict-aliasing
+BUILTINS_OPTIMIZER = -O9 -fstrict-aliasing -momit-leaf-frame-pointer
+
#
# XCFLAGS may be set in the environment or on the gmake command line
#
#CFLAGS += -DDEBUG -DDEBUG_brendan -DJS_ARENAMETER -DJS_HASHMETER -DJS_DUMP_PROPTREE_STATS -DJS_DUMP_SCOPE_METERS -DJS_SCOPE_DEPTH_METER -DJS_BASIC_STATS
CFLAGS += $(OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS)
INTERP_CFLAGS += $(INTERP_OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS) $(INTERP_XCFLAGS)
+BUILTINS_CFLAGS += $(BUILTINS_OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS) $(BUILTINS_XCFLAGS)
LDFLAGS = $(XLDFLAGS)
LDFLAGS += $(OS_LDFLAGS)
ifdef MOZ_SHARK
DEFINES += -DMOZ_SHARK
CFLAGS += -F/System/Library/PrivateFrameworks
LDFLAGS += -F/System/Library/PrivateFrameworks -framework CHUD
@@ -266,16 +270,17 @@ JS_CPPFILES = \
nanojit/Assembler.cpp \
nanojit/Fragmento.cpp \
nanojit/LIR.cpp \
nanojit/Nativei386.cpp \
nanojit/RegAlloc.cpp \
nanojit/avmplus.cpp \
nanojit/Tests.cpp \
nanojit/TraceTreeDrawer.cpp \
+ jsbuiltins.cpp \
$(NULL)
ifdef JS_LIVECONNECT
DIRS += liveconnect
endif
ifdef JS_HAS_FILE_OBJECT
JS_CPPFILES += jsfile.cpp
@@ -378,18 +383,16 @@ DEPENDENCIES = $(CPPFILES:%.cpp=$(OBJ
# Hardwire dependencies for some files
#
ifdef USE_MSVC
OBJ=obj
else
OBJ=o
endif
-$(OBJDIR)/jsinterp.$(OBJ): jsinterpinlines.h
-$(OBJDIR)/jstracer.$(OBJ): jsinterpinlines.h jstracerinlines.h
$(OBJDIR)/jsinvoke.$(OBJ): jsinterp.h jsinterp.cpp
$(OBJDIR)/jsinvoke.obj : jsinterp.h jsinterp.cpp
-include $(DEPENDENCIES)
TARNAME = jsref.tar
TARFILES = files `cat files`
--- a/js/src/builtins.tbl
+++ b/js/src/builtins.tbl
@@ -31,12 +31,12 @@
* 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 ***** */
-BUILTIN2(BoxDouble, LO, F, Q, uint64, JSContext*, jsdouble, 1, 1)
-BUILTIN2(BoxInt32, LO, LO, Q, uint64, JSContext*, jsint, 1, 1)
-BUILTIN1(UnboxInt32, LO, Q, uint64, jsval*, 1, 1)
+BUILTIN2(BoxDouble, LO, F, LO, jsval, JSContext*, jsdouble, 1, 1)
+BUILTIN2(BoxInt32, LO, LO, LO, jsval, JSContext*, jsint, 1, 1)
+BUILTIN1(UnboxInt32, LO, LO, int32, jsval, 1, 1)
BUILTIN2(dmod, F, F, F, jsdouble, jsdouble, jsdouble, 1, 1)
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -131,71 +131,16 @@ Tracker::set(const void* v, LIns* ins)
#define Q ARGSIZE_Q
#ifdef DEBUG
#define NAME(op) ,#op
#else
#define NAME(op)
#endif
-FASTCALL 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;
-}
-
-/* The following boxing/unboxing primitives we can't emit inline because
- they either interact with the GC and depend on Spidermonkey's 32-bit
- integer representation. */
-
-inline FASTCALL uint64 builtin_BoxDouble(JSContext* cx, jsdouble d)
-{
- if (!cx->doubleFreeList) /* we must be certain the GC won't kick in */
- return 1LL << 32;
- jsval v; /* not rooted but ok here because we know GC won't run */
-#ifdef DEBUG
- bool ok =
-#endif
- js_NewDoubleInRootedValue(cx, d, &v);
-#ifdef DEBUG
- JS_ASSERT(ok);
-#endif
- return v & 0xffffffffLL;
-}
-
-inline FASTCALL uint64 builtin_BoxInt32(JSContext* cx, jsint i)
-{
- if (JS_LIKELY(INT_FITS_IN_JSVAL(i)))
- return INT_TO_JSVAL(i) & 0xffffffffLL;
- return builtin_BoxDouble(cx, (jsdouble)i);
-}
-
-inline FASTCALL uint64 builtin_UnboxInt32(JSContext* cx, jsval v)
-{
- if (JS_LIKELY(JSVAL_IS_INT(v)))
- return JSVAL_TO_INT(v);
- jsint i;
- if (JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_INT(*JSVAL_TO_DOUBLE(v), i))
- return i;
- return 1LL << 32;
-}
-
#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[] = {
@@ -213,18 +158,20 @@ buildTypeMap(JSStackFrame* entryFrame, J
TraceRecorder::TraceRecorder(JSContext* cx, Fragmento* fragmento, Fragment* _fragment)
{
this->cx = cx;
this->fragment = _fragment;
entryFrame = cx->fp;
entryRegs.pc = entryFrame->regs->pc;
entryRegs.sp = entryFrame->regs->sp;
+#ifdef DEBUG
printf("entryRegs.pc=%p opcode=%d\n", entryRegs.pc, *entryRegs.pc);
-
+#endif
+
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
@@ -669,18 +616,16 @@ js_LoopEdge(JSContext* cx)
}
void
js_AbortRecording(JSContext* cx, const char* reason)
{
#ifdef DEBUG
printf("Abort recording: %s.\n", reason);
#endif
- JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
- JS_ASSERT(tm->recorder != NULL);
js_DeleteRecorder(cx);
}
jsval&
TraceRecorder::argval(unsigned n) const
{
JS_ASSERT((n >= 0) && (n <= cx->fp->argc));
return cx->fp->argv[n];
@@ -896,34 +841,34 @@ TraceRecorder::native_get(LIns* obj_ins,
return false;
}
LIns*
TraceRecorder::int32_to_jsval(LIns* i_ins)
{
LIns* args[] = { cx_ins, i_ins };
LIns* ret = lir->insCall(F_BoxInt32, args);
- guard(false, lir->ins_eq0(lir->ins1(LIR_callh, ret)));
+ guard(false, lir->ins2(LIR_eq, ret, lir->insImmPtr((void*)JSVAL_ERROR_COOKIE)));
return ret;
}
LIns*
TraceRecorder::double_to_jsval(LIns* d_ins)
{
LIns* args[] = { cx_ins, d_ins };
LIns* ret = lir->insCall(F_BoxDouble, args);
- guard(false, lir->ins_eq0(lir->ins1(LIR_callh, ret)));
+ guard(false, lir->ins2(LIR_eq, ret, lir->insImmPtr((void*)JSVAL_ERROR_COOKIE)));
return ret;
}
LIns*
TraceRecorder::jsval_to_int32(LIns* v_ins)
{
LIns* ret = lir->insCall(F_UnboxInt32, &v_ins);
- guard(true, lir->ins_eq0(lir->ins1(LIR_callh, ret)));
+ guard(false, lir->ins2i(LIR_eq, ret, INT32_ERROR_COOKIE));
return ret;
}
LIns*
TraceRecorder::jsval_to_double(LIns* v_ins)
{
guard(true, lir->ins2i(LIR_eq,
lir->ins2(LIR_and, v_ins, lir->insImmPtr((void*)JSVAL_TAGMASK)),
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -43,16 +43,31 @@
#include "jsstddef.h"
#include "jslock.h"
#include "jsnum.h"
#include "jsinterp.h"
#include "nanojit/nanojit.h"
/*
+ * We use a magic boxed pointer value to represent error conditions that
+ * trigger a side exit. The address is so low that it should never be
+ * actually in use. If it is, a performance regression occurs, not an
+ * actual runtime error.
+ */
+#define JSVAL_ERROR_COOKIE OBJECT_TO_JSVAL((void*)0x10)
+
+/*
+ * We also need a magic unboxed 32-bit integer that signals an error.
+ * Again if this number is hit we experience a performance regression,
+ * not a runtime error.
+ */
+#define INT32_ERROR_COOKIE 0xffffabcd
+
+/*
* Tracker is used to keep track of values being manipulated by the
* interpreter during trace recording.
*/
class Tracker
{
struct Page {
struct Page* next;
jsuword base;
@@ -391,16 +406,21 @@ public:
bool JSOP_CALLLOCAL();
bool JSOP_INT8();
bool JSOP_INT32();
bool JSOP_LENGTH();
bool JSOP_NEWARRAY();
bool JSOP_HOLE();
};
+FASTCALL jsdouble builtin_dmod(jsdouble a, jsdouble b);
+FASTCALL jsval builtin_BoxDouble(JSContext* cx, jsdouble d);
+FASTCALL jsval builtin_BoxInt32(JSContext* cx, jsint i);
+FASTCALL jsint builtin_UnboxInt32(JSContext* cx, jsval v);
+
/*
* Trace monitor. Every runtime is associated with a trace monitor that keeps
* track of loop frequencies for all JavaScript code loaded into that runtime.
* For this we use a loop table. Adjacent slots in the loop table, one for each
* loop header in a given script, are requested using lock-free synchronization
* from the runtime-wide loop table slot space, when the script is compiled.
*
* The loop table also doubles as trace tree pointer table once a loop achieves
--- a/js/src/rules.mk
+++ b/js/src/rules.mk
@@ -76,16 +76,20 @@ endif
$(OBJDIR)/%.o: %.cpp %.h
@$(MAKE_OBJDIR)
$(CXX) -o $@ -c $(CFLAGS) $*.cpp
$(OBJDIR)/jsinterp.o: jsinterp.cpp jsinterp.h
@$(MAKE_OBJDIR)
$(CXX) -o $@ -c $(INTERP_CFLAGS) jsinterp.cpp
+$(OBJDIR)/jsbuiltins.o: jsbuiltins.cpp jsinterp.h
+ @$(MAKE_OBJDIR)
+ $(CXX) -o $@ -c $(BUILTINS_CFLAGS) jsbuiltins.cpp
+
$(OBJDIR)/%.o: %.cpp
@$(MAKE_OBJDIR)
$(CXX) -o $@ -c $(CFLAGS) $*.cpp
$(OBJDIR)/%.o: %.s
@$(MAKE_OBJDIR)
$(AS) -o $@ $(ASFLAGS) $*.s
@@ -93,16 +97,20 @@ endif
$(OBJDIR)/%.obj: %.cpp %.h
@$(MAKE_OBJDIR)
$(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(JSDLL_CFLAGS) $*.cpp
$(OBJDIR)/jsinterp.obj: jsinterp.cpp jsinterp.h
@$(MAKE_OBJDIR)
$(CXX) -Fo$(OBJDIR)/ -c $(INTERP_CFLAGS) $(JSDLL_CFLAGS) jsinterp.c
+$(OBJDIR)/jsbuiltins.obj: jsbuiltins.cpp jsinterp.h
+ @$(MAKE_OBJDIR)
+ $(CXX) -Fo$(OBJDIR)/ -c $(BUILTINS_CFLAGS) $(JSDLL_CFLAGS) jsbuiltins.c
+
$(OBJDIR)/%.obj: %.cpp
@$(MAKE_OBJDIR)
$(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(JSDLL_CFLAGS) $*.cpp
$(OBJDIR)/js.obj: js.cpp
@$(MAKE_OBJDIR)
$(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $<