Skip to content

Commit

Permalink
faster brand check (#3720)
Browse files Browse the repository at this point in the history
* faster brand check

* fixup type
  • Loading branch information
tsctx authored Oct 11, 2024
1 parent b6d53fe commit 60c07b2
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 20 deletions.
26 changes: 26 additions & 0 deletions benchmarks/fetch/webidl-is.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { bench, run, barplot } from 'mitata'
import { Headers, FormData } from '../../index.js'
import { webidl } from '../../lib/web/fetch/webidl.js'

const headers = new Headers()
const fd = new FormData()

barplot(() => {
bench('webidl.is.FormData (ok)', () => {
return webidl.is.FormData(fd)
})

bench('webidl.is.FormData (bad)', () => {
return !webidl.is.FormData(headers)
})

bench('instanceof (ok)', () => {
return fd instanceof FormData
})

bench('instanceof (bad)', () => {
return !(headers instanceof FormData)
})
})

await run()
2 changes: 1 addition & 1 deletion lib/web/fetch/formdata.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,6 @@ function makeEntry (name, value, filename) {
return { name, value }
}

webidl.is.FormData = webidl.util.MakeTypeAssertion(FormData.prototype)
webidl.is.FormData = webidl.util.MakeTypeAssertion(FormData)

module.exports = { FormData, makeEntry, setFormDataState }
2 changes: 1 addition & 1 deletion lib/web/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -986,7 +986,7 @@ Object.defineProperties(Request.prototype, {
}
})

webidl.is.Request = webidl.util.MakeTypeAssertion(Request.prototype)
webidl.is.Request = webidl.util.MakeTypeAssertion(Request)

// https://fetch.spec.whatwg.org/#requestinfo
webidl.converters.RequestInfo = function (V, prefix, argument) {
Expand Down
2 changes: 1 addition & 1 deletion lib/web/fetch/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ webidl.converters.ResponseInit = webidl.dictionaryConverter([
}
])

webidl.is.Response = webidl.util.MakeTypeAssertion(Response.prototype)
webidl.is.Response = webidl.util.MakeTypeAssertion(Response)

module.exports = {
isNetworkError,
Expand Down
25 changes: 13 additions & 12 deletions lib/web/fetch/webidl.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const BIGINT = 6
const NULL = 7
const OBJECT = 8 // function and object

const FunctionPrototypeSymbolHasInstance = Function.call.bind(Function.prototype[Symbol.hasInstance])

/** @type {import('../../../types/webidl').Webidl} */
const webidl = {
converters: {},
Expand Down Expand Up @@ -45,15 +47,15 @@ webidl.errors.invalidArgument = function (context) {

// https://webidl.spec.whatwg.org/#implements
webidl.brandCheck = function (V, I) {
if (!I.prototype.isPrototypeOf(V)) { // eslint-disable-line no-prototype-builtins
if (!FunctionPrototypeSymbolHasInstance(I, V)) {
const err = new TypeError('Illegal invocation')
err.code = 'ERR_INVALID_THIS' // node compat.
throw err
}
}

webidl.brandCheckMultiple = function (List) {
const prototypes = List.map((c) => webidl.util.MakeTypeAssertion(c.prototype))
const prototypes = List.map((c) => webidl.util.MakeTypeAssertion(c))

return (V) => {
if (prototypes.every(typeCheck => !typeCheck(V))) {
Expand Down Expand Up @@ -81,9 +83,8 @@ webidl.illegalConstructor = function () {
})
}

const isPrototypeOf = Object.prototype.isPrototypeOf
webidl.util.MakeTypeAssertion = function (Prototype) {
return (O) => isPrototypeOf.call(Prototype, O)
webidl.util.MakeTypeAssertion = function (I) {
return (O) => FunctionPrototypeSymbolHasInstance(I, O)
}

// https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values
Expand Down Expand Up @@ -462,13 +463,13 @@ webidl.nullableConverter = function (converter) {
}
}

webidl.is.ReadableStream = webidl.util.MakeTypeAssertion(ReadableStream.prototype)
webidl.is.Blob = webidl.util.MakeTypeAssertion(Blob.prototype)
webidl.is.URLSearchParams = webidl.util.MakeTypeAssertion(URLSearchParams.prototype)
webidl.is.File = webidl.util.MakeTypeAssertion((globalThis.File ?? require('node:buffer').File).prototype)
webidl.is.URL = webidl.util.MakeTypeAssertion(URL.prototype)
webidl.is.AbortSignal = webidl.util.MakeTypeAssertion(AbortSignal.prototype)
webidl.is.MessagePort = webidl.util.MakeTypeAssertion(MessagePort.prototype)
webidl.is.ReadableStream = webidl.util.MakeTypeAssertion(ReadableStream)
webidl.is.Blob = webidl.util.MakeTypeAssertion(Blob)
webidl.is.URLSearchParams = webidl.util.MakeTypeAssertion(URLSearchParams)
webidl.is.File = webidl.util.MakeTypeAssertion(globalThis.File ?? require('node:buffer').File)
webidl.is.URL = webidl.util.MakeTypeAssertion(URL)
webidl.is.AbortSignal = webidl.util.MakeTypeAssertion(AbortSignal)
webidl.is.MessagePort = webidl.util.MakeTypeAssertion(MessagePort)

// https://webidl.spec.whatwg.org/#es-DOMString
webidl.converters.DOMString = function (V, prefix, argument, opts) {
Expand Down
2 changes: 1 addition & 1 deletion lib/web/websocket/stream/websocketerror.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,6 @@ Object.defineProperties(WebSocketError.prototype, {
}
})

webidl.is.WebSocketError = webidl.util.MakeTypeAssertion(WebSocketError.prototype)
webidl.is.WebSocketError = webidl.util.MakeTypeAssertion(WebSocketError)

module.exports = { WebSocketError, createUnvalidatedWebSocketError }
4 changes: 1 addition & 3 deletions test/webidl/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ test('webidl.interfaceConverter', (t) => {
class A {}
class B {}

const converter = webidl.interfaceConverter(
webidl.util.MakeTypeAssertion(A.prototype)
)
const converter = webidl.interfaceConverter(webidl.util.MakeTypeAssertion(A))

assert.throws(() => {
converter(new B(), 'converter', 'converter')
Expand Down
2 changes: 1 addition & 1 deletion types/webidl.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ interface WebidlUtil {
*/
Stringify (V: any): string

MakeTypeAssertion <T extends { prototype: T }>(Prototype: T['prototype']): (arg: any) => arg is T
MakeTypeAssertion <I>(I: I): (arg: any) => arg is I
}

interface WebidlConverters {
Expand Down

0 comments on commit 60c07b2

Please sign in to comment.