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).
authorAndreas Gal <gal@mozilla.com>
Sat, 05 Jul 2008 16:28:03 -0700
changeset 17434 f5a30a112d06eacf7a701fcf27123fd4907e97cf
parent 17433 8c6d36837b228e0b633f5e0dbc9cfaa01ad7f798
child 17435 639f37f76fa0a16a05e95a5b05c2fb81026914a5
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.1a1pre
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).
js/src/Makefile.ref
js/src/builtins.tbl
js/src/jstracer.cpp
js/src/jstracer.h
js/src/rules.mk
--- 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) $<