Bug 460904 - rename/tweak JSTraceableFunction (r=jorendorff)
☠☠ backed out by 59afbb0f510f ☠ ☠
authorLuke Wagner <lw@mozilla.com>
Thu, 03 Sep 2009 11:57:14 -0700
changeset 32667 94da2f68afdb2334ea7cc42b530f2d455d6691a2
parent 32666 66235f4c4eea68e939dc47a11dd26ab0ad894e19
child 32668 59afbb0f510f01e5d45f6ff91e2d4bffbcd3be45
push idunknown
push userunknown
push dateunknown
reviewersjorendorff
bugs460904
milestone1.9.3a1pre
Bug 460904 - rename/tweak JSTraceableFunction (r=jorendorff)
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsbuiltins.h
js/src/jsdate.cpp
js/src/jsdtracef.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsprvtd.h
js/src/jsstr.cpp
js/src/jstracer.cpp
js/src/jstracer.h
js/src/shell/js.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4394,18 +4394,18 @@ js_generic_fast_native_method_dispatcher
      */
     if (argc != 0) {
         /* Clear the last parameter in case too few arguments were passed. */
         vp[2 + --argc] = JSVAL_VOID;
     }
 
     native =
 #ifdef JS_TRACER
-             (fs->flags & JSFUN_TRACEABLE)
-             ? JS_FUNC_TO_DATA_PTR(JSTraceableNative *, fs->call)->native
+             (fs->flags & JSFUN_TRCINFO)
+             ? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native
              :
 #endif
                (JSFastNative) fs->call;
     return native(cx, argc, vp);
 }
 
 static JSBool
 js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
@@ -4493,17 +4493,17 @@ JS_DefineFunctions(JSContext *cx, JSObje
 
             flags &= ~JSFUN_GENERIC_NATIVE;
             fun = JS_DefineFunction(cx, ctor, fs->name,
                                     (flags & JSFUN_FAST_NATIVE)
                                     ? (JSNative)
                                       js_generic_fast_native_method_dispatcher
                                     : js_generic_native_method_dispatcher,
                                     fs->nargs + 1,
-                                    flags & ~JSFUN_TRACEABLE);
+                                    flags & ~JSFUN_TRCINFO);
             if (!fun)
                 return JS_FALSE;
             fun->u.n.extra = (uint16)fs->extra;
 
             /*
              * As jsapi.h notes, fs must point to storage that lives as long
              * as fun->object lives.
              */
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -80,16 +80,17 @@
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h" /* Added by JSIFY */
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbit.h"
 #include "jsbool.h"
+#include "jstracer.h"
 #include "jsbuiltins.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h" /* for js_TraceWatchPoints */
 #include "jsdtoa.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsinterp.h"
@@ -3334,25 +3335,25 @@ JS_DEFINE_TRCINFO_1(array_push,
     (3, (static, JSVAL_FAIL, Array_p_push1, CONTEXT, THIS, JSVAL,   0, 0)))
 JS_DEFINE_TRCINFO_1(array_pop,
     (2, (static, JSVAL_FAIL, Array_p_pop, CONTEXT, THIS,            0, 0)))
 
 static JSFunctionSpec array_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,      array_toSource,     0,0),
 #endif
-    JS_TN(js_toString_str,      array_toString,     0,0, array_toString_trcinfo),
+    JS_TN(js_toString_str,      array_toString,     0,0, &array_toString_trcinfo),
     JS_FN(js_toLocaleString_str,array_toLocaleString,0,0),
 
     /* Perl-ish methods. */
-    JS_TN("join",               array_join,         1,JSFUN_GENERIC_NATIVE, array_join_trcinfo),
+    JS_TN("join",               array_join,         1,JSFUN_GENERIC_NATIVE, &array_join_trcinfo),
     JS_FN("reverse",            array_reverse,      0,JSFUN_GENERIC_NATIVE),
     JS_FN("sort",               array_sort,         1,JSFUN_GENERIC_NATIVE),
-    JS_TN("push",               array_push,         1,JSFUN_GENERIC_NATIVE, array_push_trcinfo),
-    JS_TN("pop",                array_pop,          0,JSFUN_GENERIC_NATIVE, array_pop_trcinfo),
+    JS_TN("push",               array_push,         1,JSFUN_GENERIC_NATIVE, &array_push_trcinfo),
+    JS_TN("pop",                array_pop,          0,JSFUN_GENERIC_NATIVE, &array_pop_trcinfo),
     JS_FN("shift",              array_shift,        0,JSFUN_GENERIC_NATIVE),
     JS_FN("unshift",            array_unshift,      1,JSFUN_GENERIC_NATIVE),
     JS_FN("splice",             array_splice,       2,JSFUN_GENERIC_NATIVE),
 
     /* Pythonic sequence methods. */
     JS_FN("concat",             array_concat,       1,JSFUN_GENERIC_NATIVE),
     JS_FN("slice",              array_slice,        2,JSFUN_GENERIC_NATIVE),
 
--- a/js/src/jsbuiltins.h
+++ b/js/src/jsbuiltins.h
@@ -38,29 +38,30 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsbuiltins_h___
 #define jsbuiltins_h___
 
 #ifdef JS_TRACER
 
 #include "nanojit/nanojit.h"
-#include "jstracer.h"
 
 #ifdef THIS
 #undef THIS
 #endif
 
 enum JSTNErrType { INFALLIBLE, FAIL_STATUS, FAIL_NULL, FAIL_NEG, FAIL_VOID, FAIL_COOKIE };
 enum { JSTN_ERRTYPE_MASK = 0x07, JSTN_UNBOX_AFTER = 0x08, JSTN_MORE = 0x10,
        JSTN_CONSTRUCTOR = 0x20 };
 
 #define JSTN_ERRTYPE(jstn)  ((jstn)->flags & JSTN_ERRTYPE_MASK)
 
 /*
+ * Type describing a type specialization of a JSFastNative.
+ *
  * |prefix| and |argtypes| declare what arguments should be passed to the
  * native function.  |prefix| can contain the following characters:
  *
  * 'C': a JSContext* argument
  * 'T': |this| as a JSObject* argument (bails if |this| is not an object)
  * 'S': |this| as a JSString* argument (bails if |this| is not a string)
  * 'R': a JSRuntime* argument
  * 'P': the pc as a jsbytecode*
@@ -76,26 +77,36 @@ enum { JSTN_ERRTYPE_MASK = 0x07, JSTN_UN
  * 'd': a number (double) argument
  * 'i': an integer argument
  * 's': a JSString* argument
  * 'o': a JSObject* argument
  * 'r': a JSObject* argument that is of class js_RegExpClass
  * 'f': a JSObject* argument that is of class js_FunctionClass
  * 'v': a jsval argument (boxing whatever value is actually being passed in)
  */
-struct JSTraceableNative {
-    JSFastNative            native;
+struct JSSpecializedNative {
     const nanojit::CallInfo *builtin;
     const char              *prefix;
     const char              *argtypes;
     uintN                   flags;  /* JSTNErrType | JSTN_UNBOX_AFTER | JSTN_MORE |
                                        JSTN_CONSTRUCTOR */
 };
 
 /*
+ * Type holding extra trace-specific information about a fast native.
+ *
+ * 'specializations' points to a static array of available specializations
+ * terminated by the lack of having the JSTN_MORE flag set.
+ */
+struct JSNativeTraceInfo {
+    JSFastNative            native;
+    JSSpecializedNative     *specializations;
+};
+
+/*
  * 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((JSObject*)0x10)
 
 /* Macros used by JS_DEFINE_CALLINFOn. */
@@ -376,49 +387,53 @@ class ClosureVarInfo;
     _JS_CTYPE_PCH(at5) _JS_CTYPE_PCH(at4) _JS_CTYPE_PCH(at3) _JS_CTYPE_PCH(at2)                   \
         _JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0),                                                    \
     _JS_CTYPE_ACH(at5) _JS_CTYPE_ACH(at4) _JS_CTYPE_ACH(at3) _JS_CTYPE_ACH(at2)                   \
         _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at0),                                                    \
     _JS_CTYPE_FLAGS(rt)
 
 #define JS_DEFINE_TRCINFO_1(name, tn0)                                                            \
     _JS_DEFINE_CALLINFO_n tn0                                                                     \
-    JSTraceableNative name##_trcinfo[] = {                                                        \
-        { (JSFastNative)name, _JS_TN_INIT_HELPER_n tn0 }                                          \
-    };
+    JSSpecializedNative name##_sns[] = {                                                          \
+        { _JS_TN_INIT_HELPER_n tn0 }                                                              \
+    };                                                                                            \
+    JSNativeTraceInfo name##_trcinfo = { (JSFastNative)name, name##_sns };
 
 #define JS_DEFINE_TRCINFO_2(name, tn0, tn1)                                                       \
     _JS_DEFINE_CALLINFO_n tn0                                                                     \
     _JS_DEFINE_CALLINFO_n tn1                                                                     \
-    JSTraceableNative name##_trcinfo[] = {                                                        \
-        { (JSFastNative)name, _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE },                             \
-        { (JSFastNative)name, _JS_TN_INIT_HELPER_n tn1 }                                          \
-    };
+    JSSpecializedNative name##_sns[] = {                                                          \
+        { _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE },                                                 \
+        { _JS_TN_INIT_HELPER_n tn1 }                                                              \
+    };                                                                                            \
+    JSNativeTraceInfo name##_trcinfo = { (JSFastNative)name, name##_sns };
 
 #define JS_DEFINE_TRCINFO_3(name, tn0, tn1, tn2)                                                  \
     _JS_DEFINE_CALLINFO_n tn0                                                                     \
     _JS_DEFINE_CALLINFO_n tn1                                                                     \
     _JS_DEFINE_CALLINFO_n tn2                                                                     \
-    JSTraceableNative name##_trcinfo[] = {                                                        \
-        { (JSFastNative)name, _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE },                             \
-        { (JSFastNative)name, _JS_TN_INIT_HELPER_n tn1 | JSTN_MORE },                             \
-        { (JSFastNative)name, _JS_TN_INIT_HELPER_n tn2 }                                          \
-    };
+    JSSpecializedNative name##_sns[] = {                                                          \
+        { _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE },                                                 \
+        { _JS_TN_INIT_HELPER_n tn1 | JSTN_MORE },                                                 \
+        { _JS_TN_INIT_HELPER_n tn2 }                                                              \
+    };                                                                                            \
+    JSNativeTraceInfo name##_trcinfo = { (JSFastNative)name, name##_sns };
 
 #define JS_DEFINE_TRCINFO_4(name, tn0, tn1, tn2, tn3)                                             \
     _JS_DEFINE_CALLINFO_n tn0                                                                     \
     _JS_DEFINE_CALLINFO_n tn1                                                                     \
     _JS_DEFINE_CALLINFO_n tn2                                                                     \
     _JS_DEFINE_CALLINFO_n tn3                                                                     \
-    JSTraceableNative name##_trcinfo[] = {                                                        \
-        { (JSFastNative)name, _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE },                             \
-        { (JSFastNative)name, _JS_TN_INIT_HELPER_n tn1 | JSTN_MORE },                             \
-        { (JSFastNative)name, _JS_TN_INIT_HELPER_n tn2 | JSTN_MORE },                             \
-        { (JSFastNative)name, _JS_TN_INIT_HELPER_n tn3 }                                          \
-    };
+    JSSpecializedNative name##_sns[] = {                                                          \
+        { _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE },                                                 \
+        { _JS_TN_INIT_HELPER_n tn1 | JSTN_MORE },                                                 \
+        { _JS_TN_INIT_HELPER_n tn2 | JSTN_MORE },                                                 \
+        { _JS_TN_INIT_HELPER_n tn3 }                                                              \
+    };                                                                                            \
+    JSNativeTraceInfo name##_trcinfo = { (JSFastNative)name, name##_sns };
 
 #define _JS_DEFINE_CALLINFO_n(n, args)  JS_DEFINE_CALLINFO_##n args
 
 jsdouble FASTCALL
 js_StringToNumber(JSContext* cx, JSString* str);
 
 jsdouble FASTCALL
 js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed);
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -2287,17 +2287,17 @@ date_valueOf(JSContext *cx, uintN argc, 
 
 // Don't really need an argument here, but we don't support arg-less builtins
 JS_DEFINE_TRCINFO_1(date_now,
     (1, (static, DOUBLE, date_now_tn, CONTEXT, 0, 0)))
 
 static JSFunctionSpec date_static_methods[] = {
     JS_FN("UTC",                 date_UTC,                MAXARGS,0),
     JS_FN("parse",               date_parse,              1,0),
-    JS_TN("now",                 date_now,                0,0, date_now_trcinfo),
+    JS_TN("now",                 date_now,                0,0, &date_now_trcinfo),
     JS_FS_END
 };
 
 JS_DEFINE_TRCINFO_1(date_valueOf,
     (3, (static, JSVAL_RETRY, date_valueOf_tn, CONTEXT, THIS, STRING, 0, 0)))
 
 static JSFunctionSpec date_methods[] = {
     JS_FN("getTime",             date_getTime,            0,0),
@@ -2344,17 +2344,17 @@ static JSFunctionSpec date_methods[] = {
     JS_FN("toTimeString",        date_toTimeString,       0,0),
     JS_FN("toISOString",         date_toISOString,        0,0),
     JS_FN(js_toJSON_str,         date_toISOString,        0,0),
 
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,       date_toSource,           0,0),
 #endif
     JS_FN(js_toString_str,       date_toString,           0,0),
-    JS_TN(js_valueOf_str,        date_valueOf,            0,0, date_valueOf_trcinfo),
+    JS_TN(js_valueOf_str,        date_valueOf,            0,0, &date_valueOf_trcinfo),
     JS_FS_END
 };
 
 static jsdouble *
 date_constructor(JSContext *cx, JSObject* obj)
 {
     jsdouble *date;
 
--- a/js/src/jsdtracef.cpp
+++ b/js/src/jsdtracef.cpp
@@ -51,17 +51,17 @@
 
 static char dempty[] = "<null>";
 
 static char *
 jsdtrace_fun_classname(JSFunction *fun)
 {
     return (fun &&
             !FUN_INTERPRETED(fun) &&
-            !(fun->flags & JSFUN_TRACEABLE) &&
+            !(fun->flags & JSFUN_TRCINFO) &&
             FUN_CLASP(fun))
            ? (char *)FUN_CLASP(fun)->name
            : dempty;
 }
 
 static char *
 jsdtrace_filename(JSStackFrame *fp)
 {
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -2360,36 +2360,36 @@ js_NewFunction(JSContext *cx, JSObject *
         if (!funobj)
             return NULL;
     }
     JS_ASSERT(!funobj->getPrivate());
     fun = (JSFunction *) funobj;
 
     /* Initialize all function members. */
     fun->nargs = nargs;
-    fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRACEABLE);
+    fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRCINFO);
     if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
         JS_ASSERT(!native);
         JS_ASSERT(nargs == 0);
         fun->u.i.nvars = 0;
         fun->u.i.nupvars = 0;
         fun->u.i.skipmin = 0;
         fun->u.i.wrapper = false;
         fun->u.i.script = NULL;
 #ifdef DEBUG
         fun->u.i.names.taggedAtom = 0;
 #endif
     } else {
         fun->u.n.extra = 0;
         fun->u.n.spare = 0;
         fun->u.n.clasp = NULL;
-        if (flags & JSFUN_TRACEABLE) {
+        if (flags & JSFUN_TRCINFO) {
 #ifdef JS_TRACER
-            JSTraceableNative *trcinfo =
-                JS_FUNC_TO_DATA_PTR(JSTraceableNative *, native);
+            JSNativeTraceInfo *trcinfo =
+                JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, native);
             fun->u.n.native = (JSNative) trcinfo->native;
             fun->u.n.trcinfo = trcinfo;
 #else
             fun->u.n.trcinfo = NULL;
 #endif
         } else {
             fun->u.n.native = native;
             fun->u.n.trcinfo = NULL;
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -93,19 +93,19 @@ typedef union JSLocalNames {
  * NB: JSFUN_EXPR_CLOSURE reuses JSFUN_STUB_GSOPS, which is an API request flag
  * bit only, never stored in fun->flags.
  *
  * If we need more bits in the future, all flags for FUN_INTERPRETED functions
  * can move to u.i.script->flags. For now we use function flag bits to minimize
  * pointer-chasing.
  */
 #define JSFUN_EXPR_CLOSURE  0x1000  /* expression closure: function(x) x*x */
-#define JSFUN_TRACEABLE     0x2000  /* can trace across calls to this native
-                                       function; use FUN_TRCINFO if set,
-                                       FUN_CLASP if unset */
+#define JSFUN_TRCINFO       0x2000  /* when set, u.n.trcinfo is non-null,
+                                       JSFunctionSpec::call points to a
+                                       JSNativeTraceInfo. */
 #define JSFUN_INTERPRETED   0x4000  /* use u.i if kind >= this value else u.n */
 #define JSFUN_FLAT_CLOSURE  0x8000  /* flag (aka "display") closure */
 #define JSFUN_NULL_CLOSURE  0xc000  /* null closure entrains no scope chain */
 #define JSFUN_KINDMASK      0xc000  /* encode interp vs. native and closure
                                        optimization level -- see above */
 
 #define FUN_OBJECT(fun)      (&(fun)->object)
 #define FUN_KIND(fun)        ((fun)->flags & JSFUN_KINDMASK)
@@ -120,33 +120,32 @@ typedef union JSLocalNames {
                               ? (JSFastNative) (fun)->u.n.native              \
                               : NULL)
 #define FUN_MINARGS(fun)     (((fun)->flags & JSFUN_FAST_NATIVE)              \
                               ? 0                                             \
                               : (fun)->nargs)
 #define FUN_CLASP(fun)       (JS_ASSERT(!FUN_INTERPRETED(fun)),               \
                               fun->u.n.clasp)
 #define FUN_TRCINFO(fun)     (JS_ASSERT(!FUN_INTERPRETED(fun)),               \
-                              JS_ASSERT((fun)->flags & JSFUN_TRACEABLE),      \
+                              JS_ASSERT((fun)->flags & JSFUN_TRCINFO),        \
                               fun->u.n.trcinfo)
 
 struct JSFunction {
     JSObject        object;       /* GC'ed object header */
     uint16          nargs;        /* maximum number of specified arguments,
                                      reflected as f.length/f.arity */
     uint16          flags;        /* flags, see JSFUN_* below and in jsapi.h */
     union {
         struct {
             uint16      extra;    /* number of arg slots for local GC roots */
             uint16      spare;    /* reserved for future use */
             JSNative    native;   /* native method pointer or null */
             JSClass     *clasp;   /* class of objects constructed
                                      by this function */
-            JSTraceableNative *trcinfo;  /* tracer metadata; can be first
-                                            element of array */
+            JSNativeTraceInfo *trcinfo;
         } n;
         struct {
             uint16      nvars;    /* number of local variables */
             uint16      nupvars;  /* number of upvars (computable from script
                                      but here for faster access) */
             uint16       skipmin; /* net skip amount up (toward zero) from
                                      script->staticLevel to nearest upvar,
                                      including upvars in nested functions */
@@ -179,24 +178,25 @@ struct JSFunction {
         JS_ASSERT(FUN_INTERPRETED(this));
         return countLocalNames() != 0;
     }
 
     uint32 countInterpretedReservedSlots() const;
 };
 
 /*
- * Traceable native.  This expands to a JSFunctionSpec initializer (like JS_FN
- * in jsapi.h).  fastcall is a JSFastNative; trcinfo is a JSTraceableNative *.
+ * Trace-annotated native. This expands to a JSFunctionSpec initializer (like
+ * JS_FN in jsapi.h). fastcall is a JSFastNative; trcinfo is a
+ * JSNativeTraceInfo*.
  */
 #ifdef JS_TRACER
 /* MSVC demands the intermediate (void *) cast here. */
 # define JS_TN(name,fastcall,nargs,flags,trcinfo)                             \
     JS_FN(name, JS_DATA_TO_FUNC_PTR(JSNative, trcinfo), nargs,                \
-          (flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS | JSFUN_TRACEABLE)
+          (flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS | JSFUN_TRCINFO)
 #else
 # define JS_TN(name,fastcall,nargs,flags,trcinfo)                             \
     JS_FN(name, fastcall, nargs, flags)
 #endif
 
 extern JSClass js_ArgumentsClass;
 extern JS_FRIEND_DATA(JSClass) js_CallClass;
 extern JSClass js_DeclEnvClass;
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -719,34 +719,34 @@ JS_DEFINE_TRCINFO_1(js_math_ceil,
     (1, (static, DOUBLE, math_ceil_tn, DOUBLE,          1, 1)))
 
 #endif /* JS_TRACER */
 
 static JSFunctionSpec math_static_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,  math_toSource,        0, 0),
 #endif
-    JS_TN("abs",            math_abs,             1, 0, math_abs_trcinfo),
-    JS_TN("acos",           math_acos,            1, 0, math_acos_trcinfo),
-    JS_TN("asin",           math_asin,            1, 0, math_asin_trcinfo),
-    JS_TN("atan",           math_atan,            1, 0, math_atan_trcinfo),
-    JS_TN("atan2",          math_atan2,           2, 0, math_atan2_trcinfo),
-    JS_TN("ceil",           js_math_ceil,         1, 0, js_math_ceil_trcinfo),
-    JS_TN("cos",            math_cos,             1, 0, math_cos_trcinfo),
-    JS_TN("exp",            math_exp,             1, 0, math_exp_trcinfo),
-    JS_TN("floor",          js_math_floor,        1, 0, js_math_floor_trcinfo),
-    JS_TN("log",            math_log,             1, 0, math_log_trcinfo),
-    JS_TN("max",            js_math_max,          2, 0, js_math_max_trcinfo),
-    JS_TN("min",            js_math_min,          2, 0, js_math_min_trcinfo),
-    JS_TN("pow",            math_pow,             2, 0, math_pow_trcinfo),
-    JS_TN("random",         math_random,          0, 0, math_random_trcinfo),
-    JS_TN("round",          js_math_round,        1, 0, js_math_round_trcinfo),
-    JS_TN("sin",            math_sin,             1, 0, math_sin_trcinfo),
-    JS_TN("sqrt",           math_sqrt,            1, 0, math_sqrt_trcinfo),
-    JS_TN("tan",            math_tan,             1, 0, math_tan_trcinfo),
+    JS_TN("abs",            math_abs,             1, 0, &math_abs_trcinfo),
+    JS_TN("acos",           math_acos,            1, 0, &math_acos_trcinfo),
+    JS_TN("asin",           math_asin,            1, 0, &math_asin_trcinfo),
+    JS_TN("atan",           math_atan,            1, 0, &math_atan_trcinfo),
+    JS_TN("atan2",          math_atan2,           2, 0, &math_atan2_trcinfo),
+    JS_TN("ceil",           js_math_ceil,         1, 0, &js_math_ceil_trcinfo),
+    JS_TN("cos",            math_cos,             1, 0, &math_cos_trcinfo),
+    JS_TN("exp",            math_exp,             1, 0, &math_exp_trcinfo),
+    JS_TN("floor",          js_math_floor,        1, 0, &js_math_floor_trcinfo),
+    JS_TN("log",            math_log,             1, 0, &math_log_trcinfo),
+    JS_TN("max",            js_math_max,          2, 0, &js_math_max_trcinfo),
+    JS_TN("min",            js_math_min,          2, 0, &js_math_min_trcinfo),
+    JS_TN("pow",            math_pow,             2, 0, &math_pow_trcinfo),
+    JS_TN("random",         math_random,          0, 0, &math_random_trcinfo),
+    JS_TN("round",          js_math_round,        1, 0, &js_math_round_trcinfo),
+    JS_TN("sin",            math_sin,             1, 0, &math_sin_trcinfo),
+    JS_TN("sqrt",           math_sqrt,            1, 0, &math_sqrt_trcinfo),
+    JS_TN("tan",            math_tan,             1, 0, &math_tan_trcinfo),
     JS_FS_END
 };
 
 JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj)
 {
     JSObject *Math;
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -229,18 +229,18 @@ JS_DEFINE_TRCINFO_2(num_parseInt,
 JS_DEFINE_TRCINFO_1(num_parseFloat,
     (2, (static, DOUBLE, ParseFloat, CONTEXT, STRING,   1, 1)))
 
 #endif /* JS_TRACER */
 
 static JSFunctionSpec number_functions[] = {
     JS_FN(js_isNaN_str,         num_isNaN,           1,0),
     JS_FN(js_isFinite_str,      num_isFinite,        1,0),
-    JS_TN(js_parseFloat_str,    num_parseFloat,      1,0, num_parseFloat_trcinfo),
-    JS_TN(js_parseInt_str,      num_parseInt,        2,0, num_parseInt_trcinfo),
+    JS_TN(js_parseFloat_str,    num_parseFloat,      1,0, &num_parseFloat_trcinfo),
+    JS_TN(js_parseInt_str,      num_parseInt,        2,0, &num_parseInt_trcinfo),
     JS_FS_END
 };
 
 JSClass js_NumberClass = {
     js_Number_str,
     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   NULL,
@@ -603,18 +603,17 @@ JS_DEFINE_TRCINFO_2(num_toString,
     (2, (extern, STRING, js_NumberToString,      CONTEXT, THIS_DOUBLE,        1, 1)))
 
 #endif /* JS_TRACER */
 
 static JSFunctionSpec number_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,       num_toSource,          0,JSFUN_THISP_NUMBER),
 #endif
-    JS_TN(js_toString_str,       num_toString,          1,JSFUN_THISP_NUMBER,
-          num_toString_trcinfo),
+    JS_TN(js_toString_str,       num_toString,          1,JSFUN_THISP_NUMBER, &num_toString_trcinfo),
     JS_FN(js_toLocaleString_str, num_toLocaleString,    0,JSFUN_THISP_NUMBER),
     JS_FN(js_valueOf_str,        num_valueOf,           0,JSFUN_THISP_NUMBER),
     JS_FN(js_toJSON_str,         num_valueOf,           0,JSFUN_THISP_NUMBER),
     JS_FN("toFixed",             num_toFixed,           1,JSFUN_THISP_NUMBER),
     JS_FN("toExponential",       num_toExponential,     1,JSFUN_THISP_NUMBER),
     JS_FN("toPrecision",         num_toPrecision,       1,JSFUN_THISP_NUMBER),
     JS_FS_END
 };
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1978,27 +1978,24 @@ JS_DEFINE_TRCINFO_1(obj_propertyIsEnumer
     (3, (static, BOOL_FAIL, Object_p_propertyIsEnumerable,  CONTEXT, THIS, STRING,  0, 0)))
 
 static JSFunctionSpec object_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,             obj_toSource,                0,0),
 #endif
     JS_FN(js_toString_str,             obj_toString,                0,0),
     JS_FN(js_toLocaleString_str,       obj_toLocaleString,          0,0),
-    JS_TN(js_valueOf_str,              obj_valueOf,                 0,0,
-          obj_valueOf_trcinfo),
+    JS_TN(js_valueOf_str,              obj_valueOf,                 0,0, &obj_valueOf_trcinfo),
 #if JS_HAS_OBJ_WATCHPOINT
     JS_FN(js_watch_str,                obj_watch,                   2,0),
     JS_FN(js_unwatch_str,              obj_unwatch,                 1,0),
 #endif
-    JS_TN(js_hasOwnProperty_str,       obj_hasOwnProperty,          1,0,
-          obj_hasOwnProperty_trcinfo),
+    JS_TN(js_hasOwnProperty_str,       obj_hasOwnProperty,          1,0, &obj_hasOwnProperty_trcinfo),
     JS_FN(js_isPrototypeOf_str,        obj_isPrototypeOf,           1,0),
-    JS_TN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable,    1,0,
-          obj_propertyIsEnumerable_trcinfo),
+    JS_TN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable,    1,0, &obj_propertyIsEnumerable_trcinfo),
 #if JS_HAS_GETTER_SETTER
     JS_FN(js_defineGetter_str,         js_obj_defineGetter,         2,0),
     JS_FN(js_defineSetter_str,         js_obj_defineSetter,         2,0),
     JS_FN(js_lookupGetter_str,         obj_lookupGetter,            1,0),
     JS_FN(js_lookupSetter_str,         obj_lookupSetter,            1,0),
 #endif
     JS_FS_END
 };
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -123,17 +123,18 @@ typedef struct JSCodeSpec           JSCo
 typedef struct JSPrinter            JSPrinter;
 typedef struct JSRegExp             JSRegExp;
 typedef struct JSRegExpStatics      JSRegExpStatics;
 typedef struct JSScope              JSScope;
 typedef struct JSScopeOps           JSScopeOps;
 typedef struct JSScopeProperty      JSScopeProperty;
 typedef struct JSStackHeader        JSStackHeader;
 typedef struct JSSubString          JSSubString;
-typedef struct JSTraceableNative    JSTraceableNative;
+typedef struct JSNativeTraceInfo    JSNativeTraceInfo;
+typedef struct JSSpecializedNative  JSSpecializedNative;
 typedef struct JSXML                JSXML;
 typedef struct JSXMLArray           JSXMLArray;
 typedef struct JSXMLArrayCursor     JSXMLArrayCursor;
 
 /*
  * Template declarations.
  *
  * jsprvtd.h can be included in both C and C++ translation units. For C++, it
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2336,25 +2336,24 @@ JS_DEFINE_TRCINFO_1(str_concat,
 
 static JSFunctionSpec string_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN("quote",             str_quote,             0,GENERIC_PRIMITIVE),
     JS_FN(js_toSource_str,     str_toSource,          0,JSFUN_THISP_STRING),
 #endif
 
     /* Java-like methods. */
-    JS_TN(js_toString_str,     js_str_toString,       0,JSFUN_THISP_STRING,
-          js_str_toString_trcinfo),
+    JS_TN(js_toString_str,     js_str_toString,       0,JSFUN_THISP_STRING, &js_str_toString_trcinfo),
     JS_FN(js_valueOf_str,      js_str_toString,       0,JSFUN_THISP_STRING),
     JS_FN(js_toJSON_str,       js_str_toString,       0,JSFUN_THISP_STRING),
     JS_FN("substring",         str_substring,         2,GENERIC_PRIMITIVE),
     JS_FN("toLowerCase",       str_toLowerCase,       0,GENERIC_PRIMITIVE),
     JS_FN("toUpperCase",       str_toUpperCase,       0,GENERIC_PRIMITIVE),
-    JS_TN("charAt",            str_charAt,            1,GENERIC_PRIMITIVE, str_charAt_trcinfo),
-    JS_TN("charCodeAt",        str_charCodeAt,        1,GENERIC_PRIMITIVE, str_charCodeAt_trcinfo),
+    JS_TN("charAt",            str_charAt,            1,GENERIC_PRIMITIVE, &str_charAt_trcinfo),
+    JS_TN("charCodeAt",        str_charCodeAt,        1,GENERIC_PRIMITIVE, &str_charCodeAt_trcinfo),
     JS_FN("indexOf",           str_indexOf,           1,GENERIC_PRIMITIVE),
     JS_FN("lastIndexOf",       str_lastIndexOf,       1,GENERIC_PRIMITIVE),
     JS_FN("trim",              str_trim,              0,GENERIC_PRIMITIVE),
     JS_FN("trimLeft",          str_trimLeft,          0,GENERIC_PRIMITIVE),
     JS_FN("trimRight",         str_trimRight,         0,GENERIC_PRIMITIVE),
     JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,GENERIC_PRIMITIVE),
     JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,GENERIC_PRIMITIVE),
     JS_FN("localeCompare",     str_localeCompare,     1,GENERIC_PRIMITIVE),
@@ -2364,17 +2363,17 @@ static JSFunctionSpec string_methods[] =
     JS_FN("search",            str_search,            1,GENERIC_PRIMITIVE),
     JS_FN("replace",           str_replace,           2,GENERIC_PRIMITIVE),
     JS_FN("split",             str_split,             2,GENERIC_PRIMITIVE),
 #if JS_HAS_PERL_SUBSTR
     JS_FN("substr",            str_substr,            2,GENERIC_PRIMITIVE),
 #endif
 
     /* Python-esque sequence methods. */
-    JS_TN("concat",            str_concat,            1,GENERIC_PRIMITIVE, str_concat_trcinfo),
+    JS_TN("concat",            str_concat,            1,GENERIC_PRIMITIVE, &str_concat_trcinfo),
     JS_FN("slice",             str_slice,             2,GENERIC_PRIMITIVE),
 
     /* HTML string methods. */
 #if JS_HAS_STR_HTML_HELPERS
     JS_FN("bold",              str_bold,              0,PRIMITIVE),
     JS_FN("italics",           str_italics,           0,PRIMITIVE),
     JS_FN("fixed",             str_fixed,             0,PRIMITIVE),
     JS_FN("fontsize",          str_fontsize,          1,PRIMITIVE),
@@ -2481,17 +2480,17 @@ String_fromCharCode(JSContext* cx, int32
     return js_NewStringCopyN(cx, &c, 1);
 }
 #endif
 
 JS_DEFINE_TRCINFO_1(str_fromCharCode,
     (2, (static, STRING_RETRY, String_fromCharCode, CONTEXT, INT32, 1, 1)))
 
 static JSFunctionSpec string_static_methods[] = {
-    JS_TN("fromCharCode", str_fromCharCode, 1, 0, str_fromCharCode_trcinfo),
+    JS_TN("fromCharCode", str_fromCharCode, 1, 0, &str_fromCharCode_trcinfo),
     JS_FS_END
 };
 
 static JSHashNumber
 js_hash_string_pointer(const void *key)
 {
     return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS;
 }
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -1701,21 +1701,19 @@ TraceRecorder::TraceRecorder(JSContext* 
     this->atoms = FrameAtomBase(cx, cx->fp);
     this->deepAborted = false;
     this->trashSelf = false;
     this->global_dslots = this->globalObj->dslots;
     this->loop = true; /* default assumption is we are compiling a loop */
     this->wasRootFragment = _fragment == _fragment->root;
     this->outer = outer;
     this->outerArgc = outerArgc;
-    this->pendingTraceableNative = NULL;
+    this->pendingSpecializedNative = NULL;
     this->newobj_ins = NULL;
     this->loopLabel = NULL;
-    this->generatedTraceableNative = new JSTraceableNative();
-    JS_ASSERT(generatedTraceableNative);
 
 #ifdef JS_JIT_SPEW
     debug_only_print0(LC_TMMinimal, "\n");
     debug_only_printf(LC_TMMinimal, "Recording starting from %s:%u@%u\n",
                       ti->treeFileName, ti->treeLineNumber, ti->treePCOffset);
 
     debug_only_printf(LC_TMTracer, "globalObj=%p, shape=%d\n",
                       (void*)this->globalObj, OBJ_SHAPE(this->globalObj));
@@ -1837,17 +1835,16 @@ TraceRecorder::~TraceRecorder()
 #ifdef DEBUG
     debug_only_stmt( delete verbose_filter; )
 #endif
     delete cse_filter;
     delete expr_filter;
     delete func_filter;
     delete float_filter;
     delete lir_buf_writer;
-    delete generatedTraceableNative;
 }
 
 void
 TraceRecorder::removeFragmentReferences()
 {
     fragment = NULL;
 }
 
@@ -3282,18 +3279,18 @@ TraceRecorder::snapshot(ExitType exitTyp
      */
     const JSCodeSpec& cs = js_CodeSpec[*pc];
 
     /*
      * When calling a _FAIL native, make the snapshot's pc point to the next
      * instruction after the CALL or APPLY. Even on failure, a _FAIL native
      * must not be called again from the interpreter.
      */
-    bool resumeAfter = (pendingTraceableNative &&
-                        JSTN_ERRTYPE(pendingTraceableNative) == FAIL_STATUS);
+    bool resumeAfter = (pendingSpecializedNative &&
+                        JSTN_ERRTYPE(pendingSpecializedNative) == FAIL_STATUS);
     if (resumeAfter) {
         JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_APPLY || *pc == JSOP_NEW ||
                   *pc == JSOP_SETPROP || *pc == JSOP_SETNAME || *pc == JSOP_SETMETHOD);
         pc += cs.length;
         regs->pc = pc;
         MUST_FLOW_THROUGH("restore_pc");
     }
 
@@ -3331,17 +3328,17 @@ TraceRecorder::snapshot(ExitType exitTyp
     /*
      * If this snapshot is for a side exit that leaves a boxed jsval result on
      * the stack, make a note of this in the typemap. Examples include the
      * builtinStatus guard after calling a _FAIL builtin, a JSFastNative, or
      * GetPropertyByName; and the type guard in unbox_jsval after such a call
      * (also at the beginning of a trace branched from such a type guard).
      */
     if (pendingUnboxSlot ||
-        (pendingTraceableNative && (pendingTraceableNative->flags & JSTN_UNBOX_AFTER))) {
+        (pendingSpecializedNative && (pendingSpecializedNative->flags & JSTN_UNBOX_AFTER))) {
         unsigned pos = stackSlots - 1;
         if (pendingUnboxSlot == cx->fp->regs->sp - 2)
             pos = stackSlots - 2;
         typemap[pos] = TT_JSVAL;
     }
 
     /* Now restore the the original pc (after which early returns are ok). */
     if (resumeAfter) {
@@ -6154,17 +6151,17 @@ TraceRecorder::monitorRecording(JSContex
         return JSRS_STOP;
     }
     JS_ASSERT(!tr->fragment->lastIns);
 
     /*
      * Clear one-shot state used to communicate between record_JSOP_CALL and post-
      * opcode-case-guts record hook (record_NativeCallComplete).
      */
-    tr->pendingTraceableNative = NULL;
+    tr->pendingSpecializedNative = NULL;
     tr->newobj_ins = NULL;
 
     /* Handle one-shot request from finishGetProp to snapshot post-op state and guard. */
     if (tr->pendingGuardCondition) {
         tr->guard(true, tr->pendingGuardCondition, STATUS_EXIT);
         tr->pendingGuardCondition = NULL;
     }
 
@@ -9122,17 +9119,17 @@ TraceRecorder::getClassPrototype(JSProto
 {
     JSObject* proto;
     if (!js_GetClassPrototype(cx, globalObj, INT_TO_JSID(key), &proto))
         ABORT_TRACE_ERROR("error in js_GetClassPrototype");
     proto_ins = INS_CONSTOBJ(proto);
     return JSRS_CONTINUE;
 }
 
-#define IGNORE_NATIVE_CALL_COMPLETE_CALLBACK ((JSTraceableNative*)1)
+#define IGNORE_NATIVE_CALL_COMPLETE_CALLBACK ((JSSpecializedNative*)1)
 
 JSRecordingStatus
 TraceRecorder::newString(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval)
 {
     JS_ASSERT(argc == 1);
 
     if (!JSVAL_IS_PRIMITIVE(argv[0])) {
         ABORT_IF_XML(argv[0]);
@@ -9142,17 +9139,17 @@ TraceRecorder::newString(JSObject* ctor,
     LIns* proto_ins;
     CHECK_STATUS(getClassPrototype(ctor, proto_ins));
 
     LIns* args[] = { stringify(argv[0]), proto_ins, cx_ins };
     LIns* obj_ins = lir->insCall(&js_String_tn_ci, args);
     guard(false, lir->ins_eq0(obj_ins), OOM_EXIT);
 
     set(rval, obj_ins);
-    pendingTraceableNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
+    pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
     return JSRS_CONTINUE;
 }
 
 JSRecordingStatus
 TraceRecorder::newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval)
 {
     LIns *proto_ins;
     CHECK_STATUS(getClassPrototype(ctor, proto_ins));
@@ -9183,17 +9180,17 @@ TraceRecorder::newArray(JSObject* ctor, 
             stobj_set_dslot(arr_ins, i, dslots_ins, elt_ins);
         }
 
         if (argc > 0)
             stobj_set_fslot(arr_ins, JSSLOT_ARRAY_COUNT, INS_CONST(argc));
     }
 
     set(rval, arr_ins);
-    pendingTraceableNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
+    pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK void
 TraceRecorder::propagateFailureToBuiltinStatus(LIns* ok_ins, LIns*& status_ins)
 {
     /*
      * Check the boolean return value (ok_ins) of a native JSNative,
@@ -9264,24 +9261,24 @@ TraceRecorder::emitNativePropertyOp(JSSc
     propagateFailureToBuiltinStatus(ok_ins, status_ins);
     guard(true, lir->ins_eq0(status_ins), STATUS_EXIT);
 
     // Re-load the value--but this is currently unused, so commented out.
     //boxed_ins = lir->insLoad(LIR_ldp, vp_ins, 0);
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
-TraceRecorder::emitNativeCall(JSTraceableNative* known, uintN argc, LIns* args[])
-{
-    bool constructing = known->flags & JSTN_CONSTRUCTOR;
-
-    if (JSTN_ERRTYPE(known) == FAIL_STATUS) {
+TraceRecorder::emitNativeCall(JSSpecializedNative* sn, uintN argc, LIns* args[])
+{
+    bool constructing = sn->flags & JSTN_CONSTRUCTOR;
+
+    if (JSTN_ERRTYPE(sn) == FAIL_STATUS) {
         // This needs to capture the pre-call state of the stack. So do not set
-        // pendingTraceableNative before taking this snapshot.
-        JS_ASSERT(!pendingTraceableNative);
+        // pendingSpecializedNative before taking this snapshot.
+        JS_ASSERT(!pendingSpecializedNative);
 
         // Take snapshot for js_DeepBail and store it in cx->bailExit.
         // If we are calling a slow native, add information to the side exit
         // for SynthesizeSlowNativeFrame.
         VMSideExit* exit = snapshot(DEEP_BAIL_EXIT);
         JSObject* funobj = JSVAL_TO_OBJECT(stackval(0 - (2 + argc)));
         if (FUN_SLOW_NATIVE(GET_FUNCTION_PRIVATE(cx, funobj))) {
             exit->setNativeCallee(funobj, constructing);
@@ -9289,19 +9286,19 @@ TraceRecorder::emitNativeCall(JSTraceabl
         }
         lir->insStorei(INS_CONSTPTR(exit), cx_ins, offsetof(JSContext, bailExit));
 
         // Tell nanojit not to discard or defer stack writes before this call.
         LIns* guardRec = createGuardRecord(exit);
         lir->insGuard(LIR_xbarrier, NULL, guardRec);
     }
 
-    LIns* res_ins = lir->insCall(known->builtin, args);
+    LIns* res_ins = lir->insCall(sn->builtin, args);
     rval_ins = res_ins;
-    switch (JSTN_ERRTYPE(known)) {
+    switch (JSTN_ERRTYPE(sn)) {
       case FAIL_NULL:
         guard(false, lir->ins_eq0(res_ins), OOM_EXIT);
         break;
       case FAIL_NEG:
         res_ins = lir->ins1(LIR_i2f, res_ins);
         guard(false, lir->ins2(LIR_flt, res_ins, lir->insImmf(0)), OOM_EXIT);
         break;
       case FAIL_VOID:
@@ -9315,60 +9312,60 @@ TraceRecorder::emitNativeCall(JSTraceabl
 
     set(&stackval(0 - (2 + argc)), res_ins);
 
     /*
      * The return value will be processed by NativeCallComplete since
      * we have to know the actual return value type for calls that return
      * jsval (like Array_p_pop).
      */
-    pendingTraceableNative = known;
+    pendingSpecializedNative = sn;
 
     return JSRS_CONTINUE;
 }
 
 /*
  * Check whether we have a specialized implementation for this native
  * invocation.
  */
 JS_REQUIRES_STACK JSRecordingStatus
-TraceRecorder::callTraceableNative(JSFunction* fun, uintN argc, bool constructing)
-{
-    JSTraceableNative* known = FUN_TRCINFO(fun);
-    JS_ASSERT(known && (JSFastNative)fun->u.n.native == known->native);
-
+TraceRecorder::callSpecializedNative(JSNativeTraceInfo *trcinfo, uintN argc,
+                                     bool constructing)
+{
     JSStackFrame* fp = cx->fp;
     jsbytecode *pc = fp->regs->pc;
 
     jsval& fval = stackval(0 - (2 + argc));
     jsval& tval = stackval(0 - (1 + argc));
 
     LIns* this_ins = get(&tval);
 
     LIns* args[nanojit::MAXARGS];
+    JSSpecializedNative *sn = trcinfo->specializations;
+    JS_ASSERT(sn);
     do {
-        if (((known->flags & JSTN_CONSTRUCTOR) != 0) != constructing)
+        if (((sn->flags & JSTN_CONSTRUCTOR) != 0) != constructing)
             continue;
 
-        uintN knownargc = strlen(known->argtypes);
+        uintN knownargc = strlen(sn->argtypes);
         if (argc != knownargc)
             continue;
 
-        intN prefixc = strlen(known->prefix);
+        intN prefixc = strlen(sn->prefix);
         JS_ASSERT(prefixc <= 3);
         LIns** argp = &args[argc + prefixc - 1];
         char argtype;
 
 #if defined DEBUG
         memset(args, 0xCD, sizeof(args));
 #endif
 
         uintN i;
         for (i = prefixc; i--; ) {
-            argtype = known->prefix[i];
+            argtype = sn->prefix[i];
             if (argtype == 'C') {
                 *argp = cx_ins;
             } else if (argtype == 'T') { /* this, as an object */
                 if (JSVAL_IS_PRIMITIVE(tval))
                     goto next_specialization;
                 *argp = this_ins;
             } else if (argtype == 'S') { /* this, as a string */
                 if (!JSVAL_IS_STRING(tval))
@@ -9396,17 +9393,17 @@ TraceRecorder::callTraceableNative(JSFun
             }
             argp--;
         }
 
         for (i = knownargc; i--; ) {
             jsval& arg = stackval(0 - (i + 1));
             *argp = get(&arg);
 
-            argtype = known->argtypes[i];
+            argtype = sn->argtypes[i];
             if (argtype == 'd' || argtype == 'i') {
                 if (!isNumber(arg))
                     goto next_specialization;
                 if (argtype == 'i')
                     *argp = f2i(*argp);
             } else if (argtype == 'o') {
                 if (JSVAL_IS_PRIMITIVE(arg))
                     goto next_specialization;
@@ -9424,20 +9421,20 @@ TraceRecorder::callTraceableNative(JSFun
             } else {
                 goto next_specialization;
             }
             argp--;
         }
 #if defined DEBUG
         JS_ASSERT(args[0] != (LIns *)0xcdcdcdcd);
 #endif
-        return emitNativeCall(known, argc, args);
+        return emitNativeCall(sn, argc, args);
 
 next_specialization:;
-    } while ((known++)->flags & JSTN_MORE);
+    } while ((sn++)->flags & JSTN_MORE);
 
     return JSRS_STOP;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::callNative(uintN argc, JSOp mode)
 {
     LIns* args[5];
@@ -9451,17 +9448,17 @@ TraceRecorder::callNative(uintN argc, JS
 
     switch (argc) {
       case 1:
         if (isNumber(vp[2]) &&
             (native == js_math_ceil || native == js_math_floor || native == js_math_round)) {
             LIns* a = get(&vp[2]);
             if (isPromote(a)) {
                 set(&vp[0], a);
-                pendingTraceableNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
+                pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
                 return JSRS_CONTINUE;
             }
         }
         break;
 
       case 2:
         if (isNumber(vp[2]) && isNumber(vp[3]) &&
             (native == js_math_min || native == js_math_max)) {
@@ -9471,27 +9468,33 @@ TraceRecorder::callNative(uintN argc, JS
                 a = ::demote(lir, a);
                 b = ::demote(lir, b);
                 set(&vp[0],
                     lir->ins1(LIR_i2f,
                               lir->ins_choose(lir->ins2((native == js_math_min)
                                                         ? LIR_lt
                                                         : LIR_gt, a, b),
                                               a, b)));
-                pendingTraceableNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
+                pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
                 return JSRS_CONTINUE;
             }
         }
         break;
     }
 
-    if (fun->flags & JSFUN_TRACEABLE) {
-        JSRecordingStatus status;
-        if ((status = callTraceableNative(fun, argc, mode == JSOP_NEW)) != JSRS_STOP)
-            return status;
+    if (fun->flags & JSFUN_TRCINFO) {
+        JSNativeTraceInfo *trcinfo = FUN_TRCINFO(fun);
+        JS_ASSERT(trcinfo && (JSFastNative)fun->u.n.native == trcinfo->native);
+
+        /* Try to call a type specialized version of the native. */
+        if (trcinfo->specializations) {
+            JSRecordingStatus status = callSpecializedNative(trcinfo, argc, mode == JSOP_NEW);
+            if (status != JSRS_STOP)
+                return status;
+        }
     }
 
     if (native == js_fun_apply || native == js_fun_call)
         ABORT_TRACE("trying to call native apply or call");
 
     // Allocate the vp vector and emit code to root it.
     uintN vplen = 2 + JS_MAX(argc, FUN_MINARGS(fun)) + fun->u.n.extra;
     if (!(fun->flags & JSFUN_FAST_NATIVE))
@@ -9605,42 +9608,41 @@ TraceRecorder::callNative(uintN argc, JS
         types = ARGSIZE_I << (0*ARGSIZE_SHIFT) |
                 ARGSIZE_P << (1*ARGSIZE_SHIFT) |
                 ARGSIZE_P << (2*ARGSIZE_SHIFT) |
                 ARGSIZE_I << (3*ARGSIZE_SHIFT) |
                 ARGSIZE_P << (4*ARGSIZE_SHIFT) |
                 ARGSIZE_P << (5*ARGSIZE_SHIFT);
     }
 
-    // Generate CallInfo and a JSTraceableNative structure on the fly.  Do not
-    // use JSTN_UNBOX_AFTER for mode JSOP_NEW because record_NativeCallComplete
-    // unboxes the result specially.
+    // Generate CallInfo and a JSSpecializedNative structure on the fly.
+    // Do not use JSTN_UNBOX_AFTER for mode JSOP_NEW because
+    // record_NativeCallComplete unboxes the result specially.
 
     CallInfo* ci = (CallInfo*) lir->insSkip(sizeof(struct CallInfo))->payload();
     ci->_address = uintptr_t(fun->u.n.native);
     ci->_cse = ci->_fold = 0;
     ci->_abi = ABI_CDECL;
     ci->_argtypes = types;
 #ifdef DEBUG
     ci->_name = JS_GetFunctionName(fun);
  #endif
 
-    // Generate a JSTraceableNative structure on the fly.
-    generatedTraceableNative->builtin = ci;
-    generatedTraceableNative->native = (JSFastNative)fun->u.n.native;
-    generatedTraceableNative->flags = FAIL_STATUS | ((mode == JSOP_NEW)
-                                                     ? JSTN_CONSTRUCTOR
-                                                     : JSTN_UNBOX_AFTER);
-
-    generatedTraceableNative->prefix = generatedTraceableNative->argtypes = NULL;
+    // Generate a JSSpecializedNative structure on the fly.
+    generatedSpecializedNative.builtin = ci;
+    generatedSpecializedNative.flags = FAIL_STATUS | ((mode == JSOP_NEW)
+                                                        ? JSTN_CONSTRUCTOR
+                                                        : JSTN_UNBOX_AFTER);
+    generatedSpecializedNative.prefix = NULL;
+    generatedSpecializedNative.argtypes = NULL;
 
     // argc is the original argc here. It is used to calculate where to place
     // the return value.
     JSRecordingStatus status;
-    if ((status = emitNativeCall(generatedTraceableNative, argc, args)) != JSRS_CONTINUE)
+    if ((status = emitNativeCall(&generatedSpecializedNative, argc, args)) != JSRS_CONTINUE)
         return status;
 
     // Unroot the vp.
     lir->insStorei(INS_NULL(), cx_ins, offsetof(JSContext, nativeVp));
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
@@ -9692,17 +9694,17 @@ TraceRecorder::functionCall(uintN argc, 
         if (native == js_String && argc == 1) {
             if (mode == JSOP_NEW)
                 return newString(JSVAL_TO_OBJECT(fval), 1, argv, &fval);
             if (!JSVAL_IS_PRIMITIVE(argv[0])) {
                 ABORT_IF_XML(argv[0]);
                 return call_imacro(call_imacros.String);
             }
             set(&fval, stringify(argv[0]));
-            pendingTraceableNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
+            pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
             return JSRS_CONTINUE;
         }
     }
 
     return callNative(argc, mode);
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
@@ -11037,22 +11039,22 @@ CatchStopIteration_tn(JSContext* cx, JSB
 }
 
 JS_DEFINE_TRCINFO_1(CatchStopIteration_tn,
     (3, (static, BOOL, CatchStopIteration_tn, CONTEXT, BOOL, JSVALPTR, 0, 0)))
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_NativeCallComplete()
 {
-    if (pendingTraceableNative == IGNORE_NATIVE_CALL_COMPLETE_CALLBACK)
+    if (pendingSpecializedNative == IGNORE_NATIVE_CALL_COMPLETE_CALLBACK)
         return JSRS_CONTINUE;
 
     jsbytecode* pc = cx->fp->regs->pc;
 
-    JS_ASSERT(pendingTraceableNative);
+    JS_ASSERT(pendingSpecializedNative);
     JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_APPLY || *pc == JSOP_NEW || *pc == JSOP_SETPROP);
 
     jsval& v = stackval(-1);
     LIns* v_ins = get(&v);
 
     /*
      * At this point the generated code has already called the native function
      * and we can no longer fail back to the original pc location (JSOP_CALL)
@@ -11062,22 +11064,22 @@ TraceRecorder::record_NativeCallComplete
      * Instead, the snapshot() call below sees that we are currently parked on
      * a traceable native's JSOP_CALL instruction, and it will advance the pc
      * to restore by the length of the current opcode.  If the native's return
      * type is jsval, snapshot() will also indicate in the type map that the
      * element on top of the stack is a boxed value which doesn't need to be
      * boxed if the type guard generated by unbox_jsval() fails.
      */
 
-    if (JSTN_ERRTYPE(pendingTraceableNative) == FAIL_STATUS) {
+    if (JSTN_ERRTYPE(pendingSpecializedNative) == FAIL_STATUS) {
         /* Keep cx->bailExit null when it's invalid. */
         lir->insStorei(INS_NULL(), cx_ins, (int) offsetof(JSContext, bailExit));
 
         LIns* status = lir->insLoad(LIR_ld, lirbuf->state, (int) offsetof(InterpState, builtinStatus));
-        if (pendingTraceableNative == generatedTraceableNative) {
+        if (pendingSpecializedNative == &generatedSpecializedNative) {
             LIns* ok_ins = v_ins;
 
             /*
              * Custom implementations of Iterator.next() throw a StopIteration exception.
              * Catch and clear it and set the return value to JSVAL_HOLE in this case.
              */
             if (uintptr_t(pc - nextiter_imacros.custom_iter_next) <
                 sizeof(nextiter_imacros.custom_iter_next)) {
@@ -11099,37 +11101,37 @@ TraceRecorder::record_NativeCallComplete
             set(&v, v_ins);
 
             propagateFailureToBuiltinStatus(ok_ins, status);
         }
         guard(true, lir->ins_eq0(status), STATUS_EXIT);
     }
 
     JSRecordingStatus ok = JSRS_CONTINUE;
-    if (pendingTraceableNative->flags & JSTN_UNBOX_AFTER) {
+    if (pendingSpecializedNative->flags & JSTN_UNBOX_AFTER) {
         /*
          * If we side exit on the unboxing code due to a type change, make sure that the boxed
          * value is actually currently associated with that location, and that we are talking
          * about the top of the stack here, which is where we expected boxed values.
          */
         JS_ASSERT(&v == &cx->fp->regs->sp[-1] && get(&v) == v_ins);
         set(&v, unbox_jsval(v, v_ins, snapshot(BRANCH_EXIT)));
-    } else if (JSTN_ERRTYPE(pendingTraceableNative) == FAIL_NEG) {
+    } else if (JSTN_ERRTYPE(pendingSpecializedNative) == FAIL_NEG) {
         /* Already added i2f in functionCall. */
         JS_ASSERT(JSVAL_IS_NUMBER(v));
     } else {
         /* Convert the result to double if the builtin returns int32. */
         if (JSVAL_IS_NUMBER(v) &&
-            (pendingTraceableNative->builtin->_argtypes & ARGSIZE_MASK_ANY) == ARGSIZE_I) {
+            (pendingSpecializedNative->builtin->_argtypes & ARGSIZE_MASK_ANY) == ARGSIZE_I) {
             set(&v, lir->ins1(LIR_i2f, v_ins));
         }
     }
 
-    // We'll null pendingTraceableNative in monitorRecording, on the next op cycle.
-    // There must be a next op since the stack is non-empty.
+    // We'll null pendingSpecializedNative in monitorRecording, on the next op
+    // cycle.  There must be a next op since the stack is non-empty.
     return ok;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr)
 {
     JSObject* obj = cx->fp->scopeChain;
     if (obj != globalObj)
@@ -13039,38 +13041,38 @@ CallIteratorNext_tn(JSContext* cx, jsbyt
 }
 
 JS_DEFINE_TRCINFO_1(ObjectToIterator,
     (4, (static, OBJECT_FAIL, ObjectToIterator_tn, CONTEXT, PC, THIS, INT32, 0, 0)))
 JS_DEFINE_TRCINFO_1(CallIteratorNext,
     (3, (static, JSVAL_FAIL,  CallIteratorNext_tn, CONTEXT, PC, THIS,        0, 0)))
 
 static const struct BuiltinFunctionInfo {
-    JSTraceableNative *tn;
+    JSNativeTraceInfo *ti;
     int nargs;
 } builtinFunctionInfo[JSBUILTIN_LIMIT] = {
-    {ObjectToIterator_trcinfo,   1},
-    {CallIteratorNext_trcinfo,   0},
+    {&ObjectToIterator_trcinfo,   1},
+    {&CallIteratorNext_trcinfo,   0},
 };
 
 JSObject *
 js_GetBuiltinFunction(JSContext *cx, uintN index)
 {
     JSRuntime *rt = cx->runtime;
     JSObject *funobj = rt->builtinFunctions[index];
 
     if (!funobj) {
         /* Use NULL parent and atom. Builtin functions never escape to scripts. */
         JS_ASSERT(index < JS_ARRAY_LENGTH(builtinFunctionInfo));
         const BuiltinFunctionInfo *bfi = &builtinFunctionInfo[index];
         JSFunction *fun = js_NewFunction(cx,
                                          NULL,
-                                         JS_DATA_TO_FUNC_PTR(JSNative, bfi->tn),
+                                         JS_DATA_TO_FUNC_PTR(JSNative, bfi->ti),
                                          bfi->nargs,
-                                         JSFUN_FAST_NATIVE | JSFUN_TRACEABLE,
+                                         JSFUN_FAST_NATIVE | JSFUN_TRCINFO,
                                          NULL,
                                          NULL);
         if (fun) {
             funobj = FUN_OBJECT(fun);
             STOBJ_CLEAR_PROTO(funobj);
             STOBJ_CLEAR_PARENT(funobj);
 
             JS_LOCK_GC(rt);
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -694,18 +694,18 @@ class TraceRecorder : public avmplus::GC
     nanojit::LIns*          inner_sp_ins;
     nanojit::LIns*          native_rval_ins;
     nanojit::LIns*          newobj_ins;
     bool                    deepAborted;
     bool                    trashSelf;
     Queue<nanojit::Fragment*> whichTreesToTrash;
     Queue<jsbytecode*>      cfgMerges;
     jsval*                  global_dslots;
-    JSTraceableNative*      generatedTraceableNative;
-    JSTraceableNative*      pendingTraceableNative;
+    JSSpecializedNative     generatedSpecializedNative;
+    JSSpecializedNative*    pendingSpecializedNative;
     jsval*                  pendingUnboxSlot;
     nanojit::LIns*          pendingGuardCondition;
     TraceRecorder*          nextRecorderToAbort;
     bool                    wasRootFragment;
     jsbytecode*             outer;     /* outer trace header PC */
     uint32                  outerArgc; /* outer trace deepest frame argc */
     bool                    loop;
     nanojit::LIns*          loopLabel;
@@ -921,25 +921,25 @@ class TraceRecorder : public avmplus::GC
     JS_REQUIRES_STACK JSRecordingStatus newArray(JSObject* ctor, uint32 argc, jsval* argv,
                                                  jsval* rval);
     JS_REQUIRES_STACK JSRecordingStatus newString(JSObject* ctor, uint32 argc, jsval* argv,
                                                   jsval* rval);
     JS_REQUIRES_STACK JSRecordingStatus interpretedFunctionCall(jsval& fval, JSFunction* fun,
                                                                 uintN argc, bool constructing);
     JS_REQUIRES_STACK void propagateFailureToBuiltinStatus(nanojit::LIns *ok_ins,
                                                            nanojit::LIns *&status_ins);
-    JS_REQUIRES_STACK JSRecordingStatus emitNativeCall(JSTraceableNative* known, uintN argc,
+    JS_REQUIRES_STACK JSRecordingStatus emitNativeCall(JSSpecializedNative* sn, uintN argc,
                                                        nanojit::LIns* args[]);
     JS_REQUIRES_STACK void emitNativePropertyOp(JSScope* scope,
                                                 JSScopeProperty* sprop,
                                                 nanojit::LIns* obj_ins,
                                                 bool setflag,
                                                 nanojit::LIns* boxed_ins);
-    JS_REQUIRES_STACK JSRecordingStatus callTraceableNative(JSFunction* fun, uintN argc,
-                                                            bool constructing);
+    JS_REQUIRES_STACK JSRecordingStatus callSpecializedNative(JSNativeTraceInfo* trcinfo, uintN argc,
+                                                              bool constructing);
     JS_REQUIRES_STACK JSRecordingStatus callNative(uintN argc, JSOp mode);
     JS_REQUIRES_STACK JSRecordingStatus functionCall(uintN argc, JSOp mode);
 
     JS_REQUIRES_STACK void trackCfgMerges(jsbytecode* pc);
     JS_REQUIRES_STACK void emitIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
     JS_REQUIRES_STACK void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
     JS_REQUIRES_STACK JSRecordingStatus checkTraceEnd(jsbytecode* pc);
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1731,17 +1731,17 @@ DisassembleValue(JSContext *cx, jsval v,
             SHOW_FLAG(SETTER);
             SHOW_FLAG(GETTER);
             SHOW_FLAG(BOUND_METHOD);
             SHOW_FLAG(HEAVYWEIGHT);
             SHOW_FLAG(THISP_STRING);
             SHOW_FLAG(THISP_NUMBER);
             SHOW_FLAG(THISP_BOOLEAN);
             SHOW_FLAG(EXPR_CLOSURE);
-            SHOW_FLAG(TRACEABLE);
+            SHOW_FLAG(TRCINFO);
 
 #undef SHOW_FLAG
 
             if (FUN_NULL_CLOSURE(fun))
                 fputs(" NULL_CLOSURE", stdout);
             else if (FUN_FLAT_CLOSURE(fun))
                 fputs(" FLAT_CLOSURE", stdout);
             putchar('\n');