diff options
author | Andreu Botella <andreu@andreubotella.com> | 2022-02-15 12:17:30 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-15 12:17:30 +0100 |
commit | 760f4c9e2427e87815a8e59b0807693c8dcb623a (patch) | |
tree | cb04b2b42cfcf1fc46d74a3e4c7f86c73491d2b0 /ext/timers | |
parent | 5e845442fade02cd12d13e74222b26e217c5971d (diff) |
chore(ext/timers): move ext/timers to ext/web (#13665)
Diffstat (limited to 'ext/timers')
-rw-r--r-- | ext/timers/01_timers.js | 394 | ||||
-rw-r--r-- | ext/timers/02_performance.js | 569 | ||||
-rw-r--r-- | ext/timers/Cargo.toml | 28 | ||||
-rw-r--r-- | ext/timers/README.md | 5 | ||||
-rw-r--r-- | ext/timers/benches/timers_ops.rs | 54 | ||||
-rw-r--r-- | ext/timers/lib.rs | 127 |
6 files changed, 0 insertions, 1177 deletions
diff --git a/ext/timers/01_timers.js b/ext/timers/01_timers.js deleted file mode 100644 index a0b1deb45..000000000 --- a/ext/timers/01_timers.js +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -"use strict"; - -((window) => { - const core = window.Deno.core; - const { - ArrayPrototypePush, - ArrayPrototypeShift, - Error, - FunctionPrototypeCall, - Map, - MapPrototypeDelete, - MapPrototypeGet, - MapPrototypeHas, - MapPrototypeSet, - // deno-lint-ignore camelcase - NumberPOSITIVE_INFINITY, - PromisePrototypeThen, - ObjectPrototypeIsPrototypeOf, - SafeArrayIterator, - SymbolFor, - TypeError, - } = window.__bootstrap.primordials; - const { webidl } = window.__bootstrap; - - // Shamelessly cribbed from extensions/fetch/11_streams.js - class AssertionError extends Error { - constructor(msg) { - super(msg); - this.name = "AssertionError"; - } - } - - /** - * @param {unknown} cond - * @param {string=} msg - * @returns {asserts cond} - */ - function assert(cond, msg = "Assertion failed.") { - if (!cond) { - throw new AssertionError(msg); - } - } - - function opNow() { - return core.opSync("op_now"); - } - - function sleepSync(millis = 0) { - return core.opSync("op_sleep_sync", millis); - } - - // --------------------------------------------------------------------------- - - /** - * The task queue corresponding to the timer task source. - * - * @type { {action: () => void, nestingLevel: number}[] } - */ - const timerTasks = []; - - /** - * The current task's timer nesting level, or zero if we're not currently - * running a timer task (since the minimum nesting level is 1). - * - * @type {number} - */ - let timerNestingLevel = 0; - - function handleTimerMacrotask() { - if (timerTasks.length === 0) { - return true; - } - - const task = ArrayPrototypeShift(timerTasks); - - timerNestingLevel = task.nestingLevel; - - try { - task.action(); - } finally { - timerNestingLevel = 0; - } - return timerTasks.length === 0; - } - - // --------------------------------------------------------------------------- - - /** - * The keys in this map correspond to the key ID's in the spec's map of active - * timers. The values are the timeout's cancel rid. - * - * @type {Map<number, { cancelRid: number, isRef: boolean, promiseId: number }>} - */ - const activeTimers = new Map(); - - let nextId = 1; - - /** - * @param {Function | string} callback - * @param {number} timeout - * @param {Array<any>} args - * @param {boolean} repeat - * @param {number | undefined} prevId - * @returns {number} The timer ID - */ - function initializeTimer( - callback, - timeout, - args, - repeat, - prevId, - ) { - // 2. If previousId was given, let id be previousId; otherwise, let - // previousId be an implementation-defined integer than is greater than zero - // and does not already exist in global's map of active timers. - let id; - let timerInfo; - if (prevId !== undefined) { - // `prevId` is only passed for follow-up calls on intervals - assert(repeat); - id = prevId; - timerInfo = MapPrototypeGet(activeTimers, id); - } else { - // TODO(@andreubotella): Deal with overflow. - // https://github.com/whatwg/html/issues/7358 - id = nextId++; - const cancelRid = core.opSync("op_timer_handle"); - timerInfo = { cancelRid, isRef: true, promiseId: -1 }; - - // Step 4 in "run steps after a timeout". - MapPrototypeSet(activeTimers, id, timerInfo); - } - - // 3. If the surrounding agent's event loop's currently running task is a - // task that was created by this algorithm, then let nesting level be the - // task's timer nesting level. Otherwise, let nesting level be zero. - // 4. If timeout is less than 0, then set timeout to 0. - // 5. If nesting level is greater than 5, and timeout is less than 4, then - // set timeout to 4. - // - // The nesting level of 5 and minimum of 4 ms are spec-mandated magic - // constants. - if (timeout < 0) timeout = 0; - if (timerNestingLevel > 5 && timeout < 4) timeout = 4; - - // 9. Let task be a task that runs the following steps: - const task = { - action: () => { - // 1. If id does not exist in global's map of active timers, then abort - // these steps. - // - // This is relevant if the timer has been canceled after the sleep op - // resolves but before this task runs. - if (!MapPrototypeHas(activeTimers, id)) { - return; - } - - // 2. - // 3. - // TODO(@andreubotella): Error handling. - if (typeof callback === "function") { - FunctionPrototypeCall( - callback, - globalThis, - ...new SafeArrayIterator(args), - ); - } else { - // TODO(@andreubotella): eval doesn't seem to have a primordial, but - // it can be redefined in the global scope. - (0, eval)(callback); - } - - if (repeat) { - if (MapPrototypeHas(activeTimers, id)) { - // 4. If id does not exist in global's map of active timers, then - // abort these steps. - // NOTE: If might have been removed via the author code in handler - // calling clearTimeout() or clearInterval(). - // 5. If repeat is true, then perform the timer initialization steps - // again, given global, handler, timeout, arguments, true, and id. - initializeTimer(callback, timeout, args, true, id); - } - } else { - // 6. Otherwise, remove global's map of active timers[id]. - core.tryClose(timerInfo.cancelRid); - MapPrototypeDelete(activeTimers, id); - } - }, - - // 10. Increment nesting level by one. - // 11. Set task's timer nesting level to nesting level. - nestingLevel: timerNestingLevel + 1, - }; - - // 12. Let completionStep be an algorithm step which queues a global task on - // the timer task source given global to run task. - // 13. Run steps after a timeout given global, "setTimeout/setInterval", - // timeout, completionStep, and id. - runAfterTimeout( - () => ArrayPrototypePush(timerTasks, task), - timeout, - timerInfo, - ); - - return id; - } - - // --------------------------------------------------------------------------- - - /** - * @typedef ScheduledTimer - * @property {number} millis - * @property {() => void} cb - * @property {boolean} resolved - * @property {ScheduledTimer | null} prev - * @property {ScheduledTimer | null} next - */ - - /** - * A doubly linked list of timers. - * @type { { head: ScheduledTimer | null, tail: ScheduledTimer | null } } - */ - const scheduledTimers = { head: null, tail: null }; - - /** - * @param {() => void} cb Will be run after the timeout, if it hasn't been - * cancelled. - * @param {number} millis - * @param {{ cancelRid: number, isRef: boolean, promiseId: number }} timerInfo - */ - function runAfterTimeout(cb, millis, timerInfo) { - const cancelRid = timerInfo.cancelRid; - const sleepPromise = core.opAsync("op_sleep", millis, cancelRid); - timerInfo.promiseId = - sleepPromise[SymbolFor("Deno.core.internalPromiseId")]; - if (!timerInfo.isRef) { - core.unrefOp(timerInfo.promiseId); - } - - /** @type {ScheduledTimer} */ - const timerObject = { - millis, - cb, - resolved: false, - prev: scheduledTimers.tail, - next: null, - }; - - // Add timerObject to the end of the list. - if (scheduledTimers.tail === null) { - assert(scheduledTimers.head === null); - scheduledTimers.head = scheduledTimers.tail = timerObject; - } else { - scheduledTimers.tail.next = timerObject; - scheduledTimers.tail = timerObject; - } - - // 1. - PromisePrototypeThen( - sleepPromise, - () => { - // 2. Wait until any invocations of this algorithm that had the same - // global and orderingIdentifier, that started before this one, and - // whose milliseconds is equal to or less than this one's, have - // completed. - // 4. Perform completionSteps. - - // IMPORTANT: Since the sleep ops aren't guaranteed to resolve in the - // right order, whenever one resolves, we run through the scheduled - // timers list (which is in the order in which they were scheduled), and - // we call the callback for every timer which both: - // a) has resolved, and - // b) its timeout is lower than the lowest unresolved timeout found so - // far in the list. - - timerObject.resolved = true; - - let lowestUnresolvedTimeout = NumberPOSITIVE_INFINITY; - - let currentEntry = scheduledTimers.head; - while (currentEntry !== null) { - if (currentEntry.millis < lowestUnresolvedTimeout) { - if (currentEntry.resolved) { - currentEntry.cb(); - removeFromScheduledTimers(currentEntry); - } else { - lowestUnresolvedTimeout = currentEntry.millis; - } - } - - currentEntry = currentEntry.next; - } - }, - (err) => { - if (ObjectPrototypeIsPrototypeOf(core.InterruptedPrototype, err)) { - // The timer was cancelled. - removeFromScheduledTimers(timerObject); - } else { - throw err; - } - }, - ); - } - - /** @param {ScheduledTimer} timerObj */ - function removeFromScheduledTimers(timerObj) { - if (timerObj.prev !== null) { - timerObj.prev.next = timerObj.next; - } else { - assert(scheduledTimers.head === timerObj); - scheduledTimers.head = timerObj.next; - } - if (timerObj.next !== null) { - timerObj.next.prev = timerObj.prev; - } else { - assert(scheduledTimers.tail === timerObj); - scheduledTimers.tail = timerObj.prev; - } - } - - // --------------------------------------------------------------------------- - - function checkThis(thisArg) { - if (thisArg !== null && thisArg !== undefined && thisArg !== globalThis) { - throw new TypeError("Illegal invocation"); - } - } - - function setTimeout(callback, timeout = 0, ...args) { - checkThis(this); - if (typeof callback !== "function") { - callback = webidl.converters.DOMString(callback); - } - timeout = webidl.converters.long(timeout); - - return initializeTimer(callback, timeout, args, false); - } - - function setInterval(callback, timeout = 0, ...args) { - checkThis(this); - if (typeof callback !== "function") { - callback = webidl.converters.DOMString(callback); - } - timeout = webidl.converters.long(timeout); - - return initializeTimer(callback, timeout, args, true); - } - - function clearTimeout(id = 0) { - checkThis(this); - id = webidl.converters.long(id); - const timerInfo = MapPrototypeGet(activeTimers, id); - if (timerInfo !== undefined) { - core.tryClose(timerInfo.cancelRid); - MapPrototypeDelete(activeTimers, id); - } - } - - function clearInterval(id = 0) { - checkThis(this); - clearTimeout(id); - } - - function refTimer(id) { - const timerInfo = MapPrototypeGet(activeTimers, id); - if (timerInfo === undefined || timerInfo.isRef) { - return; - } - timerInfo.isRef = true; - core.refOp(timerInfo.promiseId); - } - - function unrefTimer(id) { - const timerInfo = MapPrototypeGet(activeTimers, id); - if (timerInfo === undefined || !timerInfo.isRef) { - return; - } - timerInfo.isRef = false; - core.unrefOp(timerInfo.promiseId); - } - - window.__bootstrap.timers = { - setTimeout, - setInterval, - clearTimeout, - clearInterval, - handleTimerMacrotask, - opNow, - sleepSync, - refTimer, - unrefTimer, - }; -})(this); diff --git a/ext/timers/02_performance.js b/ext/timers/02_performance.js deleted file mode 100644 index c48a3d888..000000000 --- a/ext/timers/02_performance.js +++ /dev/null @@ -1,569 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -"use strict"; - -((window) => { - const { - ArrayPrototypeFilter, - ArrayPrototypeFind, - ArrayPrototypePush, - ArrayPrototypeReverse, - ArrayPrototypeSlice, - ObjectKeys, - ObjectPrototypeIsPrototypeOf, - Symbol, - SymbolFor, - TypeError, - } = window.__bootstrap.primordials; - - const { webidl, structuredClone } = window.__bootstrap; - const consoleInternal = window.__bootstrap.console; - const { opNow } = window.__bootstrap.timers; - const { DOMException } = window.__bootstrap.domException; - - const illegalConstructorKey = Symbol("illegalConstructorKey"); - const customInspect = SymbolFor("Deno.customInspect"); - let performanceEntries = []; - - webidl.converters["PerformanceMarkOptions"] = webidl - .createDictionaryConverter( - "PerformanceMarkOptions", - [ - { - key: "detail", - converter: webidl.converters.any, - }, - { - key: "startTime", - converter: webidl.converters.DOMHighResTimeStamp, - }, - ], - ); - - webidl.converters["DOMString or DOMHighResTimeStamp"] = (V, opts) => { - if (webidl.type(V) === "Number" && V !== null) { - return webidl.converters.DOMHighResTimeStamp(V, opts); - } - return webidl.converters.DOMString(V, opts); - }; - - webidl.converters["PerformanceMeasureOptions"] = webidl - .createDictionaryConverter( - "PerformanceMeasureOptions", - [ - { - key: "detail", - converter: webidl.converters.any, - }, - { - key: "start", - converter: webidl.converters["DOMString or DOMHighResTimeStamp"], - }, - { - key: "duration", - converter: webidl.converters.DOMHighResTimeStamp, - }, - { - key: "end", - converter: webidl.converters["DOMString or DOMHighResTimeStamp"], - }, - ], - ); - - webidl.converters["DOMString or PerformanceMeasureOptions"] = (V, opts) => { - if (webidl.type(V) === "Object" && V !== null) { - return webidl.converters["PerformanceMeasureOptions"](V, opts); - } - return webidl.converters.DOMString(V, opts); - }; - - function findMostRecent( - name, - type, - ) { - return ArrayPrototypeFind( - ArrayPrototypeReverse(ArrayPrototypeSlice(performanceEntries)), - (entry) => entry.name === name && entry.entryType === type, - ); - } - - function convertMarkToTimestamp(mark) { - if (typeof mark === "string") { - const entry = findMostRecent(mark, "mark"); - if (!entry) { - throw new DOMException( - `Cannot find mark: "${mark}".`, - "SyntaxError", - ); - } - return entry.startTime; - } - if (mark < 0) { - throw new TypeError("Mark cannot be negative."); - } - return mark; - } - - function filterByNameType( - name, - type, - ) { - return ArrayPrototypeFilter( - performanceEntries, - (entry) => - (name ? entry.name === name : true) && - (type ? entry.entryType === type : true), - ); - } - - const now = opNow; - - const _name = Symbol("[[name]]"); - const _entryType = Symbol("[[entryType]]"); - const _startTime = Symbol("[[startTime]]"); - const _duration = Symbol("[[duration]]"); - class PerformanceEntry { - [_name] = ""; - [_entryType] = ""; - [_startTime] = 0; - [_duration] = 0; - - get name() { - webidl.assertBranded(this, PerformanceEntryPrototype); - return this[_name]; - } - - get entryType() { - webidl.assertBranded(this, PerformanceEntryPrototype); - return this[_entryType]; - } - - get startTime() { - webidl.assertBranded(this, PerformanceEntryPrototype); - return this[_startTime]; - } - - get duration() { - webidl.assertBranded(this, PerformanceEntryPrototype); - return this[_duration]; - } - - constructor( - name = null, - entryType = null, - startTime = null, - duration = null, - key = undefined, - ) { - if (key !== illegalConstructorKey) { - webidl.illegalConstructor(); - } - this[webidl.brand] = webidl.brand; - - this[_name] = name; - this[_entryType] = entryType; - this[_startTime] = startTime; - this[_duration] = duration; - } - - toJSON() { - webidl.assertBranded(this, PerformanceEntryPrototype); - return { - name: this[_name], - entryType: this[_entryType], - startTime: this[_startTime], - duration: this[_duration], - }; - } - - [customInspect](inspect) { - return inspect(consoleInternal.createFilteredInspectProxy({ - object: this, - evaluate: ObjectPrototypeIsPrototypeOf( - PerformanceEntryPrototype, - this, - ), - keys: [ - "name", - "entryType", - "startTime", - "duration", - ], - })); - } - } - webidl.configurePrototype(PerformanceEntry); - const PerformanceEntryPrototype = PerformanceEntry.prototype; - - const _detail = Symbol("[[detail]]"); - class PerformanceMark extends PerformanceEntry { - [_detail] = null; - - get detail() { - webidl.assertBranded(this, PerformanceMarkPrototype); - return this[_detail]; - } - - get entryType() { - webidl.assertBranded(this, PerformanceMarkPrototype); - return "mark"; - } - - constructor( - name, - options = {}, - ) { - const prefix = "Failed to construct 'PerformanceMark'"; - webidl.requiredArguments(arguments.length, 1, { prefix }); - - name = webidl.converters.DOMString(name, { - prefix, - context: "Argument 1", - }); - - options = webidl.converters.PerformanceMarkOptions(options, { - prefix, - context: "Argument 2", - }); - - const { detail = null, startTime = now() } = options; - - super(name, "mark", startTime, 0, illegalConstructorKey); - this[webidl.brand] = webidl.brand; - if (startTime < 0) { - throw new TypeError("startTime cannot be negative"); - } - this[_detail] = structuredClone(detail); - } - - toJSON() { - webidl.assertBranded(this, PerformanceMarkPrototype); - return { - name: this.name, - entryType: this.entryType, - startTime: this.startTime, - duration: this.duration, - detail: this.detail, - }; - } - - [customInspect](inspect) { - return inspect(consoleInternal.createFilteredInspectProxy({ - object: this, - evaluate: ObjectPrototypeIsPrototypeOf(PerformanceMarkPrototype, this), - keys: [ - "name", - "entryType", - "startTime", - "duration", - "detail", - ], - })); - } - } - webidl.configurePrototype(PerformanceMark); - const PerformanceMarkPrototype = PerformanceMark.prototype; - class PerformanceMeasure extends PerformanceEntry { - [_detail] = null; - - get detail() { - webidl.assertBranded(this, PerformanceMeasurePrototype); - return this[_detail]; - } - - get entryType() { - webidl.assertBranded(this, PerformanceMeasurePrototype); - return "measure"; - } - - constructor( - name = null, - startTime = null, - duration = null, - detail = null, - key = undefined, - ) { - if (key !== illegalConstructorKey) { - webidl.illegalConstructor(); - } - - super(name, "measure", startTime, duration, key); - this[webidl.brand] = webidl.brand; - this[_detail] = structuredClone(detail); - } - - toJSON() { - webidl.assertBranded(this, PerformanceMeasurePrototype); - return { - name: this.name, - entryType: this.entryType, - startTime: this.startTime, - duration: this.duration, - detail: this.detail, - }; - } - - [customInspect](inspect) { - return inspect(consoleInternal.createFilteredInspectProxy({ - object: this, - evaluate: ObjectPrototypeIsPrototypeOf( - PerformanceMeasurePrototype, - this, - ), - keys: [ - "name", - "entryType", - "startTime", - "duration", - "detail", - ], - })); - } - } - webidl.configurePrototype(PerformanceMeasure); - const PerformanceMeasurePrototype = PerformanceMeasure.prototype; - class Performance { - constructor() { - webidl.illegalConstructor(); - } - - clearMarks(markName = undefined) { - webidl.assertBranded(this, PerformancePrototype); - if (markName !== undefined) { - markName = webidl.converters.DOMString(markName, { - prefix: "Failed to execute 'clearMarks' on 'Performance'", - context: "Argument 1", - }); - - performanceEntries = ArrayPrototypeFilter( - performanceEntries, - (entry) => !(entry.name === markName && entry.entryType === "mark"), - ); - } else { - performanceEntries = ArrayPrototypeFilter( - performanceEntries, - (entry) => entry.entryType !== "mark", - ); - } - } - - clearMeasures(measureName = undefined) { - webidl.assertBranded(this, PerformancePrototype); - if (measureName !== undefined) { - measureName = webidl.converters.DOMString(measureName, { - prefix: "Failed to execute 'clearMeasures' on 'Performance'", - context: "Argument 1", - }); - - performanceEntries = ArrayPrototypeFilter( - performanceEntries, - (entry) => - !(entry.name === measureName && entry.entryType === "measure"), - ); - } else { - performanceEntries = ArrayPrototypeFilter( - performanceEntries, - (entry) => entry.entryType !== "measure", - ); - } - } - - getEntries() { - webidl.assertBranded(this, PerformancePrototype); - return filterByNameType(); - } - - getEntriesByName( - name, - type = undefined, - ) { - webidl.assertBranded(this, PerformancePrototype); - const prefix = "Failed to execute 'getEntriesByName' on 'Performance'"; - webidl.requiredArguments(arguments.length, 1, { prefix }); - - name = webidl.converters.DOMString(name, { - prefix, - context: "Argument 1", - }); - - if (type !== undefined) { - type = webidl.converters.DOMString(type, { - prefix, - context: "Argument 2", - }); - } - - return filterByNameType(name, type); - } - - getEntriesByType(type) { - webidl.assertBranded(this, PerformancePrototype); - const prefix = "Failed to execute 'getEntriesByName' on 'Performance'"; - webidl.requiredArguments(arguments.length, 1, { prefix }); - - type = webidl.converters.DOMString(type, { - prefix, - context: "Argument 1", - }); - - return filterByNameType(undefined, type); - } - - mark( - markName, - markOptions = {}, - ) { - webidl.assertBranded(this, PerformancePrototype); - const prefix = "Failed to execute 'mark' on 'Performance'"; - webidl.requiredArguments(arguments.length, 1, { prefix }); - - markName = webidl.converters.DOMString(markName, { - prefix, - context: "Argument 1", - }); - - markOptions = webidl.converters.PerformanceMarkOptions(markOptions, { - prefix, - context: "Argument 2", - }); - - // 3.1.1.1 If the global object is a Window object and markName uses the - // same name as a read only attribute in the PerformanceTiming interface, - // throw a SyntaxError. - not implemented - const entry = new PerformanceMark(markName, markOptions); - // 3.1.1.7 Queue entry - not implemented - ArrayPrototypePush(performanceEntries, entry); - return entry; - } - - measure( - measureName, - startOrMeasureOptions = {}, - endMark = undefined, - ) { - webidl.assertBranded(this, PerformancePrototype); - const prefix = "Failed to execute 'measure' on 'Performance'"; - webidl.requiredArguments(arguments.length, 1, { prefix }); - - measureName = webidl.converters.DOMString(measureName, { - prefix, - context: "Argument 1", - }); - - startOrMeasureOptions = webidl.converters - ["DOMString or PerformanceMeasureOptions"](startOrMeasureOptions, { - prefix, - context: "Argument 2", - }); - - if (endMark !== undefined) { - endMark = webidl.converters.DOMString(endMark, { - prefix, - context: "Argument 3", - }); - } - - if ( - startOrMeasureOptions && typeof startOrMeasureOptions === "object" && - ObjectKeys(startOrMeasureOptions).length > 0 - ) { - if (endMark) { - throw new TypeError("Options cannot be passed with endMark."); - } - if ( - !("start" in startOrMeasureOptions) && - !("end" in startOrMeasureOptions) - ) { - throw new TypeError( - "A start or end mark must be supplied in options.", - ); - } - if ( - "start" in startOrMeasureOptions && - "duration" in startOrMeasureOptions && - "end" in startOrMeasureOptions - ) { - throw new TypeError( - "Cannot specify start, end, and duration together in options.", - ); - } - } - let endTime; - if (endMark) { - endTime = convertMarkToTimestamp(endMark); - } else if ( - typeof startOrMeasureOptions === "object" && - "end" in startOrMeasureOptions - ) { - endTime = convertMarkToTimestamp(startOrMeasureOptions.end); - } else if ( - typeof startOrMeasureOptions === "object" && - "start" in startOrMeasureOptions && - "duration" in startOrMeasureOptions - ) { - const start = convertMarkToTimestamp(startOrMeasureOptions.start); - const duration = convertMarkToTimestamp(startOrMeasureOptions.duration); - endTime = start + duration; - } else { - endTime = now(); - } - let startTime; - if ( - typeof startOrMeasureOptions === "object" && - "start" in startOrMeasureOptions - ) { - startTime = convertMarkToTimestamp(startOrMeasureOptions.start); - } else if ( - typeof startOrMeasureOptions === "object" && - "end" in startOrMeasureOptions && - "duration" in startOrMeasureOptions - ) { - const end = convertMarkToTimestamp(startOrMeasureOptions.end); - const duration = convertMarkToTimestamp(startOrMeasureOptions.duration); - startTime = end - duration; - } else if (typeof startOrMeasureOptions === "string") { - startTime = convertMarkToTimestamp(startOrMeasureOptions); - } else { - startTime = 0; - } - const entry = new PerformanceMeasure( - measureName, - startTime, - endTime - startTime, - typeof startOrMeasureOptions === "object" - ? startOrMeasureOptions.detail ?? null - : null, - illegalConstructorKey, - ); - ArrayPrototypePush(performanceEntries, entry); - return entry; - } - - now() { - webidl.assertBranded(this, PerformancePrototype); - return now(); - } - - toJSON() { - webidl.assertBranded(this, PerformancePrototype); - return {}; - } - - [customInspect](inspect) { - return inspect(consoleInternal.createFilteredInspectProxy({ - object: this, - evaluate: ObjectPrototypeIsPrototypeOf(PerformancePrototype, this), - keys: [], - })); - } - } - webidl.configurePrototype(Performance); - const PerformancePrototype = Performance.prototype; - - window.__bootstrap.performance = { - PerformanceEntry, - PerformanceMark, - PerformanceMeasure, - Performance, - performance: webidl.createBranded(Performance), - }; -})(this); diff --git a/ext/timers/Cargo.toml b/ext/timers/Cargo.toml deleted file mode 100644 index 15979388e..000000000 --- a/ext/timers/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -[package] -name = "deno_timers" -version = "0.34.0" -authors = ["the Deno authors"] -edition = "2021" -license = "MIT" -readme = "README.md" -repository = "https://github.com/denoland/deno" -description = "Timers API implementation for Deno" - -[lib] -path = "lib.rs" - -[dependencies] -deno_core = { version = "0.118.0", path = "../../core" } -tokio = { version = "1.10.1", features = ["full"] } - -[dev-dependencies] -deno_bench_util = { version = "0.30.0", path = "../../bench_util" } -deno_url = { version = "0.36.0", path = "../url" } -deno_web = { version = "0.67.0", path = "../web" } -deno_webidl = { version = "0.36.0", path = "../webidl" } - -[[bench]] -name = "timers_ops" -harness = false diff --git a/ext/timers/README.md b/ext/timers/README.md deleted file mode 100644 index 5a2a8e516..000000000 --- a/ext/timers/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# deno_timers - -This crate implements the timers API. - -Spec: https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers diff --git a/ext/timers/benches/timers_ops.rs b/ext/timers/benches/timers_ops.rs deleted file mode 100644 index 8d13d5807..000000000 --- a/ext/timers/benches/timers_ops.rs +++ /dev/null @@ -1,54 +0,0 @@ -use deno_core::Extension; - -use deno_bench_util::bench_or_profile; -use deno_bench_util::bencher::{benchmark_group, Bencher}; -use deno_bench_util::{bench_js_async, bench_js_sync}; -use deno_web::BlobStore; - -struct Permissions; - -impl deno_timers::TimersPermission for Permissions { - fn allow_hrtime(&mut self) -> bool { - true - } - fn check_unstable( - &self, - _state: &deno_core::OpState, - _api_name: &'static str, - ) { - } -} - -fn setup() -> Vec<Extension> { - vec![ - deno_webidl::init(), - deno_url::init(), - deno_web::init(BlobStore::default(), None), - deno_timers::init::<Permissions>(), - Extension::builder() - .js(vec![ - ("setup", - Box::new(|| Ok(r#" - const { opNow, setTimeout, handleTimerMacrotask } = globalThis.__bootstrap.timers; - Deno.core.setMacrotaskCallback(handleTimerMacrotask); - "#.to_owned())), - ), - ]) - .state(|state| { - state.put(Permissions{}); - Ok(()) - }) - .build() - ] -} - -fn bench_op_now(b: &mut Bencher) { - bench_js_sync(b, r#"opNow();"#, setup); -} - -fn bench_set_timeout(b: &mut Bencher) { - bench_js_async(b, r#"setTimeout(() => {}, 0);"#, setup); -} - -benchmark_group!(benches, bench_op_now, bench_set_timeout,); -bench_or_profile!(benches); diff --git a/ext/timers/lib.rs b/ext/timers/lib.rs deleted file mode 100644 index 63aabe9d4..000000000 --- a/ext/timers/lib.rs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -//! This module helps deno implement timers and performance APIs. - -use deno_core::error::AnyError; -use deno_core::include_js_files; -use deno_core::op_async; -use deno_core::op_sync; -use deno_core::CancelFuture; -use deno_core::CancelHandle; -use deno_core::Extension; -use deno_core::OpState; -use deno_core::Resource; -use deno_core::ResourceId; -use std::borrow::Cow; -use std::cell::RefCell; -use std::rc::Rc; -use std::time::Duration; -use std::time::Instant; - -pub trait TimersPermission { - fn allow_hrtime(&mut self) -> bool; - fn check_unstable(&self, state: &OpState, api_name: &'static str); -} - -pub fn init<P: TimersPermission + 'static>() -> Extension { - Extension::builder() - .js(include_js_files!( - prefix "deno:ext/timers", - "01_timers.js", - "02_performance.js", - )) - .ops(vec![ - ("op_now", op_sync(op_now::<P>)), - ("op_timer_handle", op_sync(op_timer_handle)), - ("op_sleep", op_async(op_sleep)), - ("op_sleep_sync", op_sync(op_sleep_sync::<P>)), - ]) - .state(|state| { - state.put(StartTime::now()); - Ok(()) - }) - .build() -} - -pub type StartTime = Instant; - -// Returns a milliseconds and nanoseconds subsec -// since the start time of the deno runtime. -// If the High precision flag is not set, the -// nanoseconds are rounded on 2ms. -pub fn op_now<TP>( - state: &mut OpState, - _argument: (), - _: (), -) -> Result<f64, AnyError> -where - TP: TimersPermission + 'static, -{ - let start_time = state.borrow::<StartTime>(); - let seconds = start_time.elapsed().as_secs(); - let mut subsec_nanos = start_time.elapsed().subsec_nanos() as f64; - let reduced_time_precision = 2_000_000.0; // 2ms in nanoseconds - - // If the permission is not enabled - // Round the nano result on 2 milliseconds - // see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision - if !state.borrow_mut::<TP>().allow_hrtime() { - subsec_nanos -= subsec_nanos % reduced_time_precision; - } - - let result = (seconds * 1_000) as f64 + (subsec_nanos / 1_000_000.0); - - Ok(result) -} - -pub struct TimerHandle(Rc<CancelHandle>); - -impl Resource for TimerHandle { - fn name(&self) -> Cow<str> { - "timer".into() - } - - fn close(self: Rc<Self>) { - self.0.cancel(); - } -} - -/// Creates a [`TimerHandle`] resource that can be used to cancel invocations of -/// [`op_sleep`]. -pub fn op_timer_handle( - state: &mut OpState, - _: (), - _: (), -) -> Result<ResourceId, AnyError> { - let rid = state - .resource_table - .add(TimerHandle(CancelHandle::new_rc())); - Ok(rid) -} - -/// Waits asynchronously until either `millis` milliseconds have passed or the -/// [`TimerHandle`] resource given by `rid` has been canceled. -pub async fn op_sleep( - state: Rc<RefCell<OpState>>, - millis: u64, - rid: ResourceId, -) -> Result<(), AnyError> { - let handle = state.borrow().resource_table.get::<TimerHandle>(rid)?; - tokio::time::sleep(Duration::from_millis(millis)) - .or_cancel(handle.0.clone()) - .await?; - Ok(()) -} - -pub fn op_sleep_sync<TP>( - state: &mut OpState, - millis: u64, - _: (), -) -> Result<(), AnyError> -where - TP: TimersPermission + 'static, -{ - state.borrow::<TP>().check_unstable(state, "Deno.sleepSync"); - std::thread::sleep(Duration::from_millis(millis)); - Ok(()) -} |