Adding missing file
☠☠ backed out by 48197599e290 ☠ ☠
authorBoris Zbarsky <bzbarsky@mit.edu>
Sun, 21 Sep 2008 08:59:52 -0400
changeset 19594 c0364f5e0a847c99acc943f347d5200dc5724228
parent 19593 c2a3ef237ca2123a896b2662fb50b5b1b15afc25
child 19595 48197599e290429a3fa6c6583190da86a054c987
push idunknown
push userunknown
push dateunknown
milestone1.9.1b1pre
Adding missing file
js/src/builtins.tbl
js/src/jitstats.tbl
js/src/jsbuiltins.cpp
js/src/jsdate.cpp
js/src/jsdate.h
js/src/jstracer.cpp
js/src/trace-test.js
--- a/js/src/builtins.tbl
+++ b/js/src/builtins.tbl
@@ -137,16 +137,22 @@ BUILTIN2(BooleanToNumber,       LO, LO, 
 BUILTIN2(ObjectToString,        LO,     LO, P,  JSString*, JSContext*, JSObject*, 0, 0)
 BUILTIN3(Array_1int,            LO, LO, LO, P,  JSObject*, JSContext*, JSObject*, jsint, 0, 0)
 BUILTIN3(Array_1str,            LO, LO, LO, P,  JSObject*, JSContext*, JSObject*, JSString*, 0, 0)
 BUILTIN4(Array_2obj,            LO, LO, LO, LO, P, JSObject*, JSContext*, JSObject*, JSObject*, JSObject**, 0, 0)
 BUILTIN5(Array_3num,            LO, LO, F, F, F, P, JSObject*, JSContext*, JSObject*, jsdouble, jsdouble, jsdouble, 0, 0)
 BUILTIN1(Arguments,             LO,     P,      JSObject*, JSContext*, 0, 0)
 BUILTIN2(imod,                  LO, LO, LO,     jsint,     jsint,      jsint, 1, 1)
 
+// Don't really need an argument here, but we don't support arg-less builtins
+BUILTIN1(Date_now,              LO,     F,      jsdouble, JSContext*, 0, 0)
+BUILTIN2(FastNewDate,           LO, LO, P,      JSObject*, JSContext*, JSObject*, 0, 0)
+// Conversion to number depends on the internal state of the date
+BUILTIN2(DateToNumber,          LO,     LO, F,  jsdouble,  JSContext*, JSObject*, 0, 0)
+
 // soft float
 BUILTIN1(fneg,   F,       F,  jsdouble, jsdouble, 1, 1)
 BUILTIN1(i2f,    LO,      F,  jsdouble, jsint,    1, 1)
 BUILTIN1(u2f,    LO,      F,  jsdouble, jsuint,   1, 1)
 BUILTIN2(fcmpeq, F,   F,  LO, jsint,    jsdouble, jsdouble, 1, 1)
 BUILTIN2(fcmplt, F,   F,  LO, jsint,    jsdouble, jsdouble, 1, 1)
 BUILTIN2(fcmple, F,   F,  LO, jsint,    jsdouble, jsdouble, 1, 1)
 BUILTIN2(fcmpgt, F,   F,  LO, jsint,    jsdouble, jsdouble, 1, 1)
new file mode 100644
--- /dev/null
+++ b/js/src/jitstats.tbl
@@ -0,0 +1,13 @@
+JITSTAT(recorderStarted)
+JITSTAT(recorderAborted)
+JITSTAT(traceCompleted)
+JITSTAT(sideExitIntoInterpreter)
+JITSTAT(typeMapMismatchAtEntry)
+JITSTAT(returnToDifferentLoopHeader)
+JITSTAT(traceTriggered)
+JITSTAT(globalShapeMismatchAtEntry)
+JITSTAT(treesTrashed)
+JITSTAT(slotPromoted)
+JITSTAT(unstableLoopVariable)
+JITSTAT(breakLoopExits)
+JITSTAT(returnLoopExits)
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -46,16 +46,18 @@
 #include "jsarray.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsgc.h"
 #include "jsiter.h"
 #include "jslibmath.h"
 #include "jsmath.h"
 #include "jsnum.h"
+#include "prmjtime.h"
+#include "jsdate.h"
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jstracer.h"
 
 #include "nanojit/avmplus.h"
 #include "nanojit/nanojit.h"
 
 using namespace avmplus;
@@ -867,16 +869,62 @@ js_Array_3num(JSContext* cx, JSObject* p
 }
 
 JSObject* FASTCALL
 js_Arguments(JSContext* cx)
 {
     return NULL;
 }
 
+jsdouble FASTCALL
+js_Date_now(JSContext*)
+{
+    return PRMJ_Now() / PRMJ_USEC_PER_MSEC;
+}
+
+JS_STATIC_ASSERT(JSSLOT_PRIVATE == JSSLOT_UTC_TIME);
+JS_STATIC_ASSERT(JSSLOT_UTC_TIME + 1 == JSSLOT_LOCAL_TIME);
+
+JSObject* FASTCALL
+js_FastNewDate(JSContext* cx, JSObject* proto)
+{
+    JS_ASSERT(JS_ON_TRACE(cx));
+    JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
+    if (!obj)
+        return NULL;
+
+    JSClass* clasp = &js_DateClass;
+    obj->classword = jsuword(clasp);
+
+    obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
+    obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
+
+    jsdouble* date = js_NewWeaklyRootedDouble(cx, 0.0);
+    if (!date)
+        return NULL;
+    *date = js_Date_now(cx);
+    obj->fslots[JSSLOT_UTC_TIME] = DOUBLE_TO_JSVAL(date);
+    obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);;
+
+    JS_ASSERT(!clasp->getObjectOps);
+    JSObjectOps* ops = &js_ObjectOps;
+    // XXXbz is this the right thing to be doing?
+    obj->map = ops->newObjectMap(cx, 1, ops, clasp, obj);
+    if (!obj->map)
+        return NULL;
+    obj->dslots = NULL;
+    return obj;    
+}
+
+jsdouble FASTCALL
+js_DateToNumber(JSContext* cx, JSObject* date)
+{
+    return *JSVAL_TO_DOUBLE(date->fslots[JSSLOT_UTC_TIME]);
+}
+
 /* soft float */
 
 jsdouble FASTCALL
 js_fneg(jsdouble x)
 {
     return -x;
 }
 
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -473,19 +473,16 @@ msFromTime(jsdouble t)
 /*
  * Other Support routines and definitions
  */
 
 /*
  * We use the first reseved slot to store UTC time, and the second for caching
  * the local time. The initial value of the cache entry is NaN.
  */
-const uint32 JSSLOT_UTC_TIME    = JSSLOT_PRIVATE;
-const uint32 JSSLOT_LOCAL_TIME  = JSSLOT_PRIVATE + 1;
-
 const uint32 DATE_RESERVED_SLOTS = 2;
 
 JSClass js_DateClass = {
     js_Date_str,
     JSCLASS_HAS_RESERVED_SLOTS(DATE_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub,
@@ -907,28 +904,20 @@ date_parse(JSContext *cx, uintN argc, js
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
 
     result = TIMECLIP(result);
     return js_NewNumberInRootedValue(cx, result, vp);
 }
 
-static JSBool
-date_now(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_date_now(JSContext *cx, uintN argc, jsval *vp)
 {
-    int64 us, ms, us2ms;
-    jsdouble msec_time;
-
-    us = PRMJ_Now();
-    JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
-    JSLL_DIV(ms, us, us2ms);
-    JSLL_L2D(msec_time, ms);
-
-    return js_NewDoubleInRootedValue(cx, msec_time, vp);
+    return js_NewDoubleInRootedValue(cx, PRMJ_Now() / PRMJ_USEC_PER_MSEC, vp);
 }
 
 /*
  * Get UTC time from the date object. Returns false if the object is not
  * Date type.
  */
 static JSBool
 GetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp)
@@ -1961,17 +1950,17 @@ date_valueOf(JSContext *cx, uintN argc, 
 
 /*
  * creation and destruction
  */
 
 static JSFunctionSpec date_static_methods[] = {
     JS_FN("UTC",                 date_UTC,                MAXARGS,0),
     JS_FN("parse",               date_parse,              1,0),
-    JS_FN("now",                 date_now,                0,0),
+    JS_FN("now",                 js_date_now,                0,0),
     JS_FS_END
 };
 
 static JSFunctionSpec date_methods[] = {
     JS_FN("getTime",             date_getTime,            0,0),
     JS_FN("getTimezoneOffset",   date_getTimezoneOffset,  0,0),
     JS_FN("getYear",             date_getYear,            0,0),
     JS_FN("getFullYear",         date_getFullYear,        0,0),
@@ -2030,54 +2019,35 @@ date_constructor(JSContext *cx, JSObject
     if (!date)
         return NULL;
 
     obj->fslots[JSSLOT_UTC_TIME] = DOUBLE_TO_JSVAL(date);
     obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
     return date;
 }
 
-static JSBool
-Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+JSBool
+js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     jsdouble *date;
     JSString *str;
     jsdouble d;
 
     /* Date called as function. */
     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
-        int64 us, ms, us2ms;
-        jsdouble msec_time;
-
-        /* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS',
-         * so compute ms from PRMJ_Now.
-         */
-        us = PRMJ_Now();
-        JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
-        JSLL_DIV(ms, us, us2ms);
-        JSLL_L2D(msec_time, ms);
-
-        return date_format(cx, msec_time, FORMATSPEC_FULL, rval);
+        return date_format(cx, PRMJ_Now() / PRMJ_USEC_PER_MSEC,
+                           FORMATSPEC_FULL, rval);
     }
 
     /* Date called as constructor. */
     if (argc == 0) {
-        int64 us, ms, us2ms;
-        jsdouble msec_time;
-
         date = date_constructor(cx, obj);
         if (!date)
             return JS_FALSE;
-
-        us = PRMJ_Now();
-        JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
-        JSLL_DIV(ms, us, us2ms);
-        JSLL_L2D(msec_time, ms);
-
-        *date = msec_time;
+        *date = PRMJ_Now() / PRMJ_USEC_PER_MSEC;
     } else if (argc == 1) {
         if (!JSVAL_IS_STRING(argv[0])) {
             /* the argument is a millisecond number */
             d = js_ValueToNumber(cx, &argv[0]);
             if (JSVAL_IS_NULL(argv[0]))
                 return JS_FALSE;
             date = date_constructor(cx, obj);
             if (!date)
@@ -2121,17 +2091,17 @@ Date(JSContext *cx, JSObject *obj, uintN
 JSObject *
 js_InitDateClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto;
     jsdouble *proto_date;
 
     /* set static LocalTZA */
     LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
-    proto = JS_InitClass(cx, obj, NULL, &js_DateClass, Date, MAXARGS,
+    proto = JS_InitClass(cx, obj, NULL, &js_DateClass, js_Date, MAXARGS,
                          NULL, date_methods, NULL, date_static_methods);
     if (!proto)
         return NULL;
 
     /* Alias toUTCString with toGMTString.  (ECMA B.2.6) */
     if (!JS_AliasProperty(cx, proto, "toUTCString", "toGMTString"))
         return NULL;
 
--- a/js/src/jsdate.h
+++ b/js/src/jsdate.h
@@ -46,16 +46,28 @@
 
 JS_BEGIN_EXTERN_C
 
 extern JSClass js_DateClass;
 
 extern JSObject *
 js_InitDateClass(JSContext *cx, JSObject *obj);
 
+extern JSBool
+js_date_now(JSContext *cx, uintN argc, jsval *vp);
+
+extern JSClass js_DateClass;
+
+/*
+ * We use the first reseved slot to store UTC time, and the second for caching
+ * the local time. The initial value of the cache entry is NaN.
+ */
+#define JSSLOT_UTC_TIME    JSSLOT_PRIVATE
+#define JSSLOT_LOCAL_TIME  (JSSLOT_PRIVATE + 1)
+
 /*
  * These functions provide a C interface to the date/time object
  */
 
 /*
  * Construct a new Date Object from a time value given in milliseconds UTC
  * since the epoch.
  */
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -62,16 +62,17 @@
 #include "jsfun.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsregexp.h"
 #include "jsscope.h"
 #include "jsscript.h"
+#include "jsdate.h"
 #include "jstracer.h"
 
 #include "jsautooplen.h"        // generated headers last
 
 /* Number of iterations of a loop where we start tracing.  That is, we don't
    start tracing until the beginning of the HOTLOOP-th iteration. */
 #define HOTLOOP 2
 
@@ -3324,22 +3325,36 @@ TraceRecorder::binary(LOpcode op)
         (op >= LIR_fsub && op <= LIR_fdiv)) { // fsub, fmul, fdiv
         LIns* args[2];
         if (JSVAL_IS_STRING(l)) {
             args[0] = a;
             args[1] = cx_ins;
             a = lir->insCall(F_StringToNumber, args);
             leftNumber = true;
         }
+        if (JSVAL_IS_OBJECT(l) &&
+            guardClass(JSVAL_TO_OBJECT(l), a, &js_DateClass)) {
+            args[0] = a;
+            args[1] = cx_ins;
+            a = lir->insCall(F_DateToNumber, args);
+            leftNumber = true;
+        }
         if (JSVAL_IS_STRING(r)) {
             args[0] = b;
             args[1] = cx_ins;
             b = lir->insCall(F_StringToNumber, args);
             rightNumber = true;
         }
+        if (JSVAL_IS_OBJECT(r) &&
+            guardClass(JSVAL_TO_OBJECT(r), b, &js_DateClass)) {
+            args[0] = b;
+            args[1] = cx_ins;
+            b = lir->insCall(F_DateToNumber, args);
+            rightNumber = true;
+        }
     }
     if (leftNumber && rightNumber) {
         if (intop) {
             LIns *args[] = { a };
             a = lir->insCall(op == LIR_ush ? F_DoubleToUint32 : F_DoubleToInt32, args);
             b = f2i(b);
         }
         a = lir->ins2(op, a, b);
@@ -4111,16 +4126,19 @@ TraceRecorder::record_JSOP_NEG()
 }
 
 JSBool
 js_Array(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
 
 JSBool
 js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
 
+JSBool
+js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+
 bool
 TraceRecorder::record_JSOP_NEW()
 {
     /* Get immediate argc and find the constructor function. */
     jsbytecode *pc = cx->fp->regs->pc;
     unsigned argc = GET_ARGC(pc);
     jsval& fval = stackval(0 - (2 + argc));
     JS_ASSERT(&fval >= StackBase(cx->fp));
@@ -4153,16 +4171,17 @@ TraceRecorder::record_JSOP_NEW()
     }
 
     static JSTraceableNative knownNatives[] = {
         { (JSFastNative)js_Array,  F_FastNewArray,  "pC", "",    FAIL_NULL },
         { (JSFastNative)js_Array,  F_Array_1int,    "pC", "i",   FAIL_NULL },
         { (JSFastNative)js_Array,  F_Array_2obj,    "pC", "oo",  FAIL_NULL },
         { (JSFastNative)js_Array,  F_Array_3num,    "pC", "ddd", FAIL_NULL },
         { (JSFastNative)js_Object, F_FastNewObject, "fC", "",    FAIL_NULL },
+        { (JSFastNative)js_Date,   F_FastNewDate,   "pC", "",    FAIL_NULL },
     };
 
     for (uintN i = 0; i < JS_ARRAY_LENGTH(knownNatives); i++) {
         JSTraceableNative* known = &knownNatives[i];
         if ((JSFastNative)fun->u.n.native != known->native)
             continue;
 
         uintN knownargc = strlen(known->argtypes);
@@ -4830,16 +4849,17 @@ TraceRecorder::record_JSOP_CALL()
         { js_str_replace,              F_String_p_replace_str, "TC",  "sr",   FAIL_NULL },
         { js_str_replace,              F_String_p_replace_str2,"TC",  "ss",   FAIL_NULL },
         { js_str_replace,              F_String_p_replace_str3,"TC",  "sss",  FAIL_NULL },
         { js_str_split,                F_String_p_split,       "TC",  "s",    FAIL_NULL },
         { js_str_substring,            F_String_p_substring,   "TC",  "ii",   FAIL_NULL },
         { js_str_substring,            F_String_p_substring_1, "TC",  "i",    FAIL_NULL },
         { js_str_toLowerCase,          F_toLowerCase,          "TC",   "",    FAIL_NULL },
         { js_str_toUpperCase,          F_toUpperCase,          "TC",   "",    FAIL_NULL },
+        { js_date_now,                 F_Date_now,             "C",    "",    INFALLIBLE },
     };
 
     uintN i = 0;
     LIns* arg1_ins = NULL;
     jsval arg1 = JSVAL_VOID;
 
     JSFastNative native = (JSFastNative)fun->u.n.native;
     if (native == js_fun_apply) {
--- a/js/src/trace-test.js
+++ b/js/src/trace-test.js
@@ -1481,17 +1481,18 @@ function testArrayPushPop() {
     a.push(sum1);
     a.push(sum2);
     return a.join(",");
 }
 testArrayPushPop.expected = "55,45";
 test(testArrayPushPop);
 
 // Test stack reconstruction after a nested exit
-function testNestedExitStackInner(j, counter) {
+function testNestedExitStackInner(j, counter)
+{
   ++counter;
   var b = 0;
   for (var i = 1; i <= RUNLOOP; i++) {
     ++b;
     var a;
     // Make sure that once everything has been traced we suddenly switch to
     // a different control flow the first time we run the outermost tree,
     // triggering a side exit.
@@ -1499,37 +1500,55 @@ function testNestedExitStackInner(j, cou
       a = 1;
     else
       a = 0;
     ++b;
     b += a;
   }
   return counter + b;
 }
-function testNestedExitStackOuter() {
+function testNestedExitStackOuter()
+{
   var counter = 0;
   for (var j = 1; j <= RUNLOOP; ++j) {
     for (var k = 1; k <= RUNLOOP; ++k) {
       counter = testNestedExitStackInner(j, counter);
     }
   }
   return counter;
 }
 testNestedExitStackOuter.expected = 81;
-testNestedExitStackOuter.jitstats = {};
-testNestedExitStackOuter.jitstats.recorderStarted = 4;
-testNestedExitStackOuter.jitstats.recorderAborted = 0;
+testNestedExitStackOuter.jitstats = {
+    recorderStarted: 4,
+    recorderAborted: 0
+};
 test(testNestedExitStackOuter);
 
-function testHOTLOOPSize() {
+function testHOTLOOPSize()
+{
     return HOTLOOP > 1;
 }
 testHOTLOOPSize.expected = true;
 test(testHOTLOOPSize);
 
+function testDateNow()
+{
+    var time = 0;
+    for (var j = 1; j <= RUNLOOP; ++j) {
+	time = Date.now();
+    }
+    return "ok";
+}
+testDateNow.expected = "ok";
+testDateNow.jitstats = {
+    recorderStarted: 1,
+    recorderAborted: 0
+};
+test(testDateNow);
+
 // This test has to come last, since it messes with Object.prototype
 // and thus confuses jitstats.
 function testGlobalProtoAccess() {
     return "ok";
 }
 this.__proto__.a = 3; for (var j = 0; j < 4; ++j) { [a]; }
 testGlobalProtoAccess.expected = "ok";
 test(testGlobalProtoAccess);