From f068ba4b226588ce7b8e1448dfef0f38979c1394 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Sun, 21 Sep 2008 08:59:52 -0400 Subject: [PATCH] Adding missing file --- js/src/builtins.tbl | 6 ++++++ js/src/jitstats.tbl | 13 +++++++++++ js/src/jsbuiltins.cpp | 48 +++++++++++++++++++++++++++++++++++++++++ js/src/jsdate.cpp | 50 +++++++++---------------------------------- js/src/jsdate.h | 12 +++++++++++ js/src/jstracer.cpp | 20 +++++++++++++++++ js/src/trace-test.js | 31 +++++++++++++++++++++------ 7 files changed, 134 insertions(+), 46 deletions(-) create mode 100644 js/src/jitstats.tbl diff --git a/js/src/builtins.tbl b/js/src/builtins.tbl index 2fcbb425aa8..de419a64aca 100644 --- a/js/src/builtins.tbl +++ b/js/src/builtins.tbl @@ -142,6 +142,12 @@ BUILTIN5(Array_3num, LO, LO, F, F, F, P, JSObject*, JSContext*, JSObj 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) diff --git a/js/src/jitstats.tbl b/js/src/jitstats.tbl new file mode 100644 index 00000000000..6121494946a --- /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) diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp index 3da6157cea8..c6fe35ddcec 100644 --- a/js/src/jsbuiltins.cpp +++ b/js/src/jsbuiltins.cpp @@ -51,6 +51,8 @@ #include "jslibmath.h" #include "jsmath.h" #include "jsnum.h" +#include "prmjtime.h" +#include "jsdate.h" #include "jsscope.h" #include "jsstr.h" #include "jstracer.h" @@ -872,6 +874,52 @@ 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 diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index b2a1e025446..8ceaacdd72a 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -478,9 +478,6 @@ msFromTime(jsdouble t) * 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 = { @@ -912,18 +909,10 @@ date_parse(JSContext *cx, uintN argc, jsval *vp) 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); } /* @@ -1966,7 +1955,7 @@ date_valueOf(JSContext *cx, uintN argc, jsval *vp) 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 }; @@ -2035,8 +2024,8 @@ date_constructor(JSContext *cx, JSObject* obj) 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; @@ -2044,35 +2033,16 @@ Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) /* 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 */ @@ -2126,7 +2096,7 @@ js_InitDateClass(JSContext *cx, JSObject *obj) /* 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; diff --git a/js/src/jsdate.h b/js/src/jsdate.h index 6c5b3aa333c..b556a6f7cb5 100644 --- a/js/src/jsdate.h +++ b/js/src/jsdate.h @@ -51,6 +51,18 @@ 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 */ diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 976884ee5ab..521e0aa8a28 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -67,6 +67,7 @@ #include "jsregexp.h" #include "jsscope.h" #include "jsscript.h" +#include "jsdate.h" #include "jstracer.h" #include "jsautooplen.h" // generated headers last @@ -3329,12 +3330,26 @@ TraceRecorder::binary(LOpcode op) 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) { @@ -4116,6 +4131,9 @@ 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() { @@ -4158,6 +4176,7 @@ TraceRecorder::record_JSOP_NEW() { (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++) { @@ -4835,6 +4854,7 @@ TraceRecorder::record_JSOP_CALL() { 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; diff --git a/js/src/trace-test.js b/js/src/trace-test.js index a795714ea18..2214a43dcc9 100644 --- a/js/src/trace-test.js +++ b/js/src/trace-test.js @@ -1486,7 +1486,8 @@ 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++) { @@ -1504,7 +1505,8 @@ function testNestedExitStackInner(j, counter) { } return counter + b; } -function testNestedExitStackOuter() { +function testNestedExitStackOuter() +{ var counter = 0; for (var j = 1; j <= RUNLOOP; ++j) { for (var k = 1; k <= RUNLOOP; ++k) { @@ -1514,17 +1516,34 @@ function testNestedExitStackOuter() { 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() {