--- a/js/src/builtins.tbl
+++ b/js/src/builtins.tbl
@@ -134,16 +134,19 @@ BUILTIN3(Object_p_propertyIsEnumerable,
BUILTIN2(BooleanToNumber, LO, LO, F, jsdouble, JSContext*, jsint, 1, 1)
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)
+// Don't really need an argument here, but we don't support arg-less builtins
+BUILTIN1(Date_now, LO, F, jsdouble, JSContext*, 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)
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -46,16 +46,17 @@
#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 "jsscope.h"
#include "jsstr.h"
#include "jstracer.h"
#include "nanojit/avmplus.h"
#include "nanojit/nanojit.h"
using namespace avmplus;
@@ -857,16 +858,22 @@ 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;
+}
+
/* soft float */
jsdouble FASTCALL
js_fneg(jsdouble x)
{
return -x;
}
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -907,18 +907,18 @@ 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)
{
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.
*/
@@ -1953,17 +1953,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),
--- a/js/src/jsdate.h
+++ b/js/src/jsdate.h
@@ -46,16 +46,19 @@
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);
+
/*
* 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
@@ -61,16 +61,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
@@ -5029,16 +5030,17 @@ TraceRecorder::record_JSOP_CALL()
{ js_str_replace, F_String_p_replace_str, "SC", "sr", FAIL_NULL },
{ js_str_replace, F_String_p_replace_str2,"SC", "ss", FAIL_NULL },
{ js_str_replace, F_String_p_replace_str3,"SC", "sss", FAIL_NULL },
{ js_str_split, F_String_p_split, "SC", "s", FAIL_NULL },
{ js_str_substring, F_String_p_substring, "SC", "ii", FAIL_NULL },
{ js_str_substring, F_String_p_substring_1, "SC", "i", FAIL_NULL },
{ js_str_toLowerCase, F_toLowerCase, "SC", "", FAIL_NULL },
{ js_str_toUpperCase, F_toUpperCase, "SC", "", FAIL_NULL },
+ { js_date_now, F_Date_now, "C", "", INFALLIBLE },
};
uintN i = 0;
LIns* arg1_ins = NULL;
jsval arg1 = JSVAL_VOID;
jsval thisval = tval;
if ((JSFastNative)fun->u.n.native == js_fun_apply) {
if (argc != 2)
--- a/js/src/trace-test.js
+++ b/js/src/trace-test.js
@@ -1670,11 +1670,30 @@ testRUNLOOPCorrectness.jitstats = {
recorderStarted: 1,
recorderAborted: 0,
traceTriggered: 1
};
// Change the global shape right before doing the test
this.testRUNLOOPCorrectnessVar = 1;
test(testRUNLOOPCorrectness);
+function testDateNow()
+{
+ // Accessing global.Date for the first time will change the global shape,
+ // so do it before the loop starts; otherwise we have to loop an extra time
+ // to pick things up.
+ var time = Date.now();
+ for (var j = 0; j < RUNLOOP; ++j) {
+ time = Date.now();
+ }
+ return "ok";
+}
+testDateNow.expected = "ok";
+testDateNow.jitstats = {
+ recorderStarted: 1,
+ recorderAborted: 0,
+ traceTriggered: 1
+};
+test(testDateNow);
+
/* Keep these at the end so that we can see the summary after the trace-debug spew. */
print("\npassed:", passes.length && passes.join(","));
print("\nFAILED:", fails.length && fails.join(","));