diff --git a/core/00_primordials.js b/core/00_primordials.js index d48dfde79e..19e16860fd 100644 --- a/core/00_primordials.js +++ b/core/00_primordials.js @@ -248,31 +248,6 @@ copyPrototype(original.prototype, primordials, `${name}Prototype`); }); - // Create copies of abstract intrinsic objects that are not directly exposed - // on the global object. - // Refs: https://tc39.es/ecma262/#sec-%typedarray%-intrinsic-object - [ - { name: "TypedArray", original: Reflect.getPrototypeOf(Uint8Array) }, - { - name: "ArrayIterator", - original: { - prototype: Reflect.getPrototypeOf(Array.prototype[Symbol.iterator]()), - }, - }, - { - name: "StringIterator", - original: { - prototype: Reflect.getPrototypeOf(String.prototype[Symbol.iterator]()), - }, - }, - ].forEach(({ name, original }) => { - primordials[name] = original; - // The static %TypedArray% methods require a valid `this`, but can't be bound, - // as they need a subclass constructor as the receiver: - copyPrototype(original, primordials, name); - copyPrototype(original.prototype, primordials, `${name}Prototype`); - }); - const { ArrayPrototypeForEach, ArrayPrototypeMap, @@ -291,6 +266,43 @@ WeakSet, } = primordials; + // Create copies of abstract intrinsic objects that are not directly exposed + // on the global object. + // Refs: https://tc39.es/ecma262/#sec-%typedarray%-intrinsic-object + [ + { name: "TypedArray", original: Reflect.getPrototypeOf(Uint8Array) }, + { + name: "ArrayIterator", + original: { + prototype: Reflect.getPrototypeOf(Array.prototype[Symbol.iterator]()), + }, + }, + { + name: "SetIterator", + original: { + prototype: Reflect.getPrototypeOf(new Set()[Symbol.iterator]()), + }, + }, + { + name: "MapIterator", + original: { + prototype: Reflect.getPrototypeOf(new Map()[Symbol.iterator]()), + }, + }, + { + name: "StringIterator", + original: { + prototype: Reflect.getPrototypeOf(String.prototype[Symbol.iterator]()), + }, + }, + ].forEach(({ name, original }) => { + primordials[name] = original; + // The static %TypedArray% methods require a valid `this`, but can't be bound, + // as they need a subclass constructor as the receiver: + copyPrototype(original, primordials, name); + copyPrototype(original.prototype, primordials, `${name}Prototype`); + }); + // Because these functions are used by `makeSafe`, which is exposed // on the `primordials` object, it's important to use const references // to the primordials that they use: @@ -316,6 +328,14 @@ primordials.ArrayPrototypeSymbolIterator, primordials.ArrayIteratorPrototypeNext, ); + primordials.SafeSetIterator = createSafeIterator( + primordials.SetPrototypeSymbolIterator, + primordials.SetIteratorPrototypeNext, + ); + primordials.SafeMapIterator = createSafeIterator( + primordials.MapPrototypeSymbolIterator, + primordials.MapIteratorPrototypeNext, + ); primordials.SafeStringIterator = createSafeIterator( primordials.StringPrototypeSymbolIterator, primordials.StringIteratorPrototypeNext, diff --git a/ext/broadcast_channel/01_broadcast_channel.js b/ext/broadcast_channel/01_broadcast_channel.js index 0682a2d5ab..afddf8bedc 100644 --- a/ext/broadcast_channel/01_broadcast_channel.js +++ b/ext/broadcast_channel/01_broadcast_channel.js @@ -16,6 +16,7 @@ ArrayPrototypeIndexOf, ArrayPrototypeSplice, ArrayPrototypePush, + SafeArrayIterator, Symbol, Uint8Array, } = window.__bootstrap.primordials; @@ -43,7 +44,7 @@ } function dispatch(source, name, data) { - for (const channel of channels) { + for (const channel of new SafeArrayIterator(channels)) { if (channel === source) continue; // Don't self-send. if (channel[_name] !== name) continue; if (channel[_closed]) continue; diff --git a/ext/cache/01_cache.js b/ext/cache/01_cache.js index aefd989dd9..5c249f2f8e 100644 --- a/ext/cache/01_cache.js +++ b/ext/cache/01_cache.js @@ -6,6 +6,7 @@ const webidl = window.__bootstrap.webidl; const { Symbol, + SafeArrayIterator, TypeError, ObjectPrototypeIsPrototypeOf, } = window.__bootstrap.primordials; @@ -114,7 +115,7 @@ const varyHeader = getHeader(innerResponse.headerList, "vary"); if (varyHeader) { const fieldValues = varyHeader.split(","); - for (const field of fieldValues) { + for (const field of new SafeArrayIterator(fieldValues)) { if (field.trim() === "*") { throw new TypeError("Vary header must not contain '*'"); } diff --git a/ext/console/02_console.js b/ext/console/02_console.js index 9a9ead5a13..3cfa12d1f4 100644 --- a/ext/console/02_console.js +++ b/ext/console/02_console.js @@ -56,6 +56,7 @@ RegExpPrototypeTest, RegExpPrototypeToString, SafeArrayIterator, + SafeStringIterator, SafeSet, SetPrototype, SetPrototypeEntries, @@ -206,7 +207,7 @@ str = StringPrototypeNormalize(colors.stripColor(str), "NFC"); let width = 0; - for (const ch of str) { + for (const ch of new SafeStringIterator(str)) { width += isFullWidthCodePoint(StringPrototypeCodePointAt(ch, 0)) ? 2 : 1; } @@ -276,7 +277,7 @@ }` + `${tableChars.rightMiddle}\n`; - for (const row of rows) { + for (const row of new SafeArrayIterator(rows)) { result += `${renderRow(row, columnWidths, columnRightAlign)}\n`; } @@ -994,7 +995,7 @@ } const refMap = new Map(); - for (const cause of causes) { + for (const cause of new SafeArrayIterator(causes)) { if (circular !== undefined) { const index = MapPrototypeGet(circular, cause); if (index !== undefined) { @@ -1171,7 +1172,7 @@ inspectOptions.indentLevel++; - for (const key of stringKeys) { + for (const key of new SafeArrayIterator(stringKeys)) { if (inspectOptions.getters) { let propertyValue; let error = null; @@ -1207,7 +1208,7 @@ } } - for (const key of symbolKeys) { + for (const key of new SafeArrayIterator(symbolKeys)) { if ( !inspectOptions.showHidden && !propertyIsEnumerable(value, key) @@ -1639,7 +1640,7 @@ currentPart = ""; } - for (const [key, value] of rawEntries) { + for (const [key, value] of new SafeArrayIterator(rawEntries)) { if (key == "background-color") { if (value != null) { css.backgroundColor = value; @@ -1660,7 +1661,11 @@ } } else if (key == "text-decoration-line") { css.textDecorationLine = []; - for (const lineType of StringPrototypeSplit(value, /\s+/g)) { + for ( + const lineType of new SafeArrayIterator( + StringPrototypeSplit(value, /\s+/g), + ) + ) { if ( ArrayPrototypeIncludes( ["line-through", "overline", "underline"], @@ -1678,7 +1683,11 @@ } else if (key == "text-decoration") { css.textDecorationColor = null; css.textDecorationLine = []; - for (const arg of StringPrototypeSplit(value, /\s+/g)) { + for ( + const arg of new SafeArrayIterator( + StringPrototypeSplit(value, /\s+/g), + ) + ) { const maybeColor = parseCssColor(arg); if (maybeColor != null) { css.textDecorationColor = maybeColor; @@ -2135,7 +2144,7 @@ } else { const valueObj = value || {}; const keys = properties || ObjectKeys(valueObj); - for (const k of keys) { + for (const k of new SafeArrayIterator(keys)) { if (!primitive && ReflectHas(valueObj, k)) { if (!(ReflectHas(objectValues, k))) { objectValues[k] = ArrayPrototypeFill(new Array(numRows), ""); @@ -2330,7 +2339,7 @@ function wrapConsole(consoleFromDeno, consoleFromV8) { const callConsole = core.callConsole; - for (const key of ObjectKeys(consoleFromV8)) { + for (const key of new SafeArrayIterator(ObjectKeys(consoleFromV8))) { if (ObjectPrototypeHasOwnProperty(consoleFromDeno, key)) { consoleFromDeno[key] = FunctionPrototypeBind( callConsole, diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index fac407d880..f56bfb6c0d 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -34,6 +34,7 @@ StringPrototypeToUpperCase, StringPrototypeCharCodeAt, StringFromCharCode, + SafeArrayIterator, Symbol, SymbolFor, SyntaxError, @@ -4052,7 +4053,7 @@ } const pkcs8Der = ops.op_export_pkcs8_ed25519( - new Uint8Array([0x04, 0x22, ...innerKey]), + new Uint8Array([0x04, 0x22, ...new SafeArrayIterator(innerKey)]), ); pkcs8Der[15] = 0x20; return pkcs8Der.buffer; @@ -4115,7 +4116,7 @@ } const pkcs8Der = ops.op_export_pkcs8_x25519( - new Uint8Array([0x04, 0x22, ...innerKey]), + new Uint8Array([0x04, 0x22, ...new SafeArrayIterator(innerKey)]), ); pkcs8Der[15] = 0x20; return pkcs8Der.buffer; diff --git a/ext/fetch/20_headers.js b/ext/fetch/20_headers.js index ae32aec11e..c4a9198072 100644 --- a/ext/fetch/20_headers.js +++ b/ext/fetch/20_headers.js @@ -68,7 +68,7 @@ */ function fillHeaders(headers, object) { if (ArrayIsArray(object)) { - for (const header of object) { + for (const header of new SafeArrayIterator(object)) { if (header.length !== 2) { throw new TypeError( `Invalid header. Length must be 2, but is ${header.length}`, @@ -205,7 +205,7 @@ // spec but produce the same result. const headers = {}; const cookies = []; - for (const entry of list) { + for (const entry of new SafeArrayIterator(list)) { const name = byteLowerCase(entry[0]); const value = entry[1]; if (value === null) throw new TypeError("Unreachable"); @@ -405,6 +405,7 @@ [SymbolFor("Deno.privateCustomInspect")](inspect) { const headers = {}; + // deno-lint-ignore prefer-primordials for (const header of this) { headers[header[0]] = header[1]; } diff --git a/ext/fetch/21_formdata.js b/ext/fetch/21_formdata.js index 34103858f3..e79ceabad7 100644 --- a/ext/fetch/21_formdata.js +++ b/ext/fetch/21_formdata.js @@ -25,6 +25,7 @@ MathRandom, ObjectPrototypeIsPrototypeOf, Symbol, + SafeArrayIterator, StringFromCharCode, StringPrototypeTrim, StringPrototypeSlice, @@ -162,7 +163,7 @@ context: "Argument 1", }); - for (const entry of this[entryList]) { + for (const entry of new SafeArrayIterator(this[entryList])) { if (entry.name === name) return entry.value; } return null; @@ -183,7 +184,7 @@ }); const returnList = []; - for (const entry of this[entryList]) { + for (const entry of new SafeArrayIterator(this[entryList])) { if (entry.name === name) ArrayPrototypePush(returnList, entry.value); } return returnList; @@ -203,7 +204,7 @@ context: "Argument 1", }); - for (const entry of this[entryList]) { + for (const entry of new SafeArrayIterator(this[entryList])) { if (entry.name === name) return true; } return false; @@ -298,6 +299,7 @@ const chunks = []; const prefix = `--${boundary}\r\nContent-Disposition: form-data; name="`; + // deno-lint-ignore prefer-primordials for (const [name, value] of formData) { if (typeof value === "string") { ArrayPrototypePush( @@ -372,7 +374,7 @@ #parseHeaders(headersText) { const headers = new Headers(); const rawHeaders = StringPrototypeSplit(headersText, "\r\n"); - for (const rawHeader of rawHeaders) { + for (const rawHeader of new SafeArrayIterator(rawHeaders)) { const sepIndex = StringPrototypeIndexOf(rawHeader, ":"); if (sepIndex < 0) { continue; // Skip this header diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index 1b340a7662..2dc6bb5e0d 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -6,18 +6,20 @@ const ops = core.ops; const __bootstrap = window.__bootstrap; const { - ObjectDefineProperty, ArrayPrototypeMap, + ArrayPrototypeJoin, + ObjectDefineProperty, + ObjectPrototypeHasOwnProperty, + ObjectPrototypeIsPrototypeOf, Number, NumberIsSafeInteger, - ArrayPrototypeJoin, - ObjectPrototypeIsPrototypeOf, TypeError, Int32Array, Uint32Array, BigInt64Array, BigUint64Array, Function, + ReflectHas, } = window.__bootstrap.primordials; const U32_BUFFER = new Uint32Array(2); @@ -273,7 +275,11 @@ constructor(path, symbols) { [this.#rid, this.symbols] = ops.op_ffi_load({ path, symbols }); for (const symbol in symbols) { - if ("type" in symbols[symbol]) { + if (!ObjectPrototypeHasOwnProperty(symbols, symbol)) { + continue; + } + + if (ReflectHas(symbols[symbol], "type")) { const type = symbols[symbol].type; if (type === "void") { throw new TypeError( diff --git a/ext/flash/01_http.js b/ext/flash/01_http.js index 2b0caff493..8c71322d71 100644 --- a/ext/flash/01_http.js +++ b/ext/flash/01_http.js @@ -27,11 +27,11 @@ } = window.__bootstrap.webSocket; const { _ws } = window.__bootstrap.http; const { - Function, ObjectPrototypeIsPrototypeOf, - Promise, + PromisePrototype, PromisePrototypeCatch, PromisePrototypeThen, + SafeArrayIterator, SafePromiseAll, TypedArrayPrototypeSubarray, TypeError, @@ -140,7 +140,7 @@ // status-line = HTTP-version SP status-code SP reason-phrase CRLF // Date header: https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.1.2 let str = `HTTP/1.1 ${status} ${statusCodes[status]}\r\nDate: ${date}\r\n`; - for (const [name, value] of headerList) { + for (const [name, value] of new SafeArrayIterator(headerList)) { // header-field = field-name ":" OWS field-value OWS str += `${name}: ${value}\r\n`; } @@ -439,10 +439,10 @@ return async function serve(arg1, arg2) { let options = undefined; let handler = undefined; - if (arg1 instanceof Function) { + if (typeof arg1 === "function") { handler = arg1; options = arg2; - } else if (arg2 instanceof Function) { + } else if (typeof arg2 === "function") { handler = arg2; options = arg1; } else { @@ -456,7 +456,7 @@ } handler = options.handler; } - if (!(handler instanceof Function)) { + if (typeof handler !== "function") { throw new TypeError("A handler function must be provided."); } if (options === undefined) { @@ -570,7 +570,7 @@ let resp; try { resp = handler(req); - if (resp instanceof Promise) { + if (ObjectPrototypeIsPrototypeOf(PromisePrototype, resp)) { PromisePrototypeCatch( PromisePrototypeThen( resp, diff --git a/ext/http/01_http.js b/ext/http/01_http.js index ab23cbec05..bd740b600c 100644 --- a/ext/http/01_http.js +++ b/ext/http/01_http.js @@ -45,10 +45,10 @@ ArrayPrototypeSome, Error, ObjectPrototypeIsPrototypeOf, + SafeSetIterator, Set, SetPrototypeAdd, SetPrototypeDelete, - SetPrototypeValues, StringPrototypeIncludes, StringPrototypeToLowerCase, StringPrototypeSplit, @@ -153,7 +153,7 @@ if (!this.#closed) { this.#closed = true; core.close(this.#rid); - for (const rid of SetPrototypeValues(this.managedResources)) { + for (const rid of new SafeSetIterator(this.managedResources)) { SetPrototypeDelete(this.managedResources, rid); core.close(rid); } diff --git a/ext/url/00_url.js b/ext/url/00_url.js index ebb7b6277b..75bf7372a5 100644 --- a/ext/url/00_url.js +++ b/ext/url/00_url.js @@ -194,7 +194,7 @@ context: "Argument 1", }); const values = []; - for (const entry of this[_list]) { + for (const entry of new SafeArrayIterator(this[_list])) { if (entry[0] === name) { ArrayPrototypePush(values, entry[1]); } @@ -214,7 +214,7 @@ prefix, context: "Argument 1", }); - for (const entry of this[_list]) { + for (const entry of new SafeArrayIterator(this[_list])) { if (entry[0] === name) { return entry[1]; } diff --git a/ext/url/01_urlpattern.js b/ext/url/01_urlpattern.js index ac18a4c821..cef48eabbc 100644 --- a/ext/url/01_urlpattern.js +++ b/ext/url/01_urlpattern.js @@ -20,6 +20,7 @@ RegExp, RegExpPrototypeExec, RegExpPrototypeTest, + SafeArrayIterator, Symbol, SymbolFor, TypeError, @@ -71,7 +72,7 @@ const components = ops.op_urlpattern_parse(input, baseURL); - for (const key of ObjectKeys(components)) { + for (const key of new SafeArrayIterator(ObjectKeys(components))) { try { components[key].regexp = new RegExp( components[key].regexpString, @@ -155,7 +156,7 @@ const [values] = res; - for (const key of ObjectKeys(values)) { + for (const key of new SafeArrayIterator(ObjectKeys(values))) { if (!RegExpPrototypeTest(this[_components][key].regexp, values[key])) { return false; } @@ -201,7 +202,7 @@ const result = { inputs }; /** @type {string} */ - for (const key of ObjectKeys(values)) { + for (const key of new SafeArrayIterator(ObjectKeys(values))) { /** @type {Component} */ const component = this[_components][key]; const input = values[key]; diff --git a/ext/web/01_dom_exception.js b/ext/web/01_dom_exception.js index d040062043..e278c86524 100644 --- a/ext/web/01_dom_exception.js +++ b/ext/web/01_dom_exception.js @@ -19,6 +19,7 @@ ObjectEntries, ObjectPrototypeIsPrototypeOf, ObjectSetPrototypeOf, + SafeArrayIterator, Symbol, SymbolFor, } = window.__bootstrap.primordials; @@ -166,33 +167,35 @@ const DOMExceptionPrototype = DOMException.prototype; for ( - const [key, value] of ObjectEntries({ - INDEX_SIZE_ERR, - DOMSTRING_SIZE_ERR, - HIERARCHY_REQUEST_ERR, - WRONG_DOCUMENT_ERR, - INVALID_CHARACTER_ERR, - NO_DATA_ALLOWED_ERR, - NO_MODIFICATION_ALLOWED_ERR, - NOT_FOUND_ERR, - NOT_SUPPORTED_ERR, - INUSE_ATTRIBUTE_ERR, - INVALID_STATE_ERR, - SYNTAX_ERR, - INVALID_MODIFICATION_ERR, - NAMESPACE_ERR, - INVALID_ACCESS_ERR, - VALIDATION_ERR, - TYPE_MISMATCH_ERR, - SECURITY_ERR, - NETWORK_ERR, - ABORT_ERR, - URL_MISMATCH_ERR, - QUOTA_EXCEEDED_ERR, - TIMEOUT_ERR, - INVALID_NODE_TYPE_ERR, - DATA_CLONE_ERR, - }) + const [key, value] of new SafeArrayIterator( + ObjectEntries({ + INDEX_SIZE_ERR, + DOMSTRING_SIZE_ERR, + HIERARCHY_REQUEST_ERR, + WRONG_DOCUMENT_ERR, + INVALID_CHARACTER_ERR, + NO_DATA_ALLOWED_ERR, + NO_MODIFICATION_ALLOWED_ERR, + NOT_FOUND_ERR, + NOT_SUPPORTED_ERR, + INUSE_ATTRIBUTE_ERR, + INVALID_STATE_ERR, + SYNTAX_ERR, + INVALID_MODIFICATION_ERR, + NAMESPACE_ERR, + INVALID_ACCESS_ERR, + VALIDATION_ERR, + TYPE_MISMATCH_ERR, + SECURITY_ERR, + NETWORK_ERR, + ABORT_ERR, + URL_MISMATCH_ERR, + QUOTA_EXCEEDED_ERR, + TIMEOUT_ERR, + INVALID_NODE_TYPE_ERR, + DATA_CLONE_ERR, + }), + ) ) { const desc = { value, enumerable: true }; ObjectDefineProperty(DOMException, key, desc); diff --git a/ext/web/01_mimesniff.js b/ext/web/01_mimesniff.js index d2c784d6eb..47453bd996 100644 --- a/ext/web/01_mimesniff.js +++ b/ext/web/01_mimesniff.js @@ -16,6 +16,8 @@ MapPrototypeHas, MapPrototypeSet, RegExpPrototypeTest, + SafeArrayIterator, + SafeMapIterator, StringPrototypeReplaceAll, StringPrototypeToLowerCase, } = window.__bootstrap.primordials; @@ -195,7 +197,7 @@ */ function serializeMimeType(mimeType) { let serialization = essence(mimeType); - for (const param of mimeType.parameters) { + for (const param of new SafeMapIterator(mimeType.parameters)) { serialization += `;${param[0]}=`; let value = param[1]; if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, value)) { @@ -221,7 +223,7 @@ let charset = null; let essence_ = null; let mimeType = null; - for (const value of headerValues) { + for (const value of new SafeArrayIterator(headerValues)) { const temporaryMimeType = parseMimeType(value); if ( temporaryMimeType === null || diff --git a/ext/web/02_event.js b/ext/web/02_event.js index fa1c943328..0601014986 100644 --- a/ext/web/02_event.js +++ b/ext/web/02_event.js @@ -428,7 +428,7 @@ Ctor, props, ) { - for (const prop of props) { + for (const prop of new SafeArrayIterator(props)) { ReflectDefineProperty(Ctor.prototype, prop, { enumerable: true }); } } @@ -969,7 +969,7 @@ listeners[type] = []; } - for (const listener of listeners[type]) { + for (const listener of new SafeArrayIterator(listeners[type])) { if ( ((typeof listener.options === "boolean" && listener.options === options.capture) || @@ -1334,9 +1334,12 @@ [SymbolFor("Deno.privateCustomInspect")](inspect) { return inspect(consoleInternal.createFilteredInspectProxy({ object: this, - evaluate: this instanceof PromiseRejectionEvent, + evaluate: ObjectPrototypeIsPrototypeOf( + PromiseRejectionEvent.prototype, + this, + ), keys: [ - ...EVENT_PROPS, + ...new SafeArrayIterator(EVENT_PROPS), "promise", "reason", ], @@ -1451,7 +1454,7 @@ colno = jsError.frames[0].columnNumber; } else { const jsError = core.destructureError(new Error()); - for (const frame of jsError.frames) { + for (const frame of new SafeArrayIterator(jsError.frames)) { if ( typeof frame.fileName == "string" && !StringPrototypeStartsWith(frame.fileName, "deno:") diff --git a/ext/web/03_abort_signal.js b/ext/web/03_abort_signal.js index 2fa3c4bcf4..70511a9341 100644 --- a/ext/web/03_abort_signal.js +++ b/ext/web/03_abort_signal.js @@ -9,6 +9,8 @@ const { Event, setIsTrusted, defineEventHandler } = window.__bootstrap.event; const { EventTarget, listenerCount } = window.__bootstrap.eventTarget; const { + SafeArrayIterator, + SafeSetIterator, Set, SetPrototypeAdd, SetPrototypeDelete, @@ -76,7 +78,7 @@ } this[abortReason] = reason; if (this[abortAlgos] !== null) { - for (const algorithm of this[abortAlgos]) { + for (const algorithm of new SafeSetIterator(this[abortAlgos])) { algorithm(); } this[abortAlgos] = null; @@ -124,14 +126,14 @@ // only be used by Deno internals, which use it to essentially cancel async // ops which would block the event loop. addEventListener(...args) { - super.addEventListener(...args); + super.addEventListener(...new SafeArrayIterator(args)); if (this[timerId] !== null && listenerCount(this, "abort") > 0) { refTimer(this[timerId]); } } removeEventListener(...args) { - super.removeEventListener(...args); + super.removeEventListener(...new SafeArrayIterator(args)); if (this[timerId] !== null && listenerCount(this, "abort") === 0) { unrefTimer(this[timerId]); } diff --git a/ext/web/05_base64.js b/ext/web/05_base64.js index 89c409ae23..d963596ce1 100644 --- a/ext/web/05_base64.js +++ b/ext/web/05_base64.js @@ -13,7 +13,10 @@ const ops = core.ops; const webidl = window.__bootstrap.webidl; const { DOMException } = window.__bootstrap.domException; - const { TypeError } = window.__bootstrap.primordials; + const { + ObjectPrototypeIsPrototypeOf, + TypeErrorPrototype, + } = window.__bootstrap.primordials; /** * @param {string} data @@ -29,7 +32,7 @@ try { return ops.op_base64_atob(data); } catch (e) { - if (e instanceof TypeError) { + if (ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e)) { throw new DOMException( "Failed to decode base64: invalid character", "InvalidCharacterError", @@ -53,7 +56,7 @@ try { return ops.op_base64_btoa(data); } catch (e) { - if (e instanceof TypeError) { + if (ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e)) { throw new DOMException( "The string to be encoded contains characters outside of the Latin1 range.", "InvalidCharacterError", diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index d51556a37b..2a032b3264 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -42,6 +42,7 @@ queueMicrotask, RangeError, ReflectHas, + SafeArrayIterator, SafePromiseAll, SharedArrayBuffer, Symbol, @@ -769,7 +770,7 @@ } function readableStreamIsUnrefable(stream) { - return _isUnref in stream; + return ReflectHas(stream, _isUnref); } function readableStreamForRidUnrefableRef(stream) { @@ -858,7 +859,7 @@ const finalBuffer = new Uint8Array(totalLength); let i = 0; - for (const chunk of chunks) { + for (const chunk of new SafeArrayIterator(chunks)) { TypedArrayPrototypeSet(finalBuffer, chunk, i); i += chunk.byteLength; } @@ -1345,7 +1346,7 @@ if (reader !== undefined && isReadableStreamBYOBReader(reader)) { const readIntoRequests = reader[_readIntoRequests]; reader[_readIntoRequests] = []; - for (const readIntoRequest of readIntoRequests) { + for (const readIntoRequest of new SafeArrayIterator(readIntoRequests)) { readIntoRequest.closeSteps(undefined); } } @@ -1371,7 +1372,7 @@ /** @type {Array>} */ const readRequests = reader[_readRequests]; reader[_readRequests] = []; - for (const readRequest of readRequests) { + for (const readRequest of new SafeArrayIterator(readRequests)) { readRequest.closeSteps(); } } @@ -1593,7 +1594,7 @@ function readableStreamDefaultReaderErrorReadRequests(reader, e) { const readRequests = reader[_readRequests]; reader[_readRequests] = []; - for (const readRequest of readRequests) { + for (const readRequest of new SafeArrayIterator(readRequests)) { readRequest.errorSteps(e); } } @@ -2613,7 +2614,7 @@ function readableStreamBYOBReaderErrorReadIntoRequests(reader, e) { const readIntoRequests = reader[_readIntoRequests]; reader[_readIntoRequests] = []; - for (const readIntoRequest of readIntoRequests) { + for (const readIntoRequest of new SafeArrayIterator(readIntoRequests)) { readIntoRequest.errorSteps(e); } } @@ -4237,7 +4238,7 @@ stream[_state] = "errored"; stream[_controller][_errorSteps](); const storedError = stream[_storedError]; - for (const writeRequest of stream[_writeRequests]) { + for (const writeRequest of new SafeArrayIterator(stream[_writeRequests])) { writeRequest.reject(storedError); } stream[_writeRequests] = []; diff --git a/ext/web/09_file.js b/ext/web/09_file.js index d01858c922..9c3a36dc0f 100644 --- a/ext/web/09_file.js +++ b/ext/web/09_file.js @@ -26,6 +26,7 @@ MathMin, ObjectPrototypeIsPrototypeOf, RegExpPrototypeTest, + SafeArrayIterator, StringPrototypeCharAt, StringPrototypeToLowerCase, StringPrototypeSlice, @@ -94,7 +95,7 @@ /** @param {(BlobReference | Blob)[]} parts */ async function* toIterator(parts) { - for (const part of parts) { + for (const part of new SafeArrayIterator(parts)) { yield* part.stream(); } } @@ -110,7 +111,7 @@ /** @type {(BlobReference|Blob)[]} */ const processedParts = []; let size = 0; - for (const element of parts) { + for (const element of new SafeArrayIterator(parts)) { if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, element)) { const chunk = new Uint8Array(ArrayBufferPrototypeSlice(element, 0)); ArrayPrototypePush(processedParts, BlobReference.fromUint8Array(chunk)); @@ -158,7 +159,7 @@ * @returns {string[]} */ function getParts(blob, bag = []) { - for (const part of blob[_parts]) { + for (const part of new SafeArrayIterator(blob[_parts])) { if (ObjectPrototypeIsPrototypeOf(BlobPrototype, part)) { getParts(part, bag); } else { @@ -275,7 +276,7 @@ const blobParts = []; let added = 0; - for (const part of this[_parts]) { + for (const part of new SafeArrayIterator(this[_parts])) { // don't add the overflow to new blobParts if (added >= span) { // Could maybe be possible to remove variable `added` @@ -349,6 +350,7 @@ const bytes = new Uint8Array(size); const partIterator = toIterator(this[_parts]); let offset = 0; + // deno-lint-ignore prefer-primordials for await (const chunk of partIterator) { const byteLength = chunk.byteLength; if (byteLength > 0) { @@ -598,7 +600,7 @@ const parts = []; let totalSize = 0; - for (const { uuid, size } of blobData.parts) { + for (const { uuid, size } of new SafeArrayIterator(blobData.parts)) { ArrayPrototypePush(parts, new BlobReference(uuid, size)); totalSize += size; } diff --git a/ext/web/10_filereader.js b/ext/web/10_filereader.js index 49f4babe11..30396a8d0f 100644 --- a/ext/web/10_filereader.js +++ b/ext/web/10_filereader.js @@ -158,7 +158,7 @@ ); const bytes = new Uint8Array(size); let offs = 0; - for (const chunk of chunks) { + for (const chunk of new SafeArrayIterator(chunks)) { TypedArrayPrototypeSet(bytes, chunk, offs); offs += chunk.byteLength; } diff --git a/ext/web/13_message_port.js b/ext/web/13_message_port.js index 7343fbe58a..7ec8dc9f95 100644 --- a/ext/web/13_message_port.js +++ b/ext/web/13_message_port.js @@ -22,6 +22,7 @@ ArrayPrototypePush, ObjectPrototypeIsPrototypeOf, ObjectSetPrototypeOf, + SafeArrayIterator, Symbol, SymbolFor, SymbolIterator, @@ -204,7 +205,9 @@ const arrayBufferIdsInTransferables = []; const transferredArrayBuffers = []; - for (const transferable of messageData.transferables) { + for ( + const transferable of new SafeArrayIterator(messageData.transferables) + ) { switch (transferable.kind) { case "messagePort": { const port = createMessagePort(transferable.data); @@ -271,7 +274,7 @@ const serializedTransferables = []; let arrayBufferI = 0; - for (const transferable of transferables) { + for (const transferable of new SafeArrayIterator(transferables)) { if (ObjectPrototypeIsPrototypeOf(MessagePortPrototype, transferable)) { webidl.assertBranded(transferable, MessagePortPrototype); const id = transferable[_id]; diff --git a/ext/webgpu/src/01_webgpu.js b/ext/webgpu/src/01_webgpu.js index f4d15e2dd8..a5863b6c6a 100644 --- a/ext/webgpu/src/01_webgpu.js +++ b/ext/webgpu/src/01_webgpu.js @@ -316,7 +316,7 @@ context: "Argument 1", }); const requiredFeatures = descriptor.requiredFeatures ?? []; - for (const feature of requiredFeatures) { + for (const feature of new SafeArrayIterator(requiredFeatures)) { if (!SetPrototypeHas(this[_adapter].features[_features], feature)) { throw new TypeError( `${prefix}: nonGuaranteedFeatures must be a subset of the adapter features.`, @@ -1046,7 +1046,7 @@ context: "Argument 1", }); const device = assertDevice(this, { prefix, context: "this" }); - for (const entry of descriptor.entries) { + for (const entry of new SafeArrayIterator(descriptor.entries)) { let i = 0; if (entry.buffer) i++; if (entry.sampler) i++; @@ -1591,7 +1591,7 @@ device.rid, commandBufferRids, ); - for (const commandBuffer of commandBuffers) { + for (const commandBuffer of new SafeArrayIterator(commandBuffers)) { commandBuffer[_rid] = undefined; } device.pushError(err); @@ -1934,7 +1934,7 @@ if (!mappedRanges) { throw new DOMException(`${prefix}: invalid state.`, "OperationError"); } - for (const [buffer, _rid, start] of mappedRanges) { + for (const [buffer, _rid, start] of new SafeArrayIterator(mappedRanges)) { // TODO(lucacasonato): is this logic correct? const end = start + buffer.byteLength; if ( @@ -2002,7 +2002,7 @@ if (!mappedRanges) { throw new DOMException(`${prefix}: invalid state.`, "OperationError"); } - for (const [buffer, mappedRid] of mappedRanges) { + for (const [buffer, mappedRid] of new SafeArrayIterator(mappedRanges)) { const { err } = ops.op_webgpu_buffer_unmap( bufferRid, mappedRid, diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index d9c4f87cf0..dafade99dd 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -60,6 +60,7 @@ ReflectHas, ReflectOwnKeys, RegExpPrototypeTest, + SafeArrayIterator, Set, // TODO(lucacasonato): add SharedArrayBuffer to primordials // SharedArrayBuffer, @@ -632,8 +633,8 @@ function createDictionaryConverter(name, ...dictionaries) { let hasRequiredKey = false; const allMembers = []; - for (const members of dictionaries) { - for (const member of members) { + for (const members of new SafeArrayIterator(dictionaries)) { + for (const member of new SafeArrayIterator(members)) { if (member.required) { hasRequiredKey = true; } @@ -648,7 +649,7 @@ }); const defaultValues = {}; - for (const member of allMembers) { + for (const member of new SafeArrayIterator(allMembers)) { if (ReflectHas(member, "defaultValue")) { const idlMemberValue = member.defaultValue; const imvType = typeof idlMemberValue; @@ -694,7 +695,7 @@ return idlDict; } - for (const member of allMembers) { + for (const member of new SafeArrayIterator(allMembers)) { const key = member.key; let esMemberValue; @@ -820,7 +821,7 @@ } // Slow path if Proxy (e.g: in WPT tests) const keys = ReflectOwnKeys(V); - for (const key of keys) { + for (const key of new SafeArrayIterator(keys)) { const desc = ObjectGetOwnPropertyDescriptor(V, key); if (desc !== undefined && desc.enumerable === true) { const typedKey = keyConverter(key, opts); @@ -890,7 +891,7 @@ } function define(target, source) { - for (const key of ReflectOwnKeys(source)) { + for (const key of new SafeArrayIterator(ReflectOwnKeys(source))) { const descriptor = ReflectGetOwnPropertyDescriptor(source, key); if (descriptor && !ReflectDefineProperty(target, key, descriptor)) { throw new TypeError(`Cannot redefine property: ${String(key)}`); diff --git a/runtime/js/10_permissions.js b/runtime/js/10_permissions.js index f048a5d628..cf2fdde7d3 100644 --- a/runtime/js/10_permissions.js +++ b/runtime/js/10_permissions.js @@ -20,6 +20,7 @@ PromiseResolve, PromiseReject, ReflectHas, + SafeArrayIterator, SymbolFor, TypeError, } = window.__bootstrap.primordials; @@ -233,7 +234,9 @@ function serializePermissions(permissions) { if (typeof permissions == "object" && permissions != null) { const serializedPermissions = {}; - for (const key of ["read", "write", "run", "ffi"]) { + for ( + const key of new SafeArrayIterator(["read", "write", "run", "ffi"]) + ) { if (ArrayIsArray(permissions[key])) { serializedPermissions[key] = ArrayPrototypeMap( permissions[key], @@ -243,7 +246,9 @@ serializedPermissions[key] = permissions[key]; } } - for (const key of ["env", "hrtime", "net", "sys"]) { + for ( + const key of new SafeArrayIterator(["env", "hrtime", "net", "sys"]) + ) { if (ArrayIsArray(permissions[key])) { serializedPermissions[key] = ArrayPrototypeSlice(permissions[key]); } else { diff --git a/runtime/js/12_io.js b/runtime/js/12_io.js index db83343bf0..c8fc002fcf 100644 --- a/runtime/js/12_io.js +++ b/runtime/js/12_io.js @@ -12,6 +12,7 @@ Uint8Array, ArrayPrototypePush, MathMin, + SafeArrayIterator, TypedArrayPrototypeSubarray, TypedArrayPrototypeSet, } = window.__bootstrap.primordials; @@ -156,14 +157,14 @@ function concatBuffers(buffers) { let totalLen = 0; - for (const buf of buffers) { + for (const buf of new SafeArrayIterator(buffers)) { totalLen += buf.byteLength; } const contents = new Uint8Array(totalLen); let n = 0; - for (const buf of buffers) { + for (const buf of new SafeArrayIterator(buffers)) { TypedArrayPrototypeSet(contents, buf, n); n += buf.byteLength; } diff --git a/runtime/js/30_fs.js b/runtime/js/30_fs.js index 4a78ebcad1..242e480b3d 100644 --- a/runtime/js/30_fs.js +++ b/runtime/js/30_fs.js @@ -9,6 +9,7 @@ DatePrototype, MathTrunc, ObjectPrototypeIsPrototypeOf, + SafeArrayIterator, SymbolAsyncIterator, SymbolIterator, Function, @@ -211,7 +212,7 @@ let offset = 0; let str = 'const unix = Deno.build.os === "darwin" || Deno.build.os === "linux"; return {'; - for (let [name, type] of ObjectEntries(types)) { + for (let [name, type] of new SafeArrayIterator(ObjectEntries(types))) { const optional = type.startsWith("?"); if (optional) type = type.slice(1); diff --git a/runtime/js/40_process.js b/runtime/js/40_process.js index 51cae9e66f..f837b2b4c9 100644 --- a/runtime/js/40_process.js +++ b/runtime/js/40_process.js @@ -13,6 +13,7 @@ ArrayPrototypeSlice, TypeError, ObjectEntries, + SafeArrayIterator, String, } = window.__bootstrap.primordials; @@ -111,7 +112,10 @@ stdin = "inherit", }) { if (cmd[0] != null) { - cmd = [pathFromURL(cmd[0]), ...ArrayPrototypeSlice(cmd, 1)]; + cmd = [ + pathFromURL(cmd[0]), + ...new SafeArrayIterator(ArrayPrototypeSlice(cmd, 1)), + ]; } const res = opRun({ cmd: ArrayPrototypeMap(cmd, String), diff --git a/runtime/js/40_signals.js b/runtime/js/40_signals.js index 94171628f0..71ead71c7f 100644 --- a/runtime/js/40_signals.js +++ b/runtime/js/40_signals.js @@ -5,7 +5,9 @@ const core = window.Deno.core; const ops = core.ops; const { + SafeSetIterator, Set, + SetPrototypeDelete, SymbolFor, TypeError, } = window.__bootstrap.primordials; @@ -60,7 +62,7 @@ checkSignalListenerType(listener); const sigData = getSignalData(signo); - sigData.listeners.delete(listener); + SetPrototypeDelete(sigData.listeners, listener); if (sigData.listeners.size === 0 && sigData.rid) { unbindSignal(sigData.rid); @@ -73,7 +75,7 @@ if (await pollSignal(sigData.rid)) { return; } - for (const listener of sigData.listeners) { + for (const listener of new SafeSetIterator(sigData.listeners)) { listener(); } } diff --git a/runtime/js/40_spawn.js b/runtime/js/40_spawn.js index 0f26313a61..9d4aa3e9f2 100644 --- a/runtime/js/40_spawn.js +++ b/runtime/js/40_spawn.js @@ -10,6 +10,7 @@ const { ArrayPrototypeMap, ObjectEntries, + ObjectPrototypeIsPrototypeOf, String, TypeError, PromisePrototypeThen, @@ -21,6 +22,7 @@ readableStreamForRidUnrefable, readableStreamForRidUnrefableRef, readableStreamForRidUnrefableUnref, + ReadableStreamPrototype, writableStreamForRid, } = window.__bootstrap.streams; @@ -65,7 +67,9 @@ } function collectOutput(readableStream) { - if (!(readableStream instanceof ReadableStream)) { + if ( + !(ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, readableStream)) + ) { return null; } diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 1eb71339fa..901cb136fe 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -19,6 +19,7 @@ delete Intl.v8BreakIterator; ArrayPrototypeMap, DateNow, Error, + ErrorPrototype, FunctionPrototypeCall, FunctionPrototypeBind, ObjectAssign, @@ -32,6 +33,7 @@ delete Intl.v8BreakIterator; SymbolFor, SymbolIterator, PromisePrototypeThen, + SafeArrayIterator, SafeWeakMap, TypeError, WeakMapPrototypeDelete, @@ -204,7 +206,7 @@ delete Intl.v8BreakIterator; ); loadedMainWorkerScript = true; - for (const { url, script } of scripts) { + for (const { url, script } of new SafeArrayIterator(scripts)) { const err = core.evalContext(script, url)[1]; if (err !== null) { throw err.thrown; @@ -217,7 +219,7 @@ delete Intl.v8BreakIterator; } function formatException(error) { - if (error instanceof Error) { + if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, error)) { return null; } else if (typeof error == "string") { return `Uncaught ${ diff --git a/third_party b/third_party index 17fd391b8f..3e5b0cea16 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit 17fd391b8f305d1e74ce7508c824176f09ab63d0 +Subproject commit 3e5b0cea163cc0f2b3b0c7cedffc112cc49d6a78