aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp6
-rw-r--r--src/bun.js/javascript.zig13
-rw-r--r--test/bun.js/performance.test.js6
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);
+});