diff options
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 6 | ||||
-rw-r--r-- | src/bun.js/javascript.zig | 13 | ||||
-rw-r--r-- | test/bun.js/performance.test.js | 6 |
3 files changed, 25 insertions, 0 deletions
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index e69163043..c91a232e6 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -1606,6 +1606,7 @@ JSC_DEFINE_HOST_FUNCTION(functionConcatTypedArrays, (JSGlobalObject * globalObje } extern "C" uint64_t Bun__readOriginTimer(void*); +extern "C" double Bun__readOriginTimerStart(void*); static inline EncodedJSValue functionPerformanceNowBody(JSGlobalObject* globalObject) { @@ -1669,6 +1670,11 @@ private: &DOMJITSignatureForPerformanceNow); this->putDirect(vm, JSC::Identifier::fromString(vm, "now"_s), function, JSC::PropertyAttribute::DOMJITFunction | JSC::PropertyAttribute::Function); + this->putDirect( + vm, + JSC::Identifier::fromString(vm, "timeOrigin"_s), + jsNumber(Bun__readOriginTimerStart(reinterpret_cast<Zig::GlobalObject*>(this->globalObject())->bunVM())), + JSC::PropertyAttribute::ReadOnly | 0); } }; const ClassInfo JSPerformanceObject::s_info = { "Performance"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSPerformanceObject) }; diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 2e733b188..c163d99ae 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -262,6 +262,12 @@ export fn Bun__readOriginTimer(vm: *JSC.VirtualMachine) u64 { return vm.origin_timer.read(); } +export fn Bun__readOriginTimerStart(vm: *JSC.VirtualMachine) f64 { + // timespce to milliseconds + // use f128 to reduce precision loss when converting to f64 + return @floatCast(f64, (@intToFloat(f128, vm.origin_timestamp) + JSC.VirtualMachine.origin_relative_epoch) / 1_000_000.0); +} + comptime { if (!JSC.is_bindgen) { _ = Bun__getDefaultGlobal; @@ -271,6 +277,7 @@ comptime { _ = Bun__handleRejectedPromise; _ = Bun__readOriginTimer; _ = Bun__onDidAppendPlugin; + _ = Bun__readOriginTimerStart; } } @@ -365,6 +372,7 @@ pub const VirtualMachine = struct { global_api_constructors: [GlobalConstructors.len]JSC.JSValue = undefined, origin_timer: std.time.Timer = undefined, + origin_timestamp: u64 = 0, macro_event_loop: EventLoop = EventLoop{}, regular_event_loop: EventLoop = EventLoop{}, event_loop: *EventLoop = undefined, @@ -527,6 +535,10 @@ pub const VirtualMachine = struct { return this.bun_dev_watcher != null or this.bun_watcher != null; } + /// Instead of storing timestamp as a i128, we store it as a u64. + /// We subtract the timestamp from Jan 1, 2000 (Y2K) + pub const origin_relative_epoch = 975628800000 * std.time.ns_per_ms; + pub fn init( allocator: std.mem.Allocator, _args: Api.TransformOptions, @@ -570,6 +582,7 @@ pub const VirtualMachine = struct { .macros = MacroMap.init(allocator), .macro_entry_points = @TypeOf(VirtualMachine.vm.macro_entry_points).init(allocator), .origin_timer = std.time.Timer.start() catch @panic("Please don't mess with timers."), + .origin_timestamp = @truncate(u64, @intCast(u128, @maximum(std.time.nanoTimestamp(), origin_relative_epoch)) - origin_relative_epoch), .ref_strings = JSC.RefString.Map.init(allocator), .file_blobs = JSC.WebCore.Blob.Store.Map.init(allocator), }; diff --git a/test/bun.js/performance.test.js b/test/bun.js/performance.test.js index 5e8520638..0ff75b945 100644 --- a/test/bun.js/performance.test.js +++ b/test/bun.js/performance.test.js @@ -16,3 +16,9 @@ it("performance.now() should be monotonic", () => { expect(Bun.nanoseconds() > sixth).toBe(true); expect(typeof Bun.nanoseconds() === "number").toBe(true); }); + +it("performance.timeOrigin + performance.now() should be similar to Date.now()", () => { + expect( + Math.abs(performance.timeOrigin + performance.now() - Date.now()) < 1000 + ).toBe(true); +}); |