From 3b268094ccc60703987060434829e24bb4043f6a Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 14 Jun 2020 14:49:34 -0700 Subject: [PATCH 001/138] doc: use sentence-case for headings in docs Backport-PR-URL: https://github.com/nodejs/node/pull/33961 PR-URL: https://github.com/nodejs/node/pull/33889 Refs: https://developers.google.com/style/capitalization#capitalization-in-titles-and-headings Refs: https://docs.microsoft.com/en-us/style-guide/capitalization Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- doc/api/addons.md | 6 +-- doc/api/async_hooks.md | 8 ++-- doc/api/buffer.md | 4 +- doc/api/child_process.md | 44 ++++++++++---------- doc/api/cli.md | 16 +++---- doc/api/cluster.md | 6 +-- doc/api/crypto.md | 18 ++++---- doc/api/debugger.md | 8 ++-- doc/api/deprecations.md | 14 +++---- doc/api/dgram.md | 10 ++--- doc/api/dns.md | 2 +- doc/api/documentation.md | 6 +-- doc/api/domain.md | 12 +++--- doc/api/embedding.md | 2 +- doc/api/errors.md | 20 ++++----- doc/api/esm.md | 58 +++++++++++++------------- doc/api/events.md | 14 +++---- doc/api/fs.md | 40 +++++++++--------- doc/api/globals.md | 2 +- doc/api/http2.md | 14 +++---- doc/api/index.md | 34 +++++++-------- doc/api/inspector.md | 4 +- doc/api/intl.md | 2 +- doc/api/modules.md | 24 +++++------ doc/api/n-api.md | 62 +++++++++++++-------------- doc/api/net.md | 2 +- doc/api/os.md | 18 ++++---- doc/api/perf_hooks.md | 2 +- doc/api/policy.md | 8 ++-- doc/api/process.md | 10 ++--- doc/api/querystring.md | 2 +- doc/api/readline.md | 4 +- doc/api/repl.md | 24 +++++------ doc/api/report.md | 4 +- doc/api/stream.md | 88 +++++++++++++++++++-------------------- doc/api/string_decoder.md | 2 +- doc/api/synopsis.md | 2 +- doc/api/timers.md | 4 +- doc/api/tls.md | 42 ++++++++++--------- doc/api/tracing.md | 6 +-- doc/api/url.md | 6 +-- doc/api/util.md | 12 +++--- doc/api/v8.md | 4 +- doc/api/vm.md | 6 +-- doc/api/worker_threads.md | 2 +- doc/api/zlib.md | 10 ++--- 46 files changed, 346 insertions(+), 342 deletions(-) diff --git a/doc/api/addons.md b/doc/api/addons.md index 34f49d9a24ac77..9a2b6d1a536359 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -1,4 +1,4 @@ -# C++ Addons +# C++ addons @@ -395,7 +395,7 @@ only the symbols exported by Node.js will be available. source image. Using this option, the Addon will have access to the full set of dependencies. -### Loading Addons using `require()` +### Loading addons using `require()` The filename extension of the compiled Addon binary is `.node` (as opposed to `.dll` or `.so`). The [`require()`][require] function is written to look for @@ -410,7 +410,7 @@ there is a file `addon.js` in the same directory as the binary `addon.node`, then [`require('addon')`][require] will give precedence to the `addon.js` file and load it instead. -## Native Abstractions for Node.js +## Native abstractions for Node.js Each of the examples illustrated in this document make direct use of the Node.js and V8 APIs for implementing Addons. The V8 API can, and has, changed diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index cdac6287f4d6e6..49aac3dc445e45 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -1,4 +1,4 @@ -# Async Hooks +# Async hooks @@ -127,7 +127,7 @@ class MyAddedCallbacks extends MyAsyncCallbacks { const asyncHook = async_hooks.createHook(new MyAddedCallbacks()); ``` -##### Error Handling +##### Error handling If any `AsyncHook` callbacks throw, the application will print the stack trace and exit. The exit path does follow that of an uncaught exception, but @@ -201,7 +201,7 @@ be called again until enabled. For API consistency `disable()` also returns the `AsyncHook` instance. -#### Hook Callbacks +#### Hook callbacks Key events in the lifetime of asynchronous events have been categorized into four areas: instantiation, before/after the callback is called, and when the @@ -626,7 +626,7 @@ only on chained promises. That means promises not created by `then()`/`catch()` will not have the `before` and `after` callbacks fired on them. For more details see the details of the V8 [PromiseHooks][] API. -## JavaScript Embedder API +## JavaScript embedder API Library developers that handle their own asynchronous resources performing tasks like I/O, connection pooling, or managing callback queues may use the diff --git a/doc/api/buffer.md b/doc/api/buffer.md index b43b7eded247d7..2df4fe795082bf 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -53,7 +53,7 @@ const buf6 = Buffer.from('tést'); const buf7 = Buffer.from('tést', 'latin1'); ``` -## Buffers and Character Encodings +## Buffers and character encodings diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 1c1f736ed1b2da..779542c00fe58b 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -1,4 +1,4 @@ -# Child Process +# Child process @@ -70,7 +70,7 @@ For certain use cases, such as automating shell scripts, the the synchronous methods can have significant impact on performance due to stalling the event loop while spawned processes complete. -## Asynchronous Process Creation +## Asynchronous process creation The [`child_process.spawn()`][], [`child_process.fork()`][], [`child_process.exec()`][], and [`child_process.execFile()`][] methods all follow the idiomatic asynchronous @@ -153,7 +153,7 @@ changes: * `env` {Object} Environment key-value pairs. **Default:** `process.env`. * `encoding` {string} **Default:** `'utf8'` * `shell` {string} Shell to execute the command with. See - [Shell Requirements][] and [Default Windows Shell][]. **Default:** + [Shell requirements][] and [Default Windows shell][]. **Default:** `'/bin/sh'` on Unix, `process.env.ComSpec` on Windows. * `timeout` {number} **Default:** `0` * `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or @@ -270,8 +270,8 @@ changes: done on Windows. Ignored on Unix. **Default:** `false`. * `shell` {boolean|string} If `true`, runs `command` inside of a shell. Uses `'/bin/sh'` on Unix, and `process.env.ComSpec` on Windows. A different - shell can be specified as a string. See [Shell Requirements][] and - [Default Windows Shell][]. **Default:** `false` (no shell). + shell can be specified as a string. See [Shell requirements][] and + [Default Windows shell][]. **Default:** `false` (no shell). * `callback` {Function} Called with the output when process terminates. * `error` {Error} * `stdout` {string|Buffer} @@ -355,7 +355,7 @@ changes: **Default:** `process.execArgv`. * `serialization` {string} Specify the kind of serialization used for sending messages between processes. Possible values are `'json'` and `'advanced'`. - See [Advanced Serialization][] for more details. **Default:** `'json'`. + See [Advanced serialization][] for more details. **Default:** `'json'`. * `silent` {boolean} If `true`, stdin, stdout, and stderr of the child will be piped to the parent, otherwise they will be inherited from the parent, see the `'pipe'` and `'inherit'` options for [`child_process.spawn()`][]'s @@ -434,11 +434,11 @@ changes: * `gid` {number} Sets the group identity of the process (see setgid(2)). * `serialization` {string} Specify the kind of serialization used for sending messages between processes. Possible values are `'json'` and `'advanced'`. - See [Advanced Serialization][] for more details. **Default:** `'json'`. + See [Advanced serialization][] for more details. **Default:** `'json'`. * `shell` {boolean|string} If `true`, runs `command` inside of a shell. Uses `'/bin/sh'` on Unix, and `process.env.ComSpec` on Windows. A different - shell can be specified as a string. See [Shell Requirements][] and - [Default Windows Shell][]. **Default:** `false` (no shell). + shell can be specified as a string. See [Shell requirements][] and + [Default Windows shell][]. **Default:** `false` (no shell). * `windowsVerbatimArguments` {boolean} No quoting or escaping of arguments is done on Windows. Ignored on Unix. This is set to `true` automatically when `shell` is specified and is CMD. **Default:** `false`. @@ -699,7 +699,7 @@ see [V8 issue 7381](https://bugs.chromium.org/p/v8/issues/detail?id=7381). See also: [`child_process.exec()`][] and [`child_process.fork()`][]. -## Synchronous Process Creation +## Synchronous process creation The [`child_process.spawnSync()`][], [`child_process.execSync()`][], and [`child_process.execFileSync()`][] methods are synchronous and will block the @@ -755,8 +755,8 @@ changes: normally be created on Windows systems. **Default:** `false`. * `shell` {boolean|string} If `true`, runs `command` inside of a shell. Uses `'/bin/sh'` on Unix, and `process.env.ComSpec` on Windows. A different - shell can be specified as a string. See [Shell Requirements][] and - [Default Windows Shell][]. **Default:** `false` (no shell). + shell can be specified as a string. See [Shell requirements][] and + [Default Windows shell][]. **Default:** `false` (no shell). * Returns: {Buffer|string} The stdout from the command. The `child_process.execFileSync()` method is generally identical to @@ -804,7 +804,7 @@ changes: **Default:** `'pipe'`. * `env` {Object} Environment key-value pairs. **Default:** `process.env`. * `shell` {string} Shell to execute the command with. See - [Shell Requirements][] and [Default Windows Shell][]. **Default:** + [Shell requirements][] and [Default Windows shell][]. **Default:** `'/bin/sh'` on Unix, `process.env.ComSpec` on Windows. * `uid` {number} Sets the user identity of the process. (See setuid(2)). * `gid` {number} Sets the group identity of the process. (See setgid(2)). @@ -884,8 +884,8 @@ changes: **Default:** `'buffer'`. * `shell` {boolean|string} If `true`, runs `command` inside of a shell. Uses `'/bin/sh'` on Unix, and `process.env.ComSpec` on Windows. A different - shell can be specified as a string. See [Shell Requirements][] and - [Default Windows Shell][]. **Default:** `false` (no shell). + shell can be specified as a string. See [Shell requirements][] and + [Default Windows shell][]. **Default:** `false` (no shell). * `windowsVerbatimArguments` {boolean} No quoting or escaping of arguments is done on Windows. Ignored on Unix. This is set to `true` automatically when `shell` is specified and is CMD. **Default:** `false`. @@ -1025,7 +1025,7 @@ message might not be the same as what is originally sent. If the `serialization` option was set to `'advanced'` used when spawning the child process, the `message` argument can contain data that JSON is not able to represent. -See [Advanced Serialization][] for more details. +See [Advanced serialization][] for more details. ### `subprocess.channel` @@ -160,7 +160,7 @@ added: v12.12.0 > Stability: 1 - Experimental -Enable experimental Source Map V3 support for stack traces. +Enable experimental Source Map v3 support for stack traces. Currently, overriding `Error.prepareStackTrace` is ignored when the `--enable-source-maps` flag is set. @@ -1099,7 +1099,7 @@ added: v0.1.3 Print node's version. -## Environment Variables +## Environment variables ### `NODE_DEBUG=module[,…]` @@ -753,7 +753,7 @@ changes: `undefined` (inherits from parent process). * `serialization` {string} Specify the kind of serialization used for sending messages between processes. Possible values are `'json'` and `'advanced'`. - See [Advanced Serialization for `child_process`][] for more details. + See [Advanced serialization for `child_process`][] for more details. **Default:** `false`. * `silent` {boolean} Whether or not to send output to parent's stdio. **Default:** `false`. @@ -883,5 +883,5 @@ socket.on('data', (id) => { [`process` event: `'message'`]: process.html#process_event_message [`server.close()`]: net.html#net_event_close [`worker.exitedAfterDisconnect`]: #cluster_worker_exitedafterdisconnect -[Advanced Serialization for `child_process`]: child_process.html#child_process_advanced_serialization +[Advanced serialization for `child_process`]: child_process.html#child_process_advanced_serialization [Child Process module]: child_process.html#child_process_child_process_fork_modulepath_args_options diff --git a/doc/api/crypto.md b/doc/api/crypto.md index e45d41586cffd4..016a60802c46b4 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1585,7 +1585,7 @@ added: v6.3.0 * Returns: {Object} An object containing commonly used constants for crypto and security related operations. The specific constants currently defined are - described in [Crypto Constants][]. + described in [Crypto constants][]. ### `crypto.DEFAULT_ENCODING` @@ -6,7 +6,7 @@ -The `dgram` module provides an implementation of UDP Datagram sockets. +The `dgram` module provides an implementation of UDP datagram sockets. ```js const dgram = require('dgram'); @@ -558,7 +558,7 @@ also use explicit scope in addresses, so only packets sent to a multicast address without specifying an explicit scope are affected by the most recent successful use of this call. -#### Examples: IPv6 Outgoing Multicast Interface +#### Example: IPv6 outgoing multicast interface On most systems, where scope format uses the interface name: @@ -580,7 +580,7 @@ socket.bind(1234, () => { }); ``` -#### Example: IPv4 Outgoing Multicast Interface +#### Example: IPv4 outgoing multicast interface All systems use an IP of the host on the desired physical interface: ```js @@ -591,7 +591,7 @@ socket.bind(1234, () => { }); ``` -#### Call Results +#### Call results A call on a socket that is not ready to send or no longer open may throw a *Not running* [`Error`][]. diff --git a/doc/api/dns.md b/doc/api/dns.md index b89be2f104694f..8a4ee45fe10de5 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -621,7 +621,7 @@ That is, if attempting to resolve with the first server provided results in a subsequent servers provided. Fallback DNS servers will only be used if the earlier ones time out or result in some other error. -## DNS Promises API +## DNS promises API The `dns.promises` API provides an alternative set of asynchronous DNS methods that return `Promise` objects rather than using callbacks. The API is accessible diff --git a/doc/api/documentation.md b/doc/api/documentation.md index 7059c4d33e11ca..f15936b3f43279 100644 --- a/doc/api/documentation.md +++ b/doc/api/documentation.md @@ -1,4 +1,4 @@ -# About this Documentation +# About this documentation @@ -12,7 +12,7 @@ Node.js is a JavaScript runtime built on the [V8 JavaScript engine][]. Report errors in this documentation in [the issue tracker][]. See [the contributing guide][] for directions on how to submit pull requests. -## Stability Index +## Stability index @@ -43,7 +43,7 @@ Bugs or behavior changes may surprise end users when Experimental API modifications occur. To avoid surprises, use of an Experimental feature may need a command-line flag. Experimental features may also emit a [warning][]. -## JSON Output +## JSON output diff --git a/doc/api/domain.md b/doc/api/domain.md index fa3aef66b98241..b9219fbb4d714e 100644 --- a/doc/api/domain.md +++ b/doc/api/domain.md @@ -30,7 +30,7 @@ will be notified, rather than losing the context of the error in the `process.on('uncaughtException')` handler, or causing the program to exit immediately with an error code. -## Warning: Don't Ignore Errors! +## Warning: Don't ignore errors! @@ -199,7 +199,7 @@ are added to it. * `error.domainThrown` A boolean indicating whether the error was thrown, emitted, or passed to a bound callback function. -## Implicit Binding +## Implicit binding @@ -225,7 +225,7 @@ Implicit binding routes thrown errors and `'error'` events to the `Domain`. Implicit binding only takes care of thrown errors and `'error'` events. -## Explicit Binding +## Explicit binding @@ -432,9 +432,9 @@ d.run(() => { In this example, the `d.on('error')` handler will be triggered, rather than crashing the program. -## Domains and Promises +## Domains and promises -As of Node.js 8.0.0, the handlers of Promises are run inside the domain in +As of Node.js 8.0.0, the handlers of promises are run inside the domain in which the call to `.then()` or `.catch()` itself was made: ```js @@ -472,7 +472,7 @@ d2.run(() => { ``` Domains will not interfere with the error handling mechanisms for -Promises. In other words, no `'error'` event will be emitted for unhandled +promises. In other words, no `'error'` event will be emitted for unhandled `Promise` rejections. [`Error`]: errors.html#errors_class_error diff --git a/doc/api/embedding.md b/doc/api/embedding.md index a8fe2de72c9310..1a416f52c600de 100644 --- a/doc/api/embedding.md +++ b/doc/api/embedding.md @@ -1,4 +1,4 @@ -# C++ Embedder API +# C++ embedder API diff --git a/doc/api/errors.md b/doc/api/errors.md index bbec1313c5d827..d59c4029e60e5e 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -16,11 +16,11 @@ errors: Node.js detects an exceptional logic violation that should never occur. These are raised typically by the `assert` module. -All JavaScript and System errors raised by Node.js inherit from, or are +All JavaScript and system errors raised by Node.js inherit from, or are instances of, the standard JavaScript {Error} class and are guaranteed to provide *at least* the properties available on that class. -## Error Propagation and Interception +## Error propagation and interception @@ -186,7 +186,7 @@ circumstance of why the error occurred. `Error` objects capture a "stack trace" detailing the point in the code at which the `Error` was instantiated, and may provide a text description of the error. -All errors generated by Node.js, including all System and JavaScript errors, +All errors generated by Node.js, including all system and JavaScript errors, will either be instances of, or inherit from, the `Error` class. ### `new Error(message)` @@ -258,7 +258,7 @@ not capture any frames. The `error.code` property is a string label that identifies the kind of error. `error.code` is the most stable way to identify an error. It will only change between major versions of Node.js. In contrast, `error.message` strings may -change between any versions of Node.js. See [Node.js Error Codes][] for details +change between any versions of Node.js. See [Node.js error codes][] for details about specific codes. ### `error.message` @@ -497,7 +497,7 @@ If present, `error.port` is the network connection port that is not available. The `error.syscall` property is a string describing the [syscall][] that failed. -### Common System Errors +### Common system errors This is a list of system errors commonly-encountered when writing a Node.js program. For a comprehensive list, see the [`errno`(3) man page][]. @@ -574,7 +574,7 @@ require('url').parse(() => { }); Node.js will generate and throw `TypeError` instances *immediately* as a form of argument validation. -## Exceptions vs. Errors +## Exceptions vs. errors @@ -588,7 +588,7 @@ Some exceptions are *unrecoverable* at the JavaScript layer. Such exceptions will *always* cause the Node.js process to crash. Examples include `assert()` checks or `abort()` calls in the C++ layer. -## OpenSSL Errors +## OpenSSL errors Errors originating in `crypto` or `tls` are of class `Error`, and in addition to the standard `.code` and `.message` properties, may have some additional @@ -612,7 +612,7 @@ The OpenSSL library the error originates in. A human-readable string describing the reason for the error. -## Node.js Error Codes +## Node.js error codes ### `ERR_AMBIGUOUS_ARGUMENT` @@ -2213,7 +2213,7 @@ changes: A module file could not be resolved while attempting a [`require()`][] or `import` operation. -## Legacy Node.js Error Codes +## Legacy Node.js error codes > Stability: 0 - Deprecated. These error codes are either inconsistent, or have > been removed. @@ -2618,7 +2618,7 @@ such as `process.stdout.on('data')`. [`zlib`]: zlib.html [ES Module]: esm.html [ICU]: intl.html#intl_internationalization_support -[Node.js Error Codes]: #nodejs-error-codes +[Node.js error codes]: #nodejs-error-codes [V8's stack trace API]: https://github.com/v8/v8/wiki/Stack-Trace-API [WHATWG Supported Encodings]: util.html#util_whatwg_supported_encodings [WHATWG URL API]: url.html#url_the_whatwg_url_api diff --git a/doc/api/esm.md b/doc/api/esm.md index b92ae3138e97a4..9252eaeed2306a 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -1,4 +1,4 @@ -# ECMAScript Modules +# ECMAScript modules @@ -121,7 +121,7 @@ files in the package should be interpreted. Regardless of the value of the `"type"` field, `.mjs` files are always treated as ES modules and `.cjs` files are always treated as CommonJS. -### Package Scope and File Extensions +### Package scope and file extensions A folder containing a `package.json` file, and all subfolders below that folder down until the next folder containing another `package.json`, is considered a @@ -196,7 +196,7 @@ unspecified. ## Packages -### Package Entry Points +### Package entry points In a package’s `package.json` file, two fields can define entry points for a package: `"main"` and `"exports"`. The `"main"` field is supported in all @@ -216,7 +216,7 @@ CommonJS; `"main"` will be overridden by `"exports"` if it exists. As such fallback for legacy versions of Node.js that do not support the `"exports"` field. -[Conditional Exports][] can be used within `"exports"` to define different +[Conditional exports][] can be used within `"exports"` to define different package entry points per environment, including whether the package is referenced via `require` or via `import`. For more information about supporting both CommonJS and ES Modules in a single package please consult @@ -274,7 +274,7 @@ will encapsulation be lost but module consumers will be unable to `import feature from 'my-mod/feature'` as they will need to provide the full path `import feature from 'my-mod/feature/index.js`. -#### Main Entry Point Export +#### Main entry point export To set the main entry point for a package, it is advisable to define both `"exports"` and `"main"` in the package’s `package.json` file: @@ -298,7 +298,7 @@ package. It is not a strong encapsulation since a direct require of any absolute subpath of the package such as `require('/path/to/node_modules/pkg/subpath.js')` will still load `subpath.js`. -#### Subpath Exports +#### Subpath exports When using the `"exports"` field, custom subpaths can be defined along with the main entry point by treating the main entry point as the @@ -355,7 +355,7 @@ module inside the subfolder. Any modules which are not public should be moved to another folder to retain the encapsulation benefits of exports. -#### Package Exports Fallbacks +#### Package exports fallbacks For possible new specifier support in future, array fallbacks are supported for all invalid specifiers: @@ -372,7 +372,7 @@ supported for all invalid specifiers: Since `"not:valid"` is not a valid specifier, `"./submodule.js"` is used instead as the fallback, as if it were the only target. -#### Exports Sugar +#### Exports sugar If the `"."` export is the only export, the `"exports"` field provides sugar for this case being the direct `"exports"` field value. @@ -398,7 +398,7 @@ can be written: } ``` -#### Conditional Exports +#### Conditional exports Conditional exports provide a way to map to different paths depending on certain conditions. They are supported for both CommonJS and ES module imports. @@ -536,7 +536,7 @@ and in a CommonJS one. For example, this code will also work: const { something } = require('a-package/foo'); // Loads from ./foo.js. ``` -### Dual CommonJS/ES Module Packages +### Dual CommonJS/ES module packages Prior to the introduction of support for ES modules in Node.js, it was a common pattern for package authors to include both CommonJS and ES module JavaScript @@ -549,12 +549,12 @@ ignores) the top-level `"module"` field. Node.js can now run ES module entry points, and a package can contain both CommonJS and ES module entry points (either via separate specifiers such as `'pkg'` and `'pkg/es-module'`, or both at the same specifier via [Conditional -Exports][]). Unlike in the scenario where `"module"` is only used by bundlers, +exports][]). Unlike in the scenario where `"module"` is only used by bundlers, or ES module files are transpiled into CommonJS on the fly before evaluation by Node.js, the files referenced by the ES module entry point are evaluated as ES modules. -#### Dual Package Hazard +#### Dual package hazard When an application is using a package that provides both CommonJS and ES module sources, there is a risk of certain bugs if both versions of the package get @@ -577,7 +577,7 @@ all-CommonJS or all-ES module environments, respectively, and therefore is surprising to users. It also differs from the behavior users are familiar with when using transpilation via tools like [Babel][] or [`esm`][]. -#### Writing Dual Packages While Avoiding or Minimizing Hazards +#### Writing dual packages while avoiding or minimizing hazards First, the hazard described in the previous section occurs when a package contains both CommonJS and ES module sources and both sources are provided for @@ -607,11 +607,11 @@ following conditions: browsers. 1. The hazards described in the previous section are avoided or minimized. -##### Approach #1: Use an ES Module Wrapper +##### Approach #1: Use an ES module wrapper Write the package in CommonJS or transpile ES module sources into CommonJS, and create an ES module wrapper file that defines the named exports. Using -[Conditional Exports][], the ES module wrapper is used for `import` and the +[Conditional exports][], the ES module wrapper is used for `import` and the CommonJS entry point for `require`. @@ -689,7 +689,7 @@ stateless): } ``` -##### Approach #2: Isolate State +##### Approach #2: Isolate state A `package.json` file can define the separate CommonJS and ES module entry points directly: @@ -859,7 +859,7 @@ property: * `url` {string} The absolute `file:` URL of the module. -## Differences Between ES Modules and CommonJS +## Differences between ES modules and CommonJS ### Mandatory file extensions @@ -955,7 +955,7 @@ To include an ES module into CommonJS, use [`import()`][]. ### `import` statements An `import` statement can reference an ES module or a CommonJS module. Other -file types such as JSON or Native modules are not supported. For those, use +file types such as JSON or native modules are not supported. For those, use [`module.createRequire()`][]. `import` statements are permitted only in ES modules. For similar functionality @@ -991,9 +991,9 @@ It is also possible to [Dynamic `import()`][] is supported in both CommonJS and ES modules. It can be used to include ES module files from CommonJS code. -## CommonJS, JSON, and Native Modules +## CommonJS, JSON, and native modules -CommonJS, JSON, and Native modules can be used with +CommonJS, JSON, and native modules can be used with [`module.createRequire()`][]. ```js @@ -1043,7 +1043,7 @@ syncBuiltinESMExports(); fs.readFileSync === readFileSync; ``` -## Experimental JSON Modules +## Experimental JSON modules Currently importing JSON modules are only supported in the `commonjs` mode and are loaded using the CJS loader. [WHATWG JSON modules specification][] are @@ -1073,7 +1073,7 @@ node index.mjs # fails node --experimental-json-modules index.mjs # works ``` -## Experimental Wasm Modules +## Experimental Wasm modules Importing Web Assembly modules is supported under the `--experimental-wasm-modules` flag, allowing any `.wasm` files to be @@ -1097,7 +1097,7 @@ node --experimental-wasm-modules index.mjs would provide the exports interface for the instantiation of `module.wasm`. -## Experimental Top-Level `await` +## Experimental top-level `await` When the `--experimental-top-level-await` flag is provided, `await` may be used in the top level (outside of async functions) within modules. This implements @@ -1123,7 +1123,7 @@ node b.mjs # fails node --experimental-top-level-await b.mjs # works ``` -## Experimental Loaders +## Experimental loaders **Note: This API is currently being redesigned and will still change.** @@ -1148,11 +1148,11 @@ and parent URL. The module specifier is the string in an `import` statement or this one, or `undefined` if this is the main entry point for the application. The `conditions` property on the `context` is an array of conditions for -[Conditional Exports][] that apply to this resolution request. They can be used +[Conditional exports][] that apply to this resolution request. They can be used for looking up conditional mappings elsewhere or to modify the list when calling the default resolution logic. -The [current set of Node.js default conditions][Conditional Exports] will always +The [current set of Node.js default conditions][Conditional exports] will always be in the `context.conditions` list passed to the hook. If the hook wants to ensure Node.js-compatible resolution logic, all items from this default condition list **must** be passed through to the `defaultResolve` function. @@ -1512,7 +1512,7 @@ loaded from disk but before Node.js executes it; and so on for any `.coffee`, `.litcoffee` or `.coffee.md` files referenced via `import` statements of any loaded file. -## Resolution Algorithm +## Resolution algorithm ### Features @@ -1525,7 +1525,7 @@ The resolver has the following properties: * No folder mains * Bare specifier package resolution lookup through node_modules -### Resolver Algorithm +### Resolver algorithm The algorithm to load an ES module specifier is given through the **ESM_RESOLVE** method below. It returns the resolved URL for a @@ -1797,7 +1797,7 @@ success! [Babel]: https://babeljs.io/ [CommonJS]: modules.html -[Conditional Exports]: #esm_conditional_exports +[Conditional exports]: #esm_conditional_exports [Dynamic `import()`]: https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports [ECMAScript-modules implementation]: https://github.com/nodejs/modules/blob/master/doc/plan-for-new-modules-implementation.md [ECMAScript Top-Level `await` proposal]: https://github.com/tc39/proposal-top-level-await/ diff --git a/doc/api/events.md b/doc/api/events.md index e5d8e41c049769..80e9ccf6fef27a 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -74,7 +74,7 @@ myEmitter.on('event', (a, b) => { myEmitter.emit('event', 'a', 'b'); ``` -## Asynchronous vs. Synchronous +## Asynchronous vs. synchronous The `EventEmitter` calls all listeners synchronously in the order in which they were registered. This ensures the proper sequencing of @@ -167,7 +167,7 @@ myEmitter.emit('error', new Error('whoops!')); // Still throws and crashes Node.js ``` -## Capture Rejections of Promises +## Capture rejections of promises > Stability: 1 - captureRejections is experimental. @@ -968,7 +968,7 @@ There are two key differences between the Node.js `EventTarget` and the 2. In the Node.js `EventTarget`, if an event listener is an async function or returns a `Promise`, and the returned `Promise` rejects, the rejection will be automatically captured and handled the same way as a listener that - throws synchronously (see [`EventTarget` Error Handling][] for details). + throws synchronously (see [`EventTarget` error handling][] for details). ### `NodeEventTarget` vs. `EventEmitter` @@ -990,7 +990,7 @@ and cannot be used in place of an `EventEmitter` in most cases. 3. The `NodeEventTarget` supports `EventListener` objects as well as functions as handlers for all event types. -### Event Listener +### Event listener Event listeners registered for an event `type` may either be JavaScript functions or objects with a `handleEvent` property whose value is a function. @@ -1000,7 +1000,7 @@ passed to the `eventTarget.dispatchEvent()` function. Async functions may be used as event listeners. If an async handler function rejects, the rejection will be captured and be will handled as described in -[`EventTarget` Error Handling][]. +[`EventTarget` error handling][]. An error thrown by one handler function will not prevent the other handlers from being invoked. @@ -1042,7 +1042,7 @@ target.addEventListener('foo', handler3); target.addEventListener('foo', handler4, { once: true }); ``` -### `EventTarget` Error Handling +### `EventTarget` error handling When a registered event listener throws (or returns a Promise that rejects), by default the error will be forwarded to the `process.on('error')` event @@ -1399,7 +1399,7 @@ to the `EventTarget`. [`emitter.removeListener()`]: #events_emitter_removelistener_eventname_listener [`emitter.setMaxListeners(n)`]: #events_emitter_setmaxlisteners_n [`Event` Web API]: https://dom.spec.whatwg.org/#event -[`EventTarget` Error Handling]: #events_eventtarget_error_handling +[`EventTarget` error handling]: #events_eventtarget_error_handling [`EventTarget` Web API]: https://dom.spec.whatwg.org/#eventtarget [`fs.ReadStream`]: fs.html#fs_class_fs_readstream [`net.Server`]: net.html#net_class_net_server diff --git a/doc/api/fs.md b/doc/api/fs.md index fe89d169cce0f9..317a1ca174ca0d 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -1,4 +1,4 @@ -# File System +# File system @@ -242,7 +242,7 @@ fs.readFileSync(new URL('file:///C:/path/%5c')); \ or / characters */ ``` -## File Descriptors +## File descriptors On POSIX systems, for every process, the kernel maintains a table of currently open files and resources. Each open file is assigned a simple numeric @@ -277,7 +277,7 @@ at any given time so it is critical to close the descriptor when operations are completed. Failure to do so will result in a memory leak that will eventually cause an application to crash. -## Threadpool Usage +## Threadpool usage All file system APIs except `fs.FSWatcher()` and those that are explicitly synchronous use libuv's threadpool, which can have surprising and negative @@ -1030,7 +1030,7 @@ added: v0.11.13 The timestamp indicating the creation time of this file. -### Stat Time Values +### Stat time values The `atimeMs`, `mtimeMs`, `ctimeMs`, `birthtimeMs` properties are numeric values that hold the corresponding times in milliseconds. Their @@ -1155,7 +1155,7 @@ changes: Tests a user's permissions for the file or directory specified by `path`. The `mode` argument is an optional integer that specifies the accessibility -checks to be performed. Check [File Access Constants][] for possible values +checks to be performed. Check [File access constants][] for possible values of `mode`. It is possible to create a mask consisting of the bitwise OR of two or more values (e.g. `fs.constants.W_OK | fs.constants.R_OK`). @@ -1297,7 +1297,7 @@ changes: Synchronously tests a user's permissions for the file or directory specified by `path`. The `mode` argument is an optional integer that specifies the -accessibility checks to be performed. Check [File Access Constants][] for +accessibility checks to be performed. Check [File access constants][] for possible values of `mode`. It is possible to create a mask consisting of the bitwise OR of two or more values (e.g. `fs.constants.W_OK | fs.constants.R_OK`). @@ -1623,7 +1623,7 @@ through any other `fs` operation may lead to undefined behavior. Returns an object containing commonly used constants for file system operations. The specific constants currently defined are described in -[FS Constants][]. +[FS constants][]. ## `fs.copyFile(src, dest[, mode], callback)` @@ -4290,7 +4290,7 @@ It is unsafe to use `fs.writeFile()` multiple times on the same file without waiting for the callback. For this scenario, [`fs.createWriteStream()`][] is recommended. -### Using `fs.writeFile()` with File Descriptors +### Using `fs.writeFile()` with file descriptors When `file` is a file descriptor, the behavior is almost identical to directly calling `fs.write()` like: @@ -4893,7 +4893,7 @@ added: v10.0.0 Tests a user's permissions for the file or directory specified by `path`. The `mode` argument is an optional integer that specifies the accessibility -checks to be performed. Check [File Access Constants][] for possible values +checks to be performed. Check [File access constants][] for possible values of `mode`. It is possible to create a mask consisting of the bitwise OR of two or more values (e.g. `fs.constants.W_OK | fs.constants.R_OK`). @@ -5480,7 +5480,7 @@ Any specified `FileHandle` has to support writing. It is unsafe to use `fsPromises.writeFile()` multiple times on the same file without waiting for the `Promise` to be resolved (or rejected). -## FS Constants +## FS constants The following constants are exported by `fs.constants`. @@ -5504,7 +5504,7 @@ fs.open('/path/to/my/file', O_RDWR | O_CREAT | O_EXCL, (err, fd) => { }); ``` -### File Access Constants +### File access constants The following constants are meant for use with [`fs.access()`][]. @@ -5536,7 +5536,7 @@ The following constants are meant for use with [`fs.access()`][]. -### File Copy Constants +### File copy constants The following constants are meant for use with [`fs.copyFile()`][]. @@ -5564,7 +5564,7 @@ The following constants are meant for use with [`fs.copyFile()`][]. -### File Open Constants +### File open constants The following constants are meant for use with `fs.open()`. @@ -5658,7 +5658,7 @@ The following constants are meant for use with `fs.open()`. -### File Type Constants +### File type constants The following constants are meant for use with the [`fs.Stats`][] object's `mode` property for determining a file's type. @@ -5702,7 +5702,7 @@ The following constants are meant for use with the [`fs.Stats`][] object's -### File Mode Constants +### File mode constants The following constants are meant for use with the [`fs.Stats`][] object's `mode` property for determining the access permissions for a file. @@ -5762,7 +5762,7 @@ The following constants are meant for use with the [`fs.Stats`][] object's -## File System Flags +## File system flags The following flags are available wherever the `flag` option takes a string. @@ -5910,8 +5910,8 @@ the file contents. [`util.promisify()`]: util.html#util_util_promisify_original [Caveats]: #fs_caveats [Common System Errors]: errors.html#errors_common_system_errors -[FS Constants]: #fs_fs_constants_1 -[File Access Constants]: #fs_file_access_constants +[FS constants]: #fs_fs_constants_1 +[File access constants]: #fs_file_access_constants [MDN-Date]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date [MDN-Number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type [MSDN-Rel-Path]: https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#fully-qualified-vs-relative-paths diff --git a/doc/api/globals.md b/doc/api/globals.md index 7e6129e9038aa2..4e2e362bcdeb5b 100644 --- a/doc/api/globals.md +++ b/doc/api/globals.md @@ -1,4 +1,4 @@ -# Global Objects +# Global objects diff --git a/doc/api/http2.md b/doc/api/http2.md index 956196dff22d13..67bb4c27e4d0b0 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -119,7 +119,7 @@ User code will not create `Http2Session` instances directly. Server-side new HTTP/2 connection is received. Client-side `Http2Session` instances are created using the `http2.connect()` method. -#### `Http2Session` and Sockets +#### `Http2Session` and sockets Every `Http2Session` instance is associated with exactly one [`net.Socket`][] or [`tls.TLSSocket`][] when it is created. When either the `Socket` or the @@ -2366,7 +2366,7 @@ client.close(); added: v8.4.0 --> -#### Error Codes for `RST_STREAM` and `GOAWAY` +#### Error codes for `RST_STREAM` and `GOAWAY` | Value | Name | Constant | @@ -2432,7 +2432,7 @@ added: v8.4.0 Returns a [HTTP/2 Settings Object][] containing the deserialized settings from the given `Buffer` as generated by `http2.getPackedSettings()`. -### Headers Object +### Headers object Headers are represented as own-properties on JavaScript objects. The property keys will be serialized to lower-case. Property values should be strings (if @@ -2480,7 +2480,7 @@ server.on('stream', (stream, headers) => { }); ``` -### Settings Object +### Settings object -* [About these Docs](documentation.html) -* [Usage & Example](synopsis.html) +* [About these docs](documentation.html) +* [Usage and example](synopsis.html)
-* [Assertion Testing](assert.html) -* [Async Hooks](async_hooks.html) +* [Assertion testing](assert.html) +* [Async hooks](async_hooks.html) * [Buffer](buffer.html) -* [C++ Addons](addons.html) -* [C/C++ Addons with N-API](n-api.html) -* [C++ Embedder API](embedding.html) -* [Child Processes](child_process.html) +* [C++ addons](addons.html) +* [C/C++ addons with N-API](n-api.html) +* [C++ embedder API](embedding.html) +* [Child processes](child_process.html) * [Cluster](cluster.html) -* [Command Line Options](cli.html) +* [Command line options](cli.html) * [Console](console.html) * [Crypto](crypto.html) * [Debugger](debugger.html) * [Deprecated APIs](deprecations.html) * [DNS](dns.html) * [Domain](domain.html) -* [ECMAScript Modules](esm.html) +* [ECMAScript modules](esm.html) * [Errors](errors.html) * [Events](events.html) -* [File System](fs.html) +* [File system](fs.html) * [Globals](globals.html) * [HTTP](http.html) * [HTTP/2](http2.html) @@ -39,27 +39,27 @@ * [Net](net.html) * [OS](os.html) * [Path](path.html) -* [Performance Hooks](perf_hooks.html) +* [Performance hooks](perf_hooks.html) * [Policies](policy.html) * [Process](process.html) * [Punycode](punycode.html) -* [Query Strings](querystring.html) +* [Query strings](querystring.html) * [Readline](readline.html) * [REPL](repl.html) * [Report](report.html) * [Stream](stream.html) -* [String Decoder](string_decoder.html) +* [String decoder](string_decoder.html) * [Timers](timers.html) * [TLS/SSL](tls.html) -* [Trace Events](tracing.html) +* [Trace events](tracing.html) * [TTY](tty.html) -* [UDP/Datagram](dgram.html) +* [UDP/datagram](dgram.html) * [URL](url.html) * [Utilities](util.html) * [V8](v8.html) * [VM](vm.html) * [WASI](wasi.html) -* [Worker Threads](worker_threads.html) +* [Worker threads](worker_threads.html) * [Zlib](zlib.html)
diff --git a/doc/api/inspector.md b/doc/api/inspector.md index ece84aa2c1f2a8..4f9501a5f861a7 100644 --- a/doc/api/inspector.md +++ b/doc/api/inspector.md @@ -188,7 +188,7 @@ to the run-time events. Apart from the debugger, various V8 Profilers are available through the DevTools protocol. -### CPU Profiler +### CPU profiler Here's an example showing how to use the [CPU Profiler][]: @@ -213,7 +213,7 @@ session.post('Profiler.enable', () => { }); ``` -### Heap Profiler +### Heap profiler Here's an example showing how to use the [Heap Profiler][]: diff --git a/doc/api/intl.md b/doc/api/intl.md index 25f7e61cd1808a..8b7dee489b4e9b 100644 --- a/doc/api/intl.md +++ b/doc/api/intl.md @@ -1,4 +1,4 @@ -# Internationalization Support +# Internationalization support diff --git a/doc/api/modules.md b/doc/api/modules.md index 0d23edcbe7e8fb..eccf4ed68d3e58 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -78,7 +78,7 @@ Because `module` provides a `filename` property (normally equivalent to `__filename`), the entry point of the current application can be obtained by checking `require.main.filename`. -## Addenda: Package Manager Tips +## Addenda: Package manager tips @@ -139,7 +139,7 @@ Attempting to do so will throw [an error][]. The `.mjs` extension is reserved for [ECMAScript Modules][] which cannot be loaded via `require()`. See [ECMAScript Modules][] for more details. -## All Together... +## All together... @@ -254,7 +254,7 @@ allowing transitive dependencies to be loaded even when they would cause cycles. To have a module execute code multiple times, export a function, and call that function. -### Module Caching Caveats +### Module caching caveats @@ -269,7 +269,7 @@ them as different modules and will reload the file multiple times. For example, `require('./foo')` and `require('./FOO')` return two different objects, irrespective of whether or not `./foo` and `./FOO` are the same file. -## Core Modules +## Core modules @@ -347,7 +347,7 @@ in main, a.done = true, b.done = true Careful planning is required to allow cyclic module dependencies to work correctly within an application. -## File Modules +## File modules @@ -373,7 +373,7 @@ either be a core module or is loaded from a `node_modules` folder. If the given path does not exist, `require()` will throw an [`Error`][] with its `code` property set to `'MODULE_NOT_FOUND'`. -## Folders as Modules +## Folders as modules @@ -413,7 +413,7 @@ with the default error: Error: Cannot find module 'some-library' ``` -## Loading from `node_modules` Folders +## Loading from `node_modules` folders @@ -737,7 +737,7 @@ Returns an array containing the paths searched during resolution of `request` or `null` if the `request` string references a core module, for example `http` or `fs`. -## The `module` Object +## The `module` object @@ -935,7 +935,7 @@ Since `require()` returns the `module.exports`, and the `module` is typically *only* available within a specific module's code, it must be explicitly exported in order to be used. -## The `Module` Object +## The `Module` object @@ -1083,7 +1083,7 @@ added: v13.7.0 Creates a new `sourceMap` instance. -`payload` is an object with keys matching the [Source Map V3 format][]: +`payload` is an object with keys matching the [Source map v3 format][]: * `file`: {string} * `version`: {number} @@ -1134,4 +1134,4 @@ consists of the following keys: [`NODE_V8_COVERAGE=dir`]: cli.html#cli_node_v8_coverage_dir [`Error.prepareStackTrace(error, trace)`]: https://v8.dev/docs/stack-trace-api#customizing-stack-traces [`SourceMap`]: modules.html#modules_class_module_sourcemap -[Source Map V3 format]: https://sourcemaps.info/spec.html#h.mofvlxcwqzej +[Source map v3 format]: https://sourcemaps.info/spec.html#h.mofvlxcwqzej diff --git a/doc/api/n-api.md b/doc/api/n-api.md index e375616d23dd90..902cb883aeec92 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -31,7 +31,7 @@ properties: `napi_value`. * In case of an error status code, additional information can be obtained using `napi_get_last_error_info`. More information can be found in the error - handling section [Error Handling][]. + handling section [Error handling][]. The N-API is a C API that ensures ABI stability across Node.js versions and different compiler levels. A C++ API can be easier to use. @@ -78,7 +78,7 @@ it still gets the benefits of the ABI stability provided by the C API. When using `node-addon-api` instead of the C APIs, start with the API [docs][] for `node-addon-api`. -## Implications of ABI Stability +## Implications of ABI stability Although N-API provides an ABI stability guarantee, other parts of Node.js do not, and any external libraries used from the addon may not. In particular, @@ -196,7 +196,7 @@ GitHub projects using CMake.js. #### prebuildify -[prebuildify][] is tool based on node-gyp. The advantage of prebuildify is +[prebuildify][] is a tool based on node-gyp. The advantage of prebuildify is that the built binaries are bundled with the native module when it's uploaded to npm. The binaries are downloaded from npm and are immediately available to the module user when the native module is installed. @@ -233,7 +233,7 @@ opt-in to access those APIs: In this case the entire API surface, including any experimental APIs, will be available to the module code. -## N-API Version Matrix +## N-API version matrix N-API versions are additive and versioned independently from Node.js. Version 4 is an extension to version 3 in that it has all of the APIs @@ -343,7 +343,7 @@ NAPI_MODULE_INIT() { } ``` -## Environment Life Cycle APIs +## Environment life cycle APIs > Stability: 1 - Experimental @@ -425,7 +425,7 @@ This API retrieves data that was previously associated with the currently running Agent via `napi_set_instance_data()`. If no data is set, the call will succeed and `data` will be set to `NULL`. -## Basic N-API Data Types +## Basic N-API data types N-API exposes the following fundamental datatypes as abstractions that are consumed by the various APIs. These APIs should be treated as opaque, @@ -492,7 +492,7 @@ typedef struct { not implemented for any VM. * `error_code`: The N-API status code that originated with the last error. -See the [Error Handling][] section for additional information. +See the [Error handling][] section for additional information. ### napi_env @@ -557,7 +557,7 @@ typedef enum { } napi_threadsafe_function_call_mode; ``` -### N-API Memory Management types +### N-API memory management types #### napi_handle_scope This is an abstraction used to control and modify the lifetime of objects @@ -575,7 +575,7 @@ using [`napi_close_handle_scope`][]. Closing the scope can indicate to the GC that all `napi_value`s created during the lifetime of the handle scope are no longer referenced from the current stack frame. -For more details, review the [Object Lifetime Management][]. +For more details, review the [Object lifetime management][]. #### napi_escapable_handle_scope @@ -1252,7 +1252,7 @@ The following process scheduling constants are exported by -### libuv Constants +### libuv constants diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md index 20f0cc0c4bb89b..8d540491604846 100644 --- a/doc/api/perf_hooks.md +++ b/doc/api/perf_hooks.md @@ -1,4 +1,4 @@ -# Performance Measurement APIs +# Performance measurement APIs diff --git a/doc/api/policy.md b/doc/api/policy.md index e7ccbaa9db08e6..05918500fcac21 100644 --- a/doc/api/policy.md +++ b/doc/api/policy.md @@ -49,7 +49,7 @@ node --experimental-policy=policy.json --policy-integrity="sha384-SggXRQHwCG8g+D ## Features -### Error Behavior +### Error behavior When a policy check fails, Node.js by default will throw an error. It is possible to change the error behavior to one of a few possibilities @@ -73,7 +73,7 @@ available to change the behavior: } ``` -### Integrity Checks +### Integrity checks Policy files must use integrity checks with Subresource Integrity strings compatible with the browser @@ -115,7 +115,7 @@ body for the resource which can be useful for local development. It is not recommended in production since it would allow unexpected alteration of resources to be considered valid. -### Dependency Redirection +### Dependency redirection An application may need to ship patched versions of modules or to prevent modules from allowing all modules access to all other modules. Redirection @@ -164,7 +164,7 @@ module to load any specifier without redirection. This can be useful for local development and may have some valid usage in production, but should be used only with care after auditing a module to ensure its behavior is valid. -#### Example: Patched Dependency +#### Example: Patched dependency Redirected dependencies can provide attenuated or modified functionality as fits the application. For example, log data about timing of function durations by diff --git a/doc/api/process.md b/doc/api/process.md index 820b95f4d66bf5..eda3ac16f7a984 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -12,7 +12,7 @@ accessed using `require()`: const process = require('process'); ``` -## Process Events +## Process events The `process` object is an instance of [`EventEmitter`][]. @@ -122,7 +122,7 @@ not be the same as what is originally sent. If the `serialization` option was set to `advanced` used when spawning the process, the `message` argument can contain data that JSON is not able to represent. -See [Advanced Serialization for `child_process`][] for more details. +See [Advanced serialization for `child_process`][] for more details. ### Event: `'multipleResolves'` @@ -2533,7 +2533,7 @@ Will generate an object similar to: unicode: '11.0' } ``` -## Exit Codes +## Exit codes Node.js will normally exit with a `0` status code when no more async operations are pending. The following status codes are used in other @@ -2614,7 +2614,7 @@ cases: [`require.resolve()`]: modules.html#modules_require_resolve_request_options [`subprocess.kill()`]: child_process.html#child_process_subprocess_kill_signal [`v8.setFlagsFromString()`]: v8.html#v8_v8_setflagsfromstring_flags -[Advanced Serialization for `child_process`]: child_process.html#child_process_advanced_serialization +[Advanced serialization for `child_process`]: child_process.html#child_process_advanced_serialization [Android building]: https://github.com/nodejs/node/blob/master/BUILDING.md#androidandroid-based-devices-eg-firefox-os [Child Process]: child_process.html [Cluster]: cluster.html diff --git a/doc/api/querystring.md b/doc/api/querystring.md index c7fafd23d955b8..0797e3ee220d53 100644 --- a/doc/api/querystring.md +++ b/doc/api/querystring.md @@ -1,4 +1,4 @@ -# Query String +# Query string diff --git a/doc/api/readline.md b/doc/api/readline.md index d70a49304ce64d..a737e4bd24d34c 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -536,7 +536,7 @@ the best compatibility if it defines an `output.columns` property and emits a `'resize'` event on the `output` if or when the columns ever change ([`process.stdout`][] does this automatically when it is a TTY). -### Use of the `completer` Function +### Use of the `completer` function The `completer` function takes the current line entered by the user as an argument, and returns an `Array` with 2 entries: @@ -661,7 +661,7 @@ rl.on('line', (line) => { }); ``` -## Example: Read File Stream Line-by-Line +## Example: Read file stream line-by-Line A common use case for `readline` is to consume an input file one line at a time. The easiest way to do so is leveraging the [`fs.ReadStream`][] API as diff --git a/doc/api/repl.md b/doc/api/repl.md index 42926ca0f1cf2d..4940001a4ebfd2 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -12,7 +12,7 @@ It can be accessed using: const repl = require('repl'); ``` -## Design and Features +## Design and features The `repl` module exports the [`repl.REPLServer`][] class. While running, instances of [`repl.REPLServer`][] will accept individual lines of user input, @@ -28,7 +28,7 @@ recovery, and customizable evaluation functions. Terminals that do not support ANSI styles and Emacs-style line editing automatically fall back to a limited feature set. -### Commands and Special Keys +### Commands and special keys The following special commands are supported by all REPL instances: @@ -72,14 +72,14 @@ The following key combinations in the REPL have these special effects: For key bindings related to the reverse-i-search, see [`reverse-i-search`][]. For all other key bindings, see [TTY keybindings][]. -### Default Evaluation +### Default evaluation By default, all instances of [`repl.REPLServer`][] use an evaluation function that evaluates JavaScript expressions and provides access to Node.js built-in modules. This default behavior can be overridden by passing in an alternative evaluation function when the [`repl.REPLServer`][] instance is created. -#### JavaScript Expressions +#### JavaScript expressions The default evaluator supports direct evaluation of JavaScript expressions: @@ -96,7 +96,7 @@ Unless otherwise scoped within blocks or functions, variables declared either implicitly or using the `const`, `let`, or `var` keywords are declared at the global scope. -#### Global and Local Scope +#### Global and local scope The default evaluator provides access to any variables that exist in the global scope. It is possible to expose a variable to the REPL explicitly by assigning @@ -132,7 +132,7 @@ Object.defineProperty(r.context, 'm', { }); ``` -#### Accessing Core Node.js Modules +#### Accessing core Node.js modules The default evaluator will automatically load Node.js core modules into the REPL environment when used. For instance, unless otherwise declared as a @@ -143,7 +143,7 @@ global or scoped variable, the input `fs` will be evaluated on-demand as > fs.createReadStream('./some/file'); ``` -#### Global Uncaught Exceptions +#### Global uncaught exceptions @@ -577,7 +577,7 @@ NODE_OPTIONS="--report-uncaught-exception \ Specific API documentation can be found under [`process API documentation`][] section. -## Interaction with Workers +## Interaction with workers @@ -120,8 +120,8 @@ that implements an HTTP server: const http = require('http'); const server = http.createServer((req, res) => { - // `req` is an http.IncomingMessage, which is a Readable Stream. - // `res` is an http.ServerResponse, which is a Writable Stream. + // `req` is an http.IncomingMessage, which is a readable stream. + // `res` is an http.ServerResponse, which is a writable stream. let body = ''; // Get the data as utf8 strings. @@ -176,9 +176,9 @@ are not required to implement the stream interfaces directly and will generally have no reason to call `require('stream')`. Developers wishing to implement new types of streams should refer to the -section [API for Stream Implementers][]. +section [API for stream implementers][]. -### Writable Streams +### Writable streams Writable streams are an abstraction for a *destination* to which data is written. @@ -649,7 +649,7 @@ write('hello', () => { A `Writable` stream in object mode will always ignore the `encoding` argument. -### Readable Streams +### Readable streams Readable streams are an abstraction for a *source* from which data is consumed. @@ -668,7 +668,7 @@ Examples of `Readable` streams include: All [`Readable`][] streams implement the interface defined by the `stream.Readable` class. -#### Two Reading Modes +#### Two reading modes `Readable` streams effectively operate in one of two modes: flowing and paused. These modes are separate from [object mode][object-mode]. @@ -719,7 +719,7 @@ stop flowing, and the data to be consumed via removed, then the stream will start flowing again if there is a [`'data'`][] event handler. -#### Three States +#### Three states The "two modes" of operation for a `Readable` stream are a simplified abstraction for the more complicated internal state management that is happening @@ -762,7 +762,7 @@ pass.resume(); // Must be called to make stream emit 'data'. While `readable.readableFlowing` is `false`, data may be accumulating within the stream's internal buffer. -#### Choose One API Style +#### Choose one API style The `Readable` stream API evolved across multiple Node.js versions and provides multiple methods of consuming stream data. In general, developers should choose @@ -1184,7 +1184,7 @@ added: v9.4.0 * {boolean} This property reflects the current state of a `Readable` stream as described -in the [Stream Three States][] section. +in the [Three states][] section. ##### `readable.readableHighWaterMark` @@ -1777,7 +1777,7 @@ on the type of stream being created, as detailed in the chart below: The implementation code for a stream should *never* call the "public" methods of a stream that are intended for use by consumers (as described in the -[API for Stream Consumers][] section). Doing so may lead to adverse side effects +[API for stream consumers][] section). Doing so may lead to adverse side effects in application code consuming the stream. Avoid overriding public methods such as `write()`, `end()`, `cork()`, @@ -1787,7 +1787,7 @@ Doing so can break current and future stream invariants leading to behavior and/or compatibility issues with other streams, stream utilities, and user expectations. -### Simplified Construction +### Simplified construction @@ -1807,7 +1807,7 @@ const myWritable = new Writable({ }); ``` -### Implementing a Writable Stream +### Implementing a writable stream The `stream.Writable` class is extended to implement a [`Writable`][] stream. @@ -1891,7 +1891,7 @@ function MyWritable(options) { util.inherits(MyWritable, Writable); ``` -Or, using the Simplified Constructor approach: +Or, using the simplified constructor approach: ```js const { Writable } = require('stream'); @@ -2008,7 +2008,7 @@ This optional function will be called before the stream closes, delaying the `'finish'` event until `callback` is called. This is useful to close resources or write buffered data before a stream ends. -#### Errors While Writing +#### Errors while writing Errors occurring during the processing of the [`writable._write()`][], [`writable._writev()`][] and [`writable._final()`][] methods must be propagated @@ -2033,7 +2033,7 @@ const myWritable = new Writable({ }); ``` -#### An Example Writable Stream +#### An example writable stream The following illustrates a rather simplistic (and somewhat pointless) custom `Writable` stream implementation. While this specific `Writable` stream instance @@ -2054,7 +2054,7 @@ class MyWritable extends Writable { } ``` -#### Decoding buffers in a Writable Stream +#### Decoding buffers in a writable stream Decoding buffers is a common task, for instance, when using transformers whose input is a string. This is not a trivial process when using multi-byte @@ -2094,7 +2094,7 @@ w.end(euro[1]); console.log(w.data); // currency: € ``` -### Implementing a Readable Stream +### Implementing a readable stream The `stream.Readable` class is extended to implement a [`Readable`][] stream. @@ -2160,7 +2160,7 @@ function MyReadable(options) { util.inherits(MyReadable, Readable); ``` -Or, using the Simplified Constructor approach: +Or, using the simplified constructor approach: ```js const { Readable } = require('stream'); @@ -2293,7 +2293,7 @@ For streams not operating in object mode, if the `chunk` parameter of `readable.push()` is `undefined`, it will be treated as empty string or buffer. See [`readable.push('')`][] for more information. -#### Errors While Reading +#### Errors while reading Errors occurring during processing of the [`readable._read()`][] must be propagated through the [`readable.destroy(err)`][readable-_destroy] method. @@ -2315,7 +2315,7 @@ const myReadable = new Readable({ }); ``` -#### An Example Counting Stream +#### An example counting stream @@ -2345,7 +2345,7 @@ class Counter extends Readable { } ``` -### Implementing a Duplex Stream +### Implementing a duplex stream A [`Duplex`][] stream is one that implements both [`Readable`][] and [`Writable`][], such as a TCP socket connection. @@ -2412,7 +2412,7 @@ function MyDuplex(options) { util.inherits(MyDuplex, Duplex); ``` -Or, using the Simplified Constructor approach: +Or, using the simplified constructor approach: ```js const { Duplex } = require('stream'); @@ -2427,7 +2427,7 @@ const myDuplex = new Duplex({ }); ``` -#### An Example Duplex Stream +#### An example duplex stream The following illustrates a simple example of a `Duplex` stream that wraps a hypothetical lower-level source object to which data can be written, and @@ -2467,7 +2467,7 @@ The most important aspect of a `Duplex` stream is that the `Readable` and `Writable` sides operate independently of one another despite co-existing within a single object instance. -#### Object Mode Duplex Streams +#### Object mode duplex streams For `Duplex` streams, `objectMode` can be set exclusively for either the `Readable` or `Writable` side using the `readableObjectMode` and @@ -2508,7 +2508,7 @@ myTransform.write(100); // Prints: 64 ``` -### Implementing a Transform Stream +### Implementing a transform stream A [`Transform`][] stream is a [`Duplex`][] stream where the output is computed in some way from the input. Examples include [zlib][] streams or [crypto][] @@ -2567,7 +2567,7 @@ function MyTransform(options) { util.inherits(MyTransform, Transform); ``` -Or, using the Simplified Constructor approach: +Or, using the simplified constructor approach: ```js const { Transform } = require('stream'); @@ -2682,11 +2682,11 @@ stream that simply passes the input bytes across to the output. Its purpose is primarily for examples and testing, but there are some use cases where `stream.PassThrough` is useful as a building block for novel sorts of streams. -## Additional Notes +## Additional notes -### Streams Compatibility with Async Generators and Async Iterators +### Streams compatibility with async generators and async iterators With the support of async generators and iterators in JavaScript, async generators are effectively a first-class language-level stream construct at @@ -2695,7 +2695,7 @@ this point. Some common interop cases of using Node.js streams with async generators and async iterators are provided below. -#### Consuming Readable Streams with Async Iterators +#### Consuming readable streams with async iterators ```js (async function() { @@ -2708,9 +2708,9 @@ and async iterators are provided below. Async iterators register a permanent error handler on the stream to prevent any unhandled post-destroy errors. -#### Creating Readable Streams with Async Generators +#### Creating readable streams with async generators -We can construct a Node.js Readable Stream from an asynchronous generator +We can construct a Node.js readable stream from an asynchronous generator using the `Readable.from()` utility method: ```js @@ -2729,7 +2729,7 @@ readable.on('data', (chunk) => { }); ``` -#### Piping to Writable Streams from Async Iterators +#### Piping to writable streams from async iterators When writing to a writable stream from an async iterator, ensure correct handling of backpressure and errors. [`stream.pipeline()`][] abstracts away @@ -2762,7 +2762,7 @@ pipelinePromise(iterator, writable) -### Compatibility with Older Node.js Versions +### Compatibility with older Node.js versions @@ -2903,8 +2903,8 @@ contain multi-byte characters. [`writable.uncork()`]: #stream_writable_uncork [`writable.writableFinished`]: #stream_writable_writablefinished [`zlib.createDeflate()`]: zlib.html#zlib_zlib_createdeflate_options -[API for Stream Consumers]: #stream_api_for_stream_consumers -[API for Stream Implementers]: #stream_api_for_stream_implementers +[API for stream consumers]: #stream_api_for_stream_consumers +[API for stream implementers]: #stream_api_for_stream_implementers [Compatibility]: #stream_compatibility_with_older_node_js_versions [HTTP requests, on the client]: http.html#http_class_http_clientrequest [HTTP responses, on the server]: http.html#http_class_http_serverresponse @@ -2932,7 +2932,7 @@ contain multi-byte characters. [stream-resume]: #stream_readable_resume [stream-uncork]: #stream_writable_uncork [stream-write]: #stream_writable_write_chunk_encoding_callback -[Stream Three States]: #stream_three_states +[Three states]: #stream_three_states [writable-_destroy]: #stream_writable_destroy_err_callback [writable-destroy]: #stream_writable_destroy_error [writable-new]: #stream_new_stream_writable_options diff --git a/doc/api/string_decoder.md b/doc/api/string_decoder.md index 54fcc876c9a9e9..5cd6121d50ddb9 100644 --- a/doc/api/string_decoder.md +++ b/doc/api/string_decoder.md @@ -1,4 +1,4 @@ -# String Decoder +# String decoder diff --git a/doc/api/synopsis.md b/doc/api/synopsis.md index c296ffb0fa43c7..8ae933a499a16c 100644 --- a/doc/api/synopsis.md +++ b/doc/api/synopsis.md @@ -1,4 +1,4 @@ -# Usage & Example +# Usage and example ## Usage diff --git a/doc/api/timers.md b/doc/api/timers.md index a312022791f54b..8b080b16ffb70e 100644 --- a/doc/api/timers.md +++ b/doc/api/timers.md @@ -123,7 +123,7 @@ Calling `timeout.unref()` creates an internal timer that will wake the Node.js event loop. Creating too many of these can adversely impact performance of the Node.js application. -## Scheduling Timers +## Scheduling timers A timer in Node.js is an internal construct that calls a given function after a certain period of time. When a timer's function is called varies depending on @@ -226,7 +226,7 @@ setTimeoutPromise(40, 'foobar').then((value) => { }); ``` -## Cancelling Timers +## Cancelling timers The [`setImmediate()`][], [`setInterval()`][], and [`setTimeout()`][] methods each return objects that represent the scheduled timers. These can be used to diff --git a/doc/api/tls.md b/doc/api/tls.md index 4b49260e2663df..71c127ca6cc346 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -12,7 +12,7 @@ The module can be accessed using: const tls = require('tls'); ``` -## TLS/SSL Concepts +## TLS/SSL concepts The TLS/SSL is a public/private key infrastructure (PKI). For most common cases, each client and server must have a *private key*. @@ -64,11 +64,11 @@ Where: * `certfile`: is a concatenation of all Certificate Authority (CA) certs into a single file, e.g. `cat ca1-cert.pem ca2-cert.pem > ca-cert.pem` -### Perfect Forward Secrecy +### Perfect forward secrecy -The term "[Forward Secrecy][]" or "Perfect Forward Secrecy" describes a feature +The term _[forward secrecy][]_ or _perfect forward secrecy_ describes a feature of key-agreement (i.e., key-exchange) methods. That is, the server and client keys are used to negotiate new temporary keys that are used specifically and only for the current communication session. Practically, this means that even @@ -76,11 +76,11 @@ if the server's private key is compromised, communication can only be decrypted by eavesdroppers if the attacker manages to obtain the key-pair specifically generated for the session. -Perfect Forward Secrecy is achieved by randomly generating a key pair for +Perfect forward secrecy is achieved by randomly generating a key pair for key-agreement on every TLS/SSL handshake (in contrast to using the same key for all sessions). Methods implementing this technique are called "ephemeral". -Currently two methods are commonly used to achieve Perfect Forward Secrecy (note +Currently two methods are commonly used to achieve perfect forward secrecy (note the character "E" appended to the traditional abbreviations): * [DHE][]: An ephemeral version of the Diffie Hellman key-agreement protocol. @@ -90,7 +90,7 @@ the character "E" appended to the traditional abbreviations): Ephemeral methods may have some performance drawbacks, because key generation is expensive. -To use Perfect Forward Secrecy using `DHE` with the `tls` module, it is required +To use perfect forward secrecy using `DHE` with the `tls` module, it is required to generate Diffie-Hellman parameters and specify them with the `dhparam` option to [`tls.createSecureContext()`][]. The following illustrates the use of the OpenSSL command-line interface to generate such parameters: @@ -99,12 +99,12 @@ the OpenSSL command-line interface to generate such parameters: openssl dhparam -outform PEM -out dhparam.pem 2048 ``` -If using Perfect Forward Secrecy using `ECDHE`, Diffie-Hellman parameters are +If using perfect forward secrecy using `ECDHE`, Diffie-Hellman parameters are not required and a default ECDHE curve will be used. The `ecdhCurve` property can be used when creating a TLS Server to specify the list of names of supported curves to use, see [`tls.createServer()`][] for more info. -Perfect Forward Secrecy was optional up to TLSv1.2, but it is not optional for +Perfect forward secrecy was optional up to TLSv1.2, but it is not optional for TLSv1.3, because all TLSv1.3 cipher suites use ECDHE. ### ALPN and SNI @@ -175,13 +175,15 @@ understanding of the implications and risks. TLSv1.3 does not support renegotiation. -### Session Resumption +### Session resumption Establishing a TLS session can be relatively slow. The process can be sped up by saving and later reusing the session state. There are several mechanisms to do so, discussed here from oldest to newest (and preferred). -***Session Identifiers*** Servers generate a unique ID for new connections and +#### Session identifiers + +Servers generate a unique ID for new connections and send it to the client. Clients and servers save the session state. When reconnecting, clients send the ID of their saved session state and if the server also has the state for that ID, it can agree to use it. Otherwise, the server @@ -200,7 +202,9 @@ reuse sessions. To reuse sessions across load balancers or cluster workers, servers must use a shared session cache (such as Redis) in their session handlers. -***Session Tickets*** The servers encrypt the entire session state and send it +#### Session tickets + +The servers encrypt the entire session state and send it to the client as a "ticket". When reconnecting, the state is sent to the server in the initial connection. This mechanism avoids the need for server-side session cache. If the server doesn't use the ticket, for any reason (failure @@ -267,7 +271,7 @@ Subsequent connections should say "Reused", for example: Reused, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256 ``` -## Modifying the Default TLS Cipher suite +## Modifying the default TLS cipher suite Node.js is built with a default suite of enabled and disabled TLS ciphers. This default cipher list can be configured when building Node.js to allow @@ -340,8 +344,8 @@ of an application. The `--tls-cipher-list` switch and `ciphers` option should by used only if absolutely necessary. The default cipher suite prefers GCM ciphers for [Chrome's 'modern -cryptography' setting][] and also prefers ECDHE and DHE ciphers for Perfect -Forward Secrecy, while offering *some* backward compatibility. +cryptography' setting][] and also prefers ECDHE and DHE ciphers for perfect +forward secrecy, while offering *some* backward compatibility. 128 bit AES is preferred over 192 and 256 bit AES in light of [specific attacks affecting larger AES key sizes][]. @@ -904,7 +908,7 @@ added: v5.0.0 * Returns: {Object} Returns an object representing the type, name, and size of parameter of -an ephemeral key exchange in [Perfect Forward Secrecy][] on a client +an ephemeral key exchange in [perfect forward secrecy][] on a client connection. It returns an empty object when the key exchange is not ephemeral. As this is only supported on a client socket; `null` is returned if called on a server socket. The supported types are `'DH'` and `'ECDH'`. The @@ -946,7 +950,7 @@ If the full certificate chain was requested, each certificate will include an `issuerCertificate` property containing an object representing its issuer's certificate. -#### Certificate Object +#### Certificate object > Stability: 1 - Experimental -Trace Event provides a mechanism to centralize tracing information generated by -V8, Node.js core, and userspace code. +The `trace_events` module provides a mechanism to centralize tracing information +generated by V8, Node.js core, and userspace code. Tracing can be enabled with the `--trace-event-categories` command-line flag or by using the `trace_events` module. The `--trace-event-categories` flag diff --git a/doc/api/url.md b/doc/api/url.md index dfe312bef805c8..fbe8aa397918ba 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -11,7 +11,7 @@ accessed using: const url = require('url'); ``` -## URL Strings and URL Objects +## URL strings and URL objects A URL string is a structured string containing multiple meaningful components. When parsed, a URL object is returned containing properties for each of these @@ -406,7 +406,7 @@ console.log(myURL.href); Invalid URL protocol values assigned to the `protocol` property are ignored. -##### Special Schemes +##### Special schemes The [WHATWG URL Standard][] considers a handful of URL protocol schemes to be _special_ in terms of how they are parsed and serialized. When a URL is @@ -1276,7 +1276,7 @@ url.resolve('http://example.com/one', '/two'); // 'http://example.com/two' ``` -## Percent-Encoding in URLs +## Percent-encoding in URLs URLs are permitted to only contain a certain range of characters. Any character falling outside of that range must be encoded. How such characters are encoded, diff --git a/doc/api/util.md b/doc/api/util.md index bc57d8ee06130f..269210c1a38f07 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -756,7 +756,7 @@ ignored, if not supported. * `bgCyanBright` * `bgWhiteBright` -### Custom inspection functions on Objects +### Custom inspection functions on objects @@ -1047,7 +1047,7 @@ while (buffer = getNextChunkSomehow()) { string += decoder.decode(); // end-of-stream ``` -### WHATWG Supported Encodings +### WHATWG supported encodings Per the [WHATWG Encoding Standard][], the encodings supported by the `TextDecoder` API are outlined in the tables below. For each encoding, @@ -1056,7 +1056,7 @@ one or more aliases may be used. Different Node.js build configurations support different sets of encodings. (see [Internationalization][]) -#### Encodings Supported by Default (With Full ICU Data) +#### Encodings supported by default (with full ICU data) | Encoding | Aliases | | ----------------- | -------------------------------- | @@ -1095,7 +1095,7 @@ Different Node.js build configurations support different sets of encodings. | `'shift_jis'` | `'csshiftjis'`, `'ms932'`, `'ms_kanji'`, `'shift-jis'`, `'sjis'`, `'windows-31j'`, `'x-sjis'` | | `'euc-kr'` | `'cseuckr'`, `'csksc56011987'`, `'iso-ir-149'`, `'korean'`, `'ks_c_5601-1987'`, `'ks_c_5601-1989'`, `'ksc5601'`, `'ksc_5601'`, `'windows-949'` | -#### Encodings Supported when Node.js is built with the `small-icu` option +#### Encodings supported when Node.js is built with the `small-icu` option | Encoding | Aliases | | ----------- | --------------------------------- | @@ -1103,7 +1103,7 @@ Different Node.js build configurations support different sets of encodings. | `'utf-16le'` | `'utf-16'` | | `'utf-16be'` | | -#### Encodings Supported when ICU is disabled +#### Encodings supported when ICU is disabled | Encoding | Aliases | | ----------- | --------------------------------- | @@ -2427,7 +2427,7 @@ util.log('Timestamped message.'); [`util.types.isNativeError()`]: #util_util_types_isnativeerror_value [`util.types.isSharedArrayBuffer()`]: #util_util_types_issharedarraybuffer_value [Common System Errors]: errors.html#errors_common_system_errors -[Custom inspection functions on Objects]: #util_custom_inspection_functions_on_objects +[Custom inspection functions on objects]: #util_custom_inspection_functions_on_objects [Custom promisified functions]: #util_custom_promisified_functions [Customizing `util.inspect` colors]: #util_customizing_util_inspect_colors [Internationalization]: intl.html diff --git a/doc/api/v8.md b/doc/api/v8.md index ec6a6ea9a0508f..531612330f061b 100644 --- a/doc/api/v8.md +++ b/doc/api/v8.md @@ -231,7 +231,7 @@ DevTools. The JSON schema is undocumented and specific to the V8 engine, and may change from one version of V8 to the next. A heap snapshot is specific to a single V8 isolate. When using -[Worker Threads][], a heap snapshot generated from the main thread will +[worker threads][], a heap snapshot generated from the main thread will not contain any information about the workers, and vice versa. ```js @@ -519,4 +519,4 @@ A subclass of [`Deserializer`][] corresponding to the format written by [`vm.Script`]: vm.html#vm_new_vm_script_code_options [HTML structured clone algorithm]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm [V8]: https://developers.google.com/v8/ -[Worker Threads]: worker_threads.html +[worker threads]: worker_threads.html diff --git a/doc/api/vm.md b/doc/api/vm.md index 7d16b48b04afc2..7ef5ff622795ca 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -1,4 +1,4 @@ -# VM (Executing JavaScript) +# VM (executing JavaScript) @@ -1168,7 +1168,7 @@ local scope, so the value `localVar` is changed. In this way `vm.runInThisContext()` is much like an [indirect `eval()` call][], e.g. `(0,eval)('code')`. -## Example: Running an HTTP Server within a VM +## Example: Running an HTTP server within a VM When using either [`script.runInThisContext()`][] or [`vm.runInThisContext()`][], the code is executed within the current V8 global @@ -1218,7 +1218,7 @@ within which it can operate. The process of creating the V8 Context and associating it with the `contextObject` is what this document refers to as "contextifying" the object. -## Timeout limitations when using `process.nextTick()`, Promises, and `queueMicrotask()` +## Timeout limitations when using `process.nextTick()`, promises, and `queueMicrotask()` Because of the internal mechanics of how the `process.nextTick()` queue and the microtask queue that underlies Promises are implemented within V8 and diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md index 33d9aa0eb413ed..45b9a5f0fd2323 100644 --- a/doc/api/worker_threads.md +++ b/doc/api/worker_threads.md @@ -1,4 +1,4 @@ -# Worker Threads +# Worker threads diff --git a/doc/api/zlib.md b/doc/api/zlib.md index 439b9d85e05c57..d50792664840c4 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -93,7 +93,7 @@ do_unzip(buffer) }); ``` -## Threadpool Usage and Performance Considerations +## Threadpool usage and performance considerations All `zlib` APIs, except those that are explicitly synchronous, use the Node.js internal threadpool. This can lead to surprising effects and performance @@ -133,7 +133,7 @@ message. The examples given below are drastically simplified to show the basic concept. Using `zlib` encoding can be expensive, and the results ought to be cached. -See [Memory Usage Tuning][] for more information on the speed/memory/compression +See [Memory usage tuning][] for more information on the speed/memory/compression tradeoffs involved in `zlib` usage. ```js @@ -252,7 +252,7 @@ possible to determine whether the input ended prematurely or lacks the integrity checks, making it necessary to manually check that the decompressed result is valid. -## Memory Usage Tuning +## Memory usage tuning @@ -837,7 +837,7 @@ added: v0.5.8 Creates and returns a new [`Unzip`][] object. -## Convenience Methods +## Convenience methods @@ -1186,7 +1186,7 @@ Decompress a chunk of data with [`Unzip`][]. [`stream.Transform`]: stream.html#stream_class_stream_transform [`zlib.bytesWritten`]: #zlib_zlib_byteswritten [Brotli parameters]: #zlib_brotli_constants -[Memory Usage Tuning]: #zlib_memory_usage_tuning +[Memory usage tuning]: #zlib_memory_usage_tuning [RFC 7932]: https://www.rfc-editor.org/rfc/rfc7932.txt [Streams API]: stream.md [convenience methods]: #zlib_convenience_methods From e0206bafe648e5ec56ca017b0861ff7cd0c47ee6 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 2 Jun 2020 00:42:46 +0200 Subject: [PATCH 002/138] util: restrict custom inspect function + vm.Context interaction When `util.inspect()` is called on an object with a custom inspect function, and that object is from a different `vm.Context`, that function will not receive any arguments that access context-specific data anymore. PR-URL: https://github.com/nodejs/node/pull/33690 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig --- doc/api/util.md | 7 +++ lib/internal/util/inspect.js | 39 ++++++++++++-- test/parallel/test-util-inspect.js | 83 ++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 3 deletions(-) diff --git a/doc/api/util.md b/doc/api/util.md index 269210c1a38f07..7b3d08e0a0bcab 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -398,6 +398,13 @@ stream.write('With ES6'); added: v0.3.0 changes: - version: v14.0.0 + pr-url: https://github.com/nodejs/node/pull/33690 + description: If `object` is from a different `vm.Context` now, a custom + inspection function on it will not receive context-specific + arguments anymore. + - version: + - v13.13.0 + - v12.17.0 pr-url: https://github.com/nodejs/node/pull/32392 description: The `maxStringLength` option is supported now. - version: diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 4cb0ee55f080e7..03e62226236df3 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -12,6 +12,7 @@ const { DatePrototypeToString, ErrorPrototypeToString, Float32Array, + FunctionPrototypeCall, FunctionPrototypeToString, Int16Array, JSONStringify, @@ -26,6 +27,7 @@ const { Number, NumberIsNaN, NumberPrototypeValueOf, + Object, ObjectAssign, ObjectCreate, ObjectDefineProperty, @@ -38,6 +40,7 @@ const { ObjectPrototypeHasOwnProperty, ObjectPrototypePropertyIsEnumerable, ObjectSeal, + ObjectSetPrototypeOf, RegExp, RegExpPrototypeToString, Set, @@ -213,8 +216,8 @@ const ansi = new RegExp(ansiPattern, 'g'); let getStringWidth; -function getUserOptions(ctx) { - return { +function getUserOptions(ctx, isCrossContext) { + const ret = { stylize: ctx.stylize, showHidden: ctx.showHidden, depth: ctx.depth, @@ -229,6 +232,33 @@ function getUserOptions(ctx) { getters: ctx.getters, ...ctx.userOptions }; + + // Typically, the target value will be an instance of `Object`. If that is + // *not* the case, the object may come from another vm.Context, and we want + // to avoid passing it objects from this Context in that case, so we remove + // the prototype from the returned object itself + the `stylize()` function, + // and remove all other non-primitives, including non-primitive user options. + if (isCrossContext) { + ObjectSetPrototypeOf(ret, null); + for (const key of ObjectKeys(ret)) { + if ((typeof ret[key] === 'object' || typeof ret[key] === 'function') && + ret[key] !== null) { + delete ret[key]; + } + } + ret.stylize = ObjectSetPrototypeOf((value, flavour) => { + let stylized; + try { + stylized = `${ctx.stylize(value, flavour)}`; + } catch {} + + if (typeof stylized !== 'string') return value; + // `stylized` is a string as it should be, which is safe to pass along. + return stylized; + }, null); + } + + return ret; } /** @@ -728,7 +758,10 @@ function formatValue(ctx, value, recurseTimes, typedArray) { // This makes sure the recurseTimes are reported as before while using // a counter internally. const depth = ctx.depth === null ? null : ctx.depth - recurseTimes; - const ret = maybeCustom.call(context, depth, getUserOptions(ctx)); + const isCrossContext = + proxy !== undefined || !(context instanceof Object); + const ret = FunctionPrototypeCall( + maybeCustom, context, depth, getUserOptions(ctx, isCrossContext)); // If the custom inspection method returned `this`, don't go into // infinite recursion. if (ret !== context) { diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 1a38904e09e670..55dcb851154ecf 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -2906,3 +2906,86 @@ assert.strictEqual( "'aaaa'... 999996 more characters" ); } + +{ + // Verify that util.inspect() invokes custom inspect functions on objects + // from other vm.Contexts but does not pass data from its own Context to that + // function. + const target = vm.runInNewContext(` + ({ + [Symbol.for('nodejs.util.inspect.custom')](depth, ctx) { + this.depth = depth; + this.ctx = ctx; + try { + this.stylized = ctx.stylize('🐈'); + } catch (e) { + this.stylizeException = e; + } + return this.stylized; + } + }) + `, Object.create(null)); + assert.strictEqual(target.ctx, undefined); + + { + // Subtest 1: Just try to inspect the object with default options. + assert.strictEqual(util.inspect(target), '🐈'); + assert.strictEqual(typeof target.ctx, 'object'); + const objectGraph = fullObjectGraph(target); + assert(!objectGraph.has(Object)); + assert(!objectGraph.has(Function)); + } + + { + // Subtest 2: Use a stylize function that returns a non-primitive. + const output = util.inspect(target, { + stylize: common.mustCall((str) => { + return {}; + }) + }); + assert.strictEqual(output, '[object Object]'); + assert.strictEqual(typeof target.ctx, 'object'); + const objectGraph = fullObjectGraph(target); + assert(!objectGraph.has(Object)); + assert(!objectGraph.has(Function)); + } + + { + // Subtest 3: Use a stylize function that throws an exception. + const output = util.inspect(target, { + stylize: common.mustCall((str) => { + throw new Error('oops'); + }) + }); + assert.strictEqual(output, '🐈'); + assert.strictEqual(typeof target.ctx, 'object'); + const objectGraph = fullObjectGraph(target); + assert(!objectGraph.has(Object)); + assert(!objectGraph.has(Function)); + } + + function fullObjectGraph(value) { + const graph = new Set([value]); + + for (const entry of graph) { + if ((typeof entry !== 'object' && typeof entry !== 'function') || + entry === null) { + continue; + } + + graph.add(Object.getPrototypeOf(entry)); + const descriptors = Object.values( + Object.getOwnPropertyDescriptors(entry)); + for (const descriptor of descriptors) { + graph.add(descriptor.value); + graph.add(descriptor.set); + graph.add(descriptor.get); + } + } + + return graph; + } + + // Consistency check. + assert(fullObjectGraph(global).has(Function.prototype)); +} From b8a17ccc9a5e835e50fcee5592c5d8abffde1321 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Tue, 16 Jun 2020 12:27:14 -0700 Subject: [PATCH 003/138] doc: document n-api callback scope usage Document that it is not necessary to open handle and/or callback scopes inside finalizer, async work, thread-safe function etc. callbacks unless for reasons documented in the section about object lifetime management. Link usage of callback signatures to their definition. Fixes: https://github.com/nodejs/node/issues/33893 PR-URL: https://github.com/nodejs/node/pull/33915 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Chengzhong Wu Reviewed-By: Michael Dawson --- doc/api/n-api.md | 52 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 902cb883aeec92..d1fa23260f178f 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -391,6 +391,7 @@ napi_status napi_set_instance_data(napi_env env, * `[in] data`: The data item to make available to bindings of this instance. * `[in] finalize_cb`: The function to call when the environment is being torn down. The function receives `data` so that it might free it. + [`napi_finalize`][] provides more details. * `[in] finalize_hint`: Optional hint to pass to the finalize callback during collection. @@ -597,6 +598,7 @@ minimum lifetimes explicitly. For more details, review the [Object lifetime management][]. ### N-API callback types + #### napi_callback_info A synchronous function that disassociates a connected `dgram.Socket` from -its remote address. Trying to call `disconnect()` on an already disconnected -socket will result in an [`ERR_SOCKET_DGRAM_NOT_CONNECTED`][] exception. +its remote address. Trying to call `disconnect()` on an unbound or already +disconnected socket will result in an [`ERR_SOCKET_DGRAM_NOT_CONNECTED`][] +exception. ### `socket.dropMembership(multicastAddress[, multicastInterface])` + The `assert` module provides a set of assertion functions for verifying invariants. diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 49aac3dc445e45..b3aec8cce457f5 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -4,6 +4,8 @@ > Stability: 1 - Experimental + + The `async_hooks` module provides an API to track asynchronous resources. It can be accessed using: diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 2df4fe795082bf..719af1ba7f5814 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + In Node.js, `Buffer` objects are used to represent binary data in the form of a sequence of bytes. Many Node.js APIs, for example streams and file system operations, support `Buffer`s, as interactions with the operating system or diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 779542c00fe58b..49b972362d4c87 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `child_process` module provides the ability to spawn child processes in a manner that is similar, but not identical, to popen(3). This capability is primarily provided by the [`child_process.spawn()`][] function: diff --git a/doc/api/cluster.md b/doc/api/cluster.md index 3c67d4cf1ed371..1ed5e38670fb3c 100644 --- a/doc/api/cluster.md +++ b/doc/api/cluster.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + A single instance of Node.js runs in a single thread. To take advantage of multi-core systems, the user will sometimes want to launch a cluster of Node.js processes to handle the load. diff --git a/doc/api/console.md b/doc/api/console.md index 2f4a8e64ed5bfa..ffc8825a46cb95 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 016a60802c46b4..28483b61ab6b71 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `crypto` module provides cryptographic functionality that includes a set of wrappers for OpenSSL's hash, HMAC, cipher, decipher, sign, and verify functions. diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 8e8f06551b7dac..be0323a306b27e 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -6,6 +6,8 @@ + + The `dgram` module provides an implementation of UDP datagram sockets. ```js diff --git a/doc/api/dns.md b/doc/api/dns.md index 8a4ee45fe10de5..4f5133fea563c2 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `dns` module enables name resolution. For example, use it to look up IP addresses of host names. diff --git a/doc/api/domain.md b/doc/api/domain.md index b9219fbb4d714e..109e41f749f1b4 100644 --- a/doc/api/domain.md +++ b/doc/api/domain.md @@ -16,6 +16,8 @@ changes: > Stability: 0 - Deprecated + + **This module is pending deprecation**. Once a replacement API has been finalized, this module will be fully deprecated. Most end users should **not** have cause to use this module. Users who absolutely must have diff --git a/doc/api/events.md b/doc/api/events.md index 80e9ccf6fef27a..d6aab8feab1d9b 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -6,6 +6,8 @@ + + Much of the Node.js core API is built around an idiomatic asynchronous event-driven architecture in which certain kinds of objects (called "emitters") emit named events that cause `Function` objects ("listeners") to be called. diff --git a/doc/api/fs.md b/doc/api/fs.md index 317a1ca174ca0d..d20e1901ae371b 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -6,6 +6,8 @@ + + The `fs` module provides an API for interacting with the file system in a manner closely modeled around standard POSIX functions. diff --git a/doc/api/http.md b/doc/api/http.md index e8b12ae23577f8..b523f7453f1fb8 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + To use the HTTP server and client one must `require('http')`. The HTTP interfaces in Node.js are designed to support many features diff --git a/doc/api/http2.md b/doc/api/http2.md index 67bb4c27e4d0b0..4b3fc33b7052f8 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -10,6 +10,8 @@ changes: > Stability: 2 - Stable + + The `http2` module provides an implementation of the [HTTP/2][] protocol. It can be accessed using: diff --git a/doc/api/https.md b/doc/api/https.md index 96f21930f4ad3b..2f362d40cf7340 100644 --- a/doc/api/https.md +++ b/doc/api/https.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + HTTPS is the HTTP protocol over TLS/SSL. In Node.js this is implemented as a separate module. diff --git a/doc/api/inspector.md b/doc/api/inspector.md index 4f9501a5f861a7..f541b9eb99fb68 100644 --- a/doc/api/inspector.md +++ b/doc/api/inspector.md @@ -4,6 +4,8 @@ > Stability: 1 - Experimental + + The `inspector` module provides an API for interacting with the V8 inspector. It can be accessed using: diff --git a/doc/api/net.md b/doc/api/net.md index 6fedabf0d2c80e..860d2171839c44 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -5,6 +5,8 @@ > Stability: 2 - Stable + + The `net` module provides an asynchronous network API for creating stream-based TCP or [IPC][] servers ([`net.createServer()`][]) and clients ([`net.createConnection()`][]). diff --git a/doc/api/os.md b/doc/api/os.md index a6c83e0206f589..83681cdedfad04 100644 --- a/doc/api/os.md +++ b/doc/api/os.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `os` module provides operating system-related utility methods and properties. It can be accessed using: diff --git a/doc/api/path.md b/doc/api/path.md index 8349bce252a56b..14acbb1eb5f99d 100644 --- a/doc/api/path.md +++ b/doc/api/path.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `path` module provides utilities for working with file and directory paths. It can be accessed using: diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md index 8d540491604846..759c141a2c77dc 100644 --- a/doc/api/perf_hooks.md +++ b/doc/api/perf_hooks.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + This module provides an implementation of a subset of the W3C [Web Performance APIs][] as well as additional APIs for Node.js-specific performance measurements. diff --git a/doc/api/process.md b/doc/api/process.md index eda3ac16f7a984..b2c0b483f839e5 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -3,6 +3,8 @@ + + The `process` object is a `global` that provides information about, and control over, the current Node.js process. As a global, it is always available to Node.js applications without using `require()`. It can also be explicitly diff --git a/doc/api/punycode.md b/doc/api/punycode.md index 4c9dc3460a08dd..bcdfb9a167fd04 100644 --- a/doc/api/punycode.md +++ b/doc/api/punycode.md @@ -10,6 +10,8 @@ changes: > Stability: 0 - Deprecated + + **The version of the punycode module bundled in Node.js is being deprecated**. In a future major version of Node.js this module will be removed. Users currently depending on the `punycode` module should switch to using the diff --git a/doc/api/querystring.md b/doc/api/querystring.md index 0797e3ee220d53..03ee78aad0a23d 100644 --- a/doc/api/querystring.md +++ b/doc/api/querystring.md @@ -6,6 +6,8 @@ + + The `querystring` module provides utilities for parsing and formatting URL query strings. It can be accessed using: diff --git a/doc/api/readline.md b/doc/api/readline.md index a737e4bd24d34c..d34ca6e91e7f61 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `readline` module provides an interface for reading data from a [Readable][] stream (such as [`process.stdin`][]) one line at a time. It can be accessed using: diff --git a/doc/api/repl.md b/doc/api/repl.md index 4940001a4ebfd2..56dc29fcec8217 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `repl` module provides a Read-Eval-Print-Loop (REPL) implementation that is available both as a standalone program or includible in other applications. It can be accessed using: diff --git a/doc/api/stream.md b/doc/api/stream.md index 7afa52c2f95314..749593f92c7836 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + A stream is an abstract interface for working with streaming data in Node.js. The `stream` module provides an API for implementing the stream interface. diff --git a/doc/api/string_decoder.md b/doc/api/string_decoder.md index 5cd6121d50ddb9..59056b861321b4 100644 --- a/doc/api/string_decoder.md +++ b/doc/api/string_decoder.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `string_decoder` module provides an API for decoding `Buffer` objects into strings in a manner that preserves encoded multi-byte UTF-8 and UTF-16 characters. It can be accessed using: diff --git a/doc/api/timers.md b/doc/api/timers.md index 8b080b16ffb70e..1157ae286e0d0a 100644 --- a/doc/api/timers.md +++ b/doc/api/timers.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `timer` module exposes a global API for scheduling functions to be called at some future period of time. Because the timer functions are globals, there is no need to call `require('timers')` to use the API. diff --git a/doc/api/tls.md b/doc/api/tls.md index 71c127ca6cc346..0fd84e198ac93d 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `tls` module provides an implementation of the Transport Layer Security (TLS) and Secure Socket Layer (SSL) protocols that is built on top of OpenSSL. The module can be accessed using: diff --git a/doc/api/tracing.md b/doc/api/tracing.md index 907fc2bbe23ba7..9350e0b9ca97da 100644 --- a/doc/api/tracing.md +++ b/doc/api/tracing.md @@ -4,6 +4,8 @@ > Stability: 1 - Experimental + + The `trace_events` module provides a mechanism to centralize tracing information generated by V8, Node.js core, and userspace code. diff --git a/doc/api/tty.md b/doc/api/tty.md index b1b1ebdb26796a..f4a83c290a3854 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `tty` module provides the `tty.ReadStream` and `tty.WriteStream` classes. In most cases, it will not be necessary or possible to use this module directly. However, it can be accessed using: diff --git a/doc/api/url.md b/doc/api/url.md index fbe8aa397918ba..06b80a438ad748 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `url` module provides utilities for URL resolution and parsing. It can be accessed using: diff --git a/doc/api/util.md b/doc/api/util.md index 7b3d08e0a0bcab..3887de8e38991e 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `util` module supports the needs of Node.js internal APIs. Many of the utilities are useful for application and module developers as well. To access it: diff --git a/doc/api/v8.md b/doc/api/v8.md index 531612330f061b..921c4378199496 100644 --- a/doc/api/v8.md +++ b/doc/api/v8.md @@ -2,6 +2,8 @@ + + The `v8` module exposes APIs that are specific to the version of [V8][] built into the Node.js binary. It can be accessed using: diff --git a/doc/api/vm.md b/doc/api/vm.md index 7ef5ff622795ca..773173085cc7e6 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -6,6 +6,8 @@ + + The `vm` module enables compiling and running code within V8 Virtual Machine contexts. **The `vm` module is not a security mechanism. Do not use it to run untrusted code**. diff --git a/doc/api/wasi.md b/doc/api/wasi.md index b46aacfbcb1ecb..46673af9e7fb34 100644 --- a/doc/api/wasi.md +++ b/doc/api/wasi.md @@ -4,6 +4,8 @@ > Stability: 1 - Experimental + + The WASI API provides an implementation of the [WebAssembly System Interface][] specification. WASI gives sandboxed WebAssembly applications access to the underlying operating system via a collection of POSIX-like functions. diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md index 45b9a5f0fd2323..26fb12be92992c 100644 --- a/doc/api/worker_threads.md +++ b/doc/api/worker_threads.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `worker_threads` module enables the use of threads that execute JavaScript in parallel. To access it: diff --git a/doc/api/zlib.md b/doc/api/zlib.md index d50792664840c4..34adda9788dfe4 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -4,6 +4,8 @@ > Stability: 2 - Stable + + The `zlib` module provides compression functionality implemented using Gzip, Deflate/Inflate, and Brotli. diff --git a/test/doctool/test-doctool-html.js b/test/doctool/test-doctool-html.js index 0ffa9f9149085d..30221a7fe18b1a 100644 --- a/test/doctool/test-doctool-html.js +++ b/test/doctool/test-doctool-html.js @@ -41,7 +41,7 @@ function toHTML({ input, filename, nodeVersion, versions }) { .use(replaceLinks, { filename, linksMapper: testLinksMapper }) .use(markdown) .use(html.firstHeader) - .use(html.preprocessText) + .use(html.preprocessText, { nodeVersion }) .use(html.preprocessElements, { filename }) .use(html.buildToc, { filename, apilinks: {} }) .use(remark2rehype, { allowDangerousHTML: true }) diff --git a/tools/doc/common.js b/tools/doc/common.js index 86daae6cfc6d56..11e4ad6e2c99aa 100644 --- a/tools/doc/common.js +++ b/tools/doc/common.js @@ -7,6 +7,10 @@ function isYAMLBlock(text) { return /^/.test(text); +} + function arrify(value) { return Array.isArray(value) ? value : [value]; } @@ -43,4 +47,4 @@ function extractAndParseYAML(text) { return meta; } -module.exports = { arrify, isYAMLBlock, extractAndParseYAML }; +module.exports = { arrify, isYAMLBlock, isSourceLink, extractAndParseYAML }; diff --git a/tools/doc/generate.js b/tools/doc/generate.js index dcb72a99d931f6..93c3b263009bb6 100644 --- a/tools/doc/generate.js +++ b/tools/doc/generate.js @@ -82,7 +82,7 @@ async function main() { const content = await unified() .use(replaceLinks, { filename, linksMapper }) .use(markdown) - .use(html.preprocessText) + .use(html.preprocessText, { nodeVersion }) .use(json.jsonAPI, { filename }) .use(html.firstHeader) .use(html.preprocessElements, { filename }) diff --git a/tools/doc/html.js b/tools/doc/html.js index b58563045def8d..b8333f8bcbc498 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -104,10 +104,13 @@ function firstHeader() { // Handle general body-text replacements. // For example, link man page references to the actual page. -function preprocessText() { +function preprocessText({ nodeVersion }) { return (tree) => { visit(tree, null, (node) => { - if (node.type === 'text' && node.value) { + if (common.isSourceLink(node.value)) { + const [path] = node.value.match(/(?<=)/); + node.value = `

Source Code: ${path}

`; + } else if (node.type === 'text' && node.value) { const value = linkJsTypeDocs(linkManPages(node.value)); if (value !== node.value) { node.type = 'html'; From 70c4045aa5ba169a8c730d92d377d1cf1d4710a6 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 23 Jun 2020 00:33:04 +0200 Subject: [PATCH 006/138] vm: add run-after-evaluate microtask mode This allows timeouts to apply to e.g. `Promise`s and `async function`s from code running inside of `vm.Context`s, by giving the Context its own microtasks queue. Fixes: https://github.com/nodejs/node/issues/3020 PR-URL: https://github.com/nodejs/node/pull/34023 Reviewed-By: James M Snell Reviewed-By: Denys Otrishko --- doc/api/vm.md | 74 ++++++++++++++--- lib/vm.js | 24 +++++- src/env.h | 1 + src/module_wrap.cc | 31 +++++--- src/module_wrap.h | 9 ++- src/node_contextify.cc | 79 +++++++++++++++++-- src/node_contextify.h | 28 +++++++ test/known_issues/known_issues.status | 3 - .../test-vm-timeout-escape-queuemicrotask.js | 2 +- .../test-vm-timeout-escape-promise-2.js | 38 +++++++++ ...test-vm-timeout-escape-promise-module-2.js | 42 ++++++++++ .../test-vm-timeout-escape-promise-module.js | 42 ++++++++++ .../test-vm-timeout-escape-promise.js | 8 +- 13 files changed, 342 insertions(+), 39 deletions(-) create mode 100644 test/parallel/test-vm-timeout-escape-promise-2.js create mode 100644 test/parallel/test-vm-timeout-escape-promise-module-2.js create mode 100644 test/parallel/test-vm-timeout-escape-promise-module.js rename test/{known_issues => parallel}/test-vm-timeout-escape-promise.js (74%) diff --git a/doc/api/vm.md b/doc/api/vm.md index 773173085cc7e6..6fd07b0fd910f0 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -188,6 +188,9 @@ overhead. + +* `instance` {WebAssembly.Instance} + +Attempt to initialize `instance` as a WASI reactor by invoking its +`_initialize()` export, if it is present. If `instance` contains a `_start()` +export, then an exception is thrown. + +`initialize()` requires that `instance` exports a [`WebAssembly.Memory`][] named +`memory`. If `instance` does not have a `memory` export an exception is thrown. + +If `initialize()` is called more than once, an exception is thrown. + ### `wasi.wasiImport` + +Type: Documentation-only + +[`socket.bufferSize`][] is just an alias for [`writable.writableLength`][]. + [`--pending-deprecation`]: cli.html#cli_pending_deprecation [`--throw-deprecation`]: cli.html#cli_throw_deprecation [`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size @@ -2781,6 +2794,7 @@ no longer required due to simplification of the implementation. [`script.createCachedData()`]: vm.html#vm_script_createcacheddata [`setInterval()`]: timers.html#timers_setinterval_callback_delay_args [`setTimeout()`]: timers.html#timers_settimeout_callback_delay_args +[`socket.bufferSize`]: net.html#net_socket_buffersize [`timeout.ref()`]: timers.html#timers_timeout_ref [`timeout.refresh()`]: timers.html#timers_timeout_refresh [`timeout.unref()`]: timers.html#timers_timeout_unref @@ -2817,6 +2831,7 @@ no longer required due to simplification of the implementation. [`util`]: util.html [`worker.exitedAfterDisconnect`]: cluster.html#cluster_worker_exitedafterdisconnect [`worker.terminate()`]: worker_threads.html#worker_threads_worker_terminate +[`writable.writableLength`]: stream.html#stream_writable_writablelength [`zlib.bytesWritten`]: zlib.html#zlib_zlib_byteswritten [Legacy URL API]: url.html#url_legacy_url_api [NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf diff --git a/doc/api/net.md b/doc/api/net.md index 860d2171839c44..6c9e0468cef3c8 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -545,8 +545,12 @@ socket as reported by the operating system: ### `socket.bufferSize` +> Stability: 0 - Deprecated: Use [`writable.writableLength`][] instead. + * {integer} This property shows the number of characters buffered for writing. The buffer @@ -1276,6 +1280,7 @@ Returns `true` if input is a version 6 IP address, otherwise returns `false`. [`socket.setEncoding()`]: #net_socket_setencoding_encoding [`socket.setTimeout()`]: #net_socket_settimeout_timeout_callback [`socket.setTimeout(timeout)`]: #net_socket_settimeout_timeout_callback +[`writable.writableLength`]: stream.html#stream_writable_writablelength [`writable.destroyed`]: stream.html#stream_writable_destroyed [`writable.destroy()`]: stream.html#stream_writable_destroy_error [`writable.end()`]: stream.html#stream_writable_end_chunk_encoding_callback From 4dc89c6d30fec316110dbcb182ed37dc4c9d43f3 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Tue, 30 Jun 2020 17:26:27 -0700 Subject: [PATCH 016/138] meta: fixup CODEOWNERS so it hopefully works the CODEOWNERS rules for QUIC are not working and it's not entirely clear why. Hoping it's just the way the paths were specified. PR-URL: https://github.com/nodejs/node/pull/34147 Reviewed-By: Anna Henningsen Reviewed-By: Jiawen Geng --- .github/CODEOWNERS | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6fb4f7dc493b6a..e78612d424d09a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -59,12 +59,12 @@ # quic -./deps/ngtcp2/* @nodejs/quic -./deps/nghttp3/* @nodejs/quic -./doc/api/quic.md @nodejs/quic -./lib/internal/quic/* @nodejs/quic -./src/node_bob* @nodejs/quic -./src/quic/* @nodejs/quic +/deps/ngtcp2/ @nodejs/quic +/deps/nghttp3/ @nodejs/quic +/doc/api/quic.md @nodejs/quic +/lib/internal/quic/ @nodejs/quic +/src/node_bob* @nodejs/quic +/src/quic/ @nodejs/quic # modules From 05a69e2e88074516e0ee7dd5bfdbdb46f7888383 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 27 Jun 2020 21:25:46 -0700 Subject: [PATCH 017/138] doc: clarify ambiguous rdev description Replace "is considered 'special'" with "represents a device". The latter is more clear and is derived from the stat() man page. The former is also derived from the man page, but is ambiguous because: * "considered" introduces doubt. Is it, or isn't it? * "special" is never defined. "represents a device" communicates more meaning. * "special" is in scare-quotes, introducing more doubt as to what exactly it means. Refs: https://man7.org/linux/man-pages/man2/fstat.2.html PR-URL: https://github.com/nodejs/node/pull/34094 Reviewed-By: Anna Henningsen Reviewed-By: Ujjwal Sharma --- doc/api/fs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/fs.md b/doc/api/fs.md index d20e1901ae371b..c6620be87ad1c2 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -888,7 +888,7 @@ The numeric group identifier of the group that owns the file (POSIX). * {number|bigint} -A numeric device identifier if the file is considered "special". +A numeric device identifier if the file represents a device. ### `stats.size` From ee6ccef091e1650a5687c340365d548e4f6cee32 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 27 Jun 2020 22:22:12 -0700 Subject: [PATCH 018/138] doc: clarify O_EXCL text in fs.md PR-URL: https://github.com/nodejs/node/pull/34096 Reviewed-By: Anna Henningsen Reviewed-By: Ujjwal Sharma --- doc/api/fs.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/api/fs.md b/doc/api/fs.md index c6620be87ad1c2..d64b011147d510 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -5817,10 +5817,10 @@ are available from `fs.constants`. On Windows, flags are translated to their equivalent ones where applicable, e.g. `O_WRONLY` to `FILE_GENERIC_WRITE`, or `O_EXCL|O_CREAT` to `CREATE_NEW`, as accepted by `CreateFileW`. -The exclusive flag `'x'` (`O_EXCL` flag in open(2)) ensures that path is newly -created. On POSIX systems, path is considered to exist even if it is a symlink -to a non-existent file. The exclusive flag may or may not work with network -file systems. +The exclusive flag `'x'` (`O_EXCL` flag in open(2)) causes the operation to +return an error if the path already exists. On POSIX, if the path is a symbolic +link, using `O_EXCL` returns an error even if the link is to a path that does +not exist. The exclusive flag may or may not work with network file systems. On Linux, positional writes don't work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to From 64bd518f268c84ec3b656be82348f5fcacf495a0 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 28 Jun 2020 20:37:25 -0700 Subject: [PATCH 019/138] doc: clarify that APIs are no longer experimental MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change "no longer considered experimental" to "no longer experimental". It's more clear and direct. PR-URL: https://github.com/nodejs/node/pull/34113 Reviewed-By: Trivikram Kamat Reviewed-By: Michaël Zasso Reviewed-By: Zeyu Yang Reviewed-By: Luigi Pinca --- doc/api/process.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/api/process.md b/doc/api/process.md index b2c0b483f839e5..ea8d8367c63a5d 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -1794,7 +1794,7 @@ added: v11.8.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This API is no longer considered experimental. + description: This API is no longer experimental. --> * {Object} @@ -1824,7 +1824,7 @@ added: v11.12.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This API is no longer considered experimental. + description: This API is no longer experimental. --> * {string} @@ -1843,7 +1843,7 @@ added: v11.12.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This API is no longer considered experimental. + description: This API is no longer experimental. --> * {string} @@ -1862,7 +1862,7 @@ added: v11.8.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This API is no longer considered experimental. + description: This API is no longer experimental. --> * `err` {Error} A custom error used for reporting the JavaScript stack. @@ -1905,7 +1905,7 @@ added: v11.12.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This API is no longer considered experimental. + description: This API is no longer experimental. --> * {boolean} @@ -1923,7 +1923,7 @@ added: v11.12.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This API is no longer considered experimental. + description: This API is no longer experimental. --> * {boolean} @@ -1940,7 +1940,7 @@ added: v11.12.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This API is no longer considered experimental. + description: This API is no longer experimental. --> * {string} @@ -1958,7 +1958,7 @@ added: v11.8.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This API is no longer considered experimental. + description: This API is no longer experimental. --> * `filename` {string} Name of the file where the report is written. This From 9d30f0542c1f49bb39a84deb4a9eeb935120e020 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 28 Jun 2020 21:08:22 -0700 Subject: [PATCH 020/138] doc: change "currently not considered public" to "not supported" PR-URL: https://github.com/nodejs/node/pull/34114 Reviewed-By: Trivikram Kamat Reviewed-By: Anna Henningsen --- doc/api/async_hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index b3aec8cce457f5..7bbff4cddbce57 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -304,7 +304,7 @@ been initialized. This can contain useful information that can vary based on the value of `type`. For instance, for the `GETADDRINFOREQWRAP` resource type, `resource` provides the host name used when looking up the IP address for the host in `net.Server.listen()`. The API for accessing this information is -currently not considered public, but using the Embedder API, users can provide +not supported, but using the Embedder API, users can provide and document their own resource objects. For example, such a resource object could contain the SQL query being executed. From fbcd1fa0f4a5892426c020bd5d13323ac38c64cc Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sun, 28 Jun 2020 20:32:12 +0200 Subject: [PATCH 021/138] tls: remove unnecessary close listener Wrapped streams are expected to behave the same as socket with handle. Remove unnecessary difference in handling. PR-URL: https://github.com/nodejs/node/pull/34105 Reviewed-By: Anna Henningsen Reviewed-By: Trivikram Kamat --- lib/_tls_wrap.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index 02fd7b002651c3..7031bc5047a47e 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -490,7 +490,6 @@ function TLSSocket(socket, opts) { // handle, but a JS stream doesn't have one. Wrap it up to make it look like // a socket. wrap = new JSStreamSocket(socket); - wrap.once('close', () => this.destroy()); } // Just a documented property to make secure sockets From 49d2d493365baff86579b1fbbdf40e3d26d6658d Mon Sep 17 00:00:00 2001 From: falguniraina <48027052+falguniraina@users.noreply.github.com> Date: Fri, 19 Jun 2020 21:28:52 +0530 Subject: [PATCH 022/138] doc: improve text in issues.md PR-URL: https://github.com/nodejs/node/pull/33973 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Rich Trott Reviewed-By: Trivikram Kamat Reviewed-By: Myles Borins Reviewed-By: Zeyu Yang --- doc/guides/contributing/issues.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/guides/contributing/issues.md b/doc/guides/contributing/issues.md index 31a47c1cd33c16..a021e4c8207c7d 100644 --- a/doc/guides/contributing/issues.md +++ b/doc/guides/contributing/issues.md @@ -90,10 +90,10 @@ including whether the behavior being seen is a bug or a feature. This discussion is part of the process and should be kept focused, helpful, and professional. Short, clipped responses that provide neither additional context nor supporting -detail are not helpful or professional. To many, such responses are simply +details are not helpful or professional to many. Such responses are simply annoying and unfriendly. -Contributors are encouraged to help one another make forward progress as much +Contributors are encouraged to help one another to make forward progress as much as possible, empowering one another to solve issues collaboratively. If you choose to comment on an issue that you feel either is not a problem that needs to be fixed, or if you encounter information in an issue that you feel is From da5fde6594406dfed63c10c47d33115c7b985ae7 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 29 Jun 2020 21:17:05 -0700 Subject: [PATCH 023/138] doc: changed "considered experimental" to "experimental" in cli.md Change "no longer considered experimental" to "no longer experimental" in cli.md. PR-URL: https://github.com/nodejs/node/pull/34128 Reviewed-By: Denys Otrishko Reviewed-By: Trivikram Kamat --- doc/api/cli.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/api/cli.md b/doc/api/cli.md index 1d04b01a0b546a..10bfefeee14b14 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -641,7 +641,7 @@ added: v11.8.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This option is no longer considered experimental. + description: This option is no longer experimental. - version: v12.0.0 pr-url: https://github.com/nodejs/node/pull/27312 description: Changed from `--diagnostic-report-directory` to @@ -656,7 +656,7 @@ added: v11.8.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This option is no longer considered experimental. + description: This option is no longer experimental. - version: v12.0.0 pr-url: https://github.com/nodejs/node/pull/27312 description: changed from `--diagnostic-report-filename` to @@ -671,7 +671,7 @@ added: v11.8.0 changes: - version: v14.0.0 pr-url: https://github.com/nodejs/node/pull/32496 - description: This option is no longer considered experimental. + description: This option is no longer experimental. - version: v12.0.0 pr-url: https://github.com/nodejs/node/pull/27312 description: changed from `--diagnostic-report-on-fatalerror` to @@ -690,7 +690,7 @@ added: v11.8.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This option is no longer considered experimental. + description: This option is no longer experimental. - version: v12.0.0 pr-url: https://github.com/nodejs/node/pull/27312 description: changed from `--diagnostic-report-on-signal` to @@ -707,7 +707,7 @@ added: v11.8.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This option is no longer considered experimental. + description: This option is no longer experimental. - version: v12.0.0 pr-url: https://github.com/nodejs/node/pull/27312 description: changed from `--diagnostic-report-signal` to @@ -723,7 +723,7 @@ added: v11.8.0 changes: - version: v13.12.0 pr-url: https://github.com/nodejs/node/pull/32242 - description: This option is no longer considered experimental. + description: This option is no longer experimental. - version: v12.0.0 pr-url: https://github.com/nodejs/node/pull/27312 description: changed from `--diagnostic-report-uncaught-exception` to From 78a4d97b820deb686fb2ce5142095708244e0197 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 29 Jun 2020 21:21:19 -0700 Subject: [PATCH 024/138] doc: change "considered experimental" to "experimental" in n-api.md This changes "considered" experimental" to "experimental" in the n-api.md file and introduces some additional brevity. PR-URL: https://github.com/nodejs/node/pull/34129 Reviewed-By: Denys Otrishko Reviewed-By: Trivikram Kamat --- doc/api/n-api.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index d1fa23260f178f..559e9a11a2918c 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -222,8 +222,7 @@ can be specified explicitly when including the header: This restricts the N-API surface to just the functionality that was available in the specified (and earlier) versions. -Some of the N-API surface is considered experimental and requires explicit -opt-in to access those APIs: +Some of the N-API surface is experimental and requires explicit opt-in: ```c #define NAPI_EXPERIMENTAL From 26ecdf8ade71c6e25cd46969a1af678c92bc39d2 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Sat, 27 Jun 2020 21:29:58 -0700 Subject: [PATCH 025/138] doc: move sam-github to TSC Emeriti I don't have enough time to remain active in the TSC, so I will step down. PR-URL: https://github.com/nodejs/node/pull/34095 Reviewed-By: Gireesh Punathil Reviewed-By: Daniel Bevenius Reviewed-By: Colin Ihrig --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fda0fc98ea2340..3387975cca122c 100644 --- a/README.md +++ b/README.md @@ -187,8 +187,6 @@ For information about the governance of the Node.js project, see **Matheus Marchini** <mat@mmarchini.me> * [MylesBorins](https://github.com/MylesBorins) - **Myles Borins** <myles.borins@gmail.com> (he/him) -* [sam-github](https://github.com/sam-github) - -**Sam Roberts** <vieuxtech@gmail.com> * [targos](https://github.com/targos) - **Michaël Zasso** <targos@protonmail.com> (he/him) * [tniessen](https://github.com/tniessen) - @@ -226,6 +224,8 @@ For information about the governance of the Node.js project, see **Bert Belder** <bertbelder@gmail.com> * [rvagg](https://github.com/rvagg) - **Rod Vagg** <r@va.gg> +* [sam-github](https://github.com/sam-github) - +**Sam Roberts** <vieuxtech@gmail.com> * [shigeki](https://github.com/shigeki) - **Shigeki Ohtsu** <ohtsu@ohtsu.org> (he/him) * [thefourtheye](https://github.com/thefourtheye) - @@ -391,8 +391,6 @@ For information about the governance of the Node.js project, see **Ujjwal Sharma** <ryzokuken@disroot.org> (he/him) * [saghul](https://github.com/saghul) - **Saúl Ibarra Corretgé** <saghul@gmail.com> -* [sam-github](https://github.com/sam-github) - -**Sam Roberts** <vieuxtech@gmail.com> * [santigimeno](https://github.com/santigimeno) - **Santiago Gimeno** <santiago.gimeno@gmail.com> * [sebdeckers](https://github.com/sebdeckers) - @@ -530,6 +528,8 @@ For information about the governance of the Node.js project, see **Roman Klauke** <romaaan.git@gmail.com> * [RReverser](https://github.com/RReverser) - **Ingvar Stepanyan** <me@rreverser.com> +* [sam-github](https://github.com/sam-github) - +**Sam Roberts** <vieuxtech@gmail.com> * [stefanmb](https://github.com/stefanmb) - **Stefan Budeanu** <stefan@budeanu.com> * [tellnes](https://github.com/tellnes) - From af9e6f6e1bb6992cfc49be25da122e15b3306be1 Mon Sep 17 00:00:00 2001 From: Derek Lewis Date: Sun, 7 Jun 2020 17:21:45 -0400 Subject: [PATCH 026/138] doc: add http highlight grammar Prior to this commit, http request message code blocks in Markdown files were not being highlighted correctly. This has been corrected by adding the new grammar to the bundle, removing the CRLFs (`\r\n`) from these code samples, adding a reminder to re-add them, and tuning the syntax theme to support attribute highlighting. PR-URL: https://github.com/nodejs/node/pull/33785 Reviewed-By: Rich Trott Reviewed-By: Luigi Pinca Reviewed-By: Matteo Collina --- doc/api/http.md | 10 +++++----- doc/api/http2.md | 10 +++++----- doc/api_assets/README.md | 3 ++- doc/api_assets/highlight.pack.js | 2 +- doc/api_assets/hljs.css | 1 + 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/doc/api/http.md b/doc/api/http.md index b523f7453f1fb8..a9fedd8c606a47 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -2090,13 +2090,13 @@ added: v0.1.90 **Only valid for request obtained from [`http.Server`][].** -Request URL string. This contains only the URL that is -present in the actual HTTP request. If the request is: +Request URL string. This contains only the URL that is present in the actual +HTTP request. If the request is (remember, each header line ends with `\r\n` +plus a final `\r\n` after the last one indicating the end of the header): ```http -GET /status?name=ryan HTTP/1.1\r\n -Accept: text/plain\r\n -\r\n +GET /status?name=ryan HTTP/1.1 +Accept: text/plain ``` To parse the URL into its parts: diff --git a/doc/api/http2.md b/doc/api/http2.md index 4b3fc33b7052f8..389e361338f87a 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -3027,13 +3027,13 @@ added: v8.4.0 * {string} -Request URL string. This contains only the URL that is -present in the actual HTTP request. If the request is: +Request URL string. This contains only the URL that is present in the actual +HTTP request. If the request is (remember, each header line ends with `\r\n` +plus a final `\r\n` after the last one indicating the end of the header): ```http -GET /status?name=ryan HTTP/1.1\r\n -Accept: text/plain\r\n -\r\n +GET /status?name=ryan HTTP/1.1 +Accept: text/plain ``` Then `request.url` will be: diff --git a/doc/api_assets/README.md b/doc/api_assets/README.md index 58799cf12fcb88..3c0e1d1cbb2976 100644 --- a/doc/api_assets/README.md +++ b/doc/api_assets/README.md @@ -2,7 +2,7 @@ ## highlight.pack.js -_Generated by [highlightjs.org/download][] on 2020-05-16._ +_Generated by [highlightjs.org/download][] on 2020-06-07._ Grammars included in the custom bundle: @@ -10,6 +10,7 @@ Grammars included in the custom bundle: * C * C++ * CoffeeScript +* HTTP * JavaScript * JSON * Markdown diff --git a/doc/api_assets/highlight.pack.js b/doc/api_assets/highlight.pack.js index a493e16d3a7238..bd134963d24609 100644 --- a/doc/api_assets/highlight.pack.js +++ b/doc/api_assets/highlight.pack.js @@ -3,4 +3,4 @@ License: BSD-3-Clause Copyright (c) 2006-2020, Ivan Sagalaev */ -var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!n.hasOwnProperty(r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach((function(e){for(n in e)t[n]=e[n]})),t}function r(e){return e.nodeName.toLowerCase()}var a=Object.freeze({__proto__:null,escapeHTML:n,inherit:t,nodeStream:function(e){var n=[];return function e(t,a){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=e(i,a),r(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n},mergeStreams:function(e,t,a){var i=0,s="",o=[];function l(){return e.length&&t.length?e[0].offset!==t[0].offset?e[0].offset"}function u(e){s+=""}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||t.length;){var g=l();if(s+=n(a.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+n(a.substr(i))}});const i="",s=e=>!!e.kind;class o{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=n(e)}openNode(e){if(!s(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){s(e)&&(this.buffer+=i)}span(e){this.buffer+=``}value(){return this.buffer}}class l{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){let n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){e.children&&(e.children.every(e=>"string"==typeof e)?(e.text=e.children.join(""),delete e.children):e.children.forEach(e=>{"string"!=typeof e&&l._collapse(e)}))}}class c extends l{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){let t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new o(this,this.options).value()}finalize(){}}function u(e){return e&&e.source||e}const d="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",g={begin:"\\\\[\\s\\S]",relevance:0},h={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[g]},f={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[g]},p={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,r){var a=t({className:"comment",begin:e,end:n,contains:[]},r||{});return a.contains.push(p),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|XXX):",relevance:0}),a},b=m("//","$"),v=m("/\\*","\\*/"),x=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:d,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",BACKSLASH_ESCAPE:g,APOS_STRING_MODE:h,QUOTE_STRING_MODE:f,PHRASAL_WORDS_MODE:p,COMMENT:m,C_LINE_COMMENT_MODE:b,C_BLOCK_COMMENT_MODE:v,HASH_COMMENT_MODE:x,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:d,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^\/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[g,{begin:/\[/,end:/\]/,relevance:0,contains:[g]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0}}),E="of and for in not or if then".split(" ");function R(e,n){return n?+n:(t=e,E.includes(t.toLowerCase())?0:1);var t}const N=n,w=t,{nodeStream:y,mergeStreams:O}=a;return function(n){var r=[],a={},i={},s=[],o=!0,l=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,d="Could not find the language '{}', did you forget to load/include a language module?",g={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0,__emitter:c};function h(e){return g.noHighlightRe.test(e)}function f(e,n,t,r){var a={code:n,language:e};T("before:highlight",a);var i=a.result?a.result:p(a.language,a.code,t,r);return i.code=a.code,T("after:highlight",i),i}function p(e,n,r,i){var s=n;function l(e,n){var t=v.case_insensitive?n[0].toLowerCase():n[0];return e.keywords.hasOwnProperty(t)&&e.keywords[t]}function c(){null!=_.subLanguage?function(){if(""!==k){var e="string"==typeof _.subLanguage;if(!e||a[_.subLanguage]){var n=e?p(_.subLanguage,k,!0,E[_.subLanguage]):m(k,_.subLanguage.length?_.subLanguage:void 0);_.relevance>0&&(T+=n.relevance),e&&(E[_.subLanguage]=n.top),w.addSublanguage(n.emitter,n.language)}else w.addText(k)}}():function(){var e,n,t,r;if(_.keywords){for(n=0,_.lexemesRe.lastIndex=0,t=_.lexemesRe.exec(k),r="";t;){r+=k.substring(n,t.index);var a=null;(e=l(_,t))?(w.addText(r),r="",T+=e[1],a=e[0],w.addKeyword(t[0],a)):r+=t[0],n=_.lexemesRe.lastIndex,t=_.lexemesRe.exec(k)}r+=k.substr(n),w.addText(r)}else w.addText(k)}(),k=""}function h(e){e.className&&w.openNode(e.className),_=Object.create(e,{parent:{value:_}})}var f={};function b(n,t){var a,i=t&&t[0];if(k+=n,null==i)return c(),0;if("begin"==f.type&&"end"==t.type&&f.index==t.index&&""===i){if(k+=s.slice(t.index,t.index+1),!o)throw(a=Error("0 width match regex")).languageName=e,a.badRule=f.rule,a;return 1}if(f=t,"begin"===t.type)return function(e){var n=e[0],t=e.rule;return t.__onBegin&&(t.__onBegin(e)||{}).ignoreMatch?function(e){return 0===_.matcher.regexIndex?(k+=e[0],1):(B=!0,0)}(n):(t&&t.endSameAsBegin&&(t.endRe=RegExp(n.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),t.skip?k+=n:(t.excludeBegin&&(k+=n),c(),t.returnBegin||t.excludeBegin||(k=n)),h(t),t.returnBegin?0:n.length)}(t);if("illegal"===t.type&&!r)throw(a=Error('Illegal lexeme "'+i+'" for mode "'+(_.className||"")+'"')).mode=_,a;if("end"===t.type){var l=function(e){var n=e[0],t=s.substr(e.index),r=function e(n,t){if(function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(n.endRe,t)){for(;n.endsParent&&n.parent;)n=n.parent;return n}if(n.endsWithParent)return e(n.parent,t)}(_,t);if(r){var a=_;a.skip?k+=n:(a.returnEnd||a.excludeEnd||(k+=n),c(),a.excludeEnd&&(k=n));do{_.className&&w.closeNode(),_.skip||_.subLanguage||(T+=_.relevance),_=_.parent}while(_!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.endRe=r.endRe),h(r.starts)),a.returnEnd?0:n.length}}(t);if(null!=l)return l}if("illegal"===t.type&&""===i)return 1;if(A>1e5&&A>3*t.index)throw Error("potential infinite loop, way more iterations than matches");return k+=i,i.length}var v=M(e);if(!v)throw console.error(d.replace("{}",e)),Error('Unknown language: "'+e+'"');!function(e){function n(n,t){return RegExp(u(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class r{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);let e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+="|"),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"==l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("==l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;let n=this.matcherRe.exec(e);if(!n)return null;let t=n.findIndex((e,n)=>n>0&&null!=e),r=this.matchIndexes[t];return Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];let n=new r;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){let n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;let t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e){let n=e.input[e.index-1],t=e.input[e.index+e[0].length];if("."===n||"."===t)return{ignoreMatch:!0}}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");!function r(s,o){s.compiled||(s.compiled=!0,s.__onBegin=null,s.keywords=s.keywords||s.beginKeywords,s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,R(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemesRe=n(s.lexemes||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__onBegin=i),s.begin||(s.begin=/\B|\b/),s.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(s.endRe=n(s.end)),s.terminator_end=u(s.end)||"",s.endsWithParent&&o.terminator_end&&(s.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(s.illegalRe=n(s.illegal)),null==s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return t(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?t(e,{starts:e.starts?t(e.starts):null}):Object.isFrozen(e)?t(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){r(e,s)})),s.starts&&r(s.starts,o),s.matcher=function(e){let n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(s))}(e)}(v);var x,_=i||v,E={},w=new g.__emitter(g);!function(){for(var e=[],n=_;n!==v;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>w.openNode(e))}();var y,O,k="",T=0,L=0,A=0,B=!1;try{for(_.matcher.considerAll();A++,B?B=!1:(_.matcher.lastIndex=L,_.matcher.considerAll()),y=_.matcher.exec(s);)O=b(s.substring(L,y.index),y),L=y.index+O;return b(s.substr(L)),w.closeAllNodes(),w.finalize(),x=w.toHTML(),{relevance:T,value:x,language:e,illegal:!1,emitter:w,top:_}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:s.slice(L-100,L+100),mode:n.mode},sofar:x,relevance:0,value:N(s),emitter:w};if(o)return{relevance:0,value:N(s),emitter:w,language:e,top:_,errorRaised:n};throw n}}function m(e,n){n=n||g.languages||Object.keys(a);var t=function(e){const n={relevance:0,emitter:new g.__emitter(g),value:N(e),illegal:!1,top:E};return n.emitter.addText(e),n}(e),r=t;return n.filter(M).filter(k).forEach((function(n){var a=p(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function b(e){return g.tabReplace||g.useBR?e.replace(l,(function(e,n){return g.useBR&&"\n"===e?"
":g.tabReplace?n.replace(/\t/g,g.tabReplace):""})):e}function v(e){var n,t,r,a,s,o=function(e){var n,t=e.className+" ";if(t+=e.parentNode?e.parentNode.className:"",n=g.languageDetectRe.exec(t)){var r=M(n[1]);return r||(console.warn(d.replace("{}",n[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?n[1]:"no-highlight"}return t.split(/\s+/).find(e=>h(e)||M(e))}(e);h(o)||(T("before:highlightBlock",{block:e,language:o}),g.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"):n=e,s=n.textContent,r=o?f(o,s,!0):m(s),(t=y(n)).length&&((a=document.createElement("div")).innerHTML=r.value,r.value=O(t,y(a),s)),r.value=b(r.value),T("after:highlightBlock",{block:e,result:r}),e.innerHTML=r.value,e.className=function(e,n,t){var r=n?i[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,o,r.language),e.result={language:r.language,re:r.relevance},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.relevance}))}function x(){if(!x.called){x.called=!0;var e=document.querySelectorAll("pre code");r.forEach.call(e,v)}}const E={disableAutodetect:!0,name:"Plain text"};function M(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]}function k(e){var n=M(e);return n&&!n.disableAutodetect}function T(e,n){var t=e;s.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(n,{highlight:f,highlightAuto:m,fixMarkup:b,highlightBlock:v,configure:function(e){g=w(g,e)},initHighlighting:x,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",x,!1)},registerLanguage:function(e,t){var r;try{r=t(n)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!o)throw n;console.error(n),r=E}r.name||(r.name=e),a[e]=r,r.rawDefinition=t.bind(null,n),r.aliases&&r.aliases.forEach((function(n){i[n]=e}))},listLanguages:function(){return Object.keys(a)},getLanguage:M,requireLanguage:function(e){var n=M(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:k,inherit:w,addPlugin:function(e,n){s.push(e)}}),n.debugMode=function(){o=!1},n.safeMode=function(){o=!0},n.versionString="10.0.3";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(n,_),n}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);hljs.registerLanguage("json",function(){"use strict";return function(n){var e={literal:"true false null"},i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/})].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)],illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}());hljs.registerLanguage("xml",function(){"use strict";return function(e){var n={className:"symbol",begin:"&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;"},a={begin:"\\s",contains:[{className:"meta-keyword",begin:"#?[a-z_][a-z1-9_-]+",illegal:"\\n"}]},s=e.inherit(a,{begin:"\\(",end:"\\)"}),t=e.inherit(e.APOS_STRING_MODE,{className:"meta-string"}),i=e.inherit(e.QUOTE_STRING_MODE,{className:"meta-string"}),c={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin:"",relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{className:"meta",begin:"",contains:[a,s,i,t]}]}]},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[",end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:")",end:">",keywords:{name:"style"},contains:[c],starts:{end:"",returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:")",end:">",keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}}}());hljs.registerLanguage("markdown",function(){"use strict";return function(n){const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0,relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a];return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c,end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}());hljs.registerLanguage("bash",function(){"use strict";return function(e){const s={};Object.assign(s,{className:"variable",variants:[{begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:[{begin:/:-/,contains:[s]}]}]});const n={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},t={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,n]};n.contains.push(t);const a={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]};return{name:"Bash",aliases:["sh","zsh"],lexemes:/\b-?[a-z\._]+\b/,keywords:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},contains:[{className:"meta",begin:/^#![^\n]+sh\s*$/,relevance:10},{className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0},a,e.HASH_COMMENT_MODE,t,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}}());hljs.registerLanguage("shell",function(){"use strict";return function(s){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"}}]}}}());hljs.registerLanguage("c-like",function(){"use strict";return function(e){function t(e){return"(?:"+e+")?"}var n="(decltype\\(auto\\)|"+t("[a-zA-Z_]\\w*::")+"[a-zA-Z_]\\w*"+t("<.*?>")+")",r={className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},a={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},{begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\((?:.|\n)*?\)\1"/}]},s={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},i={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(a,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c={className:"title",begin:t("[a-zA-Z_]\\w*::")+e.IDENT_RE,relevance:0},o=t("[a-zA-Z_]\\w*::")+e.IDENT_RE+"\\s*\\(",l={keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary",literal:"true false nullptr NULL"},d=[r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,a],_={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:l,contains:d.concat([{begin:/\(/,end:/\)/,keywords:l,contains:d.concat(["self"]),relevance:0}]),relevance:0},u={className:"function",begin:"("+n+"[\\*&\\s]+)+"+o,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:l,illegal:/[^\w\s\*&:<>]/,contains:[{begin:"decltype\\(auto\\)",keywords:l,relevance:0},{begin:o,returnBegin:!0,contains:[c],relevance:0},{className:"params",begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,s,r,{begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,s,r]}]},r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,i]};return{aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:l,disableAutodetect:!0,illegal:"",keywords:l,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:l},{className:"class",beginKeywords:"class struct",end:/[{;:]/,contains:[{begin://,contains:["self"]},e.TITLE_MODE]}]),exports:{preprocessor:i,strings:a,keywords:l}}}}());hljs.registerLanguage("cpp",function(){"use strict";return function(e){var t=e.getLanguage("c-like").rawDefinition();return t.disableAutodetect=!1,t.name="C++",t.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],t}}());hljs.registerLanguage("coffeescript",function(){"use strict";return function(e){var n={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super yield import export from as default await then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",built_in:"npm require console print module global window document"},i="[A-Za-z$_][0-9A-Za-z$_]*",s={className:"subst",begin:/#\{/,end:/}/,keywords:n},a=[e.BINARY_NUMBER_MODE,e.inherit(e.C_NUMBER_MODE,{starts:{end:"(\\s*/)?",relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[e.BACKSLASH_ESCAPE]},{begin:/"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,s]},{begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s]}]},{className:"regexp",variants:[{begin:"///",end:"///",contains:[s,e.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)",relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+i},{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{begin:"```",end:"```"},{begin:"`",end:"`"}]}];s.contains=a;var t=e.inherit(e.TITLE_MODE,{begin:i}),r={className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/,end:/\)/,keywords:n,contains:["self"].concat(a)}]};return{name:"CoffeeScript",aliases:["coffee","cson","iced"],keywords:n,illegal:/\/\*/,contains:a.concat([e.COMMENT("###","###"),e.HASH_COMMENT_MODE,{className:"function",begin:"^\\s*"+i+"\\s*=\\s*(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[t,r]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function",begin:"(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[r]}]},{className:"class",beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[t]},t]},{begin:i+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}());hljs.registerLanguage("javascript",function(){"use strict";return function(e){var n={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/},a="[A-Za-z$_][0-9A-Za-z$_]*",s={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},r={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:e.C_NUMBER_RE+"n?"}],relevance:0},i={className:"subst",begin:"\\$\\{",end:"\\}",keywords:s,contains:[]},t={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,i],subLanguage:"xml"}},c={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,i],subLanguage:"css"}},o={className:"string",begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,i]};i.contains=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,t,c,o,r,e.REGEXP_MODE];var l=i.contains.concat([e.C_BLOCK_COMMENT_MODE,e.C_LINE_COMMENT_MODE]),d={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:l};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:s,contains:[{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},{className:"meta",begin:/^#!/,end:/$/},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,t,c,o,e.C_LINE_COMMENT_MODE,e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:a+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),e.C_BLOCK_COMMENT_MODE,r,{begin:/[{,\n]\s*/,relevance:0,contains:[{begin:a+"\\s*:",returnBegin:!0,relevance:0,contains:[{className:"attr",begin:a,relevance:0}]}]},{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.REGEXP_MODE,{className:"function",begin:"(\\(.*?\\)|"+a+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:a},{begin:/\(\s*\)/},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:s,contains:l}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:"<>",end:""},{begin:n.begin,end:n.end}],subLanguage:"xml",contains:[{begin:n.begin,end:n.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:a}),d],illegal:/\[|%/},{begin:/\$[(.]/},e.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0},{begin:"(get|set)\\s+(?="+a+"\\()",end:/{/,keywords:"get set",contains:[e.inherit(e.TITLE_MODE,{begin:a}),{begin:/\(\)/},d]}],illegal:/#(?!!)/}}}());hljs.registerLanguage("c",function(){"use strict";return function(e){var n=e.getLanguage("c-like").rawDefinition();return n.name="C",n.aliases=["c","h"],n}}());hljs.registerLanguage("plaintext",function(){"use strict";return function(t){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}()); \ No newline at end of file +var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!n.hasOwnProperty(r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach((function(e){for(n in e)t[n]=e[n]})),t}function r(e){return e.nodeName.toLowerCase()}var a=Object.freeze({__proto__:null,escapeHTML:n,inherit:t,nodeStream:function(e){var n=[];return function e(t,a){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=e(i,a),r(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n},mergeStreams:function(e,t,a){var i=0,s="",o=[];function l(){return e.length&&t.length?e[0].offset!==t[0].offset?e[0].offset"}function u(e){s+=""}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||t.length;){var g=l();if(s+=n(a.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+n(a.substr(i))}});const i="
",s=e=>!!e.kind;class o{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=n(e)}openNode(e){if(!s(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){s(e)&&(this.buffer+=i)}span(e){this.buffer+=``}value(){return this.buffer}}class l{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){let n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){e.children&&(e.children.every(e=>"string"==typeof e)?(e.text=e.children.join(""),delete e.children):e.children.forEach(e=>{"string"!=typeof e&&l._collapse(e)}))}}class c extends l{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){let t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new o(this,this.options).value()}finalize(){}}function u(e){return e&&e.source||e}const d="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",g={begin:"\\\\[\\s\\S]",relevance:0},h={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[g]},f={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[g]},p={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,r){var a=t({className:"comment",begin:e,end:n,contains:[]},r||{});return a.contains.push(p),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|XXX):",relevance:0}),a},b=m("//","$"),v=m("/\\*","\\*/"),x=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:d,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",BACKSLASH_ESCAPE:g,APOS_STRING_MODE:h,QUOTE_STRING_MODE:f,PHRASAL_WORDS_MODE:p,COMMENT:m,C_LINE_COMMENT_MODE:b,C_BLOCK_COMMENT_MODE:v,HASH_COMMENT_MODE:x,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:d,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^\/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[g,{begin:/\[/,end:/\]/,relevance:0,contains:[g]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0}}),E="of and for in not or if then".split(" ");function R(e,n){return n?+n:(t=e,E.includes(t.toLowerCase())?0:1);var t}const N=n,w=t,{nodeStream:y,mergeStreams:O}=a;return function(n){var r=[],a={},i={},s=[],o=!0,l=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,d="Could not find the language '{}', did you forget to load/include a language module?",g={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0,__emitter:c};function h(e){return g.noHighlightRe.test(e)}function f(e,n,t,r){var a={code:n,language:e};T("before:highlight",a);var i=a.result?a.result:p(a.language,a.code,t,r);return i.code=a.code,T("after:highlight",i),i}function p(e,n,r,i){var s=n;function l(e,n){var t=v.case_insensitive?n[0].toLowerCase():n[0];return e.keywords.hasOwnProperty(t)&&e.keywords[t]}function c(){null!=_.subLanguage?function(){if(""!==k){var e="string"==typeof _.subLanguage;if(!e||a[_.subLanguage]){var n=e?p(_.subLanguage,k,!0,E[_.subLanguage]):m(k,_.subLanguage.length?_.subLanguage:void 0);_.relevance>0&&(T+=n.relevance),e&&(E[_.subLanguage]=n.top),w.addSublanguage(n.emitter,n.language)}else w.addText(k)}}():function(){var e,n,t,r;if(_.keywords){for(n=0,_.lexemesRe.lastIndex=0,t=_.lexemesRe.exec(k),r="";t;){r+=k.substring(n,t.index);var a=null;(e=l(_,t))?(w.addText(r),r="",T+=e[1],a=e[0],w.addKeyword(t[0],a)):r+=t[0],n=_.lexemesRe.lastIndex,t=_.lexemesRe.exec(k)}r+=k.substr(n),w.addText(r)}else w.addText(k)}(),k=""}function h(e){e.className&&w.openNode(e.className),_=Object.create(e,{parent:{value:_}})}var f={};function b(n,t){var a,i=t&&t[0];if(k+=n,null==i)return c(),0;if("begin"==f.type&&"end"==t.type&&f.index==t.index&&""===i){if(k+=s.slice(t.index,t.index+1),!o)throw(a=Error("0 width match regex")).languageName=e,a.badRule=f.rule,a;return 1}if(f=t,"begin"===t.type)return function(e){var n=e[0],t=e.rule;return t.__onBegin&&(t.__onBegin(e)||{}).ignoreMatch?function(e){return 0===_.matcher.regexIndex?(k+=e[0],1):(B=!0,0)}(n):(t&&t.endSameAsBegin&&(t.endRe=RegExp(n.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),t.skip?k+=n:(t.excludeBegin&&(k+=n),c(),t.returnBegin||t.excludeBegin||(k=n)),h(t),t.returnBegin?0:n.length)}(t);if("illegal"===t.type&&!r)throw(a=Error('Illegal lexeme "'+i+'" for mode "'+(_.className||"")+'"')).mode=_,a;if("end"===t.type){var l=function(e){var n=e[0],t=s.substr(e.index),r=function e(n,t){if(function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(n.endRe,t)){for(;n.endsParent&&n.parent;)n=n.parent;return n}if(n.endsWithParent)return e(n.parent,t)}(_,t);if(r){var a=_;a.skip?k+=n:(a.returnEnd||a.excludeEnd||(k+=n),c(),a.excludeEnd&&(k=n));do{_.className&&w.closeNode(),_.skip||_.subLanguage||(T+=_.relevance),_=_.parent}while(_!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.endRe=r.endRe),h(r.starts)),a.returnEnd?0:n.length}}(t);if(null!=l)return l}if("illegal"===t.type&&""===i)return 1;if(A>1e5&&A>3*t.index)throw Error("potential infinite loop, way more iterations than matches");return k+=i,i.length}var v=M(e);if(!v)throw console.error(d.replace("{}",e)),Error('Unknown language: "'+e+'"');!function(e){function n(n,t){return RegExp(u(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class r{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);let e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+="|"),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"==l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("==l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;let n=this.matcherRe.exec(e);if(!n)return null;let t=n.findIndex((e,n)=>n>0&&null!=e),r=this.matchIndexes[t];return Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];let n=new r;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){let n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;let t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e){let n=e.input[e.index-1],t=e.input[e.index+e[0].length];if("."===n||"."===t)return{ignoreMatch:!0}}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");!function r(s,o){s.compiled||(s.compiled=!0,s.__onBegin=null,s.keywords=s.keywords||s.beginKeywords,s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,R(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemesRe=n(s.lexemes||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__onBegin=i),s.begin||(s.begin=/\B|\b/),s.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(s.endRe=n(s.end)),s.terminator_end=u(s.end)||"",s.endsWithParent&&o.terminator_end&&(s.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(s.illegalRe=n(s.illegal)),null==s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return t(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?t(e,{starts:e.starts?t(e.starts):null}):Object.isFrozen(e)?t(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){r(e,s)})),s.starts&&r(s.starts,o),s.matcher=function(e){let n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(s))}(e)}(v);var x,_=i||v,E={},w=new g.__emitter(g);!function(){for(var e=[],n=_;n!==v;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>w.openNode(e))}();var y,O,k="",T=0,L=0,A=0,B=!1;try{for(_.matcher.considerAll();A++,B?B=!1:(_.matcher.lastIndex=L,_.matcher.considerAll()),y=_.matcher.exec(s);)O=b(s.substring(L,y.index),y),L=y.index+O;return b(s.substr(L)),w.closeAllNodes(),w.finalize(),x=w.toHTML(),{relevance:T,value:x,language:e,illegal:!1,emitter:w,top:_}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:s.slice(L-100,L+100),mode:n.mode},sofar:x,relevance:0,value:N(s),emitter:w};if(o)return{relevance:0,value:N(s),emitter:w,language:e,top:_,errorRaised:n};throw n}}function m(e,n){n=n||g.languages||Object.keys(a);var t=function(e){const n={relevance:0,emitter:new g.__emitter(g),value:N(e),illegal:!1,top:E};return n.emitter.addText(e),n}(e),r=t;return n.filter(M).filter(k).forEach((function(n){var a=p(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function b(e){return g.tabReplace||g.useBR?e.replace(l,(function(e,n){return g.useBR&&"\n"===e?"
":g.tabReplace?n.replace(/\t/g,g.tabReplace):""})):e}function v(e){var n,t,r,a,s,o=function(e){var n,t=e.className+" ";if(t+=e.parentNode?e.parentNode.className:"",n=g.languageDetectRe.exec(t)){var r=M(n[1]);return r||(console.warn(d.replace("{}",n[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?n[1]:"no-highlight"}return t.split(/\s+/).find(e=>h(e)||M(e))}(e);h(o)||(T("before:highlightBlock",{block:e,language:o}),g.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"):n=e,s=n.textContent,r=o?f(o,s,!0):m(s),(t=y(n)).length&&((a=document.createElement("div")).innerHTML=r.value,r.value=O(t,y(a),s)),r.value=b(r.value),T("after:highlightBlock",{block:e,result:r}),e.innerHTML=r.value,e.className=function(e,n,t){var r=n?i[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,o,r.language),e.result={language:r.language,re:r.relevance},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.relevance}))}function x(){if(!x.called){x.called=!0;var e=document.querySelectorAll("pre code");r.forEach.call(e,v)}}const E={disableAutodetect:!0,name:"Plain text"};function M(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]}function k(e){var n=M(e);return n&&!n.disableAutodetect}function T(e,n){var t=e;s.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(n,{highlight:f,highlightAuto:m,fixMarkup:b,highlightBlock:v,configure:function(e){g=w(g,e)},initHighlighting:x,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",x,!1)},registerLanguage:function(e,t){var r;try{r=t(n)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!o)throw n;console.error(n),r=E}r.name||(r.name=e),a[e]=r,r.rawDefinition=t.bind(null,n),r.aliases&&r.aliases.forEach((function(n){i[n]=e}))},listLanguages:function(){return Object.keys(a)},getLanguage:M,requireLanguage:function(e){var n=M(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:k,inherit:w,addPlugin:function(e,n){s.push(e)}}),n.debugMode=function(){o=!1},n.safeMode=function(){o=!0},n.versionString="10.0.3";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(n,_),n}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);hljs.registerLanguage("c-like",function(){"use strict";return function(e){function t(e){return"(?:"+e+")?"}var n="(decltype\\(auto\\)|"+t("[a-zA-Z_]\\w*::")+"[a-zA-Z_]\\w*"+t("<.*?>")+")",r={className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},a={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},{begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\((?:.|\n)*?\)\1"/}]},s={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},i={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(a,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c={className:"title",begin:t("[a-zA-Z_]\\w*::")+e.IDENT_RE,relevance:0},o=t("[a-zA-Z_]\\w*::")+e.IDENT_RE+"\\s*\\(",l={keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary",literal:"true false nullptr NULL"},d=[r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,a],_={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:l,contains:d.concat([{begin:/\(/,end:/\)/,keywords:l,contains:d.concat(["self"]),relevance:0}]),relevance:0},u={className:"function",begin:"("+n+"[\\*&\\s]+)+"+o,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:l,illegal:/[^\w\s\*&:<>]/,contains:[{begin:"decltype\\(auto\\)",keywords:l,relevance:0},{begin:o,returnBegin:!0,contains:[c],relevance:0},{className:"params",begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,s,r,{begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,s,r]}]},r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,i]};return{aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:l,disableAutodetect:!0,illegal:"",keywords:l,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:l},{className:"class",beginKeywords:"class struct",end:/[{;:]/,contains:[{begin://,contains:["self"]},e.TITLE_MODE]}]),exports:{preprocessor:i,strings:a,keywords:l}}}}());hljs.registerLanguage("cpp",function(){"use strict";return function(e){var t=e.getLanguage("c-like").rawDefinition();return t.disableAutodetect=!1,t.name="C++",t.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],t}}());hljs.registerLanguage("xml",function(){"use strict";return function(e){var n={className:"symbol",begin:"&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;"},a={begin:"\\s",contains:[{className:"meta-keyword",begin:"#?[a-z_][a-z1-9_-]+",illegal:"\\n"}]},s=e.inherit(a,{begin:"\\(",end:"\\)"}),t=e.inherit(e.APOS_STRING_MODE,{className:"meta-string"}),i=e.inherit(e.QUOTE_STRING_MODE,{className:"meta-string"}),c={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin:"",relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{className:"meta",begin:"",contains:[a,s,i,t]}]}]},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[",end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:")",end:">",keywords:{name:"style"},contains:[c],starts:{end:"",returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:")",end:">",keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}}}());hljs.registerLanguage("markdown",function(){"use strict";return function(n){const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0,relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a];return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c,end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}());hljs.registerLanguage("coffeescript",function(){"use strict";return function(e){var n={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super yield import export from as default await then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",built_in:"npm require console print module global window document"},i="[A-Za-z$_][0-9A-Za-z$_]*",s={className:"subst",begin:/#\{/,end:/}/,keywords:n},a=[e.BINARY_NUMBER_MODE,e.inherit(e.C_NUMBER_MODE,{starts:{end:"(\\s*/)?",relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[e.BACKSLASH_ESCAPE]},{begin:/"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,s]},{begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s]}]},{className:"regexp",variants:[{begin:"///",end:"///",contains:[s,e.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)",relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+i},{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{begin:"```",end:"```"},{begin:"`",end:"`"}]}];s.contains=a;var t=e.inherit(e.TITLE_MODE,{begin:i}),r={className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/,end:/\)/,keywords:n,contains:["self"].concat(a)}]};return{name:"CoffeeScript",aliases:["coffee","cson","iced"],keywords:n,illegal:/\/\*/,contains:a.concat([e.COMMENT("###","###"),e.HASH_COMMENT_MODE,{className:"function",begin:"^\\s*"+i+"\\s*=\\s*(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[t,r]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function",begin:"(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[r]}]},{className:"class",beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[t]},t]},{begin:i+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}());hljs.registerLanguage("bash",function(){"use strict";return function(e){const s={};Object.assign(s,{className:"variable",variants:[{begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:[{begin:/:-/,contains:[s]}]}]});const n={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},t={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,n]};n.contains.push(t);const a={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]};return{name:"Bash",aliases:["sh","zsh"],lexemes:/\b-?[a-z\._]+\b/,keywords:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},contains:[{className:"meta",begin:/^#![^\n]+sh\s*$/,relevance:10},{className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0},a,e.HASH_COMMENT_MODE,t,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}}());hljs.registerLanguage("shell",function(){"use strict";return function(s){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"}}]}}}());hljs.registerLanguage("plaintext",function(){"use strict";return function(t){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}());hljs.registerLanguage("json",function(){"use strict";return function(n){var e={literal:"true false null"},i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/})].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)],illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}());hljs.registerLanguage("javascript",function(){"use strict";return function(e){var n={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/},a="[A-Za-z$_][0-9A-Za-z$_]*",s={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},r={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:e.C_NUMBER_RE+"n?"}],relevance:0},i={className:"subst",begin:"\\$\\{",end:"\\}",keywords:s,contains:[]},t={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,i],subLanguage:"xml"}},c={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,i],subLanguage:"css"}},o={className:"string",begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,i]};i.contains=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,t,c,o,r,e.REGEXP_MODE];var l=i.contains.concat([e.C_BLOCK_COMMENT_MODE,e.C_LINE_COMMENT_MODE]),d={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:l};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:s,contains:[{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},{className:"meta",begin:/^#!/,end:/$/},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,t,c,o,e.C_LINE_COMMENT_MODE,e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:a+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),e.C_BLOCK_COMMENT_MODE,r,{begin:/[{,\n]\s*/,relevance:0,contains:[{begin:a+"\\s*:",returnBegin:!0,relevance:0,contains:[{className:"attr",begin:a,relevance:0}]}]},{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.REGEXP_MODE,{className:"function",begin:"(\\(.*?\\)|"+a+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:a},{begin:/\(\s*\)/},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:s,contains:l}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:"<>",end:""},{begin:n.begin,end:n.end}],subLanguage:"xml",contains:[{begin:n.begin,end:n.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:a}),d],illegal:/\[|%/},{begin:/\$[(.]/},e.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0},{begin:"(get|set)\\s+(?="+a+"\\()",end:/{/,keywords:"get set",contains:[e.inherit(e.TITLE_MODE,{begin:a}),{begin:/\(\)/},d]}],illegal:/#(?!!)/}}}());hljs.registerLanguage("typescript",function(){"use strict";return function(e){var n={keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class public private protected get set super static implements enum export import declare type namespace abstract as from extends async await",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document any number boolean string void Promise"},r={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},a={begin:"\\(",end:/\)/,keywords:n,contains:["self",e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.NUMBER_MODE]},t={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,r,a]},s={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:e.C_NUMBER_RE+"n?"}],relevance:0},i={className:"subst",begin:"\\$\\{",end:"\\}",keywords:n,contains:[]},o={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,i],subLanguage:"xml"}},c={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,i],subLanguage:"css"}},E={className:"string",begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,i]};return i.contains=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,o,c,E,s,e.REGEXP_MODE],{name:"TypeScript",aliases:["ts"],keywords:n,contains:[{className:"meta",begin:/^\s*['"]use strict['"]/},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,o,c,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.REGEXP_MODE,{className:"function",begin:"(\\(.*?\\)|"+e.IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:e.IDENT_RE},{begin:/\(\s*\)/},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]}]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[\{;]/,excludeEnd:!0,keywords:n,contains:["self",e.inherit(e.TITLE_MODE,{begin:"[A-Za-z$_][0-9A-Za-z$_]*"}),t],illegal:/%/,relevance:0},{beginKeywords:"constructor",end:/[\{;]/,excludeEnd:!0,contains:["self",t]},{begin:/module\./,keywords:{built_in:"module"},relevance:0},{beginKeywords:"module",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:"interface extends"},{begin:/\$[(.]/},{begin:"\\."+e.IDENT_RE,relevance:0},r,a]}}}());hljs.registerLanguage("c",function(){"use strict";return function(e){var n=e.getLanguage("c-like").rawDefinition();return n.name="C",n.aliases=["c","h"],n}}());hljs.registerLanguage("http",function(){"use strict";return function(e){var n="HTTP/[0-9\\.]+";return{name:"HTTP",aliases:["https"],illegal:"\\S",contains:[{begin:"^"+n,end:"$",contains:[{className:"number",begin:"\\b\\d{3}\\b"}]},{begin:"^[A-Z]+ (.*?) "+n+"$",returnBegin:!0,end:"$",contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{begin:n},{className:"keyword",begin:"[A-Z]+"}]},{className:"attribute",begin:"^\\w",end:": ",excludeEnd:!0,illegal:"\\n|\\s|=",starts:{end:"$",relevance:0}},{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}]}}}()); \ No newline at end of file diff --git a/doc/api_assets/hljs.css b/doc/api_assets/hljs.css index de798089557c55..e944148b835ee2 100644 --- a/doc/api_assets/hljs.css +++ b/doc/api_assets/hljs.css @@ -7,6 +7,7 @@ color: #333; } +.hljs-attribute, .hljs-keyword { color: #338; } From e33c09cb3ac9bd099037b413e0e6b21851e0bc6a Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 30 Jun 2020 21:44:32 -0700 Subject: [PATCH 027/138] doc: simplify and clarify ReferenceError material in errors.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "should always be considered" -> "indicate" PR-URL: https://github.com/nodejs/node/pull/34151 Reviewed-By: Luigi Pinca Reviewed-By: Anto Aravinth Reviewed-By: Christian Clauss Reviewed-By: Gerhard Stöbich Reviewed-By: Chengzhong Wu Reviewed-By: Andrey Pechkurov --- doc/api/errors.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/api/errors.md b/doc/api/errors.md index d59c4029e60e5e..e768c98578e053 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -391,8 +391,7 @@ doesNotExist; ``` Unless an application is dynamically generating and running code, -`ReferenceError` instances should always be considered a bug in the code -or its dependencies. +`ReferenceError` instances indicate a bug in the code or its dependencies. ## Class: `SyntaxError` From 7fc56ebd0d01d84b15c5fe7143b2a89779ab13ee Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 30 Jun 2020 21:48:16 -0700 Subject: [PATCH 028/138] doc: remove "considered" in errors.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "would be considered a `TypeError`" -> "would be a `TypeError`". Using "considered" introduces unnecessary ambiguity. Is is not actually a TypeError but merely "considered" one? Why is that? We don't say. Simplify to "is a TypeError". PR-URL: https://github.com/nodejs/node/pull/34152 Reviewed-By: Luigi Pinca Reviewed-By: Christian Clauss Reviewed-By: Matteo Collina Reviewed-By: Gerhard Stöbich Reviewed-By: Andrey Pechkurov Reviewed-By: Vladimir de Turckheim Reviewed-By: Benjamin Gruenbaum --- doc/api/errors.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/api/errors.md b/doc/api/errors.md index e768c98578e053..3efe6bcd47d712 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -562,8 +562,7 @@ program. For a comprehensive list, see the [`errno`(3) man page][]. * Extends {errors.Error} Indicates that a provided argument is not an allowable type. For example, -passing a function to a parameter which expects a string would be considered -a `TypeError`. +passing a function to a parameter which expects a string would be a `TypeError`. ```js require('url').parse(() => { }); From f5691fa6b66ee0b978855514926c1e3387ad568f Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Tue, 30 Jun 2020 09:55:27 -0400 Subject: [PATCH 029/138] test: report actual error code on failure Add a custom message to parallel/test-dgram-error-message-address so that the actual error code that doesn't match the allowed errors is output on assertion failure. PR-URL: https://github.com/nodejs/node/pull/34134 Reviewed-By: Gireesh Punathil Reviewed-By: Anna Henningsen Reviewed-By: Shelley Vohr Reviewed-By: Trivikram Kamat Reviewed-By: Jiawen Geng --- test/parallel/test-dgram-error-message-address.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-dgram-error-message-address.js b/test/parallel/test-dgram-error-message-address.js index 859ee560c34c01..cf243ed2e8560a 100644 --- a/test/parallel/test-dgram-error-message-address.js +++ b/test/parallel/test-dgram-error-message-address.js @@ -47,7 +47,7 @@ socket_ipv6.on('listening', common.mustNotCall()); socket_ipv6.on('error', common.mustCall(function(e) { // EAFNOSUPPORT or EPROTONOSUPPORT means IPv6 is disabled on this system. const allowed = ['EADDRNOTAVAIL', 'EAFNOSUPPORT', 'EPROTONOSUPPORT']; - assert(allowed.includes(e.code)); + assert(allowed.includes(e.code), `'${e.code}' was not one of ${allowed}.`); assert.strictEqual(e.port, undefined); assert.strictEqual(e.message, `bind ${e.code} 111::1`); assert.strictEqual(e.address, '111::1'); From cfd4c8012d04d68212d95e760efd67a0a0a2b997 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 30 Jun 2020 22:36:10 +0200 Subject: [PATCH 030/138] crypto: move typechecking for timingSafeEqual into C++ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the function more robust against V8 inlining. Fixes: https://github.com/nodejs/node/issues/34073 PR-URL: https://github.com/nodejs/node/pull/34141 Reviewed-By: Richard Lau Reviewed-By: Ujjwal Sharma Reviewed-By: Ben Noordhuis Reviewed-By: Tobias Nießen Reviewed-By: Rich Trott Reviewed-By: Zeyu Yang --- lib/crypto.js | 7 +++-- lib/internal/crypto/util.js | 18 ------------- lib/internal/errors.js | 2 -- src/node_crypto.cc | 26 ++++++++++++++++--- src/node_errors.h | 3 +++ .../test-crypto-timing-safe-equal.js | 4 +-- 6 files changed, 33 insertions(+), 27 deletions(-) diff --git a/lib/crypto.js b/lib/crypto.js index 5e45a1cd987260..e4b9d479a50671 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -44,7 +44,11 @@ const { getOptionValue } = require('internal/options'); const pendingDeprecation = getOptionValue('--pending-deprecation'); const { fipsMode } = internalBinding('config'); const fipsForced = getOptionValue('--force-fips'); -const { getFipsCrypto, setFipsCrypto } = internalBinding('crypto'); +const { + getFipsCrypto, + setFipsCrypto, + timingSafeEqual, +} = internalBinding('crypto'); const { randomBytes, randomFill, @@ -101,7 +105,6 @@ const { getHashes, setDefaultEncoding, setEngine, - timingSafeEqual } = require('internal/crypto/util'); const Certificate = require('internal/crypto/certificate'); diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js index 286efc39a61e4f..8d43514906fde8 100644 --- a/lib/internal/crypto/util.js +++ b/lib/internal/crypto/util.js @@ -9,7 +9,6 @@ const { getCurves: _getCurves, getHashes: _getHashes, setEngine: _setEngine, - timingSafeEqual: _timingSafeEqual } = internalBinding('crypto'); const { @@ -20,7 +19,6 @@ const { hideStackFrames, codes: { ERR_CRYPTO_ENGINE_UNKNOWN, - ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, ERR_INVALID_ARG_TYPE, } } = require('internal/errors'); @@ -76,21 +74,6 @@ function setEngine(id, flags) { throw new ERR_CRYPTO_ENGINE_UNKNOWN(id); } -function timingSafeEqual(buf1, buf2) { - if (!isArrayBufferView(buf1)) { - throw new ERR_INVALID_ARG_TYPE('buf1', - ['Buffer', 'TypedArray', 'DataView'], buf1); - } - if (!isArrayBufferView(buf2)) { - throw new ERR_INVALID_ARG_TYPE('buf2', - ['Buffer', 'TypedArray', 'DataView'], buf2); - } - if (buf1.byteLength !== buf2.byteLength) { - throw new ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH(); - } - return _timingSafeEqual(buf1, buf2); -} - const getArrayBufferView = hideStackFrames((buffer, name, encoding) => { if (typeof buffer === 'string') { if (encoding === 'buffer') @@ -116,6 +99,5 @@ module.exports = { kHandle, setDefaultEncoding, setEngine, - timingSafeEqual, toBuf }; diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 2e877edc6a78e3..e43c0006363d13 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -804,8 +804,6 @@ E('ERR_CRYPTO_SCRYPT_INVALID_PARAMETER', 'Invalid scrypt parameter', Error); E('ERR_CRYPTO_SCRYPT_NOT_SUPPORTED', 'Scrypt algorithm not supported', Error); // Switch to TypeError. The current implementation does not seem right. E('ERR_CRYPTO_SIGN_KEY_REQUIRED', 'No key provided to sign', Error); -E('ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH', - 'Input buffers must have the same byte length', RangeError); E('ERR_DIR_CLOSED', 'Directory handle was closed', Error); E('ERR_DIR_CONCURRENT_OPERATION', 'Cannot do synchronous work on directory handle with concurrent ' + diff --git a/src/node_crypto.cc b/src/node_crypto.cc index e34b27b166c5d3..aace8e2c05e915 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -6831,10 +6831,30 @@ void StatelessDiffieHellman(const FunctionCallbackInfo& args) { void TimingSafeEqual(const FunctionCallbackInfo& args) { - ArrayBufferViewContents buf1(args[0]); - ArrayBufferViewContents buf2(args[1]); + // Moving the type checking into JS leads to test failures, most likely due + // to V8 inlining certain parts of the wrapper. Therefore, keep them in C++. + // Refs: https://github.com/nodejs/node/issues/34073. + Environment* env = Environment::GetCurrent(args); + if (!args[0]->IsArrayBufferView()) { + THROW_ERR_INVALID_ARG_TYPE( + env, "The \"buf1\" argument must be an instance of " + "Buffer, TypedArray, or DataView."); + return; + } + if (!args[1]->IsArrayBufferView()) { + THROW_ERR_INVALID_ARG_TYPE( + env, "The \"buf2\" argument must be an instance of " + "Buffer, TypedArray, or DataView."); + return; + } + + ArrayBufferViewContents buf1(args[0].As()); + ArrayBufferViewContents buf2(args[1].As()); - CHECK_EQ(buf1.length(), buf2.length()); + if (buf1.length() != buf2.length()) { + THROW_ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH(env); + return; + } return args.GetReturnValue().Set( CRYPTO_memcmp(buf1.data(), buf2.data(), buf1.length()) == 0); diff --git a/src/node_errors.h b/src/node_errors.h index b9f001d777bb07..45498f3e00463e 100644 --- a/src/node_errors.h +++ b/src/node_errors.h @@ -33,6 +33,7 @@ void OnFatalError(const char* location, const char* message); V(ERR_BUFFER_TOO_LARGE, Error) \ V(ERR_CONSTRUCT_CALL_REQUIRED, TypeError) \ V(ERR_CONSTRUCT_CALL_INVALID, TypeError) \ + V(ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, RangeError) \ V(ERR_CRYPTO_UNKNOWN_CIPHER, Error) \ V(ERR_CRYPTO_UNKNOWN_DH_GROUP, Error) \ V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, Error) \ @@ -86,6 +87,8 @@ void OnFatalError(const char* location, const char* message); "Buffer is not available for the current Context") \ V(ERR_CONSTRUCT_CALL_INVALID, "Constructor cannot be called") \ V(ERR_CONSTRUCT_CALL_REQUIRED, "Cannot call constructor without `new`") \ + V(ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, \ + "Input buffers must have the same byte length") \ V(ERR_CRYPTO_UNKNOWN_CIPHER, "Unknown cipher") \ V(ERR_CRYPTO_UNKNOWN_DH_GROUP, "Unknown DH group") \ V(ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE, \ diff --git a/test/sequential/test-crypto-timing-safe-equal.js b/test/sequential/test-crypto-timing-safe-equal.js index f9709ac966d6a1..769b5f7d8810c3 100644 --- a/test/sequential/test-crypto-timing-safe-equal.js +++ b/test/sequential/test-crypto-timing-safe-equal.js @@ -48,7 +48,7 @@ assert.throws( name: 'TypeError', message: 'The "buf1" argument must be an instance of Buffer, TypedArray, or ' + - "DataView. Received type string ('not a buffer')" + 'DataView.' } ); @@ -59,6 +59,6 @@ assert.throws( name: 'TypeError', message: 'The "buf2" argument must be an instance of Buffer, TypedArray, or ' + - "DataView. Received type string ('not a buffer')" + 'DataView.' } ); From bddc99ec7ffd40cde7c82455d3ad01dc0f9cdaf8 Mon Sep 17 00:00:00 2001 From: Xu Meng Date: Mon, 29 Jun 2020 05:54:23 -0500 Subject: [PATCH 031/138] test: skip some IBM i unsupported test cases Issuing a shutdown() on IBM i PASE with parameter SHUT_WR also sends a normal close sequence to the partner program. This leads to timing issues and ECONNRESET failures in some test cases. Refs: https://github.com/libuv/libuv/pull/2782 PR-URL: https://github.com/nodejs/node/pull/34118 Reviewed-By: Richard Lau Reviewed-By: Beth Griggs Reviewed-By: James M Snell --- test/parallel/parallel.status | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index b72cd30775c05c..94d15064b38423 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -65,3 +65,13 @@ test-cluster-shared-leak: SKIP test-http-writable-true-after-close: SKIP test-http2-connect-method: SKIP test-net-error-twice: SKIP +# https://github.com/libuv/libuv/pull/2782 +test-net-allow-half-open: SKIP +test-net-keepalive: SKIP +test-net-persistent-keepalive: SKIP +test-net-socket-close-after-end: SKIP +test-net-socket-connect-without-cb: SKIP +test-net-socket-connecting: SKIP +test-net-socket-ready-without-cb: SKIP +test-net-write-after-end-nt: SKIP +test-tls-env-extra-ca: SKIP \ No newline at end of file From 22c1fbf4cbd4ba5f1a1f66d30660101e901c0712 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Wed, 1 Jul 2020 06:21:48 -0700 Subject: [PATCH 032/138] doc: simply dns.ADDRCONFIG language PR-URL: https://github.com/nodejs/node/pull/34155 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- doc/api/dns.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/api/dns.md b/doc/api/dns.md index 4f5133fea563c2..17edcadebf6996 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -225,10 +225,9 @@ changes: The following flags can be passed as hints to [`dns.lookup()`][]. -* `dns.ADDRCONFIG`: Returned address types are determined by the types -of addresses supported by the current system. For example, IPv4 addresses -are only returned if the current system has at least one IPv4 address -configured. Loopback addresses are not considered. +* `dns.ADDRCONFIG`: Limits returned address types to the types of non-loopback +addresses configured on the system. For example, IPv4 addresses are only +returned if the current system has at least one IPv4 address configured. * `dns.V4MAPPED`: If the IPv6 family was specified, but no IPv6 addresses were found, then return IPv4 mapped IPv6 addresses. It is not supported on some operating systems (e.g FreeBSD 10.1). From 9f0bf5c9e17eaf6ffda5ce48916fd965c15f9959 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Wed, 1 Jul 2020 19:55:46 -0700 Subject: [PATCH 033/138] doc: improve triaging text in issues.md Remove a double negative and many superfluous sentences. The sentiment in the removed material is good, but we already tell people that discussion should be focused, helpful, and professional. Having two extra paragraphs greatly reduces the likelihood that people will read the material. PR-URL: https://github.com/nodejs/node/pull/34164 Reviewed-By: Anto Aravinth Reviewed-By: James M Snell --- doc/guides/contributing/issues.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/doc/guides/contributing/issues.md b/doc/guides/contributing/issues.md index a021e4c8207c7d..5e123f03e10117 100644 --- a/doc/guides/contributing/issues.md +++ b/doc/guides/contributing/issues.md @@ -84,23 +84,11 @@ See [How to create a Minimal, Complete, and Verifiable example](https://stackove ## Triaging a Bug Report -Once an issue has been opened, it is not uncommon for there to be discussion +Once an issue has been opened, it is common for there to be discussion around it. Some contributors may have differing opinions about the issue, including whether the behavior being seen is a bug or a feature. This discussion is part of the process and should be kept focused, helpful, and professional. -Short, clipped responses that provide neither additional context nor supporting -details are not helpful or professional to many. Such responses are simply -annoying and unfriendly. - -Contributors are encouraged to help one another to make forward progress as much -as possible, empowering one another to solve issues collaboratively. If you -choose to comment on an issue that you feel either is not a problem that needs -to be fixed, or if you encounter information in an issue that you feel is -incorrect, explain *why* you feel that way with additional supporting context, -and be willing to be convinced that you may be wrong. By doing so, we can often -reach the correct outcome much faster. - ## Resolving a Bug Report In the vast majority of cases, issues are resolved by opening a Pull Request. From ab6b786e9db046f2fee0211c7f7ef2614dc3da84 Mon Sep 17 00:00:00 2001 From: rickyes Date: Wed, 1 Jul 2020 18:22:53 +0800 Subject: [PATCH 034/138] doc: add streams to the pipeline function signature PR-URL: https://github.com/nodejs/node/pull/34153 Reviewed-By: Robert Nagy Reviewed-By: James M Snell --- doc/api/stream.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/api/stream.md b/doc/api/stream.md index 749593f92c7836..ef3216828573c7 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -1598,6 +1598,7 @@ const cleanup = finished(rs, (err) => { ``` ### `stream.pipeline(source[, ...transforms], destination, callback)` +### `stream.pipeline(streams, callback)` +* `streams` {Stream[]|Iterable[]|AsyncIterable[]|Function[]} * `source` {Stream|Iterable|AsyncIterable|Function} * Returns: {Iterable|AsyncIterable} * `...transforms` {Stream|Function} From e273edf9430e7559b629bd217d8bef9450bb7259 Mon Sep 17 00:00:00 2001 From: rickyes Date: Mon, 22 Jun 2020 21:15:34 +0800 Subject: [PATCH 035/138] doc: Add maxTotalSockets option to agent constructor PR-URL: https://github.com/nodejs/node/pull/34013 Refs: https://github.com/nodejs/node/pull/33617 Reviewed-By: Robert Nagy Reviewed-By: James M Snell --- doc/api/http.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/api/http.md b/doc/api/http.md index a9fedd8c606a47..6e1ea468d0e7ad 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -113,6 +113,9 @@ http.get({ * `section` {string} A string identifying the portion of the application for which the `debuglog` function is being created. +* `callback` {Function} A callback invoked the first time the logging function +is called with a function argument that is a more optimized logging function. * Returns: {Function} The logging function The `util.debuglog()` method is used to create a function that conditionally @@ -121,6 +123,19 @@ FOO-BAR 3257: hi there, it's foo-bar [2333] Multiple comma-separated `section` names may be specified in the `NODE_DEBUG` environment variable: `NODE_DEBUG=fs,net,tls`. +The optional `callback` argument can be used to replace the logging function +with a different function that doesn't have any initialization or +unnecessary wrapping. + +```js +const util = require('util'); +let debuglog = util.debuglog('internals', (debug) => { + // Replace with a logging function that optimizes out + // testing if the section is enabled + debuglog = debug; +}); +``` + ## `util.deprecate(fn, msg[, code])` + +Used when a feature that is not available +to the current platform which is running Node.js is used. + ### `ERR_FS_FILE_TOO_LARGE` @@ -2526,12 +2535,6 @@ while trying to read and parse it. The `--entry-type=...` flag is not compatible with the Node.js REPL. - -#### `ERR_FEATURE_UNAVAILABLE_ON_PLATFORM` - -Used when a feature that is not available -to the current platform which is running Node.js is used. - #### `ERR_STREAM_HAS_STRINGDECODER` From 8f7ed40fc4ca50f3949d2804c5369b3d88706129 Mon Sep 17 00:00:00 2001 From: Nikola Glavina Date: Sun, 5 Jul 2020 23:37:01 +0200 Subject: [PATCH 056/138] src: fix unused namespace member C++ linter fails because of unused ArrayBuffer namespace member PR-URL: https://github.com/nodejs/node/pull/34212 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Jiawen Geng Reviewed-By: Richard Lau Reviewed-By: Gireesh Punathil --- src/env.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/env.cc b/src/env.cc index bfcee5a6a0f827..1ab9206ce48c8b 100644 --- a/src/env.cc +++ b/src/env.cc @@ -27,7 +27,6 @@ namespace node { using errors::TryCatchScope; -using v8::ArrayBuffer; using v8::Boolean; using v8::Context; using v8::EmbedderGraph; From ed0f5697d8c605930ddc823bb902b041669f304a Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 2 Jul 2020 12:51:00 +0200 Subject: [PATCH 057/138] src: fix minor comment typo in KeyObjectData MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/34167 Reviewed-By: Anna Henningsen Reviewed-By: Richard Lau Reviewed-By: Tobias Nießen Reviewed-By: David Carlier --- src/node_crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_crypto.h b/src/node_crypto.h index a61089f0f131c0..63468e4f18dad1 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -420,7 +420,7 @@ class KeyObjectData { KeyType GetKeyType() const; // These functions allow unprotected access to the raw key material and should - // only be used to implement cryptograohic operations requiring the key. + // only be used to implement cryptographic operations requiring the key. ManagedEVPPKey GetAsymmetricKey() const; const char* GetSymmetricKey() const; size_t GetSymmetricKeySize() const; From b20e6ed94ef7b6318f3a642e3982b46586203a8e Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 4 Jul 2020 06:32:56 -0700 Subject: [PATCH 058/138] repl: fix verb conjugation in deprecation message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/34198 Reviewed-By: Michaël Zasso Reviewed-By: Ruben Bridgewater Reviewed-By: Zeyu Yang Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- lib/repl.js | 8 ++++---- test/parallel/test-repl-options.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index f526dffcf7e5a0..26376a43c56d66 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -225,13 +225,13 @@ function REPLServer(prompt, ObjectDefineProperty(this, 'inputStream', { get: pendingDeprecation ? deprecate(() => this.input, - 'repl.inputStream and repl.outputStream is deprecated. ' + + 'repl.inputStream and repl.outputStream are deprecated. ' + 'Use repl.input and repl.output instead', 'DEP0141') : () => this.input, set: pendingDeprecation ? deprecate((val) => this.input = val, - 'repl.inputStream and repl.outputStream is deprecated. ' + + 'repl.inputStream and repl.outputStream are deprecated. ' + 'Use repl.input and repl.output instead', 'DEP0141') : (val) => this.input = val, @@ -241,13 +241,13 @@ function REPLServer(prompt, ObjectDefineProperty(this, 'outputStream', { get: pendingDeprecation ? deprecate(() => this.output, - 'repl.inputStream and repl.outputStream is deprecated. ' + + 'repl.inputStream and repl.outputStream are deprecated. ' + 'Use repl.input and repl.output instead', 'DEP0141') : () => this.output, set: pendingDeprecation ? deprecate((val) => this.output = val, - 'repl.inputStream and repl.outputStream is deprecated. ' + + 'repl.inputStream and repl.outputStream are deprecated. ' + 'Use repl.input and repl.output instead', 'DEP0141') : (val) => this.output = val, diff --git a/test/parallel/test-repl-options.js b/test/parallel/test-repl-options.js index cb7b2f08b65468..ca3cf2a3a4b3af 100644 --- a/test/parallel/test-repl-options.js +++ b/test/parallel/test-repl-options.js @@ -35,7 +35,7 @@ common.expectWarning({ DeprecationWarning: { DEP0142: 'repl._builtinLibs is deprecated. Check module.builtinModules instead', - DEP0141: 'repl.inputStream and repl.outputStream is deprecated. ' + + DEP0141: 'repl.inputStream and repl.outputStream are deprecated. ' + 'Use repl.input and repl.output instead', DEP0124: 'REPLServer.rli is deprecated', } From 09faebd9ad14f7db7659a36a0f927e6f5f4d1f01 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 4 Jul 2020 06:53:01 -0700 Subject: [PATCH 059/138] test: replace deprecated function call from test-repl-history-navigation test-repl-history-navigation fails with NODE_PENDING_DEPRECATION=1. Replace deprecated repl.inputStream with repl.input. PR-URL: https://github.com/nodejs/node/pull/34199 Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- test/parallel/test-repl-history-navigation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-repl-history-navigation.js b/test/parallel/test-repl-history-navigation.js index 9155ad722b8710..fa40ac624000f4 100644 --- a/test/parallel/test-repl-history-navigation.js +++ b/test/parallel/test-repl-history-navigation.js @@ -596,7 +596,7 @@ function runTest() { enumerable: true }); } - repl.inputStream.run(opts.test); + repl.input.run(opts.test); }); } From 2e20cd4fde46e190a96e007c2ffec48670e5a1a3 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 4 Jul 2020 06:26:30 -0700 Subject: [PATCH 060/138] doc: remove errors that were never released Refs: https://github.com/nodejs/node/pull/33764#issuecomment-653667275 PR-URL: https://github.com/nodejs/node/pull/34197 Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- doc/api/errors.md | 72 ----------------------------------------------- 1 file changed, 72 deletions(-) diff --git a/doc/api/errors.md b/doc/api/errors.md index 4dda1105dd8218..1a6f7141891b4e 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -2487,78 +2487,6 @@ removed: v10.0.0 Used when an attempt is made to use a `zlib` object after it has already been closed. -### Other error codes - -These errors have never been released, but had been present on master between -releases. - - -#### `ERR_ENTRY_TYPE_MISMATCH` - -The `--entry-type=commonjs` flag was used to attempt to execute an `.mjs` file -or a `.js` file where the nearest parent `package.json` contains -`"type": "module"`; or -the `--entry-type=module` flag was used to attempt to execute a `.cjs` file or -a `.js` file where the nearest parent `package.json` either lacks a `"type"` -field or contains `"type": "commonjs"`. - - -#### `ERR_FS_WATCHER_ALREADY_STARTED` - -An attempt was made to start a watcher returned by `fs.watch()` that has -already been started. - - -#### `ERR_FS_WATCHER_NOT_STARTED` - -An attempt was made to initiate operations on a watcher returned by -`fs.watch()` that has not yet been started. - - -#### `ERR_HTTP2_ALREADY_SHUTDOWN` - -Occurs with multiple attempts to shutdown an HTTP/2 session. - - -#### `ERR_HTTP2_ERROR` - -A non-specific HTTP/2 error has occurred. - - -#### `ERR_INVALID_REPL_HISTORY` - -Used in the `repl` in case the old history file is used and an error occurred -while trying to read and parse it. - - -#### `ERR_INVALID_REPL_TYPE` - -The `--entry-type=...` flag is not compatible with the Node.js REPL. - - -#### `ERR_STREAM_HAS_STRINGDECODER` - -Used to prevent an abort if a string decoder was set on the Socket. - -```js -const Socket = require('net').Socket; -const instance = new Socket(); - -instance.setEncoding('utf8'); -``` - - -#### `ERR_STRING_TOO_LARGE` - -An attempt has been made to create a string larger than the maximum allowed -size. - - -#### `ERR_TTY_WRITABLE_NOT_READABLE` - -This `Error` is thrown when a read is attempted on a TTY `WriteStream`, -such as `process.stdout.on('data')`. - [`'uncaughtException'`]: process.html#process_event_uncaughtexception [`--disable-proto=throw`]: cli.html#cli_disable_proto_mode [`--force-fips`]: cli.html#cli_force_fips From abfab9892beb374bf31787ba80fe1350192ed558 Mon Sep 17 00:00:00 2001 From: sapics Date: Tue, 30 Jun 2020 00:16:11 +0900 Subject: [PATCH 061/138] doc: replace http to https of link urls PR-URL: https://github.com/nodejs/node/pull/34158 Reviewed-By: Anna Henningsen Reviewed-By: Anto Aravinth Reviewed-By: James M Snell --- doc/api/cli.md | 2 +- doc/api/dns.md | 4 ++-- doc/api/errors.md | 6 +++--- doc/api/esm.md | 8 ++++---- doc/api/fs.md | 2 +- doc/api/n-api.md | 4 ++-- doc/api/net.md | 2 +- doc/api/process.md | 2 +- doc/changelogs/CHANGELOG_ARCHIVE.md | 6 +++--- doc/changelogs/CHANGELOG_IOJS.md | 2 +- doc/guides/cpp-style-guide.md | 12 ++++++------ doc/guides/maintaining-icu.md | 4 ++-- doc/guides/maintaining-openssl.md | 2 +- doc/guides/writing-tests.md | 2 +- 14 files changed, 29 insertions(+), 29 deletions(-) diff --git a/doc/api/cli.md b/doc/api/cli.md index 10bfefeee14b14..4c5d8b4d36d690 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -1545,5 +1545,5 @@ $ node --max-old-space-size=1536 index.js [emit_warning]: process.html#process_process_emitwarning_warning_type_code_ctor [experimental ECMAScript Module loader]: esm.html#esm_experimental_loaders [jitless]: https://v8.dev/blog/jitless -[libuv threadpool documentation]: http://docs.libuv.org/en/latest/threadpool.html +[libuv threadpool documentation]: https://docs.libuv.org/en/latest/threadpool.html [remote code execution]: https://www.owasp.org/index.php/Code_Injection diff --git a/doc/api/dns.md b/doc/api/dns.md index 17edcadebf6996..5d55e33c7d1553 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -616,7 +616,7 @@ The [`dns.setServers()`][] method affects only [`dns.resolve()`][], [`dns.lookup()`][]). This method works much like -[resolve.conf](http://man7.org/linux/man-pages/man5/resolv.conf.5.html). +[resolve.conf](https://man7.org/linux/man-pages/man5/resolv.conf.5.html). That is, if attempting to resolve with the first server provided results in a `NOTFOUND` error, the `resolve()` method will *not* attempt to resolve with subsequent servers provided. Fallback DNS servers will only be used if the @@ -1080,7 +1080,7 @@ The `dnsPromises.setServers()` method must not be called while a DNS query is in progress. This method works much like -[resolve.conf](http://man7.org/linux/man-pages/man5/resolv.conf.5.html). +[resolve.conf](https://man7.org/linux/man-pages/man5/resolv.conf.5.html). That is, if attempting to resolve with the first server provided results in a `NOTFOUND` error, the `resolve()` method will *not* attempt to resolve with subsequent servers provided. Fallback DNS servers will only be used if the diff --git a/doc/api/errors.md b/doc/api/errors.md index 1a6f7141891b4e..660d0d539672fa 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -2508,7 +2508,7 @@ closed. [`dgram.createSocket()`]: dgram.html#dgram_dgram_createsocket_options_callback [`dgram.disconnect()`]: dgram.html#dgram_socket_disconnect [`dgram.remoteAddress()`]: dgram.html#dgram_socket_remoteaddress -[`errno`(3) man page]: http://man7.org/linux/man-pages/man3/errno.3.html +[`errno`(3) man page]: https://man7.org/linux/man-pages/man3/errno.3.html [`fs.Dir`]: fs.html#fs_class_fs_dir [`fs.readFileSync`]: fs.html#fs_fs_readfilesync_path_options [`fs.readdir`]: fs.html#fs_fs_readdir_path_options_callback @@ -2520,7 +2520,7 @@ closed. [`hash.update()`]: crypto.html#crypto_hash_update_data_inputencoding [`http`]: http.html [`https`]: https.html -[`libuv Error handling`]: http://docs.libuv.org/en/v1.x/errors.html +[`libuv Error handling`]: https://docs.libuv.org/en/v1.x/errors.html [`net`]: net.html [`new URL(input)`]: url.html#url_new_url_input_base [`new URLSearchParams(iterable)`]: url.html#url_new_urlsearchparams_iterable @@ -2554,7 +2554,7 @@ closed. [file descriptors]: https://en.wikipedia.org/wiki/File_descriptor [policy]: policy.html [stream-based]: stream.html -[syscall]: http://man7.org/linux/man-pages/man2/syscalls.2.html +[syscall]: https://man7.org/linux/man-pages/man2/syscalls.2.html [Subresource Integrity specification]: https://www.w3.org/TR/SRI/#the-integrity-attribute [try-catch]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch [vm]: vm.html diff --git a/doc/api/esm.md b/doc/api/esm.md index c06ba4782af884..75a7c07ddbcbe3 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -1817,11 +1817,11 @@ success! [`module.createRequire()`]: modules.html#modules_module_createrequire_filename [`module.syncBuiltinESMExports()`]: modules.html#modules_module_syncbuiltinesmexports [`transformSource` hook]: #esm_code_transformsource_code_hook -[ArrayBuffer]: http://www.ecma-international.org/ecma-262/6.0/#sec-arraybuffer-constructor +[ArrayBuffer]: https://www.ecma-international.org/ecma-262/6.0/#sec-arraybuffer-constructor [SharedArrayBuffer]: https://tc39.es/ecma262/#sec-sharedarraybuffer-constructor -[string]: http://www.ecma-international.org/ecma-262/6.0/#sec-string-constructor -[TypedArray]: http://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects -[Uint8Array]: http://www.ecma-international.org/ecma-262/6.0/#sec-uint8array +[string]: https://www.ecma-international.org/ecma-262/6.0/#sec-string-constructor +[TypedArray]: https://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects +[Uint8Array]: https://www.ecma-international.org/ecma-262/6.0/#sec-uint8array [`util.TextDecoder`]: util.html#util_class_util_textdecoder [import an ES or CommonJS module for its side effects only]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Import_a_module_for_its_side_effects_only [special scheme]: https://url.spec.whatwg.org/#special-scheme diff --git a/doc/api/fs.md b/doc/api/fs.md index f7014ec7c7d9c3..150707df3bf6ce 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -5909,7 +5909,7 @@ the file contents. [`fsPromises.open()`]: #fs_fspromises_open_path_flags_mode [`fsPromises.opendir()`]: #fs_fspromises_opendir_path_options [`fsPromises.utimes()`]: #fs_fspromises_utimes_path_atime_mtime -[`inotify(7)`]: http://man7.org/linux/man-pages/man7/inotify.7.html +[`inotify(7)`]: https://man7.org/linux/man-pages/man7/inotify.7.html [`kqueue(2)`]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 [`net.Socket`]: net.html#net_class_net_socket [`stat()`]: fs.html#fs_fs_stat_path_options_callback diff --git a/doc/api/n-api.md b/doc/api/n-api.md index d75df50a8747bd..1c90c110104f17 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -5533,8 +5533,8 @@ This API may only be called from the main thread. [`napi_wrap`]: #n_api_napi_wrap [`node_api.h`]: https://github.com/nodejs/node/blob/master/src/node_api.h [`process.release`]: process.html#process_process_release -[`uv_ref`]: http://docs.libuv.org/en/v1.x/handle.html#c.uv_ref -[`uv_unref`]: http://docs.libuv.org/en/v1.x/handle.html#c.uv_unref +[`uv_ref`]: https://docs.libuv.org/en/v1.x/handle.html#c.uv_ref +[`uv_unref`]: https://docs.libuv.org/en/v1.x/handle.html#c.uv_unref [async_hooks `type`]: async_hooks.html#async_hooks_type [context-aware addons]: addons.html#addons_context_aware_addons [docs]: https://github.com/nodejs/node-addon-api#api-documentation diff --git a/doc/api/net.md b/doc/api/net.md index 6c9e0468cef3c8..cff82deeb0be11 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -1267,7 +1267,7 @@ Returns `true` if input is a version 6 IP address, otherwise returns `false`. [`server.listen(handle)`]: #net_server_listen_handle_backlog_callback [`server.listen(options)`]: #net_server_listen_options_callback [`server.listen(path)`]: #net_server_listen_path_backlog_callback -[`socket(7)`]: http://man7.org/linux/man-pages/man7/socket.7.html +[`socket(7)`]: https://man7.org/linux/man-pages/man7/socket.7.html [`socket.connect()`]: #net_socket_connect [`socket.connect(options)`]: #net_socket_connect_options_connectlistener [`socket.connect(path)`]: #net_socket_connect_path_connectlistener diff --git a/doc/api/process.md b/doc/api/process.md index 5eb90fe6e79aeb..a07b05d8b262c7 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -2622,6 +2622,6 @@ cases: [process_warning]: #process_event_warning [report documentation]: report.html [terminal raw mode]: tty.html#tty_readstream_setrawmode_mode -[uv_rusage_t]: http://docs.libuv.org/en/v1.x/misc.html#c.uv_rusage_t +[uv_rusage_t]: https://docs.libuv.org/en/v1.x/misc.html#c.uv_rusage_t [wikipedia_minor_fault]: https://en.wikipedia.org/wiki/Page_fault#Minor [wikipedia_major_fault]: https://en.wikipedia.org/wiki/Page_fault#Major diff --git a/doc/changelogs/CHANGELOG_ARCHIVE.md b/doc/changelogs/CHANGELOG_ARCHIVE.md index 55302c99402b76..650d4c6c69cddd 100644 --- a/doc/changelogs/CHANGELOG_ARCHIVE.md +++ b/doc/changelogs/CHANGELOG_ARCHIVE.md @@ -3130,8 +3130,8 @@ https://github.com/nodejs/node/commit/bb0d1e65e1671aaeb21fac186b066701da0bc33b * Major API Changes * Promises removed. See - http://groups.google.com/group/nodejs/msg/426f3071f3eec16b - http://groups.google.com/group/nodejs/msg/df199d233ff17efa + https://groups.google.com/group/nodejs/msg/426f3071f3eec16b + https://groups.google.com/group/nodejs/msg/df199d233ff17efa The API for fs was fs.readdir("/usr").addCallback(function (files) { puts("/usr files: " + files); @@ -3718,7 +3718,7 @@ https://github.com/nodejs/node/commit/77d407df2826b20e9177c26c0d2bb4481e497937 * Move EventEmitter.prototype.emit() completely into C++. * Bugfix: Fix memory leak in event emitters. - http://groups.google.com/group/nodejs/browse_thread/thread/a8d1dfc2fd57a6d1 + https://groups.google.com/group/nodejs/browse_thread/thread/a8d1dfc2fd57a6d1 * Bugfix: Had problems reading scripts with non-ascii characters. * Bugfix: Fix Detach() in node::Server diff --git a/doc/changelogs/CHANGELOG_IOJS.md b/doc/changelogs/CHANGELOG_IOJS.md index 0a650253182b6d..540e244f1139a9 100644 --- a/doc/changelogs/CHANGELOG_IOJS.md +++ b/doc/changelogs/CHANGELOG_IOJS.md @@ -408,7 +408,7 @@ See https://github.com/nodejs/io.js/labels/confirmed-bug for complete and curren * **dgram**: If an error occurs within `socket.send()` and a callback has been provided, the error is only passed as the first argument to the callback and not emitted on the `socket` object; previous behavior was to do both (Matteo Collina & Chris Dickinson) [#1796](https://github.com/nodejs/node/pull/1796) * **freelist**: Deprecate the undocumented `freelist` core module (Sakthipriyan Vairamani) [#2176](https://github.com/nodejs/node/pull/2176). * **http**: - * Status codes now all use the official [IANA names](http://www.iana.org/assignments/http-status-codes) as per [RFC7231](https://tools.ietf.org/html/rfc7231), e.g. `http.STATUS_CODES[414]` now returns `'URI Too Long'` rather than `'Request-URI Too Large'` (jomo) [#1470](https://github.com/nodejs/node/pull/1470). + * Status codes now all use the official [IANA names](https://www.iana.org/assignments/http-status-codes) as per [RFC7231](https://tools.ietf.org/html/rfc7231), e.g. `http.STATUS_CODES[414]` now returns `'URI Too Long'` rather than `'Request-URI Too Large'` (jomo) [#1470](https://github.com/nodejs/node/pull/1470). * Calling .getName() on an HTTP agent no longer returns a trailing colon, HTTPS agents will no longer return an extra colon near the middle of the string (Brendan Ashworth) [#1617](https://github.com/nodejs/node/pull/1617). * **node**: * `NODE_MODULE_VERSION` has been bumped to `45` to reflect the break in ABI (Rod Vagg) [#2096](https://github.com/nodejs/node/pull/2096). diff --git a/doc/guides/cpp-style-guide.md b/doc/guides/cpp-style-guide.md index 85db8e1595aa9c..adf8f0481697f8 100644 --- a/doc/guides/cpp-style-guide.md +++ b/doc/guides/cpp-style-guide.md @@ -391,15 +391,15 @@ side effects. Node.js is built [without C++ exception handling][], so code using `throw` or even `try` and `catch` **will** break. -[C++ Core Guidelines]: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines +[C++ Core Guidelines]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines [Google C++ Style Guide]: https://google.github.io/styleguide/cppguide.html [Google’s `cpplint`]: https://github.com/google/styleguide [errors]: https://github.com/nodejs/node/blob/master/doc/guides/using-internal-errors.md -[ES.47]: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-nullptr -[ES.48]: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts -[ES.49]: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named -[R.20]: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-owner -[R.21]: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-unique +[ES.47]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-nullptr +[ES.48]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts +[ES.49]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named +[R.20]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-owner +[R.21]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-unique [Run Time Type Information]: https://en.wikipedia.org/wiki/Run-time_type_information [cppref_auto_ptr]: https://en.cppreference.com/w/cpp/memory/auto_ptr [without C++ exception handling]: https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html#intro.using.exception.no diff --git a/doc/guides/maintaining-icu.md b/doc/guides/maintaining-icu.md index 083c11ba938481..bf5727d4e865c3 100644 --- a/doc/guides/maintaining-icu.md +++ b/doc/guides/maintaining-icu.md @@ -40,7 +40,7 @@ main data files do not need to be upgraded in order to apply time zone data file fixes. The [IANA tzdata](https://www.iana.org/time-zones) project releases new versions -and announces them on the [`tz-announce`](http://mm.icann.org/pipermail/tz-announce/) +and announces them on the [`tz-announce`](https://mm.icann.org/pipermail/tz-announce/) mailing list. The Unicode project takes new releases and publishes @@ -98,7 +98,7 @@ Node.js is built. * Make sure your Node.js workspace is clean (`git status` should be sufficient). -* Configure Node.js with the specific [ICU version](http://icu-project.org/download) +* Configure Node.js with the specific [ICU version](http://site.icu-project.org/download) you want to upgrade to, for example: ```bash diff --git a/doc/guides/maintaining-openssl.md b/doc/guides/maintaining-openssl.md index 34deb05523b15c..a77771d9feea38 100644 --- a/doc/guides/maintaining-openssl.md +++ b/doc/guides/maintaining-openssl.md @@ -5,7 +5,7 @@ This document describes how to update `deps/openssl/`. ## Requirements * Linux environment. * `perl` Only Perl version 5 is tested. -* `nasm` () Version 2.11 or higher is needed. +* `nasm` () Version 2.11 or higher is needed. * GNU `as` in binutils. Version 2.26 or higher is needed. ## 0. Check Requirements diff --git a/doc/guides/writing-tests.md b/doc/guides/writing-tests.md index e441d934113e75..0aa4cb8221f278 100644 --- a/doc/guides/writing-tests.md +++ b/doc/guides/writing-tests.md @@ -432,7 +432,7 @@ To generate a test coverage report, see the Nightly coverage reports for the Node.js master branch are available at . -[ASCII]: http://man7.org/linux/man-pages/man7/ascii.7.html +[ASCII]: https://man7.org/linux/man-pages/man7/ascii.7.html [Google Test]: https://github.com/google/googletest [`common` module]: https://github.com/nodejs/node/blob/master/test/common/README.md [all maintained branches]: https://github.com/nodejs/lts From daf2abf393da4be380e1dee2ec43d1aedf7a979e Mon Sep 17 00:00:00 2001 From: sapics Date: Mon, 29 Jun 2020 23:58:19 +0900 Subject: [PATCH 062/138] lib: replace http to https of comment link urls PR-URL: https://github.com/nodejs/node/pull/34158 Reviewed-By: Anna Henningsen Reviewed-By: Anto Aravinth Reviewed-By: James M Snell --- lib/_http_server.js | 2 +- lib/https.js | 2 +- lib/internal/child_process.js | 2 +- lib/internal/source_map/source_map.js | 3 ++- lib/internal/tty.js | 2 +- lib/internal/util/inspect.js | 4 ++-- lib/querystring.js | 2 +- lib/readline.js | 2 +- 8 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/_http_server.js b/lib/_http_server.js index 680fadba715f07..842bfb5eb7a0d5 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -351,7 +351,7 @@ function Server(options, requestListener) { // Similar option to this. Too lazy to write my own docs. // http://www.squid-cache.org/Doc/config/half_closed_clients/ - // http://wiki.squid-cache.org/SquidFaq/InnerWorkings#What_is_a_half-closed_filedescriptor.3F + // https://wiki.squid-cache.org/SquidFaq/InnerWorkings#What_is_a_half-closed_filedescriptor.3F this.httpAllowHalfOpen = false; this.on('connection', connectionListener); diff --git a/lib/https.js b/lib/https.js index 1d3a6e5024b65b..17a89c2f0bc0bb 100644 --- a/lib/https.js +++ b/lib/https.js @@ -55,7 +55,7 @@ function Server(opts, requestListener) { if (!opts.ALPNProtocols) { // http/1.0 is not defined as Protocol IDs in IANA - // http://www.iana.org/assignments/tls-extensiontype-values + // https://www.iana.org/assignments/tls-extensiontype-values // /tls-extensiontype-values.xhtml#alpn-protocol-ids opts.ALPNProtocols = ['http/1.1']; } diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js index 6438e6b650b814..85ce63a9660f86 100644 --- a/lib/internal/child_process.js +++ b/lib/internal/child_process.js @@ -944,7 +944,7 @@ function getValidStdio(stdio, sync) { // At least 3 stdio will be created // Don't concat() a new Array() because it would be sparse, and // stdio.reduce() would skip the sparse elements of stdio. - // See http://stackoverflow.com/a/5501711/3561 + // See https://stackoverflow.com/a/5501711/3561 while (stdio.length < 3) stdio.push(undefined); // Translate stdio into C++-readable form diff --git a/lib/internal/source_map/source_map.js b/lib/internal/source_map/source_map.js index 2cd70c5c944e19..7d21e02429a086 100644 --- a/lib/internal/source_map/source_map.js +++ b/lib/internal/source_map/source_map.js @@ -113,7 +113,8 @@ class StringCharIterator { } /** - * Implements Source Map V3 model. See http://code.google.com/p/closure-compiler/wiki/SourceMaps + * Implements Source Map V3 model. + * See https://github.com/google/closure-compiler/wiki/Source-Maps * for format description. * @constructor * @param {string} sourceMappingURL diff --git a/lib/internal/tty.js b/lib/internal/tty.js index 44d51737008eb0..1ebd09193ef57e 100644 --- a/lib/internal/tty.js +++ b/lib/internal/tty.js @@ -125,7 +125,7 @@ function getColorDepth(env = process.env) { env.NO_COLOR !== undefined || // The "dumb" special terminal, as defined by terminfo, doesn't support // ANSI color control codes. - // See http://invisible-island.net/ncurses/terminfo.ti.html#toc-_Specials + // See https://invisible-island.net/ncurses/terminfo.ti.html#toc-_Specials env.TERM === 'dumb') { return COLORS_2; } diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 03e62226236df3..824c5961e9512c 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -338,7 +338,7 @@ ObjectDefineProperty(inspect, 'defaultOptions', { } }); -// Set Graphics Rendition http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +// Set Graphics Rendition https://en.wikipedia.org/wiki/ANSI_escape_code#graphics // Each color consists of an array with the color code as first entry and the // reset code as second entry. const defaultFG = 39; @@ -2051,7 +2051,7 @@ if (internalBinding('config').hasIntl) { */ const isFullWidthCodePoint = (code) => { // Code points are partially derived from: - // http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt + // https://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt return code >= 0x1100 && ( code <= 0x115f || // Hangul Jamo code === 0x2329 || // LEFT-POINTING ANGLE BRACKET diff --git a/lib/querystring.js b/lib/querystring.js index f057226f08b51f..05cca60fc4c57f 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -140,7 +140,7 @@ const noEscape = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 // 112 - 127 ]; // QueryString.escape() replaces encodeURIComponent() -// http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.4 +// https://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.4 function qsEscape(str) { if (typeof str !== 'string') { if (typeof str === 'object') diff --git a/lib/readline.js b/lib/readline.js index 7d44dd2366cf39..a8f60ac9111e26 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -22,7 +22,7 @@ // Inspiration for this code comes from Salvatore Sanfilippo's linenoise. // https://github.com/antirez/linenoise // Reference: -// * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html +// * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html // * http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html 'use strict'; From 3e3d908c816d110740890bac332030e154c00738 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Fri, 3 Jul 2020 13:24:11 +0200 Subject: [PATCH 063/138] src: add encoding_type variable in WritePrivateKey This commit adds a local variable named encoding_type which is set to the value of the Maybe using ToChecked(). The motivation for this is the code for ToChecked() could be executed multiple times depending on path taken at runtime. I also think this improves readability, or at least it is as readable as before this change. PR-URL: https://github.com/nodejs/node/pull/34181 Reviewed-By: Anna Henningsen Reviewed-By: David Carlier --- src/node_crypto.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index aace8e2c05e915..eae0f2e49d3c86 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3151,7 +3151,8 @@ static MaybeLocal WritePrivateKey( bool err; - if (config.type_.ToChecked() == kKeyEncodingPKCS1) { + PKEncodingType encoding_type = config.type_.ToChecked(); + if (encoding_type == kKeyEncodingPKCS1) { // PKCS#1 is only permitted for RSA keys. CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_RSA); @@ -3171,7 +3172,7 @@ static MaybeLocal WritePrivateKey( CHECK_NULL(config.cipher_); err = i2d_RSAPrivateKey_bio(bio.get(), rsa.get()) != 1; } - } else if (config.type_.ToChecked() == kKeyEncodingPKCS8) { + } else if (encoding_type == kKeyEncodingPKCS8) { if (config.format_ == kKeyFormatPEM) { // Encode PKCS#8 as PEM. err = PEM_write_bio_PKCS8PrivateKey( @@ -3191,7 +3192,7 @@ static MaybeLocal WritePrivateKey( nullptr, nullptr) != 1; } } else { - CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSEC1); + CHECK_EQ(encoding_type, kKeyEncodingSEC1); // SEC1 is only permitted for EC keys. CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_EC); From 280cd967d31048b74aa297555d7cafa91c4be183 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 7 Jul 2020 18:05:33 +0200 Subject: [PATCH 064/138] domain: fix unintentional deprecation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 646e5a471766e27e8317bb changed the way that the domain hook callback is called. Previously, the callback was only used in the case that async_hooks were *not* being used (since domains already integrate with async hooks the way they should), and the corresponding deprecation warning also only emitted in that case. However, that commit didn’t move that condition along when the code was ported from C++ to JS. As a consequence, the domain hook callback was used when it wasn’t necessary to use it, and the deprecation warning emitted accidentally along with it. Refs: https://github.com/nodejs/node/commit/646e5a471766e27e8317bb54d1fd1d2c72cffb69#diff-9f21ce1b9d6d46fdd07b969e8a04e140L192 Refs: https://github.com/nodejs/node/commit/646e5a471766e27e8317bb54d1fd1d2c72cffb69#diff-e6db408e12db906ead6ddfac3de15a6fR119 Refs: https://github.com/nodejs/node/pull/33801#issuecomment-654744913 PR-URL: https://github.com/nodejs/node/pull/34245 Fixes: https://github.com/nodejs/node/issues/34069 Reviewed-By: Vladimir de Turckheim Reviewed-By: Shelley Vohr Reviewed-By: James M Snell Reviewed-By: Gerhard Stöbich Reviewed-By: Gus Caplan Reviewed-By: Andrey Pechkurov Reviewed-By: Stephen Belanger --- lib/internal/async_hooks.js | 6 +++--- test/parallel/test-domain-http-server.js | 4 +++- test/parallel/test-domain-implicit-binding.js | 2 ++ test/parallel/test-domain-implicit-fs.js | 2 ++ test/parallel/test-domain-multi.js | 2 ++ test/parallel/test-domain-promise.js | 2 ++ 6 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/internal/async_hooks.js b/lib/internal/async_hooks.js index fc894ebe4d773f..591c1c8e79d6c6 100644 --- a/lib/internal/async_hooks.js +++ b/lib/internal/async_hooks.js @@ -112,18 +112,18 @@ function useDomainTrampoline(fn) { } function callbackTrampoline(asyncId, cb, ...args) { - if (asyncId && hasHooks(kBefore)) + if (asyncId !== 0 && hasHooks(kBefore)) emitBeforeNative(asyncId); let result; - if (typeof domain_cb === 'function') { + if (asyncId === 0 && typeof domain_cb === 'function') { ArrayPrototypeUnshift(args, cb); result = ReflectApply(domain_cb, this, args); } else { result = ReflectApply(cb, this, args); } - if (asyncId && hasHooks(kAfter)) + if (asyncId !== 0 && hasHooks(kAfter)) emitAfterNative(asyncId); return result; diff --git a/test/parallel/test-domain-http-server.js b/test/parallel/test-domain-http-server.js index 6168566334a11d..2f0c757a99df35 100644 --- a/test/parallel/test-domain-http-server.js +++ b/test/parallel/test-domain-http-server.js @@ -20,12 +20,14 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const domain = require('domain'); const http = require('http'); const assert = require('assert'); const debug = require('util').debuglog('test'); +process.on('warning', common.mustNotCall()); + const objects = { foo: 'bar', baz: {}, num: 42, arr: [1, 2, 3] }; objects.baz.asdf = objects; diff --git a/test/parallel/test-domain-implicit-binding.js b/test/parallel/test-domain-implicit-binding.js index 15f6685df93b7b..9f119a420368f0 100644 --- a/test/parallel/test-domain-implicit-binding.js +++ b/test/parallel/test-domain-implicit-binding.js @@ -6,6 +6,8 @@ const domain = require('domain'); const fs = require('fs'); const isEnumerable = Function.call.bind(Object.prototype.propertyIsEnumerable); +process.on('warning', common.mustNotCall()); + { const d = new domain.Domain(); diff --git a/test/parallel/test-domain-implicit-fs.js b/test/parallel/test-domain-implicit-fs.js index d5a6e79bc90734..c785ff75c67656 100644 --- a/test/parallel/test-domain-implicit-fs.js +++ b/test/parallel/test-domain-implicit-fs.js @@ -26,6 +26,8 @@ const common = require('../common'); const assert = require('assert'); const domain = require('domain'); +process.on('warning', common.mustNotCall()); + const d = new domain.Domain(); d.on('error', common.mustCall(function(er) { diff --git a/test/parallel/test-domain-multi.js b/test/parallel/test-domain-multi.js index 63701150f8c331..072f8e86bb077c 100644 --- a/test/parallel/test-domain-multi.js +++ b/test/parallel/test-domain-multi.js @@ -26,6 +26,8 @@ const common = require('../common'); const domain = require('domain'); const http = require('http'); +process.on('warning', common.mustNotCall()); + const a = domain.create(); a.enter(); // This will be our "root" domain diff --git a/test/parallel/test-domain-promise.js b/test/parallel/test-domain-promise.js index 704092522357fd..2a127f3d40272b 100644 --- a/test/parallel/test-domain-promise.js +++ b/test/parallel/test-domain-promise.js @@ -5,6 +5,8 @@ const domain = require('domain'); const fs = require('fs'); const vm = require('vm'); +process.on('warning', common.mustNotCall()); + { const d = domain.create(); From 9c98af71db0fc715c40d4c4347923b2f767a795a Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 30 Jun 2020 19:05:24 +0200 Subject: [PATCH 065/138] src: exit explicitly after printing V8 help MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V8 will not exit the process after handling --help anymore: https://chromium-review.googlesource.com/c/v8/v8/+/2276276 As a drive-by fix, correctly return in the `print_bash_completion` case as well. Refs: https://github.com/nodejs/node/pull/34135 Co-authored-by: Ulan Degenbaev PR-URL: https://github.com/nodejs/node/pull/34136 Reviewed-By: Shelley Vohr Reviewed-By: Richard Lau Reviewed-By: Daniel Bevenius Reviewed-By: Gireesh Punathil Reviewed-By: Michaël Zasso --- src/node.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/node.cc b/src/node.cc index 1c776c79fc6887..c2befefefd8130 100644 --- a/src/node.cc +++ b/src/node.cc @@ -946,9 +946,8 @@ void Init(int* argc, } if (per_process::cli_options->print_v8_help) { - // Doesn't return. V8::SetFlagsFromString("--help", static_cast(6)); - UNREACHABLE(); + exit(0); } *argc = argv_.size(); @@ -1010,13 +1009,16 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) { if (per_process::cli_options->print_bash_completion) { std::string completion = options_parser::GetBashCompletion(); printf("%s\n", completion.c_str()); - exit(0); + result.exit_code = 0; + result.early_return = true; + return result; } if (per_process::cli_options->print_v8_help) { - // Doesn't return. V8::SetFlagsFromString("--help", static_cast(6)); - UNREACHABLE(); + result.exit_code = 0; + result.early_return = true; + return result; } #if HAVE_OPENSSL From a38219f962ed27c25f5351a5841778f6f923950c Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 30 Jun 2020 20:15:39 +0200 Subject: [PATCH 066/138] test: add regression test for C++-created Buffer transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a test for a regression that occurs when transferring some `Buffer` objects that were created from C++ to a parent thread. Fixes: https://github.com/nodejs/node/issues/34126 PR-URL: https://github.com/nodejs/node/pull/34140 Reviewed-By: Gerhard Stöbich --- ...test-worker-crypto-sign-transfer-result.js | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 test/parallel/test-worker-crypto-sign-transfer-result.js diff --git a/test/parallel/test-worker-crypto-sign-transfer-result.js b/test/parallel/test-worker-crypto-sign-transfer-result.js new file mode 100644 index 00000000000000..ca5675d1426c60 --- /dev/null +++ b/test/parallel/test-worker-crypto-sign-transfer-result.js @@ -0,0 +1,30 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const { Worker } = require('worker_threads'); +const fixturesPath = require.resolve('../common/fixtures'); + +// Test that transferring the result of e.g. crypto.sign() from Worker to parent +// thread does not crash + +const w = new Worker(` +const { parentPort } = require('worker_threads'); +const crypto = require('crypto'); +const assert = require('assert'); +const fixtures = require(${JSON.stringify(fixturesPath)}); + +const keyPem = fixtures.readKey('rsa_private.pem'); + +const buf = crypto.sign('sha256', Buffer.from('hello'), keyPem); +assert.notStrictEqual(buf.byteLength, 0); +parentPort.postMessage(buf, [buf.buffer]); +assert.strictEqual(buf.byteLength, 0); +`, { eval: true }); + +w.on('message', common.mustCall((buf) => { + assert.notStrictEqual(buf.byteLength, 0); +})); +w.on('exit', common.mustCall()); From 0f9bafd03d0d2ffc2fc986f3799bdd7ae66d6f9a Mon Sep 17 00:00:00 2001 From: Xu Meng Date: Sat, 4 Jul 2020 22:31:58 -0500 Subject: [PATCH 067/138] test: skip an ipv6 test on IBM i Due to some unknown system configuration, the code `socket_ipv6.bind(0, 111::1)` does not throw the expected error EADDRNOTAVAIL on some IBM i systems. This issue is still being investigated. To get the IBM i CI passing, skip it for now. PR-URL: https://github.com/nodejs/node/pull/34209 Reviewed-By: Richard Lau Reviewed-By: Anna Henningsen --- test/parallel/parallel.status | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index 94d15064b38423..d95b3e45d40252 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -74,4 +74,6 @@ test-net-socket-connect-without-cb: SKIP test-net-socket-connecting: SKIP test-net-socket-ready-without-cb: SKIP test-net-write-after-end-nt: SKIP -test-tls-env-extra-ca: SKIP \ No newline at end of file +test-tls-env-extra-ca: SKIP +# https://github.com/nodejs/node/pull/34209 +test-dgram-error-message-address: SKIP From 38b3c2a30080489efe4d832caa71d9713cf86260 Mon Sep 17 00:00:00 2001 From: rickyes Date: Wed, 1 Jul 2020 21:43:59 +0800 Subject: [PATCH 068/138] test: add arrayOfStreams to pipeline PR-URL: https://github.com/nodejs/node/pull/34156 Reviewed-By: Robert Nagy Reviewed-By: Matteo Collina Reviewed-By: Anna Henningsen --- test/parallel/test-stream-pipeline.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/parallel/test-stream-pipeline.js b/test/parallel/test-stream-pipeline.js index 203a32b5cd74a1..5077aaa11a4e6b 100644 --- a/test/parallel/test-stream-pipeline.js +++ b/test/parallel/test-stream-pipeline.js @@ -1211,3 +1211,23 @@ const net = require('net'); d.write('test'); d.end(); } + +{ + const r = new Readable({ + read() {} + }); + r.push('hello'); + r.push('world'); + r.push(null); + let res = ''; + const w = new Writable({ + write(chunk, encoding, callback) { + res += chunk; + callback(); + } + }); + pipeline([r, w], common.mustCall((err) => { + assert.ok(!err); + assert.strictEqual(res, 'helloworld'); + })); +} From ec9b49a9b90c328ca8e1acdd60ee3cc518ebf3b4 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 6 Jul 2020 14:52:02 -0700 Subject: [PATCH 069/138] test: add known issue for fs.open() keeping event loop open PR-URL: https://github.com/nodejs/node/pull/34228 Reviewed-By: James M Snell Reviewed-By: Richard Lau Reviewed-By: Ben Noordhuis Reviewed-By: Robert Nagy --- test/known_issues/known_issues.status | 2 ++ test/known_issues/test-fs-open-no-close.js | 30 ++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 test/known_issues/test-fs-open-no-close.js diff --git a/test/known_issues/known_issues.status b/test/known_issues/known_issues.status index 86d95e41d199dd..01a82246c93fcb 100644 --- a/test/known_issues/known_issues.status +++ b/test/known_issues/known_issues.status @@ -27,3 +27,5 @@ test-vm-timeout-escape-queuemicrotask: SKIP # The Raspberry Pis are too slow to run this test. # See https://github.com/nodejs/build/issues/2227#issuecomment-608334574 test-crypto-authenticated-stream: SKIP +# The bug being checked is that the test never exits. +test-fs-open-no-close: TIMEOUT diff --git a/test/known_issues/test-fs-open-no-close.js b/test/known_issues/test-fs-open-no-close.js new file mode 100644 index 00000000000000..648ab00f69e63f --- /dev/null +++ b/test/known_issues/test-fs-open-no-close.js @@ -0,0 +1,30 @@ +'use strict'; + +// Failing to close a file should not keep the event loop open. + +const common = require('../common'); + +// This issue only shows up on Raspberry Pi devices in our CI. When this test is +// moved out of known_issues, this check can be removed, as the test should pass +// on all platforms at that point. +const assert = require('assert'); +if (process.arch !== 'arm' || process.config.variables.arm_version > 7) { + assert.fail('This test is for Raspberry Pi devices in CI'); +} + +const fs = require('fs'); + +const debuglog = (arg) => { + console.log(new Date().toLocaleString(), arg); +}; + +const tmpdir = require('../common/tmpdir'); +tmpdir.refresh(); + +{ + fs.open(`${tmpdir.path}/dummy`, 'wx+', common.mustCall((err, fd) => { + debuglog('fs open() callback'); + assert.ifError(err); + })); + debuglog('waiting for callback'); +} From 96ebd5f352c3eaf9ada5904a98444ceb48b52b21 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Tue, 30 Jun 2020 23:49:07 +0200 Subject: [PATCH 070/138] http: add note about timer unref PR-URL: https://github.com/nodejs/node/pull/34143 Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- lib/_http_server.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/_http_server.js b/lib/_http_server.js index 842bfb5eb7a0d5..bef14bc880165c 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -568,6 +568,10 @@ function socketOnData(server, socket, parser, state, d) { } function onParserExecute(server, socket, parser, state, ret) { + // When underlying `net.Socket` instance is consumed - no + // `data` events are emitted, and thus `socket.setTimeout` fires the + // callback even if the data is constantly flowing into the socket. + // See, https://github.com/nodejs/node/commit/ec2822adaad76b126b5cccdeaa1addf2376c9aa6 socket._unrefTimer(); debug('SERVER socketOnParserExecute %d', ret); onParserExecuteCommon(server, socket, parser, state, ret, undefined); From a6a656abaa507a1b24195f74a9dcfab29f532917 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 6 Jul 2020 12:59:12 -0700 Subject: [PATCH 071/138] doc: document security issues with url.parse() Fixes: https://github.com/nodejs/node/issues/31279 PR-URL: https://github.com/nodejs/node/pull/34226 Reviewed-By: Ben Noordhuis Reviewed-By: Anna Henningsen Reviewed-By: Trivikram Kamat --- doc/api/url.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/api/url.md b/doc/api/url.md index 06b80a438ad748..53aec1f6596985 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -1244,6 +1244,12 @@ A `TypeError` is thrown if `urlString` is not a string. A `URIError` is thrown if the `auth` property is present but cannot be decoded. +Use of the legacy `url.parse()` method is discouraged. Users should +use the WHATWG `URL` API. Because the `url.parse()` method uses a +lenient, non-standard algorithm for parsing URL strings, security +issues can be introduced. Specifically, issues with [host name spoofing][] and +incorrect handling of usernames and passwords have been identified. + ### `url.resolve(from, to)` + +The `'ready'` event is emitted when the `Http2Stream` has been opened, has +been assigned an `id`, and can be used. The listener does not expect any +arguments. + #### Event: `'timeout'` -In Node.js, `Buffer` objects are used to represent binary data in the form -of a sequence of bytes. Many Node.js APIs, for example streams and file system -operations, support `Buffer`s, as interactions with the operating system or -other processes generally always happen in terms of binary data. +`Buffer` objects are used to represent a fixed-length sequence of bytes. Many +Node.js APIs support `Buffer`s. -The `Buffer` class is a subclass of the [`Uint8Array`][] class that is built -into the JavaScript language. A number of additional methods are supported -that cover additional use cases. Node.js APIs accept plain [`Uint8Array`][]s -wherever `Buffer`s are supported as well. - -Instances of `Buffer`, and instances of [`Uint8Array`][] in general, -are similar to arrays of integers from `0` to `255`, but correspond to -fixed-sized blocks of memory and cannot contain any other values. -The size of a `Buffer` is established when it is created and cannot be changed. +The `Buffer` class is a subclass of JavaScript's [`Uint8Array`][] class and +extends it with methods that cover additional use cases. Node.js APIs accept +plain [`Uint8Array`][]s wherever `Buffer`s are supported as well. The `Buffer` class is within the global scope, making it unlikely that one would need to ever use `require('buffer').Buffer`. @@ -165,11 +157,10 @@ changes: description: The `Buffer`s class now inherits from `Uint8Array`. --> -`Buffer` instances are also [`Uint8Array`][] instances, which is the language’s -built-in class for working with binary data. [`Uint8Array`][] in turn is a -subclass of [`TypedArray`][]. Therefore, all [`TypedArray`][] methods are also -available on `Buffer`s. However, there are subtle incompatibilities between -the `Buffer` API and the [`TypedArray`][] API. +`Buffer` instances are also JavaScript [`Uint8Array`][] and [`TypedArray`][] +instances. All [`TypedArray`][] methods are available on `Buffer`s. There are, +however, subtle incompatibilities between the `Buffer` API and the +[`TypedArray`][] API. In particular: @@ -182,26 +173,37 @@ In particular: * [`buf.toString()`][] is incompatible with its `TypedArray` equivalent. * A number of methods, e.g. [`buf.indexOf()`][], support additional arguments. -There are two ways to create new [`TypedArray`][] instances from a `Buffer`. +There are two ways to create new [`TypedArray`][] instances from a `Buffer`: + +* Passing a `Buffer` to a [`TypedArray`][] constructor will copy the `Buffer`s + contents, interpreted an array array of integers, and not as a byte sequence + of the target type. + +```js +const buf = Buffer.from([1, 2, 3, 4]); +const uint32array = new Uint32Array(buf); + +console.log(uint32array); -When passing a `Buffer` to a [`TypedArray`][] constructor, the `Buffer`’s -elements will be copied, interpreted as an array of integers, and not as a byte -array of the target type. For example, -`new Uint32Array(Buffer.from([1, 2, 3, 4]))` creates a 4-element -[`Uint32Array`][] with elements `[1, 2, 3, 4]`, rather than a -[`Uint32Array`][] with a single element `[0x1020304]` or `[0x4030201]`. +// Prints: Uint32Array(4) [ 1, 2, 3, 4 ] +``` -In order to create a [`TypedArray`][] that shares its memory with the `Buffer`, -the underlying [`ArrayBuffer`][] can be passed to the [`TypedArray`][] -constructor instead: +* Passing the `Buffer`s underlying [`ArrayBuffer`][] will create a + [`TypedArray`][] that shares its memory with the `Buffer`. ```js const buf = Buffer.from('hello', 'utf16le'); const uint16arr = new Uint16Array( - buf.buffer, buf.byteOffset, buf.length / Uint16Array.BYTES_PER_ELEMENT); + buf.buffer, + buf.byteOffset, + buf.length / Uint16Array.BYTES_PER_ELEMENT); + +console.log(uint16array); + +// Prints: Uint16Array(5) [ 104, 101, 108, 108, 111 ] ``` -It is also possible to create a new `Buffer` that shares the same allocated +It is possible to create a new `Buffer` that shares the same allocated memory as a [`TypedArray`][] instance by using the `TypedArray` object’s `.buffer` property in the same way. [`Buffer.from()`][`Buffer.from(arrayBuf)`] behaves like `new Uint8Array()` in this context. @@ -214,6 +216,7 @@ arr[1] = 4000; // Copies the contents of `arr`. const buf1 = Buffer.from(arr); + // Shares memory with `arr`. const buf2 = Buffer.from(arr.buffer); @@ -773,7 +776,7 @@ range is between `0x00` and `0xFF` (hex) or `0` and `255` (decimal). This operator is inherited from `Uint8Array`, so its behavior on out-of-bounds access is the same as `Uint8Array`. In other words, `buf[index]` returns -`undefined` when `index` is negative or `>= buf.length`, and +`undefined` when `index` is negative or greater or equal to `buf.length`, and `buf[index] = value` does not modify the buffer if `index` is negative or `>= buf.length`. @@ -795,8 +798,8 @@ console.log(buf.toString('utf8')); ### `buf.buffer` -* {ArrayBuffer} The underlying `ArrayBuffer` object based on - which this `Buffer` object is created. +* {ArrayBuffer} The underlying `ArrayBuffer` object based on which this `Buffer` + object is created. This `ArrayBuffer` is not guaranteed to correspond exactly to the original `Buffer`. See the notes on `buf.byteOffset` for details. @@ -811,16 +814,15 @@ console.log(buffer.buffer === arrayBuffer); ### `buf.byteOffset` -* {integer} The `byteOffset` on the underlying `ArrayBuffer` object based on - which this `Buffer` object is created. +* {integer} The `byteOffset` of the `Buffer`s underlying `ArrayBuffer` object. When setting `byteOffset` in `Buffer.from(ArrayBuffer, byteOffset, length)`, -or sometimes when allocating a buffer smaller than `Buffer.poolSize`, the -buffer doesn't start from a zero offset on the underlying `ArrayBuffer`. +or sometimes when allocating a `Buffer` smaller than `Buffer.poolSize`, the +buffer does not start from a zero offset on the underlying `ArrayBuffer`. This can cause problems when accessing the underlying `ArrayBuffer` directly using `buf.buffer`, as other parts of the `ArrayBuffer` may be unrelated -to the `buf` object itself. +to the `Buffer` object itself. A common issue when creating a `TypedArray` object that shares its memory with a `Buffer` is that in this case one needs to specify the `byteOffset` correctly: @@ -1340,6 +1342,21 @@ deprecated: v8.0.0 The `buf.parent` property is a deprecated alias for `buf.buffer`. ### `buf.readBigInt64BE([offset])` + + +* `offset` {integer} Number of bytes to skip before starting to read. Must + satisfy: `0 <= offset <= buf.length - 8`. **Default:** `0`. +* Returns: {bigint} + +Reads a signed, big-endian 64-bit integer from `buf` at the specified `offset`. + +Integers read from a `Buffer` are interpreted as two's complement signed +values. + ### `buf.readBigInt64LE([offset])` + +* `offset` {integer} Number of bytes to skip before starting to read. Must + satisfy: `0 <= offset <= buf.length - 8`. **Default:** `0`. +* Returns: {bigint} + +Reads an unsigned, little-endian 64-bit integer from `buf` at the specified +`offset`. + +```js +const buf = Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]); console.log(buf.readBigUInt64LE(0)); // Prints: 18446744069414584320n ``` ### `buf.readDoubleBE([offset])` -### `buf.readDoubleLE([offset])` + +* `offset` {integer} Number of bytes to skip before starting to read. Must + satisfy `0 <= offset <= buf.length - 8`. **Default:** `0`. +* Returns: {number} + +Reads a 64-bit, little-endian double from `buf` at the specified `offset`. + +```js +const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]); + console.log(buf.readDoubleLE(0)); // Prints: 5.447603722011605e-270 console.log(buf.readDoubleLE(1)); @@ -1414,7 +1465,6 @@ console.log(buf.readDoubleLE(1)); ``` ### `buf.readFloatBE([offset])` -### `buf.readFloatLE([offset])` + +* `offset` {integer} Number of bytes to skip before starting to read. Must + satisfy `0 <= offset <= buf.length - 4`. **Default:** `0`. +* Returns: {number} + +Reads a 32-bit, little-endian float from `buf` at the specified `offset`. + +```js +const buf = Buffer.from([1, 2, 3, 4]); + console.log(buf.readFloatLE(0)); // Prints: 1.539989614439558e-36 console.log(buf.readFloatLE(1)); @@ -1473,7 +1542,6 @@ console.log(buf.readInt8(2)); ``` ### `buf.readInt16BE([offset])` -### `buf.readInt16LE([offset])` + +* `offset` {integer} Number of bytes to skip before starting to read. Must + satisfy `0 <= offset <= buf.length - 2`. **Default:** `0`. +* Returns: {integer} + +Reads a signed, little-endian 16-bit integer from `buf` at the specified +`offset`. + +Integers read from a `Buffer` are interpreted as two's complement signed values. + +```js +const buf = Buffer.from([0, 5]); + console.log(buf.readInt16LE(0)); // Prints: 1280 console.log(buf.readInt16LE(1)); @@ -1505,7 +1595,6 @@ console.log(buf.readInt16LE(1)); ``` ### `buf.readInt32BE([offset])` -### `buf.readInt32LE([offset])` + +* `offset` {integer} Number of bytes to skip before starting to read. Must + satisfy `0 <= offset <= buf.length - 4`. **Default:** `0`. +* Returns: {integer} + +Reads a signed, little-endian 32-bit integer from `buf` at the specified +`offset`. + +Integers read from a `Buffer` are interpreted as two's complement signed values. + +```js +const buf = Buffer.from([0, 0, 0, 5]); + console.log(buf.readInt32LE(0)); // Prints: 83886080 console.log(buf.readInt32LE(1)); @@ -1537,7 +1648,6 @@ console.log(buf.readInt32LE(1)); ``` ### `buf.readIntBE(offset, byteLength)` -### `buf.readIntLE(offset, byteLength)` + +* `offset` {integer} Number of bytes to skip before starting to read. Must + satisfy `0 <= offset <= buf.length - byteLength`. +* `byteLength` {integer} Number of bytes to read. Must satisfy + `0 < byteLength <= 6`. +* Returns: {integer} + +Reads `byteLength` number of bytes from `buf` at the specified `offset` +and interprets the result as a little-endian, two's complement signed value +supporting up to 48 bits of accuracy. + +```js +const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]); + +console.log(buf.readIntLE(0, 6).toString(16)); +// Prints: -546f87a9cbee +``` + ### `buf.readUInt8([offset])` + +* `offset` {integer} Number of bytes to skip before starting to read. Must + satisfy `0 <= offset <= buf.length - 2`. **Default:** `0`. +* Returns: {integer} + +Reads an unsigned, little-endian 16-bit integer from `buf` at the specified +`offset`. + +```js +const buf = Buffer.from([0x12, 0x34, 0x56]); + +console.log(buf.readUInt16LE(0).toString(16)); +// Prints: 3412 console.log(buf.readUInt16LE(1).toString(16)); // Prints: 5634 console.log(buf.readUInt16LE(2).toString(16)); @@ -1632,7 +1787,6 @@ console.log(buf.readUInt16LE(2).toString(16)); ``` ### `buf.readUInt32BE([offset])` -### `buf.readUInt32LE([offset])` + +* `offset` {integer} Number of bytes to skip before starting to read. Must + satisfy `0 <= offset <= buf.length - 4`. **Default:** `0`. +* Returns: {integer} + +Reads an unsigned, little-endian 32-bit integer from `buf` at the specified +`offset`. + +```js +const buf = Buffer.from([0x12, 0x34, 0x56, 0x78]); + console.log(buf.readUInt32LE(0).toString(16)); // Prints: 78563412 console.log(buf.readUInt32LE(1).toString(16)); @@ -1662,7 +1837,6 @@ console.log(buf.readUInt32LE(1).toString(16)); ``` ### `buf.readUIntBE(offset, byteLength)` -### `buf.readUIntLE(offset, byteLength)` + +* `offset` {integer} Number of bytes to skip before starting to read. Must + satisfy `0 <= offset <= buf.length - byteLength`. +* `byteLength` {integer} Number of bytes to read. Must satisfy + `0 < byteLength <= 6`. +* Returns: {integer} + +Reads `byteLength` number of bytes from `buf` at the specified `offset` +and interprets the result as an unsigned, little-endian integer supporting +up to 48 bits of accuracy. + +```js +const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]); + +console.log(buf.readUIntLE(0, 6).toString(16)); +// Prints: ab9078563412 +``` + ### `buf.subarray([start[, end]])` + +* `value` {bigint} Number to be written to `buf`. +* `offset` {integer} Number of bytes to skip before starting to write. Must + satisfy: `0 <= offset <= buf.length - 8`. **Default:** `0`. +* Returns: {integer} `offset` plus the number of bytes written. + +Writes `value` to `buf` at the specified `offset` as little-endian. + +`value` is interpreted and written as a two's complement signed integer. + +```js +const buf = Buffer.allocUnsafe(8); + +buf.writeBigInt64LE(0x0102030405060708n, 0); + +console.log(buf); +// Prints: +``` + ### `buf.writeBigUInt64BE(value[, offset])` + + +* `value` {bigint} Number to be written to `buf`. +* `offset` {integer} Number of bytes to skip before starting to write. Must + satisfy: `0 <= offset <= buf.length - 8`. **Default:** `0`. +* Returns: {integer} `offset` plus the number of bytes written. + +Writes `value` to `buf` at the specified `offset` as big-endian. + +```js +const buf = Buffer.allocUnsafe(8); + +buf.writeBigUInt64BE(0xdecafafecacefaden, 0); + +console.log(buf); +// Prints: +``` + ### `buf.writeBigUInt64LE(value[, offset])` + +* `value` {number} Number to be written to `buf`. +* `offset` {integer} Number of bytes to skip before starting to write. Must + satisfy `0 <= offset <= buf.length - 8`. **Default:** `0`. +* Returns: {integer} `offset` plus the number of bytes written. + +Writes `value` to `buf` at the specified `offset` as little-endian. The `value` +must be a JavaScript number. Behavior is undefined when `value` is anything +other than a JavaScript number. + +```js +const buf = Buffer.allocUnsafe(8); buf.writeDoubleLE(123.456, 0); @@ -2119,7 +2381,6 @@ console.log(buf); ``` ### `buf.writeFloatBE(value[, offset])` -### `buf.writeFloatLE(value[, offset])` + +* `value` {number} Number to be written to `buf`. +* `offset` {integer} Number of bytes to skip before starting to write. Must + satisfy `0 <= offset <= buf.length - 4`. **Default:** `0`. +* Returns: {integer} `offset` plus the number of bytes written. + +Writes `value` to `buf` at the specified `offset` as little-endian. Behavior is +undefined when `value` is anything other than a JavaScript number. + +```js +const buf = Buffer.allocUnsafe(4); + buf.writeFloatLE(0xcafebabe, 0); console.log(buf); @@ -2185,7 +2467,6 @@ console.log(buf); ``` ### `buf.writeInt16BE(value[, offset])` -### `buf.writeInt16LE(value[, offset])` + +* `value` {integer} Number to be written to `buf`. +* `offset` {integer} Number of bytes to skip before starting to write. Must + satisfy `0 <= offset <= buf.length - 2`. **Default:** `0`. +* Returns: {integer} `offset` plus the number of bytes written. + +Writes `value` to `buf` at the specified `offset` as little-endian. The `value` +must be a valid signed 16-bit integer. Behavior is undefined when `value` is +anything other than a signed 16-bit integer. + +The `value` is interpreted and written as a two's complement signed integer. + +```js +const buf = Buffer.allocUnsafe(2); + +buf.writeInt16LE(0x0304, 0); + +console.log(buf); +// Prints: ``` ### `buf.writeInt32BE(value[, offset])` -### `buf.writeInt32LE(value[, offset])` + +* `value` {integer} Number to be written to `buf`. +* `offset` {integer} Number of bytes to skip before starting to write. Must + satisfy `0 <= offset <= buf.length - 4`. **Default:** `0`. +* Returns: {integer} `offset` plus the number of bytes written. + +Writes `value` to `buf` at the specified `offset` as little-endian. The `value` +must be a valid signed 32-bit integer. Behavior is undefined when `value` is +anything other than a signed 32-bit integer. + +The `value` is interpreted and written as a two's complement signed integer. + +```js +const buf = Buffer.allocUnsafe(4); + +buf.writeInt32LE(0x05060708, 0); + +console.log(buf); +// Prints: ``` ### `buf.writeIntBE(value, offset, byteLength)` -### `buf.writeIntLE(value, offset, byteLength)` + +* `value` {integer} Number to be written to `buf`. +* `offset` {integer} Number of bytes to skip before starting to write. Must + satisfy `0 <= offset <= buf.length - byteLength`. +* `byteLength` {integer} Number of bytes to write. Must satisfy + `0 < byteLength <= 6`. +* Returns: {integer} `offset` plus the number of bytes written. + +Writes `byteLength` bytes of `value` to `buf` at the specified `offset` +as little-endian. Supports up to 48 bits of accuracy. Behavior is undefined +when `value` is anything other than a signed integer. + +```js +const buf = Buffer.allocUnsafe(6); + buf.writeIntLE(0x1234567890ab, 0, 6); console.log(buf); @@ -2318,7 +2679,6 @@ console.log(buf); ``` ### `buf.writeUInt16BE(value[, offset])` -### `buf.writeUInt16LE(value[, offset])` + +* `value` {integer} Number to be written to `buf`. +* `offset` {integer} Number of bytes to skip before starting to write. Must + satisfy `0 <= offset <= buf.length - 2`. **Default:** `0`. +* Returns: {integer} `offset` plus the number of bytes written. + +Writes `value` to `buf` at the specified `offset` as little-endian. The `value` +must be a valid unsigned 16-bit integer. Behavior is undefined when `value` is +anything other than an unsigned 16-bit integer. + +```js +const buf = Buffer.allocUnsafe(4); buf.writeUInt16LE(0xdead, 0); buf.writeUInt16LE(0xbeef, 2); @@ -2355,7 +2737,6 @@ console.log(buf); ``` ### `buf.writeUInt32BE(value[, offset])` -### `buf.writeUInt32LE(value[, offset])` + +* `value` {integer} Number to be written to `buf`. +* `offset` {integer} Number of bytes to skip before starting to write. Must + satisfy `0 <= offset <= buf.length - 4`. **Default:** `0`. +* Returns: {integer} `offset` plus the number of bytes written. + +Writes `value` to `buf` at the specified `offset` as little-endian. The `value` +must be a valid unsigned 32-bit integer. Behavior is undefined when `value` is +anything other than an unsigned 32-bit integer. + +```js +const buf = Buffer.allocUnsafe(4); buf.writeUInt32LE(0xfeedface, 0); @@ -2390,7 +2793,6 @@ console.log(buf); ``` ### `buf.writeUIntBE(value, offset, byteLength)` -### `buf.writeUIntLE(value, offset, byteLength)` + +* `value` {integer} Number to be written to `buf`. +* `offset` {integer} Number of bytes to skip before starting to write. Must + satisfy `0 <= offset <= buf.length - byteLength`. +* `byteLength` {integer} Number of bytes to write. Must satisfy + `0 < byteLength <= 6`. +* Returns: {integer} `offset` plus the number of bytes written. + +Writes `byteLength` bytes of `value` to `buf` at the specified `offset` +as little-endian. Supports up to 48 bits of accuracy. Behavior is undefined +when `value` is anything other than an unsigned integer. + +```js +const buf = Buffer.allocUnsafe(6); buf.writeUIntLE(0x1234567890ab, 0, 6); @@ -2555,7 +2982,13 @@ changes: See [`Buffer.from(string[, encoding])`][`Buffer.from(string)`]. -## `buffer.INSPECT_MAX_BYTES` +## `buffer` module APIs + +While, the `Buffer` object is available as a global, there are additional +`Buffer`-related APIs that are available only via the `buffer` module +accessed using `require('buffer')`. + +### `buffer.INSPECT_MAX_BYTES` @@ -2566,10 +2999,7 @@ Returns the maximum number of bytes that will be returned when `buf.inspect()` is called. This can be overridden by user modules. See [`util.inspect()`][] for more details on `buf.inspect()` behavior. -This is a property on the `buffer` module returned by -`require('buffer')`, not on the `Buffer` global or a `Buffer` instance. - -## `buffer.kMaxLength` +### `buffer.kMaxLength` @@ -2578,10 +3008,7 @@ added: v3.0.0 An alias for [`buffer.constants.MAX_LENGTH`][]. -This is a property on the `buffer` module returned by -`require('buffer')`, not on the `Buffer` global or a `Buffer` instance. - -## `buffer.transcode(source, fromEnc, toEnc)` +### `buffer.transcode(source, fromEnc, toEnc)` @@ -2632,7 +3056,7 @@ See [`Buffer.allocUnsafeSlow()`][]. This was never a class in the sense that the constructor always returned a `Buffer` instance, rather than a `SlowBuffer` instance. -### `new SlowBuffer(size)` +#### `new SlowBuffer(size)` @@ -2643,15 +3067,12 @@ deprecated: v6.0.0 See [`Buffer.allocUnsafeSlow()`][]. -## Buffer constants +### Buffer constants -`buffer.constants` is a property on the `buffer` module returned by -`require('buffer')`, not on the `Buffer` global or a `Buffer` instance. - -### `buffer.constants.MAX_LENGTH` +#### `buffer.constants.MAX_LENGTH` @@ -2663,7 +3084,7 @@ On 64-bit architectures, this value currently is `(2^31)-1` (~2GB). This value is also available as [`buffer.kMaxLength`][]. -### `buffer.constants.MAX_STRING_LENGTH` +#### `buffer.constants.MAX_STRING_LENGTH` @@ -2807,7 +3228,6 @@ introducing security vulnerabilities into an application. [`TypedArray#slice()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice [`TypedArray#subarray()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray [`TypedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray -[`Uint32Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array [`Uint8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array [`buf.buffer`]: #buffer_buf_buffer [`buf.compare()`]: #buffer_buf_compare_target_targetstart_targetend_sourcestart_sourceend From 8f8d16849cf9cd48026f5af4add6f06e323eeae0 Mon Sep 17 00:00:00 2001 From: Derek Lewis Date: Tue, 7 Jul 2020 11:01:11 -0400 Subject: [PATCH 104/138] meta: make issue template mobile friendly and address nits PR-URL: https://github.com/nodejs/node/pull/34243 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Evan Lucas Reviewed-By: Trivikram Kamat Reviewed-By: Rich Trott Reviewed-By: Anto Aravinth --- .../ISSUE_TEMPLATE/3-api-ref-docs-problem.md | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/3-api-ref-docs-problem.md b/.github/ISSUE_TEMPLATE/3-api-ref-docs-problem.md index 3ec3959eb67173..f63d540abaf4e2 100644 --- a/.github/ISSUE_TEMPLATE/3-api-ref-docs-problem.md +++ b/.github/ISSUE_TEMPLATE/3-api-ref-docs-problem.md @@ -7,29 +7,48 @@ labels: doc # 📗 API Reference Docs Problem - +For more general support, please open an issue +using the issue tracker for our help repository. + + https://github.com/nodejs/help + +--- + +For the issue title, please enter a one-line +summary after “doc: ” (preferably 50 characters +or less and no more than 72). + +The “✍️” are placeholders signifying requests for +input. Replace them with your responses. + +If you are unsure of something, do your best. - + + - **Version**: ✍️ + + + - **Platform**: ✍️ + + + - **Subsystem**: ✍️ ## Location @@ -37,18 +56,22 @@ Subsystem: if known, please specify affected core module name _Section of the site where the content exists_ Affected URL(s): + - https://nodejs.org/api/✍️ -## Problem description +## Description -_Concise explanation of what you found to be problematic_ +_Concise explanation of the problem_ - + ✍️ --- - + -- [ ] I would like to work on this issue and submit a pull request. +- [ ] I would like to work on this issue and + submit a pull request. From 28ce378e176790f26a121cd72f8f37f50866132e Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 11 Jul 2020 18:12:18 -0700 Subject: [PATCH 105/138] test: fix flaky test-http2-reset-flood Set `allowHalfOpen: true` in the client. Fixes: https://github.com/nodejs/node/issues/29802 Refs: https://github.com/nodejs/node/pull/31806 PR-URL: https://github.com/nodejs/node/pull/34318 Reviewed-By: Anna Henningsen Reviewed-By: Robert Nagy --- test/parallel/parallel.status | 4 ---- test/parallel/test-http2-reset-flood.js | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index d95b3e45d40252..b50684d96fcc7e 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -5,8 +5,6 @@ prefix parallel # sample-test : PASS,FLAKY [true] # This section applies to all platforms -# https://github.com/nodejs/node/issues/29802 -test-http2-reset-flood: PASS,FLAKY [$system==win32] # https://github.com/nodejs/node/issues/32863 @@ -48,8 +46,6 @@ test-fs-stream-construct: PASS,FLAKY [$system==freebsd] # https://github.com/nodejs/node/issues/31727 test-fs-stat-bigint: PASS,FLAKY -# https://github.com/nodejs/node/issues/29802 -test-http2-reset-flood: PASS,FLAKY # https://github.com/nodejs/node/issues/28803 test-stdout-close-catch: PASS,FLAKY # https://github.com/nodejs/node/issues/31280 diff --git a/test/parallel/test-http2-reset-flood.js b/test/parallel/test-http2-reset-flood.js index 25520f81f23717..a20970862091ca 100644 --- a/test/parallel/test-http2-reset-flood.js +++ b/test/parallel/test-http2-reset-flood.js @@ -28,7 +28,7 @@ if (process.env.HAS_STARTED_WORKER) { process.env.HAS_STARTED_WORKER = 1; const worker = new Worker(__filename).on('message', common.mustCall((port) => { const h2header = Buffer.alloc(9); - const conn = net.connect(port); + const conn = net.connect({ port, allowHalfOpen: true }); conn.write('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n'); From 0b42e5d2054b94e017c18c0980925f1538ff929a Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Tue, 14 Jul 2020 09:32:24 -0400 Subject: [PATCH 106/138] doc: add danielleadams to collaborators PR-URL: https://github.com/nodejs/node/pull/34360 Reviewed-By: Anna Henningsen Reviewed-By: Rich Trott Reviewed-By: Gireesh Punathil --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8ef40a4d56fff8..85211650f71096 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,8 @@ For information about the governance of the Node.js project, see **Shelley Vohr** <codebytere@gmail.com> (she/her) * [danbev](https://github.com/danbev) - **Daniel Bevenius** <daniel.bevenius@gmail.com> (he/him) +* [danielleadams](https://github.com/danielleadams) - +**Danielle Adams** <adamzdanielle@gmail.com> (she/her) * [davisjam](https://github.com/davisjam) - **Jamie Davis** <davisjam@vt.edu> (he/him) * [devnexen](https://github.com/devnexen) - From 16160e654f2018df2a496cdfb7b1d5e32cd49887 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 11 Jul 2020 16:17:31 -0700 Subject: [PATCH 107/138] Revert "http2: streamline OnStreamRead streamline memory accounting" This reverts commit 51ccf1b5e90540a11c33866da15d4a7f52d7fddb. Fixes: https://github.com/nodejs/node/issues/31089 PR-URL: https://github.com/nodejs/node/pull/34315 Reviewed-By: Anna Henningsen Reviewed-By: David Carlier Reviewed-By: James M Snell Reviewed-By: Denys Otrishko --- src/node_http2.cc | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/node_http2.cc b/src/node_http2.cc index de7a7f044e28c2..3227ae66a2dead 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -1754,11 +1754,7 @@ void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { statistics_.data_received += nread; - if (LIKELY(stream_buf_offset_ == 0)) { - // Shrink to the actual amount of used data. - buf.Resize(nread); - IncrementCurrentSessionMemory(nread); - } else { + if (UNLIKELY(stream_buf_offset_ > 0)) { // This is a very unlikely case, and should only happen if the ReadStart() // call in OnStreamAfterWrite() immediately provides data. If that does // happen, we concatenate the data we received with the already-stored @@ -1769,20 +1765,20 @@ void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { memcpy(new_buf.data(), stream_buf_.base + stream_buf_offset_, pending_len); memcpy(new_buf.data() + pending_len, buf.data(), nread); - // The data in stream_buf_ is already accounted for, add nread received - // bytes to session memory but remove the already processed - // stream_buf_offset_ bytes. - // TODO(@jasnell): There are some cases where nread is < stream_buf_offset_ - // here but things still work. Those need to be investigated. - // CHECK_GE(nread, stream_buf_offset_); - IncrementCurrentSessionMemory(nread - stream_buf_offset_); - buf = std::move(new_buf); nread = buf.size(); stream_buf_offset_ = 0; stream_buf_ab_.Reset(); + + // We have now fully processed the stream_buf_ input chunk (by moving the + // remaining part into buf, which will be accounted for below). + DecrementCurrentSessionMemory(stream_buf_.len); } + // Shrink to the actual amount of used data. + buf.Resize(nread); + IncrementCurrentSessionMemory(nread); + // Remember the current buffer, so that OnDataChunkReceived knows the // offset of a DATA frame's data into the socket read buffer. stream_buf_ = uv_buf_init(buf.data(), static_cast(nread)); From 73d6792a059f7968c2535397b59d95eee5de7bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sat, 16 May 2020 16:31:15 +0200 Subject: [PATCH 108/138] repl: support --loader option in builtin REPL Fixes: https://github.com/nodejs/node/issues/33435 PR-URL: https://github.com/nodejs/node/pull/33437 Reviewed-By: Gus Caplan Reviewed-By: Ruben Bridgewater --- lib/internal/main/repl.js | 49 ++++++++++--------- lib/internal/modules/run_main.js | 15 +----- lib/internal/process/esm_loader.js | 20 +++++++- .../esm_display_syntax_error_import.out | 1 + ...esm_display_syntax_error_import_module.out | 1 + test/message/esm_loader_not_found.out | 8 +-- .../esm_loader_not_found_cjs_hint_bare.out | 2 +- ...esm_loader_not_found_cjs_hint_relative.out | 8 +-- 8 files changed, 58 insertions(+), 46 deletions(-) diff --git a/lib/internal/main/repl.js b/lib/internal/main/repl.js index 693b7048a37f9c..a8356687ccedf5 100644 --- a/lib/internal/main/repl.js +++ b/lib/internal/main/repl.js @@ -7,6 +7,7 @@ const { prepareMainThreadExecution } = require('internal/bootstrap/pre_execution'); +const esmLoader = require('internal/process/esm_loader'); const { evalScript } = require('internal/process/execution'); @@ -32,31 +33,33 @@ if (process.env.NODE_REPL_EXTERNAL_MODULE) { process.exit(1); } - console.log(`Welcome to Node.js ${process.version}.\n` + - 'Type ".help" for more information.'); + esmLoader.loadESM(() => { + console.log(`Welcome to Node.js ${process.version}.\n` + + 'Type ".help" for more information.'); - const cliRepl = require('internal/repl'); - cliRepl.createInternalRepl(process.env, (err, repl) => { - if (err) { - throw err; - } - repl.on('exit', () => { - if (repl._flushing) { - repl.pause(); - return repl.once('flushHistory', () => { - process.exit(); - }); + const cliRepl = require('internal/repl'); + cliRepl.createInternalRepl(process.env, (err, repl) => { + if (err) { + throw err; } - process.exit(); + repl.on('exit', () => { + if (repl._flushing) { + repl.pause(); + return repl.once('flushHistory', () => { + process.exit(); + }); + } + process.exit(); + }); }); - }); - // If user passed '-e' or '--eval' along with `-i` or `--interactive`, - // evaluate the code in the current context. - if (getOptionValue('[has_eval_string]')) { - evalScript('[eval]', - getOptionValue('--eval'), - getOptionValue('--inspect-brk'), - getOptionValue('--print')); - } + // If user passed '-e' or '--eval' along with `-i` or `--interactive`, + // evaluate the code in the current context. + if (getOptionValue('[has_eval_string]')) { + evalScript('[eval]', + getOptionValue('--eval'), + getOptionValue('--inspect-brk'), + getOptionValue('--print')); + } + }); } diff --git a/lib/internal/modules/run_main.js b/lib/internal/modules/run_main.js index 5f8b1f53d33768..0967ef539ca20e 100644 --- a/lib/internal/modules/run_main.js +++ b/lib/internal/modules/run_main.js @@ -40,21 +40,10 @@ function shouldUseESMLoader(mainPath) { function runMainESM(mainPath) { const esmLoader = require('internal/process/esm_loader'); const { pathToFileURL } = require('internal/url'); - const { hasUncaughtExceptionCaptureCallback } = - require('internal/process/execution'); - return esmLoader.initializeLoader().then(() => { + esmLoader.loadESM((ESMLoader) => { const main = path.isAbsolute(mainPath) ? pathToFileURL(mainPath).href : mainPath; - return esmLoader.ESMLoader.import(main); - }).catch((e) => { - if (hasUncaughtExceptionCaptureCallback()) { - process._fatalException(e); - return; - } - internalBinding('errors').triggerUncaughtException( - e, - true /* fromPromise */ - ); + return ESMLoader.import(main); }); } diff --git a/lib/internal/process/esm_loader.js b/lib/internal/process/esm_loader.js index fe47098fde2f63..8f076b3ef32efd 100644 --- a/lib/internal/process/esm_loader.js +++ b/lib/internal/process/esm_loader.js @@ -4,6 +4,9 @@ const { ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING, } = require('internal/errors').codes; const { Loader } = require('internal/modules/esm/loader'); +const { + hasUncaughtExceptionCaptureCallback, +} = require('internal/process/execution'); const { pathToFileURL } = require('internal/url'); const { getModuleFromWrap, @@ -34,7 +37,6 @@ exports.importModuleDynamicallyCallback = async function(wrap, specifier) { let ESMLoader = new Loader(); exports.ESMLoader = ESMLoader; -exports.initializeLoader = initializeLoader; async function initializeLoader() { const { getOptionValue } = require('internal/options'); const userLoader = getOptionValue('--experimental-loader'); @@ -59,3 +61,19 @@ async function initializeLoader() { return exports.ESMLoader = ESMLoader; })(); } + +exports.loadESM = async function loadESM(callback) { + try { + await initializeLoader(); + await callback(ESMLoader); + } catch (err) { + if (hasUncaughtExceptionCaptureCallback()) { + process._fatalException(err); + return; + } + internalBinding('errors').triggerUncaughtException( + err, + true /* fromPromise */ + ); + } +}; diff --git a/test/message/esm_display_syntax_error_import.out b/test/message/esm_display_syntax_error_import.out index 387a63a734b512..fe174d54a5c49f 100644 --- a/test/message/esm_display_syntax_error_import.out +++ b/test/message/esm_display_syntax_error_import.out @@ -5,3 +5,4 @@ SyntaxError: The requested module '../fixtures/es-module-loaders/module-named-ex at ModuleJob._instantiate (internal/modules/esm/module_job.js:*:*) at async ModuleJob.run (internal/modules/esm/module_job.js:*:*) at async Loader.import (internal/modules/esm/loader.js:*:*) + at async Object.loadESM (internal/process/esm_loader.js:*:*) diff --git a/test/message/esm_display_syntax_error_import_module.out b/test/message/esm_display_syntax_error_import_module.out index ae8b99d55fef20..d220627bd02654 100644 --- a/test/message/esm_display_syntax_error_import_module.out +++ b/test/message/esm_display_syntax_error_import_module.out @@ -5,3 +5,4 @@ SyntaxError: The requested module './module-named-exports.mjs' does not provide at ModuleJob._instantiate (internal/modules/esm/module_job.js:*:*) at async ModuleJob.run (internal/modules/esm/module_job.js:*:*) at async Loader.import (internal/modules/esm/loader.js:*:*) + at async Object.loadESM (internal/process/esm_loader.js:*:*) diff --git a/test/message/esm_loader_not_found.out b/test/message/esm_loader_not_found.out index 1d2aa957150082..60abb529a3c871 100644 --- a/test/message/esm_loader_not_found.out +++ b/test/message/esm_loader_not_found.out @@ -1,6 +1,6 @@ (node:*) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time (Use `node --trace-warnings ...` to show where the warning was created) -internal/modules/run_main.js:* +internal/process/esm_loader.js:* internalBinding('errors').triggerUncaughtException( ^ Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'i-dont-exist' imported from * @@ -11,8 +11,8 @@ Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'i-dont-exist' imported from * at Loader.getModuleJob (internal/modules/esm/loader.js:*:*) at Loader.import (internal/modules/esm/loader.js:*:*) at internal/process/esm_loader.js:*:* - at Object.initializeLoader (internal/process/esm_loader.js:*:*) - at runMainESM (internal/modules/run_main.js:*:*) - at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:*:*) { + at initializeLoader (internal/process/esm_loader.js:*:*) + at Object.loadESM (internal/process/esm_loader.js:*:*) + at runMainESM (internal/modules/run_main.js:*:*) { code: 'ERR_MODULE_NOT_FOUND' } diff --git a/test/message/esm_loader_not_found_cjs_hint_bare.out b/test/message/esm_loader_not_found_cjs_hint_bare.out index e56f1da0f6e76e..51a99cb29886bd 100644 --- a/test/message/esm_loader_not_found_cjs_hint_bare.out +++ b/test/message/esm_loader_not_found_cjs_hint_bare.out @@ -1,4 +1,4 @@ -internal/modules/run_main.js:* +internal/process/esm_loader.js:* internalBinding('errors').triggerUncaughtException( ^ diff --git a/test/message/esm_loader_not_found_cjs_hint_relative.out b/test/message/esm_loader_not_found_cjs_hint_relative.out index 76df3163bb728c..f7460c31416dc9 100644 --- a/test/message/esm_loader_not_found_cjs_hint_relative.out +++ b/test/message/esm_loader_not_found_cjs_hint_relative.out @@ -1,6 +1,6 @@ (node:*) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time (Use `node --trace-warnings ...` to show where the warning was created) -internal/modules/run_main.js:* +internal/process/esm_loader.js:* internalBinding('errors').triggerUncaughtException( ^ @@ -13,8 +13,8 @@ Did you mean to import ./test/common/fixtures.js? at Loader.getModuleJob (internal/modules/esm/loader.js:*:*) at Loader.import (internal/modules/esm/loader.js:*:*) at internal/process/esm_loader.js:*:* - at Object.initializeLoader (internal/process/esm_loader.js:*:*) - at runMainESM (internal/modules/run_main.js:*:*) - at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:*:*) { + at initializeLoader (internal/process/esm_loader.js:*:*) + at Object.loadESM (internal/process/esm_loader.js:*:*) + at runMainESM (internal/modules/run_main.js:*:*) { code: 'ERR_MODULE_NOT_FOUND' } From b2cd87e6115ec2c42af39eb62bbb603f1127bdc6 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 7 Jul 2020 22:03:17 +0200 Subject: [PATCH 109/138] src,doc,test: remove String::New default parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `kNormal` has been the implicit default for a while now (since V8 7.6). Refs: https://github.com/v8/v8/commit/e0d7f816990ada28ebe1281ca9431236ef8c6e4f Backport-PR-URL: https://github.com/nodejs/node/pull/34358 PR-URL: https://github.com/nodejs/node/pull/34248 Reviewed-By: Ben Noordhuis Reviewed-By: Tobias Nießen Reviewed-By: James M Snell --- doc/api/addons.md | 42 ++++++------------- src/README.md | 4 +- src/api/callback.cc | 4 +- src/api/environment.cc | 3 +- src/api/exceptions.cc | 19 +++------ src/cares_wrap.cc | 5 +-- src/heap_utils.cc | 11 ++--- src/node_credentials.cc | 4 +- src/node_crypto.cc | 7 ++-- src/node_env_var.cc | 3 +- src/node_i18n.cc | 3 +- src/node_os.cc | 6 +-- src/node_perf.cc | 7 +--- src/node_process_events.cc | 12 ++---- src/node_report_module.cc | 21 +++------- src/node_url.cc | 16 ++----- src/node_v8.cc | 5 +-- src/spawn_sync.cc | 3 +- src/tls_wrap.cc | 2 +- src/util.h | 6 +-- test/addons/async-hooks-promise/binding.cc | 3 +- test/addons/async-resource/binding.cc | 6 +-- test/addons/dlopen-ping-pong/binding.cc | 2 +- test/addons/heap-profiler/binding.cc | 2 +- .../hello-world-function-export/binding.cc | 2 +- test/addons/hello-world/binding.cc | 5 +-- test/addons/load-long-path/binding.cc | 2 +- test/addons/new-target/binding.cc | 2 +- test/addons/non-node-context/binding.cc | 3 +- test/addons/openssl-binding/binding.cc | 2 +- test/addons/parse-encoding/binding.cc | 3 +- test/addons/symlinked-module/binding.cc | 2 +- test/addons/worker-buffer-callback/binding.cc | 3 +- test/addons/zlib-binding/binding.cc | 2 +- test/cctest/test_environment.cc | 20 ++++----- test/cctest/test_linked_binding.cc | 24 +++++------ 36 files changed, 95 insertions(+), 171 deletions(-) diff --git a/doc/api/addons.md b/doc/api/addons.md index 9a2b6d1a536359..fca5d2a154db4f 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -65,7 +65,6 @@ namespace demo { using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; @@ -73,7 +72,7 @@ using v8::Value; void Method(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(String::NewFromUtf8( - isolate, "world", NewStringType::kNormal).ToLocalChecked()); + isolate, "world").ToLocalChecked()); } void Initialize(Local exports) { @@ -226,8 +225,7 @@ NODE_MODULE_INIT(/* exports, module, context */) { // per-addon-instance data we created above by passing `external` as the // third parameter to the `FunctionTemplate` constructor. exports->Set(context, - String::NewFromUtf8(isolate, "method", NewStringType::kNormal) - .ToLocalChecked(), + String::NewFromUtf8(isolate, "method").ToLocalChecked(), FunctionTemplate::New(isolate, Method, external) ->GetFunction(context).ToLocalChecked()).FromJust(); } @@ -538,7 +536,6 @@ using v8::Exception; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Number; using v8::Object; using v8::String; @@ -555,8 +552,7 @@ void Add(const FunctionCallbackInfo& args) { // Throw an Error that is passed back to JavaScript isolate->ThrowException(Exception::TypeError( String::NewFromUtf8(isolate, - "Wrong number of arguments", - NewStringType::kNormal).ToLocalChecked())); + "Wrong number of arguments").ToLocalChecked())); return; } @@ -564,8 +560,7 @@ void Add(const FunctionCallbackInfo& args) { if (!args[0]->IsNumber() || !args[1]->IsNumber()) { isolate->ThrowException(Exception::TypeError( String::NewFromUtf8(isolate, - "Wrong arguments", - NewStringType::kNormal).ToLocalChecked())); + "Wrong arguments").ToLocalChecked())); return; } @@ -614,7 +609,6 @@ using v8::Function; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Null; using v8::Object; using v8::String; @@ -627,8 +621,7 @@ void RunCallback(const FunctionCallbackInfo& args) { const unsigned argc = 1; Local argv[argc] = { String::NewFromUtf8(isolate, - "hello world", - NewStringType::kNormal).ToLocalChecked() }; + "hello world").ToLocalChecked() }; cb->Call(context, Null(isolate), argc, argv).ToLocalChecked(); } @@ -676,7 +669,6 @@ using v8::Context; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; @@ -688,8 +680,7 @@ void CreateObject(const FunctionCallbackInfo& args) { Local obj = Object::New(isolate); obj->Set(context, String::NewFromUtf8(isolate, - "msg", - NewStringType::kNormal).ToLocalChecked(), + "msg").ToLocalChecked(), args[0]->ToString(context).ToLocalChecked()) .FromJust(); @@ -734,7 +725,6 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; @@ -742,7 +732,7 @@ using v8::Value; void MyFunction(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(String::NewFromUtf8( - isolate, "hello world", NewStringType::kNormal).ToLocalChecked()); + isolate, "hello world").ToLocalChecked()); } void CreateFunction(const FunctionCallbackInfo& args) { @@ -754,7 +744,7 @@ void CreateFunction(const FunctionCallbackInfo& args) { // omit this to make it anonymous fn->SetName(String::NewFromUtf8( - isolate, "theFunction", NewStringType::kNormal).ToLocalChecked()); + isolate, "theFunction").ToLocalChecked()); args.GetReturnValue().Set(fn); } @@ -850,7 +840,6 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Number; using v8::Object; using v8::ObjectTemplate; @@ -874,8 +863,7 @@ void MyObject::Init(Local exports) { // Prepare constructor template Local tpl = FunctionTemplate::New(isolate, New, addon_data); - tpl->SetClassName(String::NewFromUtf8( - isolate, "MyObject", NewStringType::kNormal).ToLocalChecked()); + tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype @@ -884,8 +872,8 @@ void MyObject::Init(Local exports) { Local constructor = tpl->GetFunction(context).ToLocalChecked(); addon_data->SetInternalField(0, constructor); exports->Set(context, String::NewFromUtf8( - isolate, "MyObject", NewStringType::kNormal).ToLocalChecked(), - constructor).FromJust(); + isolate, "MyObject").ToLocalChecked(), + constructor).FromJust(); } void MyObject::New(const FunctionCallbackInfo& args) { @@ -1055,7 +1043,6 @@ using v8::FunctionTemplate; using v8::Global; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Number; using v8::Object; using v8::String; @@ -1074,8 +1061,7 @@ MyObject::~MyObject() { void MyObject::Init(Isolate* isolate) { // Prepare constructor template Local tpl = FunctionTemplate::New(isolate, New); - tpl->SetClassName(String::NewFromUtf8( - isolate, "MyObject", NewStringType::kNormal).ToLocalChecked()); + tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype @@ -1279,7 +1265,6 @@ using v8::FunctionTemplate; using v8::Global; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; @@ -1297,8 +1282,7 @@ MyObject::~MyObject() { void MyObject::Init(Isolate* isolate) { // Prepare constructor template Local tpl = FunctionTemplate::New(isolate, New); - tpl->SetClassName(String::NewFromUtf8( - isolate, "MyObject", NewStringType::kNormal).ToLocalChecked()); + tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Local context = isolate->GetCurrentContext(); diff --git a/src/README.md b/src/README.md index a3a6a71aa55544..079326cd200a49 100644 --- a/src/README.md +++ b/src/README.md @@ -146,9 +146,7 @@ v8::Local GetFoo(v8::Local context, // The 'foo_string' handle cannot be returned from this function because // it is not “escaped” with `.Escape()`. v8::Local foo_string = - v8::String::NewFromUtf8(isolate, - "foo", - v8::NewStringType::kNormal).ToLocalChecked(); + v8::String::NewFromUtf8(isolate, "foo").ToLocalChecked(); v8::Local return_value; if (obj->Get(context, foo_string).ToLocal(&return_value)) { diff --git a/src/api/callback.cc b/src/api/callback.cc index 2bb34b088f74e1..84664c089594eb 100644 --- a/src/api/callback.cc +++ b/src/api/callback.cc @@ -13,7 +13,6 @@ using v8::Isolate; using v8::Local; using v8::MaybeLocal; using v8::MicrotasksScope; -using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; @@ -214,8 +213,7 @@ MaybeLocal MakeCallback(Isolate* isolate, Local argv[], async_context asyncContext) { Local method_string = - String::NewFromUtf8(isolate, method, NewStringType::kNormal) - .ToLocalChecked(); + String::NewFromUtf8(isolate, method).ToLocalChecked(); return MakeCallback(isolate, recv, method_string, argc, argv, asyncContext); } diff --git a/src/api/environment.cc b/src/api/environment.cc index 90cb2be2e6edc8..fdfd257aec12f5 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc @@ -437,8 +437,7 @@ MaybeLocal LoadEnvironment( // This is a slightly hacky way to convert UTF-8 to UTF-16. Local str = String::NewFromUtf8(env->isolate(), - main_script_source_utf8, - v8::NewStringType::kNormal).ToLocalChecked(); + main_script_source_utf8).ToLocalChecked(); auto main_utf16 = std::make_unique(env->isolate(), str); // TODO(addaleax): Avoid having a global table for all scripts. diff --git a/src/api/exceptions.cc b/src/api/exceptions.cc index 998d370d3b5fd6..310b2acc4073d6 100644 --- a/src/api/exceptions.cc +++ b/src/api/exceptions.cc @@ -15,7 +15,6 @@ using v8::Exception; using v8::Integer; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; @@ -42,8 +41,7 @@ Local ErrnoException(Isolate* isolate, Local path_string; if (path != nullptr) { // FIXME(bnoordhuis) It's questionable to interpret the file path as UTF-8. - path_string = String::NewFromUtf8(isolate, path, NewStringType::kNormal) - .ToLocalChecked(); + path_string = String::NewFromUtf8(isolate, path).ToLocalChecked(); } if (path_string.IsEmpty() == false) { @@ -78,16 +76,13 @@ static Local StringFromPath(Isolate* isolate, const char* path) { return String::Concat( isolate, FIXED_ONE_BYTE_STRING(isolate, "\\\\"), - String::NewFromUtf8(isolate, path + 8, NewStringType::kNormal) - .ToLocalChecked()); + String::NewFromUtf8(isolate, path + 8).ToLocalChecked()); } else if (strncmp(path, "\\\\?\\", 4) == 0) { - return String::NewFromUtf8(isolate, path + 4, NewStringType::kNormal) - .ToLocalChecked(); + return String::NewFromUtf8(isolate, path + 4).ToLocalChecked(); } #endif - return String::NewFromUtf8(isolate, path, NewStringType::kNormal) - .ToLocalChecked(); + return String::NewFromUtf8(isolate, path).ToLocalChecked(); } @@ -206,8 +201,7 @@ Local WinapiErrnoException(Isolate* isolate, Local cons2 = String::Concat( isolate, cons1, - String::NewFromUtf8(isolate, path, NewStringType::kNormal) - .ToLocalChecked()); + String::NewFromUtf8(isolate, path).ToLocalChecked()); Local cons3 = String::Concat(isolate, cons2, FIXED_ONE_BYTE_STRING(isolate, "'")); e = Exception::Error(cons3); @@ -222,8 +216,7 @@ Local WinapiErrnoException(Isolate* isolate, if (path != nullptr) { obj->Set(env->context(), env->path_string(), - String::NewFromUtf8(isolate, path, NewStringType::kNormal) - .ToLocalChecked()) + String::NewFromUtf8(isolate, path).ToLocalChecked()) .Check(); } diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 4a332db71279a4..73a0ac6b334345 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -66,7 +66,6 @@ using v8::Int32; using v8::Integer; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Null; using v8::Object; using v8::String; @@ -1937,8 +1936,8 @@ void CanonicalizeIP(const FunctionCallbackInfo& args) { char canonical_ip[INET6_ADDRSTRLEN]; const int af = (rc == 4 ? AF_INET : AF_INET6); CHECK_EQ(0, uv_inet_ntop(af, &result, canonical_ip, sizeof(canonical_ip))); - Local val = String::NewFromUtf8(isolate, canonical_ip, - NewStringType::kNormal).ToLocalChecked(); + Local val = String::NewFromUtf8(isolate, canonical_ip) + .ToLocalChecked(); args.GetReturnValue().Set(val); } diff --git a/src/heap_utils.cc b/src/heap_utils.cc index 386bf61e4eca00..449feb9e78d0e1 100644 --- a/src/heap_utils.cc +++ b/src/heap_utils.cc @@ -118,8 +118,7 @@ class JSGraph : public EmbedderGraph { name_str += " "; name_str += n->Name(); } - if (!String::NewFromUtf8( - isolate_, name_str.c_str(), v8::NewStringType::kNormal) + if (!String::NewFromUtf8(isolate_, name_str.c_str()) .ToLocal(&value) || obj->Set(context, name_string, value).IsNothing() || obj->Set(context, @@ -168,9 +167,8 @@ class JSGraph : public EmbedderGraph { Local edge_name_value; const char* edge_name = edge.first; if (edge_name != nullptr) { - if (!String::NewFromUtf8( - isolate_, edge_name, v8::NewStringType::kNormal) - .ToLocal(&edge_name_value)) { + if (!String::NewFromUtf8(isolate_, edge_name) + .ToLocal(&edge_name_value)) { return MaybeLocal(); } } else { @@ -377,8 +375,7 @@ void TriggerHeapSnapshot(const FunctionCallbackInfo& args) { DiagnosticFilename name(env, "Heap", "heapsnapshot"); if (!WriteSnapshot(isolate, *name)) return; - if (String::NewFromUtf8(isolate, *name, v8::NewStringType::kNormal) - .ToLocal(&filename_v)) { + if (String::NewFromUtf8(isolate, *name).ToLocal(&filename_v)) { args.GetReturnValue().Set(filename_v); } return; diff --git a/src/node_credentials.cc b/src/node_credentials.cc index d552a501726396..83db705e10df4f 100644 --- a/src/node_credentials.cc +++ b/src/node_credentials.cc @@ -20,7 +20,6 @@ using v8::HandleScope; using v8::Isolate; using v8::Local; using v8::MaybeLocal; -using v8::NewStringType; using v8::Object; using v8::String; using v8::TryCatch; @@ -46,8 +45,7 @@ bool SafeGetenv(const char* key, std::string* text, Environment* env) { TryCatch ignore_errors(env->isolate()); MaybeLocal maybe_value = env->env_vars()->Get( env->isolate(), - String::NewFromUtf8(env->isolate(), key, NewStringType::kNormal) - .ToLocalChecked()); + String::NewFromUtf8(env->isolate(), key).ToLocalChecked()); Local value; if (!maybe_value.ToLocal(&value)) goto fail; String::Utf8Value utf8_value(env->isolate(), value); diff --git a/src/node_crypto.cc b/src/node_crypto.cc index eae0f2e49d3c86..dfc21ae6876105 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -392,8 +392,7 @@ void ThrowCryptoError(Environment* env, } HandleScope scope(env->isolate()); Local exception_string = - String::NewFromUtf8(env->isolate(), message, NewStringType::kNormal) - .ToLocalChecked(); + String::NewFromUtf8(env->isolate(), message).ToLocalChecked(); CryptoErrorVector errors; errors.Capture(); Local exception; @@ -1017,8 +1016,8 @@ void GetRootCertificates(const FunctionCallbackInfo& args) { for (size_t i = 0; i < arraysize(root_certs); i++) { if (!String::NewFromOneByte( env->isolate(), - reinterpret_cast(root_certs[i]), - NewStringType::kNormal).ToLocal(&result[i])) { + reinterpret_cast(root_certs[i])) + .ToLocal(&result[i])) { return; } } diff --git a/src/node_env_var.cc b/src/node_env_var.cc index 23eaad48586130..1a162888fd37a7 100644 --- a/src/node_env_var.cc +++ b/src/node_env_var.cc @@ -179,8 +179,7 @@ Local RealEnvStore::Enumerate(Isolate* isolate) const { // https://github.com/libuv/libuv/pull/2473 and can be removed later. if (items[i].name[0] == '=' || items[i].name[0] == '\0') continue; #endif - MaybeLocal str = String::NewFromUtf8( - isolate, items[i].name, NewStringType::kNormal); + MaybeLocal str = String::NewFromUtf8(isolate, items[i].name); if (str.IsEmpty()) { isolate->ThrowException(ERR_STRING_TOO_LONG(isolate)); return Local(); diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 5382e469a4087c..cc2d245b8a77d9 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -338,8 +338,7 @@ void ICUErrorName(const FunctionCallbackInfo& args) { UErrorCode status = static_cast(args[0].As()->Value()); args.GetReturnValue().Set( String::NewFromUtf8(env->isolate(), - u_errorName(status), - NewStringType::kNormal).ToLocalChecked()); + u_errorName(status)).ToLocalChecked()); } } // anonymous namespace diff --git a/src/node_os.cc b/src/node_os.cc index 085fb1aef01c32..2e151ac4f89213 100644 --- a/src/node_os.cc +++ b/src/node_os.cc @@ -71,8 +71,7 @@ static void GetHostname(const FunctionCallbackInfo& args) { } args.GetReturnValue().Set( - String::NewFromUtf8(env->isolate(), buf, NewStringType::kNormal) - .ToLocalChecked()); + String::NewFromUtf8(env->isolate(), buf).ToLocalChecked()); } static void GetOSInformation(const FunctionCallbackInfo& args) { @@ -192,8 +191,7 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo& args) { // to assume UTF8 as the default as well. It’s what people will expect if // they name the interface from any input that uses UTF-8, which should be // the most frequent case by far these days.) - name = String::NewFromUtf8(isolate, raw_name, - NewStringType::kNormal).ToLocalChecked(); + name = String::NewFromUtf8(isolate, raw_name).ToLocalChecked(); snprintf(mac.data(), mac.size(), diff --git a/src/node_perf.cc b/src/node_perf.cc index 916a9974d5d6f9..b5efc05689f20c 100644 --- a/src/node_perf.cc +++ b/src/node_perf.cc @@ -24,7 +24,6 @@ using v8::Isolate; using v8::Local; using v8::Map; using v8::MaybeLocal; -using v8::NewStringType; using v8::Number; using v8::Object; using v8::PropertyAttribute; @@ -60,16 +59,14 @@ inline void InitObject(const PerformanceEntry& entry, Local obj) { obj->DefineOwnProperty(context, env->name_string(), String::NewFromUtf8(isolate, - entry.name().c_str(), - NewStringType::kNormal) + entry.name().c_str()) .ToLocalChecked(), attr) .Check(); obj->DefineOwnProperty(context, env->entry_type_string(), String::NewFromUtf8(isolate, - entry.type().c_str(), - NewStringType::kNormal) + entry.type().c_str()) .ToLocalChecked(), attr) .Check(); diff --git a/src/node_process_events.cc b/src/node_process_events.cc index 1b902949e264e0..0c149b26e334b0 100644 --- a/src/node_process_events.cc +++ b/src/node_process_events.cc @@ -14,7 +14,6 @@ using v8::Just; using v8::Local; using v8::Maybe; using v8::MaybeLocal; -using v8::NewStringType; using v8::Nothing; using v8::Object; using v8::String; @@ -58,21 +57,18 @@ Maybe ProcessEmitWarningGeneric(Environment* env, // The caller has to be able to handle a failure anyway, so we might as well // do proper error checking for string creation. - if (!String::NewFromUtf8(env->isolate(), warning, NewStringType::kNormal) - .ToLocal(&args[argc++])) { + if (!String::NewFromUtf8(env->isolate(), warning).ToLocal(&args[argc++])) return Nothing(); - } + if (type != nullptr) { if (!String::NewFromOneByte(env->isolate(), - reinterpret_cast(type), - NewStringType::kNormal) + reinterpret_cast(type)) .ToLocal(&args[argc++])) { return Nothing(); } if (code != nullptr && !String::NewFromOneByte(env->isolate(), - reinterpret_cast(code), - NewStringType::kNormal) + reinterpret_cast(code)) .ToLocal(&args[argc++])) { return Nothing(); } diff --git a/src/node_report_module.cc b/src/node_report_module.cc index d9dad28221a5cf..97c6bea3ad5ec5 100644 --- a/src/node_report_module.cc +++ b/src/node_report_module.cc @@ -49,8 +49,7 @@ void WriteReport(const FunctionCallbackInfo& info) { isolate, env, *message, *trigger, filename, error); // Return value is the report filename info.GetReturnValue().Set( - String::NewFromUtf8(isolate, filename.c_str(), v8::NewStringType::kNormal) - .ToLocalChecked()); + String::NewFromUtf8(isolate, filename.c_str()).ToLocalChecked()); } // External JavaScript API for returning a report @@ -71,10 +70,8 @@ void GetReport(const FunctionCallbackInfo& info) { isolate, env, "JavaScript API", __func__, error, out); // Return value is the contents of a report as a string. - info.GetReturnValue().Set(String::NewFromUtf8(isolate, - out.str().c_str(), - v8::NewStringType::kNormal) - .ToLocalChecked()); + info.GetReturnValue().Set( + String::NewFromUtf8(isolate, out.str().c_str()).ToLocalChecked()); } static void GetCompact(const FunctionCallbackInfo& info) { @@ -94,9 +91,7 @@ static void GetDirectory(const FunctionCallbackInfo& info) { node::Mutex::ScopedLock lock(node::per_process::cli_options_mutex); Environment* env = Environment::GetCurrent(info); std::string directory = node::per_process::cli_options->report_directory; - auto result = String::NewFromUtf8(env->isolate(), - directory.c_str(), - v8::NewStringType::kNormal); + auto result = String::NewFromUtf8(env->isolate(), directory.c_str()); info.GetReturnValue().Set(result.ToLocalChecked()); } @@ -112,9 +107,7 @@ static void GetFilename(const FunctionCallbackInfo& info) { node::Mutex::ScopedLock lock(node::per_process::cli_options_mutex); Environment* env = Environment::GetCurrent(info); std::string filename = node::per_process::cli_options->report_filename; - auto result = String::NewFromUtf8(env->isolate(), - filename.c_str(), - v8::NewStringType::kNormal); + auto result = String::NewFromUtf8(env->isolate(), filename.c_str()); info.GetReturnValue().Set(result.ToLocalChecked()); } @@ -129,9 +122,7 @@ static void SetFilename(const FunctionCallbackInfo& info) { static void GetSignal(const FunctionCallbackInfo& info) { Environment* env = Environment::GetCurrent(info); std::string signal = env->isolate_data()->options()->report_signal; - auto result = String::NewFromUtf8(env->isolate(), - signal.c_str(), - v8::NewStringType::kNormal); + auto result = String::NewFromUtf8(env->isolate(), signal.c_str()); info.GetReturnValue().Set(result.ToLocalChecked()); } diff --git a/src/node_url.cc b/src/node_url.cc index 029a04a429b7a5..4f0d5f284b14dd 100644 --- a/src/node_url.cc +++ b/src/node_url.cc @@ -2175,9 +2175,7 @@ void Parse(Environment* env, Local argv[2] = { undef, undef }; argv[ERR_ARG_FLAGS] = Integer::NewFromUnsigned(isolate, url.flags); argv[ERR_ARG_INPUT] = - String::NewFromUtf8(env->isolate(), - input, - NewStringType::kNormal).ToLocalChecked(); + String::NewFromUtf8(env->isolate(), input).ToLocalChecked(); error_cb.As()->Call(context, recv, arraysize(argv), argv) .FromMaybe(Local()); } @@ -2225,9 +2223,7 @@ void EncodeAuthSet(const FunctionCallbackInfo& args) { AppendOrEscape(&output, ch, USERINFO_ENCODE_SET); } args.GetReturnValue().Set( - String::NewFromUtf8(env->isolate(), - output.c_str(), - NewStringType::kNormal).ToLocalChecked()); + String::NewFromUtf8(env->isolate(), output.c_str()).ToLocalChecked()); } void ToUSVString(const FunctionCallbackInfo& args) { @@ -2279,9 +2275,7 @@ void DomainToASCII(const FunctionCallbackInfo& args) { } std::string out = host.ToStringMove(); args.GetReturnValue().Set( - String::NewFromUtf8(env->isolate(), - out.c_str(), - NewStringType::kNormal).ToLocalChecked()); + String::NewFromUtf8(env->isolate(), out.c_str()).ToLocalChecked()); } void DomainToUnicode(const FunctionCallbackInfo& args) { @@ -2299,9 +2293,7 @@ void DomainToUnicode(const FunctionCallbackInfo& args) { } std::string out = host.ToStringMove(); args.GetReturnValue().Set( - String::NewFromUtf8(env->isolate(), - out.c_str(), - NewStringType::kNormal).ToLocalChecked()); + String::NewFromUtf8(env->isolate(), out.c_str()).ToLocalChecked()); } void SetURLConstructor(const FunctionCallbackInfo& args) { diff --git a/src/node_v8.cc b/src/node_v8.cc index 047ca594095d16..f34125d5f49e16 100644 --- a/src/node_v8.cc +++ b/src/node_v8.cc @@ -37,7 +37,6 @@ using v8::HeapStatistics; using v8::Integer; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Object; using v8::ScriptCompiler; using v8::String; @@ -225,9 +224,7 @@ void Initialize(Local target, MaybeStackBuffer, 16> heap_spaces(number_of_heap_spaces); for (size_t i = 0; i < number_of_heap_spaces; i++) { env->isolate()->GetHeapSpaceStatistics(&s, i); - heap_spaces[i] = String::NewFromUtf8(env->isolate(), - s.space_name(), - NewStringType::kNormal) + heap_spaces[i] = String::NewFromUtf8(env->isolate(), s.space_name()) .ToLocalChecked(); } target->Set(env->context(), diff --git a/src/spawn_sync.cc b/src/spawn_sync.cc index 11126c478f76f7..d7d06be34bdb10 100644 --- a/src/spawn_sync.cc +++ b/src/spawn_sync.cc @@ -695,8 +695,7 @@ Local SyncProcessRunner::BuildResultObject() { if (term_signal_ > 0) js_result->Set(context, env()->signal_string(), String::NewFromUtf8(env()->isolate(), - signo_string(term_signal_), - v8::NewStringType::kNormal) + signo_string(term_signal_)) .ToLocalChecked()) .Check(); else diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index 792d3ea79ceea9..04c035a1e8f3e5 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -1143,7 +1143,7 @@ unsigned int TLSWrap::PskServerCallback(SSL* s, HandleScope scope(isolate); MaybeLocal maybe_identity_str = - v8::String::NewFromUtf8(isolate, identity, v8::NewStringType::kNormal); + String::NewFromUtf8(isolate, identity); v8::Local identity_str; if (!maybe_identity_str.ToLocal(&identity_str)) return 0; diff --git a/src/util.h b/src/util.h index f817eac1298d61..dc0d97f1df7dd2 100644 --- a/src/util.h +++ b/src/util.h @@ -676,11 +676,9 @@ inline v8::MaybeLocal ToV8Value(v8::Local context, do { \ v8::Isolate* isolate = target->GetIsolate(); \ v8::Local constant_name = \ - v8::String::NewFromUtf8(isolate, name, v8::NewStringType::kNormal) \ - .ToLocalChecked(); \ + v8::String::NewFromUtf8(isolate, name).ToLocalChecked(); \ v8::Local constant_value = \ - v8::String::NewFromUtf8(isolate, constant, v8::NewStringType::kNormal) \ - .ToLocalChecked(); \ + v8::String::NewFromUtf8(isolate, constant).ToLocalChecked(); \ v8::PropertyAttribute constant_attributes = \ static_cast(v8::ReadOnly | v8::DontDelete); \ target \ diff --git a/test/addons/async-hooks-promise/binding.cc b/test/addons/async-hooks-promise/binding.cc index 1571690edead24..452cbda8793aa1 100644 --- a/test/addons/async-hooks-promise/binding.cc +++ b/test/addons/async-hooks-promise/binding.cc @@ -15,8 +15,7 @@ using v8::Value; static void ThrowError(Isolate* isolate, const char* err_msg) { Local str = String::NewFromOneByte( isolate, - reinterpret_cast(err_msg), - NewStringType::kNormal).ToLocalChecked(); + reinterpret_cast(err_msg)).ToLocalChecked(); isolate->ThrowException(str); } diff --git a/test/addons/async-resource/binding.cc b/test/addons/async-resource/binding.cc index ab33858c233dd0..6fd9b37cbeda40 100644 --- a/test/addons/async-resource/binding.cc +++ b/test/addons/async-resource/binding.cc @@ -55,8 +55,7 @@ void CallViaFunction(const FunctionCallbackInfo& args) { auto r = static_cast(args[0].As()->Value()); Local name = - String::NewFromUtf8(isolate, "methöd", v8::NewStringType::kNormal) - .ToLocalChecked(); + String::NewFromUtf8(isolate, "methöd").ToLocalChecked(); Local fn = r->get_resource()->Get(isolate->GetCurrentContext(), name) .ToLocalChecked(); @@ -73,8 +72,7 @@ void CallViaString(const FunctionCallbackInfo& args) { auto r = static_cast(args[0].As()->Value()); Local name = - String::NewFromUtf8(isolate, "methöd", v8::NewStringType::kNormal) - .ToLocalChecked(); + String::NewFromUtf8(isolate, "methöd").ToLocalChecked(); Local arg = Integer::New(isolate, 42); MaybeLocal ret = r->MakeCallback(name, 1, &arg); diff --git a/test/addons/dlopen-ping-pong/binding.cc b/test/addons/dlopen-ping-pong/binding.cc index 7b211be1195bf7..c8711f09aedac6 100644 --- a/test/addons/dlopen-ping-pong/binding.cc +++ b/test/addons/dlopen-ping-pong/binding.cc @@ -38,7 +38,7 @@ void Ping(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); assert(ping_func != nullptr); args.GetReturnValue().Set(String::NewFromUtf8( - isolate, ping_func(), NewStringType::kNormal).ToLocalChecked()); + isolate, ping_func()).ToLocalChecked()); } void init(Local exports) { diff --git a/test/addons/heap-profiler/binding.cc b/test/addons/heap-profiler/binding.cc index 9e1e97e9fc2afc..98156d5548960e 100644 --- a/test/addons/heap-profiler/binding.cc +++ b/test/addons/heap-profiler/binding.cc @@ -20,7 +20,7 @@ inline void Initialize(v8::Local binding) { v8::Isolate* const isolate = binding->GetIsolate(); v8::Local context = isolate->GetCurrentContext(); binding->Set(context, v8::String::NewFromUtf8( - isolate, "test", v8::NewStringType::kNormal).ToLocalChecked(), + isolate, "test").ToLocalChecked(), v8::FunctionTemplate::New(isolate, Test) ->GetFunction(context) .ToLocalChecked()).FromJust(); diff --git a/test/addons/hello-world-function-export/binding.cc b/test/addons/hello-world-function-export/binding.cc index e5476c4ee1e364..525b8cc732b4b1 100644 --- a/test/addons/hello-world-function-export/binding.cc +++ b/test/addons/hello-world-function-export/binding.cc @@ -4,7 +4,7 @@ void Method(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(v8::String::NewFromUtf8( - isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()); + isolate, "world").ToLocalChecked()); } void init(v8::Local exports, v8::Local module) { diff --git a/test/addons/hello-world/binding.cc b/test/addons/hello-world/binding.cc index f2d26b53e985cf..77de6c45a3a8f1 100644 --- a/test/addons/hello-world/binding.cc +++ b/test/addons/hello-world/binding.cc @@ -4,7 +4,7 @@ static void Method(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(v8::String::NewFromUtf8( - isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()); + isolate, "world").ToLocalChecked()); } // Not using the full NODE_MODULE_INIT() macro here because we want to test the @@ -21,8 +21,7 @@ static void FakeInit(v8::Local exports, v8::Local context) { auto isolate = context->GetIsolate(); auto exception = v8::Exception::Error(v8::String::NewFromUtf8(isolate, - "FakeInit should never run!", v8::NewStringType::kNormal) - .ToLocalChecked()); + "FakeInit should never run!").ToLocalChecked()); isolate->ThrowException(exception); } diff --git a/test/addons/load-long-path/binding.cc b/test/addons/load-long-path/binding.cc index 02eecec099807a..cd9fdf7f406c66 100644 --- a/test/addons/load-long-path/binding.cc +++ b/test/addons/load-long-path/binding.cc @@ -4,7 +4,7 @@ void Method(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(v8::String::NewFromUtf8( - isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()); + isolate, "world").ToLocalChecked()); } void init(v8::Local exports) { diff --git a/test/addons/new-target/binding.cc b/test/addons/new-target/binding.cc index 48ceeb55ca1aae..ba747fbbe87ea7 100644 --- a/test/addons/new-target/binding.cc +++ b/test/addons/new-target/binding.cc @@ -13,7 +13,7 @@ inline void Initialize(v8::Local binding) { auto isolate = binding->GetIsolate(); auto context = isolate->GetCurrentContext(); binding->Set(context, v8::String::NewFromUtf8( - isolate, "Class", v8::NewStringType::kNormal).ToLocalChecked(), + isolate, "Class").ToLocalChecked(), v8::FunctionTemplate::New(isolate, NewClass) ->GetFunction(context) .ToLocalChecked()).FromJust(); diff --git a/test/addons/non-node-context/binding.cc b/test/addons/non-node-context/binding.cc index 776786cef5180f..6fe776b7c60c3d 100644 --- a/test/addons/non-node-context/binding.cc +++ b/test/addons/non-node-context/binding.cc @@ -35,8 +35,7 @@ inline void RunInNewContext( context->Global()->Set( context, - String::NewFromUtf8(isolate, "data", NewStringType::kNormal) - .ToLocalChecked(), + String::NewFromUtf8(isolate, "data").ToLocalChecked(), args[1]).FromJust(); assert(args[0]->IsString()); // source code diff --git a/test/addons/openssl-binding/binding.cc b/test/addons/openssl-binding/binding.cc index 6cfecc4505421e..05849b6c14fe31 100644 --- a/test/addons/openssl-binding/binding.cc +++ b/test/addons/openssl-binding/binding.cc @@ -24,7 +24,7 @@ inline void Initialize(v8::Local exports, v8::Local context) { auto isolate = context->GetIsolate(); auto key = v8::String::NewFromUtf8( - isolate, "randomBytes", v8::NewStringType::kNormal).ToLocalChecked(); + isolate, "randomBytes").ToLocalChecked(); auto value = v8::FunctionTemplate::New(isolate, RandomBytes) ->GetFunction(context) .ToLocalChecked(); diff --git a/test/addons/parse-encoding/binding.cc b/test/addons/parse-encoding/binding.cc index 1501544153ad62..cdbd8e44466db8 100644 --- a/test/addons/parse-encoding/binding.cc +++ b/test/addons/parse-encoding/binding.cc @@ -23,8 +23,7 @@ void ParseEncoding(const v8::FunctionCallbackInfo& args) { ENCODING_MAP(V) #undef V auto encoding_string = - v8::String::NewFromUtf8(args.GetIsolate(), encoding_name, - v8::NewStringType::kNormal) + v8::String::NewFromUtf8(args.GetIsolate(), encoding_name) .ToLocalChecked(); args.GetReturnValue().Set(encoding_string); } diff --git a/test/addons/symlinked-module/binding.cc b/test/addons/symlinked-module/binding.cc index 02eecec099807a..cd9fdf7f406c66 100644 --- a/test/addons/symlinked-module/binding.cc +++ b/test/addons/symlinked-module/binding.cc @@ -4,7 +4,7 @@ void Method(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(v8::String::NewFromUtf8( - isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()); + isolate, "world").ToLocalChecked()); } void init(v8::Local exports) { diff --git a/test/addons/worker-buffer-callback/binding.cc b/test/addons/worker-buffer-callback/binding.cc index ac4c0cb498b7c7..9cacc6996243bd 100644 --- a/test/addons/worker-buffer-callback/binding.cc +++ b/test/addons/worker-buffer-callback/binding.cc @@ -25,8 +25,7 @@ void Initialize(Local exports, exports->Set(context, v8::String::NewFromUtf8( - isolate, "buffer", v8::NewStringType::kNormal) - .ToLocalChecked(), + isolate, "buffer").ToLocalChecked(), node::Buffer::New( isolate, data, diff --git a/test/addons/zlib-binding/binding.cc b/test/addons/zlib-binding/binding.cc index abfb0615842594..53d25642f0d563 100644 --- a/test/addons/zlib-binding/binding.cc +++ b/test/addons/zlib-binding/binding.cc @@ -46,7 +46,7 @@ inline void Initialize(v8::Local exports, v8::Local context) { auto isolate = context->GetIsolate(); auto key = v8::String::NewFromUtf8( - isolate, "compressBytes", v8::NewStringType::kNormal).ToLocalChecked(); + isolate, "compressBytes").ToLocalChecked(); auto value = v8::FunctionTemplate::New(isolate, CompressBytes) ->GetFunction(context) .ToLocalChecked(); diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc index 11fc99a73bc5bb..6de332b59b2fe5 100644 --- a/test/cctest/test_environment.cc +++ b/test/cctest/test_environment.cc @@ -114,8 +114,8 @@ TEST_F(EnvironmentTest, PreExecutionPreparation) { v8::Local script = v8::Script::Compile( context, v8::String::NewFromOneByte(isolate_, - reinterpret_cast(run_script), - v8::NewStringType::kNormal).ToLocalChecked()) + reinterpret_cast(run_script)) + .ToLocalChecked()) .ToLocalChecked(); v8::Local result = script->Run(context).ToLocalChecked(); CHECK(result->IsString()); @@ -140,8 +140,8 @@ TEST_F(EnvironmentTest, LoadEnvironmentWithCallback) { context, v8::String::NewFromOneByte( isolate_, - reinterpret_cast("argv0"), - v8::NewStringType::kNormal).ToLocalChecked()).ToLocalChecked(); + reinterpret_cast("argv0")) + .ToLocalChecked()).ToLocalChecked(); CHECK(argv0->IsString()); return info.process_object; @@ -165,15 +165,15 @@ TEST_F(EnvironmentTest, LoadEnvironmentWithSource) { context, v8::String::NewFromOneByte( isolate_, - reinterpret_cast("process"), - v8::NewStringType::kNormal).ToLocalChecked()) + reinterpret_cast("process")) + .ToLocalChecked()) .ToLocalChecked()->IsObject()); CHECK(main_ret.As()->Get( context, v8::String::NewFromOneByte( isolate_, - reinterpret_cast("require"), - v8::NewStringType::kNormal).ToLocalChecked()) + reinterpret_cast("require")) + .ToLocalChecked()) .ToLocalChecked()->IsFunction()); } @@ -509,8 +509,8 @@ TEST_F(EnvironmentTest, InspectorMultipleEmbeddedEnvironments) { context, v8::String::NewFromOneByte( isolate_, - reinterpret_cast("messageFromWorker"), - v8::NewStringType::kNormal).ToLocalChecked()) + reinterpret_cast("messageFromWorker")) + .ToLocalChecked()) .ToLocalChecked(); CHECK_EQ(data.extracted_value, 42); CHECK_EQ(from_inspector->IntegerValue(context).FromJust(), 42); diff --git a/test/cctest/test_linked_binding.cc b/test/cctest/test_linked_binding.cc index 6724402c55aef1..523acc86c63e2a 100644 --- a/test/cctest/test_linked_binding.cc +++ b/test/cctest/test_linked_binding.cc @@ -9,11 +9,11 @@ void InitializeBinding(v8::Local exports, exports->Set( context, v8::String::NewFromOneByte(isolate, - reinterpret_cast("key"), - v8::NewStringType::kNormal).ToLocalChecked(), + reinterpret_cast("key")) + .ToLocalChecked(), v8::String::NewFromOneByte(isolate, - reinterpret_cast("value"), - v8::NewStringType::kNormal).ToLocalChecked()) + reinterpret_cast("value")) + .ToLocalChecked()) .FromJust(); } @@ -33,8 +33,8 @@ TEST_F(LinkedBindingTest, SimpleTest) { v8::Local script = v8::Script::Compile( context, v8::String::NewFromOneByte(isolate_, - reinterpret_cast(run_script), - v8::NewStringType::kNormal).ToLocalChecked()) + reinterpret_cast(run_script)) + .ToLocalChecked()) .ToLocalChecked(); v8::Local completion_value = script->Run(context).ToLocalChecked(); v8::String::Utf8Value utf8val(isolate_, completion_value); @@ -51,11 +51,11 @@ void InitializeLocalBinding(v8::Local exports, exports->Set( context, v8::String::NewFromOneByte(isolate, - reinterpret_cast("key"), - v8::NewStringType::kNormal).ToLocalChecked(), + reinterpret_cast("key")) + .ToLocalChecked(), v8::String::NewFromOneByte(isolate, - reinterpret_cast("value"), - v8::NewStringType::kNormal).ToLocalChecked()) + reinterpret_cast("value")) + .ToLocalChecked()) .FromJust(); } @@ -74,8 +74,8 @@ TEST_F(LinkedBindingTest, LocallyDefinedLinkedBindingTest) { v8::Local script = v8::Script::Compile( context, v8::String::NewFromOneByte(isolate_, - reinterpret_cast(run_script), - v8::NewStringType::kNormal).ToLocalChecked()) + reinterpret_cast(run_script)) + .ToLocalChecked()) .ToLocalChecked(); v8::Local completion_value = script->Run(context).ToLocalChecked(); v8::String::Utf8Value utf8val(isolate_, completion_value); From 8d7330be0e8a6952438c4671a84d361568b621b2 Mon Sep 17 00:00:00 2001 From: Antoine du HAMEL Date: Wed, 11 Mar 2020 23:44:31 +0100 Subject: [PATCH 110/138] module: deprecate module.parent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This feature does not work when a module is imported using ECMAScript modules specification, therefore it is deprecated. Fixes: https://github.com/nodejs/modules/issues/469 Backport-PR-URL: https://github.com/nodejs/node/pull/33533 PR-URL: https://github.com/nodejs/node/pull/32217 Reviewed-By: Gus Caplan Reviewed-By: Bradley Farias Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Matteo Collina Reviewed-By: Tobias Nießen Reviewed-By: Ruben Bridgewater --- doc/api/deprecations.md | 33 +++++++++++++++++++ doc/api/modules.md | 12 +++++-- lib/internal/modules/cjs/loader.js | 3 +- test/common/index.js | 4 +-- test/common/require-as.js | 2 +- test/js-native-api/test_instance_data/test.js | 2 +- test/node-api/test_instance_data/test.js | 2 +- test/parallel/test-cli-eval.js | 2 +- 8 files changed, 51 insertions(+), 9 deletions(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 842ebf97ec5aff..58168640cec6cc 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -2707,6 +2707,39 @@ Type: Runtime `Transform._transformState` will be removed in future versions where it is no longer required due to simplification of the implementation. + +### DEP0144: `module.parent` + + +Type: Documentation-only + +A CommonJS module can access the first module that required it using +`module.parent`. This feature is deprecated because it does not work +consistently in the presence of ECMAScript modules and because it gives an +inaccurate representation of the CommonJS module graph. + +Some modules use it to check if they are the entry point of the current process. +Instead, it is recommended to compare `require.main` and `module`: + +```js +if (require.main === module) { + // Code section that will run only if current file is the entry point. +} +``` + +When looking for the CommonJS modules that have required the current one, +`require.cache` and `module.children` can be used: + +```js +const moduleParents = Object.values(require.cache) + .filter((m) => m.children.includes(module)); +``` + ### DEP0XXX: `socket.bufferSize` -* {module} +> Stability: 0 - Deprecated: Please use [`require.main`][] and +> [`module.children`][] instead. + +* {module | null | undefined} -The module that first required this one. +The module that first required this one, or `null` if the current module is the +entry point of the current process, or `undefined` if the module was loaded by +something that is not a CommonJS module (E.G.: REPL or `import`). ### `module.path` From 1dd265384b24b17d9460689a6a478b123ebd61a7 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Wed, 8 Jul 2020 22:32:13 -0700 Subject: [PATCH 112/138] doc: reword warnings about sockets passed to subprocesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the docs more concise. Make warnings direct ("do not use" and "should") rather than "is not recommended" or "is recommended". Backport-PR-URL: https://github.com/nodejs/node/pull/34377 PR-URL: https://github.com/nodejs/node/pull/34273 Reviewed-By: Tobias Nießen Reviewed-By: James M Snell Reviewed-By: Anto Aravinth Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat --- doc/api/child_process.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 04ed991fed6fec..d88adf49885b11 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -1380,14 +1380,12 @@ process.on('message', (m, socket) => { }); ``` -Once a socket has been passed to a child, the parent is no longer capable of -tracking when the socket is destroyed. To indicate this, the `.connections` -property becomes `null`. It is recommended not to use `.maxConnections` when -this occurs. - -It is also recommended that any `'message'` handlers in the child process -verify that `socket` exists, as the connection may have been closed during the -time it takes to send the connection to the child. +Do not use `.maxConnections` on a socket that has been passed to a subprocess. +The parent cannot track when the socket is destroyed. + +Any `'message'` handlers in the subprocess should verify that `socket` exists, +as the connection may have been closed during the time it takes to send the +connection to the child. ### `subprocess.signalCode` From 17174e69ce32a27740794cc9baaf9ee433bb8281 Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Fri, 10 Jul 2020 23:37:20 -0700 Subject: [PATCH 113/138] doc: clarify conditional exports guidance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/34306 Reviewed-By: Rich Trott Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Jan Krems --- doc/api/esm.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/api/esm.md b/doc/api/esm.md index d705e2d8efdfda..c9bb7473a8e689 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -456,7 +456,7 @@ Conditional exports can also be extended to exports subpaths, for example: "exports": { ".": "./main.js", "./feature": { - "browser": "./feature-browser.js", + "node": "./feature-node.js", "default": "./feature.js" } } @@ -464,8 +464,16 @@ Conditional exports can also be extended to exports subpaths, for example: ``` Defines a package where `require('pkg/feature')` and `import 'pkg/feature'` -could provide different implementations between the browser and Node.js, -given third-party tool support for a `"browser"` condition. +could provide different implementations between Node.js and other JS +environments. + +When using environment branches, always include a `"default"` condition where +possible. Providing a `"default"` condition ensures that any unknown JS +environments are able to use this universal implementation, which helps avoid +these JS environments from having to pretend to be existing environments in +order to support packages with conditional exports. For this reason, using +`"node"` and `"default"` condition branches is usually preferable to using +`"node"` and `"browser"` condition branches. #### Nested conditions @@ -479,11 +487,11 @@ use in Node.js but not the browser: { "main": "./main.js", "exports": { - "browser": "./feature-browser.mjs", "node": { "import": "./feature-node.mjs", "require": "./feature-node.cjs" - } + }, + "default": "./feature.mjs", } } ``` From 02ea320e0cf26f3f9d69948b9377903206784044 Mon Sep 17 00:00:00 2001 From: Bradley Farias Date: Wed, 11 Sep 2019 10:03:11 -0500 Subject: [PATCH 114/138] policy: add startup benchmark and make SRI lazier PR-URL: https://github.com/nodejs/node/pull/29527 Reviewed-By: Joyee Cheung Reviewed-By: James M Snell --- benchmark/policy/policy-startup.js | 51 ++++++++++++++++ lib/internal/policy/manifest.js | 78 ++++++++++++++++--------- lib/internal/policy/sri.js | 14 +++-- test/benchmark/test-benchmark-policy.js | 9 +++ 4 files changed, 119 insertions(+), 33 deletions(-) create mode 100644 benchmark/policy/policy-startup.js create mode 100644 test/benchmark/test-benchmark-policy.js diff --git a/benchmark/policy/policy-startup.js b/benchmark/policy/policy-startup.js new file mode 100644 index 00000000000000..1588123d8007d9 --- /dev/null +++ b/benchmark/policy/policy-startup.js @@ -0,0 +1,51 @@ +// Tests the impact on eager operations required for policies affecting +// general startup, does not test lazy operations +'use strict'; +const common = require('../common.js'); + +const configs = { + n: [1024] +}; + +const options = { + flags: ['--expose-internals'] +}; + +const bench = common.createBenchmark(main, configs, options); + +function main(conf) { + const hash = (str, algo) => { + const hash = require('crypto').createHash(algo); + return hash.update(str).digest('base64'); + }; + const resources = Object.fromEntries( + // Simulate graph of 1k modules + Array.from({ length: 1024 }, (_, i) => { + return [`./_${i}`, { + integrity: `sha256-${hash(`// ./_${i}`, 'sha256')}`, + dependencies: Object.fromEntries(Array.from({ + // Average 3 deps per 4 modules + length: Math.floor((i % 4) / 2) + }, (_, ii) => { + return [`_${ii}`, `./_${i - ii}`]; + })), + }]; + }) + ); + const json = JSON.parse(JSON.stringify({ resources }), (_, o) => { + if (o && typeof o === 'object') { + Reflect.setPrototypeOf(o, null); + Object.freeze(o); + } + return o; + }); + const { Manifest } = require('internal/policy/manifest'); + + bench.start(); + + for (let i = 0; i < conf.n; i++) { + new Manifest(json, 'file://benchmark/policy-relative'); + } + + bench.end(conf.n); +} diff --git a/lib/internal/policy/manifest.js b/lib/internal/policy/manifest.js index 672eab1c3837a6..0531f198f21971 100644 --- a/lib/internal/policy/manifest.js +++ b/lib/internal/policy/manifest.js @@ -4,6 +4,7 @@ const { ArrayIsArray, Map, MapPrototypeSet, + ObjectCreate, ObjectEntries, ObjectFreeze, ObjectSetPrototypeOf, @@ -31,7 +32,6 @@ const { URL } = require('internal/url'); const { createHash, timingSafeEqual } = crypto; const HashUpdate = uncurryThis(crypto.Hash.prototype.update); const HashDigest = uncurryThis(crypto.Hash.prototype.digest); -const BufferEquals = uncurryThis(Buffer.prototype.equals); const BufferToString = uncurryThis(Buffer.prototype.toString); const kRelativeURLStringPattern = /^\.{0,2}\//; const { getOptionValue } = require('internal/options'); @@ -56,9 +56,47 @@ function REACTION_LOG(error) { } class Manifest { + /** + * @type {Map} + * + * Used to compare a resource to the content body at the resource. + * `true` is used to signify that all integrities are allowed, otherwise, + * SRI strings are parsed to compare with the body. + * + * This stores strings instead of eagerly parsing SRI strings + * and only converts them to SRI data structures when needed. + * This avoids needing to parse all SRI strings at startup even + * if some never end up being used. + */ #integrities = new SafeMap(); + /** + * @type {Map true | URL>} + * + * Used to find where a dependency is located. + * + * This stores functions to lazily calculate locations as needed. + * `true` is used to signify that the location is not specified + * by the manifest and default resolution should be allowed. + */ #dependencies = new SafeMap(); + /** + * @type {(err: Error) => void} + * + * Performs default action for what happens when a manifest encounters + * a violation such as abort()ing or exiting the process, throwing the error, + * or logging the error. + */ #reaction = null; + /** + * `obj` should match the policy file format described in the docs + * it is expected to not have prototype pollution issues either by reassigning + * the prototype to `null` for values or by running prior to any user code. + * + * `manifestURL` is a URL to resolve relative locations against. + * + * @param {object} obj + * @param {string} manifestURL + */ constructor(obj, manifestURL) { const integrities = this.#integrities; const dependencies = this.#dependencies; @@ -98,35 +136,14 @@ class Manifest { let integrity = manifestEntries[i][1].integrity; if (!integrity) integrity = null; if (integrity != null) { - debug(`Manifest contains integrity for url ${originalHREF}`); + debug('Manifest contains integrity for url %s', originalHREF); if (typeof integrity === 'string') { - const sri = ObjectFreeze(SRI.parse(integrity)); if (integrities.has(resourceHREF)) { - const old = integrities.get(resourceHREF); - let mismatch = false; - - if (old.length !== sri.length) { - mismatch = true; - } else { - compare: - for (let sriI = 0; sriI < sri.length; sriI++) { - for (let oldI = 0; oldI < old.length; oldI++) { - if (sri[sriI].algorithm === old[oldI].algorithm && - BufferEquals(sri[sriI].value, old[oldI].value) && - sri[sriI].options === old[oldI].options) { - continue compare; - } - } - mismatch = true; - break compare; - } - } - - if (mismatch) { + if (integrities.get(resourceHREF) !== integrity) { throw new ERR_MANIFEST_INTEGRITY_MISMATCH(resourceURL); } } - integrities.set(resourceHREF, sri); + integrities.set(resourceHREF, integrity); } else if (integrity === true) { integrities.set(resourceHREF, true); } else { @@ -138,7 +155,7 @@ class Manifest { let dependencyMap = manifestEntries[i][1].dependencies; if (dependencyMap === null || dependencyMap === undefined) { - dependencyMap = {}; + dependencyMap = ObjectCreate(null); } if (typeof dependencyMap === 'object' && !ArrayIsArray(dependencyMap)) { /** @@ -200,13 +217,18 @@ class Manifest { assertIntegrity(url, content) { const href = `${url}`; - debug(`Checking integrity of ${href}`); + debug('Checking integrity of %s', href); const integrities = this.#integrities; const realIntegrities = new Map(); if (integrities.has(href)) { - const integrityEntries = integrities.get(href); + let integrityEntries = integrities.get(href); if (integrityEntries === true) return true; + if (typeof integrityEntries === 'string') { + const sri = ObjectFreeze(SRI.parse(integrityEntries)); + integrities.set(href, sri); + integrityEntries = sri; + } // Avoid clobbered Symbol.iterator for (let i = 0; i < integrityEntries.length; i++) { const { diff --git a/lib/internal/policy/sri.js b/lib/internal/policy/sri.js index d70df5c1aa1f7b..c4b5e7f1ca209a 100644 --- a/lib/internal/policy/sri.js +++ b/lib/internal/policy/sri.js @@ -1,17 +1,19 @@ 'use strict'; -// Value of https://w3c.github.io/webappsec-subresource-integrity/#the-integrity-attribute +// Utility to parse the value of +// https://w3c.github.io/webappsec-subresource-integrity/#the-integrity-attribute const { ObjectDefineProperty, ObjectFreeze, + ObjectGetPrototypeOf, ObjectSeal, + ObjectSetPrototypeOf, RegExp, RegExpPrototypeExec, RegExpPrototypeTest, StringPrototypeSlice, } = primordials; -// Returns [{algorithm, value (in base64 string), options,}] const { ERR_SRI_PARSE } = require('internal/errors').codes; @@ -21,7 +23,8 @@ const kHASH_ALGO = 'sha(?:256|384|512)'; // Base64 const kHASH_VALUE = '[A-Za-z0-9+/]+[=]{0,2}'; const kHASH_EXPRESSION = `(${kHASH_ALGO})-(${kHASH_VALUE})`; -const kOPTION_EXPRESSION = `(${kVCHAR}*)`; +// Ungrouped since unused +const kOPTION_EXPRESSION = `(?:${kVCHAR}*)`; const kHASH_WITH_OPTIONS = `${kHASH_EXPRESSION}(?:[?](${kOPTION_EXPRESSION}))?`; const kSRIPattern = RegExp(`(${kWSP}*)(?:${kHASH_WITH_OPTIONS})`, 'g'); ObjectSeal(kSRIPattern); @@ -29,9 +32,10 @@ const kAllWSP = RegExp(`^${kWSP}*$`); ObjectSeal(kAllWSP); const BufferFrom = require('buffer').Buffer.from; +const RealArrayPrototype = ObjectGetPrototypeOf([]); +// Returns {algorithm, value (in base64 string), options,}[] const parse = (str) => { - kSRIPattern.lastIndex = 0; let prevIndex = 0; let match; const entries = []; @@ -62,7 +66,7 @@ const parse = (str) => { throw new ERR_SRI_PARSE(str, str.charAt(prevIndex), prevIndex); } } - return entries; + return ObjectSetPrototypeOf(entries, RealArrayPrototype); }; module.exports = { diff --git a/test/benchmark/test-benchmark-policy.js b/test/benchmark/test-benchmark-policy.js new file mode 100644 index 00000000000000..7eb0992b1f1eda --- /dev/null +++ b/test/benchmark/test-benchmark-policy.js @@ -0,0 +1,9 @@ +'use strict'; + +require('../common'); + +const runBenchmark = require('../common/benchmark'); + +runBenchmark('policy', [ + 'n=1', +]); From 58dfeac1338308b47d53b185fd311a364fca557a Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 12 Jul 2020 15:36:02 -0700 Subject: [PATCH 115/138] test: use mustCall() in pummel test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace 'exit' check with common.mustCall(). PR-URL: https://github.com/nodejs/node/pull/34327 Reviewed-By: Anna Henningsen Reviewed-By: Michaël Zasso Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- test/pummel/test-net-connect-econnrefused.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/pummel/test-net-connect-econnrefused.js b/test/pummel/test-net-connect-econnrefused.js index 39737f73bf0831..38a71b6cfd4944 100644 --- a/test/pummel/test-net-connect-econnrefused.js +++ b/test/pummel/test-net-connect-econnrefused.js @@ -48,17 +48,14 @@ function pummel() { } function check() { - setTimeout(function() { + setTimeout(common.mustCall(function() { assert.strictEqual(process._getActiveRequests().length, 0); const activeHandles = process._getActiveHandles(); assert.ok(activeHandles.every((val) => val.constructor.name !== 'Socket')); - check_called = true; - }, 0); + }), 0); } -let check_called = false; process.on('exit', function() { assert.strictEqual(rounds, ROUNDS); assert.strictEqual(reqs, ROUNDS * ATTEMPTS_PER_ROUND); - assert(check_called); }); From 9cd523d148dcefa6dd86cb7ef6448520aad5c574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Tue, 14 Jul 2020 10:12:25 +0200 Subject: [PATCH 116/138] deps: update V8 to 8.4.371.19 Backport-PR-URL: https://github.com/nodejs/node/pull/34356 PR-URL: https://github.com/nodejs/node/pull/33579 Reviewed-By: Matteo Collina Reviewed-By: Jiawen Geng Reviewed-By: Michael Dawson Reviewed-By: Rich Trott Reviewed-By: Shelley Vohr --- deps/v8/.gitignore | 2 + deps/v8/AUTHORS | 3 + deps/v8/BUILD.gn | 309 ++- deps/v8/COMMON_OWNERS | 2 + deps/v8/DEPS | 44 +- deps/v8/INTL_OWNERS | 1 + deps/v8/WATCHLISTS | 7 - deps/v8/build_overrides/build.gni | 8 + deps/v8/gni/v8.gni | 9 +- deps/v8/include/DEPS | 1 + deps/v8/include/cppgc/DEPS | 7 + deps/v8/include/cppgc/allocation.h | 106 +- deps/v8/include/cppgc/common.h | 26 + deps/v8/include/cppgc/custom-space.h | 62 + deps/v8/include/cppgc/garbage-collected.h | 177 +- deps/v8/include/cppgc/heap.h | 36 +- deps/v8/include/cppgc/internal/accessors.h | 26 + .../{internals.h => internal/api-constants.h} | 27 +- .../cppgc/internal/compiler-specific.h | 26 + .../cppgc/{ => internal}/finalizer-trait.h | 8 +- .../v8/include/cppgc/{ => internal}/gc-info.h | 10 +- deps/v8/include/cppgc/internal/logging.h | 50 + .../include/cppgc/internal/persistent-node.h | 109 + .../include/cppgc/internal/pointer-policies.h | 133 + .../cppgc/internal/prefinalizer-handler.h | 31 + deps/v8/include/cppgc/liveness-broker.h | 50 + deps/v8/include/cppgc/macros.h | 26 + deps/v8/include/cppgc/member.h | 206 ++ deps/v8/include/cppgc/persistent.h | 304 +++ deps/v8/include/cppgc/platform.h | 4 +- deps/v8/include/cppgc/prefinalizer.h | 54 + deps/v8/include/cppgc/source-location.h | 59 + deps/v8/include/cppgc/trace-trait.h | 67 + deps/v8/include/cppgc/type-traits.h | 109 + deps/v8/include/cppgc/visitor.h | 138 + deps/v8/include/js_protocol.pdl | 30 + deps/v8/include/libplatform/libplatform.h | 4 +- deps/v8/include/libplatform/v8-tracing.h | 56 +- deps/v8/include/v8-fast-api-calls.h | 2 +- deps/v8/include/v8-inspector-protocol.h | 8 +- deps/v8/include/v8-inspector.h | 2 +- deps/v8/include/v8-internal.h | 67 +- deps/v8/include/v8-platform.h | 163 +- deps/v8/include/v8-profiler.h | 2 +- deps/v8/include/v8-util.h | 2 +- deps/v8/include/v8-version-string.h | 2 +- deps/v8/include/v8-version.h | 6 +- deps/v8/include/v8-wasm-trap-handler-posix.h | 2 +- deps/v8/include/v8-wasm-trap-handler-win.h | 2 +- deps/v8/include/v8.h | 161 +- deps/v8/include/v8config.h | 9 + deps/v8/infra/mb/mb_config.pyl | 26 +- deps/v8/infra/testing/builders.pyl | 45 +- deps/v8/src/DEPS | 10 + deps/v8/src/api/api-arguments.h | 8 +- deps/v8/src/api/api-inl.h | 1 - deps/v8/src/api/api.cc | 341 ++- deps/v8/src/api/api.h | 15 +- deps/v8/src/asmjs/asm-js.cc | 12 +- deps/v8/src/asmjs/asm-scanner.cc | 2 +- deps/v8/src/ast/ast-value-factory.cc | 14 +- deps/v8/src/ast/ast-value-factory.h | 12 +- deps/v8/src/ast/ast.h | 20 +- deps/v8/src/ast/scopes.cc | 18 +- deps/v8/src/ast/scopes.h | 3 +- deps/v8/src/ast/variables.h | 5 +- deps/v8/src/base/address-region.h | 8 + deps/v8/src/base/cpu.cc | 6 +- deps/v8/src/base/platform/mutex.h | 3 +- deps/v8/src/base/platform/platform-aix.cc | 29 + deps/v8/src/base/platform/platform-posix.cc | 4 +- deps/v8/src/base/platform/platform-solaris.cc | 18 - deps/v8/src/base/platform/time.cc | 17 +- deps/v8/src/builtins/arm/builtins-arm.cc | 471 +++- deps/v8/src/builtins/arm64/builtins-arm64.cc | 445 ++- deps/v8/src/builtins/array-copywithin.tq | 141 +- deps/v8/src/builtins/array-every.tq | 239 +- deps/v8/src/builtins/array-filter.tq | 343 ++- deps/v8/src/builtins/array-find.tq | 263 +- deps/v8/src/builtins/array-findindex.tq | 265 +- deps/v8/src/builtins/array-foreach.tq | 217 +- deps/v8/src/builtins/array-from.tq | 323 ++- deps/v8/src/builtins/array-isarray.tq | 32 +- deps/v8/src/builtins/array-join.tq | 1100 ++++---- deps/v8/src/builtins/array-lastindexof.tq | 243 +- deps/v8/src/builtins/array-map.tq | 458 ++-- deps/v8/src/builtins/array-of.tq | 84 +- deps/v8/src/builtins/array-reduce-right.tq | 323 ++- deps/v8/src/builtins/array-reduce.tq | 323 ++- deps/v8/src/builtins/array-reverse.tq | 301 +-- deps/v8/src/builtins/array-shift.tq | 175 +- deps/v8/src/builtins/array-slice.tq | 379 ++- deps/v8/src/builtins/array-some.tq | 239 +- deps/v8/src/builtins/array-splice.tq | 708 ++--- deps/v8/src/builtins/array-unshift.tq | 146 +- deps/v8/src/builtins/array.tq | 129 +- deps/v8/src/builtins/base.tq | 85 +- deps/v8/src/builtins/bigint.tq | 427 ++- deps/v8/src/builtins/boolean.tq | 66 +- deps/v8/src/builtins/builtins-array.cc | 10 + .../builtins/builtins-async-function-gen.cc | 10 +- deps/v8/src/builtins/builtins-async-gen.cc | 39 +- deps/v8/src/builtins/builtins-async-gen.h | 39 +- .../builtins/builtins-async-generator-gen.cc | 34 +- deps/v8/src/builtins/builtins-call-gen.cc | 18 +- deps/v8/src/builtins/builtins-callsite.cc | 6 +- .../src/builtins/builtins-collections-gen.cc | 5 +- deps/v8/src/builtins/builtins-dataview.cc | 1 + deps/v8/src/builtins/builtins-date-gen.cc | 3 + deps/v8/src/builtins/builtins-definitions.h | 45 +- deps/v8/src/builtins/builtins-error.cc | 67 +- deps/v8/src/builtins/builtins-handler-gen.cc | 35 +- deps/v8/src/builtins/builtins-internal-gen.cc | 3 +- deps/v8/src/builtins/builtins-intl.cc | 82 +- deps/v8/src/builtins/builtins-iterator-gen.cc | 109 +- deps/v8/src/builtins/builtins-iterator-gen.h | 20 +- .../builtins/builtins-microtask-queue-gen.cc | 11 +- deps/v8/src/builtins/builtins-object-gen.cc | 66 +- deps/v8/src/builtins/builtins-promise.cc | 24 - deps/v8/src/builtins/builtins-promise.h | 12 + deps/v8/src/builtins/builtins-proxy-gen.cc | 3 +- deps/v8/src/builtins/builtins-regexp-gen.cc | 14 +- .../builtins-sharedarraybuffer-gen.cc | 2 +- deps/v8/src/builtins/builtins-string-gen.cc | 22 +- deps/v8/src/builtins/builtins-string-gen.h | 2 +- deps/v8/src/builtins/builtins-string.tq | 385 ++- deps/v8/src/builtins/builtins-trace.cc | 91 +- .../src/builtins/builtins-typed-array-gen.cc | 14 +- deps/v8/src/builtins/builtins-wasm-gen.cc | 191 +- deps/v8/src/builtins/builtins-wasm-gen.h | 35 + deps/v8/src/builtins/builtins-weak-refs.cc | 57 +- deps/v8/src/builtins/cast.tq | 81 +- deps/v8/src/builtins/collections.tq | 87 +- deps/v8/src/builtins/console.tq | 20 +- deps/v8/src/builtins/convert.tq | 7 + deps/v8/src/builtins/data-view.tq | 1489 +++++------ deps/v8/src/builtins/finalization-registry.tq | 105 + .../src/builtins/growable-fixed-array-gen.cc | 4 + .../src/builtins/growable-fixed-array-gen.h | 1 + deps/v8/src/builtins/growable-fixed-array.tq | 76 +- deps/v8/src/builtins/ia32/builtins-ia32.cc | 434 ++- deps/v8/src/builtins/ic-callable.tq | 183 ++ deps/v8/src/builtins/ic.tq | 59 + deps/v8/src/builtins/internal-coverage.tq | 57 +- deps/v8/src/builtins/iterator.tq | 177 +- deps/v8/src/builtins/math.tq | 764 +++--- deps/v8/src/builtins/mips/builtins-mips.cc | 34 +- .../v8/src/builtins/mips64/builtins-mips64.cc | 35 +- deps/v8/src/builtins/number.tq | 108 +- deps/v8/src/builtins/object-fromentries.tq | 102 +- deps/v8/src/builtins/object.tq | 336 +-- deps/v8/src/builtins/ppc/builtins-ppc.cc | 492 ++-- .../builtins/promise-abstract-operations.tq | 928 ++++--- .../builtins/promise-all-element-closure.tq | 326 ++- deps/v8/src/builtins/promise-all.tq | 659 +++-- deps/v8/src/builtins/promise-any.tq | 372 +++ deps/v8/src/builtins/promise-constructor.tq | 162 +- deps/v8/src/builtins/promise-finally.tq | 348 +-- deps/v8/src/builtins/promise-jobs.tq | 120 +- deps/v8/src/builtins/promise-misc.tq | 431 +-- deps/v8/src/builtins/promise-race.tq | 212 +- deps/v8/src/builtins/promise-reaction-job.tq | 180 +- deps/v8/src/builtins/promise-resolve.tq | 316 ++- deps/v8/src/builtins/promise-then.tq | 117 +- deps/v8/src/builtins/proxy-constructor.tq | 81 +- deps/v8/src/builtins/proxy-delete-property.tq | 104 +- deps/v8/src/builtins/proxy-get-property.tq | 97 +- .../v8/src/builtins/proxy-get-prototype-of.tq | 101 +- deps/v8/src/builtins/proxy-has-property.tq | 90 +- deps/v8/src/builtins/proxy-is-extensible.tq | 90 +- .../src/builtins/proxy-prevent-extensions.tq | 92 +- deps/v8/src/builtins/proxy-revocable.tq | 73 +- deps/v8/src/builtins/proxy-revoke.tq | 44 +- deps/v8/src/builtins/proxy-set-property.tq | 136 +- .../v8/src/builtins/proxy-set-prototype-of.tq | 112 +- deps/v8/src/builtins/proxy.tq | 32 +- deps/v8/src/builtins/reflect.tq | 154 +- deps/v8/src/builtins/regexp-exec.tq | 71 +- deps/v8/src/builtins/regexp-match-all.tq | 410 ++- deps/v8/src/builtins/regexp-match.tq | 267 +- deps/v8/src/builtins/regexp-replace.tq | 459 ++-- deps/v8/src/builtins/regexp-search.tq | 168 +- deps/v8/src/builtins/regexp-source.tq | 30 +- deps/v8/src/builtins/regexp-split.tq | 102 +- deps/v8/src/builtins/regexp-test.tq | 45 +- deps/v8/src/builtins/regexp.tq | 716 +++-- deps/v8/src/builtins/string-endswith.tq | 119 +- deps/v8/src/builtins/string-html.tq | 215 +- deps/v8/src/builtins/string-iterator.tq | 72 +- deps/v8/src/builtins/string-pad.tq | 172 +- deps/v8/src/builtins/string-repeat.tq | 106 +- deps/v8/src/builtins/string-replaceall.tq | 374 ++- deps/v8/src/builtins/string-slice.tq | 47 +- deps/v8/src/builtins/string-startswith.tq | 103 +- deps/v8/src/builtins/string-substr.tq | 61 +- deps/v8/src/builtins/string-substring.tq | 40 +- deps/v8/src/builtins/symbol.tq | 74 +- deps/v8/src/builtins/torque-internal.tq | 309 +-- .../builtins/typed-array-createtypedarray.tq | 767 +++--- deps/v8/src/builtins/typed-array-every.tq | 81 +- deps/v8/src/builtins/typed-array-filter.tq | 130 +- deps/v8/src/builtins/typed-array-find.tq | 81 +- deps/v8/src/builtins/typed-array-findindex.tq | 86 +- deps/v8/src/builtins/typed-array-foreach.tq | 79 +- deps/v8/src/builtins/typed-array-from.tq | 329 ++- deps/v8/src/builtins/typed-array-of.tq | 90 +- deps/v8/src/builtins/typed-array-reduce.tq | 98 +- .../src/builtins/typed-array-reduceright.tq | 104 +- deps/v8/src/builtins/typed-array-set.tq | 573 ++-- deps/v8/src/builtins/typed-array-slice.tq | 177 +- deps/v8/src/builtins/typed-array-some.tq | 81 +- deps/v8/src/builtins/typed-array-sort.tq | 227 +- deps/v8/src/builtins/typed-array-subarray.tq | 112 +- deps/v8/src/builtins/typed-array.tq | 464 ++-- deps/v8/src/builtins/wasm.tq | 273 ++ deps/v8/src/builtins/x64/builtins-x64.cc | 53 +- deps/v8/src/codegen/arm/constants-arm.h | 17 - deps/v8/src/codegen/arm/cpu-arm.cc | 13 - .../codegen/arm/interface-descriptors-arm.cc | 24 + .../v8/src/codegen/arm/macro-assembler-arm.cc | 33 +- deps/v8/src/codegen/arm/macro-assembler-arm.h | 18 + deps/v8/src/codegen/arm/register-arm.h | 2 + .../src/codegen/arm64/assembler-arm64-inl.h | 1 + deps/v8/src/codegen/arm64/assembler-arm64.cc | 4 +- .../src/codegen/arm64/instructions-arm64.cc | 13 +- .../v8/src/codegen/arm64/instructions-arm64.h | 5 +- .../arm64/interface-descriptors-arm64.cc | 24 + .../codegen/arm64/macro-assembler-arm64-inl.h | 2 +- .../codegen/arm64/macro-assembler-arm64.cc | 66 +- .../src/codegen/arm64/macro-assembler-arm64.h | 13 +- deps/v8/src/codegen/arm64/register-arm64.h | 9 +- deps/v8/src/codegen/assembler.cc | 1 - deps/v8/src/codegen/code-stub-assembler.cc | 409 +-- deps/v8/src/codegen/code-stub-assembler.h | 225 +- deps/v8/src/codegen/compiler.cc | 1142 ++++---- deps/v8/src/codegen/compiler.h | 116 +- .../external-reference-encoder.cc} | 81 +- .../src/codegen/external-reference-encoder.h | 60 + deps/v8/src/codegen/external-reference.cc | 4 + deps/v8/src/codegen/external-reference.h | 2 + deps/v8/src/codegen/ia32/assembler-ia32.cc | 43 + deps/v8/src/codegen/ia32/assembler-ia32.h | 11 + .../ia32/interface-descriptors-ia32.cc | 40 + .../src/codegen/ia32/macro-assembler-ia32.cc | 27 +- .../src/codegen/ia32/macro-assembler-ia32.h | 15 + deps/v8/src/codegen/ia32/register-ia32.h | 2 + deps/v8/src/codegen/interface-descriptors.cc | 28 +- deps/v8/src/codegen/interface-descriptors.h | 122 +- .../mips/interface-descriptors-mips.cc | 24 + .../src/codegen/mips/macro-assembler-mips.cc | 2 +- deps/v8/src/codegen/mips/register-mips.h | 2 + .../v8/src/codegen/mips64/assembler-mips64.cc | 76 +- .../mips64/interface-descriptors-mips64.cc | 24 + .../codegen/mips64/macro-assembler-mips64.cc | 6 +- deps/v8/src/codegen/mips64/register-mips64.h | 32 +- .../src/codegen/optimized-compilation-info.cc | 4 +- .../src/codegen/optimized-compilation-info.h | 7 + deps/v8/src/codegen/ppc/assembler-ppc-inl.h | 83 +- deps/v8/src/codegen/ppc/assembler-ppc.cc | 28 +- deps/v8/src/codegen/ppc/assembler-ppc.h | 43 +- deps/v8/src/codegen/ppc/constants-ppc.h | 33 +- .../codegen/ppc/interface-descriptors-ppc.cc | 24 + .../v8/src/codegen/ppc/macro-assembler-ppc.cc | 275 +- deps/v8/src/codegen/ppc/macro-assembler-ppc.h | 129 +- deps/v8/src/codegen/ppc/register-ppc.h | 2 + deps/v8/src/codegen/reloc-info.cc | 3 +- .../s390/interface-descriptors-s390.cc | 24 + .../src/codegen/s390/macro-assembler-s390.cc | 2 +- deps/v8/src/codegen/s390/register-s390.h | 2 + deps/v8/src/codegen/tnode.h | 6 + deps/v8/src/codegen/turbo-assembler.cc | 2 +- .../codegen/unoptimized-compilation-info.cc | 11 +- .../codegen/unoptimized-compilation-info.h | 37 +- deps/v8/src/codegen/x64/assembler-x64.cc | 18 + deps/v8/src/codegen/x64/assembler-x64.h | 3 + .../codegen/x64/interface-descriptors-x64.cc | 35 + .../v8/src/codegen/x64/macro-assembler-x64.cc | 11 +- deps/v8/src/codegen/x64/macro-assembler-x64.h | 10 +- deps/v8/src/codegen/x64/register-x64.h | 2 + deps/v8/src/common/external-pointer-inl.h | 32 + deps/v8/src/common/external-pointer.h | 33 + deps/v8/src/common/globals.h | 24 +- deps/v8/src/common/message-template.h | 12 +- deps/v8/src/common/ptr-compr-inl.h | 10 + .../compiler-dispatcher.cc | 3 +- .../compiler-dispatcher/compiler-dispatcher.h | 1 - deps/v8/src/compiler/OWNERS | 3 +- deps/v8/src/compiler/access-builder.cc | 16 +- deps/v8/src/compiler/access-info.cc | 10 +- .../backend/arm/code-generator-arm.cc | 29 +- .../backend/arm/instruction-selector-arm.cc | 31 +- .../backend/arm64/code-generator-arm64.cc | 58 +- .../backend/arm64/instruction-codes-arm64.h | 6 + .../arm64/instruction-scheduler-arm64.cc | 6 + .../arm64/instruction-selector-arm64.cc | 56 +- .../v8/src/compiler/backend/code-generator.cc | 8 +- deps/v8/src/compiler/backend/code-generator.h | 17 +- .../backend/ia32/code-generator-ia32.cc | 106 +- .../backend/ia32/instruction-codes-ia32.h | 8 + .../ia32/instruction-scheduler-ia32.cc | 8 + .../backend/ia32/instruction-selector-ia32.cc | 47 +- .../compiler/backend/instruction-selector.cc | 36 +- .../backend/mips/code-generator-mips.cc | 4 +- .../backend/mips/instruction-selector-mips.cc | 2 + .../backend/mips64/code-generator-mips64.cc | 292 +- .../backend/mips64/instruction-codes-mips64.h | 3 + .../mips64/instruction-scheduler-mips64.cc | 3 + .../mips64/instruction-selector-mips64.cc | 27 +- .../backend/ppc/code-generator-ppc.cc | 206 +- .../backend/ppc/instruction-codes-ppc.h | 22 +- .../backend/ppc/instruction-scheduler-ppc.cc | 20 + .../backend/ppc/instruction-selector-ppc.cc | 98 +- .../compiler/backend/register-allocator.cc | 65 +- .../src/compiler/backend/register-allocator.h | 21 +- .../backend/s390/code-generator-s390.cc | 7 +- .../backend/s390/instruction-selector-s390.cc | 4 + .../backend/x64/code-generator-x64.cc | 292 +- .../backend/x64/instruction-codes-x64.h | 9 + .../backend/x64/instruction-scheduler-x64.cc | 9 + .../backend/x64/instruction-selector-x64.cc | 58 +- deps/v8/src/compiler/code-assembler.cc | 18 + deps/v8/src/compiler/code-assembler.h | 11 +- .../src/compiler/common-operator-reducer.cc | 3 +- .../src/compiler/compilation-dependencies.cc | 9 +- .../src/compiler/effect-control-linearizer.cc | 74 +- deps/v8/src/compiler/graph-assembler.cc | 96 +- deps/v8/src/compiler/graph-assembler.h | 14 +- deps/v8/src/compiler/graph-reducer.cc | 11 +- deps/v8/src/compiler/graph-reducer.h | 4 + deps/v8/src/compiler/heap-refs.h | 86 +- deps/v8/src/compiler/int64-lowering.cc | 67 +- deps/v8/src/compiler/js-call-reducer.cc | 244 +- deps/v8/src/compiler/js-call-reducer.h | 9 +- deps/v8/src/compiler/js-generic-lowering.cc | 2 +- deps/v8/src/compiler/js-heap-broker.cc | 77 +- deps/v8/src/compiler/js-inlining-heuristic.cc | 22 +- deps/v8/src/compiler/js-inlining-heuristic.h | 4 + .../js-native-context-specialization.cc | 81 +- deps/v8/src/compiler/js-type-hint-lowering.cc | 7 + deps/v8/src/compiler/js-typed-lowering.cc | 72 +- deps/v8/src/compiler/linkage.cc | 35 +- .../src/compiler/machine-operator-reducer.cc | 350 ++- .../src/compiler/machine-operator-reducer.h | 17 + deps/v8/src/compiler/machine-operator.cc | 1053 ++++---- deps/v8/src/compiler/machine-operator.h | 54 +- deps/v8/src/compiler/memory-lowering.cc | 39 +- deps/v8/src/compiler/memory-lowering.h | 7 +- deps/v8/src/compiler/memory-optimizer.cc | 18 +- deps/v8/src/compiler/node-matchers.h | 3 +- deps/v8/src/compiler/node-properties.cc | 15 + deps/v8/src/compiler/node-properties.h | 5 + deps/v8/src/compiler/node.cc | 32 +- deps/v8/src/compiler/node.h | 5 +- deps/v8/src/compiler/opcodes.h | 6 + deps/v8/src/compiler/operation-typer.cc | 39 +- deps/v8/src/compiler/operator-properties.cc | 2 +- deps/v8/src/compiler/operator.h | 2 - deps/v8/src/compiler/pipeline-statistics.cc | 2 +- deps/v8/src/compiler/pipeline.cc | 17 +- deps/v8/src/compiler/raw-machine-assembler.h | 6 + .../v8/src/compiler/redundancy-elimination.cc | 12 +- deps/v8/src/compiler/representation-change.cc | 16 +- deps/v8/src/compiler/schedule.cc | 24 +- .../serializer-for-background-compilation.cc | 20 + deps/v8/src/compiler/simd-scalar-lowering.cc | 44 +- deps/v8/src/compiler/simplified-lowering.cc | 1946 +++++++------- deps/v8/src/compiler/simplified-operator.cc | 94 +- deps/v8/src/compiler/simplified-operator.h | 27 +- deps/v8/src/compiler/typed-optimization.cc | 48 +- deps/v8/src/compiler/typed-optimization.h | 2 + deps/v8/src/compiler/types.cc | 9 +- deps/v8/src/compiler/types.h | 8 +- deps/v8/src/compiler/verifier.cc | 2 + deps/v8/src/compiler/wasm-compiler.cc | 991 ++++--- deps/v8/src/compiler/wasm-compiler.h | 46 +- deps/v8/src/d8/d8-platforms.cc | 14 +- deps/v8/src/d8/d8-platforms.h | 8 + deps/v8/src/d8/d8.cc | 141 +- deps/v8/src/d8/d8.h | 4 +- deps/v8/src/debug/debug-evaluate.cc | 8 +- deps/v8/src/debug/debug-frames.cc | 9 - deps/v8/src/debug/debug-frames.h | 3 +- deps/v8/src/debug/debug-interface.h | 32 +- deps/v8/src/debug/debug-scope-iterator.cc | 41 +- deps/v8/src/debug/debug-scope-iterator.h | 6 +- deps/v8/src/debug/debug-scopes.cc | 104 +- deps/v8/src/debug/debug-scopes.h | 7 +- .../src/debug/debug-stack-trace-iterator.cc | 33 +- .../v8/src/debug/debug-stack-trace-iterator.h | 2 + deps/v8/src/debug/debug.cc | 68 +- deps/v8/src/debug/debug.h | 5 + deps/v8/src/debug/liveedit.cc | 17 +- deps/v8/src/debug/ppc/debug-ppc.cc | 3 +- deps/v8/src/debug/wasm/gdb-server/OWNERS | 3 + .../debug/wasm/gdb-server/gdb-remote-util.cc | 104 + .../debug/wasm/gdb-server/gdb-remote-util.h | 72 + .../wasm/gdb-server/gdb-server-thread.cc | 2 +- .../debug/wasm/gdb-server/gdb-server-thread.h | 4 +- .../src/debug/wasm/gdb-server/gdb-server.cc | 400 ++- .../v8/src/debug/wasm/gdb-server/gdb-server.h | 166 +- deps/v8/src/debug/wasm/gdb-server/packet.cc | 364 +++ deps/v8/src/debug/wasm/gdb-server/packet.h | 105 + deps/v8/src/debug/wasm/gdb-server/session.cc | 108 +- deps/v8/src/debug/wasm/gdb-server/session.h | 32 +- deps/v8/src/debug/wasm/gdb-server/target.cc | 636 ++++- deps/v8/src/debug/wasm/gdb-server/target.h | 87 +- .../v8/src/debug/wasm/gdb-server/transport.cc | 101 +- deps/v8/src/debug/wasm/gdb-server/transport.h | 102 +- deps/v8/src/debug/wasm/gdb-server/util.h | 27 - .../wasm/gdb-server/wasm-module-debug.cc | 388 +++ .../debug/wasm/gdb-server/wasm-module-debug.h | 105 + deps/v8/src/deoptimizer/deoptimizer.cc | 303 ++- deps/v8/src/deoptimizer/deoptimizer.h | 32 +- .../v8/src/deoptimizer/ppc/deoptimizer-ppc.cc | 23 +- deps/v8/src/diagnostics/arm64/disasm-arm64.cc | 21 +- deps/v8/src/diagnostics/disassembler.cc | 14 +- deps/v8/src/diagnostics/ia32/disasm-ia32.cc | 17 + deps/v8/src/diagnostics/objects-debug.cc | 53 +- deps/v8/src/diagnostics/objects-printer.cc | 169 +- deps/v8/src/diagnostics/ppc/disasm-ppc.cc | 43 + .../src/diagnostics/unwinding-info-win64.cc | 31 - deps/v8/src/diagnostics/x64/disasm-x64.cc | 9 +- deps/v8/src/execution/arm/simulator-arm.cc | 4 +- deps/v8/src/execution/frame-constants.h | 4 +- deps/v8/src/execution/frames-inl.h | 8 +- deps/v8/src/execution/frames.cc | 237 +- deps/v8/src/execution/frames.h | 127 +- deps/v8/src/execution/futex-emulation.cc | 14 +- deps/v8/src/execution/isolate.cc | 128 +- deps/v8/src/execution/isolate.h | 33 +- deps/v8/src/execution/messages.cc | 95 +- deps/v8/src/execution/messages.h | 12 +- .../v8/src/execution/off-thread-isolate-inl.h | 22 + deps/v8/src/execution/off-thread-isolate.cc | 129 +- deps/v8/src/execution/off-thread-isolate.h | 95 +- .../src/execution/ppc/frame-constants-ppc.h | 4 +- deps/v8/src/execution/ppc/simulator-ppc.cc | 4 +- deps/v8/src/execution/ppc/simulator-ppc.h | 2 +- deps/v8/src/execution/protectors-inl.h | 9 +- deps/v8/src/execution/protectors.cc | 33 +- deps/v8/src/execution/protectors.h | 15 +- deps/v8/src/extensions/gc-extension.cc | 13 +- deps/v8/src/flags/flag-definitions.h | 112 +- deps/v8/src/handles/global-handles.cc | 3 +- deps/v8/src/handles/handles.h | 2 +- deps/v8/src/handles/persistent-handles.cc | 122 + deps/v8/src/handles/persistent-handles.h | 88 + deps/v8/src/heap/OWNERS | 1 + deps/v8/src/heap/array-buffer-tracker.cc | 1 + deps/v8/src/heap/code-stats.cc | 1 + deps/v8/src/heap/concurrent-allocator-inl.h | 86 + deps/v8/src/heap/concurrent-allocator.cc | 43 + deps/v8/src/heap/concurrent-allocator.h | 57 + deps/v8/src/heap/concurrent-marking.cc | 1 + deps/v8/src/heap/concurrent-marking.h | 1 + deps/v8/src/heap/cppgc/allocation.cc | 11 + .../heap/cppgc/asm/arm/push_registers_asm.cc | 39 + .../cppgc/asm/arm64/push_registers_asm.cc | 52 + .../cppgc/asm/arm64/push_registers_masm.S | 32 + .../heap/cppgc/asm/ia32/push_registers_asm.cc | 53 + .../heap/cppgc/asm/ia32/push_registers_masm.S | 48 + .../heap/cppgc/asm/mips/push_registers_asm.cc | 48 + .../cppgc/asm/mips64/push_registers_asm.cc | 48 + .../heap/cppgc/asm/ppc/push_registers_asm.cc | 94 + .../heap/cppgc/asm/s390/push_registers_asm.cc | 35 + .../src/heap/cppgc/asm/x64/push_registers.S | 52 - .../heap/cppgc/asm/x64/push_registers_asm.cc | 94 + ..._registers_win.S => push_registers_masm.S} | 0 deps/v8/src/heap/cppgc/free-list.cc | 190 ++ deps/v8/src/heap/cppgc/free-list.h | 62 + deps/v8/src/heap/cppgc/gc-info-table.cc | 2 +- deps/v8/src/heap/cppgc/gc-info-table.h | 2 +- deps/v8/src/heap/cppgc/gc-info.cc | 2 +- deps/v8/src/heap/cppgc/globals.h | 9 + deps/v8/src/heap/cppgc/heap-inl.h | 35 +- .../src/heap/cppgc/heap-object-header-inl.h | 15 +- deps/v8/src/heap/cppgc/heap-object-header.cc | 4 +- deps/v8/src/heap/cppgc/heap-object-header.h | 14 +- deps/v8/src/heap/cppgc/heap-page.cc | 201 ++ deps/v8/src/heap/cppgc/heap-page.h | 181 ++ deps/v8/src/heap/cppgc/heap-space.cc | 58 + deps/v8/src/heap/cppgc/heap-space.h | 127 + deps/v8/src/heap/cppgc/heap-visitor.h | 88 + deps/v8/src/heap/cppgc/heap.cc | 122 +- deps/v8/src/heap/cppgc/heap.h | 123 +- deps/v8/src/heap/cppgc/liveness-broker.cc | 15 + deps/v8/src/heap/cppgc/logging.cc | 29 + deps/v8/src/heap/cppgc/marker.cc | 152 ++ deps/v8/src/heap/cppgc/marker.h | 121 + deps/v8/src/heap/cppgc/marking-visitor.cc | 143 + deps/v8/src/heap/cppgc/marking-visitor.h | 70 + deps/v8/src/heap/cppgc/object-allocator-inl.h | 74 + deps/v8/src/heap/cppgc/object-allocator.cc | 87 + deps/v8/src/heap/cppgc/object-allocator.h | 40 + .../src/heap/cppgc/object-start-bitmap-inl.h | 95 + deps/v8/src/heap/cppgc/object-start-bitmap.h | 80 + deps/v8/src/heap/cppgc/page-memory-inl.h | 57 + deps/v8/src/heap/cppgc/page-memory.cc | 211 ++ deps/v8/src/heap/cppgc/page-memory.h | 237 ++ deps/v8/src/heap/cppgc/persistent-node.cc | 60 + deps/v8/src/heap/cppgc/pointer-policies.cc | 35 + .../v8/src/heap/cppgc/prefinalizer-handler.cc | 66 + deps/v8/src/heap/cppgc/prefinalizer-handler.h | 44 + deps/v8/src/heap/cppgc/raw-heap.cc | 32 + deps/v8/src/heap/cppgc/raw-heap.h | 106 + deps/v8/src/heap/cppgc/sanitizers.h | 39 + deps/v8/src/heap/cppgc/source-location.cc | 16 + deps/v8/src/heap/cppgc/stack.cc | 49 +- deps/v8/src/heap/cppgc/stack.h | 12 +- deps/v8/src/heap/cppgc/sweeper.cc | 213 ++ deps/v8/src/heap/cppgc/sweeper.h | 38 + deps/v8/src/heap/cppgc/visitor.h | 23 + deps/v8/src/heap/cppgc/worklist.h | 473 ++++ deps/v8/src/heap/embedder-tracing.cc | 12 +- deps/v8/src/heap/embedder-tracing.h | 5 +- deps/v8/src/heap/factory-base.cc | 5 +- deps/v8/src/heap/factory.cc | 129 +- deps/v8/src/heap/factory.h | 45 +- .../finalization-registry-cleanup-task.cc | 14 +- deps/v8/src/heap/gc-tracer.cc | 28 +- deps/v8/src/heap/gc-tracer.h | 11 +- deps/v8/src/heap/heap-inl.h | 4 +- deps/v8/src/heap/heap.cc | 896 ++++--- deps/v8/src/heap/heap.h | 117 +- deps/v8/src/heap/incremental-marking-job.cc | 17 +- deps/v8/src/heap/incremental-marking-job.h | 9 +- deps/v8/src/heap/incremental-marking.cc | 136 +- deps/v8/src/heap/incremental-marking.h | 9 +- deps/v8/src/heap/invalidated-slots.cc | 2 + deps/v8/src/heap/large-spaces.cc | 547 ++++ deps/v8/src/heap/large-spaces.h | 232 ++ deps/v8/src/{base => heap}/list.h | 24 +- deps/v8/src/heap/local-allocator-inl.h | 42 +- deps/v8/src/heap/local-allocator.h | 15 +- deps/v8/src/heap/local-heap.cc | 46 +- deps/v8/src/heap/local-heap.h | 28 +- deps/v8/src/heap/mark-compact-inl.h | 5 +- deps/v8/src/heap/mark-compact.cc | 68 +- deps/v8/src/heap/mark-compact.h | 1 + deps/v8/src/heap/marking-visitor-inl.h | 37 +- deps/v8/src/heap/marking-visitor.h | 1 + deps/v8/src/heap/marking.cc | 16 +- deps/v8/src/heap/marking.h | 16 +- deps/v8/src/heap/memory-chunk-inl.h | 50 + deps/v8/src/heap/memory-chunk.cc | 157 ++ deps/v8/src/heap/memory-chunk.h | 471 ++++ deps/v8/src/heap/object-stats.cc | 5 +- deps/v8/src/heap/objects-visiting-inl.h | 16 - deps/v8/src/heap/objects-visiting.h | 12 +- deps/v8/src/heap/off-thread-factory.cc | 192 +- deps/v8/src/heap/off-thread-factory.h | 17 - deps/v8/src/heap/off-thread-heap.cc | 241 ++ deps/v8/src/heap/off-thread-heap.h | 52 + deps/v8/src/heap/read-only-heap.cc | 138 +- deps/v8/src/heap/read-only-heap.h | 42 +- deps/v8/src/heap/read-only-spaces.cc | 172 ++ deps/v8/src/heap/read-only-spaces.h | 125 + ...{remembered-set.h => remembered-set-inl.h} | 56 +- deps/v8/src/heap/safepoint.cc | 41 +- deps/v8/src/heap/safepoint.h | 26 +- deps/v8/src/heap/scavenge-job.cc | 5 +- deps/v8/src/heap/scavenger-inl.h | 4 +- deps/v8/src/heap/scavenger.cc | 55 +- deps/v8/src/heap/scavenger.h | 7 +- deps/v8/src/heap/setup-heap-internal.cc | 172 +- deps/v8/src/heap/slot-set.h | 32 +- deps/v8/src/heap/spaces-inl.h | 55 +- deps/v8/src/heap/spaces.cc | 948 +------ deps/v8/src/heap/spaces.h | 784 +----- deps/v8/src/heap/sweeper.cc | 221 +- deps/v8/src/heap/sweeper.h | 35 +- deps/v8/src/heap/third-party/heap-api-stub.cc | 53 + deps/v8/src/ic/accessor-assembler.cc | 7 +- deps/v8/src/ic/ic.cc | 46 +- deps/v8/src/ic/keyed-store-generic.cc | 30 +- deps/v8/src/init/bootstrapper.cc | 547 ++-- deps/v8/src/init/bootstrapper.h | 14 + deps/v8/src/init/heap-symbols.h | 4 + deps/v8/src/init/v8.cc | 3 + deps/v8/src/inspector/BUILD.gn | 29 +- deps/v8/src/inspector/search-util.cc | 4 +- deps/v8/src/inspector/string-16.h | 2 +- deps/v8/src/inspector/string-util.cc | 86 + deps/v8/src/inspector/string-util.h | 11 +- deps/v8/src/inspector/v8-console.cc | 36 +- deps/v8/src/inspector/v8-console.h | 2 +- .../src/inspector/v8-debugger-agent-impl.cc | 94 +- .../v8/src/inspector/v8-debugger-agent-impl.h | 5 + deps/v8/src/inspector/v8-debugger-script.cc | 15 + deps/v8/src/inspector/v8-debugger-script.h | 3 + deps/v8/src/inspector/value-mirror.cc | 4 + deps/v8/src/interpreter/bytecode-generator.cc | 85 +- deps/v8/src/interpreter/bytecode-generator.h | 2 +- .../src/interpreter/interpreter-assembler.cc | 168 +- .../src/interpreter/interpreter-generator.cc | 14 +- deps/v8/src/interpreter/interpreter.cc | 17 +- deps/v8/src/libplatform/default-job.cc | 150 ++ deps/v8/src/libplatform/default-job.h | 126 + deps/v8/src/libplatform/default-platform.cc | 59 +- deps/v8/src/libplatform/default-platform.h | 14 +- .../tracing/json-trace-event-listener.cc | 168 -- .../tracing/json-trace-event-listener.h | 46 - .../libplatform/tracing/tracing-controller.cc | 201 +- deps/v8/src/logging/counters-definitions.h | 8 +- deps/v8/src/logging/counters.h | 4 +- deps/v8/src/logging/log.cc | 9 +- deps/v8/src/logging/log.h | 2 +- deps/v8/src/objects/allocation-site-inl.h | 3 +- deps/v8/src/objects/allocation-site.h | 12 +- deps/v8/src/objects/allocation-site.tq | 2 + deps/v8/src/objects/api-callbacks-inl.h | 23 +- deps/v8/src/objects/api-callbacks.h | 35 +- deps/v8/src/objects/api-callbacks.tq | 18 +- deps/v8/src/objects/arguments.h | 3 - deps/v8/src/objects/arguments.tq | 293 +- deps/v8/src/objects/backing-store.cc | 56 +- deps/v8/src/objects/backing-store.h | 12 +- deps/v8/src/objects/cell.h | 3 - deps/v8/src/objects/cell.tq | 1 + .../objects/class-definitions-tq-deps-inl.h | 44 + deps/v8/src/objects/code-inl.h | 29 + deps/v8/src/objects/code.cc | 8 +- deps/v8/src/objects/code.h | 42 +- deps/v8/src/objects/contexts-inl.h | 14 +- deps/v8/src/objects/contexts.h | 54 +- deps/v8/src/objects/contexts.tq | 19 +- deps/v8/src/objects/debug-objects-inl.h | 3 + deps/v8/src/objects/debug-objects.h | 11 +- deps/v8/src/objects/debug-objects.tq | 13 + deps/v8/src/objects/descriptor-array-inl.h | 5 +- deps/v8/src/objects/descriptor-array.h | 11 +- deps/v8/src/objects/descriptor-array.tq | 1 + deps/v8/src/objects/elements-kind.h | 8 + deps/v8/src/objects/embedder-data-slot-inl.h | 22 +- deps/v8/src/objects/embedder-data-slot.h | 12 +- deps/v8/src/objects/feedback-vector.cc | 20 +- deps/v8/src/objects/feedback-vector.h | 2 +- deps/v8/src/objects/feedback-vector.tq | 4 +- deps/v8/src/objects/field-type.cc | 9 + deps/v8/src/objects/field-type.h | 1 + deps/v8/src/objects/fixed-array-inl.h | 93 +- deps/v8/src/objects/fixed-array.h | 121 +- deps/v8/src/objects/fixed-array.tq | 36 +- deps/v8/src/objects/foreign-inl.h | 18 +- deps/v8/src/objects/foreign.h | 20 +- deps/v8/src/objects/foreign.tq | 3 +- deps/v8/src/objects/frame-array-inl.h | 14 +- deps/v8/src/objects/frame-array.h | 17 +- deps/v8/src/objects/free-space-inl.h | 3 +- deps/v8/src/objects/free-space.h | 13 +- deps/v8/src/objects/free-space.tq | 1 + deps/v8/src/objects/function-kind.h | 4 + deps/v8/src/objects/heap-number-inl.h | 10 +- deps/v8/src/objects/heap-number.h | 13 +- deps/v8/src/objects/heap-number.tq | 5 +- deps/v8/src/objects/heap-object.h | 2 +- deps/v8/src/objects/intl-objects.cc | 17 +- deps/v8/src/objects/intl-objects.h | 33 +- deps/v8/src/objects/intl-objects.tq | 11 + deps/v8/src/objects/js-aggregate-error-inl.h | 25 + deps/v8/src/objects/js-aggregate-error.h | 27 + deps/v8/src/objects/js-aggregate-error.tq | 81 + deps/v8/src/objects/js-array-buffer-inl.h | 104 +- deps/v8/src/objects/js-array-buffer.cc | 13 +- deps/v8/src/objects/js-array-buffer.h | 119 +- deps/v8/src/objects/js-array-buffer.tq | 16 +- deps/v8/src/objects/js-array.tq | 3 +- deps/v8/src/objects/js-break-iterator-inl.h | 10 +- deps/v8/src/objects/js-break-iterator.cc | 4 +- deps/v8/src/objects/js-break-iterator.h | 20 +- deps/v8/src/objects/js-collator-inl.h | 5 +- deps/v8/src/objects/js-collator.cc | 25 +- deps/v8/src/objects/js-collator.h | 11 +- deps/v8/src/objects/js-collection.h | 2 - deps/v8/src/objects/js-date-time-format-inl.h | 7 +- deps/v8/src/objects/js-date-time-format.cc | 214 +- deps/v8/src/objects/js-date-time-format.h | 14 +- deps/v8/src/objects/js-display-names-inl.h | 7 +- deps/v8/src/objects/js-display-names.cc | 29 +- deps/v8/src/objects/js-display-names.h | 15 +- deps/v8/src/objects/js-list-format-inl.h | 6 +- deps/v8/src/objects/js-list-format.cc | 3 +- deps/v8/src/objects/js-list-format.h | 16 +- deps/v8/src/objects/js-locale-inl.h | 4 +- deps/v8/src/objects/js-locale.cc | 61 +- deps/v8/src/objects/js-locale.h | 18 +- deps/v8/src/objects/js-number-format-inl.h | 6 +- deps/v8/src/objects/js-number-format.cc | 45 +- deps/v8/src/objects/js-number-format.h | 14 +- deps/v8/src/objects/js-objects-inl.h | 6 +- deps/v8/src/objects/js-objects.cc | 57 +- deps/v8/src/objects/js-objects.h | 14 +- deps/v8/src/objects/js-objects.tq | 3 +- deps/v8/src/objects/js-plural-rules-inl.h | 6 +- deps/v8/src/objects/js-plural-rules.cc | 1 - deps/v8/src/objects/js-plural-rules.h | 13 +- deps/v8/src/objects/js-promise-inl.h | 4 +- deps/v8/src/objects/js-promise.h | 12 +- deps/v8/src/objects/js-promise.tq | 26 +- deps/v8/src/objects/js-regexp-inl.h | 7 +- .../objects/js-regexp-string-iterator-inl.h | 6 +- .../src/objects/js-regexp-string-iterator.h | 5 +- .../src/objects/js-regexp-string-iterator.tq | 8 +- deps/v8/src/objects/js-regexp.h | 11 +- .../src/objects/js-relative-time-format-inl.h | 7 +- deps/v8/src/objects/js-relative-time-format.h | 20 +- deps/v8/src/objects/js-segment-iterator-inl.h | 6 +- deps/v8/src/objects/js-segment-iterator.h | 15 +- deps/v8/src/objects/js-segmenter-inl.h | 6 +- deps/v8/src/objects/js-segmenter.cc | 4 +- deps/v8/src/objects/js-segmenter.h | 17 +- deps/v8/src/objects/js-weak-refs-inl.h | 72 +- deps/v8/src/objects/js-weak-refs.h | 40 +- deps/v8/src/objects/js-weak-refs.tq | 17 +- deps/v8/src/objects/layout-descriptor-inl.h | 1 + deps/v8/src/objects/lookup.cc | 52 +- deps/v8/src/objects/managed.h | 5 +- deps/v8/src/objects/map-inl.h | 3 + deps/v8/src/objects/map.cc | 69 +- deps/v8/src/objects/map.h | 38 +- deps/v8/src/objects/maybe-object-inl.h | 31 +- deps/v8/src/objects/maybe-object.h | 5 +- deps/v8/src/objects/object-list-macros.h | 8 +- .../objects/objects-body-descriptors-inl.h | 99 +- .../v8/src/objects/objects-body-descriptors.h | 89 +- deps/v8/src/objects/objects-definitions.h | 12 +- deps/v8/src/objects/objects.cc | 212 +- deps/v8/src/objects/objects.h | 1 + deps/v8/src/objects/ordered-hash-table.cc | 21 - deps/v8/src/objects/ordered-hash-table.h | 7 - deps/v8/src/objects/promise.tq | 2 +- deps/v8/src/objects/script.h | 6 +- .../v8/src/objects/shared-function-info-inl.h | 2 + deps/v8/src/objects/source-text-module.cc | 10 + deps/v8/src/objects/source-text-module.h | 5 + deps/v8/src/objects/string-inl.h | 105 +- deps/v8/src/objects/string-table.h | 2 +- deps/v8/src/objects/string.cc | 12 +- deps/v8/src/objects/string.h | 46 +- deps/v8/src/objects/string.tq | 11 +- deps/v8/src/objects/visitors.h | 46 +- deps/v8/src/parsing/expression-scope.h | 37 +- deps/v8/src/parsing/parse-info.cc | 360 +-- deps/v8/src/parsing/parse-info.h | 434 ++- deps/v8/src/parsing/parser-base.h | 127 +- deps/v8/src/parsing/parser.cc | 192 +- deps/v8/src/parsing/parser.h | 35 +- deps/v8/src/parsing/parsing.cc | 72 +- .../pending-compilation-error-handler.cc | 111 +- .../pending-compilation-error-handler.h | 54 +- deps/v8/src/parsing/preparse-data-impl.h | 9 +- deps/v8/src/parsing/preparse-data.cc | 14 +- deps/v8/src/parsing/preparse-data.h | 7 +- deps/v8/src/parsing/preparser.cc | 9 +- deps/v8/src/parsing/preparser.h | 11 +- deps/v8/src/parsing/rewriter.cc | 19 +- deps/v8/src/parsing/scanner-inl.h | 16 +- deps/v8/src/parsing/scanner.cc | 15 +- deps/v8/src/parsing/scanner.h | 23 +- deps/v8/src/parsing/token.h | 10 +- deps/v8/src/profiler/cpu-profiler.cc | 13 +- deps/v8/src/profiler/cpu-profiler.h | 43 +- deps/v8/src/profiler/heap-profiler.cc | 19 +- .../src/profiler/heap-snapshot-generator.cc | 6 +- deps/v8/src/profiler/profile-generator.cc | 1 + deps/v8/src/profiler/profile-generator.h | 1 - .../v8/src/profiler/sampling-heap-profiler.cc | 8 +- deps/v8/src/profiler/tracing-cpu-profiler.cc | 1 + .../regexp/arm/regexp-macro-assembler-arm.cc | 19 - .../regexp/arm/regexp-macro-assembler-arm.h | 9 +- .../arm64/regexp-macro-assembler-arm64.cc | 22 - .../arm64/regexp-macro-assembler-arm64.h | 9 +- .../ia32/regexp-macro-assembler-ia32.cc | 19 - .../regexp/ia32/regexp-macro-assembler-ia32.h | 9 +- .../mips/regexp-macro-assembler-mips.cc | 19 - .../regexp/mips/regexp-macro-assembler-mips.h | 9 +- .../mips64/regexp-macro-assembler-mips64.cc | 19 - .../mips64/regexp-macro-assembler-mips64.h | 9 +- .../regexp/ppc/regexp-macro-assembler-ppc.cc | 56 +- .../regexp/ppc/regexp-macro-assembler-ppc.h | 36 +- .../v8/src/regexp/regexp-bytecode-generator.h | 105 +- deps/v8/src/regexp/regexp-compiler-tonode.cc | 2 + deps/v8/src/regexp/regexp-compiler.cc | 68 +- deps/v8/src/regexp/regexp-compiler.h | 18 +- deps/v8/src/regexp/regexp-interpreter.cc | 134 +- deps/v8/src/regexp/regexp-interpreter.h | 26 +- deps/v8/src/regexp/regexp-macro-assembler.cc | 18 + deps/v8/src/regexp/regexp-macro-assembler.h | 20 +- deps/v8/src/regexp/regexp-nodes.h | 9 + deps/v8/src/regexp/regexp-utils.cc | 5 +- deps/v8/src/regexp/regexp.cc | 160 +- deps/v8/src/regexp/regexp.h | 2 +- .../s390/regexp-macro-assembler-s390.cc | 20 - .../regexp/s390/regexp-macro-assembler-s390.h | 8 +- .../regexp/x64/regexp-macro-assembler-x64.cc | 19 - .../regexp/x64/regexp-macro-assembler-x64.h | 9 +- deps/v8/src/roots/roots-inl.h | 32 +- deps/v8/src/roots/roots.cc | 21 +- deps/v8/src/roots/roots.h | 85 +- deps/v8/src/runtime/runtime-compiler.cc | 25 +- deps/v8/src/runtime/runtime-debug.cc | 1 + deps/v8/src/runtime/runtime-internal.cc | 34 +- deps/v8/src/runtime/runtime-module.cc | 2 +- deps/v8/src/runtime/runtime-numbers.cc | 4 +- deps/v8/src/runtime/runtime-object.cc | 13 +- deps/v8/src/runtime/runtime-promise.cc | 57 + deps/v8/src/runtime/runtime-regexp.cc | 18 +- deps/v8/src/runtime/runtime-scopes.cc | 35 +- deps/v8/src/runtime/runtime-test.cc | 266 +- deps/v8/src/runtime/runtime-wasm.cc | 238 +- deps/v8/src/runtime/runtime-weak-refs.cc | 30 + deps/v8/src/runtime/runtime.cc | 1 + deps/v8/src/runtime/runtime.h | 66 +- deps/v8/src/snapshot/DEPS | 2 +- deps/v8/src/snapshot/code-serializer.cc | 13 +- deps/v8/src/snapshot/code-serializer.h | 6 +- ...eserializer.cc => context-deserializer.cc} | 25 +- ...-deserializer.h => context-deserializer.h} | 12 +- ...al-serializer.cc => context-serializer.cc} | 134 +- ...tial-serializer.h => context-serializer.h} | 22 +- .../v8/src/snapshot/deserializer-allocator.cc | 4 +- deps/v8/src/snapshot/deserializer-allocator.h | 3 +- deps/v8/src/snapshot/deserializer.cc | 112 +- deps/v8/src/snapshot/deserializer.h | 10 +- .../v8/src/snapshot/embedded/embedded-data.cc | 6 +- .../platform-embedded-file-writer-aix.cc | 10 - .../platform-embedded-file-writer-aix.h | 3 - .../platform-embedded-file-writer-base.cc | 43 +- .../platform-embedded-file-writer-base.h | 2 +- .../platform-embedded-file-writer-generic.cc | 16 +- .../platform-embedded-file-writer-generic.h | 4 +- .../platform-embedded-file-writer-mac.cc | 4 - .../platform-embedded-file-writer-mac.h | 2 - deps/v8/src/snapshot/mksnapshot.cc | 2 +- deps/v8/src/snapshot/object-deserializer.cc | 8 +- .../v8/src/snapshot/read-only-deserializer.cc | 4 +- deps/v8/src/snapshot/read-only-serializer.cc | 8 +- deps/v8/src/snapshot/read-only-serializer.h | 2 +- deps/v8/src/snapshot/roots-serializer.cc | 5 +- deps/v8/src/snapshot/roots-serializer.h | 3 +- deps/v8/src/snapshot/serializer-allocator.h | 3 +- .../src/snapshot/serializer-deserializer.cc | 61 + ...zer-common.h => serializer-deserializer.h} | 206 +- deps/v8/src/snapshot/serializer.cc | 174 +- deps/v8/src/snapshot/serializer.h | 33 +- deps/v8/src/snapshot/snapshot-compression.cc | 2 + deps/v8/src/snapshot/snapshot-compression.h | 4 +- deps/v8/src/snapshot/snapshot-data.cc | 80 + deps/v8/src/snapshot/snapshot-data.h | 129 + deps/v8/src/snapshot/snapshot-source-sink.h | 20 +- deps/v8/src/snapshot/snapshot-utils.cc | 25 + deps/v8/src/snapshot/snapshot-utils.h | 18 + .../{snapshot-common.cc => snapshot.cc} | 401 ++- deps/v8/src/snapshot/snapshot.h | 197 +- deps/v8/src/snapshot/startup-deserializer.cc | 16 +- deps/v8/src/snapshot/startup-serializer.cc | 94 +- deps/v8/src/snapshot/startup-serializer.h | 14 +- deps/v8/src/strings/uri.cc | 2 +- deps/v8/src/torque/ast.h | 26 +- .../torque/class-debug-reader-generator.cc | 2 +- deps/v8/src/torque/constants.h | 3 +- deps/v8/src/torque/csa-generator.cc | 159 +- deps/v8/src/torque/declaration-visitor.cc | 11 +- deps/v8/src/torque/earley-parser.h | 5 +- deps/v8/src/torque/global-context.cc | 7 +- deps/v8/src/torque/global-context.h | 13 + deps/v8/src/torque/implementation-visitor.cc | 707 +++-- deps/v8/src/torque/implementation-visitor.h | 30 +- deps/v8/src/torque/instance-type-generator.cc | 75 +- deps/v8/src/torque/instructions.h | 16 +- deps/v8/src/torque/torque-compiler.cc | 2 +- deps/v8/src/torque/torque-parser.cc | 100 +- deps/v8/src/torque/type-oracle.h | 8 + deps/v8/src/torque/type-visitor.cc | 15 +- deps/v8/src/torque/type-visitor.h | 4 +- deps/v8/src/torque/types.cc | 188 +- deps/v8/src/torque/types.h | 70 +- deps/v8/src/torque/utils.h | 2 +- deps/v8/src/tracing/DEPS | 4 + deps/v8/src/tracing/trace-categories.cc | 9 + deps/v8/src/tracing/trace-categories.h | 58 + deps/v8/src/tracing/trace-event.cc | 2 + deps/v8/src/tracing/trace-event.h | 47 +- deps/v8/src/tracing/traced-value.cc | 15 + deps/v8/src/tracing/traced-value.h | 13 +- deps/v8/src/utils/ostreams.h | 4 +- deps/v8/src/utils/pointer-with-payload.h | 2 +- deps/v8/src/utils/vector.h | 39 +- .../wasm/baseline/arm/liftoff-assembler-arm.h | 1559 +++++++++-- .../baseline/arm64/liftoff-assembler-arm64.h | 637 ++++- .../baseline/ia32/liftoff-assembler-ia32.h | 1403 ++++++++-- .../v8/src/wasm/baseline/liftoff-assembler.cc | 213 +- deps/v8/src/wasm/baseline/liftoff-assembler.h | 426 ++- deps/v8/src/wasm/baseline/liftoff-compiler.cc | 1268 +++++---- deps/v8/src/wasm/baseline/liftoff-compiler.h | 5 +- deps/v8/src/wasm/baseline/liftoff-register.h | 20 + .../baseline/mips/liftoff-assembler-mips.h | 869 ++++-- .../mips64/liftoff-assembler-mips64.h | 1077 ++++++-- .../wasm/baseline/ppc/liftoff-assembler-ppc.h | 554 +++- .../baseline/s390/liftoff-assembler-s390.h | 554 +++- .../wasm/baseline/x64/liftoff-assembler-x64.h | 1495 +++++++++-- deps/v8/src/wasm/c-api.cc | 4 +- deps/v8/src/wasm/compilation-environment.h | 13 +- deps/v8/src/wasm/decoder.h | 35 + deps/v8/src/wasm/function-body-decoder-impl.h | 750 ++++-- deps/v8/src/wasm/function-body-decoder.cc | 3 +- deps/v8/src/wasm/function-body-decoder.h | 4 +- deps/v8/src/wasm/function-compiler.cc | 35 +- deps/v8/src/wasm/function-compiler.h | 7 +- deps/v8/src/wasm/graph-builder-interface.cc | 84 +- deps/v8/src/wasm/local-decl-encoder.cc | 13 +- deps/v8/src/wasm/module-compiler.cc | 321 +-- deps/v8/src/wasm/module-compiler.h | 9 +- deps/v8/src/wasm/module-decoder.cc | 204 +- deps/v8/src/wasm/module-decoder.h | 8 +- deps/v8/src/wasm/module-instantiate.cc | 66 +- deps/v8/src/wasm/struct-types.h | 116 + deps/v8/src/wasm/value-type.h | 133 +- deps/v8/src/wasm/wasm-code-manager.cc | 346 +-- deps/v8/src/wasm/wasm-code-manager.h | 170 +- deps/v8/src/wasm/wasm-constants.h | 16 +- deps/v8/src/wasm/wasm-debug-evaluate.cc | 190 +- deps/v8/src/wasm/wasm-debug-evaluate.h | 2 +- deps/v8/src/wasm/wasm-debug.cc | 935 ++----- deps/v8/src/wasm/wasm-debug.h | 19 +- deps/v8/src/wasm/wasm-engine.cc | 258 +- deps/v8/src/wasm/wasm-engine.h | 21 +- deps/v8/src/wasm/wasm-feature-flags.h | 8 +- deps/v8/src/wasm/wasm-features.cc | 3 + deps/v8/src/wasm/wasm-interpreter.cc | 263 +- deps/v8/src/wasm/wasm-js.cc | 31 +- deps/v8/src/wasm/wasm-module-builder.cc | 121 +- deps/v8/src/wasm/wasm-module-builder.h | 41 +- deps/v8/src/wasm/wasm-module.cc | 37 +- deps/v8/src/wasm/wasm-module.h | 103 +- deps/v8/src/wasm/wasm-objects-inl.h | 51 + deps/v8/src/wasm/wasm-objects.cc | 129 +- deps/v8/src/wasm/wasm-objects.h | 119 +- deps/v8/src/wasm/wasm-objects.tq | 12 + deps/v8/src/wasm/wasm-opcodes.cc | 45 +- deps/v8/src/wasm/wasm-opcodes.h | 464 ++-- deps/v8/src/wasm/wasm-serialization.cc | 12 +- deps/v8/src/wasm/wasm-tier.h | 6 + deps/v8/test/benchmarks/benchmarks.status | 5 + deps/v8/test/cctest/BUILD.gn | 25 +- deps/v8/test/cctest/cctest.cc | 2 +- deps/v8/test/cctest/cctest.h | 6 + deps/v8/test/cctest/cctest.status | 32 +- .../test-js-context-specialization.cc | 6 + deps/v8/test/cctest/compiler/test-linkage.cc | 28 + deps/v8/test/cctest/compiler/value-helper.h | 24 +- deps/v8/test/cctest/heap/heap-utils.cc | 1 + deps/v8/test/cctest/heap/test-compaction.cc | 3 +- .../cctest/heap/test-concurrent-allocation.cc | 100 + .../test/cctest/heap/test-embedder-tracing.cc | 3 +- deps/v8/test/cctest/heap/test-heap.cc | 81 +- .../cctest/heap/test-invalidated-slots.cc | 4 +- deps/v8/test/cctest/heap/test-spaces.cc | 2 + .../AsyncGenerators.golden | 42 +- .../DestructuringAssignment.golden | 87 +- .../bytecode_expectations/ForAwaitOf.golden | 136 +- .../bytecode_expectations/ForOf.golden | 120 +- .../bytecode_expectations/ForOfLoop.golden | 240 +- .../bytecode_expectations/Generators.golden | 31 +- .../PrivateAccessorAccess.golden | 30 +- .../PrivateClassFieldAccess.golden | 84 + .../PrivateMethodAccess.golden | 20 +- .../StaticPrivateMethodAccess.golden | 28 +- .../interpreter/test-bytecode-generator.cc | 36 + .../cctest/interpreter/test-interpreter.cc | 33 +- .../test/cctest/libplatform/test-tracing.cc | 451 ++-- deps/v8/test/cctest/parsing/test-preparser.cc | 23 +- deps/v8/test/cctest/parsing/test-scanner.cc | 6 +- deps/v8/test/cctest/test-api-icu.cc | 57 + deps/v8/test/cctest/test-api-wasm.cc | 34 + deps/v8/test/cctest/test-api.cc | 150 +- .../test/cctest/test-code-stub-assembler.cc | 299 ++- deps/v8/test/cctest/test-constantpool.cc | 25 +- deps/v8/test/cctest/test-cpu-profiler.cc | 49 +- deps/v8/test/cctest/test-debug-helper.cc | 1 + deps/v8/test/cctest/test-debug.cc | 22 +- deps/v8/test/cctest/test-disasm-ia32.cc | 7 + deps/v8/test/cctest/test-disasm-x64.cc | 21 + .../test/cctest/test-field-type-tracking.cc | 149 +- deps/v8/test/cctest/test-flags.cc | 1 - deps/v8/test/cctest/test-inspector.cc | 109 +- deps/v8/test/cctest/test-js-weak-refs.cc | 139 +- deps/v8/test/cctest/test-log.cc | 6 +- deps/v8/test/cctest/test-parsing.cc | 269 +- .../v8/test/cctest/test-persistent-handles.cc | 114 + deps/v8/test/cctest/test-regexp.cc | 49 +- deps/v8/test/cctest/test-roots.cc | 2 +- deps/v8/test/cctest/test-serialize.cc | 219 +- deps/v8/test/cctest/torque/test-torque.cc | 44 +- deps/v8/test/cctest/wasm/test-gc.cc | 311 +++ .../cctest/wasm/test-liftoff-inspection.cc | 37 +- .../cctest/wasm/test-run-wasm-atomics64.cc | 31 +- .../cctest/wasm/test-run-wasm-bulk-memory.cc | 58 +- .../cctest/wasm/test-run-wasm-exceptions.cc | 18 +- deps/v8/test/cctest/wasm/test-run-wasm-js.cc | 84 +- .../cctest/wasm/test-run-wasm-simd-liftoff.cc | 35 + .../test-run-wasm-simd-scalar-lowering.cc | 47 + .../v8/test/cctest/wasm/test-run-wasm-simd.cc | 219 +- deps/v8/test/cctest/wasm/test-run-wasm.cc | 6 +- .../test/cctest/wasm/test-wasm-breakpoints.cc | 46 +- .../cctest/wasm/test-wasm-debug-evaluate.cc | 111 +- .../wasm/test-wasm-interpreter-entry.cc | 260 -- .../cctest/wasm/test-wasm-serialization.cc | 18 +- .../cctest/wasm/test-wasm-shared-engine.cc | 3 +- deps/v8/test/cctest/wasm/test-wasm-stack.cc | 6 +- .../cctest/wasm/test-wasm-trap-position.cc | 4 +- deps/v8/test/cctest/wasm/wasm-run-utils.cc | 65 +- deps/v8/test/cctest/wasm/wasm-run-utils.h | 55 +- deps/v8/test/common/wasm/wasm-macro-gen.h | 148 +- .../v8/test/common/wasm/wasm-module-runner.cc | 3 + .../debug-liveedit-patch-positions-replace.js | 2 +- .../es6/debug-promises/promise-any-caught.js | 39 + .../debug-promises/promise-any-uncaught.js | 67 + .../debugger/debug/regress/regress-10319.js | 46 + ...bled-tier-down-wasm-unsupported-liftoff.js | 5 +- .../wasm/debug-enabled-tier-down-wasm.js | 13 +- .../debug/wasm/debug-step-into-wasm.js | 8 +- deps/v8/test/debugger/debugger.status | 29 +- deps/v8/test/debugging/debugging.status | 9 +- deps/v8/test/debugging/testcfg.py | 3 +- deps/v8/test/debugging/wasm/gdb-server/OWNERS | 3 + .../debugging/wasm/gdb-server/breakpoints.py | 58 + .../test/debugging/wasm/gdb-server/connect.py | 34 +- .../test/debugging/wasm/gdb-server/float.py | 71 + .../test/debugging/wasm/gdb-server/gdb_rsp.py | 137 +- .../test/debugging/wasm/gdb-server/memory.py | 96 + .../test/debugging/wasm/gdb-server/status.py | 109 + .../debugging/wasm/gdb-server/stepping.py | 56 + .../wasm/gdb-server/test_files/__init__.py | 0 .../wasm/gdb-server/test_files/test.js | 33 - .../wasm/gdb-server/test_files/test_basic.js | 31 + .../wasm/gdb-server/test_files/test_basic.py | 23 + .../wasm/gdb-server/test_files/test_float.js | 31 + .../wasm/gdb-server/test_files/test_float.py | 21 + .../wasm/gdb-server/test_files/test_memory.js | 48 + .../wasm/gdb-server/test_files/test_memory.py | 43 + .../wasm/gdb-server/test_files/test_trap.js | 31 + .../wasm/gdb-server/test_files/test_trap.py | 28 + .../v8/test/debugging/wasm/gdb-server/trap.py | 37 + deps/v8/test/fuzzer/fuzzer.status | 5 + deps/v8/test/fuzzer/parser.cc | 6 +- deps/v8/test/fuzzer/wasm-compile.cc | 143 +- deps/v8/test/fuzzer/wasm-fuzzer-common.cc | 11 +- ...asm-js-breakpoint-before-exec-expected.txt | 20 +- .../debugger/asm-js-breakpoint-before-exec.js | 9 +- ...asm-js-breakpoint-during-exec-expected.txt | 14 +- .../debugger/asm-js-breakpoint-during-exec.js | 2 - ...t-preview-internal-properties-expected.txt | 4 +- .../inspector/debugger/wasm-anyref-global.js | 11 +- ...int-reset-on-debugger-restart-expected.txt | 11 + ...sm-breakpoint-reset-on-debugger-restart.js | 63 + .../debugger/wasm-debug-evaluate-expected.txt | 5 + .../inspector/debugger/wasm-debug-evaluate.js | 155 ++ .../inspector/debugger/wasm-global-names.js | 12 +- .../wasm-inspect-many-registers-expected.txt | 160 +- .../debugger/wasm-inspect-many-registers.js | 20 +- .../debugger/wasm-memory-names-expected.txt | 19 + .../inspector/debugger/wasm-memory-names.js | 117 + .../debugger/wasm-scope-info-expected.txt | 105 +- .../wasm-scope-info-liftoff-expected.txt | 66 +- .../debugger/wasm-scope-info-liftoff.js | 2 - .../inspector/debugger/wasm-scope-info.js | 2 - .../debugger/wasm-scripts-expected.txt | 80 +- .../test/inspector/debugger/wasm-scripts.js | 101 +- .../wasm-set-breakpoint-liftoff-expected.txt | 111 +- .../debugger/wasm-set-breakpoint-liftoff.js | 2 - .../wasm-step-after-trap-expected.txt | 56 + .../debugger/wasm-step-after-trap.js | 102 + .../wasm-stepping-byte-offsets-expected.txt | 84 +- .../debugger/wasm-stepping-byte-offsets.js | 6 +- .../debugger/wasm-stepping-liftoff.js | 2 - ...wasm-stepping-with-source-map-expected.txt | 87 +- .../debugger/wasm-stepping-with-source-map.js | 3 +- deps/v8/test/inspector/inspector-test.cc | 1 - deps/v8/test/inspector/inspector.status | 22 +- .../runtime/internal-properties-expected.txt | 2 +- .../runtime/query-objects-expected.txt | 3 + .../test/inspector/runtime/query-objects.js | 28 + .../runtime/regress-1075763-expected.txt | 26 + .../test/inspector/runtime/regress-1075763.js | 14 + .../runtime/regress-1078205-expected.txt | 157 ++ .../test/inspector/runtime/regress-1078205.js | 34 + .../runtime/regress-986051-expected.txt | 76 + .../test/inspector/runtime/regress-986051.js | 25 + .../runtime/remote-object-expected.txt | 2 +- .../test/intl/date-format/check-calendar.js | 2 - .../date-format/check-numbering-system.js | 2 - ...nstructor-calendar-numberingSytem-order.js | 1 - .../intl/date-format/property-override.js | 1 + deps/v8/test/intl/date-format/related-year.js | 1 - .../intl/displaynames/constructor-order.js | 2 - deps/v8/test/intl/displaynames/constructor.js | 1 - .../intl/displaynames/resolved-options.js | 2 - .../intl/displaynames/supported-locale.js | 2 - deps/v8/test/intl/intl.status | 13 +- .../v8/test/intl/locale/locale-constructor.js | 5 +- .../number-format/check-numbering-system.js | 2 - .../constructor-numberingSytem-order.js | 2 - .../number-format/unified/sign-display.js | 2 +- deps/v8/test/intl/regress-10437.js | 18 + deps/v8/test/intl/regress-10438.js | 51 + deps/v8/test/intl/regress-1074578.js | 45 + deps/v8/test/intl/regress-364374.js | 60 + deps/v8/test/intl/regress-966285.js | 2 - deps/v8/test/intl/regress-9786.js | 2 - deps/v8/test/intl/regress-9787.js | 2 - deps/v8/test/intl/regress-9788.js | 2 - deps/v8/test/intl/regress-9887.js | 2 - .../resolved-options-nu-extended.js | 38 +- deps/v8/test/js-perf-test/JSTests1.json | 16 + .../Operators/abstract-equality.js | 79 + deps/v8/test/js-perf-test/Operators/run.js | 28 + deps/v8/test/message/fail/spread-call-4.js | 5 + deps/v8/test/message/fail/spread-call-4.out | 5 + deps/v8/test/message/message.status | 9 +- .../message/wasm-trace-memory-interpreted.js | 8 - .../message/wasm-trace-memory-interpreted.out | 14 - .../weakref-finalizationregistry-error.js | 3 +- .../weakref-finalizationregistry-error.out | 2 + deps/v8/test/mjsunit/asm/load-elimination.js | 2 - .../v8/test/mjsunit/call-intrinsic-fuzzing.js | 6 +- .../mjsunit/compiler/abstract-equal-symbol.js | 4 +- .../compiler/abstract-equal-undetectable.js | 31 +- .../compiler/bigint-add-no-deopt-loop.js | 4 +- .../monomorphic-named-load-with-no-map.js | 53 + deps/v8/test/mjsunit/compiler/osr-infinite.js | 1 - .../compiler/redundancy-elimination.js | 12 +- .../test/mjsunit/compiler/regress-1065737.js | 17 + .../test/mjsunit/compiler/regress-1067544.js | 16 + .../test/mjsunit/compiler/regress-1068494.js | 14 + .../test/mjsunit/compiler/regress-1070892.js | 17 + .../test/mjsunit/compiler/regress-1071743.js | 32 + .../test/mjsunit/compiler/regress-1074736.js | 17 + .../test/mjsunit/compiler/regress-1082704.js | 16 + .../test/mjsunit/compiler/regress-1084820.js | 27 + .../test/mjsunit/compiler/regress-1092650.js | 23 + .../test/mjsunit/compiler/regress-1094132.js | 78 + .../v8/test/mjsunit/const-field-tracking-2.js | 225 ++ deps/v8/test/mjsunit/es6/array-copywithin.js | 2 +- .../es6/promise-all-resolve-not-callable.js | 30 + ...promise-allsettled-resolve-not-callable.js | 30 + .../es6/promise-race-resolve-not-callable.js | 30 + .../test/mjsunit/es6/proxies-constructor.js | 16 - deps/v8/test/mjsunit/es6/proxies-revocable.js | 6 - deps/v8/test/mjsunit/es6/reflect-construct.js | 3 +- .../mjsunit/es6/regress/regress-411237.js | 17 - .../es6/typedarray-from-optional-arguments.js | 32 + .../test/mjsunit/harmony/aggregate-error.js | 213 ++ .../mjsunit/harmony/logical-assignment.js | 42 + .../test/mjsunit/harmony/optional-chaining.js | 1 - .../mjsunit/harmony/promise-any-overflow-1.js | 21 + .../mjsunit/harmony/promise-any-overflow-2.js | 18 + .../promise-any-resolve-not-callable.js | 30 + deps/v8/test/mjsunit/harmony/promise-any.js | 94 + .../test/mjsunit/harmony/string-matchAll.js | 2 +- .../harmony/weakrefs/basics-cleanupsome.js | 25 + .../test/mjsunit/harmony/weakrefs/basics.js | 20 - .../cleanup-doesnt-iterate-all-holdings.js | 93 - .../weakrefs/cleanup-is-not-a-microtask.js | 3 +- .../{iterating-in-cleanup.js => cleanup.js} | 33 +- .../mjsunit/harmony/weakrefs/cleanupsome-2.js | 8 +- .../weakrefs/cleanupsome-after-unregister.js | 8 +- .../harmony/weakrefs/cleanupsome-optional.js | 13 + .../mjsunit/harmony/weakrefs/cleanupsome.js | 10 +- .../weakrefs/clearkeptobjects-on-quit.js | 13 + .../weakrefs/finalizationregistry-and-weakref | 6 +- ...nalizationregistry-independent-lifetime.js | 3 +- ...nalizationregistry-keeps-holdings-alive.js | 12 +- ...ry-scheduled-for-cleanup-multiple-times.js | 19 +- .../multiple-dirty-finalization-groups.js | 8 +- .../weakrefs/reentrant-gc-from-cleanup.js | 4 +- ...ress-finalizationregistry-dirty-enqueue.js | 36 + .../harmony/weakrefs/undefined-holdings.js | 10 +- .../weakrefs/unregister-after-cleanup.js | 12 +- .../weakrefs/unregister-before-cleanup.js | 2 +- .../weakrefs/unregister-called-twice.js | 2 +- ...eanup5.js => unregister-inside-cleanup.js} | 22 +- .../weakrefs/unregister-inside-cleanup1.js | 42 - .../weakrefs/unregister-inside-cleanup2.js | 36 +- .../weakrefs/unregister-inside-cleanup3.js | 26 +- .../weakrefs/unregister-inside-cleanup4.js | 50 - .../harmony/weakrefs/unregister-many.js | 8 +- ...register-when-cleanup-already-scheduled.js | 2 +- .../harmony/weakrefs/weak-cell-basics.js | 8 +- .../harmony/weakrefs/weak-unregistertoken.js | 8 +- deps/v8/test/mjsunit/mjsunit.js | 2 +- deps/v8/test/mjsunit/mjsunit.status | 113 +- deps/v8/test/mjsunit/never-optimize.js | 29 +- ...uiltins.js => object-tostring-builtins.js} | 4 +- deps/v8/test/mjsunit/regress-crbug-1078825.js | 20 + deps/v8/test/mjsunit/regress/regress-10508.js | 15 + .../test/mjsunit/regress/regress-1069964.js | 8 + .../test/mjsunit/regress/regress-1071190.js | 23 + .../test/mjsunit/regress/regress-1076569.js | 16 + .../test/mjsunit/regress/regress-1077804.js | 21 + .../test/mjsunit/regress/regress-1078913.js | 29 + deps/v8/test/mjsunit/regress/regress-1365.js | 1 - .../v8/test/mjsunit/regress/regress-447756.js | 9 +- .../v8/test/mjsunit/regress/regress-491481.js | 15 - .../regress/regress-crbug-1053939-1.js | 16 + .../regress/regress-crbug-1055138-1.js | 64 + .../regress/regress-crbug-1055138-2.js | 34 + .../regress/regress-crbug-1055138-3.js | 40 + .../mjsunit/regress/regress-crbug-1060023.js | 10 + ...ess-347542.js => regress-crbug-1063796.js} | 13 +- .../mjsunit/regress/regress-crbug-1065741.js | 19 + .../mjsunit/regress/regress-crbug-1067757.js | 30 + .../mjsunit/regress/regress-crbug-1070560.js | 16 + .../mjsunit/regress/regress-crbug-1074737.js | 40 + .../mjsunit/regress/regress-crbug-1077508.js | 14 + .../mjsunit/regress/regress-crbug-754177.js | 7 +- .../mjsunit/regress/regress-v8-10484-1.js | 18 + .../mjsunit/regress/regress-v8-10484-2.js | 24 + .../test/mjsunit/regress/regress-v8-10513.js | 25 + .../mjsunit/regress/wasm/regress-10309.js | 2 +- .../mjsunit/regress/wasm/regress-1054466.js | 6 +- .../mjsunit/regress/wasm/regress-1055692.js | 35 - .../mjsunit/regress/wasm/regress-1065599.js | 27 + .../mjsunit/regress/wasm/regress-1065635.js | 13 + .../mjsunit/regress/wasm/regress-1065852.js | 14 + .../mjsunit/regress/wasm/regress-1067621.js | 82 + .../mjsunit/regress/wasm/regress-1070078.js | 39 + .../mjsunit/regress/wasm/regress-1073553.js | 14 + .../mjsunit/regress/wasm/regress-1074586-b.js | 23 + .../mjsunit/regress/wasm/regress-1074586.js | 94 + .../mjsunit/regress/wasm/regress-1075953.js | 38 + .../mjsunit/regress/wasm/regress-1079449.js | 37 + .../mjsunit/regress/wasm/regress-1081030.js | 25 + .../test/mjsunit/regress/wasm/regress-7049.js | 53 - .../mjsunit/regress/wasm/regress-715216a.js | 12 - .../mjsunit/regress/wasm/regress-715216b.js | 12 - .../mjsunit/regress/wasm/regress-719175.js | 16 - .../mjsunit/regress/wasm/regress-766003.js | 16 - .../mjsunit/regress/wasm/regress-771243.js | 38 - .../mjsunit/regress/wasm/regress-772332.js | 32 - .../mjsunit/regress/wasm/regress-778917.js | 19 - .../mjsunit/regress/wasm/regress-831463.js | 21 - .../mjsunit/regress/wasm/regress-834624.js | 29 - .../regress/wasm/regress-crbug-1007608.js | 26 - .../test/mjsunit/serialize-deserialize-now.js | 17 + deps/v8/test/mjsunit/tools/foozzie.js | 18 +- .../test/mjsunit/wasm/anyfunc-interpreter.js | 12 - .../wasm/anyref-globals-interpreter.js | 12 - .../test/mjsunit/wasm/anyref-interpreter.js | 12 - deps/v8/test/mjsunit/wasm/asm-wasm.js | 24 + .../compilation-hints-async-compilation.js | 2 +- .../mjsunit/wasm/compilation-hints-decoder.js | 6 +- .../mjsunit/wasm/compilation-hints-ignored.js | 4 +- .../wasm/compilation-hints-interpreter.js | 113 - ...compilation-hints-streaming-compilation.js | 2 +- .../compilation-hints-sync-compilation.js | 2 +- .../wasm/compiled-module-management.js | 1 + .../wasm/exceptions-anyref-interpreter.js | 12 - .../wasm/exceptions-global-interpreter.js | 12 - .../mjsunit/wasm/exceptions-interpreter.js | 12 - .../wasm/exceptions-rethrow-interpreter.js | 12 - .../wasm/exceptions-simd-interpreter.js | 12 - deps/v8/test/mjsunit/wasm/exceptions-simd.js | 2 +- deps/v8/test/mjsunit/wasm/exceptions.js | 51 +- .../v8/test/mjsunit/wasm/futex-interpreter.js | 12 - ...ndirect-call-non-zero-table-interpreter.js | 12 - .../v8/test/mjsunit/wasm/interpreter-mixed.js | 222 -- deps/v8/test/mjsunit/wasm/interpreter.js | 569 ---- .../mjsunit/wasm/multi-value-interpreter.js | 7 - .../test/mjsunit/wasm/nullref-interpreter.js | 12 - .../mjsunit/wasm/streaming-error-position.js | 2 +- .../mjsunit/wasm/table-access-interpreter.js | 12 - .../mjsunit/wasm/table-fill-interpreter.js | 12 - .../wasm/table-grow-from-wasm-interpreter.js | 12 - .../test/mjsunit/wasm/wasm-module-builder.js | 29 +- .../test/mjsunit/wasm/worker-interpreter.js | 68 - deps/v8/test/mozilla/mozilla.status | 5 + deps/v8/test/test262/BUILD.gn | 1 + deps/v8/test/test262/harness-ishtmldda.js | 5 + deps/v8/test/test262/test262.status | 159 +- deps/v8/test/test262/testcfg.py | 13 +- deps/v8/test/torque/test-torque.tq | 2063 +++++++------- deps/v8/test/unittests/BUILD.gn | 36 +- .../unittests/api/remote-object-unittest.cc | 17 - .../compiler-dispatcher-unittest.cc | 8 +- .../instruction-selector-arm64-unittest.cc | 95 +- .../effect-control-linearizer-unittest.cc | 235 ++ .../compiler/int64-lowering-unittest.cc | 6 +- .../machine-operator-reducer-unittest.cc | 251 +- .../unittests/compiler/node-test-utils.cc | 14 + .../test/unittests/compiler/node-test-utils.h | 7 + .../redundancy-elimination-unittest.cc | 28 +- .../test/unittests/compiler/typer-unittest.cc | 40 +- .../execution/microtask-queue-unittest.cc | 12 +- .../v8/test/unittests/heap/bitmap-unittest.cc | 2 +- .../heap/cppgc/allocation_unittest.cc | 42 - .../heap/cppgc/custom-spaces-unittest.cc | 130 + ...nittest.cc => finalizer-trait-unittest.cc} | 4 +- .../heap/cppgc/free-list-unittest.cc | 187 ++ .../heap/cppgc/garbage-collected-unittest.cc | 143 + .../heap/cppgc/garbage-collected_unittest.cc | 26 - ...c-info_unittest.cc => gc-info-unittest.cc} | 2 +- ...test.cc => heap-object-header-unittest.cc} | 0 .../heap/cppgc/heap-page-unittest.cc | 274 ++ .../unittests/heap/cppgc/heap-unittest.cc | 115 + .../unittests/heap/cppgc/logging-unittest.cc | 79 + .../unittests/heap/cppgc/marker-unittest.cc | 188 ++ .../heap/cppgc/marking-visitor-unittest.cc | 285 ++ .../unittests/heap/cppgc/member-unittest.cc | 304 +++ .../cppgc/object-start-bitmap-unittest.cc | 189 ++ .../heap/cppgc/page-memory-unittest.cc | 308 +++ .../heap/cppgc/persistent-unittest.cc | 658 +++++ .../heap/cppgc/prefinalizer-unittest.cc | 199 ++ .../heap/cppgc/source-location-unittest.cc | 61 + .../unittests/heap/cppgc/stack-unittest.cc | 357 +++ .../unittests/heap/cppgc/stack_unittest.cc | 256 -- .../unittests/heap/cppgc/sweeper-unittest.cc | 230 ++ deps/v8/test/unittests/heap/cppgc/tests.cc | 17 +- deps/v8/test/unittests/heap/cppgc/tests.h | 25 +- .../unittests/heap/cppgc/visitor-unittest.cc | 232 ++ .../unittests/heap/cppgc/worklist-unittest.cc | 346 +++ .../heap/embedder-tracing-unittest.cc | 48 +- deps/v8/test/unittests/heap/heap-unittest.cc | 4 +- .../unittests/{base => heap}/list-unittest.cc | 12 +- .../heap/off-thread-factory-unittest.cc | 140 +- .../test/unittests/heap/safepoint-unittest.cc | 3 + .../test/unittests/heap/slot-set-unittest.cc | 36 +- .../v8/test/unittests/heap/spaces-unittest.cc | 27 +- .../libplatform/default-job-unittest.cc | 233 ++ .../libplatform/default-platform-unittest.cc | 10 +- .../objects/backing-store-unittest.cc | 22 +- .../tasks/background-compile-task-unittest.cc | 5 +- deps/v8/test/unittests/test-helpers.cc | 10 +- deps/v8/test/unittests/test-helpers.h | 3 +- deps/v8/test/unittests/test-utils.cc | 65 +- deps/v8/test/unittests/test-utils.h | 216 +- .../test/unittests/torque/torque-unittest.cc | 46 + deps/v8/test/unittests/unittests.status | 5 + .../test/unittests/utils/vector-unittest.cc | 54 +- .../wasm/function-body-decoder-unittest.cc | 40 +- .../unittests/wasm/module-decoder-unittest.cc | 65 +- .../wasm/wasm-code-manager-unittest.cc | 16 +- .../unittests/wasm/wasm-gdbserver-unittest.cc | 275 ++ .../unittests/wasm/wasm-opcodes-unittest.cc | 35 - deps/v8/test/wasm-api-tests/callbacks.cc | 4 +- .../test/wasm-api-tests/wasm-api-tests.status | 6 + deps/v8/test/wasm-js/testcfg.py | 4 - deps/v8/test/wasm-js/tests.tar.gz.sha1 | 2 +- deps/v8/test/wasm-js/wasm-js.status | 9 +- deps/v8/test/wasm-spec-tests/testcfg.py | 8 +- .../v8/test/wasm-spec-tests/tests.tar.gz.sha1 | 2 +- .../wasm-spec-tests/wasm-spec-tests.status | 19 +- deps/v8/test/webkit/webkit.status | 6 +- deps/v8/testing/gmock/BUILD.gn | 9 +- .../gmock/gmock-generated-function-mockers.h | 10 - deps/v8/third_party/googletest/BUILD.gn | 22 +- deps/v8/third_party/jinja2/README.chromium | 1 + deps/v8/third_party/jsoncpp/BUILD.gn | 50 + deps/v8/third_party/jsoncpp/LICENSE | 55 + deps/v8/third_party/jsoncpp/README.chromium | 16 + .../third_party/jsoncpp/generated/version.h | 22 + deps/v8/third_party/v8/builtins/array-sort.tq | 2374 ++++++++--------- deps/v8/third_party/zlib/BUILD.gn | 81 +- deps/v8/third_party/zlib/DEPS | 3 + deps/v8/third_party/zlib/README.chromium | 1 + deps/v8/third_party/zlib/chromeconf.h | 4 + .../contrib/optimizations/insert_string.h | 59 +- deps/v8/third_party/zlib/cpu_features.c | 7 +- deps/v8/third_party/zlib/cpu_features.h | 1 + deps/v8/third_party/zlib/crc32.c | 6 +- deps/v8/third_party/zlib/crc_folding.c | 6 +- deps/v8/third_party/zlib/deflate.c | 4 +- deps/v8/third_party/zlib/fill_window_sse.c | 7 +- deps/v8/third_party/zlib/google/OWNERS | 1 + .../zlib/google/compression_utils_portable.cc | 2 +- .../third_party/zlib/google/zip_internal.cc | 1 + .../zlib/patches/0005-infcover-gtest.patch | 405 +++ deps/v8/tools/callstats.html | 148 +- .../clusterfuzz/testdata/failure_output.txt | 4 +- .../testdata/sanity_check_output.txt | 4 +- deps/v8/tools/clusterfuzz/v8_commands.py | 1 + deps/v8/tools/clusterfuzz/v8_mock.js | 30 +- deps/v8/tools/clusterfuzz/v8_sanity_checks.js | 13 + deps/v8/tools/csvparser.js | 8 +- deps/v8/tools/debug_helper/BUILD.gn | 5 + .../debug_helper/get-object-properties.cc | 14 +- deps/v8/tools/gen-postmortem-metadata.py | 1 - deps/v8/tools/logreader.js | 3 +- deps/v8/tools/map-processor.html | 126 +- deps/v8/tools/map-processor.js | 139 +- deps/v8/tools/testrunner/base_runner.py | 6 - .../v8/tools/testrunner/local/junit_output.py | 49 - deps/v8/tools/testrunner/local/variants.py | 3 + deps/v8/tools/testrunner/standard_runner.py | 2 + deps/v8/tools/testrunner/testproc/progress.py | 113 +- deps/v8/tools/testrunner/testproc/util.py | 39 + .../testrunner/testproc/util_unittest.py | 61 + deps/v8/tools/torque/format-torque.py | 10 + deps/v8/tools/unittests/run_tests_test.py | 6 +- .../testdata/expected_test_results1.json | 229 +- .../testdata/expected_test_results2.json | 144 +- deps/v8/tools/v8heapconst.py | 423 +-- deps/v8/tools/wasm/update-wasm-spec-tests.sh | 2 +- deps/v8/tools/whitespace.txt | 6 +- 1404 files changed, 73183 insertions(+), 39738 deletions(-) create mode 100644 deps/v8/include/cppgc/DEPS create mode 100644 deps/v8/include/cppgc/common.h create mode 100644 deps/v8/include/cppgc/custom-space.h create mode 100644 deps/v8/include/cppgc/internal/accessors.h rename deps/v8/include/cppgc/{internals.h => internal/api-constants.h} (57%) create mode 100644 deps/v8/include/cppgc/internal/compiler-specific.h rename deps/v8/include/cppgc/{ => internal}/finalizer-trait.h (92%) rename deps/v8/include/cppgc/{ => internal}/gc-info.h (81%) create mode 100644 deps/v8/include/cppgc/internal/logging.h create mode 100644 deps/v8/include/cppgc/internal/persistent-node.h create mode 100644 deps/v8/include/cppgc/internal/pointer-policies.h create mode 100644 deps/v8/include/cppgc/internal/prefinalizer-handler.h create mode 100644 deps/v8/include/cppgc/liveness-broker.h create mode 100644 deps/v8/include/cppgc/macros.h create mode 100644 deps/v8/include/cppgc/member.h create mode 100644 deps/v8/include/cppgc/persistent.h create mode 100644 deps/v8/include/cppgc/prefinalizer.h create mode 100644 deps/v8/include/cppgc/source-location.h create mode 100644 deps/v8/include/cppgc/trace-trait.h create mode 100644 deps/v8/include/cppgc/type-traits.h create mode 100644 deps/v8/include/cppgc/visitor.h delete mode 100644 deps/v8/src/builtins/builtins-promise.cc create mode 100644 deps/v8/src/builtins/builtins-wasm-gen.h create mode 100644 deps/v8/src/builtins/finalization-registry.tq create mode 100644 deps/v8/src/builtins/ic-callable.tq create mode 100644 deps/v8/src/builtins/ic.tq create mode 100644 deps/v8/src/builtins/promise-any.tq create mode 100644 deps/v8/src/builtins/wasm.tq rename deps/v8/src/{snapshot/serializer-common.cc => codegen/external-reference-encoder.cc} (53%) create mode 100644 deps/v8/src/codegen/external-reference-encoder.h create mode 100644 deps/v8/src/common/external-pointer-inl.h create mode 100644 deps/v8/src/common/external-pointer.h create mode 100644 deps/v8/src/debug/wasm/gdb-server/OWNERS create mode 100644 deps/v8/src/debug/wasm/gdb-server/gdb-remote-util.cc create mode 100644 deps/v8/src/debug/wasm/gdb-server/gdb-remote-util.h create mode 100644 deps/v8/src/debug/wasm/gdb-server/packet.cc create mode 100644 deps/v8/src/debug/wasm/gdb-server/packet.h delete mode 100644 deps/v8/src/debug/wasm/gdb-server/util.h create mode 100644 deps/v8/src/debug/wasm/gdb-server/wasm-module-debug.cc create mode 100644 deps/v8/src/debug/wasm/gdb-server/wasm-module-debug.h create mode 100644 deps/v8/src/execution/off-thread-isolate-inl.h create mode 100644 deps/v8/src/handles/persistent-handles.cc create mode 100644 deps/v8/src/handles/persistent-handles.h create mode 100644 deps/v8/src/heap/concurrent-allocator-inl.h create mode 100644 deps/v8/src/heap/concurrent-allocator.cc create mode 100644 deps/v8/src/heap/concurrent-allocator.h create mode 100644 deps/v8/src/heap/cppgc/asm/arm/push_registers_asm.cc create mode 100644 deps/v8/src/heap/cppgc/asm/arm64/push_registers_asm.cc create mode 100644 deps/v8/src/heap/cppgc/asm/arm64/push_registers_masm.S create mode 100644 deps/v8/src/heap/cppgc/asm/ia32/push_registers_asm.cc create mode 100644 deps/v8/src/heap/cppgc/asm/ia32/push_registers_masm.S create mode 100644 deps/v8/src/heap/cppgc/asm/mips/push_registers_asm.cc create mode 100644 deps/v8/src/heap/cppgc/asm/mips64/push_registers_asm.cc create mode 100644 deps/v8/src/heap/cppgc/asm/ppc/push_registers_asm.cc create mode 100644 deps/v8/src/heap/cppgc/asm/s390/push_registers_asm.cc delete mode 100644 deps/v8/src/heap/cppgc/asm/x64/push_registers.S create mode 100644 deps/v8/src/heap/cppgc/asm/x64/push_registers_asm.cc rename deps/v8/src/heap/cppgc/asm/x64/{push_registers_win.S => push_registers_masm.S} (100%) create mode 100644 deps/v8/src/heap/cppgc/free-list.cc create mode 100644 deps/v8/src/heap/cppgc/free-list.h create mode 100644 deps/v8/src/heap/cppgc/heap-page.cc create mode 100644 deps/v8/src/heap/cppgc/heap-page.h create mode 100644 deps/v8/src/heap/cppgc/heap-space.cc create mode 100644 deps/v8/src/heap/cppgc/heap-space.h create mode 100644 deps/v8/src/heap/cppgc/heap-visitor.h create mode 100644 deps/v8/src/heap/cppgc/liveness-broker.cc create mode 100644 deps/v8/src/heap/cppgc/logging.cc create mode 100644 deps/v8/src/heap/cppgc/marker.cc create mode 100644 deps/v8/src/heap/cppgc/marker.h create mode 100644 deps/v8/src/heap/cppgc/marking-visitor.cc create mode 100644 deps/v8/src/heap/cppgc/marking-visitor.h create mode 100644 deps/v8/src/heap/cppgc/object-allocator-inl.h create mode 100644 deps/v8/src/heap/cppgc/object-allocator.cc create mode 100644 deps/v8/src/heap/cppgc/object-allocator.h create mode 100644 deps/v8/src/heap/cppgc/object-start-bitmap-inl.h create mode 100644 deps/v8/src/heap/cppgc/object-start-bitmap.h create mode 100644 deps/v8/src/heap/cppgc/page-memory-inl.h create mode 100644 deps/v8/src/heap/cppgc/page-memory.cc create mode 100644 deps/v8/src/heap/cppgc/page-memory.h create mode 100644 deps/v8/src/heap/cppgc/persistent-node.cc create mode 100644 deps/v8/src/heap/cppgc/pointer-policies.cc create mode 100644 deps/v8/src/heap/cppgc/prefinalizer-handler.cc create mode 100644 deps/v8/src/heap/cppgc/prefinalizer-handler.h create mode 100644 deps/v8/src/heap/cppgc/raw-heap.cc create mode 100644 deps/v8/src/heap/cppgc/raw-heap.h create mode 100644 deps/v8/src/heap/cppgc/source-location.cc create mode 100644 deps/v8/src/heap/cppgc/sweeper.cc create mode 100644 deps/v8/src/heap/cppgc/sweeper.h create mode 100644 deps/v8/src/heap/cppgc/visitor.h create mode 100644 deps/v8/src/heap/cppgc/worklist.h create mode 100644 deps/v8/src/heap/large-spaces.cc create mode 100644 deps/v8/src/heap/large-spaces.h rename deps/v8/src/{base => heap}/list.h (83%) create mode 100644 deps/v8/src/heap/memory-chunk-inl.h create mode 100644 deps/v8/src/heap/memory-chunk.cc create mode 100644 deps/v8/src/heap/memory-chunk.h create mode 100644 deps/v8/src/heap/off-thread-heap.cc create mode 100644 deps/v8/src/heap/off-thread-heap.h create mode 100644 deps/v8/src/heap/read-only-spaces.cc create mode 100644 deps/v8/src/heap/read-only-spaces.h rename deps/v8/src/heap/{remembered-set.h => remembered-set-inl.h} (87%) create mode 100644 deps/v8/src/heap/third-party/heap-api-stub.cc create mode 100644 deps/v8/src/libplatform/default-job.cc create mode 100644 deps/v8/src/libplatform/default-job.h delete mode 100644 deps/v8/src/libplatform/tracing/json-trace-event-listener.cc delete mode 100644 deps/v8/src/libplatform/tracing/json-trace-event-listener.h create mode 100644 deps/v8/src/objects/class-definitions-tq-deps-inl.h create mode 100644 deps/v8/src/objects/js-aggregate-error-inl.h create mode 100644 deps/v8/src/objects/js-aggregate-error.h create mode 100644 deps/v8/src/objects/js-aggregate-error.tq create mode 100644 deps/v8/src/runtime/runtime-weak-refs.cc rename deps/v8/src/snapshot/{partial-deserializer.cc => context-deserializer.cc} (81%) rename deps/v8/src/snapshot/{partial-deserializer.h => context-deserializer.h} (77%) rename deps/v8/src/snapshot/{partial-serializer.cc => context-serializer.cc} (63%) rename deps/v8/src/snapshot/{partial-serializer.h => context-serializer.h} (68%) create mode 100644 deps/v8/src/snapshot/serializer-deserializer.cc rename deps/v8/src/snapshot/{serializer-common.h => serializer-deserializer.h} (61%) create mode 100644 deps/v8/src/snapshot/snapshot-data.cc create mode 100644 deps/v8/src/snapshot/snapshot-data.h create mode 100644 deps/v8/src/snapshot/snapshot-utils.cc create mode 100644 deps/v8/src/snapshot/snapshot-utils.h rename deps/v8/src/snapshot/{snapshot-common.cc => snapshot.cc} (52%) create mode 100644 deps/v8/src/tracing/DEPS create mode 100644 deps/v8/src/tracing/trace-categories.cc create mode 100644 deps/v8/src/tracing/trace-categories.h create mode 100644 deps/v8/src/wasm/struct-types.h create mode 100644 deps/v8/test/cctest/heap/test-concurrent-allocation.cc create mode 100644 deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateClassFieldAccess.golden create mode 100644 deps/v8/test/cctest/test-api-icu.cc create mode 100644 deps/v8/test/cctest/test-persistent-handles.cc create mode 100644 deps/v8/test/cctest/wasm/test-gc.cc create mode 100644 deps/v8/test/cctest/wasm/test-run-wasm-simd-scalar-lowering.cc delete mode 100644 deps/v8/test/cctest/wasm/test-wasm-interpreter-entry.cc create mode 100644 deps/v8/test/debugger/debug/es6/debug-promises/promise-any-caught.js create mode 100644 deps/v8/test/debugger/debug/es6/debug-promises/promise-any-uncaught.js create mode 100644 deps/v8/test/debugger/debug/regress/regress-10319.js create mode 100644 deps/v8/test/debugging/wasm/gdb-server/OWNERS create mode 100644 deps/v8/test/debugging/wasm/gdb-server/breakpoints.py create mode 100644 deps/v8/test/debugging/wasm/gdb-server/float.py create mode 100644 deps/v8/test/debugging/wasm/gdb-server/memory.py create mode 100644 deps/v8/test/debugging/wasm/gdb-server/status.py create mode 100644 deps/v8/test/debugging/wasm/gdb-server/stepping.py create mode 100644 deps/v8/test/debugging/wasm/gdb-server/test_files/__init__.py delete mode 100644 deps/v8/test/debugging/wasm/gdb-server/test_files/test.js create mode 100644 deps/v8/test/debugging/wasm/gdb-server/test_files/test_basic.js create mode 100644 deps/v8/test/debugging/wasm/gdb-server/test_files/test_basic.py create mode 100644 deps/v8/test/debugging/wasm/gdb-server/test_files/test_float.js create mode 100644 deps/v8/test/debugging/wasm/gdb-server/test_files/test_float.py create mode 100644 deps/v8/test/debugging/wasm/gdb-server/test_files/test_memory.js create mode 100644 deps/v8/test/debugging/wasm/gdb-server/test_files/test_memory.py create mode 100644 deps/v8/test/debugging/wasm/gdb-server/test_files/test_trap.js create mode 100644 deps/v8/test/debugging/wasm/gdb-server/test_files/test_trap.py create mode 100644 deps/v8/test/debugging/wasm/gdb-server/trap.py create mode 100644 deps/v8/test/inspector/debugger/wasm-breakpoint-reset-on-debugger-restart-expected.txt create mode 100644 deps/v8/test/inspector/debugger/wasm-breakpoint-reset-on-debugger-restart.js create mode 100644 deps/v8/test/inspector/debugger/wasm-debug-evaluate-expected.txt create mode 100644 deps/v8/test/inspector/debugger/wasm-debug-evaluate.js create mode 100644 deps/v8/test/inspector/debugger/wasm-memory-names-expected.txt create mode 100644 deps/v8/test/inspector/debugger/wasm-memory-names.js create mode 100644 deps/v8/test/inspector/debugger/wasm-step-after-trap-expected.txt create mode 100644 deps/v8/test/inspector/debugger/wasm-step-after-trap.js create mode 100644 deps/v8/test/inspector/runtime/regress-1075763-expected.txt create mode 100644 deps/v8/test/inspector/runtime/regress-1075763.js create mode 100644 deps/v8/test/inspector/runtime/regress-1078205-expected.txt create mode 100644 deps/v8/test/inspector/runtime/regress-1078205.js create mode 100644 deps/v8/test/inspector/runtime/regress-986051-expected.txt create mode 100644 deps/v8/test/inspector/runtime/regress-986051.js create mode 100644 deps/v8/test/intl/regress-10437.js create mode 100644 deps/v8/test/intl/regress-10438.js create mode 100644 deps/v8/test/intl/regress-1074578.js create mode 100644 deps/v8/test/intl/regress-364374.js create mode 100644 deps/v8/test/js-perf-test/Operators/abstract-equality.js create mode 100644 deps/v8/test/js-perf-test/Operators/run.js create mode 100644 deps/v8/test/message/fail/spread-call-4.js create mode 100644 deps/v8/test/message/fail/spread-call-4.out delete mode 100644 deps/v8/test/message/wasm-trace-memory-interpreted.js delete mode 100644 deps/v8/test/message/wasm-trace-memory-interpreted.out create mode 100644 deps/v8/test/mjsunit/compiler/monomorphic-named-load-with-no-map.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-1065737.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-1067544.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-1068494.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-1070892.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-1071743.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-1074736.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-1082704.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-1084820.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-1092650.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-1094132.js create mode 100644 deps/v8/test/mjsunit/const-field-tracking-2.js create mode 100644 deps/v8/test/mjsunit/es6/promise-all-resolve-not-callable.js create mode 100644 deps/v8/test/mjsunit/es6/promise-allsettled-resolve-not-callable.js create mode 100644 deps/v8/test/mjsunit/es6/promise-race-resolve-not-callable.js delete mode 100644 deps/v8/test/mjsunit/es6/regress/regress-411237.js create mode 100644 deps/v8/test/mjsunit/es6/typedarray-from-optional-arguments.js create mode 100644 deps/v8/test/mjsunit/harmony/aggregate-error.js create mode 100644 deps/v8/test/mjsunit/harmony/logical-assignment.js create mode 100644 deps/v8/test/mjsunit/harmony/promise-any-overflow-1.js create mode 100644 deps/v8/test/mjsunit/harmony/promise-any-overflow-2.js create mode 100644 deps/v8/test/mjsunit/harmony/promise-any-resolve-not-callable.js create mode 100644 deps/v8/test/mjsunit/harmony/promise-any.js create mode 100644 deps/v8/test/mjsunit/harmony/weakrefs/basics-cleanupsome.js delete mode 100644 deps/v8/test/mjsunit/harmony/weakrefs/cleanup-doesnt-iterate-all-holdings.js rename deps/v8/test/mjsunit/harmony/weakrefs/{iterating-in-cleanup.js => cleanup.js} (78%) create mode 100644 deps/v8/test/mjsunit/harmony/weakrefs/cleanupsome-optional.js create mode 100644 deps/v8/test/mjsunit/harmony/weakrefs/clearkeptobjects-on-quit.js create mode 100644 deps/v8/test/mjsunit/harmony/weakrefs/stress-finalizationregistry-dirty-enqueue.js rename deps/v8/test/mjsunit/harmony/weakrefs/{unregister-inside-cleanup5.js => unregister-inside-cleanup.js} (65%) delete mode 100644 deps/v8/test/mjsunit/harmony/weakrefs/unregister-inside-cleanup1.js delete mode 100644 deps/v8/test/mjsunit/harmony/weakrefs/unregister-inside-cleanup4.js rename deps/v8/test/mjsunit/{class-of-builtins.js => object-tostring-builtins.js} (95%) create mode 100644 deps/v8/test/mjsunit/regress-crbug-1078825.js create mode 100644 deps/v8/test/mjsunit/regress/regress-10508.js create mode 100644 deps/v8/test/mjsunit/regress/regress-1069964.js create mode 100644 deps/v8/test/mjsunit/regress/regress-1071190.js create mode 100644 deps/v8/test/mjsunit/regress/regress-1076569.js create mode 100644 deps/v8/test/mjsunit/regress/regress-1077804.js create mode 100644 deps/v8/test/mjsunit/regress/regress-1078913.js delete mode 100644 deps/v8/test/mjsunit/regress/regress-491481.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1053939-1.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1055138-1.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1055138-2.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1055138-3.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1060023.js rename deps/v8/test/mjsunit/regress/{regress-347542.js => regress-crbug-1063796.js} (51%) create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1065741.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1067757.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1070560.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1074737.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1077508.js create mode 100644 deps/v8/test/mjsunit/regress/regress-v8-10484-1.js create mode 100644 deps/v8/test/mjsunit/regress/regress-v8-10484-2.js create mode 100644 deps/v8/test/mjsunit/regress/regress-v8-10513.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1055692.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1065599.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1065635.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1065852.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1067621.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1070078.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1073553.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1074586-b.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1074586.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1075953.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1079449.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-1081030.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-7049.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-715216a.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-715216b.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-719175.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-766003.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-771243.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-772332.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-778917.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-831463.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-834624.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-crbug-1007608.js create mode 100644 deps/v8/test/mjsunit/serialize-deserialize-now.js delete mode 100644 deps/v8/test/mjsunit/wasm/anyfunc-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/anyref-globals-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/anyref-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/compilation-hints-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/exceptions-anyref-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/exceptions-global-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/exceptions-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/exceptions-rethrow-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/exceptions-simd-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/futex-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/indirect-call-non-zero-table-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/interpreter-mixed.js delete mode 100644 deps/v8/test/mjsunit/wasm/interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/multi-value-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/nullref-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/table-access-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/table-fill-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/table-grow-from-wasm-interpreter.js delete mode 100644 deps/v8/test/mjsunit/wasm/worker-interpreter.js create mode 100644 deps/v8/test/test262/harness-ishtmldda.js delete mode 100644 deps/v8/test/unittests/heap/cppgc/allocation_unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/custom-spaces-unittest.cc rename deps/v8/test/unittests/heap/cppgc/{finalizer-trait_unittest.cc => finalizer-trait-unittest.cc} (98%) create mode 100644 deps/v8/test/unittests/heap/cppgc/free-list-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/garbage-collected-unittest.cc delete mode 100644 deps/v8/test/unittests/heap/cppgc/garbage-collected_unittest.cc rename deps/v8/test/unittests/heap/cppgc/{gc-info_unittest.cc => gc-info-unittest.cc} (99%) rename deps/v8/test/unittests/heap/cppgc/{heap-object-header_unittest.cc => heap-object-header-unittest.cc} (100%) create mode 100644 deps/v8/test/unittests/heap/cppgc/heap-page-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/heap-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/logging-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/marker-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/marking-visitor-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/member-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/object-start-bitmap-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/page-memory-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/persistent-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/prefinalizer-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/source-location-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/stack-unittest.cc delete mode 100644 deps/v8/test/unittests/heap/cppgc/stack_unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/sweeper-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/visitor-unittest.cc create mode 100644 deps/v8/test/unittests/heap/cppgc/worklist-unittest.cc rename deps/v8/test/unittests/{base => heap}/list-unittest.cc (90%) create mode 100644 deps/v8/test/unittests/libplatform/default-job-unittest.cc create mode 100644 deps/v8/test/unittests/wasm/wasm-gdbserver-unittest.cc delete mode 100644 deps/v8/test/unittests/wasm/wasm-opcodes-unittest.cc delete mode 100644 deps/v8/testing/gmock/include/gmock/gmock-generated-function-mockers.h create mode 100644 deps/v8/third_party/jsoncpp/BUILD.gn create mode 100644 deps/v8/third_party/jsoncpp/LICENSE create mode 100644 deps/v8/third_party/jsoncpp/README.chromium create mode 100644 deps/v8/third_party/jsoncpp/generated/version.h create mode 100644 deps/v8/third_party/zlib/DEPS create mode 100644 deps/v8/third_party/zlib/patches/0005-infcover-gtest.patch delete mode 100644 deps/v8/tools/testrunner/local/junit_output.py create mode 100644 deps/v8/tools/testrunner/testproc/util.py create mode 100644 deps/v8/tools/testrunner/testproc/util_unittest.py diff --git a/deps/v8/.gitignore b/deps/v8/.gitignore index 1afbd765d3e6c2..6d2cf1077a522a 100644 --- a/deps/v8/.gitignore +++ b/deps/v8/.gitignore @@ -61,6 +61,8 @@ !/third_party/antlr4 !/third_party/binutils !/third_party/inspector_protocol +!/third_party/jsoncpp +/third_party/jsoncpp/source !/third_party/colorama /third_party/colorama/src !/third_party/googletest diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index 7036ecd42bc461..47a83c5ff1c905 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -43,6 +43,7 @@ Julia Computing, Inc. <*@juliacomputing.com> Aaron Bieber Abdulla Kamar +Adam Kallai Akinori MUSHA Alessandro Pignotti Alex Kodat @@ -112,6 +113,7 @@ James Pike James M Snell Jianghua Yang Jiawen Geng +Jiaxun Yang Joel Stanley Johan Bergström Jonathan Liu @@ -211,3 +213,4 @@ Zhao Jiazhong Zhongping Wang 柳荣一 Yanbo Li +Gilang Mentari Hamidy \ No newline at end of file diff --git a/deps/v8/BUILD.gn b/deps/v8/BUILD.gn index b2dde3f9d70312..167e63503c5535 100644 --- a/deps/v8/BUILD.gn +++ b/deps/v8/BUILD.gn @@ -218,6 +218,17 @@ declare_args() { # Enable control-flow integrity features, such as pointer authentication for # ARM64. v8_control_flow_integrity = false + + # Enable object names in cppgc for debug purposes. + cppgc_enable_object_names = false + + # Enable V8 heap sandbox experimental feature. + # Sets -DV8_HEAP_SANDBOX. + v8_enable_heap_sandbox = "" + + # Experimental support for native context independent code. + # https://crbug.com/v8/8888 + v8_enable_nci_code = false } # Derived defaults. @@ -254,7 +265,9 @@ if (v8_enable_pointer_compression == "") { if (v8_enable_fast_torque == "") { v8_enable_fast_torque = v8_enable_fast_mksnapshot } - +if (v8_enable_heap_sandbox == "") { + v8_enable_heap_sandbox = false +} if (v8_enable_single_generation == "") { v8_enable_single_generation = v8_disable_write_barriers } @@ -284,6 +297,9 @@ assert( !v8_enable_pointer_compression || !v8_enable_shared_ro_heap, "Pointer compression is not supported with shared read-only heap enabled") +assert(!v8_enable_heap_sandbox || v8_enable_pointer_compression, + "V8 Heap Sandbox requires pointer compression") + v8_random_seed = "314159265" v8_toolset_for_shell = "host" @@ -294,8 +310,11 @@ v8_toolset_for_shell = "host" config("internal_config_base") { visibility = [ ":*" ] # Only targets in this file can depend on this. + configs = [ ":v8_tracing_config" ] + include_dirs = [ ".", + "include", "$target_gen_dir", ] } @@ -308,7 +327,6 @@ config("internal_config") { "//build/config/compiler:wexit_time_destructors", ":internal_config_base", ":v8_header_features", - ":v8_tracing_config", ] if (is_component_build) { @@ -346,6 +364,14 @@ config("libbase_config") { } } +# This config should be applied to code using the cppgc_base. +config("cppgc_base_config") { + defines = [] + if (cppgc_enable_object_names) { + defines += [ "CPPGC_SUPPORTS_OBJECT_NAMES" ] + } +} + # This config should be applied to code using the libsampler. config("libsampler_config") { include_dirs = [ "include" ] @@ -389,6 +415,9 @@ config("v8_header_features") { if (v8_enable_pointer_compression || v8_enable_31bit_smis_on_64bit_arch) { defines += [ "V8_31BIT_SMIS_ON_64BIT_ARCH" ] } + if (v8_enable_heap_sandbox) { + defines += [ "V8_HEAP_SANDBOX" ] + } if (v8_deprecation_warnings) { defines += [ "V8_DEPRECATION_WARNINGS" ] } @@ -428,10 +457,6 @@ config("features") { } if (v8_enable_lite_mode) { defines += [ "V8_LITE_MODE" ] - - # TODO(v8:7777): Remove the define once the --jitless runtime flag does - # everything we need. - defines += [ "V8_JITLESS_MODE" ] } if (v8_enable_gdbjit) { defines += [ "ENABLE_GDB_JIT_INTERFACE" ] @@ -501,10 +526,6 @@ config("features") { if (v8_check_microtasks_scopes_consistency) { defines += [ "V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY" ] } - - # TODO(v8:8519): Remove the define once all use-sites in - # the code are removed/fixed - defines += [ "V8_EMBEDDED_BUILTINS" ] if (v8_use_multi_snapshots) { defines += [ "V8_MULTI_SNAPSHOTS" ] } @@ -532,6 +553,9 @@ config("features") { if (v8_enable_wasm_gdb_remote_debugging) { defines += [ "V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING" ] } + if (v8_enable_nci_code) { + defines += [ "V8_ENABLE_NCI_CODE" ] + } } config("toolchain") { @@ -630,7 +654,9 @@ config("toolchain") { if (v8_can_use_fpu_instructions) { defines += [ "CAN_USE_FPU_INSTRUCTIONS" ] } - + if (mips_use_msa) { + defines += [ "_MIPS_MSA" ] + } if (host_byteorder == "little") { defines += [ "V8_TARGET_ARCH_MIPS64_LE" ] } else if (host_byteorder == "big") { @@ -646,9 +672,6 @@ config("toolchain") { } if (mips_arch_variant == "r6") { defines += [ "_MIPS_ARCH_MIPS64R6" ] - if (mips_use_msa) { - defines += [ "_MIPS_MSA" ] - } } else if (mips_arch_variant == "r2") { defines += [ "_MIPS_ARCH_MIPS64R2" ] } @@ -1012,9 +1035,12 @@ torque_files = [ "src/builtins/convert.tq", "src/builtins/console.tq", "src/builtins/data-view.tq", + "src/builtins/finalization-registry.tq", "src/builtins/frames.tq", "src/builtins/frame-arguments.tq", "src/builtins/growable-fixed-array.tq", + "src/builtins/ic-callable.tq", + "src/builtins/ic.tq", "src/builtins/internal-coverage.tq", "src/builtins/iterator.tq", "src/builtins/math.tq", @@ -1024,6 +1050,7 @@ torque_files = [ "src/builtins/promise-abstract-operations.tq", "src/builtins/promise-all.tq", "src/builtins/promise-all-element-closure.tq", + "src/builtins/promise-any.tq", "src/builtins/promise-constructor.tq", "src/builtins/promise-finally.tq", "src/builtins/promise-misc.tq", @@ -1082,6 +1109,7 @@ torque_files = [ "src/builtins/typed-array-sort.tq", "src/builtins/typed-array-subarray.tq", "src/builtins/typed-array.tq", + "src/builtins/wasm.tq", "src/ic/handler-configuration.tq", "src/objects/allocation-site.tq", "src/objects/api-callbacks.tq", @@ -1101,6 +1129,7 @@ torque_files = [ "src/objects/heap-number.tq", "src/objects/heap-object.tq", "src/objects/intl-objects.tq", + "src/objects/js-aggregate-error.tq", "src/objects/js-array-buffer.tq", "src/objects/js-array.tq", "src/objects/js-collection-iterator.tq", @@ -1184,7 +1213,7 @@ template("run_torque") { "class-verifiers-tq.h", "enum-verifiers-tq.cc", "objects-printer-tq.cc", - "objects-body-descriptors-tq-inl.h", + "objects-body-descriptors-tq-inl.inc", "class-definitions-tq.cc", "class-definitions-tq-inl.h", "class-definitions-tq.h", @@ -1196,6 +1225,8 @@ template("run_torque") { "instance-types-tq.h", "internal-class-definitions-tq.h", "internal-class-definitions-tq-inl.h", + "exported-class-definitions-tq.h", + "exported-class-definitions-tq-inl.h", ] outputs = [] @@ -1270,6 +1301,7 @@ v8_source_set("torque_generated_initializers") { deps = [ ":generate_bytecode_builtins_list", ":run_torque", + ":v8_tracing", ] public_deps = [ ":v8_maybe_icu" ] @@ -1298,6 +1330,7 @@ v8_source_set("torque_generated_definitions") { deps = [ ":generate_bytecode_builtins_list", ":run_torque", + ":v8_tracing", ] public_deps = [ ":v8_maybe_icu" ] @@ -1573,7 +1606,10 @@ v8_source_set("v8_initializers") { "test/cctest:*", ] - deps = [ ":torque_generated_initializers" ] + deps = [ + ":torque_generated_initializers", + ":v8_tracing", + ] sources = [ ### gcmole(all) ### @@ -1624,6 +1660,7 @@ v8_source_set("v8_initializers") { "src/builtins/builtins-typed-array-gen.h", "src/builtins/builtins-utils-gen.h", "src/builtins/builtins-wasm-gen.cc", + "src/builtins/builtins-wasm-gen.h", "src/builtins/growable-fixed-array-gen.cc", "src/builtins/growable-fixed-array-gen.h", "src/builtins/setup-builtins-internal.cc", @@ -1701,7 +1738,10 @@ v8_source_set("v8_initializers") { v8_source_set("v8_init") { visibility = [ ":*" ] # Only targets in this file can depend on this. - deps = [ ":v8_initializers" ] + deps = [ + ":v8_initializers", + ":v8_tracing", + ] sources = [ ### gcmole(all) ### @@ -2005,6 +2045,7 @@ v8_source_set("v8_compiler_opt") { ":generate_bytecode_builtins_list", ":run_torque", ":v8_maybe_icu", + ":v8_tracing", ] if (is_debug && !v8_optimized_debug && v8_enable_fast_mksnapshot) { @@ -2029,6 +2070,7 @@ v8_source_set("v8_compiler") { ":generate_bytecode_builtins_list", ":run_torque", ":v8_maybe_icu", + ":v8_tracing", ] configs = [ ":internal_config" ] @@ -2042,6 +2084,18 @@ group("v8_compiler_for_mksnapshot") { } } +# Any target using trace events must directly or indirectly depend on +# v8_tracing. +group("v8_tracing") { + if (v8_use_perfetto) { + if (build_with_chromium) { + public_deps = [ "//third_party/perfetto:libperfetto" ] + } else { + public_deps = [ ":v8_libperfetto" ] + } + } +} + v8_source_set("v8_base_without_compiler") { visibility = [ ":*" ] # Only targets in this file can depend on this. @@ -2053,6 +2107,7 @@ v8_source_set("v8_base_without_compiler") { ### gcmole(all) ### "$target_gen_dir/builtins-generated/bytecodes-builtins-list.h", + "include/cppgc/common.h", "include/v8-fast-api-calls.h", "include/v8-inspector-protocol.h", "include/v8-inspector.h", @@ -2121,7 +2176,6 @@ v8_source_set("v8_base_without_compiler") { "src/builtins/builtins-json.cc", "src/builtins/builtins-number.cc", "src/builtins/builtins-object.cc", - "src/builtins/builtins-promise.cc", "src/builtins/builtins-promise.h", "src/builtins/builtins-reflect.cc", "src/builtins/builtins-regexp.cc", @@ -2160,6 +2214,8 @@ v8_source_set("v8_base_without_compiler") { "src/codegen/constant-pool.h", "src/codegen/constants-arch.h", "src/codegen/cpu-features.h", + "src/codegen/external-reference-encoder.cc", + "src/codegen/external-reference-encoder.h", "src/codegen/external-reference-table.cc", "src/codegen/external-reference-table.h", "src/codegen/external-reference.cc", @@ -2207,6 +2263,8 @@ v8_source_set("v8_base_without_compiler") { "src/common/assert-scope.cc", "src/common/assert-scope.h", "src/common/checks.h", + "src/common/external-pointer-inl.h", + "src/common/external-pointer.h", "src/common/message-template.h", "src/common/ptr-compr-inl.h", "src/common/ptr-compr.h", @@ -2284,6 +2342,7 @@ v8_source_set("v8_base_without_compiler") { "src/execution/messages.h", "src/execution/microtask-queue.cc", "src/execution/microtask-queue.h", + "src/execution/off-thread-isolate-inl.h", "src/execution/off-thread-isolate.cc", "src/execution/off-thread-isolate.h", "src/execution/pointer-authentication.h", @@ -2330,6 +2389,8 @@ v8_source_set("v8_base_without_compiler") { "src/handles/local-handles.h", "src/handles/maybe-handles-inl.h", "src/handles/maybe-handles.h", + "src/handles/persistent-handles.cc", + "src/handles/persistent-handles.h", "src/heap/array-buffer-collector.cc", "src/heap/array-buffer-collector.h", "src/heap/array-buffer-sweeper.cc", @@ -2344,6 +2405,9 @@ v8_source_set("v8_base_without_compiler") { "src/heap/code-stats.h", "src/heap/combined-heap.cc", "src/heap/combined-heap.h", + "src/heap/concurrent-allocator-inl.h", + "src/heap/concurrent-allocator.cc", + "src/heap/concurrent-allocator.h", "src/heap/concurrent-marking.cc", "src/heap/concurrent-marking.h", "src/heap/embedder-tracing.cc", @@ -2376,6 +2440,9 @@ v8_source_set("v8_base_without_compiler") { "src/heap/invalidated-slots.h", "src/heap/item-parallel-job.cc", "src/heap/item-parallel-job.h", + "src/heap/large-spaces.cc", + "src/heap/large-spaces.h", + "src/heap/list.h", "src/heap/local-allocator-inl.h", "src/heap/local-allocator.h", "src/heap/local-heap.cc", @@ -2389,6 +2456,9 @@ v8_source_set("v8_base_without_compiler") { "src/heap/marking-worklist.h", "src/heap/marking.cc", "src/heap/marking.h", + "src/heap/memory-chunk-inl.h", + "src/heap/memory-chunk.cc", + "src/heap/memory-chunk.h", "src/heap/memory-measurement-inl.h", "src/heap/memory-measurement.cc", "src/heap/memory-measurement.h", @@ -2401,9 +2471,13 @@ v8_source_set("v8_base_without_compiler") { "src/heap/objects-visiting.h", "src/heap/off-thread-factory.cc", "src/heap/off-thread-factory.h", + "src/heap/off-thread-heap.cc", + "src/heap/off-thread-heap.h", "src/heap/read-only-heap-inl.h", "src/heap/read-only-heap.cc", "src/heap/read-only-heap.h", + "src/heap/read-only-spaces.cc", + "src/heap/read-only-spaces.h", "src/heap/remembered-set.h", "src/heap/safepoint.cc", "src/heap/safepoint.h", @@ -2598,6 +2672,8 @@ v8_source_set("v8_base_without_compiler") { "src/objects/internal-index.h", "src/objects/intl-objects.cc", "src/objects/intl-objects.h", + "src/objects/js-aggregate-error-inl.h", + "src/objects/js-aggregate-error.h", "src/objects/js-array-buffer-inl.h", "src/objects/js-array-buffer.cc", "src/objects/js-array-buffer.h", @@ -2888,6 +2964,7 @@ v8_source_set("v8_base_without_compiler") { "src/runtime/runtime-typedarray.cc", "src/runtime/runtime-utils.h", "src/runtime/runtime-wasm.cc", + "src/runtime/runtime-weak-refs.cc", "src/runtime/runtime.cc", "src/runtime/runtime.h", "src/sanitizer/asan.h", @@ -2897,6 +2974,10 @@ v8_source_set("v8_base_without_compiler") { "src/sanitizer/tsan.h", "src/snapshot/code-serializer.cc", "src/snapshot/code-serializer.h", + "src/snapshot/context-deserializer.cc", + "src/snapshot/context-deserializer.h", + "src/snapshot/context-serializer.cc", + "src/snapshot/context-serializer.h", "src/snapshot/deserializer-allocator.cc", "src/snapshot/deserializer-allocator.h", "src/snapshot/deserializer.cc", @@ -2905,10 +2986,6 @@ v8_source_set("v8_base_without_compiler") { "src/snapshot/embedded/embedded-data.h", "src/snapshot/object-deserializer.cc", "src/snapshot/object-deserializer.h", - "src/snapshot/partial-deserializer.cc", - "src/snapshot/partial-deserializer.h", - "src/snapshot/partial-serializer.cc", - "src/snapshot/partial-serializer.h", "src/snapshot/read-only-deserializer.cc", "src/snapshot/read-only-deserializer.h", "src/snapshot/read-only-serializer.cc", @@ -2918,15 +2995,19 @@ v8_source_set("v8_base_without_compiler") { "src/snapshot/roots-serializer.h", "src/snapshot/serializer-allocator.cc", "src/snapshot/serializer-allocator.h", - "src/snapshot/serializer-common.cc", - "src/snapshot/serializer-common.h", + "src/snapshot/serializer-deserializer.cc", + "src/snapshot/serializer-deserializer.h", "src/snapshot/serializer.cc", "src/snapshot/serializer.h", - "src/snapshot/snapshot-common.cc", "src/snapshot/snapshot-compression.cc", "src/snapshot/snapshot-compression.h", + "src/snapshot/snapshot-data.cc", + "src/snapshot/snapshot-data.h", "src/snapshot/snapshot-source-sink.cc", "src/snapshot/snapshot-source-sink.h", + "src/snapshot/snapshot-utils.cc", + "src/snapshot/snapshot-utils.h", + "src/snapshot/snapshot.cc", "src/snapshot/snapshot.h", "src/snapshot/startup-deserializer.cc", "src/snapshot/startup-deserializer.h", @@ -3026,6 +3107,7 @@ v8_source_set("v8_base_without_compiler") { "src/wasm/signature-map.h", "src/wasm/streaming-decoder.cc", "src/wasm/streaming-decoder.h", + "src/wasm/struct-types.h", "src/wasm/value-type.h", "src/wasm/wasm-arguments.h", "src/wasm/wasm-code-manager.cc", @@ -3085,21 +3167,28 @@ v8_source_set("v8_base_without_compiler") { if (v8_enable_third_party_heap) { sources += v8_third_party_heap_files + } else { + sources += [ "src/heap/third-party/heap-api-stub.cc" ] } if (v8_enable_wasm_gdb_remote_debugging) { sources += [ + "src/debug/wasm/gdb-server/gdb-remote-util.cc", + "src/debug/wasm/gdb-server/gdb-remote-util.h", "src/debug/wasm/gdb-server/gdb-server-thread.cc", "src/debug/wasm/gdb-server/gdb-server-thread.h", "src/debug/wasm/gdb-server/gdb-server.cc", "src/debug/wasm/gdb-server/gdb-server.h", + "src/debug/wasm/gdb-server/packet.cc", + "src/debug/wasm/gdb-server/packet.h", "src/debug/wasm/gdb-server/session.cc", "src/debug/wasm/gdb-server/session.h", "src/debug/wasm/gdb-server/target.cc", "src/debug/wasm/gdb-server/target.h", "src/debug/wasm/gdb-server/transport.cc", "src/debug/wasm/gdb-server/transport.h", - "src/debug/wasm/gdb-server/util.h", + "src/debug/wasm/gdb-server/wasm-module-debug.cc", + "src/debug/wasm/gdb-server/wasm-module-debug.h", ] } @@ -3420,6 +3509,7 @@ v8_source_set("v8_base_without_compiler") { ":v8_libbase", ":v8_libsampler", ":v8_shared_internal_headers", + ":v8_tracing", ":v8_version", "src/inspector:inspector", ] @@ -3511,6 +3601,14 @@ v8_source_set("v8_base_without_compiler") { ] deps += [ "src/third_party/vtune:v8_vtune_trace_mark" ] } + + if (v8_use_perfetto) { + sources -= [ "//base/trace_event/common/trace_event_common.h" ] + sources += [ + "src/tracing/trace-categories.cc", + "src/tracing/trace-categories.h", + ] + } } group("v8_base") { @@ -3672,7 +3770,6 @@ v8_component("v8_libbase") { "src/base/ieee754.h", "src/base/iterator.h", "src/base/lazy-instance.h", - "src/base/list.h", "src/base/logging.cc", "src/base/logging.h", "src/base/lsan.h", @@ -3843,6 +3940,8 @@ v8_component("v8_libplatform") { "include/libplatform/v8-tracing.h", "src/libplatform/default-foreground-task-runner.cc", "src/libplatform/default-foreground-task-runner.h", + "src/libplatform/default-job.cc", + "src/libplatform/default-job.h", "src/libplatform/default-platform.cc", "src/libplatform/default-platform.h", "src/libplatform/default-worker-threads-task-runner.cc", @@ -3873,20 +3972,25 @@ v8_component("v8_libplatform") { deps = [ ":v8_headers", ":v8_libbase", + ":v8_tracing", ] + if (v8_use_perfetto) { + sources -= [ + "//base/trace_event/common/trace_event_common.h", + "src/libplatform/tracing/trace-buffer.cc", + "src/libplatform/tracing/trace-buffer.h", + "src/libplatform/tracing/trace-object.cc", + "src/libplatform/tracing/trace-writer.cc", + "src/libplatform/tracing/trace-writer.h", + ] sources += [ - "src/libplatform/tracing/json-trace-event-listener.cc", - "src/libplatform/tracing/json-trace-event-listener.h", "src/libplatform/tracing/trace-event-listener.cc", "src/libplatform/tracing/trace-event-listener.h", ] deps += [ + # TODO(skyostil): Switch TraceEventListener to protozero. "//third_party/perfetto/protos/perfetto/trace:lite", - "//third_party/perfetto/protos/perfetto/trace/chrome:minimal_complete_lite", - "//third_party/perfetto/protos/perfetto/trace/chrome:zero", - "//third_party/perfetto/src/tracing:client_api", - "//third_party/perfetto/src/tracing:platform_posix", ] } } @@ -3914,9 +4018,8 @@ v8_source_set("fuzzer_support") { configs = [ ":internal_config_base" ] - deps = [ ":v8" ] - public_deps = [ + ":v8", ":v8_libbase", ":v8_libplatform", ":v8_maybe_icu", @@ -3928,14 +4031,33 @@ v8_source_set("cppgc_base") { sources = [ "include/cppgc/allocation.h", - "include/cppgc/api-constants.h", - "include/cppgc/finalizer-trait.h", + "include/cppgc/common.h", + "include/cppgc/custom-space.h", "include/cppgc/garbage-collected.h", - "include/cppgc/gc-info.h", "include/cppgc/heap.h", + "include/cppgc/internal/accessors.h", + "include/cppgc/internal/api-contants.h", + "include/cppgc/internal/compiler-specific.h", + "include/cppgc/internal/finalizer-traits.h", + "include/cppgc/internal/gc-info.h", + "include/cppgc/internal/persistent-node.h", + "include/cppgc/internal/pointer-policies.h", + "include/cppgc/internal/prefinalizer-handler.h", + "include/cppgc/liveness-broker.h", + "include/cppgc/liveness-broker.h", + "include/cppgc/macros.h", + "include/cppgc/member.h", + "include/cppgc/persistent.h", "include/cppgc/platform.h", + "include/cppgc/prefinalizer.h", + "include/cppgc/source-location.h", + "include/cppgc/trace-trait.h", + "include/cppgc/type-traits.h", + "include/cppgc/visitor.h", "include/v8config.h", "src/heap/cppgc/allocation.cc", + "src/heap/cppgc/free-list.cc", + "src/heap/cppgc/free-list.h", "src/heap/cppgc/gc-info-table.cc", "src/heap/cppgc/gc-info-table.h", "src/heap/cppgc/gc-info.cc", @@ -3943,23 +4065,75 @@ v8_source_set("cppgc_base") { "src/heap/cppgc/heap-object-header-inl.h", "src/heap/cppgc/heap-object-header.cc", "src/heap/cppgc/heap-object-header.h", + "src/heap/cppgc/heap-page.cc", + "src/heap/cppgc/heap-page.h", + "src/heap/cppgc/heap-space.cc", + "src/heap/cppgc/heap-space.h", + "src/heap/cppgc/heap-visitor.h", "src/heap/cppgc/heap.cc", "src/heap/cppgc/heap.h", + "src/heap/cppgc/liveness-broker.cc", + "src/heap/cppgc/logging.cc", + "src/heap/cppgc/marker.cc", + "src/heap/cppgc/marker.h", + "src/heap/cppgc/marking-visitor.cc", + "src/heap/cppgc/marking-visitor.h", + "src/heap/cppgc/object-allocator-inl.h", + "src/heap/cppgc/object-allocator.cc", + "src/heap/cppgc/object-allocator.h", + "src/heap/cppgc/object-start-bitmap-inl.h", + "src/heap/cppgc/object-start-bitmap.h", + "src/heap/cppgc/page-memory-inl.h", + "src/heap/cppgc/page-memory.cc", + "src/heap/cppgc/page-memory.h", + "src/heap/cppgc/persistent-node.cc", "src/heap/cppgc/platform.cc", + "src/heap/cppgc/pointer-policies.cc", + "src/heap/cppgc/prefinalizer-handler.cc", + "src/heap/cppgc/prefinalizer-handler.h", + "src/heap/cppgc/raw-heap.cc", + "src/heap/cppgc/raw-heap.h", "src/heap/cppgc/sanitizers.h", + "src/heap/cppgc/source-location.cc", "src/heap/cppgc/stack.cc", "src/heap/cppgc/stack.h", + "src/heap/cppgc/sweeper.cc", + "src/heap/cppgc/sweeper.h", + "src/heap/cppgc/worklist.h", ] - if (target_cpu == "x64") { - if (is_win) { - sources += [ "src/heap/cppgc/asm/x64/push_registers_win.S" ] - } else { - sources += [ "src/heap/cppgc/asm/x64/push_registers.S" ] + if (is_clang || !is_win) { + if (target_cpu == "x64") { + sources += [ "src/heap/cppgc/asm/x64/push_registers_asm.cc" ] + } else if (target_cpu == "x86") { + sources += [ "src/heap/cppgc/asm/ia32/push_registers_asm.cc" ] + } else if (target_cpu == "arm") { + sources += [ "src/heap/cppgc/asm/arm/push_registers_asm.cc" ] + } else if (target_cpu == "arm64") { + sources += [ "src/heap/cppgc/asm/arm64/push_registers_asm.cc" ] + } else if (target_cpu == "ppc64") { + sources += [ "src/heap/cppgc/asm/ppc/push_registers_asm.cc" ] + } else if (target_cpu == "s390x") { + sources += [ "src/heap/cppgc/asm/s390/push_registers_asm.cc" ] + } else if (target_cpu == "mipsel") { + sources += [ "src/heap/cppgc/asm/mips/push_registers_asm.cc" ] + } else if (target_cpu == "mips64el") { + sources += [ "src/heap/cppgc/asm/mips64/push_registers_asm.cc" ] + } + } else if (is_win) { + if (target_cpu == "x64") { + sources += [ "src/heap/cppgc/asm/x64/push_registers_masm.S" ] + } else if (target_cpu == "x86") { + sources += [ "src/heap/cppgc/asm/ia32/push_registers_masm.S" ] + } else if (target_cpu == "arm64") { + sources += [ "src/heap/cppgc/asm/arm64/push_registers_masm.S" ] } } - configs = [ ":internal_config" ] + configs = [ + ":internal_config", + ":cppgc_base_config", + ] public_deps = [ ":v8_libbase" ] } @@ -4010,12 +4184,6 @@ v8_static_library("wee8") { ] } -v8_static_library("cppgc") { - deps = [ ":cppgc_base" ] - - configs = [ ":internal_config" ] -} - ############################################################################### # Executables # @@ -4074,6 +4242,7 @@ if (current_toolchain == v8_snapshot_toolchain) { ":v8_libbase", ":v8_libplatform", ":v8_maybe_icu", + ":v8_tracing", "//build/win:default_exe_manifest", ] } @@ -4308,6 +4477,14 @@ if (is_component_build) { public_configs = [ ":external_config" ] } + v8_component("cppgc") { + public_deps = [ ":cppgc_base" ] + + configs = [ ":internal_config" ] + + public_configs = [ ":external_config" ] + } + v8_component("cppgc_for_testing") { testonly = true @@ -4340,6 +4517,12 @@ if (is_component_build) { public_configs = [ ":external_config" ] } + group("cppgc") { + public_deps = [ ":cppgc_base" ] + + public_configs = [ ":external_config" ] + } + group("cppgc_for_testing") { testonly = true @@ -4374,6 +4557,7 @@ v8_executable("d8") { ":v8", ":v8_libbase", ":v8_libplatform", + ":v8_tracing", "//build/win:default_exe_manifest", ] @@ -4392,10 +4576,6 @@ v8_executable("d8") { if (v8_enable_vtunejit) { deps += [ "src/third_party/vtune:v8_vtune" ] } - - if (v8_use_perfetto) { - deps += [ "//third_party/perfetto/src/tracing:in_process_backend" ] - } } v8_executable("v8_hello_world") { @@ -4551,6 +4731,7 @@ v8_source_set("wasm_module_runner") { deps = [ ":generate_bytecode_builtins_list", ":run_torque", + ":v8_tracing", ] public_deps = [ ":v8_maybe_icu" ] @@ -4627,6 +4808,7 @@ v8_source_set("lib_wasm_fuzzer_common") { deps = [ ":generate_bytecode_builtins_list", ":run_torque", + ":v8_tracing", ] public_deps = [ ":v8_maybe_icu" ] @@ -4709,7 +4891,7 @@ if (!build_with_chromium && v8_use_perfetto) { "-Wno-tautological-constant-compare", ] } - if (is_win) { + if (is_win && is_clang) { cflags += [ "-Wno-microsoft-unqualified-friend" ] } } @@ -4868,4 +5050,21 @@ if (!build_with_chromium && v8_use_perfetto) { configs += [ "//build/config/compiler:no_chromium_code" ] } } # host_toolchain + + v8_component("v8_libperfetto") { + configs = [ ":v8_tracing_config" ] + public_configs = [ "//third_party/perfetto/gn:public_config" ] + deps = [ + "//third_party/perfetto/src/trace_processor:export_json", + "//third_party/perfetto/src/trace_processor:storage_minimal", + "//third_party/perfetto/src/tracing:client_api", + "//third_party/perfetto/src/tracing/core", + + # TODO(skyostil): Support non-POSIX platforms. + "//third_party/perfetto/protos/perfetto/config:cpp", + "//third_party/perfetto/protos/perfetto/trace/track_event:zero", + "//third_party/perfetto/src/tracing:in_process_backend", + "//third_party/perfetto/src/tracing:platform_posix", + ] + } } # if (!build_with_chromium && v8_use_perfetto) diff --git a/deps/v8/COMMON_OWNERS b/deps/v8/COMMON_OWNERS index 1eee48173a1576..1319a579173c3c 100644 --- a/deps/v8/COMMON_OWNERS +++ b/deps/v8/COMMON_OWNERS @@ -2,6 +2,7 @@ adamk@chromium.org ahaas@chromium.org bbudge@chromium.org binji@chromium.org +bikineev@chromium.org bmeurer@chromium.org cbruni@chromium.org clemensb@chromium.org @@ -25,6 +26,7 @@ mslekova@chromium.org mvstanton@chromium.org mythria@chromium.org neis@chromium.org +omerkatz@chromium.org petermarshall@chromium.org rmcilroy@chromium.org sigurds@chromium.org diff --git a/deps/v8/DEPS b/deps/v8/DEPS index 1bc687beaf6ead..7b38c3dcd07b17 100644 --- a/deps/v8/DEPS +++ b/deps/v8/DEPS @@ -34,7 +34,7 @@ vars = { 'gn_version': 'git_revision:5ed3c9cc67b090d5e311e4bd2aba072173e82db9', # luci-go CIPD package version. - 'luci_go': 'git_revision:de73cf6c4bde86f0a9c8d54151b69b0154a398f1', + 'luci_go': 'git_revision:56ae79476e3caf14da59d75118408aa778637936', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_build-tools_version @@ -55,7 +55,7 @@ vars = { # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_platform-tools_version # and whatever else without interference from each other. - 'android_sdk_platform-tools_version': 'Jxtur3_L9RzY4q79K-AwIahwFW4oi5uYVD5URx9h62wC', + 'android_sdk_platform-tools_version': 'zMVtBEihXp2Z0NYFNjLLmNrwy6252b_YWG6sh2l0QAcC', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_platforms_version # and whatever else without interference from each other. @@ -67,20 +67,20 @@ vars = { # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_tools-lint_version # and whatever else without interference from each other. - 'android_sdk_tools-lint_version': '89hXqZYzCum3delB5RV7J_QyWkaRodqdtQS0s3LMh3wC', + 'android_sdk_cmdline-tools_version': 'CR25ixsRhwuRnhdgDpGFyl9S0C_0HO9SUgFrwX46zq8C', } deps = { 'v8/build': - Var('chromium_url') + '/chromium/src/build.git' + '@' + '26e9d485d01d6e0eb9dadd21df767a63494c8fea', + Var('chromium_url') + '/chromium/src/build.git' + '@' + '1b904cc30093c25d5fd48389bd58e3f7409bcf80', 'v8/third_party/depot_tools': - Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + '2b2aec6506a810f8d7bd018609de2c2450b3c121', + Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + '454f4ba4b3a69feb03c73f93d789062033433b4c', 'v8/third_party/icu': - Var('chromium_url') + '/chromium/deps/icu.git' + '@' + 'd7aff76cf6bb0fbef3afa6c07718f78a80a70f8f', + Var('chromium_url') + '/chromium/deps/icu.git' + '@' + 'f2223961702f00a8833874b0560d615a2cc42738', 'v8/third_party/instrumented_libraries': Var('chromium_url') + '/chromium/src/third_party/instrumented_libraries.git' + '@' + 'bb3f1802c237dd19105dd0f7919f99e536a39d10', 'v8/buildtools': - Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '7977eb176752aeec29d888cfe8e677ac12ed1c41', + Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '204a35a2a64f7179f8b76d7a0385653690839e21', 'v8/buildtools/clang_format/script': Var('chromium_url') + '/chromium/llvm-project/cfe/tools/clang-format.git' + '@' + '96636aa0e9f047f17447f2d45a094d0b59ed7917', 'v8/buildtools/linux64': { @@ -108,7 +108,7 @@ deps = { 'v8/buildtools/third_party/libc++abi/trunk': Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxxabi.git' + '@' + '196ba1aaa8ac285d94f4ea8d9836390a45360533', 'v8/buildtools/third_party/libunwind/trunk': - Var('chromium_url') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + '43bb9f872232f531bac80093ceb4de61c64b9ab7', + Var('chromium_url') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + 'd999d54f4bca789543a2eb6c995af2d9b5a1f3ed', 'v8/buildtools/win': { 'packages': [ { @@ -126,7 +126,7 @@ deps = { 'condition': 'checkout_android', }, 'v8/third_party/android_platform': { - 'url': Var('chromium_url') + '/chromium/src/third_party/android_platform.git' + '@' + '2244b5ea295f8fda3179bef160c84ef8fa0ec9fc', + 'url': Var('chromium_url') + '/chromium/src/third_party/android_platform.git' + '@' + '716366f5685ad8aaf1208c64941e440e8e117441', 'condition': 'checkout_android', }, 'v8/third_party/android_sdk/public': { @@ -160,15 +160,15 @@ deps = { 'version': Var('android_sdk_sources_version'), }, { - 'package': 'chromium/third_party/android_sdk/public/tools-lint', - 'version': Var('android_sdk_tools-lint_version'), + 'package': 'chromium/third_party/android_sdk/public/cmdline-tools', + 'version': Var('android_sdk_cmdline-tools_version'), }, ], 'condition': 'checkout_android', 'dep_type': 'cipd', }, 'v8/third_party/catapult': { - 'url': Var('chromium_url') + '/catapult.git' + '@' + '032c78376792ef343ea361bca2181ba6dec6b95f', + 'url': Var('chromium_url') + '/catapult.git' + '@' + 'e9a8d378c950ee44beec5dd5207e151f48e5b5be', 'condition': 'checkout_android', }, 'v8/third_party/colorama/src': { @@ -176,23 +176,23 @@ deps = { 'condition': 'checkout_android', }, 'v8/third_party/fuchsia-sdk': { - 'url': Var('chromium_url') + '/chromium/src/third_party/fuchsia-sdk.git' + '@' + '2457e41d8dc379f74662d3157e76339ba92cee06', + 'url': Var('chromium_url') + '/chromium/src/third_party/fuchsia-sdk.git' + '@' + '277fe9120cce5f7a42d43554646fa447f88a1598', 'condition': 'checkout_fuchsia', }, 'v8/third_party/googletest/src': - Var('chromium_url') + '/external/github.com/google/googletest.git' + '@' + '10b1902d893ea8cc43c69541d70868f91af3646b', + Var('chromium_url') + '/external/github.com/google/googletest.git' + '@' + 'a09ea700d32bab83325aff9ff34d0582e50e3997', 'v8/third_party/jinja2': - Var('chromium_url') + '/chromium/src/third_party/jinja2.git' + '@' + 'b41863e42637544c2941b574c7877d3e1f663e25', + Var('chromium_url') + '/chromium/src/third_party/jinja2.git' + '@' + '3f90fa05c85718505e28c9c3426c1ba52843b9b7', 'v8/third_party/markupsafe': Var('chromium_url') + '/chromium/src/third_party/markupsafe.git' + '@' + '8f45f5cfa0009d2a70589bcda0349b8cb2b72783', 'v8/tools/swarming_client': - Var('chromium_url') + '/infra/luci/client-py.git' + '@' + 'cc958279ffd6853e0a1b227a7e957ca334fe56af', + Var('chromium_url') + '/infra/luci/client-py.git' + '@' + '160b445a44e0daacf6f3f8570ca2707ec451f374', 'v8/test/benchmarks/data': Var('chromium_url') + '/v8/deps/third_party/benchmarks.git' + '@' + '05d7188267b4560491ff9155c5ee13e207ecd65f', 'v8/test/mozilla/data': Var('chromium_url') + '/v8/deps/third_party/mozilla-tests.git' + '@' + 'f6c578a10ea707b1a8ab0b88943fe5115ce2b9be', 'v8/test/test262/data': - Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + 'f6b2ccdd091ff82da54150796297c3a96d7edb41', + Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + 'd2f7d4285c4a5267f5be37a9c823a397daadad1b', 'v8/test/test262/harness': Var('chromium_url') + '/external/github.com/test262-utils/test262-harness-py.git' + '@' + '4555345a943d0c99a9461182705543fb171dda4b', 'v8/third_party/qemu-linux-x64': { @@ -219,7 +219,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/third_party/aemu/linux-amd64', - 'version': '7YlCgase5GlIanqHn-nZClSlZ5kQETJyVUYRF7Jjy6UC' + 'version': '5LzaFiFYMxwWXcgus5JjF74yr90M5oz9IMo29pTdoLgC' }, ], 'condition': 'host_os == "linux" and checkout_fuchsia', @@ -236,7 +236,7 @@ deps = { 'dep_type': 'cipd', }, 'v8/tools/clang': - Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + '105a8460911176861a422738eee4daad8dfe88a2', + Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + 'de3e20662b84f0ee361a5ae11c99a9513df7c8e8', 'v8/tools/luci-go': { 'packages': [ { @@ -266,11 +266,13 @@ deps = { 'dep_type': 'cipd', }, 'v8/third_party/perfetto': - Var('android_url') + '/platform/external/perfetto.git' + '@' + 'b9b24d1b0b80aafec393af085067e9eae829412f', + Var('android_url') + '/platform/external/perfetto.git' + '@' + 'ff70e0d273ed10995866c803f23e11250eb3dc52', 'v8/third_party/protobuf': Var('chromium_url') + '/external/github.com/google/protobuf'+ '@' + 'b68a347f56137b4b1a746e8c7438495a6ac1bd91', 'v8/third_party/zlib': - Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + '156be8c52f80cde343088b4a69a80579101b6e67', + Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + '90fc47e6eed7bd1a59ad1603761303ef24705593', + 'v8/third_party/jsoncpp/source': + Var('chromium_url') + '/external/github.com/open-source-parsers/jsoncpp.git'+ '@' + '645250b6690785be60ab6780ce4b58698d884d11', 'v8/third_party/ittapi': { # Force checkout ittapi libraries to pass v8 header includes check on # bots that has check_v8_header_includes enabled. diff --git a/deps/v8/INTL_OWNERS b/deps/v8/INTL_OWNERS index dbe6f3b7b54292..6e9f2cedb98c4d 100644 --- a/deps/v8/INTL_OWNERS +++ b/deps/v8/INTL_OWNERS @@ -1,3 +1,4 @@ cira@chromium.org mnita@google.com jshin@chromium.org +ftang@chromium.org diff --git a/deps/v8/WATCHLISTS b/deps/v8/WATCHLISTS index 47470f49e42308..54d6bbec1c51ff 100644 --- a/deps/v8/WATCHLISTS +++ b/deps/v8/WATCHLISTS @@ -33,10 +33,6 @@ { 'WATCHLIST_DEFINITIONS': { - 'api': { - 'filepath': 'include/' \ - '|src/api\.(cc|h)$', - }, 'snapshot': { 'filepath': 'src/snapshot/', }, @@ -94,9 +90,6 @@ }, 'WATCHLISTS': { - 'api': [ - 'yangguo+watch@chromium.org', - ], 'csa': [ 'jgruber+watch@chromium.org', ], diff --git a/deps/v8/build_overrides/build.gni b/deps/v8/build_overrides/build.gni index 5b99eb94022596..dde92c46eaa78d 100644 --- a/deps/v8/build_overrides/build.gni +++ b/deps/v8/build_overrides/build.gni @@ -16,6 +16,14 @@ perfetto_build_with_embedder = true perfetto_protobuf_target_prefix = "//" perfetto_protobuf_gni = "//gni/proto_library.gni" +# We use Perfetto's Trace Processor to convert traces to the legacy JSON +# format. +enable_perfetto_trace_processor = true + +# When building with chromium, determines whether we want to also use the +# perfetto library from chromium instead declaring our own. +use_perfetto_client_library = false + # Uncomment these to specify a different NDK location and version in # non-Chromium builds. # default_android_ndk_root = "//third_party/android_ndk" diff --git a/deps/v8/gni/v8.gni b/deps/v8/gni/v8.gni index 0b2806ca949b77..9d286ebbfc0226 100644 --- a/deps/v8/gni/v8.gni +++ b/deps/v8/gni/v8.gni @@ -54,8 +54,7 @@ declare_args() { # Expose symbols for dynamic linking. v8_expose_symbols = false - # Use Perfetto (https://perfetto.dev) as the default TracingController. Not - # currently implemented. + # Implement tracing using Perfetto (https://perfetto.dev). v8_use_perfetto = false # Override global symbol level setting for v8 @@ -82,6 +81,12 @@ if (v8_enable_backtrace == "") { v8_enable_backtrace = is_debug && !v8_optimized_debug } +# If chromium is configured to use the perfetto client library, v8 should also +# use perfetto for tracing. +if (build_with_chromium && use_perfetto_client_library) { + v8_use_perfetto = true +} + # Points to // in v8 stand-alone or to //v8/ in chromium. We need absolute # paths for all configs in templates as they are shared in different # subdirectories. diff --git a/deps/v8/include/DEPS b/deps/v8/include/DEPS index ca60f841f530ab..7305ff51125503 100644 --- a/deps/v8/include/DEPS +++ b/deps/v8/include/DEPS @@ -1,4 +1,5 @@ include_rules = [ # v8-inspector-protocol.h depends on generated files under include/inspector. "+inspector", + "+cppgc/common.h", ] diff --git a/deps/v8/include/cppgc/DEPS b/deps/v8/include/cppgc/DEPS new file mode 100644 index 00000000000000..04c343de27c329 --- /dev/null +++ b/deps/v8/include/cppgc/DEPS @@ -0,0 +1,7 @@ +include_rules = [ + "-include", + "+v8config.h", + "+v8-platform.h", + "+cppgc", + "-src", +] diff --git a/deps/v8/include/cppgc/allocation.h b/deps/v8/include/cppgc/allocation.h index 3e717ad7d428f8..49ad49c34d6bc9 100644 --- a/deps/v8/include/cppgc/allocation.h +++ b/deps/v8/include/cppgc/allocation.h @@ -6,12 +6,14 @@ #define INCLUDE_CPPGC_ALLOCATION_H_ #include + #include -#include "include/cppgc/garbage-collected.h" -#include "include/cppgc/gc-info.h" -#include "include/cppgc/heap.h" -#include "include/cppgc/internals.h" +#include "cppgc/custom-space.h" +#include "cppgc/garbage-collected.h" +#include "cppgc/heap.h" +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/gc-info.h" namespace cppgc { @@ -35,36 +37,80 @@ class V8_EXPORT MakeGarbageCollectedTraitInternal { } static void* Allocate(cppgc::Heap* heap, size_t size, GCInfoIndex index); + static void* Allocate(cppgc::Heap* heapx, size_t size, GCInfoIndex index, + CustomSpaceIndex space_inde); friend class HeapObjectHeader; }; } // namespace internal -// Users with custom allocation needs (e.g. overriding size) should override -// MakeGarbageCollectedTrait (see below) and inherit their trait from -// MakeGarbageCollectedTraitBase to get access to low-level primitives. +/** + * Base trait that provides utilities for advancers users that have custom + * allocation needs (e.g., overriding size). It's expected that users override + * MakeGarbageCollectedTrait (see below) and inherit from + * MakeGarbageCollectedTraitBase and make use of the low-level primitives + * offered to allocate and construct an object. + */ template class MakeGarbageCollectedTraitBase : private internal::MakeGarbageCollectedTraitInternal { + private: + template + struct SpacePolicy { + static void* Allocate(Heap* heap, size_t size) { + // Custom space. + static_assert(std::is_base_of::value, + "Custom space must inherit from CustomSpaceBase."); + return internal::MakeGarbageCollectedTraitInternal::Allocate( + heap, size, internal::GCInfoTrait::Index(), + CustomSpace::kSpaceIndex); + } + }; + + template + struct SpacePolicy { + static void* Allocate(Heap* heap, size_t size) { + // Default space. + return internal::MakeGarbageCollectedTraitInternal::Allocate( + heap, size, internal::GCInfoTrait::Index()); + } + }; + protected: - // Allocates an object of |size| bytes on |heap|. - // - // TODO(mlippautz): Allow specifying arena for specific embedder uses. + /** + * Allocates memory for an object of type T. + * + * \param heap The heap to allocate this object on. + * \param size The size that should be reserved for the object. + * \returns the memory to construct an object of type T on. + */ static void* Allocate(Heap* heap, size_t size) { - return internal::MakeGarbageCollectedTraitInternal::Allocate( - heap, size, internal::GCInfoTrait::Index()); + return SpacePolicy::Space>::Allocate(heap, size); } - // Marks an object as being fully constructed, resulting in precise handling - // by the garbage collector. + /** + * Marks an object as fully constructed, resulting in precise handling by the + * garbage collector. + * + * \param payload The base pointer the object is allocated at. + */ static void MarkObjectAsFullyConstructed(const void* payload) { - // internal::MarkObjectAsFullyConstructed(payload); internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed( payload); } }; +/** + * Default trait class that specifies how to construct an object of type T. + * Advanced users may override how an object is constructed using the utilities + * that are provided through MakeGarbageCollectedTraitBase. + * + * Any trait overriding construction must + * - allocate through MakeGarbageCollectedTraitBase::Allocate; + * - mark the object as fully constructed using + * MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed; + */ template class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase { public: @@ -72,6 +118,10 @@ class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase { static T* Call(Heap* heap, Args&&... args) { static_assert(internal::IsGarbageCollectedType::value, "T needs to be a garbage collected object"); + static_assert( + !internal::IsGarbageCollectedMixinType::value || + sizeof(T) <= internal::api_constants::kLargeObjectSizeThreshold, + "GarbageCollectedMixin may not be a large object"); void* memory = MakeGarbageCollectedTraitBase::Allocate(heap, sizeof(T)); T* object = ::new (memory) T(std::forward(args)...); MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed(object); @@ -79,11 +129,31 @@ class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase { } }; -// Default MakeGarbageCollected: Constructs an instance of T, which is a garbage -// collected type. +/** + * Allows users to specify a post-construction callback for specific types. The + * callback is invoked on the instance of type T right after it has been + * constructed. This can be useful when the callback requires a + * fully-constructed object to be able to dispatch to virtual methods. + */ +template +struct PostConstructionCallbackTrait { + static void Call(T*) {} +}; + +/** + * Constructs a managed object of type T where T transitively inherits from + * GarbageCollected. + * + * \param args List of arguments with which an instance of T will be + * constructed. + * \returns an instance of type T. + */ template T* MakeGarbageCollected(Heap* heap, Args&&... args) { - return MakeGarbageCollectedTrait::Call(heap, std::forward(args)...); + T* object = + MakeGarbageCollectedTrait::Call(heap, std::forward(args)...); + PostConstructionCallbackTrait::Call(object); + return object; } } // namespace cppgc diff --git a/deps/v8/include/cppgc/common.h b/deps/v8/include/cppgc/common.h new file mode 100644 index 00000000000000..228b9abb74e763 --- /dev/null +++ b/deps/v8/include/cppgc/common.h @@ -0,0 +1,26 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_COMMON_H_ +#define INCLUDE_CPPGC_COMMON_H_ + +// TODO(chromium:1056170): Remove dependency on v8. +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +// Indicator for the stack state of the embedder. +enum class EmbedderStackState { + kMayContainHeapPointers, + kNoHeapPointers, + kUnknown V8_ENUM_DEPRECATE_SOON("Use kMayContainHeapPointers") = + kMayContainHeapPointers, + kNonEmpty V8_ENUM_DEPRECATE_SOON("Use kMayContainHeapPointers") = + kMayContainHeapPointers, + kEmpty V8_ENUM_DEPRECATE_SOON("Use kNoHeapPointers") = kNoHeapPointers, +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_COMMON_H_ diff --git a/deps/v8/include/cppgc/custom-space.h b/deps/v8/include/cppgc/custom-space.h new file mode 100644 index 00000000000000..2597a5bdef7a41 --- /dev/null +++ b/deps/v8/include/cppgc/custom-space.h @@ -0,0 +1,62 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_CUSTOM_SPACE_H_ +#define INCLUDE_CPPGC_CUSTOM_SPACE_H_ + +#include + +namespace cppgc { + +struct CustomSpaceIndex { + CustomSpaceIndex(size_t value) : value(value) {} // NOLINT + size_t value; +}; + +/** + * Top-level base class for custom spaces. Users must inherit from CustomSpace + * below. + */ +class CustomSpaceBase { + public: + virtual ~CustomSpaceBase() = default; + virtual CustomSpaceIndex GetCustomSpaceIndex() const = 0; +}; + +/** + * Base class custom spaces should directly inherit from. The class inheriting + * from CustomSpace must define kSpaceIndex as unique space index. These + * indices need for form a sequence starting at 0. + * + * Example: + * \code + * class CustomSpace1 : public CustomSpace { + * public: + * static constexpr CustomSpaceIndex kSpaceIndex = 0; + * }; + * class CustomSpace2 : public CustomSpace { + * public: + * static constexpr CustomSpaceIndex kSpaceIndex = 1; + * }; + * \endcode + */ +template +class CustomSpace : public CustomSpaceBase { + public: + CustomSpaceIndex GetCustomSpaceIndex() const final { + return ConcreteCustomSpace::kSpaceIndex; + } +}; + +/** + * User-overridable trait that allows pinning types to custom spaces. + */ +template +struct SpaceTrait { + using Space = void; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_CUSTOM_SPACE_H_ diff --git a/deps/v8/include/cppgc/garbage-collected.h b/deps/v8/include/cppgc/garbage-collected.h index 6c62daafdc5d8d..c263a9fecf0d96 100644 --- a/deps/v8/include/cppgc/garbage-collected.h +++ b/deps/v8/include/cppgc/garbage-collected.h @@ -7,31 +7,20 @@ #include -#include "include/cppgc/internals.h" -#include "include/cppgc/platform.h" +#include "cppgc/internal/api-constants.h" +#include "cppgc/macros.h" +#include "cppgc/platform.h" +#include "cppgc/trace-trait.h" +#include "cppgc/type-traits.h" namespace cppgc { -namespace internal { - -template -struct IsGarbageCollectedType : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; -template -struct IsGarbageCollectedType< - T, void_t::IsGarbageCollectedTypeMarker>> - : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; +class Visitor; -} // namespace internal +namespace internal { -template -class GarbageCollected { +class GarbageCollectedBase { public: - using IsGarbageCollectedTypeMarker = void; - // Must use MakeGarbageCollected. void* operator new(size_t) = delete; void* operator new[](size_t) = delete; @@ -44,10 +33,160 @@ class GarbageCollected { } void operator delete[](void*) = delete; + protected: + GarbageCollectedBase() = default; +}; + +} // namespace internal + +/** + * Base class for managed objects. Only descendent types of GarbageCollected + * can be constructed using MakeGarbageCollected. Must be inherited from as + * left-most base class. + * + * Types inheriting from GarbageCollected must provide a method of + * signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed + * pointers to the visitor and delegates to garbage-collected base classes. + * The method must be virtual if the type is not directly a child of + * GarbageCollected and marked as final. + * + * \code + * // Example using final class. + * class FinalType final : public GarbageCollected { + * public: + * void Trace(cppgc::Visitor* visitor) const { + * // Dispatch using visitor->Trace(...); + * } + * }; + * + * // Example using non-final base class. + * class NonFinalBase : public GarbageCollected { + * public: + * virtual void Trace(cppgc::Visitor*) const {} + * }; + * + * class FinalChild final : public NonFinalBase { + * public: + * void Trace(cppgc::Visitor* visitor) const final { + * // Dispatch using visitor->Trace(...); + * NonFinalBase::Trace(visitor); + * } + * }; + * \endcode + */ +template +class GarbageCollected : public internal::GarbageCollectedBase { + public: + using IsGarbageCollectedTypeMarker = void; + protected: GarbageCollected() = default; }; +/** + * Base class for managed mixin objects. Such objects cannot be constructed + * directly but must be mixed into the inheritance hierarchy of a + * GarbageCollected object. + * + * Types inheriting from GarbageCollectedMixin must override a virtual method + * of signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed + * pointers to the visitor and delegates to base classes. + * + * \code + * class Mixin : public GarbageCollectedMixin { + * public: + * void Trace(cppgc::Visitor* visitor) const override { + * // Dispatch using visitor->Trace(...); + * } + * }; + * \endcode + */ +class GarbageCollectedMixin : public internal::GarbageCollectedBase { + public: + using IsGarbageCollectedMixinTypeMarker = void; + + // Sentinel used to mark not-fully-constructed mixins. + static constexpr void* kNotFullyConstructedObject = nullptr; + + // Provide default implementation that indicate that the vtable is not yet + // set up properly. This is used to to get GCInfo objects for mixins so that + // these objects can be processed later on. + virtual TraceDescriptor GetTraceDescriptor() const { + return {kNotFullyConstructedObject, nullptr}; + } + + /** + * This Trace method must be overriden by objects inheriting from + * GarbageCollectedMixin. + */ + virtual void Trace(cppgc::Visitor*) const {} +}; + +/** + * Macro defines all methods and markers needed for handling mixins. Must be + * used on the type that is inheriting from GarbageCollected *and* + * GarbageCollectedMixin. + * + * \code + * class Mixin : public GarbageCollectedMixin { + * public: + * void Trace(cppgc::Visitor* visitor) const override { + * // Dispatch using visitor->Trace(...); + * } + * }; + * + * class Foo : public GarbageCollected, public Mixin { + * USING_GARBAGE_COLLECTED_MIXIN(); + * public: + * void Trace(cppgc::Visitor* visitor) const override { + * // Dispatch using visitor->Trace(...); + * Mixin::Trace(visitor); + * } + * }; + * \endcode + */ +#define USING_GARBAGE_COLLECTED_MIXIN() \ + public: \ + /* Marker is used by clang to check for proper usages of the macro. */ \ + typedef int HasUsingGarbageCollectedMixinMacro; \ + \ + TraceDescriptor GetTraceDescriptor() const override { \ + static_assert( \ + internal::IsSubclassOfTemplate< \ + std::remove_const_t>, \ + cppgc::GarbageCollected>::value, \ + "Only garbage collected objects can have garbage collected mixins"); \ + return {this, TraceTrait>>::Trace}; \ + } \ + \ + private: \ + friend class internal::__thisIsHereToForceASemicolonAfterThisMacro + +/** + * Merge two or more Mixins into one. + * + * \code + * class A : public GarbageCollectedMixin {}; + * class B : public GarbageCollectedMixin {}; + * class C : public A, public B { + * MERGE_GARBAGE_COLLECTED_MIXINS(); + * public: + * }; + * \endcode + */ +#define MERGE_GARBAGE_COLLECTED_MIXINS() \ + public: \ + /* When using multiple mixins the methods become */ \ + /* ambigous. Providing additional implementations */ \ + /* disambiguate them again. */ \ + TraceDescriptor GetTraceDescriptor() const override { \ + return {kNotFullyConstructedObject, nullptr}; \ + } \ + \ + private: \ + friend class internal::__thisIsHereToForceASemicolonAfterThisMacro + } // namespace cppgc #endif // INCLUDE_CPPGC_GARBAGE_COLLECTED_H_ diff --git a/deps/v8/include/cppgc/heap.h b/deps/v8/include/cppgc/heap.h index a0568d534fbee2..90046c35055e2e 100644 --- a/deps/v8/include/cppgc/heap.h +++ b/deps/v8/include/cppgc/heap.h @@ -6,8 +6,11 @@ #define INCLUDE_CPPGC_HEAP_H_ #include +#include -#include "include/v8config.h" +#include "cppgc/common.h" +#include "cppgc/custom-space.h" +#include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { namespace internal { @@ -16,10 +19,39 @@ class Heap; class V8_EXPORT Heap { public: - static std::unique_ptr Create(); + /** + * Specifies the stack state the embedder is in. + */ + using StackState = EmbedderStackState; + + struct HeapOptions { + static HeapOptions Default() { return {}; } + + /** + * Custom spaces added to heap are required to have indices forming a + * numbered sequence starting at 0, i.e., their kSpaceIndex must correspond + * to the index they reside in the vector. + */ + std::vector> custom_spaces; + }; + + static std::unique_ptr Create(HeapOptions = HeapOptions::Default()); virtual ~Heap() = default; + /** + * Forces garbage collection. + * + * \param source String specifying the source (or caller) triggering a + * forced garbage collection. + * \param reason String specifying the reason for the forced garbage + * collection. + * \param stack_state The embedder stack state, see StackState. + */ + void ForceGarbageCollectionSlow( + const char* source, const char* reason, + StackState stack_state = StackState::kMayContainHeapPointers); + private: Heap() = default; diff --git a/deps/v8/include/cppgc/internal/accessors.h b/deps/v8/include/cppgc/internal/accessors.h new file mode 100644 index 00000000000000..ee0a0042fe07b7 --- /dev/null +++ b/deps/v8/include/cppgc/internal/accessors.h @@ -0,0 +1,26 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_ACCESSORS_H_ +#define INCLUDE_CPPGC_INTERNAL_ACCESSORS_H_ + +#include "cppgc/internal/api-constants.h" + +namespace cppgc { + +class Heap; + +namespace internal { + +inline cppgc::Heap* GetHeapFromPayload(const void* payload) { + return *reinterpret_cast( + ((reinterpret_cast(payload) & api_constants::kPageBaseMask) + + api_constants::kGuardPageSize) + + api_constants::kHeapOffset); +} + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_ACCESSORS_H_ diff --git a/deps/v8/include/cppgc/internals.h b/deps/v8/include/cppgc/internal/api-constants.h similarity index 57% rename from deps/v8/include/cppgc/internals.h rename to deps/v8/include/cppgc/internal/api-constants.h index 1e57779758b6c7..ef910a48571f46 100644 --- a/deps/v8/include/cppgc/internals.h +++ b/deps/v8/include/cppgc/internal/api-constants.h @@ -2,25 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef INCLUDE_CPPGC_INTERNALS_H_ -#define INCLUDE_CPPGC_INTERNALS_H_ +#ifndef INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ +#define INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ #include #include -#include "include/v8config.h" +#include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { namespace internal { -// Pre-C++17 custom implementation of std::void_t. -template -struct make_void { - typedef void type; -}; -template -using void_t = typename make_void::type; - // Embedders should not rely on this code! // Internal constants to avoid exposing internal types on the API surface. @@ -33,9 +25,20 @@ static constexpr size_t kFullyConstructedBitFieldOffsetFromPayload = // Mask for in-construction bit. static constexpr size_t kFullyConstructedBitMask = size_t{1}; +// Page constants used to align pointers to page begin. +static constexpr size_t kPageSize = size_t{1} << 17; +static constexpr size_t kPageAlignment = kPageSize; +static constexpr size_t kPageBaseMask = ~(kPageAlignment - 1); +static constexpr size_t kGuardPageSize = 4096; + +// Offset of the Heap backref. +static constexpr size_t kHeapOffset = 0; + +static constexpr size_t kLargeObjectSizeThreshold = kPageSize / 2; + } // namespace api_constants } // namespace internal } // namespace cppgc -#endif // INCLUDE_CPPGC_INTERNALS_H_ +#endif // INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ diff --git a/deps/v8/include/cppgc/internal/compiler-specific.h b/deps/v8/include/cppgc/internal/compiler-specific.h new file mode 100644 index 00000000000000..e1f5c1d57fb850 --- /dev/null +++ b/deps/v8/include/cppgc/internal/compiler-specific.h @@ -0,0 +1,26 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ +#define INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ + +namespace cppgc { + +#if defined(__has_cpp_attribute) +#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) __has_cpp_attribute(FEATURE) +#else +#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) 0 +#endif + +// [[no_unique_address]] comes in C++20 but supported in clang with -std >= +// c++11. +#if CPPGC_HAS_CPP_ATTRIBUTE(no_unique_address) // NOLINTNEXTLINE +#define CPPGC_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else +#define CPPGC_NO_UNIQUE_ADDRESS +#endif + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ diff --git a/deps/v8/include/cppgc/finalizer-trait.h b/deps/v8/include/cppgc/internal/finalizer-trait.h similarity index 92% rename from deps/v8/include/cppgc/finalizer-trait.h rename to deps/v8/include/cppgc/internal/finalizer-trait.h index 12216ed84ed9f6..a95126591cb72d 100644 --- a/deps/v8/include/cppgc/finalizer-trait.h +++ b/deps/v8/include/cppgc/internal/finalizer-trait.h @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef INCLUDE_CPPGC_FINALIZER_TRAIT_H_ -#define INCLUDE_CPPGC_FINALIZER_TRAIT_H_ +#ifndef INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ +#define INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ #include -#include "include/cppgc/internals.h" +#include "cppgc/type-traits.h" namespace cppgc { namespace internal { @@ -87,4 +87,4 @@ constexpr FinalizationCallback FinalizerTrait::kCallback; } // namespace internal } // namespace cppgc -#endif // INCLUDE_CPPGC_FINALIZER_TRAIT_H_ +#endif // INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ diff --git a/deps/v8/include/cppgc/gc-info.h b/deps/v8/include/cppgc/internal/gc-info.h similarity index 81% rename from deps/v8/include/cppgc/gc-info.h rename to deps/v8/include/cppgc/internal/gc-info.h index 987ba34fa4254c..9aac1361c61afd 100644 --- a/deps/v8/include/cppgc/gc-info.h +++ b/deps/v8/include/cppgc/internal/gc-info.h @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef INCLUDE_CPPGC_GC_INFO_H_ -#define INCLUDE_CPPGC_GC_INFO_H_ +#ifndef INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ +#define INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ #include -#include "include/cppgc/finalizer-trait.h" -#include "include/v8config.h" +#include "cppgc/internal/finalizer-trait.h" +#include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { namespace internal { @@ -40,4 +40,4 @@ struct GCInfoTrait { } // namespace internal } // namespace cppgc -#endif // INCLUDE_CPPGC_GC_INFO_H_ +#endif // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ diff --git a/deps/v8/include/cppgc/internal/logging.h b/deps/v8/include/cppgc/internal/logging.h new file mode 100644 index 00000000000000..79beaef7d4f80d --- /dev/null +++ b/deps/v8/include/cppgc/internal/logging.h @@ -0,0 +1,50 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_LOGGING_H_ +#define INCLUDE_CPPGC_INTERNAL_LOGGING_H_ + +#include "cppgc/source-location.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +void V8_EXPORT DCheckImpl(const char*, + const SourceLocation& = SourceLocation::Current()); +[[noreturn]] void V8_EXPORT +FatalImpl(const char*, const SourceLocation& = SourceLocation::Current()); + +// Used to ignore -Wunused-variable. +template +struct EatParams {}; + +#if DEBUG +#define CPPGC_DCHECK_MSG(condition, message) \ + do { \ + if (V8_UNLIKELY(!(condition))) { \ + ::cppgc::internal::DCheckImpl(message); \ + } \ + } while (false) +#else +#define CPPGC_DCHECK_MSG(condition, message) \ + (static_cast(::cppgc::internal::EatParams(condition), message)>{})) +#endif + +#define CPPGC_DCHECK(condition) CPPGC_DCHECK_MSG(condition, #condition) + +#define CPPGC_CHECK_MSG(condition, message) \ + do { \ + if (V8_UNLIKELY(!(condition))) { \ + ::cppgc::internal::FatalImpl(message); \ + } \ + } while (false) + +#define CPPGC_CHECK(condition) CPPGC_CHECK_MSG(condition, #condition) + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_LOGGING_H_ diff --git a/deps/v8/include/cppgc/internal/persistent-node.h b/deps/v8/include/cppgc/internal/persistent-node.h new file mode 100644 index 00000000000000..11cf69623e8dad --- /dev/null +++ b/deps/v8/include/cppgc/internal/persistent-node.h @@ -0,0 +1,109 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ +#define INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ + +#include +#include +#include + +#include "cppgc/internal/logging.h" +#include "cppgc/trace-trait.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +class Visitor; + +namespace internal { + +// PersistentNode represesents a variant of two states: +// 1) traceable node with a back pointer to the Persistent object; +// 2) freelist entry. +class PersistentNode final { + public: + PersistentNode() = default; + + PersistentNode(const PersistentNode&) = delete; + PersistentNode& operator=(const PersistentNode&) = delete; + + void InitializeAsUsedNode(void* owner, TraceCallback trace) { + owner_ = owner; + trace_ = trace; + } + + void InitializeAsFreeNode(PersistentNode* next) { + next_ = next; + trace_ = nullptr; + } + + void UpdateOwner(void* owner) { + CPPGC_DCHECK(IsUsed()); + owner_ = owner; + } + + PersistentNode* FreeListNext() const { + CPPGC_DCHECK(!IsUsed()); + return next_; + } + + void Trace(Visitor* visitor) const { + CPPGC_DCHECK(IsUsed()); + trace_(visitor, owner_); + } + + bool IsUsed() const { return trace_; } + + private: + // PersistentNode acts as a designated union: + // If trace_ != nullptr, owner_ points to the corresponding Persistent handle. + // Otherwise, next_ points to the next freed PersistentNode. + union { + void* owner_ = nullptr; + PersistentNode* next_; + }; + TraceCallback trace_ = nullptr; +}; + +class V8_EXPORT PersistentRegion { + using PersistentNodeSlots = std::array; + + public: + PersistentRegion() = default; + + PersistentRegion(const PersistentRegion&) = delete; + PersistentRegion& operator=(const PersistentRegion&) = delete; + + PersistentNode* AllocateNode(void* owner, TraceCallback trace) { + if (!free_list_head_) { + EnsureNodeSlots(); + } + PersistentNode* node = free_list_head_; + free_list_head_ = free_list_head_->FreeListNext(); + node->InitializeAsUsedNode(owner, trace); + return node; + } + + void FreeNode(PersistentNode* node) { + node->InitializeAsFreeNode(free_list_head_); + free_list_head_ = node; + } + + void Trace(Visitor*); + + size_t NodesInUse() const; + + private: + void EnsureNodeSlots(); + + std::vector> nodes_; + PersistentNode* free_list_head_ = nullptr; +}; + +} // namespace internal + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ diff --git a/deps/v8/include/cppgc/internal/pointer-policies.h b/deps/v8/include/cppgc/internal/pointer-policies.h new file mode 100644 index 00000000000000..fe8d94b57a68bb --- /dev/null +++ b/deps/v8/include/cppgc/internal/pointer-policies.h @@ -0,0 +1,133 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ +#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ + +#include +#include + +#include "cppgc/source-location.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +class PersistentRegion; + +// Tags to distinguish between strong and weak member types. +class StrongMemberTag; +class WeakMemberTag; +class UntracedMemberTag; + +struct DijkstraWriteBarrierPolicy { + static void InitializingBarrier(const void*, const void*) { + // Since in initializing writes the source object is always white, having no + // barrier doesn't break the tri-color invariant. + } + static void AssigningBarrier(const void*, const void*) { + // TODO(chromium:1056170): Add actual implementation. + } +}; + +struct NoWriteBarrierPolicy { + static void InitializingBarrier(const void*, const void*) {} + static void AssigningBarrier(const void*, const void*) {} +}; + +class V8_EXPORT EnabledCheckingPolicy { + protected: + EnabledCheckingPolicy(); + void CheckPointer(const void* ptr); + + private: + void* impl_; +}; + +class DisabledCheckingPolicy { + protected: + void CheckPointer(const void* raw) {} +}; + +#if V8_ENABLE_CHECKS +using DefaultCheckingPolicy = EnabledCheckingPolicy; +#else +using DefaultCheckingPolicy = DisabledCheckingPolicy; +#endif + +class KeepLocationPolicy { + public: + constexpr const SourceLocation& Location() const { return location_; } + + protected: + constexpr explicit KeepLocationPolicy(const SourceLocation& location) + : location_(location) {} + + // KeepLocationPolicy must not copy underlying source locations. + KeepLocationPolicy(const KeepLocationPolicy&) = delete; + KeepLocationPolicy& operator=(const KeepLocationPolicy&) = delete; + + // Location of the original moved from object should be preserved. + KeepLocationPolicy(KeepLocationPolicy&&) = default; + KeepLocationPolicy& operator=(KeepLocationPolicy&&) = default; + + private: + SourceLocation location_; +}; + +class IgnoreLocationPolicy { + public: + constexpr SourceLocation Location() const { return {}; } + + protected: + constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {} +}; + +#if CPPGC_SUPPORTS_OBJECT_NAMES +using DefaultLocationPolicy = KeepLocationPolicy; +#else +using DefaultLocationPolicy = IgnoreLocationPolicy; +#endif + +struct StrongPersistentPolicy { + using IsStrongPersistent = std::true_type; + + static V8_EXPORT PersistentRegion& GetPersistentRegion(void* object); +}; + +struct WeakPersistentPolicy { + using IsStrongPersistent = std::false_type; + + static V8_EXPORT PersistentRegion& GetPersistentRegion(void* object); +}; + +// Persistent/Member forward declarations. +template +class BasicPersistent; +template +class BasicMember; + +// Special tag type used to denote some sentinel member. The semantics of the +// sentinel is defined by the embedder. +struct SentinelPointer { + template + operator T*() const { // NOLINT + static constexpr intptr_t kSentinelValue = -1; + return reinterpret_cast(kSentinelValue); + } + // Hidden friends. + friend bool operator==(SentinelPointer, SentinelPointer) { return true; } + friend bool operator!=(SentinelPointer, SentinelPointer) { return false; } +}; + +} // namespace internal + +constexpr internal::SentinelPointer kSentinelPointer; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ diff --git a/deps/v8/include/cppgc/internal/prefinalizer-handler.h b/deps/v8/include/cppgc/internal/prefinalizer-handler.h new file mode 100644 index 00000000000000..939a9b8ff0a8fd --- /dev/null +++ b/deps/v8/include/cppgc/internal/prefinalizer-handler.h @@ -0,0 +1,31 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_PREFINALIZER_HANDLER_H_ +#define INCLUDE_CPPGC_INTERNAL_PREFINALIZER_HANDLER_H_ + +#include "cppgc/heap.h" +#include "cppgc/liveness-broker.h" + +namespace cppgc { +namespace internal { + +class V8_EXPORT PreFinalizerRegistrationDispatcher final { + public: + using PreFinalizerCallback = bool (*)(const LivenessBroker&, void*); + struct PreFinalizer { + void* object_; + PreFinalizerCallback callback_; + + bool operator==(const PreFinalizer& other); + }; + + static void RegisterPrefinalizer(cppgc::Heap* heap, + PreFinalizer prefinalzier); +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_PREFINALIZER_HANDLER_H_ diff --git a/deps/v8/include/cppgc/liveness-broker.h b/deps/v8/include/cppgc/liveness-broker.h new file mode 100644 index 00000000000000..69dbc11f1f4a95 --- /dev/null +++ b/deps/v8/include/cppgc/liveness-broker.h @@ -0,0 +1,50 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_LIVENESS_BROKER_H_ +#define INCLUDE_CPPGC_LIVENESS_BROKER_H_ + +#include "cppgc/heap.h" +#include "cppgc/member.h" +#include "cppgc/trace-trait.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +namespace internal { +class LivenessBrokerFactory; +} // namespace internal + +class V8_EXPORT LivenessBroker final { + public: + template + bool IsHeapObjectAlive(const T* object) const { + return object && + IsHeapObjectAliveImpl( + TraceTrait::GetTraceDescriptor(object).base_object_payload); + } + + template + bool IsHeapObjectAlive(const WeakMember& weak_member) const { + return (weak_member != kSentinelPointer) && + IsHeapObjectAlive(weak_member.Get()); + } + + template + bool IsHeapObjectAlive(const UntracedMember& untraced_member) const { + return (untraced_member != kSentinelPointer) && + IsHeapObjectAlive(untraced_member.Get()); + } + + private: + LivenessBroker() = default; + + bool IsHeapObjectAliveImpl(const void*) const; + + friend class internal::LivenessBrokerFactory; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_LIVENESS_BROKER_H_ diff --git a/deps/v8/include/cppgc/macros.h b/deps/v8/include/cppgc/macros.h new file mode 100644 index 00000000000000..7c7a10e433a894 --- /dev/null +++ b/deps/v8/include/cppgc/macros.h @@ -0,0 +1,26 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_MACROS_H_ +#define INCLUDE_CPPGC_MACROS_H_ + +namespace cppgc { + +namespace internal { +class __thisIsHereToForceASemicolonAfterThisMacro {}; +} // namespace internal + +// Use if the object is only stack allocated. +#define CPPGC_STACK_ALLOCATED() \ + public: \ + using IsStackAllocatedTypeMarker = int; \ + \ + private: \ + void* operator new(size_t) = delete; \ + void* operator new(size_t, void*) = delete; \ + friend class internal::__thisIsHereToForceASemicolonAfterThisMacro + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_MACROS_H_ diff --git a/deps/v8/include/cppgc/member.h b/deps/v8/include/cppgc/member.h new file mode 100644 index 00000000000000..a183edb96fd030 --- /dev/null +++ b/deps/v8/include/cppgc/member.h @@ -0,0 +1,206 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_MEMBER_H_ +#define INCLUDE_CPPGC_MEMBER_H_ + +#include +#include +#include + +#include "cppgc/internal/pointer-policies.h" +#include "cppgc/type-traits.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +class Visitor; + +namespace internal { + +// The basic class from which all Member classes are 'generated'. +template +class BasicMember : private CheckingPolicy { + public: + using PointeeType = T; + + constexpr BasicMember() = default; + constexpr BasicMember(std::nullptr_t) {} // NOLINT + BasicMember(SentinelPointer s) : raw_(s) {} // NOLINT + BasicMember(T* raw) : raw_(raw) { // NOLINT + InitializingWriteBarrier(); + this->CheckPointer(raw_); + } + BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT + BasicMember(const BasicMember& other) : BasicMember(other.Get()) {} + // Allow heterogeneous construction. + template ::value>> + BasicMember( // NOLINT + const BasicMember& other) + : BasicMember(other.Get()) {} + // Construction from Persistent. + template ::value>> + BasicMember( // NOLINT + const BasicPersistent& + p) + : BasicMember(p.Get()) {} + + BasicMember& operator=(const BasicMember& other) { + return operator=(other.Get()); + } + // Allow heterogeneous assignment. + template ::value>> + BasicMember& operator=( + const BasicMember& other) { + return operator=(other.Get()); + } + // Assignment from Persistent. + template ::value>> + BasicMember& operator=( + const BasicPersistent& + other) { + return operator=(other.Get()); + } + BasicMember& operator=(T* other) { + SetRawAtomic(other); + AssigningWriteBarrier(); + this->CheckPointer(Get()); + return *this; + } + BasicMember& operator=(std::nullptr_t) { + Clear(); + return *this; + } + BasicMember& operator=(SentinelPointer s) { + SetRawAtomic(s); + return *this; + } + + template + void Swap(BasicMember& other) { + T* tmp = Get(); + *this = other; + other = tmp; + } + + explicit operator bool() const { return Get(); } + operator T*() const { return Get(); } // NOLINT + T* operator->() const { return Get(); } + T& operator*() const { return *Get(); } + + T* Get() const { + // Executed by the mutator, hence non atomic load. + return raw_; + } + + void Clear() { SetRawAtomic(nullptr); } + + T* Release() { + T* result = Get(); + Clear(); + return result; + } + + private: + void SetRawAtomic(T* raw) { + reinterpret_cast*>(&raw_)->store(raw, + std::memory_order_relaxed); + } + T* GetRawAtomic() const { + return reinterpret_cast*>(&raw_)->load( + std::memory_order_relaxed); + } + + void InitializingWriteBarrier() const { + WriteBarrierPolicy::InitializingBarrier( + reinterpret_cast(&raw_), static_cast(raw_)); + } + void AssigningWriteBarrier() const { + WriteBarrierPolicy::AssigningBarrier(reinterpret_cast(&raw_), + static_cast(raw_)); + } + + T* raw_ = nullptr; + + friend class cppgc::Visitor; +}; + +template +bool operator==( + BasicMember member1, + BasicMember + member2) { + return member1.Get() == member2.Get(); +} + +template +bool operator!=( + BasicMember member1, + BasicMember + member2) { + return !(member1 == member2); +} + +template +struct IsWeak< + internal::BasicMember> + : std::true_type {}; + +} // namespace internal + +/** + * Members are used in classes to contain strong pointers to other garbage + * collected objects. All Member fields of a class must be traced in the class' + * trace method. + */ +template +using Member = internal::BasicMember; + +/** + * WeakMember is similar to Member in that it is used to point to other garbage + * collected objects. However instead of creating a strong pointer to the + * object, the WeakMember creates a weak pointer, which does not keep the + * pointee alive. Hence if all pointers to to a heap allocated object are weak + * the object will be garbage collected. At the time of GC the weak pointers + * will automatically be set to null. + */ +template +using WeakMember = internal::BasicMember; + +/** + * UntracedMember is a pointer to an on-heap object that is not traced for some + * reason. Do not use this unless you know what you are doing. Keeping raw + * pointers to on-heap objects is prohibited unless used from stack. Pointee + * must be kept alive through other means. + */ +template +using UntracedMember = internal::BasicMember; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_MEMBER_H_ diff --git a/deps/v8/include/cppgc/persistent.h b/deps/v8/include/cppgc/persistent.h new file mode 100644 index 00000000000000..fc6b0b9d92efa1 --- /dev/null +++ b/deps/v8/include/cppgc/persistent.h @@ -0,0 +1,304 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_PERSISTENT_H_ +#define INCLUDE_CPPGC_PERSISTENT_H_ + +#include + +#include "cppgc/internal/persistent-node.h" +#include "cppgc/internal/pointer-policies.h" +#include "cppgc/source-location.h" +#include "cppgc/type-traits.h" +#include "cppgc/visitor.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +// The basic class from which all Persistent classes are generated. +template +class BasicPersistent : public LocationPolicy, + private WeaknessPolicy, + private CheckingPolicy { + public: + using typename WeaknessPolicy::IsStrongPersistent; + using PointeeType = T; + + // Null-state/sentinel constructors. + BasicPersistent( // NOLINT + const SourceLocation& loc = SourceLocation::Current()) + : LocationPolicy(loc) {} + + BasicPersistent(std::nullptr_t, // NOLINT + const SourceLocation& loc = SourceLocation::Current()) + : LocationPolicy(loc) {} + + BasicPersistent( // NOLINT + SentinelPointer s, const SourceLocation& loc = SourceLocation::Current()) + : LocationPolicy(loc), raw_(s) {} + + // Raw value contstructors. + BasicPersistent(T* raw, // NOLINT + const SourceLocation& loc = SourceLocation::Current()) + : LocationPolicy(loc), raw_(raw) { + if (!IsValid()) return; + node_ = WeaknessPolicy::GetPersistentRegion(raw_).AllocateNode( + this, &BasicPersistent::Trace); + this->CheckPointer(Get()); + } + + BasicPersistent(T& raw, // NOLINT + const SourceLocation& loc = SourceLocation::Current()) + : BasicPersistent(&raw, loc) {} + + // Copy ctor. + BasicPersistent(const BasicPersistent& other, + const SourceLocation& loc = SourceLocation::Current()) + : BasicPersistent(other.Get(), loc) {} + + // Heterogeneous ctor. + template ::value>> + BasicPersistent( // NOLINT + const BasicPersistent& other, + const SourceLocation& loc = SourceLocation::Current()) + : BasicPersistent(other.Get(), loc) {} + + // Move ctor. The heterogeneous move ctor is not supported since e.g. + // persistent can't reuse persistent node from weak persistent. + BasicPersistent( + BasicPersistent&& other, + const SourceLocation& loc = SourceLocation::Current()) noexcept + : LocationPolicy(std::move(other)), + raw_(std::move(other.raw_)), + node_(std::move(other.node_)) { + if (!IsValid()) return; + node_->UpdateOwner(this); + other.raw_ = nullptr; + other.node_ = nullptr; + this->CheckPointer(Get()); + } + + // Constructor from member. + template ::value>> + BasicPersistent(internal::BasicMember + member, + const SourceLocation& loc = SourceLocation::Current()) + : BasicPersistent(member.Get(), loc) {} + + ~BasicPersistent() { Clear(); } + + // Copy assignment. + BasicPersistent& operator=(const BasicPersistent& other) { + return operator=(other.Get()); + } + + template ::value>> + BasicPersistent& operator=( + const BasicPersistent& other) { + return operator=(other.Get()); + } + + // Move assignment. + BasicPersistent& operator=(BasicPersistent&& other) { + if (this == &other) return *this; + Clear(); + LocationPolicy::operator=(std::move(other)); + raw_ = std::move(other.raw_); + node_ = std::move(other.node_); + if (!IsValid()) return *this; + node_->UpdateOwner(this); + other.raw_ = nullptr; + other.node_ = nullptr; + this->CheckPointer(Get()); + return *this; + } + + // Assignment from member. + template ::value>> + BasicPersistent& operator=( + internal::BasicMember + member) { + return operator=(member.Get()); + } + + BasicPersistent& operator=(T* other) { + Assign(other); + return *this; + } + + BasicPersistent& operator=(std::nullptr_t) { + Clear(); + return *this; + } + + BasicPersistent& operator=(SentinelPointer s) { + Assign(s); + return *this; + } + + explicit operator bool() const { return Get(); } + operator T*() const { return Get(); } + T* operator->() const { return Get(); } + T& operator*() const { return *Get(); } + + T* Get() const { return raw_; } + + void Clear() { Assign(nullptr); } + + T* Release() { + T* result = Get(); + Clear(); + return result; + } + + private: + static void Trace(Visitor* v, const void* ptr) { + const auto* persistent = static_cast(ptr); + v->TraceRoot(*persistent, persistent->Location()); + } + + bool IsValid() const { + // Ideally, handling kSentinelPointer would be done by the embedder. On the + // other hand, having Persistent aware of it is beneficial since no node + // gets wasted. + return raw_ != nullptr && raw_ != kSentinelPointer; + } + + void Assign(T* ptr) { + if (IsValid()) { + if (ptr && ptr != kSentinelPointer) { + // Simply assign the pointer reusing the existing node. + raw_ = ptr; + this->CheckPointer(ptr); + return; + } + WeaknessPolicy::GetPersistentRegion(raw_).FreeNode(node_); + node_ = nullptr; + } + raw_ = ptr; + if (!IsValid()) return; + node_ = WeaknessPolicy::GetPersistentRegion(raw_).AllocateNode( + this, &BasicPersistent::Trace); + this->CheckPointer(Get()); + } + + T* raw_ = nullptr; + PersistentNode* node_ = nullptr; +}; + +template +bool operator==(const BasicPersistent& p1, + const BasicPersistent& p2) { + return p1.Get() == p2.Get(); +} + +template +bool operator!=(const BasicPersistent& p1, + const BasicPersistent& p2) { + return !(p1 == p2); +} + +template +bool operator==(const BasicPersistent& p, + BasicMember + m) { + return p.Get() == m.Get(); +} + +template +bool operator!=(const BasicPersistent& p, + BasicMember + m) { + return !(p == m); +} + +template +bool operator==(BasicMember + m, + const BasicPersistent& p) { + return m.Get() == p.Get(); +} + +template +bool operator!=(BasicMember + m, + const BasicPersistent& p) { + return !(m == p); +} + +template +struct IsWeak> : std::true_type {}; +} // namespace internal + +/** + * Persistent is a way to create a strong pointer from an off-heap object to + * another on-heap object. As long as the Persistent handle is alive the GC will + * keep the object pointed to alive. The Persistent handle is always a GC root + * from the point of view of the GC. Persistent must be constructed and + * destructed in the same thread. + */ +template +using Persistent = + internal::BasicPersistent; + +/** + * WeakPersistent is a way to create a weak pointer from an off-heap object to + * an on-heap object. The pointer is automatically cleared when the pointee gets + * collected. WeakPersistent must be constructed and destructed in the same + * thread. + */ +template +using WeakPersistent = + internal::BasicPersistent; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_PERSISTENT_H_ diff --git a/deps/v8/include/cppgc/platform.h b/deps/v8/include/cppgc/platform.h index f216c2730a4dea..8dc5e14a7d6f07 100644 --- a/deps/v8/include/cppgc/platform.h +++ b/deps/v8/include/cppgc/platform.h @@ -5,8 +5,8 @@ #ifndef INCLUDE_CPPGC_PLATFORM_H_ #define INCLUDE_CPPGC_PLATFORM_H_ -#include "include/v8-platform.h" -#include "include/v8config.h" +#include "v8-platform.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { diff --git a/deps/v8/include/cppgc/prefinalizer.h b/deps/v8/include/cppgc/prefinalizer.h new file mode 100644 index 00000000000000..2f6d68a1dac808 --- /dev/null +++ b/deps/v8/include/cppgc/prefinalizer.h @@ -0,0 +1,54 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_PREFINALIZER_H_ +#define INCLUDE_CPPGC_PREFINALIZER_H_ + +#include "cppgc/internal/accessors.h" +#include "cppgc/internal/compiler-specific.h" +#include "cppgc/internal/prefinalizer-handler.h" +#include "cppgc/liveness-broker.h" +#include "cppgc/macros.h" + +namespace cppgc { + +namespace internal { + +template +class PrefinalizerRegistration final { + public: + explicit PrefinalizerRegistration(T* self) { + static_assert(sizeof(&T::InvokePreFinalizer) > 0, + "USING_PRE_FINALIZER(T) must be defined."); + + cppgc::internal::PreFinalizerRegistrationDispatcher::RegisterPrefinalizer( + internal::GetHeapFromPayload(self), {self, T::InvokePreFinalizer}); + } + + void* operator new(size_t, void* location) = delete; + void* operator new(size_t) = delete; +}; + +} // namespace internal + +#define CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer) \ + public: \ + static bool InvokePreFinalizer(const LivenessBroker& liveness_broker, \ + void* object) { \ + static_assert(internal::IsGarbageCollectedTypeV, \ + "Only garbage collected objects can have prefinalizers"); \ + Class* self = static_cast(object); \ + if (liveness_broker.IsHeapObjectAlive(self)) return false; \ + self->Class::PreFinalizer(); \ + return true; \ + } \ + \ + private: \ + CPPGC_NO_UNIQUE_ADDRESS internal::PrefinalizerRegistration \ + prefinalizer_dummy_{this}; \ + friend class internal::__thisIsHereToForceASemicolonAfterThisMacro + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_PREFINALIZER_H_ diff --git a/deps/v8/include/cppgc/source-location.h b/deps/v8/include/cppgc/source-location.h new file mode 100644 index 00000000000000..8cc52d6a539c2f --- /dev/null +++ b/deps/v8/include/cppgc/source-location.h @@ -0,0 +1,59 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_SOURCE_LOCATION_H_ +#define INCLUDE_CPPGC_SOURCE_LOCATION_H_ + +#include + +#include "v8config.h" // NOLINT(build/include_directory) + +#if defined(__has_builtin) +#define CPPGC_SUPPORTS_SOURCE_LOCATION \ + (__has_builtin(__builtin_FUNCTION) && __has_builtin(__builtin_FILE) && \ + __has_builtin(__builtin_LINE)) // NOLINT +#elif defined(V8_CC_GNU) && __GNUC__ >= 7 +#define CPPGC_SUPPORTS_SOURCE_LOCATION 1 +#elif defined(V8_CC_INTEL) && __ICC >= 1800 +#define CPPGC_SUPPORTS_SOURCE_LOCATION 1 +#else +#define CPPGC_SUPPORTS_SOURCE_LOCATION 0 +#endif + +namespace cppgc { + +// Encapsulates source location information. Mimics C++20's +// std::source_location. +class V8_EXPORT SourceLocation final { + public: +#if CPPGC_SUPPORTS_SOURCE_LOCATION + static constexpr SourceLocation Current( + const char* function = __builtin_FUNCTION(), + const char* file = __builtin_FILE(), size_t line = __builtin_LINE()) { + return SourceLocation(function, file, line); + } +#else + static constexpr SourceLocation Current() { return SourceLocation(); } +#endif // CPPGC_SUPPORTS_SOURCE_LOCATION + + constexpr SourceLocation() = default; + + constexpr const char* Function() const { return function_; } + constexpr const char* FileName() const { return file_; } + constexpr size_t Line() const { return line_; } + + std::string ToString() const; + + private: + constexpr SourceLocation(const char* function, const char* file, size_t line) + : function_(function), file_(file), line_(line) {} + + const char* function_ = nullptr; + const char* file_ = nullptr; + size_t line_ = 0u; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_SOURCE_LOCATION_H_ diff --git a/deps/v8/include/cppgc/trace-trait.h b/deps/v8/include/cppgc/trace-trait.h new file mode 100644 index 00000000000000..e246bc53b7d9aa --- /dev/null +++ b/deps/v8/include/cppgc/trace-trait.h @@ -0,0 +1,67 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_TRACE_TRAIT_H_ +#define INCLUDE_CPPGC_TRACE_TRAIT_H_ + +#include +#include "cppgc/type-traits.h" + +namespace cppgc { + +class Visitor; + +namespace internal { + +template ::type>> +struct TraceTraitImpl; + +} // namespace internal + +using TraceCallback = void (*)(Visitor*, const void*); + +// TraceDescriptor is used to describe how to trace an object. +struct TraceDescriptor { + // The adjusted base pointer of the object that should be traced. + const void* base_object_payload; + // A callback for tracing the object. + TraceCallback callback; +}; + +template +struct TraceTrait { + static_assert(internal::IsTraceableV, "T must have a Trace() method"); + + static TraceDescriptor GetTraceDescriptor(const void* self) { + return internal::TraceTraitImpl::GetTraceDescriptor( + static_cast(self)); + } + + static void Trace(Visitor* visitor, const void* self) { + static_cast(self)->Trace(visitor); + } +}; + +namespace internal { + +template +struct TraceTraitImpl { + static TraceDescriptor GetTraceDescriptor(const void* self) { + return {self, TraceTrait::Trace}; + } +}; + +template +struct TraceTraitImpl { + static TraceDescriptor GetTraceDescriptor(const void* self) { + return static_cast(self)->GetTraceDescriptor(); + } +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_TRACE_TRAIT_H_ diff --git a/deps/v8/include/cppgc/type-traits.h b/deps/v8/include/cppgc/type-traits.h new file mode 100644 index 00000000000000..4d8ab809c8d439 --- /dev/null +++ b/deps/v8/include/cppgc/type-traits.h @@ -0,0 +1,109 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_TYPE_TRAITS_H_ +#define INCLUDE_CPPGC_TYPE_TRAITS_H_ + +#include + +namespace cppgc { + +class Visitor; + +namespace internal { + +// Pre-C++17 custom implementation of std::void_t. +template +struct make_void { + typedef void type; +}; +template +using void_t = typename make_void::type; + +// Not supposed to be specialized by the user. +template +struct IsWeak : std::false_type {}; + +template class U> +struct IsSubclassOfTemplate { + private: + template + static std::true_type SubclassCheck(U*); + static std::false_type SubclassCheck(...); + + public: + static constexpr bool value = + decltype(SubclassCheck(std::declval()))::value; +}; + +// IsTraceMethodConst is used to verify that all Trace methods are marked as +// const. It is equivalent to IsTraceable but for a non-const object. +template +struct IsTraceMethodConst : std::false_type {}; + +template +struct IsTraceMethodConst().Trace( + std::declval()))>> : std::true_type { +}; + +template +struct IsTraceable : std::false_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct IsTraceable< + T, void_t().Trace(std::declval()))>> + : std::true_type { + // All Trace methods should be marked as const. If an object of type + // 'T' is traceable then any object of type 'const T' should also + // be traceable. + static_assert(IsTraceMethodConst(), + "Trace methods should be marked as const."); +}; + +template +constexpr bool IsTraceableV = IsTraceable::value; + +template +struct IsGarbageCollectedMixinType : std::false_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct IsGarbageCollectedMixinType< + T, + void_t::IsGarbageCollectedMixinTypeMarker>> + : std::true_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct IsGarbageCollectedType : IsGarbageCollectedMixinType { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct IsGarbageCollectedType< + T, void_t::IsGarbageCollectedTypeMarker>> + : std::true_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +constexpr bool IsGarbageCollectedTypeV = + internal::IsGarbageCollectedType::value; + +template +constexpr bool IsGarbageCollectedMixinTypeV = + internal::IsGarbageCollectedMixinType::value; + +} // namespace internal + +template +constexpr bool IsWeakV = internal::IsWeak::value; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_TYPE_TRAITS_H_ diff --git a/deps/v8/include/cppgc/visitor.h b/deps/v8/include/cppgc/visitor.h new file mode 100644 index 00000000000000..a73a4abb2bdb7c --- /dev/null +++ b/deps/v8/include/cppgc/visitor.h @@ -0,0 +1,138 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_VISITOR_H_ +#define INCLUDE_CPPGC_VISITOR_H_ + +#include "cppgc/garbage-collected.h" +#include "cppgc/internal/logging.h" +#include "cppgc/internal/pointer-policies.h" +#include "cppgc/liveness-broker.h" +#include "cppgc/member.h" +#include "cppgc/source-location.h" +#include "cppgc/trace-trait.h" + +namespace cppgc { +namespace internal { +class VisitorBase; +} // namespace internal + +using WeakCallback = void (*)(const LivenessBroker&, const void*); + +/** + * Visitor passed to trace methods. All managed pointers must have called the + * visitor's trace method on them. + */ +class Visitor { + public: + template + void Trace(const Member& member) { + const T* value = member.GetRawAtomic(); + CPPGC_DCHECK(value != kSentinelPointer); + Trace(value); + } + + template + void Trace(const WeakMember& weak_member) { + static_assert(sizeof(T), "T must be fully defined"); + static_assert(internal::IsGarbageCollectedType::value, + "T must be GarabgeCollected or GarbageCollectedMixin type"); + + const T* value = weak_member.GetRawAtomic(); + + // Bailout assumes that WeakMember emits write barrier. + if (!value) { + return; + } + + // TODO(chromium:1056170): DCHECK (or similar) for deleted values as they + // should come in at a different path. + VisitWeak(value, TraceTrait::GetTraceDescriptor(value), + &HandleWeak>, &weak_member); + } + + template * = nullptr> + void TraceRoot(const Persistent& p, const SourceLocation& loc) { + using PointeeType = typename Persistent::PointeeType; + static_assert(sizeof(PointeeType), + "Persistent's pointee type must be fully defined"); + static_assert(internal::IsGarbageCollectedType::value, + "Persisent's pointee type must be GarabgeCollected or " + "GarbageCollectedMixin"); + if (!p.Get()) { + return; + } + VisitRoot(p.Get(), TraceTrait::GetTraceDescriptor(p.Get())); + } + + template < + typename WeakPersistent, + std::enable_if_t* = nullptr> + void TraceRoot(const WeakPersistent& p, const SourceLocation& loc) { + using PointeeType = typename WeakPersistent::PointeeType; + static_assert(sizeof(PointeeType), + "Persistent's pointee type must be fully defined"); + static_assert(internal::IsGarbageCollectedType::value, + "Persisent's pointee type must be GarabgeCollected or " + "GarbageCollectedMixin"); + VisitWeakRoot(p.Get(), TraceTrait::GetTraceDescriptor(p.Get()), + &HandleWeak, &p); + } + + template + void RegisterWeakCallbackMethod(const T* obj) { + RegisterWeakCallback(&WeakCallbackMethodDelegate, obj); + } + + virtual void RegisterWeakCallback(WeakCallback, const void*) {} + + protected: + virtual void Visit(const void* self, TraceDescriptor) {} + virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback, + const void* weak_member) {} + virtual void VisitRoot(const void*, TraceDescriptor) {} + virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback, + const void* weak_root) {} + + private: + template + static void WeakCallbackMethodDelegate(const LivenessBroker& info, + const void* self) { + // Callback is registered through a potential const Trace method but needs + // to be able to modify fields. See HandleWeak. + (const_cast(static_cast(self))->*method)(info); + } + + template + static void HandleWeak(const LivenessBroker& info, const void* object) { + const PointerType* weak = static_cast(object); + const auto* raw = weak->Get(); + if (raw && !info.IsHeapObjectAlive(raw)) { + // Object is passed down through the marker as const. Alternatives are + // - non-const Trace method; + // - mutable pointer in MemberBase; + const_cast(weak)->Clear(); + } + } + + Visitor() = default; + + template + void Trace(const T* t) { + static_assert(sizeof(T), "T must be fully defined"); + static_assert(internal::IsGarbageCollectedType::value, + "T must be GarabgeCollected or GarbageCollectedMixin type"); + if (!t) { + return; + } + Visit(t, TraceTrait::GetTraceDescriptor(t)); + } + + friend class internal::VisitorBase; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_VISITOR_H_ diff --git a/deps/v8/include/js_protocol.pdl b/deps/v8/include/js_protocol.pdl index 3f5410d1e1f787..706c37f958e4a0 100644 --- a/deps/v8/include/js_protocol.pdl +++ b/deps/v8/include/js_protocol.pdl @@ -204,6 +204,21 @@ domain Debugger # Exception details. optional Runtime.ExceptionDetails exceptionDetails + # Execute a Wasm Evaluator module on a given call frame. + experimental command executeWasmEvaluator + parameters + # WebAssembly call frame identifier to evaluate on. + CallFrameId callFrameId + # Code of the evaluator module. + binary evaluator + # Terminate execution after timing out (number of milliseconds). + experimental optional Runtime.TimeDelta timeout + returns + # Object wrapper for the evaluation result. + Runtime.RemoteObject result + # Exception details. + optional Runtime.ExceptionDetails exceptionDetails + # Returns possible locations for breakpoint. scriptId in start and end range locations should be # the same. command getPossibleBreakpoints @@ -510,6 +525,18 @@ domain Debugger JavaScript WebAssembly + # Debug symbols available for a wasm script. + type DebugSymbols extends object + properties + # Type of the debug symbols. + enum type + None + SourceMap + EmbeddedDWARF + ExternalDWARF + # URL of the external symbol source. + optional string externalURL + # Fired when virtual machine fails to parse the script. event scriptFailedToParse parameters @@ -584,6 +611,8 @@ domain Debugger experimental optional integer codeOffset # The language of the script. experimental optional Debugger.ScriptLanguage scriptLanguage + # If the scriptLanguage is WebASsembly, the source of debug symbols for the module. + experimental optional Debugger.DebugSymbols debugSymbols experimental domain HeapProfiler depends on Runtime @@ -980,6 +1009,7 @@ domain Runtime f32 f64 v128 + anyref # Object class (constructor) name. Specified for `object` type values only. optional string className # Remote object value in case of primitive values or JSON values (if it was requested). diff --git a/deps/v8/include/libplatform/libplatform.h b/deps/v8/include/libplatform/libplatform.h index 6051b644fb9b59..c7ea4c2bd38575 100644 --- a/deps/v8/include/libplatform/libplatform.h +++ b/deps/v8/include/libplatform/libplatform.h @@ -9,8 +9,8 @@ #include "libplatform/libplatform-export.h" #include "libplatform/v8-tracing.h" -#include "v8-platform.h" // NOLINT(build/include) -#include "v8config.h" // NOLINT(build/include) +#include "v8-platform.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) namespace v8 { namespace platform { diff --git a/deps/v8/include/libplatform/v8-tracing.h b/deps/v8/include/libplatform/v8-tracing.h index 79e6f62d23e1bb..45822d00f371d4 100644 --- a/deps/v8/include/libplatform/v8-tracing.h +++ b/deps/v8/include/libplatform/v8-tracing.h @@ -12,9 +12,12 @@ #include #include "libplatform/libplatform-export.h" -#include "v8-platform.h" // NOLINT(build/include) +#include "v8-platform.h" // NOLINT(build/include_directory) namespace perfetto { +namespace trace_processor { +class TraceProcessorStorage; +} class TracingSession; } @@ -28,7 +31,6 @@ namespace platform { namespace tracing { class TraceEventListener; -class JSONTraceEventListener; const int kTraceMaxNumArgs = 2; @@ -197,6 +199,9 @@ class V8_PLATFORM_EXPORT TraceConfig { TraceConfig() : enable_systrace_(false), enable_argument_filter_(false) {} TraceRecordMode GetTraceRecordMode() const { return record_mode_; } + const StringList& GetEnabledCategories() const { + return included_categories_; + } bool IsSystraceEnabled() const { return enable_systrace_; } bool IsArgumentFilterEnabled() const { return enable_argument_filter_; } @@ -229,6 +234,17 @@ class V8_PLATFORM_EXPORT TraceConfig { class V8_PLATFORM_EXPORT TracingController : public V8_PLATFORM_NON_EXPORTED_BASE(v8::TracingController) { public: + TracingController(); + ~TracingController() override; + +#if defined(V8_USE_PERFETTO) + // Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides + // the output stream for the JSON trace data. + void InitializeForPerfetto(std::ostream* output_stream); + // Provide an optional listener for testing that will receive trace events. + // Must be called before StartTracing(). + void SetTraceEventListenerForTesting(TraceEventListener* listener); +#else // defined(V8_USE_PERFETTO) // The pointer returned from GetCategoryGroupEnabled() points to a value with // zero or more of the following bits. Used in this class only. The // TRACE_EVENT macros should only use the value as a bool. These values must @@ -242,19 +258,8 @@ class V8_PLATFORM_EXPORT TracingController ENABLED_FOR_ETW_EXPORT = 1 << 3 }; - TracingController(); - ~TracingController() override; - // Takes ownership of |trace_buffer|. void Initialize(TraceBuffer* trace_buffer); -#ifdef V8_USE_PERFETTO - // Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides - // the output stream for the JSON trace data. - void InitializeForPerfetto(std::ostream* output_stream); - // Provide an optional listener for testing that will receive trace events. - // Must be called before StartTracing(). - void SetTraceEventListenerForTesting(TraceEventListener* listener); -#endif // v8::TracingController implementation. const uint8_t* GetCategoryGroupEnabled(const char* category_group) override; @@ -274,6 +279,10 @@ class V8_PLATFORM_EXPORT TracingController unsigned int flags, int64_t timestamp) override; void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, const char* name, uint64_t handle) override; + + static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag); +#endif // !defined(V8_USE_PERFETTO) + void AddTraceStateObserver( v8::TracingController::TraceStateObserver* observer) override; void RemoveTraceStateObserver( @@ -282,27 +291,32 @@ class V8_PLATFORM_EXPORT TracingController void StartTracing(TraceConfig* trace_config); void StopTracing(); - static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag); - protected: +#if !defined(V8_USE_PERFETTO) virtual int64_t CurrentTimestampMicroseconds(); virtual int64_t CurrentCpuTimestampMicroseconds(); +#endif // !defined(V8_USE_PERFETTO) private: +#if !defined(V8_USE_PERFETTO) void UpdateCategoryGroupEnabledFlag(size_t category_index); void UpdateCategoryGroupEnabledFlags(); +#endif // !defined(V8_USE_PERFETTO) - std::unique_ptr trace_buffer_; - std::unique_ptr trace_config_; std::unique_ptr mutex_; - std::unordered_set observers_; + std::unique_ptr trace_config_; std::atomic_bool recording_{false}; -#ifdef V8_USE_PERFETTO + std::unordered_set observers_; + +#if defined(V8_USE_PERFETTO) std::ostream* output_stream_ = nullptr; - std::unique_ptr json_listener_; + std::unique_ptr + trace_processor_; TraceEventListener* listener_for_testing_ = nullptr; std::unique_ptr tracing_session_; -#endif +#else // !defined(V8_USE_PERFETTO) + std::unique_ptr trace_buffer_; +#endif // !defined(V8_USE_PERFETTO) // Disallow copy and assign TracingController(const TracingController&) = delete; diff --git a/deps/v8/include/v8-fast-api-calls.h b/deps/v8/include/v8-fast-api-calls.h index 79a5d4d82a764d..f74406493bcf2a 100644 --- a/deps/v8/include/v8-fast-api-calls.h +++ b/deps/v8/include/v8-fast-api-calls.h @@ -165,7 +165,7 @@ #include #include -#include "v8config.h" // NOLINT(build/include) +#include "v8config.h" // NOLINT(build/include_directory) namespace v8 { diff --git a/deps/v8/include/v8-inspector-protocol.h b/deps/v8/include/v8-inspector-protocol.h index 612a2ebc3911f5..a5ffb7d6954bcf 100644 --- a/deps/v8/include/v8-inspector-protocol.h +++ b/deps/v8/include/v8-inspector-protocol.h @@ -5,9 +5,9 @@ #ifndef V8_V8_INSPECTOR_PROTOCOL_H_ #define V8_V8_INSPECTOR_PROTOCOL_H_ -#include "inspector/Debugger.h" // NOLINT(build/include) -#include "inspector/Runtime.h" // NOLINT(build/include) -#include "inspector/Schema.h" // NOLINT(build/include) -#include "v8-inspector.h" // NOLINT(build/include) +#include "inspector/Debugger.h" // NOLINT(build/include_directory) +#include "inspector/Runtime.h" // NOLINT(build/include_directory) +#include "inspector/Schema.h" // NOLINT(build/include_directory) +#include "v8-inspector.h" // NOLINT(build/include_directory) #endif // V8_V8_INSPECTOR_PROTOCOL_H_ diff --git a/deps/v8/include/v8-inspector.h b/deps/v8/include/v8-inspector.h index 01274625c1f476..6573940e2fe3c3 100644 --- a/deps/v8/include/v8-inspector.h +++ b/deps/v8/include/v8-inspector.h @@ -11,7 +11,7 @@ #include #include -#include "v8.h" // NOLINT(build/include) +#include "v8.h" // NOLINT(build/include_directory) namespace v8_inspector { diff --git a/deps/v8/include/v8-internal.h b/deps/v8/include/v8-internal.h index 52ee403f526d06..127a77dbfca070 100644 --- a/deps/v8/include/v8-internal.h +++ b/deps/v8/include/v8-internal.h @@ -10,8 +10,8 @@ #include #include -#include "v8-version.h" // NOLINT(build/include) -#include "v8config.h" // NOLINT(build/include) +#include "v8-version.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) namespace v8 { @@ -110,6 +110,16 @@ constexpr bool PointerCompressionIsEnabled() { return kApiTaggedSize != kApiSystemPointerSize; } +constexpr bool HeapSandboxIsEnabled() { +#ifdef V8_HEAP_SANDBOX + return true; +#else + return false; +#endif +} + +using ExternalPointer_t = Address; + #ifdef V8_31BIT_SMIS_ON_64BIT_ARCH using PlatformSmiTagging = SmiTagging; #else @@ -130,6 +140,15 @@ V8_INLINE static constexpr internal::Address IntToSmi(int value) { kSmiTag; } +// {obj} must be the raw tagged pointer representation of a HeapObject +// that's guaranteed to never be in ReadOnlySpace. +V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj); + +// Returns if we need to throw when an error occurs. This infers the language +// mode based on the current context and the closure. This returns true if the +// language mode is strict. +V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate); + /** * This class exports constants and functionality from within v8 that * is necessary to implement inline functions in the v8 api. Don't @@ -145,7 +164,6 @@ class Internals { 1 * kApiTaggedSize + 2 * kApiInt32Size; static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize; - static const int kForeignAddressOffset = kApiTaggedSize; static const int kJSObjectHeaderSize = 3 * kApiTaggedSize; static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize; static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize; @@ -330,11 +348,36 @@ class Internals { #endif } + V8_INLINE static internal::Isolate* GetIsolateForHeapSandbox( + internal::Address obj) { +#ifdef V8_HEAP_SANDBOX + return internal::IsolateFromNeverReadOnlySpaceObject(obj); +#else + // Not used in non-sandbox mode. + return nullptr; +#endif + } + + V8_INLINE static internal::Address ReadExternalPointerField( + internal::Isolate* isolate, internal::Address heap_object_ptr, + int offset) { + internal::Address value = ReadRawField
(heap_object_ptr, offset); +#ifdef V8_HEAP_SANDBOX + // We currently have to treat zero as nullptr in embedder slots. + if (value) value = DecodeExternalPointer(isolate, value); +#endif + return value; + } + #ifdef V8_COMPRESS_POINTERS // See v8:7703 or src/ptr-compr.* for details about pointer compression. static constexpr size_t kPtrComprHeapReservationSize = size_t{1} << 32; static constexpr size_t kPtrComprIsolateRootAlignment = size_t{1} << 32; + // See v8:10391 for details about V8 heap sandbox. + static constexpr uint32_t kExternalPointerSalt = + 0x7fffffff & ~static_cast(kHeapObjectTagMask); + V8_INLINE static internal::Address GetRootFromOnHeapAddress( internal::Address addr) { return addr & -static_cast(kPtrComprIsolateRootAlignment); @@ -345,6 +388,15 @@ class Internals { internal::Address root = GetRootFromOnHeapAddress(heap_object_ptr); return root + static_cast(static_cast(value)); } + + V8_INLINE static Address DecodeExternalPointer( + const Isolate* isolate, ExternalPointer_t encoded_pointer) { +#ifndef V8_HEAP_SANDBOX + return encoded_pointer; +#else + return encoded_pointer ^ kExternalPointerSalt; +#endif + } #endif // V8_COMPRESS_POINTERS }; @@ -371,15 +423,6 @@ V8_INLINE void PerformCastCheck(T* data) { CastCheck::value>::Perform(data); } -// {obj} must be the raw tagged pointer representation of a HeapObject -// that's guaranteed to never be in ReadOnlySpace. -V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj); - -// Returns if we need to throw when an error occurs. This infers the language -// mode based on the current context and the closure. This returns true if the -// language mode is strict. -V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate); - // A base class for backing stores, which is needed due to vagaries of // how static casts work with std::shared_ptr. class BackingStoreBase {}; diff --git a/deps/v8/include/v8-platform.h b/deps/v8/include/v8-platform.h index 5d23cd665ed399..7cfd18b5708d57 100644 --- a/deps/v8/include/v8-platform.h +++ b/deps/v8/include/v8-platform.h @@ -11,12 +11,34 @@ #include #include -#include "v8config.h" // NOLINT(build/include) +#include "v8config.h" // NOLINT(build/include_directory) namespace v8 { class Isolate; +// Valid priorities supported by the task scheduling infrastructure. +enum class TaskPriority : uint8_t { + /** + * Best effort tasks are not critical for performance of the application. The + * platform implementation should preempt such tasks if higher priority tasks + * arrive. + */ + kBestEffort, + /** + * User visible tasks are long running background tasks that will + * improve performance and memory usage of the application upon completion. + * Example: background compilation and garbage collection. + */ + kUserVisible, + /** + * User blocking tasks are highest priority tasks that block the execution + * thread (e.g. major garbage collection). They must be finished as soon as + * possible. + */ + kUserBlocking, +}; + /** * A Task represents a unit of work. */ @@ -113,6 +135,82 @@ class TaskRunner { TaskRunner& operator=(const TaskRunner&) = delete; }; +/** + * Delegate that's passed to Job's worker task, providing an entry point to + * communicate with the scheduler. + */ +class JobDelegate { + public: + /** + * Returns true if this thread should return from the worker task on the + * current thread ASAP. Workers should periodically invoke ShouldYield (or + * YieldIfNeeded()) as often as is reasonable. + */ + virtual bool ShouldYield() = 0; + + /** + * Notifies the scheduler that max concurrency was increased, and the number + * of worker should be adjusted accordingly. See Platform::PostJob() for more + * details. + */ + virtual void NotifyConcurrencyIncrease() = 0; +}; + +/** + * Handle returned when posting a Job. Provides methods to control execution of + * the posted Job. + */ +class JobHandle { + public: + virtual ~JobHandle() = default; + + /** + * Notifies the scheduler that max concurrency was increased, and the number + * of worker should be adjusted accordingly. See Platform::PostJob() for more + * details. + */ + virtual void NotifyConcurrencyIncrease() = 0; + + /** + * Contributes to the job on this thread. Doesn't return until all tasks have + * completed and max concurrency becomes 0. When Join() is called and max + * concurrency reaches 0, it should not increase again. This also promotes + * this Job's priority to be at least as high as the calling thread's + * priority. + */ + virtual void Join() = 0; + + /** + * Forces all existing workers to yield ASAP. Waits until they have all + * returned from the Job's callback before returning. + */ + virtual void Cancel() = 0; + + /** + * Returns true if associated with a Job and other methods may be called. + * Returns false after Join() or Cancel() was called. + */ + virtual bool IsRunning() = 0; +}; + +/** + * A JobTask represents work to run in parallel from Platform::PostJob(). + */ +class JobTask { + public: + virtual ~JobTask() = default; + + virtual void Run(JobDelegate* delegate) = 0; + + /** + * Controls the maximum number of threads calling Run() concurrently. Run() is + * only invoked if the number of threads previously running Run() was less + * than the value returned. Since GetMaxConcurrency() is a leaf function, it + * must not call back any JobHandle methods. + */ + virtual size_t GetMaxConcurrency() const = 0; +}; + /** * The interface represents complex arguments to trace events. */ @@ -138,6 +236,10 @@ class TracingController { public: virtual ~TracingController() = default; + // In Perfetto mode, trace events are written using Perfetto's Track Event + // API directly without going through the embedder. However, it is still + // possible to observe tracing being enabled and disabled. +#if !defined(V8_USE_PERFETTO) /** * Called by TRACE_EVENT* macros, don't call this directly. * The name parameter is a category group for example: @@ -183,6 +285,7 @@ class TracingController { **/ virtual void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {} +#endif // !defined(V8_USE_PERFETTO) class TraceStateObserver { public: @@ -368,6 +471,64 @@ class Platform { */ virtual bool IdleTasksEnabled(Isolate* isolate) { return false; } + /** + * Posts |job_task| to run in parallel. Returns a JobHandle associated with + * the Job, which can be joined or canceled. + * This avoids degenerate cases: + * - Calling CallOnWorkerThread() for each work item, causing significant + * overhead. + * - Fixed number of CallOnWorkerThread() calls that split the work and might + * run for a long time. This is problematic when many components post + * "num cores" tasks and all expect to use all the cores. In these cases, + * the scheduler lacks context to be fair to multiple same-priority requests + * and/or ability to request lower priority work to yield when high priority + * work comes in. + * A canonical implementation of |job_task| looks like: + * class MyJobTask : public JobTask { + * public: + * MyJobTask(...) : worker_queue_(...) {} + * // JobTask: + * void Run(JobDelegate* delegate) override { + * while (!delegate->ShouldYield()) { + * // Smallest unit of work. + * auto work_item = worker_queue_.TakeWorkItem(); // Thread safe. + * if (!work_item) return; + * ProcessWork(work_item); + * } + * } + * + * size_t GetMaxConcurrency() const override { + * return worker_queue_.GetSize(); // Thread safe. + * } + * }; + * auto handle = PostJob(TaskPriority::kUserVisible, + * std::make_unique(...)); + * handle->Join(); + * + * PostJob() and methods of the returned JobHandle/JobDelegate, must never be + * called while holding a lock that could be acquired by JobTask::Run or + * JobTask::GetMaxConcurrency -- that could result in a deadlock. This is + * because [1] JobTask::GetMaxConcurrency may be invoked while holding + * internal lock (A), hence JobTask::GetMaxConcurrency can only use a lock (B) + * if that lock is *never* held while calling back into JobHandle from any + * thread (A=>B/B=>A deadlock) and [2] JobTask::Run or + * JobTask::GetMaxConcurrency may be invoked synchronously from JobHandle + * (B=>JobHandle::foo=>B deadlock). + * + * A sufficient PostJob() implementation that uses the default Job provided in + * libplatform looks like: + * std::unique_ptr PostJob( + * TaskPriority priority, std::unique_ptr job_task) override { + * return std::make_unique( + * std::make_shared( + * this, std::move(job_task), kNumThreads)); + * } + */ + virtual std::unique_ptr PostJob( + TaskPriority priority, std::unique_ptr job_task) { + return nullptr; + } + /** * Monotonically increasing time in seconds from an arbitrary fixed point in * the past. This function is expected to return at least diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index 866d799076e9db..c3b25e8d6a6302 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -10,7 +10,7 @@ #include #include -#include "v8.h" // NOLINT(build/include) +#include "v8.h" // NOLINT(build/include_directory) /** * Profiler support for the V8 JavaScript engine. diff --git a/deps/v8/include/v8-util.h b/deps/v8/include/v8-util.h index 29d813e4274d16..89ec4f6a789c03 100644 --- a/deps/v8/include/v8-util.h +++ b/deps/v8/include/v8-util.h @@ -5,7 +5,7 @@ #ifndef V8_UTIL_H_ #define V8_UTIL_H_ -#include "v8.h" // NOLINT(build/include) +#include "v8.h" // NOLINT(build/include_directory) #include #include #include diff --git a/deps/v8/include/v8-version-string.h b/deps/v8/include/v8-version-string.h index fb84144d544106..8faed2a740592b 100644 --- a/deps/v8/include/v8-version-string.h +++ b/deps/v8/include/v8-version-string.h @@ -5,7 +5,7 @@ #ifndef V8_VERSION_STRING_H_ #define V8_VERSION_STRING_H_ -#include "v8-version.h" // NOLINT(build/include) +#include "v8-version.h" // NOLINT(build/include_directory) // This is here rather than v8-version.h to keep that file simple and // machine-processable. diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 64f184866537b5..cee7990e4bc193 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -9,9 +9,9 @@ // NOTE these macros are used by some of the tool scripts and the build // system so their names cannot be changed without changing the scripts. #define V8_MAJOR_VERSION 8 -#define V8_MINOR_VERSION 3 -#define V8_BUILD_NUMBER 110 -#define V8_PATCH_LEVEL 9 +#define V8_MINOR_VERSION 4 +#define V8_BUILD_NUMBER 371 +#define V8_PATCH_LEVEL 19 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/include/v8-wasm-trap-handler-posix.h b/deps/v8/include/v8-wasm-trap-handler-posix.h index 998d0a41bb73d8..9b8e8a5b496aa0 100644 --- a/deps/v8/include/v8-wasm-trap-handler-posix.h +++ b/deps/v8/include/v8-wasm-trap-handler-posix.h @@ -7,7 +7,7 @@ #include -#include "v8config.h" // NOLINT(build/include) +#include "v8config.h" // NOLINT(build/include_directory) namespace v8 { /** diff --git a/deps/v8/include/v8-wasm-trap-handler-win.h b/deps/v8/include/v8-wasm-trap-handler-win.h index 0185df6401c24b..9d3cad58483285 100644 --- a/deps/v8/include/v8-wasm-trap-handler-win.h +++ b/deps/v8/include/v8-wasm-trap-handler-win.h @@ -7,7 +7,7 @@ #include -#include "v8config.h" // NOLINT(build/include) +#include "v8config.h" // NOLINT(build/include_directory) namespace v8 { /** diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 406c47383b714d..18d72f1630ccd5 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -18,15 +18,17 @@ #include #include #include + #include #include #include #include #include -#include "v8-internal.h" // NOLINT(build/include) -#include "v8-version.h" // NOLINT(build/include) -#include "v8config.h" // NOLINT(build/include) +#include "cppgc/common.h" +#include "v8-internal.h" // NOLINT(build/include_directory) +#include "v8-version.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) // We reserve the V8_* prefix for macros defined in V8 public API and // assume there are no name conflicts with the embedder's code. @@ -123,19 +125,21 @@ namespace internal { enum class ArgumentsType; template class Arguments; +template +class CustomArguments; class DeferredHandles; +class FunctionCallbackArguments; +class GlobalHandles; class Heap; class HeapObject; class ExternalString; class Isolate; class LocalEmbedderHeapTracer; class MicrotaskQueue; -struct ScriptStreamingData; -template class CustomArguments; class PropertyCallbackArguments; -class FunctionCallbackArguments; -class GlobalHandles; +class ReadOnlyHeap; class ScopedExternalStringLock; +struct ScriptStreamingData; class ThreadLocalTop; namespace wasm { @@ -1752,11 +1756,9 @@ class V8_EXPORT ScriptCompiler { public: enum Encoding { ONE_BYTE, TWO_BYTE, UTF8 }; -#if defined(_MSC_VER) && _MSC_VER >= 1910 /* Disable on VS2015 */ V8_DEPRECATE_SOON( "This class takes ownership of source_stream, so use the constructor " "taking a unique_ptr to make these semantics clearer") -#endif StreamedSource(ExternalSourceStream* source_stream, Encoding encoding); StreamedSource(std::unique_ptr source_stream, Encoding encoding); @@ -4764,11 +4766,17 @@ class V8_EXPORT CompiledWasmModule { */ MemorySpan GetWireBytesRef(); + const std::string& source_url() const { return source_url_; } + private: - explicit CompiledWasmModule(std::shared_ptr); - friend class Utils; + friend class WasmModuleObject; + friend class WasmStreaming; + + explicit CompiledWasmModule(std::shared_ptr, + const char* source_url, size_t url_length); const std::shared_ptr native_module_; + const std::string source_url_; }; // An instance of WebAssembly.Module. @@ -5935,37 +5943,6 @@ class V8_EXPORT RegExp : public Object { static void CheckCast(Value* obj); }; -/** - * An instance of the built-in FinalizationRegistry constructor. - * - * The C++ name is FinalizationGroup for backwards compatibility. This API is - * experimental and deprecated. - */ -class V8_EXPORT FinalizationGroup : public Object { - public: - /** - * Runs the cleanup callback of the given FinalizationRegistry. - * - * V8 will inform the embedder that there are finalizer callbacks be - * called through HostCleanupFinalizationGroupCallback. - * - * HostCleanupFinalizationGroupCallback should schedule a task to - * call FinalizationGroup::Cleanup() at some point in the - * future. It's the embedders responsiblity to make this call at a - * time which does not interrupt synchronous ECMAScript code - * execution. - * - * If the result is Nothing then an exception has - * occurred. Otherwise the result is |true| if the cleanup callback - * was called successfully. The result is never |false|. - */ - V8_DEPRECATED( - "FinalizationGroup cleanup is automatic if " - "HostCleanupFinalizationGroupCallback is not set") - static V8_WARN_UNUSED_RESULT Maybe Cleanup( - Local finalization_group); -}; - /** * A JavaScript value that wraps a C++ void*. This type of value is mainly used * to associate C++ data structures with JavaScript objects. @@ -7172,6 +7149,9 @@ class V8_EXPORT Exception { static Local ReferenceError(Local message); static Local SyntaxError(Local message); static Local TypeError(Local message); + static Local WasmCompileError(Local message); + static Local WasmLinkError(Local message); + static Local WasmRuntimeError(Local message); static Local Error(Local message); /** @@ -7215,20 +7195,6 @@ typedef void (*AddCrashKeyCallback)(CrashKeyId id, const std::string& value); typedef void (*BeforeCallEnteredCallback)(Isolate*); typedef void (*CallCompletedCallback)(Isolate*); -/** - * HostCleanupFinalizationGroupCallback is called when we require the - * embedder to enqueue a task that would call - * FinalizationGroup::Cleanup(). - * - * The FinalizationGroup is the one for which the embedder needs to - * call FinalizationGroup::Cleanup() on. - * - * The context provided is the one in which the FinalizationGroup was - * created in. - */ -typedef void (*HostCleanupFinalizationGroupCallback)( - Local context, Local fg); - /** * HostImportModuleDynamicallyCallback is called when we require the * embedder to load a module. This is used as part of the dynamic @@ -7255,7 +7221,8 @@ typedef MaybeLocal (*HostImportModuleDynamicallyCallback)( /** * HostInitializeImportMetaObjectCallback is called the first time import.meta - * is accessed for a module. Subsequent access will reuse the same value. + * is accessed for a module. Subsequent access will reuse the same value. The + * callback must not throw. * * The method combines two implementation-defined abstract operations into one: * HostGetImportMetaProperties and HostFinalizeImportMeta. @@ -7326,6 +7293,7 @@ class PromiseRejectMessage { typedef void (*PromiseRejectCallback)(PromiseRejectMessage message); // --- Microtasks Callbacks --- +V8_DEPRECATE_SOON("Use *WithData version.") typedef void (*MicrotasksCompletedCallback)(Isolate*); typedef void (*MicrotasksCompletedCallbackWithData)(Isolate*, void*); typedef void (*MicrotaskCallback)(void* data); @@ -7517,6 +7485,9 @@ typedef bool (*WasmThreadsEnabledCallback)(Local context); typedef Local (*WasmLoadSourceMapCallback)(Isolate* isolate, const char* name); +// --- Callback for checking if WebAssembly Simd is enabled --- +typedef bool (*WasmSimdEnabledCallback)(Local context); + // --- Garbage Collection Callbacks --- /** @@ -7594,6 +7565,7 @@ class V8_EXPORT SharedMemoryStatistics { size_t read_only_space_physical_size_; friend class V8; + friend class internal::ReadOnlyHeap; }; /** @@ -7873,16 +7845,12 @@ enum class MemoryPressureLevel { kNone, kModerate, kCritical }; */ class V8_EXPORT EmbedderHeapTracer { public: + using EmbedderStackState = cppgc::EmbedderStackState; + enum TraceFlags : uint64_t { kNoFlags = 0, kReduceMemory = 1 << 0, - }; - - // Indicator for the stack state of the embedder. - enum EmbedderStackState { - kUnknown, - kNonEmpty, - kEmpty, + kForced = 1 << 2, }; /** @@ -8445,7 +8413,7 @@ class V8_EXPORT Isolate { kOptimizedFunctionWithOneShotBytecode = 71, kRegExpMatchIsTrueishOnNonJSRegExp = 72, kRegExpMatchIsFalseishOnJSRegExp = 73, - kDateGetTimezoneOffset = 74, + kDateGetTimezoneOffset = 74, // Unused. kStringNormalize = 75, kCallSiteAPIGetFunctionSloppyCall = 76, kCallSiteAPIGetThisSloppyCall = 77, @@ -8461,6 +8429,24 @@ class V8_EXPORT Isolate { kDateTimeFormatDateTimeStyle = 87, kBreakIteratorTypeWord = 88, kBreakIteratorTypeLine = 89, + kInvalidatedArrayBufferDetachingProtector = 90, + kInvalidatedArrayConstructorProtector = 91, + kInvalidatedArrayIteratorLookupChainProtector = 92, + kInvalidatedArraySpeciesLookupChainProtector = 93, + kInvalidatedIsConcatSpreadableLookupChainProtector = 94, + kInvalidatedMapIteratorLookupChainProtector = 95, + kInvalidatedNoElementsProtector = 96, + kInvalidatedPromiseHookProtector = 97, + kInvalidatedPromiseResolveLookupChainProtector = 98, + kInvalidatedPromiseSpeciesLookupChainProtector = 99, + kInvalidatedPromiseThenLookupChainProtector = 100, + kInvalidatedRegExpSpeciesLookupChainProtector = 101, + kInvalidatedSetIteratorLookupChainProtector = 102, + kInvalidatedStringIteratorLookupChainProtector = 103, + kInvalidatedStringLengthOverflowLookupChainProtector = 104, + kInvalidatedTypedArraySpeciesLookupChainProtector = 105, + kWasmSimdOpcodes = 106, + kVarRedeclaredCatchBinding = 107, // If you add new values here, you'll also need to update Chromium's: // web_feature.mojom, use_counter_callback.cc, and enums.xml. V8 changes to @@ -8549,17 +8535,6 @@ class V8_EXPORT Isolate { void SetAbortOnUncaughtExceptionCallback( AbortOnUncaughtExceptionCallback callback); - /** - * This specifies the callback to be called when FinalizationRegistries - * are ready to be cleaned up and require FinalizationGroup::Cleanup() - * to be called in a future task. - */ - V8_DEPRECATED( - "FinalizationRegistry cleanup is automatic if " - "HostCleanupFinalizationGroupCallback is not set") - void SetHostCleanupFinalizationGroupCallback( - HostCleanupFinalizationGroupCallback callback); - /** * This specifies the callback called by the upcoming dynamic * import() language feature to load modules. @@ -9374,6 +9349,8 @@ class V8_EXPORT Isolate { void SetWasmLoadSourceMapCallback(WasmLoadSourceMapCallback callback); + void SetWasmSimdEnabledCallback(WasmSimdEnabledCallback callback); + /** * Check if V8 is dead and therefore unusable. This is the case after * fatal errors such as out-of-memory situations. @@ -9512,7 +9489,6 @@ class V8_EXPORT Isolate { internal::Address* GetDataFromSnapshotOnce(size_t index); void ReportExternalAllocationLimitReached(); - void CheckMemoryPressure(); }; class V8_EXPORT StartupData { @@ -9601,7 +9577,8 @@ class V8_EXPORT V8 { V8_INLINE static bool Initialize() { const int kBuildConfiguration = (internal::PointerCompressionIsEnabled() ? kPointerCompression : 0) | - (internal::SmiValuesAre31Bits() ? k31BitSmis : 0); + (internal::SmiValuesAre31Bits() ? k31BitSmis : 0) | + (internal::HeapSandboxIsEnabled() ? kHeapSandbox : 0); return Initialize(kBuildConfiguration); } @@ -9740,6 +9717,7 @@ class V8_EXPORT V8 { enum BuildConfigurationFeatures { kPointerCompression = 1 << 0, k31BitSmis = 1 << 1, + kHeapSandbox = 1 << 2, }; /** @@ -11381,7 +11359,9 @@ void* Object::GetAlignedPointerFromInternalField(int index) { instance_type == I::kJSApiObjectType || instance_type == I::kJSSpecialApiObjectType)) { int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index); - return I::ReadRawField(obj, offset); + internal::Isolate* isolate = I::GetIsolateForHeapSandbox(obj); + A value = I::ReadExternalPointerField(isolate, obj, offset); + return reinterpret_cast(value); } #endif return SlowGetAlignedPointerFromInternalField(index); @@ -11411,7 +11391,9 @@ String::ExternalStringResource* String::GetExternalStringResource() const { ExternalStringResource* result; if (I::IsExternalTwoByteString(I::GetInstanceType(obj))) { - void* value = I::ReadRawField(obj, I::kStringResourceOffset); + internal::Isolate* isolate = I::GetIsolateForHeapSandbox(obj); + A value = + I::ReadExternalPointerField(isolate, obj, I::kStringResourceOffset); result = reinterpret_cast(value); } else { result = GetExternalStringResourceSlow(); @@ -11433,8 +11415,10 @@ String::ExternalStringResourceBase* String::GetExternalStringResourceBase( ExternalStringResourceBase* resource; if (type == I::kExternalOneByteRepresentationTag || type == I::kExternalTwoByteRepresentationTag) { - void* value = I::ReadRawField(obj, I::kStringResourceOffset); - resource = static_cast(value); + internal::Isolate* isolate = I::GetIsolateForHeapSandbox(obj); + A value = + I::ReadExternalPointerField(isolate, obj, I::kStringResourceOffset); + resource = reinterpret_cast(value); } else { resource = GetExternalStringResourceBaseSlow(encoding_out); } @@ -11950,7 +11934,6 @@ MaybeLocal Isolate::GetDataFromSnapshotOnce(size_t index) { int64_t Isolate::AdjustAmountOfExternalAllocatedMemory( int64_t change_in_bytes) { typedef internal::Internals I; - constexpr int64_t kMemoryReducerActivationLimit = 32 * 1024 * 1024; int64_t* external_memory = reinterpret_cast( reinterpret_cast(this) + I::kExternalMemoryOffset); int64_t* external_memory_limit = reinterpret_cast( @@ -11973,14 +11956,6 @@ int64_t Isolate::AdjustAmountOfExternalAllocatedMemory( if (change_in_bytes <= 0) return *external_memory; - int64_t allocation_diff_since_last_mc = static_cast( - static_cast(*external_memory) - - static_cast(*external_memory_low_since_mc)); - // Only check memory pressure and potentially trigger GC if the amount of - // external memory increased. - if (allocation_diff_since_last_mc > kMemoryReducerActivationLimit) { - CheckMemoryPressure(); - } if (amount > *external_memory_limit) { ReportExternalAllocationLimitReached(); } @@ -12022,7 +11997,9 @@ void* Context::GetAlignedPointerFromEmbedderData(int index) { I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); int value_offset = I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index); - return I::ReadRawField(embedder_data, value_offset); + internal::Isolate* isolate = I::GetIsolateForHeapSandbox(ctx); + return reinterpret_cast( + I::ReadExternalPointerField(isolate, embedder_data, value_offset)); #else return SlowGetAlignedPointerFromEmbedderData(index); #endif diff --git a/deps/v8/include/v8config.h b/deps/v8/include/v8config.h index 40d23c35c186e4..9825232d6a10ac 100644 --- a/deps/v8/include/v8config.h +++ b/deps/v8/include/v8config.h @@ -405,6 +405,15 @@ #endif +#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 6) +# define V8_ENUM_DEPRECATED(message) +# define V8_ENUM_DEPRECATE_SOON(message) +#else +# define V8_ENUM_DEPRECATED(message) V8_DEPRECATED(message) +# define V8_ENUM_DEPRECATE_SOON(message) V8_DEPRECATE_SOON(message) +#endif + + // A macro to provide the compiler with branch prediction information. #if V8_HAS_BUILTIN_EXPECT # define V8_UNLIKELY(condition) (__builtin_expect(!!(condition), 0)) diff --git a/deps/v8/infra/mb/mb_config.pyl b/deps/v8/infra/mb/mb_config.pyl index 8677333c2f8cdb..d4abcf89eb15e9 100644 --- a/deps/v8/infra/mb/mb_config.pyl +++ b/deps/v8/infra/mb/mb_config.pyl @@ -78,6 +78,7 @@ # Sanitizers. 'V8 Linux64 ASAN': 'release_x64_asan', 'V8 Linux64 TSAN - builder': 'release_x64_tsan', + 'V8 Linux - arm64 - sim - CFI': 'release_simulate_arm64_cfi', 'V8 Linux - arm64 - sim - MSAN': 'release_simulate_arm64_msan', # Misc. 'V8 Linux gcc': 'release_x86_gcc', @@ -98,6 +99,7 @@ 'V8 Linux64 - gcov coverage': 'release_x64_gcc_coverage', 'V8 Linux - predictable': 'release_x86_predictable', 'V8 Linux - full debug': 'full_debug_x86', + 'V8 Mac64 - full debug': 'full_debug_x64', 'V8 Random Deopt Fuzzer - debug': 'debug_x64', }, 'client.v8.clusterfuzz': { @@ -251,6 +253,7 @@ 'v8_mac64_rel_ng': 'release_x64_trybot', 'v8_mac64_dbg': 'debug_x64', 'v8_mac64_dbg_ng': 'debug_x64', + 'v8_mac64_compile_full_dbg_ng': 'full_debug_x64', 'v8_mac64_asan_rel': 'release_x64_asan_no_lsan', 'v8_linux_arm_rel_ng': 'release_simulate_arm_trybot', 'v8_linux_arm_lite_rel_ng': 'release_simulate_arm_lite_trybot', @@ -258,6 +261,7 @@ 'v8_linux_arm_armv8a_rel': 'release_simulate_arm_trybot', 'v8_linux_arm_armv8a_dbg': 'debug_simulate_arm', 'v8_linux_arm64_rel_ng': 'release_simulate_arm64_trybot', + 'v8_linux_arm64_cfi_rel_ng' : 'release_simulate_arm64_cfi', 'v8_linux_arm64_dbg': 'debug_simulate_arm64', 'v8_linux_arm64_gc_stress_dbg': 'debug_simulate_arm64', 'v8_linux_mipsel_compile_rel': 'release_simulate_mipsel', @@ -363,6 +367,8 @@ 'release_trybot', 'simulate_arm', 'v8_enable_lite_mode'], 'release_simulate_arm64': [ 'release_bot', 'simulate_arm64'], + 'release_simulate_arm64_cfi': [ + 'release_bot', 'simulate_arm64', 'v8_control_flow_integrity'], 'release_simulate_arm64_pointer_compression': [ # TODO(v8:v7703): Make pointer compression bots testing non pointer # compression mode while pointer compression is temporarily enabled @@ -452,7 +458,7 @@ 'release_x64_fuchsia_trybot': [ 'release_trybot', 'x64', 'fuchsia'], 'release_x64_gcc_coverage': [ - 'release_bot', 'x64', 'coverage', 'gcc', 'no_custom_libcxx', + 'release_bot_no_goma', 'x64', 'coverage', 'gcc', 'no_custom_libcxx', 'no_sysroot'], 'release_x64_ios_simulator': [ 'release_bot', 'x64', 'ios_simulator'], @@ -502,7 +508,7 @@ 'debug_x64_fuchsia': [ 'debug_bot', 'x64', 'fuchsia'], 'debug_x64_gcc': [ - 'debug_bot', 'x64', 'gcc', 'v8_check_header_includes'], + 'debug_bot_no_goma', 'x64', 'gcc', 'v8_check_header_includes'], 'debug_x64_header_includes': [ 'debug_bot', 'x64', 'v8_check_header_includes'], 'debug_x64_minimal_symbols': [ @@ -513,6 +519,8 @@ 'debug_trybot', 'x64'], 'debug_x64_trybot_custom': [ 'debug_trybot', 'x64', 'v8_snapshot_custom'], + 'full_debug_x64': [ + 'debug_bot', 'x64', 'v8_full_debug'], # Debug configs for x86. 'debug_x86': [ @@ -532,9 +540,9 @@ 'release_x86': [ 'release_bot', 'x86'], 'release_x86_gcc': [ - 'release_bot', 'x86', 'gcc', 'v8_check_header_includes'], + 'release_bot_no_goma', 'x86', 'gcc', 'v8_check_header_includes'], 'release_x86_gcc_minimal_symbols': [ - 'release_bot', 'x86', 'gcc', 'minimal_symbols', + 'release_bot_no_goma', 'x86', 'gcc', 'minimal_symbols', 'v8_check_header_includes'], 'release_x86_gcmole': [ 'release_bot', 'x86', 'gcmole'], @@ -623,6 +631,12 @@ 'v8_optimized_debug'], }, + 'debug_bot_no_goma': { + 'mixins': [ + 'debug', 'shared', 'no_goma', 'v8_enable_slow_dchecks', + 'v8_optimized_debug'], + }, + 'debug_trybot': { 'mixins': ['debug_bot', 'minimal_symbols'], }, @@ -776,6 +790,10 @@ 'gn_args': 'v8_correctness_fuzzer=true v8_multi_arch_build=true', }, + 'v8_control_flow_integrity' : { + 'gn_args': 'v8_control_flow_integrity=true', + }, + 'v8_enable_lite_mode': { 'gn_args': 'v8_enable_lite_mode=true', }, diff --git a/deps/v8/infra/testing/builders.pyl b/deps/v8/infra/testing/builders.pyl index 6c3379b5cbc34e..72f739487ccec3 100644 --- a/deps/v8/infra/testing/builders.pyl +++ b/deps/v8/infra/testing/builders.pyl @@ -310,12 +310,15 @@ 'os': 'Ubuntu-16.04', }, 'tests': [ + # Infra staging. + {'name': 'v8testing', 'variant': 'infra_staging', 'shards': 2}, + # Native context independent code. + {'name': 'v8testing', 'variant': 'nci'}, # Stress sampling. {'name': 'mjsunit', 'variant': 'stress_sampling'}, {'name': 'webkit', 'variant': 'stress_sampling'}, - # Infra staging. - {'name': 'test262', 'variant': 'infra_staging', 'shards': 2}, - {'name': 'v8testing', 'variant': 'infra_staging', 'shards': 2}, + # Stress snapshot. + {'name': 'mjsunit', 'variant': 'stress_snapshot'}, ], }, 'v8_linux64_msan_rel': { @@ -481,6 +484,15 @@ {'name': 'v8testing', 'variant': 'trusted', 'shards': 5}, ], }, + 'v8_linux_arm64_cfi_rel_ng_triggered': { + 'swarming_dimensions' : { + 'os': 'Ubuntu-16.04', + }, + 'tests': [ + {'name': 'test262', 'variant': 'default', 'shards': 3}, + {'name': 'v8testing', 'shards': 4}, + ], + }, 'v8_linux64_arm64_pointer_compression_rel_ng_triggered': { 'swarming_dimensions' : { 'os': 'Ubuntu-16.04', @@ -679,6 +691,15 @@ }, ], }, + 'V8 Linux - arm64 - sim - CFI': { + 'swarming_dimensions': { + 'os': 'Ubuntu-16.04', + }, + 'tests': [ + {'name': 'test262', 'variant': 'default', 'shards': 3}, + {'name': 'v8testing', 'shards': 4}, + ], + }, 'V8 Linux - arm64 - sim - MSAN': { 'swarming_dimensions': { 'os': 'Ubuntu-16.04', @@ -941,9 +962,13 @@ 'tests': [ # Infra staging. {'name': 'v8testing', 'variant': 'infra_staging', 'shards': 2}, + # Native context independent code. + {'name': 'v8testing', 'variant': 'nci'}, # Stress sampling. - {'name': 'mjsunit', 'variant': 'stress_sampling', 'shards': 1}, - {'name': 'webkit', 'variant': 'stress_sampling', 'shards': 1}, + {'name': 'mjsunit', 'variant': 'stress_sampling'}, + {'name': 'webkit', 'variant': 'stress_sampling'}, + # Stress snapshot. + {'name': 'mjsunit', 'variant': 'stress_snapshot'}, ], }, 'V8 Linux64 - debug - perfetto': { @@ -965,10 +990,14 @@ }, 'tests': [ # Infra staging. - {'name': 'v8testing', 'variant': 'infra_staging', 'shards': 1}, + {'name': 'v8testing', 'variant': 'infra_staging'}, + # Native context independent code. + {'name': 'v8testing', 'variant': 'nci'}, # Stress sampling. - {'name': 'mjsunit', 'variant': 'stress_sampling', 'shards': 1}, - {'name': 'webkit', 'variant': 'stress_sampling', 'shards': 1}, + {'name': 'mjsunit', 'variant': 'stress_sampling'}, + {'name': 'webkit', 'variant': 'stress_sampling'}, + # Stress snapshot. + {'name': 'mjsunit', 'variant': 'stress_snapshot'}, ], }, 'V8 Linux64 - gcov coverage': { diff --git a/deps/v8/src/DEPS b/deps/v8/src/DEPS index 772ad53b326066..abea95558da2c2 100644 --- a/deps/v8/src/DEPS +++ b/deps/v8/src/DEPS @@ -12,15 +12,22 @@ include_rules = [ "+src/heap/embedder-tracing.h", "+src/heap/factory.h", "+src/heap/factory-inl.h", + # TODO(v8:10496): Don't expose so much (through transitive includes) outside + # of heap/. "+src/heap/heap.h", "+src/heap/heap-inl.h", "+src/heap/heap-write-barrier-inl.h", "+src/heap/heap-write-barrier.h", "+src/heap/local-heap.h", + # TODO(v8:10496): Don't expose memory chunk outside of heap/. + "+src/heap/memory-chunk.h", + "+src/heap/memory-chunk-inl.h", "+src/heap/off-thread-factory-inl.h", "+src/heap/off-thread-factory.h", + "+src/heap/off-thread-heap.h", "+src/heap/read-only-heap-inl.h", "+src/heap/read-only-heap.h", + "+src/heap/safepoint.h", "-src/inspector", "-src/interpreter", "+src/interpreter/bytecode-array-accessor.h", @@ -54,4 +61,7 @@ specific_include_rules = { "+include/libplatform/v8-tracing.h", "+perfetto/tracing.h" ], + "builtins-trace\.cc": [ + "+protos/perfetto", + ], } diff --git a/deps/v8/src/api/api-arguments.h b/deps/v8/src/api/api-arguments.h index 794681b71d0e60..18690b5db2b6d7 100644 --- a/deps/v8/src/api/api-arguments.h +++ b/deps/v8/src/api/api-arguments.h @@ -160,11 +160,9 @@ class FunctionCallbackArguments static const int kIsolateIndex = T::kIsolateIndex; static const int kNewTargetIndex = T::kNewTargetIndex; - FunctionCallbackArguments(internal::Isolate* isolate, internal::Object data, - internal::HeapObject callee, - internal::Object holder, - internal::HeapObject new_target, - internal::Address* argv, int argc); + FunctionCallbackArguments(Isolate* isolate, Object data, HeapObject callee, + Object holder, HeapObject new_target, Address* argv, + int argc); /* * The following Call function wraps the calling of all callbacks to handle diff --git a/deps/v8/src/api/api-inl.h b/deps/v8/src/api/api-inl.h index 0d2ad2f8a0f8ce..f686424286d8fe 100644 --- a/deps/v8/src/api/api-inl.h +++ b/deps/v8/src/api/api-inl.h @@ -86,7 +86,6 @@ MAKE_TO_LOCAL(ToLocal, JSArrayBufferView, ArrayBufferView) MAKE_TO_LOCAL(ToLocal, JSDataView, DataView) MAKE_TO_LOCAL(ToLocal, JSTypedArray, TypedArray) MAKE_TO_LOCAL(ToLocalShared, JSArrayBuffer, SharedArrayBuffer) -MAKE_TO_LOCAL(ToLocal, JSFinalizationRegistry, FinalizationGroup) TYPED_ARRAYS(MAKE_TO_LOCAL_TYPED_ARRAY) diff --git a/deps/v8/src/api/api.cc b/deps/v8/src/api/api.cc index 1b59f2cf6457b2..93780bceec4186 100644 --- a/deps/v8/src/api/api.cc +++ b/deps/v8/src/api/api.cc @@ -28,6 +28,7 @@ #include "src/codegen/compiler.h" #include "src/codegen/cpu-features.h" #include "src/common/assert-scope.h" +#include "src/common/external-pointer.h" #include "src/common/globals.h" #include "src/compiler-dispatcher/compiler-dispatcher.h" #include "src/date/date.h" @@ -96,10 +97,8 @@ #include "src/regexp/regexp-utils.h" #include "src/runtime/runtime.h" #include "src/snapshot/code-serializer.h" -#include "src/snapshot/partial-serializer.h" -#include "src/snapshot/read-only-serializer.h" #include "src/snapshot/snapshot.h" -#include "src/snapshot/startup-serializer.h" +#include "src/snapshot/startup-serializer.h" // For SerializedHandleChecker. #include "src/strings/char-predicates-inl.h" #include "src/strings/string-hasher.h" #include "src/strings/unicode-inl.h" @@ -328,6 +327,7 @@ class CallDepthScope { bool CheckKeptObjectsClearedAfterMicrotaskCheckpoint( i::MicrotaskQueue* microtask_queue) { bool did_perform_microtask_checkpoint = + isolate_->thread_local_top()->CallDepthIsZero() && do_callback && microtask_queue && microtask_queue->microtasks_policy() == MicrotasksPolicy::kAuto; return !did_perform_microtask_checkpoint || @@ -598,7 +598,6 @@ SnapshotCreator::SnapshotCreator(Isolate* isolate, const intptr_t* external_references, StartupData* existing_snapshot) { SnapshotCreatorData* data = new SnapshotCreatorData(isolate); - data->isolate_ = isolate; i::Isolate* internal_isolate = reinterpret_cast(isolate); internal_isolate->set_array_buffer_allocator(&data->allocator_); internal_isolate->set_api_external_references(external_references); @@ -733,8 +732,11 @@ StartupData SnapshotCreator::CreateBlob( DCHECK(!data->created_); DCHECK(!data->default_context_.IsEmpty()); - int num_additional_contexts = static_cast(data->contexts_.Size()); + const int num_additional_contexts = static_cast(data->contexts_.Size()); + const int num_contexts = num_additional_contexts + 1; // The default context. + // Create and store lists of embedder-provided data needed during + // serialization. { i::HandleScope scope(isolate); // Convert list of context-independent data to FixedArray. @@ -773,48 +775,15 @@ StartupData SnapshotCreator::CreateBlob( isolate->heap()->CompactWeakArrayLists(internal::AllocationType::kOld); } - if (function_code_handling == FunctionCodeHandling::kClear) { - // Clear out re-compilable data from all shared function infos. Any - // JSFunctions using these SFIs will have their code pointers reset by the - // partial serializer. - // - // We have to iterate the heap and collect handles to each clearable SFI, - // before we disable allocation, since we have to allocate UncompiledDatas - // to be able to recompile them. - // - // Compiled irregexp code is also flushed by collecting and clearing any - // seen JSRegExp objects. - i::HandleScope scope(isolate); - std::vector> sfis_to_clear; - - { // Heap allocation is disallowed within this scope. - i::HeapObjectIterator heap_iterator(isolate->heap()); - for (i::HeapObject current_obj = heap_iterator.Next(); - !current_obj.is_null(); current_obj = heap_iterator.Next()) { - if (current_obj.IsSharedFunctionInfo()) { - i::SharedFunctionInfo shared = - i::SharedFunctionInfo::cast(current_obj); - if (shared.CanDiscardCompiled()) { - sfis_to_clear.emplace_back(shared, isolate); - } - } else if (current_obj.IsJSRegExp()) { - i::JSRegExp regexp = i::JSRegExp::cast(current_obj); - if (regexp.HasCompiledCode()) { - regexp.DiscardCompiledCodeForSerialization(); - } - } - } - } - - // Must happen after heap iteration since SFI::DiscardCompiled may allocate. - for (i::Handle shared : sfis_to_clear) { - i::SharedFunctionInfo::DiscardCompiled(isolate, shared); - } - } + i::Snapshot::ClearReconstructableDataForSerialization( + isolate, function_code_handling == FunctionCodeHandling::kClear); i::DisallowHeapAllocation no_gc_from_here_on; - int num_contexts = num_additional_contexts + 1; + // Create a vector with all contexts and clear associated Persistent fields. + // Note these contexts may be dead after calling Clear(), but will not be + // collected until serialization completes and the DisallowHeapAllocation + // scope above goes out of scope. std::vector contexts; contexts.reserve(num_contexts); { @@ -834,82 +803,19 @@ StartupData SnapshotCreator::CreateBlob( i::SerializedHandleChecker handle_checker(isolate, &contexts); CHECK(handle_checker.CheckGlobalAndEternalHandles()); - i::HeapObjectIterator heap_iterator(isolate->heap()); - for (i::HeapObject current_obj = heap_iterator.Next(); !current_obj.is_null(); - current_obj = heap_iterator.Next()) { - if (current_obj.IsJSFunction()) { - i::JSFunction fun = i::JSFunction::cast(current_obj); - - // Complete in-object slack tracking for all functions. - fun.CompleteInobjectSlackTrackingIfActive(); - - // Also, clear out feedback vectors, or any optimized code. - // Note that checking for fun.IsOptimized() || fun.IsInterpreted() is not - // sufficient because the function can have a feedback vector even if it - // is not compiled (e.g. when the bytecode was flushed). On the other - // hand, only checking for the feedback vector is not sufficient because - // there can be multiple functions sharing the same feedback vector. So we - // need all these checks. - if (fun.IsOptimized() || fun.IsInterpreted() || - !fun.raw_feedback_cell().value().IsUndefined()) { - fun.raw_feedback_cell().set_value( - i::ReadOnlyRoots(isolate).undefined_value()); - fun.set_code(isolate->builtins()->builtin(i::Builtins::kCompileLazy)); - } - if (function_code_handling == FunctionCodeHandling::kClear) { - DCHECK(fun.shared().HasWasmExportedFunctionData() || - fun.shared().HasBuiltinId() || fun.shared().IsApiFunction() || - fun.shared().HasUncompiledDataWithoutPreparseData()); - } - } + // Create a vector with all embedder fields serializers. + std::vector embedder_fields_serializers; + embedder_fields_serializers.reserve(num_contexts); + embedder_fields_serializers.push_back( + data->default_embedder_fields_serializer_); + for (int i = 0; i < num_additional_contexts; i++) { + embedder_fields_serializers.push_back( + data->embedder_fields_serializers_[i]); } - i::ReadOnlySerializer read_only_serializer(isolate); - read_only_serializer.SerializeReadOnlyRoots(); - - i::StartupSerializer startup_serializer(isolate, &read_only_serializer); - startup_serializer.SerializeStrongReferences(); - - // Serialize each context with a new partial serializer. - std::vector context_snapshots; - context_snapshots.reserve(num_contexts); - - // TODO(6593): generalize rehashing, and remove this flag. - bool can_be_rehashed = true; - - for (int i = 0; i < num_contexts; i++) { - bool is_default_context = i == 0; - i::PartialSerializer partial_serializer( - isolate, &startup_serializer, - is_default_context ? data->default_embedder_fields_serializer_ - : data->embedder_fields_serializers_[i - 1]); - partial_serializer.Serialize(&contexts[i], !is_default_context); - can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed(); - context_snapshots.push_back(new i::SnapshotData(&partial_serializer)); - } - - startup_serializer.SerializeWeakReferencesAndDeferred(); - can_be_rehashed = can_be_rehashed && startup_serializer.can_be_rehashed(); - - startup_serializer.CheckNoDirtyFinalizationRegistries(); - - read_only_serializer.FinalizeSerialization(); - can_be_rehashed = can_be_rehashed && read_only_serializer.can_be_rehashed(); - - i::SnapshotData read_only_snapshot(&read_only_serializer); - i::SnapshotData startup_snapshot(&startup_serializer); - StartupData result = - i::Snapshot::CreateSnapshotBlob(&startup_snapshot, &read_only_snapshot, - context_snapshots, can_be_rehashed); - - // Delete heap-allocated context snapshot instances. - for (const auto context_snapshot : context_snapshots) { - delete context_snapshot; - } data->created_ = true; - - DCHECK(i::Snapshot::VerifyChecksum(&result)); - return result; + return i::Snapshot::Create(isolate, &contexts, embedder_fields_serializers, + no_gc_from_here_on); } bool StartupData::CanBeRehashed() const { @@ -1341,21 +1247,25 @@ void Context::SetEmbedderData(int index, v8::Local value) { void* Context::SlowGetAlignedPointerFromEmbedderData(int index) { const char* location = "v8::Context::GetAlignedPointerFromEmbedderData()"; - HandleScope handle_scope(GetIsolate()); + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + i::HandleScope handle_scope(isolate); i::Handle data = EmbedderDataFor(this, index, false, location); if (data.is_null()) return nullptr; void* result; - Utils::ApiCheck(i::EmbedderDataSlot(*data, index).ToAlignedPointer(&result), - location, "Pointer is not aligned"); + Utils::ApiCheck( + i::EmbedderDataSlot(*data, index).ToAlignedPointer(isolate, &result), + location, "Pointer is not aligned"); return result; } void Context::SetAlignedPointerInEmbedderData(int index, void* value) { const char* location = "v8::Context::SetAlignedPointerInEmbedderData()"; + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); i::Handle data = EmbedderDataFor(this, index, true, location); - bool ok = i::EmbedderDataSlot(*data, index).store_aligned_pointer(value); + bool ok = + i::EmbedderDataSlot(*data, index).store_aligned_pointer(isolate, value); Utils::ApiCheck(ok, location, "Pointer is not aligned"); DCHECK_EQ(value, GetAlignedPointerFromEmbedderData(index)); } @@ -3776,6 +3686,12 @@ void v8::debug::AccessorPair::CheckCast(Value* that) { "Value is not a debug::AccessorPair"); } +void v8::debug::WasmValue::CheckCast(Value* that) { + i::Handle obj = Utils::OpenHandle(that); + Utils::ApiCheck(obj->IsWasmValue(), "v8::WasmValue::Cast", + "Value is not a debug::WasmValue"); +} + v8::BackingStore::~BackingStore() { auto i_this = reinterpret_cast(this); i_this->~BackingStore(); // manually call internal destructor @@ -5494,7 +5410,9 @@ String::ExternalStringResource* String::GetExternalStringResourceSlow() const { } if (i::StringShape(str).IsExternalTwoByte()) { - void* value = I::ReadRawField(str.ptr(), I::kStringResourceOffset); + internal::Isolate* isolate = I::GetIsolateForHeapSandbox(str.ptr()); + internal::Address value = I::ReadExternalPointerField( + isolate, str.ptr(), I::kStringResourceOffset); return reinterpret_cast(value); } return nullptr; @@ -5516,8 +5434,10 @@ String::ExternalStringResourceBase* String::GetExternalStringResourceBaseSlow( *encoding_out = static_cast(type & I::kStringEncodingMask); if (i::StringShape(str).IsExternalOneByte() || i::StringShape(str).IsExternalTwoByte()) { - void* value = I::ReadRawField(string, I::kStringResourceOffset); - resource = static_cast(value); + internal::Isolate* isolate = I::GetIsolateForHeapSandbox(string); + internal::Address value = + I::ReadExternalPointerField(isolate, string, I::kStringResourceOffset); + resource = reinterpret_cast(value); } return resource; } @@ -5635,7 +5555,7 @@ void* v8::Object::SlowGetAlignedPointerFromInternalField(int index) { if (!InternalFieldOK(obj, index, location)) return nullptr; void* result; Utils::ApiCheck(i::EmbedderDataSlot(i::JSObject::cast(*obj), index) - .ToAlignedPointer(&result), + .ToAlignedPointer(obj->GetIsolate(), &result), location, "Unaligned pointer"); return result; } @@ -5645,7 +5565,7 @@ void v8::Object::SetAlignedPointerInInternalField(int index, void* value) { const char* location = "v8::Object::SetAlignedPointerInInternalField()"; if (!InternalFieldOK(obj, index, location)) return; Utils::ApiCheck(i::EmbedderDataSlot(i::JSObject::cast(*obj), index) - .store_aligned_pointer(value), + .store_aligned_pointer(obj->GetIsolate(), value), location, "Unaligned pointer"); DCHECK_EQ(value, GetAlignedPointerFromInternalField(index)); } @@ -5664,9 +5584,9 @@ void v8::Object::SetAlignedPointerInInternalFields(int argc, int indices[], return; } void* value = values[i]; - Utils::ApiCheck( - i::EmbedderDataSlot(js_obj, index).store_aligned_pointer(value), - location, "Unaligned pointer"); + Utils::ApiCheck(i::EmbedderDataSlot(js_obj, index) + .store_aligned_pointer(obj->GetIsolate(), value), + location, "Unaligned pointer"); DCHECK_EQ(value, GetAlignedPointerFromInternalField(index)); } } @@ -5707,6 +5627,15 @@ bool v8::V8::Initialize(const int build_config) { kEmbedderSmiValueSize, internal::kSmiValueSize); } + const bool kEmbedderHeapSandbox = (build_config & kHeapSandbox) != 0; + if (kEmbedderHeapSandbox != V8_HEAP_SANDBOX_BOOL) { + FATAL( + "Embedder-vs-V8 build configuration mismatch. On embedder side " + "heap sandbox is %s while on V8 side it's %s.", + kEmbedderHeapSandbox ? "ENABLED" : "DISABLED", + V8_HEAP_SANDBOX_BOOL ? "ENABLED" : "DISABLED"); + } + i::V8::Initialize(); return true; } @@ -5824,17 +5753,7 @@ void v8::V8::InitializeExternalStartupDataFromFile(const char* snapshot_blob) { const char* v8::V8::GetVersion() { return i::Version::GetVersion(); } void V8::GetSharedMemoryStatistics(SharedMemoryStatistics* statistics) { -#ifdef V8_SHARED_RO_HEAP - i::ReadOnlySpace* ro_space = i::ReadOnlyHeap::Instance()->read_only_space(); - statistics->read_only_space_size_ = ro_space->CommittedMemory(); - statistics->read_only_space_used_size_ = ro_space->SizeOfObjects(); - statistics->read_only_space_physical_size_ = - ro_space->CommittedPhysicalMemory(); -#else - statistics->read_only_space_size_ = 0; - statistics->read_only_space_used_size_ = 0; - statistics->read_only_space_physical_size_ = 0; -#endif // V8_SHARED_RO_HEAP + i::ReadOnlyHeap::PopulateReadOnlySpaceStatistics(statistics); } template @@ -7247,8 +7166,10 @@ MaybeLocal Proxy::New(Local context, Local local_target, } CompiledWasmModule::CompiledWasmModule( - std::shared_ptr native_module) - : native_module_(std::move(native_module)) { + std::shared_ptr native_module, + const char* source_url, size_t url_length) + : native_module_(std::move(native_module)), + source_url_(source_url, url_length) { CHECK_NOT_NULL(native_module_); } @@ -7269,7 +7190,13 @@ MemorySpan CompiledWasmModule::GetWireBytesRef() { CompiledWasmModule WasmModuleObject::GetCompiledModule() { i::Handle obj = i::Handle::cast(Utils::OpenHandle(this)); - return Utils::Convert(obj->shared_native_module()); + auto source_url = i::String::cast(obj->script().source_url()); + int length; + std::unique_ptr cstring = source_url.ToCString( + i::DISALLOW_NULLS, i::FAST_STRING_TRAVERSAL, &length); + i::Handle url(source_url, obj->GetIsolate()); + return CompiledWasmModule(std::move(obj->shared_native_module()), + cstring.get(), length); } MaybeLocal WasmModuleObject::FromCompiledModule( @@ -7277,7 +7204,8 @@ MaybeLocal WasmModuleObject::FromCompiledModule( i::Isolate* i_isolate = reinterpret_cast(isolate); i::Handle module_object = i_isolate->wasm_engine()->ImportNativeModule( - i_isolate, Utils::Open(compiled_module)); + i_isolate, compiled_module.native_module_, + i::VectorOf(compiled_module.source_url())); return Local::Cast( Utils::ToLocal(i::Handle::cast(module_object))); } @@ -8059,12 +7987,6 @@ void Isolate::ReportExternalAllocationLimitReached() { heap->ReportExternalMemoryPressure(); } -void Isolate::CheckMemoryPressure() { - i::Heap* heap = reinterpret_cast(this)->heap(); - if (heap->gc_state() != i::Heap::NOT_IN_GC) return; - heap->CheckMemoryPressure(); -} - HeapProfiler* Isolate::GetHeapProfiler() { i::HeapProfiler* heap_profiler = reinterpret_cast(this)->heap_profiler(); @@ -8373,29 +8295,6 @@ void Isolate::SetAbortOnUncaughtExceptionCallback( isolate->SetAbortOnUncaughtExceptionCallback(callback); } -void Isolate::SetHostCleanupFinalizationGroupCallback( - HostCleanupFinalizationGroupCallback callback) { - i::Isolate* isolate = reinterpret_cast(this); - isolate->SetHostCleanupFinalizationGroupCallback(callback); -} - -Maybe FinalizationGroup::Cleanup( - Local finalization_group) { - i::Handle fr = - Utils::OpenHandle(*finalization_group); - i::Isolate* isolate = fr->native_context().GetIsolate(); - i::Handle i_context(fr->native_context(), isolate); - Local context = Utils::ToLocal(i_context); - ENTER_V8(isolate, context, FinalizationGroup, Cleanup, Nothing(), - i::HandleScope); - i::Handle callback(fr->cleanup(), isolate); - fr->set_scheduled_for_cleanup(false); - has_pending_exception = - i::JSFinalizationRegistry::Cleanup(isolate, fr, callback).IsNothing(); - RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); - return Just(true); -} - void Isolate::SetHostImportModuleDynamicallyCallback( HostImportModuleDynamicallyCallback callback) { i::Isolate* isolate = reinterpret_cast(this); @@ -8730,11 +8629,7 @@ void Isolate::EnqueueMicrotask(Local v8_function) { void Isolate::EnqueueMicrotask(MicrotaskCallback callback, void* data) { i::Isolate* isolate = reinterpret_cast(this); - i::HandleScope scope(isolate); - i::Handle microtask = isolate->factory()->NewCallbackTask( - isolate->factory()->NewForeign(reinterpret_cast(callback)), - isolate->factory()->NewForeign(reinterpret_cast(data))); - isolate->default_microtask_queue()->EnqueueMicrotask(*microtask); + isolate->default_microtask_queue()->EnqueueMicrotask(this, callback, data); } void Isolate::SetMicrotasksPolicy(MicrotasksPolicy policy) { @@ -9011,6 +8906,9 @@ CALLBACK_SETTER(WasmThreadsEnabledCallback, WasmThreadsEnabledCallback, CALLBACK_SETTER(WasmLoadSourceMapCallback, WasmLoadSourceMapCallback, wasm_load_source_map_callback) +CALLBACK_SETTER(WasmSimdEnabledCallback, WasmSimdEnabledCallback, + wasm_simd_enabled_callback) + void Isolate::AddNearHeapLimitCallback(v8::NearHeapLimitCallback callback, void* data) { i::Isolate* isolate = reinterpret_cast(this); @@ -9138,6 +9036,7 @@ void v8::Isolate::LocaleConfigurationChangeNotification() { #ifdef V8_INTL_SUPPORT i_isolate->ResetDefaultLocale(); + i_isolate->ClearCachedIcuObjects(); #endif // V8_INTL_SUPPORT } @@ -9256,6 +9155,9 @@ DEFINE_ERROR(RangeError, range_error) DEFINE_ERROR(ReferenceError, reference_error) DEFINE_ERROR(SyntaxError, syntax_error) DEFINE_ERROR(TypeError, type_error) +DEFINE_ERROR(WasmCompileError, wasm_compile_error) +DEFINE_ERROR(WasmLinkError, wasm_link_error) +DEFINE_ERROR(WasmRuntimeError, wasm_runtime_error) DEFINE_ERROR(Error, error) #undef DEFINE_ERROR @@ -9767,6 +9669,37 @@ debug::WasmScript* debug::WasmScript::Cast(debug::Script* script) { return static_cast(script); } +debug::WasmScript::DebugSymbolsType debug::WasmScript::GetDebugSymbolType() + const { + i::Handle script = Utils::OpenHandle(this); + DCHECK_EQ(i::Script::TYPE_WASM, script->type()); + switch (script->wasm_native_module()->module()->debug_symbols.type) { + case i::wasm::WasmDebugSymbols::Type::None: + return debug::WasmScript::DebugSymbolsType::None; + case i::wasm::WasmDebugSymbols::Type::EmbeddedDWARF: + return debug::WasmScript::DebugSymbolsType::EmbeddedDWARF; + case i::wasm::WasmDebugSymbols::Type::ExternalDWARF: + return debug::WasmScript::DebugSymbolsType::ExternalDWARF; + case i::wasm::WasmDebugSymbols::Type::SourceMap: + return debug::WasmScript::DebugSymbolsType::SourceMap; + } +} + +MemorySpan debug::WasmScript::ExternalSymbolsURL() const { + i::Handle script = Utils::OpenHandle(this); + DCHECK_EQ(i::Script::TYPE_WASM, script->type()); + + const i::wasm::WasmDebugSymbols& symbols = + script->wasm_native_module()->module()->debug_symbols; + if (symbols.external_url.is_empty()) return {}; + + internal::wasm::ModuleWireBytes wire_bytes( + script->wasm_native_module()->wire_bytes()); + i::wasm::WasmName external_url = + wire_bytes.GetNameOrNull(symbols.external_url); + return {external_url.data(), external_url.size()}; +} + int debug::WasmScript::NumFunctions() const { i::DisallowHeapAllocation no_gc; i::Handle script = Utils::OpenHandle(this); @@ -10365,6 +10298,51 @@ bool debug::AccessorPair::IsAccessorPair(Local that) { return obj->IsAccessorPair(); } +int debug::WasmValue::value_type() { + i::Handle obj = Utils::OpenHandle(this); + return obj->value_type(); +} + +v8::Local debug::WasmValue::bytes() { + i::Handle obj = Utils::OpenHandle(this); + // Should only be called on i32, i64, f32, f64, s128. + DCHECK_GE(1, obj->value_type()); + DCHECK_LE(5, obj->value_type()); + + i::Isolate* isolate = obj->GetIsolate(); + i::Handle bytes_or_ref(obj->bytes_or_ref(), isolate); + i::Handle bytes(i::Handle::cast(bytes_or_ref)); + + int length = bytes->length(); + + i::Handle fa = isolate->factory()->NewFixedArray(length); + i::Handle arr = obj->GetIsolate()->factory()->NewJSArray( + i::PACKED_SMI_ELEMENTS, length, length); + i::JSArray::SetContent(arr, fa); + + for (int i = 0; i < length; i++) { + fa->set(i, i::Smi::FromInt(bytes->get(i))); + } + + return Utils::ToLocal(arr); +} + +v8::Local debug::WasmValue::ref() { + i::Handle obj = Utils::OpenHandle(this); + // Should only be called on anyref. + DCHECK_EQ(6, obj->value_type()); + + i::Isolate* isolate = obj->GetIsolate(); + i::Handle bytes_or_ref(obj->bytes_or_ref(), isolate); + + return Utils::ToLocal(bytes_or_ref); +} + +bool debug::WasmValue::IsWasmValue(Local that) { + i::Handle obj = Utils::OpenHandle(*that); + return obj->IsWasmValue(); +} + MaybeLocal debug::GetMessageFromPromise(Local p) { i::Handle promise = Utils::OpenHandle(*p); i::Isolate* isolate = promise->GetIsolate(); @@ -11174,8 +11152,11 @@ void InvokeFinalizationRegistryCleanupFromTask( Local api_context = Utils::ToLocal(context); CallDepthScope call_depth_scope(isolate, api_context); VMState state(isolate); - if (JSFinalizationRegistry::Cleanup(isolate, finalization_registry, callback) - .IsNothing()) { + Handle argv[] = {callback}; + if (Execution::CallBuiltin(isolate, + isolate->finalization_registry_cleanup_some(), + finalization_registry, arraysize(argv), argv) + .is_null()) { call_depth_scope.Escape(); } } diff --git a/deps/v8/src/api/api.h b/deps/v8/src/api/api.h index 4c383d3e43caf3..ad879657c99247 100644 --- a/deps/v8/src/api/api.h +++ b/deps/v8/src/api/api.h @@ -33,6 +33,7 @@ namespace debug { class AccessorPair; class GeneratorObject; class Script; +class WasmValue; class WeakMap; } // namespace debug @@ -93,7 +94,6 @@ class RegisteredExtension { V(Data, Object) \ V(RegExp, JSRegExp) \ V(Object, JSReceiver) \ - V(FinalizationGroup, JSFinalizationRegistry) \ V(Array, JSArray) \ V(Map, JSMap) \ V(Set, JSSet) \ @@ -129,6 +129,7 @@ class RegisteredExtension { V(debug::Script, Script) \ V(debug::WeakMap, JSWeakMap) \ V(debug::AccessorPair, AccessorPair) \ + V(debug::WasmValue, WasmValue) \ V(Promise, JSPromise) \ V(Primitive, Object) \ V(PrimitiveArray, FixedArray) \ @@ -205,8 +206,6 @@ class Utils { v8::internal::Handle obj); static inline Local ToLocalBigUint64Array( v8::internal::Handle obj); - static inline Local ToLocal( - v8::internal::Handle obj); static inline Local ToLocalShared( v8::internal::Handle obj); @@ -275,16 +274,6 @@ class Utils { return OpenHandle(*handle); } - static inline CompiledWasmModule Convert( - std::shared_ptr native_module) { - return CompiledWasmModule{std::move(native_module)}; - } - - static inline const std::shared_ptr& Open( - const CompiledWasmModule& compiled_module) { - return compiled_module.native_module_; - } - private: static void ReportApiFailure(const char* location, const char* message); }; diff --git a/deps/v8/src/asmjs/asm-js.cc b/deps/v8/src/asmjs/asm-js.cc index 5a6846c33f4e5c..17bf39c8538722 100644 --- a/deps/v8/src/asmjs/asm-js.cc +++ b/deps/v8/src/asmjs/asm-js.cc @@ -187,7 +187,8 @@ class AsmJsCompilationJob final : public UnoptimizedCompilationJob { explicit AsmJsCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal, AccountingAllocator* allocator) : UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info, - &compilation_info_), + &compilation_info_, + CanOffThreadFinalize::kNo), allocator_(allocator), zone_(allocator, ZONE_NAME), compilation_info_(&zone_, parse_info, literal), @@ -223,7 +224,7 @@ class AsmJsCompilationJob final : public UnoptimizedCompilationJob { UnoptimizedCompilationJob::Status AsmJsCompilationJob::ExecuteJobImpl() { // Step 1: Translate asm.js module to WebAssembly module. - Zone* compile_zone = compilation_info()->zone(); + Zone* compile_zone = &zone_; Zone translate_zone(allocator_, ZONE_NAME); Utf16CharacterStream* stream = parse_info()->character_stream(); @@ -332,6 +333,13 @@ MaybeHandle AsmJs::InstantiateAsmWasm(Isolate* isolate, // but should instead point to the instantiation site (more intuitive). int position = shared->StartPosition(); + // Check that the module is not instantiated as a generator or async function. + if (IsResumableFunction(shared->scope_info().function_kind())) { + ReportInstantiationFailure(script, position, + "Cannot be instantiated as resumable function"); + return MaybeHandle(); + } + // Check that all used stdlib members are valid. bool stdlib_use_of_typed_array_present = false; wasm::AsmJsParser::StdlibSet stdlib_uses = diff --git a/deps/v8/src/asmjs/asm-scanner.cc b/deps/v8/src/asmjs/asm-scanner.cc index eaff042d31cae5..73140867084c7a 100644 --- a/deps/v8/src/asmjs/asm-scanner.cc +++ b/deps/v8/src/asmjs/asm-scanner.cc @@ -329,7 +329,7 @@ void AsmJsScanner::ConsumeNumber(uc32 ch) { token_ = kParseError; return; } - if (has_dot) { + if (has_dot || trunc(double_value_) != double_value_) { token_ = kDouble; } else { // Exceeding safe integer range is an error. diff --git a/deps/v8/src/ast/ast-value-factory.cc b/deps/v8/src/ast/ast-value-factory.cc index 7e1be44da16ea2..23f28b834ac7ec 100644 --- a/deps/v8/src/ast/ast-value-factory.cc +++ b/deps/v8/src/ast/ast-value-factory.cc @@ -27,6 +27,7 @@ #include "src/ast/ast-value-factory.h" +#include "src/base/logging.h" #include "src/common/globals.h" #include "src/execution/off-thread-isolate.h" #include "src/heap/factory-inl.h" @@ -332,20 +333,22 @@ const AstRawString* AstValueFactory::CloneFromOtherFactory( } AstConsString* AstValueFactory::NewConsString() { - return new (zone_) AstConsString; + return new (zone()) AstConsString; } AstConsString* AstValueFactory::NewConsString(const AstRawString* str) { - return NewConsString()->AddString(zone_, str); + return NewConsString()->AddString(zone(), str); } AstConsString* AstValueFactory::NewConsString(const AstRawString* str1, const AstRawString* str2) { - return NewConsString()->AddString(zone_, str1)->AddString(zone_, str2); + return NewConsString()->AddString(zone(), str1)->AddString(zone(), str2); } template void AstValueFactory::Internalize(LocalIsolate* isolate) { + if (!zone_) return; + // Strings need to be internalized before values, because values refer to // strings. for (AstRawString* current = strings_; current != nullptr;) { @@ -355,6 +358,7 @@ void AstValueFactory::Internalize(LocalIsolate* isolate) { } ResetStrings(); + zone_ = nullptr; } template EXPORT_TEMPLATE_DEFINE( V8_EXPORT_PRIVATE) void AstValueFactory::Internalize(Isolate* @@ -373,9 +377,9 @@ AstRawString* AstValueFactory::GetString(uint32_t hash_field, bool is_one_byte, if (entry->value == nullptr) { // Copy literal contents for later comparison. int length = literal_bytes.length(); - byte* new_literal_bytes = zone_->NewArray(length); + byte* new_literal_bytes = zone()->NewArray(length); memcpy(new_literal_bytes, literal_bytes.begin(), length); - AstRawString* new_string = new (zone_) AstRawString( + AstRawString* new_string = new (zone()) AstRawString( is_one_byte, Vector(new_literal_bytes, length), hash_field); CHECK_NOT_NULL(new_string); AddString(new_string); diff --git a/deps/v8/src/ast/ast-value-factory.h b/deps/v8/src/ast/ast-value-factory.h index dce9de40697f29..134612f1fd02a5 100644 --- a/deps/v8/src/ast/ast-value-factory.h +++ b/deps/v8/src/ast/ast-value-factory.h @@ -31,6 +31,7 @@ #include #include "src/base/hashmap.h" +#include "src/base/logging.h" #include "src/common/globals.h" #include "src/heap/factory.h" #include "src/numbers/conversions.h" @@ -66,6 +67,8 @@ class AstRawString final : public ZoneObject { int byte_length() const { return literal_bytes_.length(); } const unsigned char* raw_data() const { return literal_bytes_.begin(); } + bool IsPrivateName() const { return length() > 0 && FirstCharacter() == '#'; } + // For storing AstRawStrings in a hash map. uint32_t hash_field() const { return hash_field_; } uint32_t Hash() const { return hash_field_ >> Name::kHashShift; } @@ -288,6 +291,7 @@ class AstValueFactory { empty_cons_string_(nullptr), zone_(zone), hash_seed_(hash_seed) { + DCHECK_NOT_NULL(zone_); DCHECK_EQ(hash_seed, string_constants->hash_seed()); std::fill(one_character_strings_, one_character_strings_ + arraysize(one_character_strings_), @@ -295,7 +299,10 @@ class AstValueFactory { empty_cons_string_ = NewConsString(); } - Zone* zone() const { return zone_; } + Zone* zone() const { + DCHECK_NOT_NULL(zone_); + return zone_; + } const AstRawString* GetOneByteString(Vector literal) { return GetOneByteStringInternal(literal); @@ -317,6 +324,9 @@ class AstValueFactory { V8_EXPORT_PRIVATE AstConsString* NewConsString(const AstRawString* str1, const AstRawString* str2); + // Internalize all the strings in the factory, and prevent any more from being + // allocated. Multiple calls to Internalize are allowed, for simplicity, where + // subsequent calls are a no-op. template void Internalize(LocalIsolate* isolate); diff --git a/deps/v8/src/ast/ast.h b/deps/v8/src/ast/ast.h index 5bf2d7e1928f9c..6fcf30499a5f0d 100644 --- a/deps/v8/src/ast/ast.h +++ b/deps/v8/src/ast/ast.h @@ -14,8 +14,6 @@ #include "src/codegen/bailout-reason.h" #include "src/codegen/label.h" #include "src/common/globals.h" -#include "src/execution/isolate.h" -#include "src/execution/off-thread-isolate.h" #include "src/heap/factory.h" #include "src/objects/elements-kind.h" #include "src/objects/function-syntax-kind.h" @@ -117,6 +115,9 @@ namespace internal { EXPRESSION_NODE_LIST(V) // Forward declarations +class Isolate; +class OffThreadIsolate; + class AstNode; class AstNodeFactory; class Declaration; @@ -1445,9 +1446,7 @@ class VariableProxy final : public Expression { HoleCheckModeField::update(bit_field_, HoleCheckMode::kRequired); } - bool IsPrivateName() const { - return raw_name()->length() > 0 && raw_name()->FirstCharacter() == '#'; - } + bool IsPrivateName() const { return raw_name()->IsPrivateName(); } // Bind this proxy to the variable var. void BindTo(Variable* var); @@ -2242,7 +2241,7 @@ class FunctionLiteral final : public Expression { private: friend class AstNodeFactory; - FunctionLiteral(Zone* zone, const AstRawString* name, + FunctionLiteral(Zone* zone, const AstConsString* name, AstValueFactory* ast_value_factory, DeclarationScope* scope, const ScopedPtrList& body, int expected_property_count, int parameter_count, @@ -2258,7 +2257,7 @@ class FunctionLiteral final : public Expression { function_token_position_(kNoSourcePosition), suspend_count_(0), function_literal_id_(function_literal_id), - raw_name_(name ? ast_value_factory->NewConsString(name) : nullptr), + raw_name_(name), scope_(scope), body_(0, nullptr), raw_inferred_name_(ast_value_factory->empty_cons_string()), @@ -3109,7 +3108,8 @@ class AstNodeFactory final { bool has_braces, int function_literal_id, ProducedPreparseData* produced_preparse_data = nullptr) { return new (zone_) FunctionLiteral( - zone_, name, ast_value_factory_, scope, body, expected_property_count, + zone_, name ? ast_value_factory_->NewConsString(name) : nullptr, + ast_value_factory_, scope, body, expected_property_count, parameter_count, function_length, function_syntax_kind, has_duplicate_parameters, eager_compile_hint, position, has_braces, function_literal_id, produced_preparse_data); @@ -3122,8 +3122,8 @@ class AstNodeFactory final { DeclarationScope* scope, const ScopedPtrList& body, int expected_property_count, int parameter_count) { return new (zone_) FunctionLiteral( - zone_, ast_value_factory_->empty_string(), ast_value_factory_, scope, - body, expected_property_count, parameter_count, parameter_count, + zone_, ast_value_factory_->empty_cons_string(), ast_value_factory_, + scope, body, expected_property_count, parameter_count, parameter_count, FunctionSyntaxKind::kAnonymousExpression, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kShouldLazyCompile, 0, /* has_braces */ false, diff --git a/deps/v8/src/ast/scopes.cc b/deps/v8/src/ast/scopes.cc index 8c13556db915ee..3f0a1adbc3af95 100644 --- a/deps/v8/src/ast/scopes.cc +++ b/deps/v8/src/ast/scopes.cc @@ -598,7 +598,7 @@ bool DeclarationScope::Analyze(ParseInfo* info) { DCHECK_EQ(scope->scope_type_, ScopeType::FUNCTION_SCOPE); allow_deref.emplace(); info->consumed_preparse_data()->RestoreScopeAllocationData( - scope, info->ast_value_factory()); + scope, info->ast_value_factory(), info->zone()); } if (!scope->AllocateVariables(info)) return false; @@ -1138,7 +1138,8 @@ Variable* Scope::NewTemporary(const AstRawString* name, return var; } -Declaration* DeclarationScope::CheckConflictingVarDeclarations() { +Declaration* DeclarationScope::CheckConflictingVarDeclarations( + bool* allowed_catch_binding_var_redeclaration) { if (has_checked_syntax_) return nullptr; for (Declaration* decl : decls_) { // Lexical vs lexical conflicts within the same scope have already been @@ -1152,11 +1153,12 @@ Declaration* DeclarationScope::CheckConflictingVarDeclarations() { // Iterate through all scopes until the declaration scope. do { // There is a conflict if there exists a non-VAR binding. + Variable* other_var = current->LookupLocal(decl->var()->raw_name()); if (current->is_catch_scope()) { + *allowed_catch_binding_var_redeclaration |= other_var != nullptr; current = current->outer_scope(); continue; } - Variable* other_var = current->LookupLocal(decl->var()->raw_name()); if (other_var != nullptr) { DCHECK(IsLexicalVariableMode(other_var->mode())); return decl; @@ -2586,8 +2588,8 @@ Variable* ClassScope::DeclarePrivateName(const AstRawString* name, bool* was_added) { Variable* result = EnsureRareData()->private_name_map.Declare( zone(), this, name, mode, NORMAL_VARIABLE, - InitializationFlag::kNeedsInitialization, - MaybeAssignedFlag::kMaybeAssigned, is_static_flag, was_added); + InitializationFlag::kNeedsInitialization, MaybeAssignedFlag::kNotAssigned, + is_static_flag, was_added); if (*was_added) { locals_.Add(result); has_static_private_methods_ |= @@ -2683,7 +2685,7 @@ Variable* ClassScope::LookupPrivateNameInScopeInfo(const AstRawString* name) { DCHECK(IsConstVariableMode(mode)); DCHECK_EQ(init_flag, InitializationFlag::kNeedsInitialization); - DCHECK_EQ(maybe_assigned_flag, MaybeAssignedFlag::kMaybeAssigned); + DCHECK_EQ(maybe_assigned_flag, MaybeAssignedFlag::kNotAssigned); // Add the found private name to the map to speed up subsequent // lookups for the same name. @@ -2725,7 +2727,7 @@ bool ClassScope::ResolvePrivateNames(ParseInfo* info) { if (var == nullptr) { // It's only possible to fail to resolve private names here if // this is at the top level or the private name is accessed through eval. - DCHECK(info->is_eval() || outer_scope_->is_script_scope()); + DCHECK(info->flags().is_eval() || outer_scope_->is_script_scope()); Scanner::Location loc = proxy->location(); info->pending_error_handler()->ReportMessageAt( loc.beg_pos, loc.end_pos, @@ -2812,7 +2814,7 @@ Variable* ClassScope::DeclareBrandVariable(AstValueFactory* ast_value_factory, Variable* brand = Declare(zone(), ast_value_factory->dot_brand_string(), VariableMode::kConst, NORMAL_VARIABLE, InitializationFlag::kNeedsInitialization, - MaybeAssignedFlag::kMaybeAssigned, &was_added); + MaybeAssignedFlag::kNotAssigned, &was_added); DCHECK(was_added); brand->set_is_static_flag(is_static_flag); brand->ForceContextAllocation(); diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h index 08bbc696d94193..11f44bb498436f 100644 --- a/deps/v8/src/ast/scopes.h +++ b/deps/v8/src/ast/scopes.h @@ -909,7 +909,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { // Check if the scope has conflicting var // declarations, i.e. a var declaration that has been hoisted from a nested // scope over a let binding of the same name. - Declaration* CheckConflictingVarDeclarations(); + Declaration* CheckConflictingVarDeclarations( + bool* allowed_catch_binding_var_redeclaration); void set_has_checked_syntax(bool has_checked_syntax) { has_checked_syntax_ = has_checked_syntax; diff --git a/deps/v8/src/ast/variables.h b/deps/v8/src/ast/variables.h index a3a5199620ec29..7c6ee4324e8153 100644 --- a/deps/v8/src/ast/variables.h +++ b/deps/v8/src/ast/variables.h @@ -90,7 +90,10 @@ class Variable final : public ZoneObject { } void SetMaybeAssigned() { if (mode() == VariableMode::kConst) return; - + // Private names are only initialized once by us. + if (name_->IsPrivateName()) { + return; + } // If this variable is dynamically shadowing another variable, then that // variable could also be assigned (in the non-shadowing case). if (has_local_if_not_shadowed()) { diff --git a/deps/v8/src/base/address-region.h b/deps/v8/src/base/address-region.h index 9ef6160d2a79a4..44151606c0cc63 100644 --- a/deps/v8/src/base/address-region.h +++ b/deps/v8/src/base/address-region.h @@ -15,6 +15,14 @@ namespace base { // Helper class representing an address region of certain size. class AddressRegion { public: + // Function object that compares the start address of two regions. Usable as + // compare function on std data structures and algorithms. + struct StartAddressLess { + bool operator()(base::AddressRegion a, base::AddressRegion b) const { + return a.begin() < b.begin(); + } + }; + using Address = uintptr_t; AddressRegion() = default; diff --git a/deps/v8/src/base/cpu.cc b/deps/v8/src/base/cpu.cc index f1c48fa1356698..bbdae525e30b39 100644 --- a/deps/v8/src/base/cpu.cc +++ b/deps/v8/src/base/cpu.cc @@ -605,7 +605,11 @@ CPU::CPU() #endif #elif V8_HOST_ARCH_ARM64 -// Implementer, variant and part are currently unused under ARM64. +#ifdef V8_OS_WIN + // Windows makes high-resolution thread timing information available in + // user-space. + has_non_stop_time_stamp_counter_ = true; +#endif // V8_OS_WIN #elif V8_HOST_ARCH_PPC || V8_HOST_ARCH_PPC64 diff --git a/deps/v8/src/base/platform/mutex.h b/deps/v8/src/base/platform/mutex.h index 5b3b31ec1e5246..c3144f7ceb5365 100644 --- a/deps/v8/src/base/platform/mutex.h +++ b/deps/v8/src/base/platform/mutex.h @@ -67,7 +67,8 @@ class V8_BASE_EXPORT Mutex final { return native_handle_; } - V8_INLINE void AssertHeld() { DCHECK_EQ(1, level_); } + V8_INLINE void AssertHeld() const { DCHECK_EQ(1, level_); } + V8_INLINE void AssertUnheld() const { DCHECK_EQ(0, level_); } private: NativeHandle native_handle_; diff --git a/deps/v8/src/base/platform/platform-aix.cc b/deps/v8/src/base/platform/platform-aix.cc index e3d7c426b4ab9e..e1ccda2ab05601 100644 --- a/deps/v8/src/base/platform/platform-aix.cc +++ b/deps/v8/src/base/platform/platform-aix.cc @@ -129,5 +129,34 @@ void OS::SignalCodeMovingGC() {} void OS::AdjustSchedulingParams() {} +// static +void* Stack::GetStackStart() { + // pthread_getthrds_np creates 3 values: + // __pi_stackaddr, __pi_stacksize, __pi_stackend + + // higher address ----- __pi_stackend, stack base + // + // | + // | __pi_stacksize, stack grows downwards + // | + // V + // + // lower address ----- __pi_stackaddr, current sp + + pthread_t tid = pthread_self(); + struct __pthrdsinfo buf; + // clear buf + memset(&buf, 0, sizeof(buf)); + char regbuf[1]; + int regbufsize = sizeof(regbuf); + const int rc = pthread_getthrds_np(&tid, PTHRDSINFO_QUERY_ALL, &buf, + sizeof(buf), regbuf, ®bufsize); + CHECK(!rc); + if (buf.__pi_stackend == NULL || buf.__pi_stackaddr == NULL) { + return nullptr; + } + return reinterpret_cast(buf.__pi_stackend); +} + } // namespace base } // namespace v8 diff --git a/deps/v8/src/base/platform/platform-posix.cc b/deps/v8/src/base/platform/platform-posix.cc index 54f72e04e68372..c3f0b08ddde843 100644 --- a/deps/v8/src/base/platform/platform-posix.cc +++ b/deps/v8/src/base/platform/platform-posix.cc @@ -970,7 +970,7 @@ void Thread::SetThreadLocal(LocalStorageKey key, void* value) { // pthread_getattr_np used below is non portable (hence the _np suffix). We // keep this version in POSIX as most Linux-compatible derivatives will // support it. MacOS and FreeBSD are different here. -#if !defined(V8_OS_FREEBSD) && !defined(V8_OS_MACOSX) && !defined(V8_OS_SOLARIS) +#if !defined(V8_OS_FREEBSD) && !defined(V8_OS_MACOSX) && !defined(_AIX) // static void* Stack::GetStackStart() { @@ -996,7 +996,7 @@ void* Stack::GetStackStart() { return nullptr; } -#endif // !defined(V8_OS_FREEBSD) && !defined(V8_OS_MACOSX) && !defined(V8_OS_SOLARIS) +#endif // !defined(V8_OS_FREEBSD) && !defined(V8_OS_MACOSX) && !defined(_AIX) // static void* Stack::GetCurrentStackPosition() { return __builtin_frame_address(0); } diff --git a/deps/v8/src/base/platform/platform-solaris.cc b/deps/v8/src/base/platform/platform-solaris.cc index b4ac98ce73bdbb..b5b16dac568789 100644 --- a/deps/v8/src/base/platform/platform-solaris.cc +++ b/deps/v8/src/base/platform/platform-solaris.cc @@ -65,23 +65,5 @@ void OS::SignalCodeMovingGC() {} void OS::AdjustSchedulingParams() {} -// static -void* Stack::GetStackStart() { - pthread_attr_t attr; - int error; - pthread_attr_init(&attr); - error = pthread_attr_get_np(pthread_self(), &attr); - if (!error) { - void* base; - size_t size; - error = pthread_attr_getstack(&attr, &base, &size); - CHECK(!error); - pthread_attr_destroy(&attr); - return reinterpret_cast(base) + size; - } - pthread_attr_destroy(&attr); - return nullptr; -} - } // namespace base } // namespace v8 diff --git a/deps/v8/src/base/platform/time.cc b/deps/v8/src/base/platform/time.cc index f07fd8e595fc60..a12a5b0d0a7f9d 100644 --- a/deps/v8/src/base/platform/time.cc +++ b/deps/v8/src/base/platform/time.cc @@ -125,12 +125,6 @@ V8_INLINE bool IsHighResolutionTimer(clockid_t clk_id) { } #elif V8_OS_WIN -V8_INLINE bool IsQPCReliable() { - v8::base::CPU cpu; - // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. - return strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15; -} - // Returns the current value of the performance counter. V8_INLINE uint64_t QPCNowRaw() { LARGE_INTEGER perf_counter_now = {}; @@ -645,11 +639,6 @@ TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { TimeTicks QPCNow() { return TimeTicks() + QPCValueToTimeDelta(QPCNowRaw()); } -bool IsBuggyAthlon(const CPU& cpu) { - // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. - return strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15; -} - void InitializeTimeTicksNowFunctionPointer() { LARGE_INTEGER ticks_per_sec = {}; if (!QueryPerformanceFrequency(&ticks_per_sec)) ticks_per_sec.QuadPart = 0; @@ -667,8 +656,7 @@ void InitializeTimeTicksNowFunctionPointer() { // ~72% of users fall within this category. TimeTicksNowFunction now_function; CPU cpu; - if (ticks_per_sec.QuadPart <= 0 || !cpu.has_non_stop_time_stamp_counter() || - IsBuggyAthlon(cpu)) { + if (ticks_per_sec.QuadPart <= 0 || !cpu.has_non_stop_time_stamp_counter()) { now_function = &RolloverProtectedNow; } else { now_function = &QPCNow; @@ -800,8 +788,7 @@ ThreadTicks ThreadTicks::GetForThread(const HANDLE& thread_handle) { // static bool ThreadTicks::IsSupportedWin() { - static bool is_supported = base::CPU().has_non_stop_time_stamp_counter() && - !IsQPCReliable(); + static bool is_supported = base::CPU().has_non_stop_time_stamp_counter(); return is_supported; } diff --git a/deps/v8/src/builtins/arm/builtins-arm.cc b/deps/v8/src/builtins/arm/builtins-arm.cc index 49f578d1fd11bf..d340fd20b0a72b 100644 --- a/deps/v8/src/builtins/arm/builtins-arm.cc +++ b/deps/v8/src/builtins/arm/builtins-arm.cc @@ -123,32 +123,23 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { __ Push(cp, r0); __ SmiUntag(r0); +#ifdef V8_REVERSE_JSARGS + // Set up pointer to last argument (skip receiver). + __ add( + r4, fp, + Operand(StandardFrameConstants::kCallerSPOffset + kSystemPointerSize)); + // Copy arguments and receiver to the expression stack. + __ PushArray(r4, r0, r5); + // The receiver for the builtin/api call. + __ PushRoot(RootIndex::kTheHoleValue); +#else // The receiver for the builtin/api call. __ PushRoot(RootIndex::kTheHoleValue); - // Set up pointer to last argument. __ add(r4, fp, Operand(StandardFrameConstants::kCallerSPOffset)); - // Copy arguments and receiver to the expression stack. - Label loop, entry; - __ mov(r5, r0); - // ----------- S t a t e ------------- - // -- r0: number of arguments (untagged) - // -- r1: constructor function - // -- r3: new target - // -- r4: pointer to last argument - // -- r5: counter - // -- sp[0*kPointerSize]: the hole (receiver) - // -- sp[1*kPointerSize]: number of arguments (tagged) - // -- sp[2*kPointerSize]: context - // ----------------------------------- - __ b(&entry); - __ bind(&loop); - __ ldr(scratch, MemOperand(r4, r5, LSL, kPointerSizeLog2)); - __ push(scratch); - __ bind(&entry); - __ sub(r5, r5, Operand(1), SetCC); - __ b(ge, &loop); + __ PushArray(r4, r0, r5); +#endif // Call the function. // r0: number of arguments (untagged) @@ -239,29 +230,36 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // Restore new target. __ Pop(r3); + +#ifdef V8_REVERSE_JSARGS + // Push the allocated receiver to the stack. + __ Push(r0); + // We need two copies because we may have to return the original one + // and the calling conventions dictate that the called function pops the + // receiver. The second copy is pushed after the arguments, we saved in r6 + // since r0 needs to store the number of arguments before + // InvokingFunction. + __ mov(r6, r0); + + // Set up pointer to first argument (skip receiver). + __ add( + r4, fp, + Operand(StandardFrameConstants::kCallerSPOffset + kSystemPointerSize)); +#else // Push the allocated receiver to the stack. We need two copies // because we may have to return the original one and the calling // conventions dictate that the called function pops the receiver. __ Push(r0, r0); - // ----------- S t a t e ------------- - // -- r3: new target - // -- sp[0*kPointerSize]: implicit receiver - // -- sp[1*kPointerSize]: implicit receiver - // -- sp[2*kPointerSize]: padding - // -- sp[3*kPointerSize]: constructor function - // -- sp[4*kPointerSize]: number of arguments (tagged) - // -- sp[5*kPointerSize]: context - // ----------------------------------- + // Set up pointer to last argument. + __ add(r4, fp, Operand(StandardFrameConstants::kCallerSPOffset)); +#endif // Restore constructor function and argument count. __ ldr(r1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset)); __ ldr(r0, MemOperand(fp, ConstructFrameConstants::kLengthOffset)); __ SmiUntag(r0); - // Set up pointer to last argument. - __ add(r4, fp, Operand(StandardFrameConstants::kCallerSPOffset)); - Label enough_stack_space, stack_overflow; Generate_StackOverflowCheck(masm, r0, r5, &stack_overflow); __ b(&enough_stack_space); @@ -275,29 +273,13 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ bind(&enough_stack_space); - // Copy arguments and receiver to the expression stack. - Label loop, entry; - __ mov(r5, r0); - // ----------- S t a t e ------------- - // -- r0: number of arguments (untagged) - // -- r3: new target - // -- r4: pointer to last argument - // -- r5: counter - // -- sp[0*kPointerSize]: implicit receiver - // -- sp[1*kPointerSize]: implicit receiver - // -- sp[2*kPointerSize]: padding - // -- r1 and sp[3*kPointerSize]: constructor function - // -- sp[4*kPointerSize]: number of arguments (tagged) - // -- sp[5*kPointerSize]: context - // ----------------------------------- - __ b(&entry); + // Copy arguments to the expression stack. + __ PushArray(r4, r0, r5); - __ bind(&loop); - __ ldr(r6, MemOperand(r4, r5, LSL, kPointerSizeLog2)); - __ push(r6); - __ bind(&entry); - __ sub(r5, r5, Operand(1), SetCC); - __ b(ge, &loop); +#ifdef V8_REVERSE_JSARGS + // Push implicit receiver. + __ Push(r6); +#endif // Call the function. __ InvokeFunctionWithNewTarget(r1, r3, r0, CALL_FUNCTION); @@ -424,9 +406,11 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { __ cmp(sp, scratch); __ b(lo, &stack_overflow); +#ifndef V8_REVERSE_JSARGS // Push receiver. __ ldr(scratch, FieldMemOperand(r1, JSGeneratorObject::kReceiverOffset)); __ Push(scratch); +#endif // ----------- S t a t e ------------- // -- r1 : the JSGeneratorObject to resume @@ -443,19 +427,38 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { __ ldr(r2, FieldMemOperand(r1, JSGeneratorObject::kParametersAndRegistersOffset)); { +#ifdef V8_REVERSE_JSARGS + Label done_loop, loop; + __ mov(r6, r3); + + __ bind(&loop); + __ sub(r6, r6, Operand(1), SetCC); + __ b(lt, &done_loop); + __ add(scratch, r2, Operand(r6, LSL, kTaggedSizeLog2)); + __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kHeaderSize)); + __ Push(scratch); + __ b(&loop); + + __ bind(&done_loop); + + // Push receiver. + __ ldr(scratch, FieldMemOperand(r1, JSGeneratorObject::kReceiverOffset)); + __ Push(scratch); +#else Label done_loop, loop; __ mov(r6, Operand(0)); __ bind(&loop); __ cmp(r6, r3); __ b(ge, &done_loop); - __ add(scratch, r2, Operand(r6, LSL, kPointerSizeLog2)); + __ add(scratch, r2, Operand(r6, LSL, kTaggedSizeLog2)); __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kHeaderSize)); __ Push(scratch); __ add(r6, r6, Operand(1)); __ b(&loop); __ bind(&done_loop); +#endif } // Underlying function needs to have bytecode available. @@ -744,13 +747,14 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, __ Move(cp, context_address); __ ldr(cp, MemOperand(cp)); - // Push the function and the receiver onto the stack. - __ Push(r2, r3); + // Push the function. + __ Push(r2); - // Check if we have enough stack space to push all arguments. - // Clobbers r3. + // Check if we have enough stack space to push all arguments + receiver. + // Clobbers r5. Label enough_stack_space, stack_overflow; - Generate_StackOverflowCheck(masm, r0, r3, &stack_overflow); + __ add(r6, r0, Operand(1)); // Add one for receiver. + Generate_StackOverflowCheck(masm, r6, r5, &stack_overflow); __ b(&enough_stack_space); __ bind(&stack_overflow); __ CallRuntime(Runtime::kThrowStackOverflow); @@ -762,19 +766,42 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // Copy arguments to the stack in a loop. // r1: new.target // r2: function + // r3: receiver // r0: argc // r4: argv, i.e. points to first arg +#ifdef V8_REVERSE_JSARGS + Label loop, entry; + __ add(r6, r4, Operand(r0, LSL, kSystemPointerSizeLog2)); + // r6 points past last arg. + __ b(&entry); + __ bind(&loop); + __ ldr(r5, MemOperand(r6, -kSystemPointerSize, + PreIndex)); // read next parameter + __ ldr(r5, MemOperand(r5)); // dereference handle + __ push(r5); // push parameter + __ bind(&entry); + __ cmp(r4, r6); + __ b(ne, &loop); + + // Push the receiver. + __ Push(r3); +#else + // Push the receiver. + __ Push(r3); + Label loop, entry; - __ add(r3, r4, Operand(r0, LSL, kPointerSizeLog2)); - // r1 points past last arg. + __ add(r3, r4, Operand(r0, LSL, kSystemPointerSizeLog2)); + // r3 points past last arg. __ b(&entry); __ bind(&loop); - __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // read next parameter + __ ldr(r5, MemOperand(r4, kSystemPointerSize, + PostIndex)); // read next parameter __ ldr(r5, MemOperand(r5)); // dereference handle __ push(r5); // push parameter __ bind(&entry); __ cmp(r4, r3); __ b(ne, &loop); +#endif // Setup new.target and function. __ mov(r3, r1); @@ -1237,21 +1264,20 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { } static void Generate_InterpreterPushArgs(MacroAssembler* masm, - Register num_args, Register index, - Register limit, Register scratch) { - // Find the address of the last argument. - __ mov(limit, num_args); - __ mov(limit, Operand(limit, LSL, kPointerSizeLog2)); - __ sub(limit, index, limit); - - Label loop_header, loop_check; - __ b(al, &loop_check); - __ bind(&loop_header); - __ ldr(scratch, MemOperand(index, -kPointerSize, PostIndex)); - __ push(scratch); - __ bind(&loop_check); - __ cmp(index, limit); - __ b(hi, &loop_header); + Register num_args, + Register start_address, + Register scratch) { + // Find the argument with lowest address. + __ sub(scratch, num_args, Operand(1)); + __ mov(scratch, Operand(scratch, LSL, kSystemPointerSizeLog2)); + __ sub(start_address, start_address, scratch); + // Push the arguments. +#ifdef V8_REVERSE_JSARGS + __ PushArray(start_address, num_args, scratch, + TurboAssembler::PushArrayOrder::kReverse); +#else + __ PushArray(start_address, num_args, scratch); +#endif } // static @@ -1268,23 +1294,53 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl( // ----------------------------------- Label stack_overflow; +#ifdef V8_REVERSE_JSARGS + if (mode == InterpreterPushArgsMode::kWithFinalSpread) { + // The spread argument should not be pushed. + __ sub(r0, r0, Operand(1)); + } +#endif + __ add(r3, r0, Operand(1)); // Add one for receiver. Generate_StackOverflowCheck(masm, r3, r4, &stack_overflow); +#ifdef V8_REVERSE_JSARGS + if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { + // Don't copy receiver. Argument count is correct. + __ mov(r3, r0); + } + + // Push the arguments. r2 and r4 will be modified. + Generate_InterpreterPushArgs(masm, r3, r2, r4); + + // Push "undefined" as the receiver arg if we need to. + if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { + __ PushRoot(RootIndex::kUndefinedValue); + } + + if (mode == InterpreterPushArgsMode::kWithFinalSpread) { + // Pass the spread in the register r2. + // r2 already points to the penultimate argument, the spread + // lies in the next interpreter register. + __ sub(r2, r2, Operand(kSystemPointerSize)); + __ ldr(r2, MemOperand(r2)); + } +#else // Push "undefined" as the receiver arg if we need to. if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { __ PushRoot(RootIndex::kUndefinedValue); __ mov(r3, r0); // Argument count is correct. } - // Push the arguments. r2, r4, r5 will be modified. - Generate_InterpreterPushArgs(masm, r3, r2, r4, r5); + // Push the arguments. r2 and r4 will be modified. + Generate_InterpreterPushArgs(masm, r3, r2, r4); if (mode == InterpreterPushArgsMode::kWithFinalSpread) { __ Pop(r2); // Pass the spread in a register __ sub(r0, r0, Operand(1)); // Subtract one for spread } +#endif // Call the target. if (mode == InterpreterPushArgsMode::kWithFinalSpread) { @@ -1315,14 +1371,39 @@ void Builtins::Generate_InterpreterPushArgsThenConstructImpl( // ----------------------------------- Label stack_overflow; + __ add(r5, r0, Operand(1)); // Add one for receiver. + + Generate_StackOverflowCheck(masm, r5, r6, &stack_overflow); + +#ifdef V8_REVERSE_JSARGS + if (mode == InterpreterPushArgsMode::kWithFinalSpread) { + // The spread argument should not be pushed. + __ sub(r0, r0, Operand(1)); + } + + // Push the arguments. r4 and r5 will be modified. + Generate_InterpreterPushArgs(masm, r0, r4, r5); + // Push a slot for the receiver to be constructed. __ mov(r5, Operand::Zero()); __ push(r5); - Generate_StackOverflowCheck(masm, r0, r5, &stack_overflow); + if (mode == InterpreterPushArgsMode::kWithFinalSpread) { + // Pass the spread in the register r2. + // r4 already points to the penultimate argument, the spread + // lies in the next interpreter register. + __ sub(r4, r4, Operand(kSystemPointerSize)); + __ ldr(r2, MemOperand(r4)); + } else { + __ AssertUndefinedOrAllocationSite(r2, r5); + } +#else + // Push a slot for the receiver to be constructed. + __ mov(r5, Operand::Zero()); + __ push(r5); - // Push the arguments. r5, r4, r6 will be modified. - Generate_InterpreterPushArgs(masm, r0, r4, r5, r6); + // Push the arguments. r4 and r5 will be modified. + Generate_InterpreterPushArgs(masm, r0, r4, r5); if (mode == InterpreterPushArgsMode::kWithFinalSpread) { __ Pop(r2); // Pass the spread in a register @@ -1330,6 +1411,7 @@ void Builtins::Generate_InterpreterPushArgsThenConstructImpl( } else { __ AssertUndefinedOrAllocationSite(r2, r5); } +#endif if (mode == InterpreterPushArgsMode::kArrayFunction) { __ AssertFunction(r1); @@ -1604,12 +1686,21 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { { __ LoadRoot(r5, RootIndex::kUndefinedValue); __ mov(r2, r5); - __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); // receiver +#ifdef V8_REVERSE_JSARGS + __ ldr(r1, MemOperand(sp, 0)); // receiver + __ cmp(r0, Operand(1)); + __ ldr(r5, MemOperand(sp, kSystemPointerSize), ge); // thisArg + __ cmp(r0, Operand(2), ge); + __ ldr(r2, MemOperand(sp, 2 * kSystemPointerSize), ge); // argArray +#else + __ ldr(r1, MemOperand(sp, r0, LSL, kSystemPointerSizeLog2)); // receiver __ sub(r4, r0, Operand(1), SetCC); - __ ldr(r5, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // thisArg + __ ldr(r5, MemOperand(sp, r4, LSL, kSystemPointerSizeLog2), ge); // thisArg __ sub(r4, r4, Operand(1), SetCC, ge); - __ ldr(r2, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // argArray - __ add(sp, sp, Operand(r0, LSL, kPointerSizeLog2)); + __ ldr(r2, MemOperand(sp, r4, LSL, kSystemPointerSizeLog2), + ge); // argArray +#endif + __ add(sp, sp, Operand(r0, LSL, kSystemPointerSizeLog2)); __ str(r5, MemOperand(sp, 0)); } @@ -1643,6 +1734,24 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { // static void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { +#ifdef V8_REVERSE_JSARGS + // 1. Get the callable to call (passed as receiver) from the stack. + __ Pop(r1); + + // 2. Make sure we have at least one argument. + // r0: actual number of arguments + { + Label done; + __ cmp(r0, Operand::Zero()); + __ b(ne, &done); + __ PushRoot(RootIndex::kUndefinedValue); + __ add(r0, r0, Operand(1)); + __ bind(&done); + } + + // 3. Adjust the actual number of arguments. + __ sub(r0, r0, Operand(1)); +#else // 1. Make sure we have at least one argument. // r0: actual number of arguments { @@ -1656,7 +1765,7 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { // 2. Get the callable to call (passed as receiver) from the stack. // r0: actual number of arguments - __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); + __ ldr(r1, __ ReceiverOperand(r0)); // 3. Shift arguments and return address one slot down on the stack // (overwriting the original receiver). Adjust argument count to make @@ -1667,12 +1776,12 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { Register scratch = r3; Label loop; // Calculate the copy start address (destination). Copy end address is sp. - __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); + __ add(r2, sp, Operand(r0, LSL, kSystemPointerSizeLog2)); __ bind(&loop); - __ ldr(scratch, MemOperand(r2, -kPointerSize)); + __ ldr(scratch, MemOperand(r2, -kSystemPointerSize)); __ str(scratch, MemOperand(r2)); - __ sub(r2, r2, Operand(kPointerSize)); + __ sub(r2, r2, Operand(kSystemPointerSize)); __ cmp(r2, sp); __ b(ne, &loop); // Adjust the actual number of arguments and remove the top element @@ -1680,6 +1789,7 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { __ sub(r0, r0, Operand(1)); __ pop(); } +#endif // 4. Call the callable. __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); @@ -1693,6 +1803,7 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) { // -- sp[8] : target // -- sp[12] : receiver // ----------------------------------- + // NOTE: The order of args in the stack are reversed if V8_REVERSE_JSARGS // 1. Load target into r1 (if present), argumentsList into r2 (if present), // remove all arguments from the stack (including the receiver), and push @@ -1701,13 +1812,24 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) { __ LoadRoot(r1, RootIndex::kUndefinedValue); __ mov(r5, r1); __ mov(r2, r1); +#ifdef V8_REVERSE_JSARGS + __ cmp(r0, Operand(1)); + __ ldr(r1, MemOperand(sp, kSystemPointerSize), ge); // target + __ cmp(r0, Operand(2), ge); + __ ldr(r5, MemOperand(sp, 2 * kSystemPointerSize), ge); // thisArgument + __ cmp(r0, Operand(3), ge); + __ ldr(r2, MemOperand(sp, 3 * kSystemPointerSize), ge); // argumentsList +#else __ sub(r4, r0, Operand(1), SetCC); - __ ldr(r1, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // target + __ ldr(r1, MemOperand(sp, r4, LSL, kSystemPointerSizeLog2), ge); // target __ sub(r4, r4, Operand(1), SetCC, ge); - __ ldr(r5, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // thisArgument + __ ldr(r5, MemOperand(sp, r4, LSL, kSystemPointerSizeLog2), + ge); // thisArgument __ sub(r4, r4, Operand(1), SetCC, ge); - __ ldr(r2, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // argumentsList - __ add(sp, sp, Operand(r0, LSL, kPointerSizeLog2)); + __ ldr(r2, MemOperand(sp, r4, LSL, kSystemPointerSizeLog2), + ge); // argumentsList +#endif + __ add(sp, sp, Operand(r0, LSL, kSystemPointerSizeLog2)); __ str(r5, MemOperand(sp, 0)); } @@ -1734,6 +1856,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { // -- sp[8] : target // -- sp[12] : receiver // ----------------------------------- + // NOTE: The order of args in the stack are reversed if V8_REVERSE_JSARGS // 1. Load target into r1 (if present), argumentsList into r2 (if present), // new.target into r3 (if present, otherwise use target), remove all @@ -1742,15 +1865,30 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { { __ LoadRoot(r1, RootIndex::kUndefinedValue); __ mov(r2, r1); - __ str(r2, MemOperand(sp, r0, LSL, kPointerSizeLog2)); // receiver +#ifdef V8_REVERSE_JSARGS + __ mov(r4, r1); + __ cmp(r0, Operand(1)); + __ ldr(r1, MemOperand(sp, kSystemPointerSize), ge); // target + __ mov(r3, r1); // new.target defaults to target + __ cmp(r0, Operand(2), ge); + __ ldr(r2, MemOperand(sp, 2 * kSystemPointerSize), ge); // argumentsList + __ cmp(r0, Operand(3), ge); + __ ldr(r3, MemOperand(sp, 3 * kSystemPointerSize), ge); // new.target + __ add(sp, sp, Operand(r0, LSL, kSystemPointerSizeLog2)); + __ str(r4, MemOperand(sp, 0)); // set undefined to the receiver +#else + __ str(r2, MemOperand(sp, r0, LSL, kSystemPointerSizeLog2)); // receiver __ sub(r4, r0, Operand(1), SetCC); - __ ldr(r1, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // target + __ ldr(r1, MemOperand(sp, r4, LSL, kSystemPointerSizeLog2), ge); // target __ mov(r3, r1); // new.target defaults to target __ sub(r4, r4, Operand(1), SetCC, ge); - __ ldr(r2, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // argumentsList + __ ldr(r2, MemOperand(sp, r4, LSL, kSystemPointerSizeLog2), + ge); // argumentsList __ sub(r4, r4, Operand(1), SetCC, ge); - __ ldr(r3, MemOperand(sp, r4, LSL, kPointerSizeLog2), ge); // new.target - __ add(sp, sp, Operand(r0, LSL, kPointerSizeLog2)); + __ ldr(r3, MemOperand(sp, r4, LSL, kSystemPointerSizeLog2), + ge); // new.target + __ add(sp, sp, Operand(r0, LSL, kSystemPointerSizeLog2)); +#endif } // ----------- S t a t e ------------- @@ -1830,7 +1968,29 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, Label stack_overflow; Generate_StackOverflowCheck(masm, r4, scratch, &stack_overflow); - // Push arguments onto the stack (thisArgument is already on the stack). +#ifdef V8_REVERSE_JSARGS + // Move the arguments already in the stack, + // including the receiver and the return address. + { + Label copy, check; + Register num = r5, src = r6, dest = r9; // r7 and r8 are context and root. + __ mov(src, sp); + // Update stack pointer. + __ lsl(scratch, r4, Operand(kSystemPointerSizeLog2)); + __ AllocateStackSpace(scratch); + __ mov(dest, sp); + __ mov(num, r0); + __ b(&check); + __ bind(©); + __ ldr(scratch, MemOperand(src, kSystemPointerSize, PostIndex)); + __ str(scratch, MemOperand(dest, kSystemPointerSize, PostIndex)); + __ sub(num, num, Operand(1), SetCC); + __ bind(&check); + __ b(ge, ©); + } +#endif + + // Copy arguments onto the stack (thisArgument is already on the stack). { __ mov(r6, Operand(0)); __ LoadRoot(r5, RootIndex::kTheHoleValue); @@ -1838,11 +1998,16 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, __ bind(&loop); __ cmp(r6, r4); __ b(eq, &done); - __ add(scratch, r2, Operand(r6, LSL, kPointerSizeLog2)); + __ add(scratch, r2, Operand(r6, LSL, kTaggedSizeLog2)); __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kHeaderSize)); __ cmp(scratch, r5); + // Turn the hole into undefined as we go. __ LoadRoot(scratch, RootIndex::kUndefinedValue, eq); +#ifdef V8_REVERSE_JSARGS + __ str(scratch, MemOperand(r9, kSystemPointerSize, PostIndex)); +#else __ Push(scratch); +#endif __ add(r6, r6, Operand(1)); __ b(&loop); __ bind(&done); @@ -1981,7 +2146,7 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, __ LoadGlobalProxy(r3); } else { Label convert_to_object, convert_receiver; - __ ldr(r3, MemOperand(sp, r0, LSL, kPointerSizeLog2)); + __ ldr(r3, __ ReceiverOperand(r0)); __ JumpIfSmi(r3, &convert_to_object); STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); __ CompareObjectType(r3, r4, r4, FIRST_JS_RECEIVER_TYPE); @@ -2017,7 +2182,7 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); __ bind(&convert_receiver); } - __ str(r3, MemOperand(sp, r0, LSL, kPointerSizeLog2)); + __ str(r3, __ ReceiverOperand(r0)); } __ bind(&done_convert); @@ -2073,10 +2238,11 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { // (i.e. debug break and preemption) here, so check the "real stack // limit". Label done; - __ mov(scratch, Operand(r4, LSL, kPointerSizeLog2)); + __ mov(scratch, Operand(r4, LSL, kSystemPointerSizeLog2)); { UseScratchRegisterScope temps(masm); Register remaining_stack_size = temps.Acquire(); + DCHECK(!AreAliased(r0, r1, r2, r3, r4, scratch, remaining_stack_size)); // Compute the space we have left. The stack might already be overflowed // here which will cause remaining_stack_size to become negative. @@ -2096,6 +2262,25 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { __ bind(&done); } +#ifdef V8_REVERSE_JSARGS + // Pop receiver. + __ Pop(r5); + + // Push [[BoundArguments]]. + { + Label loop; + __ add(r0, r0, r4); // Adjust effective number of arguments. + __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ bind(&loop); + __ sub(r4, r4, Operand(1), SetCC); + __ ldr(scratch, MemOperand(r2, r4, LSL, kTaggedSizeLog2)); + __ Push(scratch); + __ b(gt, &loop); + } + + // Push receiver. + __ Push(r5); +#else // Reserve stack space for the [[BoundArguments]]. __ AllocateStackSpace(scratch); @@ -2106,8 +2291,8 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { __ bind(&loop); __ cmp(r5, r0); __ b(gt, &done_loop); - __ ldr(scratch, MemOperand(sp, r4, LSL, kPointerSizeLog2)); - __ str(scratch, MemOperand(sp, r5, LSL, kPointerSizeLog2)); + __ ldr(scratch, MemOperand(sp, r4, LSL, kSystemPointerSizeLog2)); + __ str(scratch, MemOperand(sp, r5, LSL, kSystemPointerSizeLog2)); __ add(r4, r4, Operand(1)); __ add(r5, r5, Operand(1)); __ b(&loop); @@ -2127,6 +2312,7 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { __ add(r0, r0, Operand(1)); __ b(gt, &loop); } +#endif } __ bind(&no_bound_arguments); } @@ -2143,7 +2329,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) { // Patch the receiver to [[BoundThis]]. __ ldr(r3, FieldMemOperand(r1, JSBoundFunction::kBoundThisOffset)); - __ str(r3, MemOperand(sp, r0, LSL, kPointerSizeLog2)); + __ str(r3, __ ReceiverOperand(r0)); // Push the [[BoundArguments]] onto the stack. Generate_PushBoundArguments(masm); @@ -2183,7 +2369,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { // 2. Call to something else, which might have a [[Call]] internal method (if // not we raise an exception). // Overwrite the original receiver the (original) target. - __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); + __ str(r1, __ ReceiverOperand(r0)); // Let the "call_as_function_delegate" take care of the rest. __ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, r1); __ Jump(masm->isolate()->builtins()->CallFunction( @@ -2292,7 +2478,7 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { __ bind(&non_proxy); { // Overwrite the original receiver with the (original) target. - __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); + __ str(r1, __ ReceiverOperand(r0)); // Let the "call_as_constructor_delegate" take care of the rest. __ LoadNativeContextSlot(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, r1); __ Jump(masm->isolate()->builtins()->CallFunction(), @@ -2319,9 +2505,13 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { __ b(eq, &dont_adapt_arguments); __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); __ ldr(r4, FieldMemOperand(r4, SharedFunctionInfo::kFlagsOffset)); + +#ifndef V8_REVERSE_JSARGS + // This optimization is disabled when the arguments are reversed. __ tst(r4, Operand(SharedFunctionInfo::IsSafeToSkipArgumentsAdaptorBit::kMask)); __ b(ne, &skip_adapt_arguments); +#endif // ------------------------------------------- // Adapt arguments. @@ -2342,10 +2532,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // r1: function // r2: expected number of arguments // r3: new target (passed through to callee) +#ifdef V8_REVERSE_JSARGS + __ add(r0, fp, Operand(r2, LSL, kSystemPointerSizeLog2)); +#else __ add(r0, fp, Operand::PointerOffsetFromSmiKey(r0)); +#endif // adjust for return address and receiver - __ add(r0, r0, Operand(2 * kPointerSize)); - __ sub(r4, r0, Operand(r2, LSL, kPointerSizeLog2)); + __ add(r0, r0, Operand(2 * kSystemPointerSize)); + __ sub(r4, r0, Operand(r2, LSL, kSystemPointerSizeLog2)); // Copy the arguments (including the receiver) to the new stack frame. // r0: copy start address @@ -2359,7 +2553,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { __ ldr(r5, MemOperand(r0, 0)); __ push(r5); __ cmp(r0, r4); // Compare before moving to next argument. - __ sub(r0, r0, Operand(kPointerSize)); + __ sub(r0, r0, Operand(kSystemPointerSize)); __ b(ne, ©); __ b(&invoke); @@ -2371,6 +2565,49 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { EnterArgumentsAdaptorFrame(masm); Generate_StackOverflowCheck(masm, r2, r5, &stack_overflow); +#ifdef V8_REVERSE_JSARGS + // Fill the remaining expected arguments with undefined. + // r0: actual number of arguments as a smi + // r1: function + // r2: expected number of arguments + // r3: new target (passed through to callee) + __ LoadRoot(r5, RootIndex::kUndefinedValue); + __ sub(r6, r2, Operand::SmiUntag(r0)); + __ sub(r4, fp, Operand(r6, LSL, kPointerSizeLog2)); + // Adjust for frame. + __ sub(r4, r4, + Operand(ArgumentsAdaptorFrameConstants::kFixedFrameSizeFromFp + + kPointerSize)); + + Label fill; + __ bind(&fill); + __ push(r5); + __ cmp(sp, r4); + __ b(ne, &fill); + + // Calculate copy start address into r0 and copy end address is fp. + // r0: actual number of arguments as a smi + // r1: function + // r2: expected number of arguments + // r3: new target (passed through to callee) + __ add(r0, fp, Operand::PointerOffsetFromSmiKey(r0)); + + // Copy the arguments (including the receiver) to the new stack frame. + // r0: copy start address + // r1: function + // r2: expected number of arguments + // r3: new target (passed through to callee) + Label copy; + __ bind(©); + + // Adjust load for return address and receiver. + __ ldr(r5, MemOperand(r0, 2 * kPointerSize)); + __ push(r5); + + __ cmp(r0, fp); // Compare before moving to next argument. + __ sub(r0, r0, Operand(kPointerSize)); + __ b(ne, ©); +#else // Calculate copy start address into r0 and copy end address is fp. // r0: actual number of arguments as a smi // r1: function @@ -2410,6 +2647,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { __ push(r5); __ cmp(sp, r4); __ b(ne, &fill); +#endif } // Call the entry point. @@ -2915,6 +3153,7 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) { // -- sp[(argc - 1) * 4] : first argument // -- sp[(argc + 0) * 4] : receiver // ----------------------------------- + // NOTE: The order of args are reversed if V8_REVERSE_JSARGS Register api_function_address = r1; Register argc = r2; @@ -2982,8 +3221,12 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) { // FunctionCallbackInfo::values_ (points at the first varargs argument passed // on the stack). +#ifdef V8_REVERSE_JSARGS + __ add(scratch, scratch, Operand((FCA::kArgsLength + 1) * kPointerSize)); +#else __ add(scratch, scratch, Operand((FCA::kArgsLength - 1) * kPointerSize)); __ add(scratch, scratch, Operand(argc, LSL, kPointerSizeLog2)); +#endif __ str(scratch, MemOperand(sp, 2 * kPointerSize)); // FunctionCallbackInfo::length_. diff --git a/deps/v8/src/builtins/arm64/builtins-arm64.cc b/deps/v8/src/builtins/arm64/builtins-arm64.cc index 9c38ae085ecc4f..46ab7a61fa88d2 100644 --- a/deps/v8/src/builtins/arm64/builtins-arm64.cc +++ b/deps/v8/src/builtins/arm64/builtins-arm64.cc @@ -143,17 +143,19 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { __ Claim(slot_count); // Preserve the incoming parameters on the stack. - __ LoadRoot(x10, RootIndex::kTheHoleValue); + __ LoadRoot(x4, RootIndex::kTheHoleValue); // Compute a pointer to the slot immediately above the location on the // stack to which arguments will be later copied. __ SlotAddress(x2, argc); +#ifndef V8_REVERSE_JSARGS // Poke the hole (receiver) in the highest slot. - __ Str(x10, MemOperand(x2)); - __ Tbnz(slot_count_without_rounding, 0, &already_aligned); + __ Str(x4, MemOperand(x2)); +#endif // Store padding, if needed. + __ Tbnz(slot_count_without_rounding, 0, &already_aligned); __ Str(padreg, MemOperand(x2, 1 * kSystemPointerSize)); __ Bind(&already_aligned); @@ -162,9 +164,18 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { Register count = x2; Register dst = x10; Register src = x11; - __ Mov(count, argc); __ SlotAddress(dst, 0); +#ifdef V8_REVERSE_JSARGS + // Poke the hole (receiver). + __ Str(x4, MemOperand(dst)); + __ Add(dst, dst, kSystemPointerSize); // Skip receiver. + __ Add(src, fp, + StandardFrameConstants::kCallerSPOffset + + kSystemPointerSize); // Skip receiver. +#else __ Add(src, fp, StandardFrameConstants::kCallerSPOffset); +#endif + __ Mov(count, argc); __ CopyDoubleWords(dst, src, count); } @@ -175,7 +186,7 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // If argc is odd: // -- sp[0*kSystemPointerSize]: argument n - 1 // -- ... - // -- sp[(n-1)*kSystemPointerSize]: argument 0 + // -- sp[(n-1)*kSystemPointerSize]: argument 1 // -- sp[(n+0)*kSystemPointerSize]: the hole (receiver) // -- sp[(n+1)*kSystemPointerSize]: padding // -- sp[(n+2)*kSystemPointerSize]: padding @@ -184,12 +195,13 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // If argc is even: // -- sp[0*kSystemPointerSize]: argument n - 1 // -- ... - // -- sp[(n-1)*kSystemPointerSize]: argument 0 + // -- sp[(n-1)*kSystemPointerSize]: argument 1 // -- sp[(n+0)*kSystemPointerSize]: the hole (receiver) // -- sp[(n+1)*kSystemPointerSize]: padding // -- sp[(n+2)*kSystemPointerSize]: number of arguments (tagged) // -- sp[(n+3)*kSystemPointerSize]: context (pushed by FrameScope) // ----------------------------------- + // NOTE: The order of args in the stack are reversed if V8_REVERSE_JSARGS // Call the function. __ InvokeFunctionWithNewTarget(x1, x3, argc, CALL_FUNCTION); @@ -264,8 +276,10 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // If not derived class constructor: Allocate the new receiver object. __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1, x4, x5); + __ Call(BUILTIN_CODE(masm->isolate(), FastNewObject), RelocInfo::CODE_TARGET); + __ B(&post_instantiation_deopt_entry); // Else: use TheHoleValue as receiver for constructor call @@ -346,8 +360,15 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { Register dst = x10; Register src = x11; __ Mov(count, x12); +#ifdef V8_REVERSE_JSARGS + __ Poke(x0, 0); // Add the receiver. + __ SlotAddress(dst, 1); // Skip receiver. + __ Add(src, fp, + StandardFrameConstants::kCallerSPOffset + kSystemPointerSize); +#else __ SlotAddress(dst, 0); __ Add(src, fp, StandardFrameConstants::kCallerSPOffset); +#endif __ CopyDoubleWords(dst, src, count); } @@ -496,7 +517,7 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { // Poke receiver into highest claimed slot. __ LoadTaggedPointerField( x5, FieldMemOperand(x1, JSGeneratorObject::kReceiverOffset)); - __ Poke(x5, Operand(x10, LSL, kSystemPointerSizeLog2)); + __ Poke(x5, __ ReceiverOperand(x10)); // ----------- S t a t e ------------- // -- x1 : the JSGeneratorObject to resume @@ -504,26 +525,33 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { // -- x10 : argument count // -- cp : generator context // -- lr : return address - // -- sp[arg count] : generator receiver - // -- sp[0 .. arg count - 1] : claimed for args + // -- sp[0 .. arg count] : claimed for receiver and args // ----------------------------------- // Copy the function arguments from the generator object's register file. - __ LoadTaggedPointerField( x5, FieldMemOperand(x1, JSGeneratorObject::kParametersAndRegistersOffset)); { Label loop, done; __ Cbz(x10, &done); +#ifdef V8_REVERSE_JSARGS + __ SlotAddress(x12, x10); + __ Add(x5, x5, Operand(x10, LSL, kTaggedSizeLog2)); + __ Add(x5, x5, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ Bind(&loop); + __ Sub(x10, x10, 1); + __ LoadAnyTaggedField(x11, MemOperand(x5, -kTaggedSize, PreIndex)); + __ Str(x11, MemOperand(x12, -kSystemPointerSize, PostIndex)); +#else __ Mov(x12, 0); - __ Bind(&loop); __ Sub(x10, x10, 1); __ Add(x11, x5, Operand(x12, LSL, kTaggedSizeLog2)); __ LoadAnyTaggedField(x11, FieldMemOperand(x11, FixedArray::kHeaderSize)); __ Poke(x11, Operand(x10, LSL, kSystemPointerSizeLog2)); __ Add(x12, x12, 1); +#endif __ Cbnz(x10, &loop); __ Bind(&done); } @@ -862,9 +890,17 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, __ SlotAddress(scratch, slots_to_claim); __ Str(padreg, MemOperand(scratch, -kSystemPointerSize)); +#ifdef V8_REVERSE_JSARGS + // Store receiver on the stack. + __ Poke(receiver, 0); + // Store function on the stack. + __ SlotAddress(scratch, argc); + __ Str(function, MemOperand(scratch, kSystemPointerSize)); +#else // Store receiver and function on the stack. __ SlotAddress(scratch, argc); __ Stp(receiver, function, MemOperand(scratch)); +#endif // Copy arguments to the stack in a loop, in reverse order. // x4: argc. @@ -874,9 +910,21 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // Skip the argument set up if we have no arguments. __ Cbz(argc, &done); - // scratch has been set to point to the location of the receiver, which + // scratch has been set to point to the location of the function, which // marks the end of the argument copy. - +#ifdef V8_REVERSE_JSARGS + __ SlotAddress(x0, 1); // Skips receiver. + __ Bind(&loop); + // Load the handle. + __ Ldr(x11, MemOperand(argv, kSystemPointerSize, PostIndex)); + // Dereference the handle. + __ Ldr(x11, MemOperand(x11)); + // Poke the result into the stack. + __ Str(x11, MemOperand(x0, kSystemPointerSize, PostIndex)); + // Loop if we've not reached the end of copy marker. + __ Cmp(x0, scratch); + __ B(le, &loop); +#else __ Bind(&loop); // Load the handle. __ Ldr(x11, MemOperand(argv, kSystemPointerSize, PostIndex)); @@ -887,6 +935,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // Loop if we've not reached the end of copy marker. __ Cmp(sp, scratch); __ B(lt, &loop); +#endif __ Bind(&done); @@ -1418,6 +1467,36 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, __ Poke(padreg, Operand(scratch, LSL, kSystemPointerSizeLog2)); } +#ifdef V8_REVERSE_JSARGS + if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { + __ Mov(slots_to_copy, num_args); + __ SlotAddress(stack_addr, 1); + } else { + // If we're not given an explicit receiver to store, we'll need to copy it + // together with the rest of the arguments. + __ Add(slots_to_copy, num_args, 1); + __ SlotAddress(stack_addr, 0); + } + + __ Sub(last_arg_addr, first_arg_index, + Operand(slots_to_copy, LSL, kSystemPointerSizeLog2)); + __ Add(last_arg_addr, last_arg_addr, kSystemPointerSize); + + // Load the final spread argument into spread_arg_out, if necessary. + if (mode == InterpreterPushArgsMode::kWithFinalSpread) { + __ Ldr(spread_arg_out, MemOperand(last_arg_addr, -kSystemPointerSize)); + } + + __ CopyDoubleWords(stack_addr, last_arg_addr, slots_to_copy, + TurboAssembler::kDstLessThanSrcAndReverse); + + if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { + // Store "undefined" as the receiver arg if we need to. + Register receiver = x14; + __ LoadRoot(receiver, RootIndex::kUndefinedValue); + __ Poke(receiver, 0); + } +#else // !V8_REVERSE_JSARGS if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { // Store "undefined" as the receiver arg if we need to. Register receiver = x14; @@ -1443,6 +1522,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, // Copy the rest of the arguments. __ SlotAddress(stack_addr, 0); __ CopyDoubleWords(stack_addr, last_arg_addr, slots_to_copy); +#endif // !V8_REVERSE_JSARGS } // static @@ -1778,14 +1858,16 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { // -- sp[8] : thisArg (if argc >= 1) // -- sp[16] : receiver // ----------------------------------- + // NOTE: The order of args in the stack are reversed if V8_REVERSE_JSARGS + ASM_LOCATION("Builtins::Generate_FunctionPrototypeApply"); Register argc = x0; - Register arg_array = x2; Register receiver = x1; - Register this_arg = x0; - Register undefined_value = x3; - Register null_value = x4; + Register arg_array = x2; + Register this_arg = x3; + Register undefined_value = x4; + Register null_value = x5; __ LoadRoot(undefined_value, RootIndex::kUndefinedValue); __ LoadRoot(null_value, RootIndex::kNullValue); @@ -1793,8 +1875,21 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { // 1. Load receiver into x1, argArray into x2 (if present), remove all // arguments from the stack (including the receiver), and push thisArg (if // present) instead. +#ifdef V8_REVERSE_JSARGS + { + Label done; + __ Mov(this_arg, undefined_value); + __ Mov(arg_array, undefined_value); + __ Peek(receiver, 0); + __ Cmp(argc, Immediate(1)); + __ B(lt, &done); + __ Peek(this_arg, kSystemPointerSize); + __ B(eq, &done); + __ Peek(arg_array, 2 * kSystemPointerSize); + __ bind(&done); + } +#else // !V8_REVERSE_JSARGS { - Register saved_argc = x10; Register scratch = x11; // Push two undefined values on the stack, to put it in a consistent state @@ -1814,16 +1909,13 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { // There are now always three arguments to read, in the slots starting from // slot argc. __ SlotAddress(scratch, argc); - - __ Mov(saved_argc, argc); - __ Ldp(arg_array, this_arg, MemOperand(scratch)); // Overwrites argc. + __ Ldp(arg_array, this_arg, MemOperand(scratch)); __ Ldr(receiver, MemOperand(scratch, 2 * kSystemPointerSize)); - __ Drop(2); // Drop the undefined values we pushed above. - __ DropArguments(saved_argc, TurboAssembler::kCountExcludesReceiver); - - __ PushArgument(this_arg); } +#endif // !V8_REVERSE_JSARGS + __ DropArguments(argc, TurboAssembler::kCountExcludesReceiver); + __ PushArgument(this_arg); // ----------- S t a t e ------------- // -- x2 : argArray @@ -1863,7 +1955,7 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { ASM_LOCATION("Builtins::Generate_FunctionPrototypeCall"); // 1. Get the callable to call (passed as receiver) from the stack. - __ Peek(function, Operand(argc, LSL, kXRegSizeLog2)); + __ Peek(function, __ ReceiverOperand(argc)); // 2. Handle case with no arguments. { @@ -1879,9 +1971,39 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { __ Bind(&non_zero); } + Label arguments_ready; +#ifdef V8_REVERSE_JSARGS + // 3. Shift arguments. It depends if the arguments is even or odd. + // That is if padding exists or not. + { + Label even; + Register copy_from = x10; + Register copy_to = x11; + Register count = x12; + __ Mov(count, argc); // CopyDoubleWords changes the count argument. + __ Tbz(argc, 0, &even); + + // Shift arguments one slot down on the stack (overwriting the original + // receiver). + __ SlotAddress(copy_from, 1); + __ Sub(copy_to, copy_from, kSystemPointerSize); + __ CopyDoubleWords(copy_to, copy_from, count); + // Overwrite the duplicated remaining last argument. + __ Poke(padreg, Operand(argc, LSL, kXRegSizeLog2)); + __ B(&arguments_ready); + + // Copy arguments one slot higher in memory, overwriting the original + // receiver and padding. + __ Bind(&even); + __ SlotAddress(copy_from, count); + __ Add(copy_to, copy_from, kSystemPointerSize); + __ CopyDoubleWords(copy_to, copy_from, count, + TurboAssembler::kSrcLessThanDst); + __ Drop(2); + } +#else // !V8_REVERSE_JSARGS // 3. Overwrite the receiver with padding. If argc is odd, this is all we // need to do. - Label arguments_ready; __ Poke(padreg, Operand(argc, LSL, kXRegSizeLog2)); __ Tbnz(argc, 0, &arguments_ready); @@ -1902,6 +2024,7 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { // Drop two slots. These are copies of the last two arguments. __ Drop(2); } +#endif // !V8_REVERSE_JSARGS // 5. Adjust argument count to make the original first argument the new // receiver and call the callable. @@ -1918,6 +2041,8 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) { // -- sp[16] : target (if argc >= 1) // -- sp[24] : receiver // ----------------------------------- + // NOTE: The order of args in the stack are reversed if V8_REVERSE_JSARGS + ASM_LOCATION("Builtins::Generate_ReflectApply"); Register argc = x0; @@ -1931,6 +2056,23 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) { // 1. Load target into x1 (if present), argumentsList into x2 (if present), // remove all arguments from the stack (including the receiver), and push // thisArgument (if present) instead. +#ifdef V8_REVERSE_JSARGS + { + Label done; + __ Mov(target, undefined_value); + __ Mov(this_argument, undefined_value); + __ Mov(arguments_list, undefined_value); + __ Cmp(argc, Immediate(1)); + __ B(lt, &done); + __ Peek(target, kSystemPointerSize); + __ B(eq, &done); + __ Peek(this_argument, 2 * kSystemPointerSize); + __ Cmp(argc, Immediate(3)); + __ B(lt, &done); + __ Peek(arguments_list, 3 * kSystemPointerSize); + __ bind(&done); + } +#else // !V8_REVERSE_JSARGS { // Push four undefined values on the stack, to put it in a consistent state // so that we can always read the three arguments we need from it. The @@ -1967,10 +2109,10 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) { __ Ldr(target, MemOperand(scratch, 3 * kSystemPointerSize)); __ Drop(4); // Drop the undefined values we pushed above. - __ DropArguments(argc, TurboAssembler::kCountExcludesReceiver); - - __ PushArgument(this_argument); } +#endif // !V8_REVERSE_JSARGS + __ DropArguments(argc, TurboAssembler::kCountExcludesReceiver); + __ PushArgument(this_argument); // ----------- S t a t e ------------- // -- x2 : argumentsList @@ -1995,6 +2137,8 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { // -- sp[16] : target // -- sp[24] : receiver // ----------------------------------- + // NOTE: The order of args in the stack are reversed if V8_REVERSE_JSARGS + ASM_LOCATION("Builtins::Generate_ReflectConstruct"); Register argc = x0; @@ -2009,6 +2153,24 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { // new.target into x3 (if present, otherwise use target), remove all // arguments from the stack (including the receiver), and push thisArgument // (if present) instead. +#ifdef V8_REVERSE_JSARGS + { + Label done; + __ Mov(target, undefined_value); + __ Mov(arguments_list, undefined_value); + __ Mov(new_target, undefined_value); + __ Cmp(argc, Immediate(1)); + __ B(lt, &done); + __ Peek(target, kSystemPointerSize); + __ B(eq, &done); + __ Peek(arguments_list, 2 * kSystemPointerSize); + __ Mov(new_target, target); // new.target defaults to target + __ Cmp(argc, Immediate(3)); + __ B(lt, &done); + __ Peek(new_target, 3 * kSystemPointerSize); + __ bind(&done); + } +#else // !V8_REVERSE_JSARGS { // Push four undefined values on the stack, to put it in a consistent state // so that we can always read the three arguments we need from it. The @@ -2048,11 +2210,13 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { __ CmovX(new_target, target, ls); // target if argc <= 2. __ Drop(4); // Drop the undefined values we pushed above. - __ DropArguments(argc, TurboAssembler::kCountExcludesReceiver); - - // Push receiver (undefined). - __ PushArgument(undefined_value); } +#endif // !V8_REVERSE_JSARGS + + __ DropArguments(argc, TurboAssembler::kCountExcludesReceiver); + + // Push receiver (undefined). + __ PushArgument(undefined_value); // ----------- S t a t e ------------- // -- x2 : argumentsList @@ -2105,6 +2269,39 @@ void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { // one slot up or one slot down, as needed. void Generate_PrepareForCopyingVarargs(MacroAssembler* masm, Register argc, Register len) { +#ifdef V8_REVERSE_JSARGS + Label even; + Register slots_to_copy = x10; + Register slots_to_claim = x12; + + __ Add(slots_to_copy, argc, 1); // Copy with receiver. + __ Mov(slots_to_claim, len); + __ Tbz(slots_to_claim, 0, &even); + + // Claim space we need. If argc is even, slots_to_claim = len + 1, as we need + // one extra padding slot. If argc is odd, we know that the original arguments + // will have a padding slot we can reuse (since len is odd), so + // slots_to_claim = len - 1. + { + Register scratch = x11; + __ Add(slots_to_claim, len, 1); + __ And(scratch, argc, 1); + __ Eor(scratch, scratch, 1); + __ Sub(slots_to_claim, slots_to_claim, Operand(scratch, LSL, 1)); + } + + __ Bind(&even); + __ Claim(slots_to_claim); + + // Move the arguments already in the stack including the receiver. + { + Register src = x11; + Register dst = x12; + __ SlotAddress(src, slots_to_claim); + __ SlotAddress(dst, 0); + __ CopyDoubleWords(dst, src, slots_to_copy); + } +#else // !V8_REVERSE_JSARGS Label len_odd, exit; Register slots_to_copy = x10; // If needed. __ Add(slots_to_copy, argc, 1); @@ -2158,6 +2355,7 @@ void Generate_PrepareForCopyingVarargs(MacroAssembler* masm, Register argc, } __ Bind(&exit); +#endif // !V8_REVERSE_JSARGS } } // namespace @@ -2217,6 +2415,19 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, // We do not use the CompareRoot macro as it would do a LoadRoot behind the // scenes and we want to avoid that in a loop. // TODO(all): Consider using Ldp and Stp. +#ifdef V8_REVERSE_JSARGS + Register dst = x16; + __ Add(dst, argc, Immediate(1)); // Consider the receiver as well. + __ SlotAddress(dst, dst); + __ Add(argc, argc, len); // Update new argc. + __ Bind(&loop); + __ Sub(len, len, 1); + __ LoadAnyTaggedField(scratch, MemOperand(src, kTaggedSize, PostIndex)); + __ CmpTagged(scratch, the_hole_value); + __ Csel(scratch, scratch, undefined_value, ne); + __ Str(scratch, MemOperand(dst, kSystemPointerSize, PostIndex)); + __ Cbnz(len, &loop); +#else __ Bind(&loop); __ Sub(len, len, 1); __ LoadAnyTaggedField(scratch, MemOperand(src, kTaggedSize, PostIndex)); @@ -2224,9 +2435,9 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, __ Csel(scratch, scratch, undefined_value, ne); __ Poke(scratch, Operand(len, LSL, kSystemPointerSizeLog2)); __ Cbnz(len, &loop); +#endif } __ Bind(&done); - // Tail-call to the actual Call or Construct builtin. __ Jump(code, RelocInfo::CODE_TARGET); @@ -2368,7 +2579,7 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, __ LoadGlobalProxy(x3); } else { Label convert_to_object, convert_receiver; - __ Peek(x3, Operand(x0, LSL, kXRegSizeLog2)); + __ Peek(x3, __ ReceiverOperand(x0)); __ JumpIfSmi(x3, &convert_to_object); STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); __ CompareObjectType(x3, x4, x4, FIRST_JS_RECEIVER_TYPE); @@ -2403,7 +2614,7 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset)); __ Bind(&convert_receiver); } - __ Poke(x3, Operand(x0, LSL, kXRegSizeLog2)); + __ Poke(x3, __ ReceiverOperand(x0)); } __ Bind(&done_convert); @@ -2474,6 +2685,83 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { __ Bind(&done); } +#ifdef V8_REVERSE_JSARGS + Label copy_bound_args; + Register total_argc = x15; + Register slots_to_claim = x12; + Register scratch = x10; + Register receiver = x14; + + __ Add(total_argc, argc, bound_argc); + __ Peek(receiver, 0); + + // Round up slots_to_claim to an even number if it is odd. + __ Add(slots_to_claim, bound_argc, 1); + __ Bic(slots_to_claim, slots_to_claim, 1); + __ Claim(slots_to_claim, kSystemPointerSize); + + __ Tbz(bound_argc, 0, ©_bound_args); + { + Label argc_even; + __ Tbz(argc, 0, &argc_even); + // Arguments count is odd (with the receiver it's even), so there's no + // alignment padding above the arguments and we have to "add" it. We + // claimed bound_argc + 1, since it is odd and it was rounded up. +1 here + // is for stack alignment padding. + // 1. Shift args one slot down. + { + Register copy_from = x11; + Register copy_to = x12; + __ SlotAddress(copy_to, slots_to_claim); + __ Add(copy_from, copy_to, kSystemPointerSize); + __ CopyDoubleWords(copy_to, copy_from, argc); + } + // 2. Write a padding in the last slot. + __ Add(scratch, total_argc, 1); + __ Str(padreg, MemOperand(sp, scratch, LSL, kSystemPointerSizeLog2)); + __ B(©_bound_args); + + __ Bind(&argc_even); + // Arguments count is even (with the receiver it's odd), so there's an + // alignment padding above the arguments and we can reuse it. We need to + // claim bound_argc - 1, but we claimed bound_argc + 1, since it is odd + // and it was rounded up. + // 1. Drop 2. + __ Drop(2); + // 2. Shift args one slot up. + { + Register copy_from = x11; + Register copy_to = x12; + __ SlotAddress(copy_to, total_argc); + __ Sub(copy_from, copy_to, kSystemPointerSize); + __ CopyDoubleWords(copy_to, copy_from, argc, + TurboAssembler::kSrcLessThanDst); + } + } + + // If bound_argc is even, there is no alignment massage to do, and we have + // already claimed the correct number of slots (bound_argc). + __ Bind(©_bound_args); + + // Copy the receiver back. + __ Poke(receiver, 0); + // Copy [[BoundArguments]] to the stack (below the receiver). + { + Label loop; + Register counter = bound_argc; + Register copy_to = x12; + __ Add(bound_argv, bound_argv, FixedArray::kHeaderSize - kHeapObjectTag); + __ SlotAddress(copy_to, 1); + __ Bind(&loop); + __ Sub(counter, counter, 1); + __ LoadAnyTaggedField(scratch, + MemOperand(bound_argv, kTaggedSize, PostIndex)); + __ Str(scratch, MemOperand(copy_to, kSystemPointerSize, PostIndex)); + __ Cbnz(counter, &loop); + } + // Update argc. + __ Mov(argc, total_argc); +#else // !V8_REVERSE_JSARGS // Check if we need padding. Label copy_args, copy_bound_args; Register total_argc = x15; @@ -2546,6 +2834,7 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { __ Bind(&done); } } +#endif // !V8_REVERSE_JSARGS } __ Bind(&no_bound_arguments); } @@ -2563,7 +2852,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) { // Patch the receiver to [[BoundThis]]. __ LoadAnyTaggedField(x10, FieldMemOperand(x1, JSBoundFunction::kBoundThisOffset)); - __ Poke(x10, Operand(x0, LSL, kSystemPointerSizeLog2)); + __ Poke(x10, __ ReceiverOperand(x0)); // Push the [[BoundArguments]] onto the stack. Generate_PushBoundArguments(masm); @@ -2604,7 +2893,8 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { // 2. Call to something else, which might have a [[Call]] internal method (if // not we raise an exception). // Overwrite the original receiver with the (original) target. - __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2)); + __ Poke(x1, __ ReceiverOperand(x0)); + // Let the "call_as_function_delegate" take care of the rest. __ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, x1); __ Jump(masm->isolate()->builtins()->CallFunction( @@ -2720,7 +3010,8 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { __ bind(&non_proxy); { // Overwrite the original receiver with the (original) target. - __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2)); + __ Poke(x1, __ ReceiverOperand(x0)); + // Let the "call_as_constructor_delegate" take care of the rest. __ LoadNativeContextSlot(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, x1); __ Jump(masm->isolate()->builtins()->CallFunction(), @@ -2793,18 +3084,22 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // alignment of the arguments. // If the number of expected arguments is larger than the number of actual // arguments, the remaining expected slots will be filled with undefined. + // TODO(v8:10201) update comment once reversed arguments order sticks Register argc_actual = x0; // Excluding the receiver. Register argc_expected = x2; // Excluding the receiver. Register function = x1; - Register argc_actual_minus_expected = x5; - Label create_adaptor_frame, dont_adapt_arguments, stack_overflow, - adapt_arguments_in_place; + Label create_adaptor_frame, dont_adapt_arguments, stack_overflow; __ Cmp(argc_expected, kDontAdaptArgumentsSentinel); __ B(eq, &dont_adapt_arguments); +#ifndef V8_REVERSE_JSARGS + // This optimization is disabled when the arguments are reversed. + Label adapt_arguments_in_place; + Register argc_actual_minus_expected = x5; + // When the difference between argc_actual and argc_expected is odd, we // create an arguments adaptor frame. __ Sub(argc_actual_minus_expected, argc_actual, argc_expected); @@ -2818,6 +3113,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { __ TestAndBranchIfAnySet( w4, SharedFunctionInfo::IsSafeToSkipArgumentsAdaptorBit::kMask, &adapt_arguments_in_place); +#endif // ------------------------------------------- // Create an arguments adaptor frame. @@ -2828,11 +3124,10 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { EnterArgumentsAdaptorFrame(masm); Register copy_from = x10; - Register copy_end = x11; Register copy_to = x12; + Register copy_end = x11; Register argc_to_copy = x13; - Register argc_unused_actual = x14; - Register scratch1 = x15, scratch2 = x16; + Register scratch1 = x15; // We need slots for the expected arguments, with one extra slot for the // receiver. @@ -2846,12 +3141,61 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { __ Bic(scratch1, scratch1, 1); __ Claim(scratch1, kSystemPointerSize); +#ifdef V8_REVERSE_JSARGS + // If we don't have enough arguments, fill the remaining expected + // arguments with undefined, otherwise skip this step. + Label enough_arguments; + __ Cmp(argc_actual, argc_expected); + __ Csel(argc_to_copy, argc_expected, argc_actual, ge); + __ Add(argc_to_copy, argc_to_copy, 1); // Include receiver. + __ B(ge, &enough_arguments); + + // Fill the remaining expected arguments with undefined. + __ RecordComment("-- Fill slots with undefined --"); + Label fill; + // scratch1 still contains the size of the claimed area, + // which is RoundUp(argc_expected + 1, 2). + __ SlotAddress(copy_to, scratch1); + __ SlotAddress(copy_end, argc_to_copy); + __ LoadRoot(scratch1, RootIndex::kUndefinedValue); + // Now we can write pairs of undefineds, potentially overwriting one word + // below copy_end, but that's ok because that slot is still within claimed + // region. This loop will execute at least once because at this point we + // know that there's at least one undefined to be pushed and + // argc_to_copy >= 1. + __ Bind(&fill); + __ Stp(scratch1, scratch1, + MemOperand(copy_to, -2 * kSystemPointerSize, PreIndex)); + __ Cmp(copy_to, copy_end); + __ B(hi, &fill); + + // Enough arguments. + __ Bind(&enough_arguments); + + // Store padding if needed, when expected arguments is even. + __ RecordComment("-- Store padding --"); + Label skip_padding; + __ Tbnz(argc_expected, 0, &skip_padding); + __ SlotAddress(scratch1, argc_expected); + __ Str(padreg, MemOperand(scratch1, kSystemPointerSize)); + __ bind(&skip_padding); + + // Copy arguments. + __ RecordComment("-- Copy actual arguments --"); __ Mov(copy_to, sp); + __ Add(copy_from, fp, 2 * kSystemPointerSize); + __ CopyDoubleWords(copy_to, copy_from, argc_to_copy); + +#else // !V8_REVERSE_JSARGS + Register argc_unused_actual = x14; + Register scratch2 = x16; // Preparing the expected arguments is done in four steps, the order of // which is chosen so we can use LDP/STP and avoid conditional branches as // much as possible. + __ Mov(copy_to, sp); + // (1) If we don't have enough arguments, fill the remaining expected // arguments with undefined, otherwise skip this step. Label enough_arguments; @@ -2918,6 +3262,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { MemOperand(copy_from, argc_actual, LSL, kSystemPointerSizeLog2)); __ Str(scratch1, MemOperand(sp, argc_expected, LSL, kSystemPointerSizeLog2)); +#endif // Arguments have been adapted. Now call the entry point. __ RecordComment("-- Call entry point --"); @@ -2939,6 +3284,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { __ Ret(); } +#ifndef V8_REVERSE_JSARGS // ----------------------------------------- // Adapt arguments in the existing frame. // ----------------------------------------- @@ -2976,6 +3322,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { __ B(&dont_adapt_arguments); } } +#endif // ------------------------------------------- // Dont adapt arguments. @@ -3492,6 +3839,7 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) { // -- sp[(argc - 1) * 8] : first argument // -- sp[(argc + 0) * 8] : receiver // ----------------------------------- + // NOTE: The order of args in the stack are reversed if V8_REVERSE_JSARGS Register api_function_address = x1; Register argc = x2; @@ -3561,9 +3909,14 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) { // FunctionCallbackInfo::values_ (points at the first varargs argument passed // on the stack). +#ifdef V8_REVERSE_JSARGS + __ Add(scratch, scratch, + Operand((FCA::kArgsLength + 1) * kSystemPointerSize)); +#else __ Add(scratch, scratch, Operand((FCA::kArgsLength - 1) * kSystemPointerSize)); __ Add(scratch, scratch, Operand(argc, LSL, kSystemPointerSizeLog2)); +#endif __ Str(scratch, MemOperand(sp, 2 * kSystemPointerSize)); // FunctionCallbackInfo::length_. diff --git a/deps/v8/src/builtins/array-copywithin.tq b/deps/v8/src/builtins/array-copywithin.tq index cee0b1e1a48355..3d2a456efbb3a8 100644 --- a/deps/v8/src/builtins/array-copywithin.tq +++ b/deps/v8/src/builtins/array-copywithin.tq @@ -3,92 +3,91 @@ // found in the LICENSE file. namespace array { - macro ConvertToRelativeIndex(index: Number, length: Number): Number { - return index < 0 ? Max(index + length, 0) : Min(index, length); - } +macro ConvertToRelativeIndex(index: Number, length: Number): Number { + return index < 0 ? Max(index + length, 0) : Min(index, length); +} - // https://tc39.github.io/ecma262/#sec-array.prototype.copyWithin - transitioning javascript builtin ArrayPrototypeCopyWithin( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - // 1. Let O be ? ToObject(this value). - const object: JSReceiver = ToObject_Inline(context, receiver); +// https://tc39.github.io/ecma262/#sec-array.prototype.copyWithin +transitioning javascript builtin ArrayPrototypeCopyWithin( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // 1. Let O be ? ToObject(this value). + const object: JSReceiver = ToObject_Inline(context, receiver); - // 2. Let len be ? ToLength(? Get(O, "length")). - const length: Number = GetLengthProperty(object); + // 2. Let len be ? ToLength(? Get(O, "length")). + const length: Number = GetLengthProperty(object); - // 3. Let relativeTarget be ? ToInteger(target). - const relativeTarget: Number = ToInteger_Inline(arguments[0]); + // 3. Let relativeTarget be ? ToInteger(target). + const relativeTarget: Number = ToInteger_Inline(arguments[0]); - // 4. If relativeTarget < 0, let to be max((len + relativeTarget), 0); - // else let to be min(relativeTarget, len). - let to: Number = ConvertToRelativeIndex(relativeTarget, length); + // 4. If relativeTarget < 0, let to be max((len + relativeTarget), 0); + // else let to be min(relativeTarget, len). + let to: Number = ConvertToRelativeIndex(relativeTarget, length); - // 5. Let relativeStart be ? ToInteger(start). - const relativeStart: Number = ToInteger_Inline(arguments[1]); + // 5. Let relativeStart be ? ToInteger(start). + const relativeStart: Number = ToInteger_Inline(arguments[1]); - // 6. If relativeStart < 0, let from be max((len + relativeStart), 0); - // else let from be min(relativeStart, len). - let from: Number = ConvertToRelativeIndex(relativeStart, length); + // 6. If relativeStart < 0, let from be max((len + relativeStart), 0); + // else let from be min(relativeStart, len). + let from: Number = ConvertToRelativeIndex(relativeStart, length); - // 7. If end is undefined, let relativeEnd be len; - // else let relativeEnd be ? ToInteger(end). - let relativeEnd: Number = length; - if (arguments[2] != Undefined) { - relativeEnd = ToInteger_Inline(arguments[2]); - } + // 7. If end is undefined, let relativeEnd be len; + // else let relativeEnd be ? ToInteger(end). + let relativeEnd: Number = length; + if (arguments[2] != Undefined) { + relativeEnd = ToInteger_Inline(arguments[2]); + } - // 8. If relativeEnd < 0, let final be max((len + relativeEnd), 0); - // else let final be min(relativeEnd, len). - const final: Number = ConvertToRelativeIndex(relativeEnd, length); + // 8. If relativeEnd < 0, let final be max((len + relativeEnd), 0); + // else let final be min(relativeEnd, len). + const final: Number = ConvertToRelativeIndex(relativeEnd, length); - // 9. Let count be min(final-from, len-to). - let count: Number = Min(final - from, length - to); + // 9. Let count be min(final-from, len-to). + let count: Number = Min(final - from, length - to); - // 10. If from 0. - while (count > 0) { - // a. Let fromKey be ! ToString(from). - // b. Let toKey be ! ToString(to). - // c. Let fromPresent be ? HasProperty(O, fromKey). - const fromPresent: Boolean = HasProperty(object, from); - - // d. If fromPresent is true, then. - if (fromPresent == True) { - // i. Let fromVal be ? Get(O, fromKey). - const fromVal: JSAny = GetProperty(object, from); - - // ii. Perform ? Set(O, toKey, fromVal, true). - SetProperty(object, to, fromVal); - } else { - // i. Perform ? DeletePropertyOrThrow(O, toKey). - DeleteProperty(object, to, LanguageMode::kStrict); - } - - // f. Let from be from + direction. - from = from + direction; - - // g. Let to be to + direction. - to = to + direction; - - // h. Let count be count - 1. - --count; + // 12. Repeat, while count > 0. + while (count > 0) { + // a. Let fromKey be ! ToString(from). + // b. Let toKey be ! ToString(to). + // c. Let fromPresent be ? HasProperty(O, fromKey). + const fromPresent: Boolean = HasProperty(object, from); + + // d. If fromPresent is true, then. + if (fromPresent == True) { + // i. Let fromVal be ? Get(O, fromKey). + const fromVal: JSAny = GetProperty(object, from); + + // ii. Perform ? Set(O, toKey, fromVal, true). + SetProperty(object, to, fromVal); + } else { + // i. Perform ? DeletePropertyOrThrow(O, toKey). + DeleteProperty(object, to, LanguageMode::kStrict); } - // 13. Return O. - return object; + // f. Let from be from + direction. + from = from + direction; + + // g. Let to be to + direction. + to = to + direction; + + // h. Let count be count - 1. + --count; } + + // 13. Return O. + return object; +} } diff --git a/deps/v8/src/builtins/array-every.tq b/deps/v8/src/builtins/array-every.tq index 4e5f99d40a5202..2514a18b747ab6 100644 --- a/deps/v8/src/builtins/array-every.tq +++ b/deps/v8/src/builtins/array-every.tq @@ -3,145 +3,142 @@ // found in the LICENSE file. namespace array { - transitioning javascript builtin - ArrayEveryLoopEagerDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { - // All continuation points in the optimized every implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - // - // Also, this great mass of casts is necessary because the signature - // of Torque javascript builtins requires JSAny type for all parameters - // other than {context}. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - return ArrayEveryLoopContinuation( - jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, - numberLength, Undefined); +transitioning javascript builtin +ArrayEveryLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { + // All continuation points in the optimized every implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + // + // Also, this great mass of casts is necessary because the signature + // of Torque javascript builtins requires JSAny type for all parameters + // other than {context}. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + return ArrayEveryLoopContinuation( + jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, + numberLength, Undefined); +} + +transitioning javascript builtin +ArrayEveryLoopLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, + result: JSAny): JSAny { + // All continuation points in the optimized every implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + let numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + // This custom lazy deopt point is right after the callback. every() needs + // to pick up at the next step, which is either continuing to the next + // array element or returning false if {result} is false. + if (!ToBoolean(result)) { + return False; } - transitioning javascript builtin - ArrayEveryLoopLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, - result: JSAny): JSAny { - // All continuation points in the optimized every implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - let numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - // This custom lazy deopt point is right after the callback. every() needs - // to pick up at the next step, which is either continuing to the next - // array element or returning false if {result} is false. - if (!ToBoolean(result)) { - return False; - } + numberK = numberK + 1; - numberK = numberK + 1; + return ArrayEveryLoopContinuation( + jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, + numberLength, Undefined); +} - return ArrayEveryLoopContinuation( - jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, - numberLength, Undefined); - } +transitioning builtin ArrayEveryLoopContinuation(implicit context: Context)( + _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, _array: JSAny, + o: JSReceiver, initialK: Number, length: Number, _initialTo: JSAny): JSAny { + // 5. Let k be 0. + // 6. Repeat, while k < len + for (let k: Number = initialK; k < length; k++) { + // 6a. Let Pk be ! ToString(k). + // k is guaranteed to be a positive integer, hence ToString is + // side-effect free and HasProperty/GetProperty do the conversion inline. - transitioning builtin ArrayEveryLoopContinuation(implicit context: Context)( - _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, - _array: JSAny, o: JSReceiver, initialK: Number, length: Number, - _initialTo: JSAny): JSAny { - // 5. Let k be 0. - // 6. Repeat, while k < len - for (let k: Number = initialK; k < length; k++) { - // 6a. Let Pk be ! ToString(k). - // k is guaranteed to be a positive integer, hence ToString is - // side-effect free and HasProperty/GetProperty do the conversion inline. - - // 6b. Let kPresent be ? HasProperty(O, Pk). - const kPresent: Boolean = HasProperty_Inline(o, k); - - // 6c. If kPresent is true, then - if (kPresent == True) { - // 6c. i. Let kValue be ? Get(O, Pk). - const kValue: JSAny = GetProperty(o, k); - - // 6c. ii. Perform ? Call(callbackfn, T, ). - const result: JSAny = Call(context, callbackfn, thisArg, kValue, k, o); - - // iii. If selected is true, then... - if (!ToBoolean(result)) { - return False; - } - } + // 6b. Let kPresent be ? HasProperty(O, Pk). + const kPresent: Boolean = HasProperty_Inline(o, k); - // 6d. Increase k by 1. (done by the loop). - } - return True; - } + // 6c. If kPresent is true, then + if (kPresent == True) { + // 6c. i. Let kValue be ? Get(O, Pk). + const kValue: JSAny = GetProperty(o, k); + + // 6c. ii. Perform ? Call(callbackfn, T, ). + const result: JSAny = Call(context, callbackfn, thisArg, kValue, k, o); - transitioning macro FastArrayEvery(implicit context: Context)( - o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny - labels Bailout(Smi) { - let k: Smi = 0; - const smiLen = Cast(len) otherwise goto Bailout(k); - const fastO: FastJSArray = Cast(o) otherwise goto Bailout(k); - let fastOW = NewFastJSArrayWitness(fastO); - - // Build a fast loop over the smi array. - for (; k < smiLen; k++) { - fastOW.Recheck() otherwise goto Bailout(k); - - // Ensure that we haven't walked beyond a possibly updated length. - if (k >= fastOW.Get().length) goto Bailout(k); - const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; - const result: JSAny = - Call(context, callbackfn, thisArg, value, k, fastOW.Get()); + // iii. If selected is true, then... if (!ToBoolean(result)) { return False; } } - return True; - } - // https://tc39.github.io/ecma262/#sec-array.prototype.every - transitioning javascript builtin - ArrayEvery(js-implicit context: NativeContext, receiver: JSAny)(...arguments): - JSAny { - try { - RequireObjectCoercible(receiver, 'Array.prototype.every'); + // 6d. Increase k by 1. (done by the loop). + } + return True; +} - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); +transitioning macro FastArrayEvery(implicit context: Context)( + o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny + labels Bailout(Smi) { + let k: Smi = 0; + const smiLen = Cast(len) otherwise goto Bailout(k); + const fastO: FastJSArray = Cast(o) otherwise goto Bailout(k); + let fastOW = NewFastJSArrayWitness(fastO); + + // Build a fast loop over the smi array. + for (; k < smiLen; k++) { + fastOW.Recheck() otherwise goto Bailout(k); + + // Ensure that we haven't walked beyond a possibly updated length. + if (k >= fastOW.Get().length) goto Bailout(k); + const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; + const result: JSAny = + Call(context, callbackfn, thisArg, value, k, fastOW.Get()); + if (!ToBoolean(result)) { + return False; + } + } + return True; +} - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); +// https://tc39.github.io/ecma262/#sec-array.prototype.every +transitioning javascript builtin +ArrayEvery( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + RequireObjectCoercible(receiver, 'Array.prototype.every'); - // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. - if (arguments.length == 0) { - goto TypeError; - } - const callbackfn = Cast(arguments[0]) otherwise TypeError; + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); - // 4. If thisArg is present, let T be thisArg; else let T be undefined. - const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined; + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); - // Special cases. - try { - return FastArrayEvery(o, len, callbackfn, thisArg) - otherwise Bailout; - } - label Bailout(kValue: Smi) deferred { - return ArrayEveryLoopContinuation( - o, callbackfn, thisArg, Undefined, o, kValue, len, Undefined); - } + // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + if (arguments.length == 0) { + goto TypeError; } - label TypeError deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + const callbackfn = Cast(arguments[0]) otherwise TypeError; + + // 4. If thisArg is present, let T be thisArg; else let T be undefined. + const thisArg: JSAny = arguments[1]; + + // Special cases. + try { + return FastArrayEvery(o, len, callbackfn, thisArg) + otherwise Bailout; + } label Bailout(kValue: Smi) deferred { + return ArrayEveryLoopContinuation( + o, callbackfn, thisArg, Undefined, o, kValue, len, Undefined); } + } label TypeError deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); } } +} diff --git a/deps/v8/src/builtins/array-filter.tq b/deps/v8/src/builtins/array-filter.tq index 1da1c551664675..1add88fa6a41ef 100644 --- a/deps/v8/src/builtins/array-filter.tq +++ b/deps/v8/src/builtins/array-filter.tq @@ -3,200 +3,197 @@ // found in the LICENSE file. namespace array { - transitioning javascript builtin - ArrayFilterLoopEagerDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny, - length: JSAny, initialTo: JSAny): JSAny { - // All continuation points in the optimized filter implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - // - // Also, this great mass of casts is necessary because the signature - // of Torque javascript builtins requires JSAny type for all parameters - // other than {context}. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const outputArray = Cast(array) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberTo = Cast(initialTo) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; +transitioning javascript builtin +ArrayFilterLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny, + length: JSAny, initialTo: JSAny): JSAny { + // All continuation points in the optimized filter implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + // + // Also, this great mass of casts is necessary because the signature + // of Torque javascript builtins requires JSAny type for all parameters + // other than {context}. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const outputArray = Cast(array) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberTo = Cast(initialTo) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + return ArrayFilterLoopContinuation( + jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK, + numberLength, numberTo); +} - return ArrayFilterLoopContinuation( - jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK, - numberLength, numberTo); +transitioning javascript builtin +ArrayFilterLoopLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny, + length: JSAny, valueK: JSAny, initialTo: JSAny, result: JSAny): JSAny { + // All continuation points in the optimized filter implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const outputArray = Cast(array) otherwise unreachable; + let numberK = Cast(initialK) otherwise unreachable; + let numberTo = Cast(initialTo) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + // This custom lazy deopt point is right after the callback. filter() needs + // to pick up at the next step, which is setting the callback + // result in the output array. After incrementing k and to, we can glide + // into the loop continuation builtin. + if (ToBoolean(result)) { + FastCreateDataProperty(outputArray, numberTo, valueK); + numberTo = numberTo + 1; } - transitioning javascript builtin - ArrayFilterLoopLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny, - length: JSAny, valueK: JSAny, initialTo: JSAny, result: JSAny): JSAny { - // All continuation points in the optimized filter implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const outputArray = Cast(array) otherwise unreachable; - let numberK = Cast(initialK) otherwise unreachable; - let numberTo = Cast(initialTo) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - // This custom lazy deopt point is right after the callback. filter() needs - // to pick up at the next step, which is setting the callback - // result in the output array. After incrementing k and to, we can glide - // into the loop continuation builtin. - if (ToBoolean(result)) { - FastCreateDataProperty(outputArray, numberTo, valueK); - numberTo = numberTo + 1; - } - - numberK = numberK + 1; + numberK = numberK + 1; - return ArrayFilterLoopContinuation( - jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK, - numberLength, numberTo); - } + return ArrayFilterLoopContinuation( + jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK, + numberLength, numberTo); +} - transitioning builtin ArrayFilterLoopContinuation(implicit context: Context)( - _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, - array: JSReceiver, o: JSReceiver, initialK: Number, length: Number, - initialTo: Number): JSAny { - let to: Number = initialTo; - // 5. Let k be 0. - // 6. Repeat, while k < len - for (let k: Number = initialK; k < length; k++) { - // 6a. Let Pk be ! ToString(k). - // k is guaranteed to be a positive integer, hence ToString is - // side-effect free and HasProperty/GetProperty do the conversion inline. - - // 6b. Let kPresent be ? HasProperty(O, Pk). - const kPresent: Boolean = HasProperty_Inline(o, k); - - // 6c. If kPresent is true, then - if (kPresent == True) { - // 6c. i. Let kValue be ? Get(O, Pk). - const kValue: JSAny = GetProperty(o, k); - - // 6c. ii. Perform ? Call(callbackfn, T, ). - const result: JSAny = Call(context, callbackfn, thisArg, kValue, k, o); - - // iii. If selected is true, then... - if (ToBoolean(result)) { - // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue). - FastCreateDataProperty(array, to, kValue); - // 2. Increase to by 1. - to = to + 1; - } +transitioning builtin ArrayFilterLoopContinuation(implicit context: Context)( + _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, + array: JSReceiver, o: JSReceiver, initialK: Number, length: Number, + initialTo: Number): JSAny { + let to: Number = initialTo; + // 5. Let k be 0. + // 6. Repeat, while k < len + for (let k: Number = initialK; k < length; k++) { + // 6a. Let Pk be ! ToString(k). + // k is guaranteed to be a positive integer, hence ToString is + // side-effect free and HasProperty/GetProperty do the conversion inline. + + // 6b. Let kPresent be ? HasProperty(O, Pk). + const kPresent: Boolean = HasProperty_Inline(o, k); + + // 6c. If kPresent is true, then + if (kPresent == True) { + // 6c. i. Let kValue be ? Get(O, Pk). + const kValue: JSAny = GetProperty(o, k); + + // 6c. ii. Perform ? Call(callbackfn, T, ). + const result: JSAny = Call(context, callbackfn, thisArg, kValue, k, o); + + // iii. If selected is true, then... + if (ToBoolean(result)) { + // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue). + FastCreateDataProperty(array, to, kValue); + // 2. Increase to by 1. + to = to + 1; } - - // 6d. Increase k by 1. (done by the loop). } - return array; + + // 6d. Increase k by 1. (done by the loop). } + return array; +} - transitioning macro FastArrayFilter(implicit context: Context)( - fastO: FastJSArray, len: Smi, callbackfn: Callable, thisArg: JSAny, - output: FastJSArray) labels Bailout(Number, Number) { - let k: Smi = 0; - let to: Smi = 0; - let fastOW = NewFastJSArrayWitness(fastO); - let fastOutputW = NewFastJSArrayWitness(output); - - fastOutputW.EnsureArrayPushable() otherwise goto Bailout(k, to); - - // Build a fast loop over the array. - for (; k < len; k++) { - fastOW.Recheck() otherwise goto Bailout(k, to); - - // Ensure that we haven't walked beyond a possibly updated length. - if (k >= fastOW.Get().length) goto Bailout(k, to); - const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; - const result: JSAny = - Call(context, callbackfn, thisArg, value, k, fastOW.Get()); - if (ToBoolean(result)) { - try { - // Since the call to {callbackfn} is observable, we can't - // use the Bailout label until we've successfully stored. - // Hence the {SlowStore} label. - fastOutputW.Recheck() otherwise SlowStore; - if (fastOutputW.Get().length != to) goto SlowStore; - fastOutputW.Push(value) otherwise SlowStore; - } - label SlowStore { - FastCreateDataProperty(fastOutputW.stable, to, value); - } - to = to + 1; +transitioning macro FastArrayFilter(implicit context: Context)( + fastO: FastJSArray, len: Smi, callbackfn: Callable, thisArg: JSAny, + output: FastJSArray) labels +Bailout(Number, Number) { + let k: Smi = 0; + let to: Smi = 0; + let fastOW = NewFastJSArrayWitness(fastO); + let fastOutputW = NewFastJSArrayWitness(output); + + fastOutputW.EnsureArrayPushable() otherwise goto Bailout(k, to); + + // Build a fast loop over the array. + for (; k < len; k++) { + fastOW.Recheck() otherwise goto Bailout(k, to); + + // Ensure that we haven't walked beyond a possibly updated length. + if (k >= fastOW.Get().length) goto Bailout(k, to); + const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; + const result: JSAny = + Call(context, callbackfn, thisArg, value, k, fastOW.Get()); + if (ToBoolean(result)) { + try { + // Since the call to {callbackfn} is observable, we can't + // use the Bailout label until we've successfully stored. + // Hence the {SlowStore} label. + fastOutputW.Recheck() otherwise SlowStore; + if (fastOutputW.Get().length != to) goto SlowStore; + fastOutputW.Push(value) otherwise SlowStore; + } label SlowStore { + FastCreateDataProperty(fastOutputW.stable, to, value); } + to = to + 1; } } +} - // This method creates a 0-length array with the ElementsKind of the - // receiver if possible, otherwise, bails out. It makes sense for the - // caller to know that the slow case needs to be invoked. - macro FastFilterSpeciesCreate(implicit context: Context)( - receiver: JSReceiver): JSReceiver labels Slow { - const len: Smi = 0; - if (IsArraySpeciesProtectorCellInvalid()) goto Slow; - const o = Cast(receiver) otherwise Slow; - const newMap: Map = - LoadJSArrayElementsMap(o.map.elements_kind, LoadNativeContext(context)); - return AllocateJSArray(ElementsKind::PACKED_SMI_ELEMENTS, newMap, len, len); - } +// This method creates a 0-length array with the ElementsKind of the +// receiver if possible, otherwise, bails out. It makes sense for the +// caller to know that the slow case needs to be invoked. +macro FastFilterSpeciesCreate(implicit context: Context)(receiver: JSReceiver): + JSReceiver labels Slow { + const len: Smi = 0; + if (IsArraySpeciesProtectorCellInvalid()) goto Slow; + const o = Cast(receiver) otherwise Slow; + const newMap: Map = + LoadJSArrayElementsMap(o.map.elements_kind, LoadNativeContext(context)); + return AllocateJSArray(ElementsKind::PACKED_SMI_ELEMENTS, newMap, len, len); +} - // https://tc39.github.io/ecma262/#sec-array.prototype.filter - transitioning javascript builtin - ArrayFilter(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - try { - RequireObjectCoercible(receiver, 'Array.prototype.filter'); +// https://tc39.github.io/ecma262/#sec-array.prototype.filter +transitioning javascript builtin +ArrayFilter( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + RequireObjectCoercible(receiver, 'Array.prototype.filter'); - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); - // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. - if (arguments.length == 0) { - goto TypeError; - } - const callbackfn = Cast(arguments[0]) otherwise TypeError; + // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + if (arguments.length == 0) { + goto TypeError; + } + const callbackfn = Cast(arguments[0]) otherwise TypeError; - // 4. If thisArg is present, let T be thisArg; else let T be undefined. - const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - let output: JSReceiver; + // 4. If thisArg is present, let T be thisArg; else let T be undefined. + const thisArg: JSAny = arguments[1]; + let output: JSReceiver; + + // Special cases. + let k: Number = 0; + let to: Number = 0; + try { + output = FastFilterSpeciesCreate(o) otherwise SlowSpeciesCreate; - // Special cases. - let k: Number = 0; - let to: Number = 0; try { - output = FastFilterSpeciesCreate(o) otherwise SlowSpeciesCreate; - - try { - const smiLen: Smi = Cast(len) otherwise goto Bailout(k, to); - const fastOutput = - Cast(output) otherwise goto Bailout(k, to); - const fastO = Cast(o) otherwise goto Bailout(k, to); - - FastArrayFilter(fastO, smiLen, callbackfn, thisArg, fastOutput) - otherwise Bailout; - return output; - } - label Bailout(kValue: Number, toValue: Number) deferred { - k = kValue; - to = toValue; - } - } - label SlowSpeciesCreate { - output = ArraySpeciesCreate(context, receiver, 0); + const smiLen: Smi = Cast(len) otherwise goto Bailout(k, to); + const fastOutput = + Cast(output) otherwise goto Bailout(k, to); + const fastO = Cast(o) otherwise goto Bailout(k, to); + + FastArrayFilter(fastO, smiLen, callbackfn, thisArg, fastOutput) + otherwise Bailout; + return output; + } label Bailout(kValue: Number, toValue: Number) deferred { + k = kValue; + to = toValue; } - - return ArrayFilterLoopContinuation( - o, callbackfn, thisArg, output, o, k, len, to); - } - label TypeError deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + } label SlowSpeciesCreate { + output = ArraySpeciesCreate(context, receiver, 0); } + + return ArrayFilterLoopContinuation( + o, callbackfn, thisArg, output, o, k, len, to); + } label TypeError deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); } } +} diff --git a/deps/v8/src/builtins/array-find.tq b/deps/v8/src/builtins/array-find.tq index cd3ec45e98e7fe..9b53f9c7000673 100644 --- a/deps/v8/src/builtins/array-find.tq +++ b/deps/v8/src/builtins/array-find.tq @@ -3,152 +3,149 @@ // found in the LICENSE file. namespace array { - transitioning javascript builtin - ArrayFindLoopEagerDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { - // All continuation points in the optimized find implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - // - // Also, this great mass of casts is necessary because the signature - // of Torque javascript builtins requires JSAny type for all parameters - // other than {context}. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - return ArrayFindLoopContinuation( - jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength); - } +transitioning javascript builtin +ArrayFindLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { + // All continuation points in the optimized find implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + // + // Also, this great mass of casts is necessary because the signature + // of Torque javascript builtins requires JSAny type for all parameters + // other than {context}. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + return ArrayFindLoopContinuation( + jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength); +} + +transitioning javascript builtin +ArrayFindLoopLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + _callback: JSAny, _thisArg: JSAny, _initialK: JSAny, _length: JSAny, + _result: JSAny): JSAny { + // This deopt continuation point is never actually called, it just + // exists to make stack traces correct from a ThrowTypeError if the + // callback was found to be non-callable. + unreachable; +} - transitioning javascript builtin - ArrayFindLoopLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - _callback: JSAny, _thisArg: JSAny, _initialK: JSAny, _length: JSAny, - _result: JSAny): JSAny { - // This deopt continuation point is never actually called, it just - // exists to make stack traces correct from a ThrowTypeError if the - // callback was found to be non-callable. - unreachable; +// Continuation that is called after a lazy deoptimization from TF that +// happens right after the callback and it's returned value must be handled +// before iteration continues. +transitioning javascript builtin +ArrayFindLoopAfterCallbackLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, + foundValue: JSAny, isFound: JSAny): JSAny { + // All continuation points in the optimized find implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + // This custom lazy deopt point is right after the callback. find() needs + // to pick up at the next step, which is returning the element if the + // callback value is truthy. Otherwise, continue the search by calling the + // continuation. + + if (ToBoolean(isFound)) { + return foundValue; } - // Continuation that is called after a lazy deoptimization from TF that - // happens right after the callback and it's returned value must be handled - // before iteration continues. - transitioning javascript builtin - ArrayFindLoopAfterCallbackLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, - foundValue: JSAny, isFound: JSAny): JSAny { - // All continuation points in the optimized find implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - // This custom lazy deopt point is right after the callback. find() needs - // to pick up at the next step, which is returning the element if the - // callback value is truthy. Otherwise, continue the search by calling the - // continuation. - - if (ToBoolean(isFound)) { - return foundValue; + return ArrayFindLoopContinuation( + jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength); +} + +transitioning builtin ArrayFindLoopContinuation(implicit context: Context)( + _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, o: JSReceiver, + initialK: Number, length: Number): JSAny { + // 5. Let k be 0. + // 6. Repeat, while k < len + for (let k: Number = initialK; k < length; k++) { + // 6a. Let Pk be ! ToString(k). + // k is guaranteed to be a positive integer, hence ToString is + // side-effect free and HasProperty/GetProperty do the conversion inline. + + // 6b. i. Let kValue be ? Get(O, Pk). + const value: JSAny = GetProperty(o, k); + + // 6c. Let testResult be ToBoolean(? Call(predicate, T, <>)). + const testResult: JSAny = Call(context, callbackfn, thisArg, value, k, o); + + // 6d. If testResult is true, return kValue. + if (ToBoolean(testResult)) { + return value; } - return ArrayFindLoopContinuation( - jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength); + // 6e. Increase k by 1. (done by the loop). } + return Undefined; +} - transitioning builtin ArrayFindLoopContinuation(implicit context: Context)( - _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, - o: JSReceiver, initialK: Number, length: Number): JSAny { - // 5. Let k be 0. - // 6. Repeat, while k < len - for (let k: Number = initialK; k < length; k++) { - // 6a. Let Pk be ! ToString(k). - // k is guaranteed to be a positive integer, hence ToString is - // side-effect free and HasProperty/GetProperty do the conversion inline. - - // 6b. i. Let kValue be ? Get(O, Pk). - const value: JSAny = GetProperty(o, k); - - // 6c. Let testResult be ToBoolean(? Call(predicate, T, <>)). - const testResult: JSAny = Call(context, callbackfn, thisArg, value, k, o); - - // 6d. If testResult is true, return kValue. - if (ToBoolean(testResult)) { - return value; - } - - // 6e. Increase k by 1. (done by the loop). +transitioning macro FastArrayFind(implicit context: Context)( + o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny + labels Bailout(Smi) { + let k: Smi = 0; + const smiLen = Cast(len) otherwise goto Bailout(k); + const fastO = Cast(o) otherwise goto Bailout(k); + let fastOW = NewFastJSArrayWitness(fastO); + + // Build a fast loop over the smi array. + for (; k < smiLen; k++) { + fastOW.Recheck() otherwise goto Bailout(k); + + // Ensure that we haven't walked beyond a possibly updated length. + if (k >= fastOW.Get().length) goto Bailout(k); + + const value: JSAny = fastOW.LoadElementOrUndefined(k); + const testResult: JSAny = + Call(context, callbackfn, thisArg, value, k, fastOW.Get()); + if (ToBoolean(testResult)) { + return value; } - return Undefined; } + return Undefined; +} - transitioning macro FastArrayFind(implicit context: Context)( - o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny - labels Bailout(Smi) { - let k: Smi = 0; - const smiLen = Cast(len) otherwise goto Bailout(k); - const fastO = Cast(o) otherwise goto Bailout(k); - let fastOW = NewFastJSArrayWitness(fastO); - - // Build a fast loop over the smi array. - for (; k < smiLen; k++) { - fastOW.Recheck() otherwise goto Bailout(k); - - // Ensure that we haven't walked beyond a possibly updated length. - if (k >= fastOW.Get().length) goto Bailout(k); - - const value: JSAny = fastOW.LoadElementOrUndefined(k); - const testResult: JSAny = - Call(context, callbackfn, thisArg, value, k, fastOW.Get()); - if (ToBoolean(testResult)) { - return value; - } +// https://tc39.github.io/ecma262/#sec-array.prototype.find +transitioning javascript builtin +ArrayPrototypeFind( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + RequireObjectCoercible(receiver, 'Array.prototype.find'); + + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); + + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); + + // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + if (arguments.length == 0) { + goto NotCallableError; } - return Undefined; - } + const callbackfn = Cast(arguments[0]) otherwise NotCallableError; - // https://tc39.github.io/ecma262/#sec-array.prototype.find - transitioning javascript builtin - ArrayPrototypeFind(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { + // 4. If thisArg is present, let T be thisArg; else let T be undefined. + const thisArg: JSAny = arguments[1]; + + // Special cases. try { - RequireObjectCoercible(receiver, 'Array.prototype.find'); - - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); - - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); - - // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. - if (arguments.length == 0) { - goto NotCallableError; - } - const callbackfn = - Cast(arguments[0]) otherwise NotCallableError; - - // 4. If thisArg is present, let T be thisArg; else let T be undefined. - const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - - // Special cases. - try { - return FastArrayFind(o, len, callbackfn, thisArg) - otherwise Bailout; - } - label Bailout(k: Smi) deferred { - return ArrayFindLoopContinuation(o, callbackfn, thisArg, o, k, len); - } - } - label NotCallableError deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + return FastArrayFind(o, len, callbackfn, thisArg) + otherwise Bailout; + } label Bailout(k: Smi) deferred { + return ArrayFindLoopContinuation(o, callbackfn, thisArg, o, k, len); } + } label NotCallableError deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); } } +} diff --git a/deps/v8/src/builtins/array-findindex.tq b/deps/v8/src/builtins/array-findindex.tq index 05a264064669b1..ed70a122594e42 100644 --- a/deps/v8/src/builtins/array-findindex.tq +++ b/deps/v8/src/builtins/array-findindex.tq @@ -3,154 +3,149 @@ // found in the LICENSE file. namespace array { - transitioning javascript builtin - ArrayFindIndexLoopEagerDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { - // All continuation points in the optimized findIndex implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - // - // Also, this great mass of casts is necessary because the signature - // of Torque javascript builtins requires JSAny type for all parameters - // other than {context}. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - return ArrayFindIndexLoopContinuation( - jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength); - } +transitioning javascript builtin +ArrayFindIndexLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { + // All continuation points in the optimized findIndex implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + // + // Also, this great mass of casts is necessary because the signature + // of Torque javascript builtins requires JSAny type for all parameters + // other than {context}. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + return ArrayFindIndexLoopContinuation( + jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength); +} + +transitioning javascript builtin +ArrayFindIndexLoopLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + _callback: JSAny, _thisArg: JSAny, _initialK: JSAny, _length: JSAny, + _result: JSAny): JSAny { + // This deopt continuation point is never actually called, it just + // exists to make stack traces correct from a ThrowTypeError if the + // callback was found to be non-callable. + unreachable; +} - transitioning javascript builtin - ArrayFindIndexLoopLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - _callback: JSAny, _thisArg: JSAny, _initialK: JSAny, _length: JSAny, - _result: JSAny): JSAny { - // This deopt continuation point is never actually called, it just - // exists to make stack traces correct from a ThrowTypeError if the - // callback was found to be non-callable. - unreachable; +// Continuation that is called after a lazy deoptimization from TF that +// happens right after the callback and it's returned value must be handled +// before iteration continues. +transitioning javascript builtin +ArrayFindIndexLoopAfterCallbackLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, + foundValue: JSAny, isFound: JSAny): JSAny { + // All continuation points in the optimized findIndex implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + // This custom lazy deopt point is right after the callback. find() needs + // to pick up at the next step, which is returning the element if the + // callback value is truthy. Otherwise, continue the search by calling the + // continuation. + + if (ToBoolean(isFound)) { + return foundValue; } - // Continuation that is called after a lazy deoptimization from TF that - // happens right after the callback and it's returned value must be handled - // before iteration continues. - transitioning javascript builtin - ArrayFindIndexLoopAfterCallbackLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, - foundValue: JSAny, isFound: JSAny): JSAny { - // All continuation points in the optimized findIndex implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - // This custom lazy deopt point is right after the callback. find() needs - // to pick up at the next step, which is returning the element if the - // callback value is truthy. Otherwise, continue the search by calling the - // continuation. - - if (ToBoolean(isFound)) { - return foundValue; + return ArrayFindIndexLoopContinuation( + jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength); +} + +transitioning builtin ArrayFindIndexLoopContinuation(implicit context: Context)( + _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, o: JSReceiver, + initialK: Number, length: Number): Number { + // 5. Let k be 0. + // 6. Repeat, while k < len + for (let k: Number = initialK; k < length; k++) { + // 6a. Let Pk be ! ToString(k). + // k is guaranteed to be a positive integer, hence ToString is + // side-effect free and HasProperty/GetProperty do the conversion inline. + + // 6b. i. Let kValue be ? Get(O, Pk). + const value: JSAny = GetProperty(o, k); + + // 6c. Let testResult be ToBoolean(? Call(predicate, T, <>)). + const testResult: JSAny = Call(context, callbackfn, thisArg, value, k, o); + + // 6d. If testResult is true, return k. + if (ToBoolean(testResult)) { + return k; } - return ArrayFindIndexLoopContinuation( - jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength); + // 6e. Increase k by 1. (done by the loop). } + return Convert(-1); +} - transitioning builtin ArrayFindIndexLoopContinuation(implicit context: - Context)( - _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, - o: JSReceiver, initialK: Number, length: Number): Number { - // 5. Let k be 0. - // 6. Repeat, while k < len - for (let k: Number = initialK; k < length; k++) { - // 6a. Let Pk be ! ToString(k). - // k is guaranteed to be a positive integer, hence ToString is - // side-effect free and HasProperty/GetProperty do the conversion inline. - - // 6b. i. Let kValue be ? Get(O, Pk). - const value: JSAny = GetProperty(o, k); - - // 6c. Let testResult be ToBoolean(? Call(predicate, T, <>)). - const testResult: JSAny = Call(context, callbackfn, thisArg, value, k, o); - - // 6d. If testResult is true, return k. - if (ToBoolean(testResult)) { - return k; - } - - // 6e. Increase k by 1. (done by the loop). +transitioning macro FastArrayFindIndex(implicit context: Context)( + o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): Number + labels Bailout(Smi) { + let k: Smi = 0; + const smiLen = Cast(len) otherwise goto Bailout(k); + const fastO = Cast(o) otherwise goto Bailout(k); + let fastOW = NewFastJSArrayWitness(fastO); + + // Build a fast loop over the smi array. + for (; k < smiLen; k++) { + fastOW.Recheck() otherwise goto Bailout(k); + + // Ensure that we haven't walked beyond a possibly updated length. + if (k >= fastOW.Get().length) goto Bailout(k); + + const value: JSAny = fastOW.LoadElementOrUndefined(k); + const testResult: JSAny = + Call(context, callbackfn, thisArg, value, k, fastOW.Get()); + if (ToBoolean(testResult)) { + return k; } - return Convert(-1); } + return -1; +} - transitioning macro FastArrayFindIndex(implicit context: Context)( - o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): Number - labels Bailout(Smi) { - let k: Smi = 0; - const smiLen = Cast(len) otherwise goto Bailout(k); - const fastO = Cast(o) otherwise goto Bailout(k); - let fastOW = NewFastJSArrayWitness(fastO); - - // Build a fast loop over the smi array. - for (; k < smiLen; k++) { - fastOW.Recheck() otherwise goto Bailout(k); - - // Ensure that we haven't walked beyond a possibly updated length. - if (k >= fastOW.Get().length) goto Bailout(k); - - const value: JSAny = fastOW.LoadElementOrUndefined(k); - const testResult: JSAny = - Call(context, callbackfn, thisArg, value, k, fastOW.Get()); - if (ToBoolean(testResult)) { - return k; - } +// https://tc39.github.io/ecma262/#sec-array.prototype.findIndex +transitioning javascript builtin +ArrayPrototypeFindIndex( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + RequireObjectCoercible(receiver, 'Array.prototype.findIndex'); + + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); + + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); + + // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + if (arguments.length == 0) { + goto NotCallableError; } - return -1; - } + const callbackfn = Cast(arguments[0]) otherwise NotCallableError; - // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex - transitioning javascript builtin - ArrayPrototypeFindIndex(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { + // 4. If thisArg is present, let T be thisArg; else let T be undefined. + const thisArg: JSAny = arguments[1]; + + // Special cases. try { - RequireObjectCoercible(receiver, 'Array.prototype.findIndex'); - - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); - - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); - - // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. - if (arguments.length == 0) { - goto NotCallableError; - } - const callbackfn = - Cast(arguments[0]) otherwise NotCallableError; - - // 4. If thisArg is present, let T be thisArg; else let T be undefined. - const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - - // Special cases. - try { - return FastArrayFindIndex(o, len, callbackfn, thisArg) - otherwise Bailout; - } - label Bailout(k: Smi) deferred { - return ArrayFindIndexLoopContinuation( - o, callbackfn, thisArg, o, k, len); - } - } - label NotCallableError deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + return FastArrayFindIndex(o, len, callbackfn, thisArg) + otherwise Bailout; + } label Bailout(k: Smi) deferred { + return ArrayFindIndexLoopContinuation(o, callbackfn, thisArg, o, k, len); } + } label NotCallableError deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); } } +} diff --git a/deps/v8/src/builtins/array-foreach.tq b/deps/v8/src/builtins/array-foreach.tq index b30c8533e69f06..938210dcdc3c61 100644 --- a/deps/v8/src/builtins/array-foreach.tq +++ b/deps/v8/src/builtins/array-foreach.tq @@ -3,129 +3,126 @@ // found in the LICENSE file. namespace array { - transitioning javascript builtin - ArrayForEachLoopEagerDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { - // All continuation points in the optimized forEach implemntation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; +transitioning javascript builtin +ArrayForEachLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { + // All continuation points in the optimized forEach implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + return ArrayForEachLoopContinuation( + jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, + numberLength, Undefined); +} - return ArrayForEachLoopContinuation( - jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, - numberLength, Undefined); - } +transitioning javascript builtin +ArrayForEachLoopLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, + _result: JSAny): JSAny { + // All continuation points in the optimized forEach implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + return ArrayForEachLoopContinuation( + jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, + numberLength, Undefined); +} - transitioning javascript builtin - ArrayForEachLoopLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, - _result: JSAny): JSAny { - // All continuation points in the optimized forEach implemntation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; +transitioning builtin ArrayForEachLoopContinuation(implicit context: Context)( + _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, _array: JSAny, + o: JSReceiver, initialK: Number, len: Number, _to: JSAny): JSAny { + // variables {array} and {to} are ignored. - return ArrayForEachLoopContinuation( - jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, - numberLength, Undefined); - } + // 5. Let k be 0. + // 6. Repeat, while k < len + for (let k: Number = initialK; k < len; k = k + 1) { + // 6a. Let Pk be ! ToString(k). + // k is guaranteed to be a positive integer, hence ToString is + // side-effect free and HasProperty/GetProperty do the conversion inline. - transitioning builtin ArrayForEachLoopContinuation(implicit context: Context)( - _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, - _array: JSAny, o: JSReceiver, initialK: Number, len: Number, - _to: JSAny): JSAny { - // variables {array} and {to} are ignored. + // 6b. Let kPresent be ? HasProperty(O, Pk). + const kPresent: Boolean = HasProperty_Inline(o, k); - // 5. Let k be 0. - // 6. Repeat, while k < len - for (let k: Number = initialK; k < len; k = k + 1) { - // 6a. Let Pk be ! ToString(k). - // k is guaranteed to be a positive integer, hence ToString is - // side-effect free and HasProperty/GetProperty do the conversion inline. + // 6c. If kPresent is true, then + if (kPresent == True) { + // 6c. i. Let kValue be ? Get(O, Pk). + const kValue: JSAny = GetProperty(o, k); - // 6b. Let kPresent be ? HasProperty(O, Pk). - const kPresent: Boolean = HasProperty_Inline(o, k); - - // 6c. If kPresent is true, then - if (kPresent == True) { - // 6c. i. Let kValue be ? Get(O, Pk). - const kValue: JSAny = GetProperty(o, k); + // 6c. ii. Perform ? Call(callbackfn, T, ). + Call(context, callbackfn, thisArg, kValue, k, o); + } - // 6c. ii. Perform ? Call(callbackfn, T, ). - Call(context, callbackfn, thisArg, kValue, k, o); - } + // 6d. Increase k by 1. (done by the loop). + } + return Undefined; +} - // 6d. Increase k by 1. (done by the loop). - } - return Undefined; +transitioning macro FastArrayForEach(implicit context: Context)( + o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny + labels Bailout(Smi) { + let k: Smi = 0; + const smiLen = Cast(len) otherwise goto Bailout(k); + const fastO = Cast(o) otherwise goto Bailout(k); + let fastOW = NewFastJSArrayWitness(fastO); + + // Build a fast loop over the smi array. + for (; k < smiLen; k++) { + fastOW.Recheck() otherwise goto Bailout(k); + + // Ensure that we haven't walked beyond a possibly updated length. + if (k >= fastOW.Get().length) goto Bailout(k); + const value: JSAny = fastOW.LoadElementNoHole(k) + otherwise continue; + Call(context, callbackfn, thisArg, value, k, fastOW.Get()); } + return Undefined; +} + +// https://tc39.github.io/ecma262/#sec-array.prototype.foreach +transitioning javascript builtin +ArrayForEach( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + RequireObjectCoercible(receiver, 'Array.prototype.forEach'); + + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); - transitioning macro FastArrayForEach(implicit context: Context)( - o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny - labels Bailout(Smi) { - let k: Smi = 0; - const smiLen = Cast(len) otherwise goto Bailout(k); - const fastO = Cast(o) otherwise goto Bailout(k); - let fastOW = NewFastJSArrayWitness(fastO); - - // Build a fast loop over the smi array. - for (; k < smiLen; k++) { - fastOW.Recheck() otherwise goto Bailout(k); - - // Ensure that we haven't walked beyond a possibly updated length. - if (k >= fastOW.Get().length) goto Bailout(k); - const value: JSAny = fastOW.LoadElementNoHole(k) - otherwise continue; - Call(context, callbackfn, thisArg, value, k, fastOW.Get()); + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); + + // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + if (arguments.length == 0) { + goto TypeError; } - return Undefined; - } + const callbackfn = Cast(arguments[0]) otherwise TypeError; - // https://tc39.github.io/ecma262/#sec-array.prototype.foreach - transitioning javascript builtin - ArrayForEach(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { + // 4. If thisArg is present, let T be thisArg; else let T be undefined. + const thisArg: JSAny = arguments[1]; + + // Special cases. + let k: Number = 0; try { - RequireObjectCoercible(receiver, 'Array.prototype.forEach'); - - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); - - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); - - // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. - if (arguments.length == 0) { - goto TypeError; - } - const callbackfn = Cast(arguments[0]) otherwise TypeError; - - // 4. If thisArg is present, let T be thisArg; else let T be undefined. - const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - - // Special cases. - let k: Number = 0; - try { - return FastArrayForEach(o, len, callbackfn, thisArg) - otherwise Bailout; - } - label Bailout(kValue: Smi) deferred { - k = kValue; - } - - return ArrayForEachLoopContinuation( - o, callbackfn, thisArg, Undefined, o, k, len, Undefined); - } - label TypeError deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + return FastArrayForEach(o, len, callbackfn, thisArg) + otherwise Bailout; + } label Bailout(kValue: Smi) deferred { + k = kValue; } + + return ArrayForEachLoopContinuation( + o, callbackfn, thisArg, Undefined, o, k, len, Undefined); + } label TypeError deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); } } +} diff --git a/deps/v8/src/builtins/array-from.tq b/deps/v8/src/builtins/array-from.tq index 6eb3b006935733..e51d37fef2ccdb 100644 --- a/deps/v8/src/builtins/array-from.tq +++ b/deps/v8/src/builtins/array-from.tq @@ -3,182 +3,181 @@ // found in the LICENSE file. namespace array { - // Array.from( items [, mapfn [, thisArg ] ] ) - // ES #sec-array.from - transitioning javascript builtin - ArrayFrom(js-implicit context: NativeContext, receiver: JSAny)(...arguments): - JSReceiver { - // Use fast path if: - // * |items| is the only argument, and - // * the receiver is the Array function. - if (arguments.length == 1 && receiver == GetArrayFunction()) { - try { - return iterator::FastIterableToList(arguments[0]) otherwise Slow; - } - label Slow { - // fall through - } +// Array.from( items [, mapfn [, thisArg ] ] ) +// ES #sec-array.from +transitioning javascript builtin +ArrayFrom(js-implicit context: NativeContext, receiver: JSAny)(...arguments): + JSReceiver { + // Use fast path if: + // * |items| is the only argument, and + // * the receiver is the Array function. + if (arguments.length == 1 && receiver == GetArrayFunction()) { + try { + return iterator::FastIterableToList(arguments[0]) otherwise Slow; + } label Slow { + // fall through } + } - const items = arguments[0]; - const mapfn = arguments[1]; - const thisArg = arguments[2]; - - // 1. Let C be the this value. - const c = receiver; - - let mapping: bool; - // 2. If mapfn is undefined, let mapping be false. - if (mapfn == Undefined) { - mapping = false; - } else { - // a. If IsCallable(mapfn) is false, throw a TypeError exception. - if (!TaggedIsCallable(mapfn)) deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, mapfn); - } - // b. Let mapping be true. - mapping = true; + const items = arguments[0]; + const mapfn = arguments[1]; + const thisArg = arguments[2]; + + // 1. Let C be the this value. + const c = receiver; + + let mapping: bool; + // 2. If mapfn is undefined, let mapping be false. + if (mapfn == Undefined) { + mapping = false; + } else { + // a. If IsCallable(mapfn) is false, throw a TypeError exception. + if (!Is(mapfn)) deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, mapfn); + } + // b. Let mapping be true. + mapping = true; + } + + // 4. Let usingIterator be ? GetMethod(items, @@iterator). + // 5. If usingIterator is not undefined, then + try { + const usingIterator = GetMethod(items, IteratorSymbolConstant()) + otherwise IteratorIsUndefined, IteratorNotCallable; + + let a: JSReceiver; + // a. If IsConstructor(C) is true, then + typeswitch (c) { + case (c: Constructor): { + // i. Let A be ? Construct(C). + a = Construct(c); + } + case (JSAny): { + // i. Let A be ? ArrayCreate(0). + a = ArrayCreate(0); + } } - // 4. Let usingIterator be ? GetMethod(items, @@iterator). - // 5. If usingIterator is not undefined, then - try { - const usingIterator = GetMethod(items, IteratorSymbolConstant()) - otherwise IteratorIsUndefined, IteratorNotCallable; - - let a: JSReceiver; - // a. If IsConstructor(C) is true, then - typeswitch (c) { - case (c: Constructor): { - // i. Let A be ? Construct(C). - a = Construct(c); - } - case (JSAny): { - // i. Let A be ? ArrayCreate(0). - a = ArrayCreate(0); - } + // c. Let iteratorRecord be ? GetIterator(items, sync, usingIterator). + const iteratorRecord = iterator::GetIterator(items, usingIterator); + + const fastIteratorResultMap = GetIteratorResultMap(); + + // d. Let k be 0. + let k: Smi = 0; + // e. Repeat, + while (true) { + // i. If k ≥ 2^53-1, then + // 1. Let error be ThrowCompletion(a newly created TypeError object). + // 2. Return ? IteratorClose(iteratorRecord, error). + // The spec requires that we throw an exception if index reaches 2^53-1, + // but an empty loop would take >100 days to do this many iterations. To + // actually run for that long would require an iterator that never set + // done to true and a target array which somehow never ran out of + // memory, e.g. a proxy that discarded the values. Ignoring this case + // just means we would repeatedly call CreateDataProperty with index = + // 2^53 + assert(k < kMaxSafeInteger); + + // ii. Let Pk be ! ToString(k). + + // iii. Let next be ? IteratorStep(iteratorRecord). + let next: JSReceiver; + try { + next = iterator::IteratorStep(iteratorRecord, fastIteratorResultMap) + otherwise NextIsFalse; + } + // iv. If next is false, then + label NextIsFalse { + // 1. Perform ? Set(A, "length", k, true). + array::SetPropertyLength(a, k); + // 2. Return A. + return a; } - // c. Let iteratorRecord be ? GetIterator(items, sync, usingIterator). - const iteratorRecord = iterator::GetIterator(items, usingIterator); - - const fastIteratorResultMap = GetIteratorResultMap(); - - // d. Let k be 0. - let k: Smi = 0; - // e. Repeat, - while (true) { - // i. If k ≥ 2^53-1, then - // 1. Let error be ThrowCompletion(a newly created TypeError object). - // 2. Return ? IteratorClose(iteratorRecord, error). - // The spec requires that we throw an exception if index reaches 2^53-1, - // but an empty loop would take >100 days to do this many iterations. To - // actually run for that long would require an iterator that never set - // done to true and a target array which somehow never ran out of - // memory, e.g. a proxy that discarded the values. Ignoring this case - // just means we would repeatedly call CreateDataProperty with index = - // 2^53 - assert(k < kMaxSafeInteger); - - // ii. Let Pk be ! ToString(k). - - // iii. Let next be ? IteratorStep(iteratorRecord). - let next: JSReceiver; - try { - next = iterator::IteratorStep(iteratorRecord, fastIteratorResultMap) - otherwise NextIsFalse; - } - // iv. If next is false, then - label NextIsFalse { - // 1. Perform ? Set(A, "length", k, true). - array::SetPropertyLength(a, k); - // 2. Return A. - return a; - } + // v. Let nextValue be ? IteratorValue(next). + const nextValue = iterator::IteratorValue(next, fastIteratorResultMap); - // v. Let nextValue be ? IteratorValue(next). - const nextValue = iterator::IteratorValue(next, fastIteratorResultMap); - - let mappedValue: JSAny; - // vi. If mapping is true, then - if (mapping) { - // 1. Let mappedValue be Call(mapfn, thisArg, « nextValue, k »). - // 2. If mappedValue is an abrupt completion, - // return ? IteratorClose(iteratorRecord, mappedValue). - // 3. Set mappedValue to mappedValue.[[Value]]. - try { - mappedValue = Call( - context, UnsafeCast(mapfn), thisArg, nextValue, k); - } catch (e) { - iterator::IteratorCloseOnException(iteratorRecord, e); - } - } else { - mappedValue = nextValue; - } - // viii. Let defineStatus be - // CreateDataPropertyOrThrow(A, Pk, mappedValue). - // ix. If defineStatus is an abrupt completion, - // return ? IteratorClose(iteratorRecord, defineStatus). + let mappedValue: JSAny; + // vi. If mapping is true, then + if (mapping) { + // 1. Let mappedValue be Call(mapfn, thisArg, « nextValue, k »). + // 2. If mappedValue is an abrupt completion, + // return ? IteratorClose(iteratorRecord, mappedValue). + // 3. Set mappedValue to mappedValue.[[Value]]. try { - FastCreateDataProperty(a, k, mappedValue); - } catch (e) deferred { - iterator::IteratorCloseOnException(iteratorRecord, e); + mappedValue = + Call(context, UnsafeCast(mapfn), thisArg, nextValue, k); + } catch (e) { + iterator::IteratorCloseOnException(iteratorRecord); + ReThrow(context, e); } - // x. Set k to k + 1. - k += 1; + } else { + mappedValue = nextValue; } - unreachable; + // viii. Let defineStatus be + // CreateDataPropertyOrThrow(A, Pk, mappedValue). + // ix. If defineStatus is an abrupt completion, + // return ? IteratorClose(iteratorRecord, defineStatus). + try { + FastCreateDataProperty(a, k, mappedValue); + } catch (e) deferred { + iterator::IteratorCloseOnException(iteratorRecord); + ReThrow(context, e); + } + // x. Set k to k + 1. + k += 1; } - label IteratorIsUndefined { - // 6. NOTE: items is not an Iterable so assume it is an array-like object. - // 7. Let arrayLike be ! ToObject(items). - const arrayLike = ToObject_Inline(context, items); - // 8. Let len be ? LengthOfArrayLike(arrayLike). - const len = GetLengthProperty(arrayLike); - - let a: JSReceiver; - // 9. If IsConstructor(C) is true, then - typeswitch (c) { - case (c: Constructor): { - // a. Let A be ? Construct(C, « len »). - a = Construct(c, len); - } - case (JSAny): { - // a. Let A be ? ArrayCreate(len). - a = ArrayCreate(len); - } + unreachable; + } label IteratorIsUndefined { + // 6. NOTE: items is not an Iterable so assume it is an array-like object. + // 7. Let arrayLike be ! ToObject(items). + const arrayLike = ToObject_Inline(context, items); + // 8. Let len be ? LengthOfArrayLike(arrayLike). + const len = GetLengthProperty(arrayLike); + + let a: JSReceiver; + // 9. If IsConstructor(C) is true, then + typeswitch (c) { + case (c: Constructor): { + // a. Let A be ? Construct(C, « len »). + a = Construct(c, len); } - - // 11. Let k be 0. - let k: Smi = 0; - // 12. Repeat, while k < len - while (k < len) { - // a. Let Pk be ! ToString(k). - // b. Let kValue be ? Get(arrayLike, Pk). - const kValue = GetProperty(arrayLike, k); - let mappedValue: JSAny; - // c. If mapping is true, then - if (mapping) { - // i. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »). - mappedValue = - Call(context, UnsafeCast(mapfn), thisArg, kValue, k); - } else { - // d. Else, let mappedValue be kValue. - mappedValue = kValue; - } - // e. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). - FastCreateDataProperty(a, k, mappedValue); - // f. Set k to k + 1. - k += 1; + case (JSAny): { + // a. Let A be ? ArrayCreate(len). + a = ArrayCreate(len); } - - // 13. Perform ? Set(A, "length", len, true). - array::SetPropertyLength(a, len); - // 14. Return A. - return a; } - label IteratorNotCallable(_value: JSAny) deferred { - ThrowTypeError(MessageTemplate::kIteratorSymbolNonCallable); + + // 11. Let k be 0. + let k: Smi = 0; + // 12. Repeat, while k < len + while (k < len) { + // a. Let Pk be ! ToString(k). + // b. Let kValue be ? Get(arrayLike, Pk). + const kValue = GetProperty(arrayLike, k); + let mappedValue: JSAny; + // c. If mapping is true, then + if (mapping) { + // i. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »). + mappedValue = + Call(context, UnsafeCast(mapfn), thisArg, kValue, k); + } else { + // d. Else, let mappedValue be kValue. + mappedValue = kValue; + } + // e. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). + FastCreateDataProperty(a, k, mappedValue); + // f. Set k to k + 1. + k += 1; } + + // 13. Perform ? Set(A, "length", len, true). + array::SetPropertyLength(a, len); + // 14. Return A. + return a; + } label IteratorNotCallable(_value: JSAny) deferred { + ThrowTypeError(MessageTemplate::kIteratorSymbolNonCallable); } } +} diff --git a/deps/v8/src/builtins/array-isarray.tq b/deps/v8/src/builtins/array-isarray.tq index 48fca60339d777..a88c1579d1aa91 100644 --- a/deps/v8/src/builtins/array-isarray.tq +++ b/deps/v8/src/builtins/array-isarray.tq @@ -3,25 +3,25 @@ // found in the LICENSE file. namespace runtime { - extern runtime ArrayIsArray(implicit context: Context)(JSAny): JSAny; +extern runtime ArrayIsArray(implicit context: Context)(JSAny): JSAny; } // namespace runtime namespace array { - // ES #sec-array.isarray - javascript builtin ArrayIsArray(js-implicit context: - NativeContext)(arg: JSAny): JSAny { - // 1. Return ? IsArray(arg). - typeswitch (arg) { - case (JSArray): { - return True; - } - case (JSProxy): { - // TODO(verwaest): Handle proxies in-place - return runtime::ArrayIsArray(arg); - } - case (JSAny): { - return False; - } +// ES #sec-array.isarray +javascript builtin ArrayIsArray(js-implicit context: NativeContext)(arg: JSAny): + JSAny { + // 1. Return ? IsArray(arg). + typeswitch (arg) { + case (JSArray): { + return True; + } + case (JSProxy): { + // TODO(verwaest): Handle proxies in-place + return runtime::ArrayIsArray(arg); + } + case (JSAny): { + return False; } } +} } // namespace array diff --git a/deps/v8/src/builtins/array-join.tq b/deps/v8/src/builtins/array-join.tq index a06365f3354b13..08d0cbf894bf49 100644 --- a/deps/v8/src/builtins/array-join.tq +++ b/deps/v8/src/builtins/array-join.tq @@ -3,646 +3,632 @@ // found in the LICENSE file. namespace array { - type LoadJoinElementFn = builtin(Context, JSReceiver, uintptr) => JSAny; +type LoadJoinElementFn = builtin(Context, JSReceiver, uintptr) => JSAny; - // Fast C call to write a fixed array (see Buffer.fixedArray) to a single - // string. - extern macro - ArrayBuiltinsAssembler::CallJSArrayArrayJoinConcatToSequentialString( - FixedArray, intptr, String, String): String; +// Fast C call to write a fixed array (see Buffer.fixedArray) to a single +// string. +extern macro +ArrayBuiltinsAssembler::CallJSArrayArrayJoinConcatToSequentialString( + FixedArray, intptr, String, String): String; - transitioning builtin LoadJoinElement( - context: Context, receiver: JSReceiver, k: uintptr): JSAny { +transitioning builtin LoadJoinElement( + context: Context, receiver: JSReceiver, k: uintptr): JSAny { + return GetProperty(receiver, Convert(k)); +} + +transitioning LoadJoinElement( + context: Context, receiver: JSReceiver, k: uintptr): JSAny { + const array: JSArray = UnsafeCast(receiver); + const dict: NumberDictionary = UnsafeCast(array.elements); + try { + return BasicLoadNumberDictionaryElement(dict, Signed(k)) + otherwise IfNoData, IfHole; + } label IfNoData deferred { return GetProperty(receiver, Convert(k)); + } label IfHole { + return kEmptyString; } +} - transitioning LoadJoinElement( - context: Context, receiver: JSReceiver, k: uintptr): JSAny { - const array: JSArray = UnsafeCast(receiver); - const dict: NumberDictionary = UnsafeCast(array.elements); - try { - return BasicLoadNumberDictionaryElement(dict, Signed(k)) - otherwise IfNoData, IfHole; - } - label IfNoData deferred { - return GetProperty(receiver, Convert(k)); - } - label IfHole { - return kEmptyString; +LoadJoinElement( + context: Context, receiver: JSReceiver, k: uintptr): JSAny { + const array: JSArray = UnsafeCast(receiver); + const fixedArray: FixedArray = UnsafeCast(array.elements); + const element: Object = fixedArray.objects[k]; + return element == TheHole ? kEmptyString : UnsafeCast(element); +} + +LoadJoinElement( + context: Context, receiver: JSReceiver, k: uintptr): JSAny { + const array: JSArray = UnsafeCast(receiver); + const fixedDoubleArray: FixedDoubleArray = + UnsafeCast(array.elements); + const element: float64 = + fixedDoubleArray.floats[k].Value() otherwise return kEmptyString; + return AllocateHeapNumberWithValue(element); +} + +builtin LoadJoinTypedElement( + context: Context, receiver: JSReceiver, k: uintptr): JSAny { + const typedArray: JSTypedArray = UnsafeCast(receiver); + assert(!IsDetachedBuffer(typedArray.buffer)); + return typed_array::LoadFixedTypedArrayElementAsTagged( + typedArray.data_ptr, k, typed_array::KindForArrayType()); +} + +transitioning builtin ConvertToLocaleString( + context: Context, element: JSAny, locales: JSAny, options: JSAny): String { + if (IsNullOrUndefined(element)) return kEmptyString; + + const prop: JSAny = GetProperty(element, 'toLocaleString'); + try { + const callable: Callable = Cast(prop) otherwise TypeError; + let result: JSAny; + if (IsNullOrUndefined(locales)) { + result = Call(context, callable, element); + } else if (IsNullOrUndefined(options)) { + result = Call(context, callable, element, locales); + } else { + result = Call(context, callable, element, locales, options); } + return ToString_Inline(result); + } label TypeError { + ThrowTypeError(MessageTemplate::kCalledNonCallable, prop); } +} - LoadJoinElement( - context: Context, receiver: JSReceiver, k: uintptr): JSAny { - const array: JSArray = UnsafeCast(receiver); - const fixedArray: FixedArray = UnsafeCast(array.elements); - const element: Object = fixedArray.objects[k]; - return element == TheHole ? kEmptyString : UnsafeCast(element); - } +// Verifies the current element JSArray accessor can still be safely used +// (see LoadJoinElement). +macro CannotUseSameArrayAccessor(implicit context: Context)( + loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map, + originalLen: Number): bool; + +CannotUseSameArrayAccessor(implicit context: Context)( + loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map, + originalLen: Number): bool { + if (loadFn == LoadJoinElement) return false; + + const array: JSArray = UnsafeCast(receiver); + if (originalMap != array.map) return true; + if (originalLen != array.length) return true; + if (IsNoElementsProtectorCellInvalid()) return true; + return false; +} - LoadJoinElement( - context: Context, receiver: JSReceiver, k: uintptr): JSAny { - const array: JSArray = UnsafeCast(receiver); - const fixedDoubleArray: FixedDoubleArray = - UnsafeCast(array.elements); - const element: float64 = - fixedDoubleArray.floats[k].Value() otherwise return kEmptyString; - return AllocateHeapNumberWithValue(element); - } +CannotUseSameArrayAccessor(implicit context: Context)( + _loadFn: LoadJoinElementFn, receiver: JSReceiver, _initialMap: Map, + _initialLen: Number): bool { + const typedArray: JSTypedArray = UnsafeCast(receiver); + return IsDetachedBuffer(typedArray.buffer); +} - builtin LoadJoinTypedElement( - context: Context, receiver: JSReceiver, k: uintptr): JSAny { - const typedArray: JSTypedArray = UnsafeCast(receiver); - assert(!IsDetachedBuffer(typedArray.buffer)); - return typed_array::LoadFixedTypedArrayElementAsTagged( - typedArray.data_ptr, k, typed_array::KindForArrayType()); +// Calculates the running total length of the resulting string. If the +// calculated length exceeds the maximum string length (see +// String::kMaxLength), throws a range error. +macro AddStringLength(implicit context: Context)( + lenA: intptr, lenB: intptr): intptr { + try { + const length: intptr = TryIntPtrAdd(lenA, lenB) otherwise IfOverflow; + if (length > kStringMaxLength) goto IfOverflow; + return length; + } label IfOverflow deferred { + ThrowInvalidStringLength(context); } +} - transitioning builtin ConvertToLocaleString( - context: Context, element: JSAny, locales: JSAny, - options: JSAny): String { - if (IsNullOrUndefined(element)) return kEmptyString; - - const prop: JSAny = GetProperty(element, 'toLocaleString'); - try { - const callable: Callable = Cast(prop) otherwise TypeError; - let result: JSAny; - if (IsNullOrUndefined(locales)) { - result = Call(context, callable, element); - } else if (IsNullOrUndefined(options)) { - result = Call(context, callable, element, locales); - } else { - result = Call(context, callable, element, locales, options); - } - return ToString_Inline(result); - } - label TypeError { - ThrowTypeError(MessageTemplate::kCalledNonCallable, prop); +// Stores an element to a fixed array and return the fixed array. If the fixed +// array is not large enough, create and return a new, larger fixed array that +// contains all previously elements and the new element. +macro StoreAndGrowFixedArray( + fixedArray: FixedArray, index: intptr, element: T): FixedArray { + const length: intptr = fixedArray.length_intptr; + assert(index <= length); + if (index < length) { + fixedArray.objects[index] = element; + return fixedArray; + } else + deferred { + const newLength: intptr = CalculateNewElementsCapacity(length); + assert(index < newLength); + const newfixedArray: FixedArray = + ExtractFixedArray(fixedArray, 0, length, newLength); + newfixedArray.objects[index] = element; + return newfixedArray; } - } +} - // Verifies the current element JSArray accessor can still be safely used - // (see LoadJoinElement). - macro CannotUseSameArrayAccessor(implicit context: Context)( - loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map, - originalLen: Number): bool; - - CannotUseSameArrayAccessor(implicit context: Context)( - loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map, - originalLen: Number): bool { - if (loadFn == LoadJoinElement) return false; - - const array: JSArray = UnsafeCast(receiver); - if (originalMap != array.map) return true; - if (originalLen != array.length) return true; - if (IsNoElementsProtectorCellInvalid()) return true; - return false; +// Contains the information necessary to create a single, separator delimited, +// flattened one or two byte string. +// The buffer is maintained and updated by Buffer.constructor, Buffer.Add(), +// Buffer.AddSeparators(). +struct Buffer { + macro Add(implicit context: Context)( + str: String, nofSeparators: intptr, separatorLength: intptr) { + // Add separators if necessary (at the beginning or more than one) + const writeSeparators: bool = this.index == 0 | nofSeparators > 1; + this.AddSeparators(nofSeparators, separatorLength, writeSeparators); + + this.totalStringLength = + AddStringLength(this.totalStringLength, str.length_intptr); + this.fixedArray = + StoreAndGrowFixedArray(this.fixedArray, this.index++, str); + this.isOneByte = + IsOneByteStringInstanceType(str.instanceType) & this.isOneByte; } - CannotUseSameArrayAccessor(implicit context: Context)( - _loadFn: LoadJoinElementFn, receiver: JSReceiver, _initialMap: Map, - _initialLen: Number): bool { - const typedArray: JSTypedArray = UnsafeCast(receiver); - return IsDetachedBuffer(typedArray.buffer); - } + macro AddSeparators(implicit context: Context)( + nofSeparators: intptr, separatorLength: intptr, write: bool) { + if (nofSeparators == 0 || separatorLength == 0) return; - // Calculates the running total length of the resulting string. If the - // calculated length exceeds the maximum string length (see - // String::kMaxLength), throws a range error. - macro AddStringLength(implicit context: Context)(lenA: intptr, lenB: intptr): - intptr { - try { - const length: intptr = TryIntPtrAdd(lenA, lenB) otherwise IfOverflow; - if (length > kStringMaxLength) goto IfOverflow; - return length; - } - label IfOverflow deferred { - ThrowInvalidStringLength(context); - } - } + const nofSeparatorsInt: intptr = nofSeparators; + const sepsLen: intptr = separatorLength * nofSeparatorsInt; + // Detect integer overflow + // TODO(tebbi): Replace with overflow-checked multiplication. + if (sepsLen / separatorLength != nofSeparatorsInt) deferred { + ThrowInvalidStringLength(context); + } - // Stores an element to a fixed array and return the fixed array. If the fixed - // array is not large enough, create and return a new, larger fixed array that - // contains all previously elements and the new element. - macro StoreAndGrowFixedArray( - fixedArray: FixedArray, index: intptr, element: T): FixedArray { - const length: intptr = fixedArray.length_intptr; - assert(index <= length); - if (index < length) { - fixedArray.objects[index] = element; - return fixedArray; - } else - deferred { - const newLength: intptr = CalculateNewElementsCapacity(length); - assert(index < newLength); - const newfixedArray: FixedArray = - ExtractFixedArray(fixedArray, 0, length, newLength); - newfixedArray.objects[index] = element; - return newfixedArray; + this.totalStringLength = AddStringLength(this.totalStringLength, sepsLen); + if (write) deferred { + this.fixedArray = StoreAndGrowFixedArray( + this.fixedArray, this.index++, Convert(nofSeparatorsInt)); } } - // Contains the information necessary to create a single, separator delimited, - // flattened one or two byte string. - // The buffer is maintained and updated by Buffer.constructor, Buffer.Add(), - // Buffer.AddSeparators(). - struct Buffer { - macro Add(implicit context: Context)( - str: String, nofSeparators: intptr, separatorLength: intptr) { - // Add separators if necessary (at the beginning or more than one) - const writeSeparators: bool = this.index == 0 | nofSeparators > 1; - this.AddSeparators(nofSeparators, separatorLength, writeSeparators); - - this.totalStringLength = - AddStringLength(this.totalStringLength, str.length_intptr); - this.fixedArray = - StoreAndGrowFixedArray(this.fixedArray, this.index++, str); - this.isOneByte = - IsOneByteStringInstanceType(str.instanceType) & this.isOneByte; - } + // Fixed array holding elements that are either: + // 1) String result of `ToString(next)`. + // 2) Smi representing the number of consecutive separators. + // `BufferJoin()` will iterate and writes these entries to a flat string. + // + // To save space, reduce reads and writes, only separators at the beginning, + // end, or more than one are written. + // + // No hole example + // receiver: ['hello', 'world'] + // fixedArray: ['hello', 'world'] + // + // Hole example + // receiver: [, 'hello', , 'world', ] + // fixedArray: [1, 'hello', 2, 'world', 1] + fixedArray: FixedArray; + + // Index to insert a new entry into `fixedArray`. + index: intptr; + + // Running total of the resulting string length. + totalStringLength: intptr; + + // `true` if the separator and all strings in the buffer are one-byte, + // otherwise `false`. + isOneByte: bool; +} - macro AddSeparators(implicit context: Context)( - nofSeparators: intptr, separatorLength: intptr, write: bool) { - if (nofSeparators == 0 || separatorLength == 0) return; +macro NewBuffer(len: uintptr, sep: String): Buffer { + const cappedBufferSize: intptr = len > kMaxNewSpaceFixedArrayElements ? + kMaxNewSpaceFixedArrayElements : + Signed(len); + assert(cappedBufferSize > 0); + return Buffer{ + fixedArray: AllocateZeroedFixedArray(cappedBufferSize), + index: 0, + totalStringLength: 0, + isOneByte: IsOneByteStringInstanceType(sep.instanceType) + }; +} - const nofSeparatorsInt: intptr = nofSeparators; - const sepsLen: intptr = separatorLength * nofSeparatorsInt; - // Detect integer overflow - // TODO(tebbi): Replace with overflow-checked multiplication. - if (sepsLen / separatorLength != nofSeparatorsInt) deferred { - ThrowInvalidStringLength(context); - } +macro BufferJoin(implicit context: Context)( + buffer: Buffer, sep: String): String { + assert(IsValidPositiveSmi(buffer.totalStringLength)); + if (buffer.totalStringLength == 0) return kEmptyString; + + // Fast path when there's only one buffer element. + if (buffer.index == 1) { + const fixedArray: FixedArray = buffer.fixedArray; + typeswitch (fixedArray.objects[0]) { + // When the element is a string, just return it and completely avoid + // allocating another string. + case (str: String): { + return str; + } - this.totalStringLength = AddStringLength(this.totalStringLength, sepsLen); - if (write) deferred { - this.fixedArray = StoreAndGrowFixedArray( - this.fixedArray, this.index++, Convert(nofSeparatorsInt)); - } + // When the element is a smi, use StringRepeat to quickly build a memory + // efficient separator repeated string. + case (nofSeparators: Number): { + return StringRepeat(context, sep, nofSeparators); + } + case (Object): { + unreachable; + } } - - // Fixed array holding elements that are either: - // 1) String result of `ToString(next)`. - // 2) Smi representing the number of consecutive separators. - // `BufferJoin()` will iterate and writes these entries to a flat string. - // - // To save space, reduce reads and writes, only separators at the beginning, - // end, or more than one are written. - // - // No hole example - // receiver: ['hello', 'world'] - // fixedArray: ['hello', 'world'] - // - // Hole example - // receiver: [, 'hello', , 'world', ] - // fixedArray: [1, 'hello', 2, 'world', 1] - fixedArray: FixedArray; - - // Index to insert a new entry into `fixedArray`. - index: intptr; - - // Running total of the resulting string length. - totalStringLength: intptr; - - // `true` if the separator and all strings in the buffer are one-byte, - // otherwise `false`. - isOneByte: bool; } - macro NewBuffer(len: uintptr, sep: String): Buffer { - const cappedBufferSize: intptr = len > kMaxNewSpaceFixedArrayElements ? - kMaxNewSpaceFixedArrayElements : - Signed(len); - assert(cappedBufferSize > 0); - return Buffer{ - fixedArray: AllocateZeroedFixedArray(cappedBufferSize), - index: 0, - totalStringLength: 0, - isOneByte: IsOneByteStringInstanceType(sep.instanceType) - }; - } - - macro BufferJoin(implicit context: Context)(buffer: Buffer, sep: String): - String { - assert(IsValidPositiveSmi(buffer.totalStringLength)); - if (buffer.totalStringLength == 0) return kEmptyString; - - // Fast path when there's only one buffer element. - if (buffer.index == 1) { - const fixedArray: FixedArray = buffer.fixedArray; - typeswitch (fixedArray.objects[0]) { - // When the element is a string, just return it and completely avoid - // allocating another string. - case (str: String): { - return str; - } + const length: uint32 = Convert(Unsigned(buffer.totalStringLength)); + const r: String = buffer.isOneByte ? AllocateSeqOneByteString(length) : + AllocateSeqTwoByteString(length); + return CallJSArrayArrayJoinConcatToSequentialString( + buffer.fixedArray, buffer.index, sep, r); +} - // When the element is a smi, use StringRepeat to quickly build a memory - // efficient separator repeated string. - case (nofSeparators: Number): { - return StringRepeat(context, sep, nofSeparators); - } - case (Object): { - unreachable; - } +transitioning macro ArrayJoinImpl(implicit context: Context)( + receiver: JSReceiver, sep: String, lengthNumber: Number, + useToLocaleString: constexpr bool, locales: JSAny, options: JSAny, + initialLoadFn: LoadJoinElementFn): String { + const initialMap: Map = receiver.map; + const len: uintptr = Convert(lengthNumber); + const separatorLength: intptr = sep.length_intptr; + let nofSeparators: intptr = 0; + let loadFn: LoadJoinElementFn = initialLoadFn; + let buffer: Buffer = NewBuffer(len, sep); + + // 6. Let k be 0. + let k: uintptr = 0; + + // 7. Repeat, while k < len + while (k < len) { + if (CannotUseSameArrayAccessor( + loadFn, receiver, initialMap, lengthNumber)) + deferred { + loadFn = LoadJoinElement; } + + if (k > 0) { + // a. If k > 0, let R be the string-concatenation of R and sep. + nofSeparators = nofSeparators + 1; } - const length: uint32 = Convert(Unsigned(buffer.totalStringLength)); - const r: String = buffer.isOneByte ? AllocateSeqOneByteString(length) : - AllocateSeqTwoByteString(length); - return CallJSArrayArrayJoinConcatToSequentialString( - buffer.fixedArray, buffer.index, sep, r); - } + // b. Let element be ? Get(O, ! ToString(k)). + const element: JSAny = loadFn(context, receiver, k++); - transitioning macro ArrayJoinImpl(implicit context: Context)( - receiver: JSReceiver, sep: String, lengthNumber: Number, - useToLocaleString: constexpr bool, locales: JSAny, options: JSAny, - initialLoadFn: LoadJoinElementFn): String { - const initialMap: Map = receiver.map; - const len: uintptr = Convert(lengthNumber); - const separatorLength: intptr = sep.length_intptr; - let nofSeparators: intptr = 0; - let loadFn: LoadJoinElementFn = initialLoadFn; - let buffer: Buffer = NewBuffer(len, sep); - - // 6. Let k be 0. - let k: uintptr = 0; - - // 7. Repeat, while k < len - while (k < len) { - if (CannotUseSameArrayAccessor( - loadFn, receiver, initialMap, lengthNumber)) - deferred { - loadFn = LoadJoinElement; + // c. If element is undefined or null, let next be the empty String; + // otherwise, let next be ? ToString(element). + let next: String; + if constexpr (useToLocaleString) { + next = ConvertToLocaleString(context, element, locales, options); + if (next == kEmptyString) continue; + } else { + typeswitch (element) { + case (str: String): { + if (str == kEmptyString) continue; + next = str; } - - if (k > 0) { - // a. If k > 0, let R be the string-concatenation of R and sep. - nofSeparators = nofSeparators + 1; - } - - // b. Let element be ? Get(O, ! ToString(k)). - const element: JSAny = loadFn(context, receiver, k++); - - // c. If element is undefined or null, let next be the empty String; - // otherwise, let next be ? ToString(element). - let next: String; - if constexpr (useToLocaleString) { - next = ConvertToLocaleString(context, element, locales, options); - if (next == kEmptyString) continue; - } else { - typeswitch (element) { - case (str: String): { - if (str == kEmptyString) continue; - next = str; - } - case (num: Number): { - next = NumberToString(num); - } - case (obj: JSAny): { - if (IsNullOrUndefined(obj)) continue; - next = ToString(context, obj); - } + case (num: Number): { + next = NumberToString(num); + } + case (obj: JSAny): { + if (IsNullOrUndefined(obj)) continue; + next = ToString(context, obj); } } - - // d. Set R to the string-concatenation of R and next. - buffer.Add(next, nofSeparators, separatorLength); - nofSeparators = 0; } - // Add any separators at the end. - buffer.AddSeparators(nofSeparators, separatorLength, true); - - // 8. Return R. - return BufferJoin(buffer, sep); + // d. Set R to the string-concatenation of R and next. + buffer.Add(next, nofSeparators, separatorLength); + nofSeparators = 0; } - transitioning macro ArrayJoin(implicit context: Context)( - useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String, - lenNumber: Number, locales: JSAny, options: JSAny): JSAny; + // Add any separators at the end. + buffer.AddSeparators(nofSeparators, separatorLength, true); - transitioning ArrayJoin(implicit context: Context)( - useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String, - lenNumber: Number, locales: JSAny, options: JSAny): JSAny { - const map: Map = receiver.map; - const kind: ElementsKind = map.elements_kind; - let loadFn: LoadJoinElementFn; + // 8. Return R. + return BufferJoin(buffer, sep); +} - try { - const array: JSArray = Cast(receiver) otherwise IfSlowPath; - if (array.length != lenNumber) goto IfSlowPath; - if (!IsPrototypeInitialArrayPrototype(map)) goto IfSlowPath; - if (IsNoElementsProtectorCellInvalid()) goto IfSlowPath; - - if (IsElementsKindLessThanOrEqual(kind, ElementsKind::HOLEY_ELEMENTS)) { - loadFn = LoadJoinElement; - } else if (IsElementsKindLessThanOrEqual( - kind, ElementsKind::HOLEY_DOUBLE_ELEMENTS)) { - loadFn = LoadJoinElement; - } else if (kind == ElementsKind::DICTIONARY_ELEMENTS) - deferred { - const dict: NumberDictionary = - UnsafeCast(array.elements); - const nofElements: Smi = GetNumberDictionaryNumberOfElements(dict); - if (nofElements == 0) { - if (sep == kEmptyString) return kEmptyString; - try { - const nofSeparators: Smi = - Cast(lenNumber - 1) otherwise IfNotSmi; - return StringRepeat(context, sep, nofSeparators); - } - label IfNotSmi { - ThrowInvalidStringLength(context); - } - } else { - loadFn = LoadJoinElement; +transitioning macro ArrayJoin(implicit context: Context)( + useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String, + lenNumber: Number, locales: JSAny, options: JSAny): JSAny; + +transitioning ArrayJoin(implicit context: Context)( + useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String, + lenNumber: Number, locales: JSAny, options: JSAny): JSAny { + const map: Map = receiver.map; + const kind: ElementsKind = map.elements_kind; + let loadFn: LoadJoinElementFn; + + try { + const array: JSArray = Cast(receiver) otherwise IfSlowPath; + if (array.length != lenNumber) goto IfSlowPath; + if (!IsPrototypeInitialArrayPrototype(map)) goto IfSlowPath; + if (IsNoElementsProtectorCellInvalid()) goto IfSlowPath; + + if (IsElementsKindLessThanOrEqual(kind, ElementsKind::HOLEY_ELEMENTS)) { + loadFn = LoadJoinElement; + } else if (IsElementsKindLessThanOrEqual( + kind, ElementsKind::HOLEY_DOUBLE_ELEMENTS)) { + loadFn = LoadJoinElement; + } else if (kind == ElementsKind::DICTIONARY_ELEMENTS) + deferred { + const dict: NumberDictionary = + UnsafeCast(array.elements); + const nofElements: Smi = GetNumberDictionaryNumberOfElements(dict); + if (nofElements == 0) { + if (sep == kEmptyString) return kEmptyString; + try { + const nofSeparators: Smi = + Cast(lenNumber - 1) otherwise IfNotSmi; + return StringRepeat(context, sep, nofSeparators); + } label IfNotSmi { + ThrowInvalidStringLength(context); } + } else { + loadFn = LoadJoinElement; } - else { - goto IfSlowPath; } + else { + goto IfSlowPath; } - label IfSlowPath { - loadFn = LoadJoinElement; - } - return ArrayJoinImpl( - receiver, sep, lenNumber, useToLocaleString, locales, options, loadFn); + } label IfSlowPath { + loadFn = LoadJoinElement; } + return ArrayJoinImpl( + receiver, sep, lenNumber, useToLocaleString, locales, options, loadFn); +} - transitioning ArrayJoin(implicit context: Context)( - useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String, - lenNumber: Number, locales: JSAny, options: JSAny): JSAny { - const map: Map = receiver.map; - const kind: ElementsKind = map.elements_kind; - let loadFn: LoadJoinElementFn; - - if (IsElementsKindGreaterThan(kind, ElementsKind::UINT32_ELEMENTS)) { - if (kind == ElementsKind::INT32_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else if (kind == ElementsKind::FLOAT32_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else if (kind == ElementsKind::FLOAT64_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else if (kind == ElementsKind::UINT8_CLAMPED_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else if (kind == ElementsKind::BIGUINT64_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else if (kind == ElementsKind::BIGINT64_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else { - unreachable; - } +transitioning ArrayJoin(implicit context: Context)( + useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String, + lenNumber: Number, locales: JSAny, options: JSAny): JSAny { + const map: Map = receiver.map; + const kind: ElementsKind = map.elements_kind; + let loadFn: LoadJoinElementFn; + + if (IsElementsKindGreaterThan(kind, ElementsKind::UINT32_ELEMENTS)) { + if (kind == ElementsKind::INT32_ELEMENTS) { + loadFn = LoadJoinTypedElement; + } else if (kind == ElementsKind::FLOAT32_ELEMENTS) { + loadFn = LoadJoinTypedElement; + } else if (kind == ElementsKind::FLOAT64_ELEMENTS) { + loadFn = LoadJoinTypedElement; + } else if (kind == ElementsKind::UINT8_CLAMPED_ELEMENTS) { + loadFn = LoadJoinTypedElement; + } else if (kind == ElementsKind::BIGUINT64_ELEMENTS) { + loadFn = LoadJoinTypedElement; + } else if (kind == ElementsKind::BIGINT64_ELEMENTS) { + loadFn = LoadJoinTypedElement; } else { - if (kind == ElementsKind::UINT8_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else if (kind == ElementsKind::INT8_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else if (kind == ElementsKind::UINT16_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else if (kind == ElementsKind::INT16_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else if (kind == ElementsKind::UINT32_ELEMENTS) { - loadFn = LoadJoinTypedElement; - } else { - unreachable; - } + unreachable; + } + } else { + if (kind == ElementsKind::UINT8_ELEMENTS) { + loadFn = LoadJoinTypedElement; + } else if (kind == ElementsKind::INT8_ELEMENTS) { + loadFn = LoadJoinTypedElement; + } else if (kind == ElementsKind::UINT16_ELEMENTS) { + loadFn = LoadJoinTypedElement; + } else if (kind == ElementsKind::INT16_ELEMENTS) { + loadFn = LoadJoinTypedElement; + } else if (kind == ElementsKind::UINT32_ELEMENTS) { + loadFn = LoadJoinTypedElement; + } else { + unreachable; } - return ArrayJoinImpl( - receiver, sep, lenNumber, useToLocaleString, locales, options, loadFn); - } - - // The Join Stack detects cyclical calls to Array Join builtins - // (Array.p.join(), Array.p.toString(), Array.p.toLocaleString()). This - // FixedArray holds a stack of receivers to the current call. - // CycleProtectedArrayJoin() is responsible for calling JoinStackPush and - // JoinStackPop when visiting and leaving a receiver, respectively. - const kMinJoinStackSize: - constexpr int31 generates 'JSArray::kMinJoinStackSize'; - macro LoadJoinStack(implicit context: Context)(): FixedArray - labels IfUninitialized { - const nativeContext: NativeContext = LoadNativeContext(context); - const stack: HeapObject = UnsafeCast( - nativeContext[NativeContextSlot::ARRAY_JOIN_STACK_INDEX]); - if (stack == Undefined) goto IfUninitialized; - assert(IsFixedArray(stack)); - return UnsafeCast(stack); } + return ArrayJoinImpl( + receiver, sep, lenNumber, useToLocaleString, locales, options, loadFn); +} - macro SetJoinStack(implicit context: Context)(stack: FixedArray): void { - const nativeContext: NativeContext = LoadNativeContext(context); - nativeContext[NativeContextSlot::ARRAY_JOIN_STACK_INDEX] = stack; - } +// The Join Stack detects cyclical calls to Array Join builtins +// (Array.p.join(), Array.p.toString(), Array.p.toLocaleString()). This +// FixedArray holds a stack of receivers to the current call. +// CycleProtectedArrayJoin() is responsible for calling JoinStackPush and +// JoinStackPop when visiting and leaving a receiver, respectively. +const kMinJoinStackSize: + constexpr int31 generates 'JSArray::kMinJoinStackSize'; +macro LoadJoinStack(implicit context: Context)(): FixedArray + labels IfUninitialized { + const nativeContext: NativeContext = LoadNativeContext(context); + const stack: HeapObject = UnsafeCast( + nativeContext[NativeContextSlot::ARRAY_JOIN_STACK_INDEX]); + if (stack == Undefined) goto IfUninitialized; + assert(IsFixedArray(stack)); + return UnsafeCast(stack); +} - // Adds a receiver to the stack. The FixedArray will automatically grow to - // accommodate the receiver. If the receiver already exists on the stack, - // this indicates a cyclical call and False is returned. - builtin JoinStackPush(implicit context: Context)( - stack: FixedArray, receiver: JSReceiver): Boolean { - const capacity: intptr = stack.length_intptr; - for (let i: intptr = 0; i < capacity; i++) { - const previouslyVisited: Object = stack.objects[i]; - - // Add `receiver` to the first open slot - if (previouslyVisited == TheHole) { - stack.objects[i] = receiver; - return True; - } +macro SetJoinStack(implicit context: Context)(stack: FixedArray): void { + const nativeContext: NativeContext = LoadNativeContext(context); + nativeContext[NativeContextSlot::ARRAY_JOIN_STACK_INDEX] = stack; +} - // Detect cycles - if (receiver == previouslyVisited) return False; +// Adds a receiver to the stack. The FixedArray will automatically grow to +// accommodate the receiver. If the receiver already exists on the stack, +// this indicates a cyclical call and False is returned. +builtin JoinStackPush(implicit context: Context)( + stack: FixedArray, receiver: JSReceiver): Boolean { + const capacity: intptr = stack.length_intptr; + for (let i: intptr = 0; i < capacity; i++) { + const previouslyVisited: Object = stack.objects[i]; + + // Add `receiver` to the first open slot + if (previouslyVisited == TheHole) { + stack.objects[i] = receiver; + return True; } - // If no open slots were found, grow the stack and add receiver to the end. - const newStack: FixedArray = - StoreAndGrowFixedArray(stack, capacity, receiver); - SetJoinStack(newStack); - return True; + // Detect cycles + if (receiver == previouslyVisited) return False; } - // Fast path the common non-nested calls. If the receiver is not already on - // the stack, add it to the stack and return true. Otherwise return false. - macro JoinStackPushInline(implicit context: Context)(receiver: JSReceiver): - bool { - try { - const stack: FixedArray = LoadJoinStack() - otherwise IfUninitialized; - if (stack.objects[0] == TheHole) { - stack.objects[0] = receiver; - } else if (JoinStackPush(stack, receiver) == False) - deferred { - return false; - } - } - label IfUninitialized { - const stack: FixedArray = - AllocateFixedArrayWithHoles(kMinJoinStackSize, AllocationFlag::kNone); + // If no open slots were found, grow the stack and add receiver to the end. + const newStack: FixedArray = + StoreAndGrowFixedArray(stack, capacity, receiver); + SetJoinStack(newStack); + return True; +} + +// Fast path the common non-nested calls. If the receiver is not already on +// the stack, add it to the stack and return true. Otherwise return false. +macro JoinStackPushInline(implicit context: Context)(receiver: JSReceiver): + bool { + try { + const stack: FixedArray = LoadJoinStack() + otherwise IfUninitialized; + if (stack.objects[0] == TheHole) { stack.objects[0] = receiver; - SetJoinStack(stack); - } - return true; + } else if (JoinStackPush(stack, receiver) == False) + deferred { + return false; + } + } label IfUninitialized { + const stack: FixedArray = + AllocateFixedArrayWithHoles(kMinJoinStackSize, AllocationFlag::kNone); + stack.objects[0] = receiver; + SetJoinStack(stack); } + return true; +} - // Removes a receiver from the stack. The FixedArray will automatically shrink - // to Heap::kMinJoinStackSize once the stack becomes empty. - builtin JoinStackPop(implicit context: Context)( - stack: FixedArray, receiver: JSReceiver): JSAny { - const len: intptr = stack.length_intptr; - for (let i: intptr = 0; i < len; i++) { - if (stack.objects[i] == receiver) { - // Shrink the Join Stack if the stack will be empty and is larger than - // the minimum size. - if (i == 0 && len > kMinJoinStackSize) deferred { - const newStack: FixedArray = AllocateFixedArrayWithHoles( - kMinJoinStackSize, AllocationFlag::kNone); - SetJoinStack(newStack); - } - else { - stack.objects[i] = TheHole; +// Removes a receiver from the stack. The FixedArray will automatically shrink +// to Heap::kMinJoinStackSize once the stack becomes empty. +builtin JoinStackPop(implicit context: Context)( + stack: FixedArray, receiver: JSReceiver): JSAny { + const len: intptr = stack.length_intptr; + for (let i: intptr = 0; i < len; i++) { + if (stack.objects[i] == receiver) { + // Shrink the Join Stack if the stack will be empty and is larger than + // the minimum size. + if (i == 0 && len > kMinJoinStackSize) deferred { + const newStack: FixedArray = AllocateFixedArrayWithHoles( + kMinJoinStackSize, AllocationFlag::kNone); + SetJoinStack(newStack); } - return Undefined; + else { + stack.objects[i] = TheHole; } + return Undefined; } - unreachable; } + unreachable; +} - // Fast path the common non-nested calls. - macro JoinStackPopInline(implicit context: Context)(receiver: JSReceiver) { - const stack: FixedArray = LoadJoinStack() - otherwise unreachable; - const len: intptr = stack.length_intptr; - - // Builtin call was not nested (receiver is the first entry) and - // did not contain other nested arrays that expanded the stack. - if (stack.objects[0] == receiver && len == kMinJoinStackSize) { - StoreFixedArrayElement(stack, 0, TheHole, SKIP_WRITE_BARRIER); - } else - deferred { - JoinStackPop(stack, receiver); - } - } +// Fast path the common non-nested calls. +macro JoinStackPopInline(implicit context: Context)(receiver: JSReceiver) { + const stack: FixedArray = LoadJoinStack() + otherwise unreachable; + const len: intptr = stack.length_intptr; + + // Builtin call was not nested (receiver is the first entry) and + // did not contain other nested arrays that expanded the stack. + if (stack.objects[0] == receiver && len == kMinJoinStackSize) { + StoreFixedArrayElement(stack, 0, TheHole, SKIP_WRITE_BARRIER); + } else + deferred { + JoinStackPop(stack, receiver); + } +} - // Main entry point for all builtins using Array Join functionality. - transitioning macro CycleProtectedArrayJoin(implicit context: - Context)( - useToLocaleString: constexpr bool, o: JSReceiver, len: Number, - sepObj: JSAny, locales: JSAny, options: JSAny): JSAny { - // 3. If separator is undefined, let sep be the single-element String ",". - // 4. Else, let sep be ? ToString(separator). - const sep: String = sepObj == Undefined ? ',' : ToString_Inline(sepObj); - - // If the receiver is not empty and not already being joined, continue with - // the normal join algorithm. - if (len > 0 && JoinStackPushInline(o)) { - try { - const result: JSAny = - ArrayJoin(useToLocaleString, o, sep, len, locales, options); - JoinStackPopInline(o); - return result; - } catch (e) deferred { - JoinStackPopInline(o); - ReThrow(context, e); - } - } else { - return kEmptyString; +// Main entry point for all builtins using Array Join functionality. +transitioning macro CycleProtectedArrayJoin( + implicit context: Context)( + useToLocaleString: constexpr bool, o: JSReceiver, len: Number, + sepObj: JSAny, locales: JSAny, options: JSAny): JSAny { + // 3. If separator is undefined, let sep be the single-element String ",". + // 4. Else, let sep be ? ToString(separator). + const sep: String = sepObj == Undefined ? ',' : ToString_Inline(sepObj); + + // If the receiver is not empty and not already being joined, continue with + // the normal join algorithm. + if (len > 0 && JoinStackPushInline(o)) { + try { + const result: JSAny = + ArrayJoin(useToLocaleString, o, sep, len, locales, options); + JoinStackPopInline(o); + return result; + } catch (e) deferred { + JoinStackPopInline(o); + ReThrow(context, e); } + } else { + return kEmptyString; } +} - // https://tc39.github.io/ecma262/#sec-array.prototype.join - transitioning javascript builtin - ArrayPrototypeJoin(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - const separator: JSAny = arguments[0]; +// https://tc39.github.io/ecma262/#sec-array.prototype.join +transitioning javascript builtin +ArrayPrototypeJoin( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const separator: JSAny = arguments[0]; - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); - // Only handle valid array lengths. Although the spec allows larger - // values, this matches historical V8 behavior. - if (len > kMaxArrayIndex + 1) - ThrowTypeError(MessageTemplate::kInvalidArrayLength); + // Only handle valid array lengths. Although the spec allows larger + // values, this matches historical V8 behavior. + if (len > kMaxArrayIndex + 1) + ThrowTypeError(MessageTemplate::kInvalidArrayLength); - return CycleProtectedArrayJoin( - false, o, len, separator, Undefined, Undefined); - } + return CycleProtectedArrayJoin( + false, o, len, separator, Undefined, Undefined); +} - // https://tc39.github.io/ecma262/#sec-array.prototype.tolocalestring - transitioning javascript builtin ArrayPrototypeToLocaleString( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const locales: JSAny = arguments[0]; - const options: JSAny = arguments[1]; +// https://tc39.github.io/ecma262/#sec-array.prototype.tolocalestring +transitioning javascript builtin ArrayPrototypeToLocaleString( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const locales: JSAny = arguments[0]; + const options: JSAny = arguments[1]; - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); - // Only handle valid array lengths. Although the spec allows larger - // values, this matches historical V8 behavior. - if (len > kMaxArrayIndex + 1) - ThrowTypeError(MessageTemplate::kInvalidArrayLength); + // Only handle valid array lengths. Although the spec allows larger + // values, this matches historical V8 behavior. + if (len > kMaxArrayIndex + 1) + ThrowTypeError(MessageTemplate::kInvalidArrayLength); - return CycleProtectedArrayJoin( - true, o, len, ',', locales, options); - } + return CycleProtectedArrayJoin(true, o, len, ',', locales, options); +} - // https://tc39.github.io/ecma262/#sec-array.prototype.tostring - transitioning javascript builtin ArrayPrototypeToString( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - // 1. Let array be ? ToObject(this value). - const array: JSReceiver = ToObject_Inline(context, receiver); +// https://tc39.github.io/ecma262/#sec-array.prototype.tostring +transitioning javascript builtin ArrayPrototypeToString( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // 1. Let array be ? ToObject(this value). + const array: JSReceiver = ToObject_Inline(context, receiver); + + // 2. Let func be ? Get(array, "join"). + const prop: JSAny = GetProperty(array, 'join'); + try { + // 3. If IsCallable(func) is false, let func be the intrinsic function + // %ObjProto_toString%. + const func: Callable = Cast(prop) otherwise NotCallable; + + // 4. Return ? Call(func, array). + return Call(context, func, array); + } label NotCallable { + return ObjectToString(context, array); + } +} - // 2. Let func be ? Get(array, "join"). - const prop: JSAny = GetProperty(array, 'join'); - try { - // 3. If IsCallable(func) is false, let func be the intrinsic function - // %ObjProto_toString%. - const func: Callable = Cast(prop) otherwise NotCallable; +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.join +transitioning javascript builtin TypedArrayPrototypeJoin( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const separator: JSAny = arguments[0]; - // 4. Return ? Call(func, array). - return Call(context, func, array); - } - label NotCallable { - return ObjectToString(context, array); - } - } + // Spec: ValidateTypedArray is applied to the this value prior to evaluating + // the algorithm. + const typedArray: JSTypedArray = typed_array::ValidateTypedArray( + context, receiver, '%TypedArray%.prototype.join'); + const length = Convert(typedArray.length); - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.join - transitioning javascript builtin TypedArrayPrototypeJoin( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const separator: JSAny = arguments[0]; + return CycleProtectedArrayJoin( + false, typedArray, length, separator, Undefined, Undefined); +} - // Spec: ValidateTypedArray is applied to the this value prior to evaluating - // the algorithm. - const typedArray: JSTypedArray = typed_array::ValidateTypedArray( - context, receiver, '%TypedArray%.prototype.join'); - const length = Convert(typedArray.length); +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tolocalestring +transitioning javascript builtin TypedArrayPrototypeToLocaleString( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const locales: JSAny = arguments[0]; + const options: JSAny = arguments[1]; - return CycleProtectedArrayJoin( - false, typedArray, length, separator, Undefined, Undefined); - } + // Spec: ValidateTypedArray is applied to the this value prior to evaluating + // the algorithm. + const typedArray: JSTypedArray = typed_array::ValidateTypedArray( + context, receiver, '%TypedArray%.prototype.toLocaleString'); + const length = Convert(typedArray.length); - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tolocalestring - transitioning javascript builtin TypedArrayPrototypeToLocaleString( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const locales: JSAny = arguments[0]; - const options: JSAny = arguments[1]; - - // Spec: ValidateTypedArray is applied to the this value prior to evaluating - // the algorithm. - const typedArray: JSTypedArray = typed_array::ValidateTypedArray( - context, receiver, '%TypedArray%.prototype.toLocaleString'); - const length = Convert(typedArray.length); - - return CycleProtectedArrayJoin( - true, typedArray, length, ',', locales, options); - } + return CycleProtectedArrayJoin( + true, typedArray, length, ',', locales, options); +} } diff --git a/deps/v8/src/builtins/array-lastindexof.tq b/deps/v8/src/builtins/array-lastindexof.tq index 52bcc75d195f97..fe416fa4a24289 100644 --- a/deps/v8/src/builtins/array-lastindexof.tq +++ b/deps/v8/src/builtins/array-lastindexof.tq @@ -3,154 +3,151 @@ // found in the LICENSE file. namespace array { - macro LoadWithHoleCheck( - elements: FixedArrayBase, index: Smi): JSAny - labels IfHole; - - LoadWithHoleCheck(implicit context: Context)( - elements: FixedArrayBase, index: Smi): JSAny - labels IfHole { - const elements: FixedArray = UnsafeCast(elements); - const element: Object = elements.objects[index]; - if (element == TheHole) goto IfHole; - return UnsafeCast(element); - } +macro LoadWithHoleCheck( + elements: FixedArrayBase, index: Smi): JSAny + labels IfHole; + +LoadWithHoleCheck(implicit context: Context)( + elements: FixedArrayBase, index: Smi): JSAny + labels IfHole { + const elements: FixedArray = UnsafeCast(elements); + const element: Object = elements.objects[index]; + if (element == TheHole) goto IfHole; + return UnsafeCast(element); +} - LoadWithHoleCheck(implicit context: Context)( - elements: FixedArrayBase, index: Smi): JSAny - labels IfHole { - const elements: FixedDoubleArray = UnsafeCast(elements); - const element: float64 = elements.floats[index].Value() otherwise IfHole; - return AllocateHeapNumberWithValue(element); - } +LoadWithHoleCheck(implicit context: Context)( + elements: FixedArrayBase, index: Smi): JSAny + labels IfHole { + const elements: FixedDoubleArray = UnsafeCast(elements); + const element: float64 = elements.floats[index].Value() otherwise IfHole; + return AllocateHeapNumberWithValue(element); +} - macro FastArrayLastIndexOf( - context: Context, array: JSArray, from: Smi, searchElement: JSAny): Smi { - const elements: FixedArrayBase = array.elements; - let k: Smi = from; - - // Bug(898785): Due to side-effects in the evaluation of `fromIndex` - // the {from} can be out-of-bounds here, so we need to clamp {k} to - // the {elements} length. We might be reading holes / hole NaNs still - // due to that, but those will be ignored below. - if (k >= elements.length) { - k = elements.length - 1; - } +macro FastArrayLastIndexOf( + context: Context, array: JSArray, from: Smi, searchElement: JSAny): Smi { + const elements: FixedArrayBase = array.elements; + let k: Smi = from; + + // Bug(898785): Due to side-effects in the evaluation of `fromIndex` + // the {from} can be out-of-bounds here, so we need to clamp {k} to + // the {elements} length. We might be reading holes / hole NaNs still + // due to that, but those will be ignored below. + if (k >= elements.length) { + k = elements.length - 1; + } - while (k >= 0) { - try { - const element: JSAny = LoadWithHoleCheck(elements, k) - otherwise Hole; + while (k >= 0) { + try { + const element: JSAny = LoadWithHoleCheck(elements, k) + otherwise Hole; - const same: Boolean = StrictEqual(searchElement, element); - if (same == True) { - assert(Is(array)); - return k; - } + const same: Boolean = StrictEqual(searchElement, element); + if (same == True) { + assert(Is(array)); + return k; } - label Hole {} // Do nothing for holes. - - --k; - } + } label Hole {} // Do nothing for holes. - assert(Is(array)); - return -1; + --k; } - transitioning macro - GetFromIndex(context: Context, length: Number, arguments: Arguments): Number { - // 4. If fromIndex is present, let n be ? ToInteger(fromIndex); - // else let n be len - 1. - const n: Number = - arguments.length < 2 ? length - 1 : ToInteger_Inline(arguments[1]); - - // 5. If n >= 0, then. - let k: Number = SmiConstant(0); - if (n >= 0) { - // a. If n is -0, let k be +0; else let k be min(n, len - 1). - // If n was -0 it got truncated to 0.0, so taking the minimum is fine. - k = Min(n, length - 1); - } else { - // a. Let k be len + n. - k = length + n; - } - return k; + assert(Is(array)); + return -1; +} + +transitioning macro +GetFromIndex(context: Context, length: Number, arguments: Arguments): Number { + // 4. If fromIndex is present, let n be ? ToInteger(fromIndex); + // else let n be len - 1. + const n: Number = + arguments.length < 2 ? length - 1 : ToInteger_Inline(arguments[1]); + + // 5. If n >= 0, then. + let k: Number = SmiConstant(0); + if (n >= 0) { + // a. If n is -0, let k be +0; else let k be min(n, len - 1). + // If n was -0 it got truncated to 0.0, so taking the minimum is fine. + k = Min(n, length - 1); + } else { + // a. Let k be len + n. + k = length + n; } + return k; +} - macro TryFastArrayLastIndexOf( - context: Context, receiver: JSReceiver, searchElement: JSAny, - from: Number): JSAny - labels Slow { - const array: FastJSArray = Cast(receiver) otherwise Slow; - const length: Smi = array.length; - if (length == 0) return SmiConstant(-1); - - const fromSmi: Smi = Cast(from) otherwise Slow; - const kind: ElementsKind = array.map.elements_kind; - if (IsFastSmiOrTaggedElementsKind(kind)) { - return FastArrayLastIndexOf( - context, array, fromSmi, searchElement); - } - assert(IsDoubleElementsKind(kind)); - return FastArrayLastIndexOf( +macro TryFastArrayLastIndexOf( + context: Context, receiver: JSReceiver, searchElement: JSAny, + from: Number): JSAny + labels Slow { + const array: FastJSArray = Cast(receiver) otherwise Slow; + const length: Smi = array.length; + if (length == 0) return SmiConstant(-1); + + const fromSmi: Smi = Cast(from) otherwise Slow; + const kind: ElementsKind = array.map.elements_kind; + if (IsFastSmiOrTaggedElementsKind(kind)) { + return FastArrayLastIndexOf( context, array, fromSmi, searchElement); } + assert(IsDoubleElementsKind(kind)); + return FastArrayLastIndexOf( + context, array, fromSmi, searchElement); +} - transitioning macro GenericArrayLastIndexOf( - context: Context, object: JSReceiver, searchElement: JSAny, - from: Number): JSAny { - let k: Number = from; - - // 7. Repeat, while k >= 0. - while (k >= 0) { - // a. Let kPresent be ? HasProperty(O, ! ToString(k)). - const kPresent: Boolean = HasProperty(object, k); +transitioning macro GenericArrayLastIndexOf( + context: Context, object: JSReceiver, searchElement: JSAny, + from: Number): JSAny { + let k: Number = from; - // b. If kPresent is true, then. - if (kPresent == True) { - // i. Let elementK be ? Get(O, ! ToString(k)). - const element: JSAny = GetProperty(object, k); + // 7. Repeat, while k >= 0. + while (k >= 0) { + // a. Let kPresent be ? HasProperty(O, ! ToString(k)). + const kPresent: Boolean = HasProperty(object, k); - // ii. Let same be the result of performing Strict Equality Comparison - // searchElement === elementK. - const same: Boolean = StrictEqual(searchElement, element); + // b. If kPresent is true, then. + if (kPresent == True) { + // i. Let elementK be ? Get(O, ! ToString(k)). + const element: JSAny = GetProperty(object, k); - // iii. If same is true, return k. - if (same == True) return k; - } + // ii. Let same be the result of performing Strict Equality Comparison + // searchElement === elementK. + const same: Boolean = StrictEqual(searchElement, element); - // c. Decrease k by 1. - --k; + // iii. If same is true, return k. + if (same == True) return k; } - // 8. Return -1. - return SmiConstant(-1); + // c. Decrease k by 1. + --k; } - // https://tc39.github.io/ecma262/#sec-array.prototype.lastIndexOf - transitioning javascript builtin ArrayPrototypeLastIndexOf( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - // 1. Let O be ? ToObject(this value). - const object: JSReceiver = ToObject_Inline(context, receiver); + // 8. Return -1. + return SmiConstant(-1); +} - // 2. Let len be ? ToLength(? Get(O, "length")). - const length: Number = GetLengthProperty(object); +// https://tc39.github.io/ecma262/#sec-array.prototype.lastIndexOf +transitioning javascript builtin ArrayPrototypeLastIndexOf( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // 1. Let O be ? ToObject(this value). + const object: JSReceiver = ToObject_Inline(context, receiver); - // 3. If len is 0, return -1. - if (length == SmiConstant(0)) return SmiConstant(-1); + // 2. Let len be ? ToLength(? Get(O, "length")). + const length: Number = GetLengthProperty(object); - // Step 4 - 6. - const from: Number = GetFromIndex(context, length, arguments); + // 3. If len is 0, return -1. + if (length == SmiConstant(0)) return SmiConstant(-1); - const searchElement: JSAny = arguments[0]; + // Step 4 - 6. + const from: Number = GetFromIndex(context, length, arguments); - try { - return TryFastArrayLastIndexOf(context, object, searchElement, from) - otherwise Baseline; - } - label Baseline { - return GenericArrayLastIndexOf(context, object, searchElement, from); - } + const searchElement: JSAny = arguments[0]; + + try { + return TryFastArrayLastIndexOf(context, object, searchElement, from) + otherwise Baseline; + } label Baseline { + return GenericArrayLastIndexOf(context, object, searchElement, from); } } +} diff --git a/deps/v8/src/builtins/array-map.tq b/deps/v8/src/builtins/array-map.tq index 9b45341c0e2568..8ff3cbaccdc9ac 100644 --- a/deps/v8/src/builtins/array-map.tq +++ b/deps/v8/src/builtins/array-map.tq @@ -3,271 +3,265 @@ // found in the LICENSE file. namespace array { - transitioning javascript builtin - ArrayMapLoopEagerDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny, - length: JSAny): JSAny { - // All continuation points in the optimized filter implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - // - // Also, this great mass of casts is necessary because the signature - // of Torque javascript builtins requires JSAny type for all parameters - // other than {context}. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const outputArray = Cast(array) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - return ArrayMapLoopContinuation( - jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK, - numberLength); - } - - transitioning javascript builtin - ArrayMapLoopLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny, - length: JSAny, result: JSAny): JSAny { - // All continuation points in the optimized filter implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const outputArray = Cast(array) otherwise unreachable; - let numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - // This custom lazy deopt point is right after the callback. map() needs - // to pick up at the next step, which is setting the callback result in - // the output array. After incrementing k, we can glide into the loop - // continuation builtin. - - // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). - FastCreateDataProperty(outputArray, numberK, result); - - // 7d. Increase k by 1. - numberK = numberK + 1; - - return ArrayMapLoopContinuation( - jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK, - numberLength); - } +transitioning javascript builtin +ArrayMapLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny, + length: JSAny): JSAny { + // All continuation points in the optimized filter implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + // + // Also, this great mass of casts is necessary because the signature + // of Torque javascript builtins requires JSAny type for all parameters + // other than {context}. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const outputArray = Cast(array) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + return ArrayMapLoopContinuation( + jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK, + numberLength); +} - transitioning builtin ArrayMapLoopContinuation(implicit context: Context)( - _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, - array: JSReceiver, o: JSReceiver, initialK: Number, - length: Number): JSAny { - // 6. Let k be 0. - // 7. Repeat, while k < len - for (let k: Number = initialK; k < length; k++) { - // 7a. Let Pk be ! ToString(k). - // k is guaranteed to be a positive integer, hence ToString is - // side-effect free and HasProperty/GetProperty do the conversion inline. - - // 7b. Let kPresent be ? HasProperty(O, Pk). - const kPresent: Boolean = HasProperty_Inline(o, k); - - // 7c. If kPresent is true, then: - if (kPresent == True) { - // i. Let kValue be ? Get(O, Pk). - const kValue: JSAny = GetProperty(o, k); - - // ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O). - const mappedValue: JSAny = - Call(context, callbackfn, thisArg, kValue, k, o); - - // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value). - FastCreateDataProperty(array, k, mappedValue); - } +transitioning javascript builtin +ArrayMapLoopLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny, + length: JSAny, result: JSAny): JSAny { + // All continuation points in the optimized filter implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const outputArray = Cast(array) otherwise unreachable; + let numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + // This custom lazy deopt point is right after the callback. map() needs + // to pick up at the next step, which is setting the callback result in + // the output array. After incrementing k, we can glide into the loop + // continuation builtin. + + // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). + FastCreateDataProperty(outputArray, numberK, result); + + // 7d. Increase k by 1. + numberK = numberK + 1; + + return ArrayMapLoopContinuation( + jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK, + numberLength); +} - // 7d. Increase k by 1. (done by the loop). +transitioning builtin ArrayMapLoopContinuation(implicit context: Context)( + _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, + array: JSReceiver, o: JSReceiver, initialK: Number, length: Number): JSAny { + // 6. Let k be 0. + // 7. Repeat, while k < len + for (let k: Number = initialK; k < length; k++) { + // 7a. Let Pk be ! ToString(k). + // k is guaranteed to be a positive integer, hence ToString is + // side-effect free and HasProperty/GetProperty do the conversion inline. + + // 7b. Let kPresent be ? HasProperty(O, Pk). + const kPresent: Boolean = HasProperty_Inline(o, k); + + // 7c. If kPresent is true, then: + if (kPresent == True) { + // i. Let kValue be ? Get(O, Pk). + const kValue: JSAny = GetProperty(o, k); + + // ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O). + const mappedValue: JSAny = + Call(context, callbackfn, thisArg, kValue, k, o); + + // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value). + FastCreateDataProperty(array, k, mappedValue); } - // 8. Return A. - return array; + // 7d. Increase k by 1. (done by the loop). } - struct Vector { - macro ReportSkippedElement() { - this.skippedElements = true; - } - - macro CreateJSArray(implicit context: Context)(validLength: Smi): JSArray { - const length: Smi = this.fixedArray.length; - assert(validLength <= length); - let kind: ElementsKind = ElementsKind::PACKED_SMI_ELEMENTS; - if (!this.onlySmis) { - if (this.onlyNumbers) { - kind = ElementsKind::PACKED_DOUBLE_ELEMENTS; - } else { - kind = ElementsKind::PACKED_ELEMENTS; - } - } + // 8. Return A. + return array; +} - if (this.skippedElements || validLength < length) { - // We also need to create a holey output array if we are - // bailing out of the fast path partway through the array. - // This is indicated by {validLength} < {length}. - // Who knows if the bailout condition will continue to fill in - // every element? - kind = FastHoleyElementsKind(kind); - } +struct Vector { + macro ReportSkippedElement() { + this.skippedElements = true; + } - const map: Map = LoadJSArrayElementsMap(kind, LoadNativeContext(context)); - let a: JSArray; - - if (IsDoubleElementsKind(kind)) { - // We need to allocate and copy. - // First, initialize the elements field before allocation to prevent - // heap corruption. - const elements: FixedDoubleArray = AllocateFixedDoubleArrayWithHoles( - SmiUntag(length), AllocationFlag::kAllowLargeObjectAllocation); - a = NewJSArray(map, this.fixedArray); - for (let i: Smi = 0; i < validLength; i++) { - typeswitch ( - UnsafeCast<(Number | TheHole)>(this.fixedArray.objects[i])) { - case (n: Number): { - elements.floats[i] = Convert(n); - } - case (TheHole): { - } - } - } - a.elements = elements; + macro CreateJSArray(implicit context: Context)(validLength: Smi): JSArray { + const length: Smi = this.fixedArray.length; + assert(validLength <= length); + let kind: ElementsKind = ElementsKind::PACKED_SMI_ELEMENTS; + if (!this.onlySmis) { + if (this.onlyNumbers) { + kind = ElementsKind::PACKED_DOUBLE_ELEMENTS; } else { - // Simply install the given fixedArray in {vector}. - a = NewJSArray(map, this.fixedArray); + kind = ElementsKind::PACKED_ELEMENTS; } + } - // Paranoia. the FixedArray now "belongs" to JSArray {a}. - this.fixedArray = kEmptyFixedArray; - return a; + if (this.skippedElements || validLength < length) { + // We also need to create a holey output array if we are + // bailing out of the fast path partway through the array. + // This is indicated by {validLength} < {length}. + // Who knows if the bailout condition will continue to fill in + // every element? + kind = FastHoleyElementsKind(kind); } - macro StoreResult(implicit context: Context)(index: Smi, result: JSAny) { - typeswitch (result) { - case (s: Smi): { - this.fixedArray.objects[index] = s; - } - case (s: HeapNumber): { - this.onlySmis = false; - this.fixedArray.objects[index] = s; - } - case (s: JSAnyNotNumber): { - this.onlySmis = false; - this.onlyNumbers = false; - this.fixedArray.objects[index] = s; + const map: Map = LoadJSArrayElementsMap(kind, LoadNativeContext(context)); + let a: JSArray; + + if (IsDoubleElementsKind(kind)) { + // We need to allocate and copy. + // First, initialize the elements field before allocation to prevent + // heap corruption. + const elements: FixedDoubleArray = AllocateFixedDoubleArrayWithHoles( + SmiUntag(length), AllocationFlag::kAllowLargeObjectAllocation); + a = NewJSArray(map, this.fixedArray); + for (let i: Smi = 0; i < validLength; i++) { + typeswitch ( + UnsafeCast<(Number | TheHole)>(this.fixedArray.objects[i])) { + case (n: Number): { + elements.floats[i] = Convert(n); + } + case (TheHole): { + } } } + a.elements = elements; + } else { + // Simply install the given fixedArray in {vector}. + a = NewJSArray(map, this.fixedArray); } - fixedArray: FixedArray; - onlySmis: bool; // initially true. - onlyNumbers: bool; // initially true. - skippedElements: bool; // initially false. + // Paranoia. the FixedArray now "belongs" to JSArray {a}. + this.fixedArray = kEmptyFixedArray; + return a; } - macro NewVector(implicit context: Context)(length: Smi): Vector { - const fixedArray = length > 0 ? - AllocateFixedArrayWithHoles( - SmiUntag(length), AllocationFlag::kAllowLargeObjectAllocation) : - kEmptyFixedArray; - return Vector{ - fixedArray, - onlySmis: true, - onlyNumbers: true, - skippedElements: false - }; + macro StoreResult(implicit context: Context)(index: Smi, result: JSAny) { + typeswitch (result) { + case (s: Smi): { + this.fixedArray.objects[index] = s; + } + case (s: HeapNumber): { + this.onlySmis = false; + this.fixedArray.objects[index] = s; + } + case (s: JSAnyNotNumber): { + this.onlySmis = false; + this.onlyNumbers = false; + this.fixedArray.objects[index] = s; + } + } } - transitioning macro FastArrayMap(implicit context: Context)( - fastO: FastJSArrayForRead, len: Smi, callbackfn: Callable, - thisArg: JSAny): JSArray - labels Bailout(JSArray, Smi) { - let k: Smi = 0; - let fastOW = NewFastJSArrayForReadWitness(fastO); - let vector = NewVector(len); + fixedArray: FixedArray; + onlySmis: bool; // initially true. + onlyNumbers: bool; // initially true. + skippedElements: bool; // initially false. +} - // Build a fast loop over the smi array. - // 7. Repeat, while k < len. - try { - for (; k < len; k++) { - fastOW.Recheck() otherwise goto PrepareBailout(k); - - // Ensure that we haven't walked beyond a possibly updated length. - if (k >= fastOW.Get().length) goto PrepareBailout(k); - - try { - const value: JSAny = fastOW.LoadElementNoHole(k) - otherwise FoundHole; - const result: JSAny = - Call(context, callbackfn, thisArg, value, k, fastOW.Get()); - vector.StoreResult(k, result); - } - label FoundHole { - // Our output array must necessarily be holey because of holes in - // the input array. - vector.ReportSkippedElement(); - } +macro NewVector(implicit context: Context)(length: Smi): Vector { + const fixedArray = length > 0 ? + AllocateFixedArrayWithHoles( + SmiUntag(length), AllocationFlag::kAllowLargeObjectAllocation) : + kEmptyFixedArray; + return Vector{ + fixedArray, + onlySmis: true, + onlyNumbers: true, + skippedElements: false + }; +} + +transitioning macro FastArrayMap(implicit context: Context)( + fastO: FastJSArrayForRead, len: Smi, callbackfn: Callable, + thisArg: JSAny): JSArray + labels Bailout(JSArray, Smi) { + let k: Smi = 0; + let fastOW = NewFastJSArrayForReadWitness(fastO); + let vector = NewVector(len); + + // Build a fast loop over the smi array. + // 7. Repeat, while k < len. + try { + for (; k < len; k++) { + fastOW.Recheck() otherwise goto PrepareBailout(k); + + // Ensure that we haven't walked beyond a possibly updated length. + if (k >= fastOW.Get().length) goto PrepareBailout(k); + + try { + const value: JSAny = fastOW.LoadElementNoHole(k) + otherwise FoundHole; + const result: JSAny = + Call(context, callbackfn, thisArg, value, k, fastOW.Get()); + vector.StoreResult(k, result); + } label FoundHole { + // Our output array must necessarily be holey because of holes in + // the input array. + vector.ReportSkippedElement(); } } - label PrepareBailout(k: Smi) deferred { - // Transform {vector} into a JSArray and bail out. - goto Bailout(vector.CreateJSArray(k), k); - } - - return vector.CreateJSArray(len); + } label PrepareBailout(k: Smi) deferred { + // Transform {vector} into a JSArray and bail out. + goto Bailout(vector.CreateJSArray(k), k); } - // https://tc39.github.io/ecma262/#sec-array.prototype.map - transitioning javascript builtin - ArrayMap(js-implicit context: NativeContext, receiver: JSAny)(...arguments): - JSAny { - try { - RequireObjectCoercible(receiver, 'Array.prototype.map'); + return vector.CreateJSArray(len); +} - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); +// https://tc39.github.io/ecma262/#sec-array.prototype.map +transitioning javascript builtin +ArrayMap( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + RequireObjectCoercible(receiver, 'Array.prototype.map'); - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); - // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. - if (arguments.length == 0) goto TypeError; + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); - const callbackfn = Cast(arguments[0]) otherwise TypeError; + // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + if (arguments.length == 0) goto TypeError; - // 4. If thisArg is present, let T be thisArg; else let T be undefined. - const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined; + const callbackfn = Cast(arguments[0]) otherwise TypeError; - let array: JSReceiver; - let k: Number = 0; - try { - // 5. Let A be ? ArraySpeciesCreate(O, len). - if (IsArraySpeciesProtectorCellInvalid()) goto SlowSpeciesCreate; - const o: FastJSArrayForRead = Cast(receiver) - otherwise SlowSpeciesCreate; - const smiLength: Smi = Cast(len) - otherwise SlowSpeciesCreate; - - return FastArrayMap(o, smiLength, callbackfn, thisArg) - otherwise Bailout; - } - label SlowSpeciesCreate { - array = ArraySpeciesCreate(context, receiver, len); - } - label Bailout(output: JSArray, kValue: Smi) deferred { - array = output; - k = kValue; - } + // 4. If thisArg is present, let T be thisArg; else let T be undefined. + const thisArg: JSAny = arguments[1]; - return ArrayMapLoopContinuation(o, callbackfn, thisArg, array, o, k, len); - } - label TypeError deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + let array: JSReceiver; + let k: Number = 0; + try { + // 5. Let A be ? ArraySpeciesCreate(O, len). + if (IsArraySpeciesProtectorCellInvalid()) goto SlowSpeciesCreate; + const o: FastJSArrayForRead = Cast(receiver) + otherwise SlowSpeciesCreate; + const smiLength: Smi = Cast(len) + otherwise SlowSpeciesCreate; + + return FastArrayMap(o, smiLength, callbackfn, thisArg) + otherwise Bailout; + } label SlowSpeciesCreate { + array = ArraySpeciesCreate(context, receiver, len); + } label Bailout(output: JSArray, kValue: Smi) deferred { + array = output; + k = kValue; } + + return ArrayMapLoopContinuation(o, callbackfn, thisArg, array, o, k, len); + } label TypeError deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); } } +} diff --git a/deps/v8/src/builtins/array-of.tq b/deps/v8/src/builtins/array-of.tq index 2df961b9955ec2..49c67bd8231dcc 100644 --- a/deps/v8/src/builtins/array-of.tq +++ b/deps/v8/src/builtins/array-of.tq @@ -3,53 +3,53 @@ // found in the LICENSE file. namespace array { - // https://tc39.github.io/ecma262/#sec-array.of - transitioning javascript builtin - ArrayOf(js-implicit context: NativeContext, receiver: JSAny)(...arguments): - JSAny { - // 1. Let len be the actual number of arguments passed to this function. - const len: Smi = Convert(arguments.length); - - // 2. Let items be the List of arguments passed to this function. - const items: Arguments = arguments; - - // 3. Let C be the this value. - const c: JSAny = receiver; - - let a: JSReceiver; - - // 4. If IsConstructor(C) is true, then - typeswitch (c) { - case (c: Constructor): { - // a. Let A be ? Construct(C, « len »). - a = Construct(c, len); - } - case (JSAny): { - // a. Let A be ? ArrayCreate(len). - a = ArrayCreate(len); - } +// https://tc39.github.io/ecma262/#sec-array.of +transitioning javascript builtin +ArrayOf( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // 1. Let len be the actual number of arguments passed to this function. + const len: Smi = Convert(arguments.length); + + // 2. Let items be the List of arguments passed to this function. + const items: Arguments = arguments; + + // 3. Let C be the this value. + const c: JSAny = receiver; + + let a: JSReceiver; + + // 4. If IsConstructor(C) is true, then + typeswitch (c) { + case (c: Constructor): { + // a. Let A be ? Construct(C, « len »). + a = Construct(c, len); } + case (JSAny): { + // a. Let A be ? ArrayCreate(len). + a = ArrayCreate(len); + } + } - // 6. Let k be 0. - let k: Smi = 0; + // 6. Let k be 0. + let k: Smi = 0; - // 7. Repeat, while k < len - while (k < len) { - // a. Let kValue be items[k]. - const kValue: JSAny = items[Convert(k)]; + // 7. Repeat, while k < len + while (k < len) { + // a. Let kValue be items[k]. + const kValue: JSAny = items[Convert(k)]; - // b. Let Pk be ! ToString(k). - // c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue). - FastCreateDataProperty(a, k, kValue); + // b. Let Pk be ! ToString(k). + // c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue). + FastCreateDataProperty(a, k, kValue); - // d. Increase k by 1. - k++; - } + // d. Increase k by 1. + k++; + } - // 8. Perform ? Set(A, "length", len, true). - array::SetPropertyLength(a, len); + // 8. Perform ? Set(A, "length", len, true). + array::SetPropertyLength(a, len); - // 9. Return A. - return a; - } + // 9. Return A. + return a; +} } diff --git a/deps/v8/src/builtins/array-reduce-right.tq b/deps/v8/src/builtins/array-reduce-right.tq index 45055862723af3..90e0e496f8f657 100644 --- a/deps/v8/src/builtins/array-reduce-right.tq +++ b/deps/v8/src/builtins/array-reduce-right.tq @@ -3,198 +3,195 @@ // found in the LICENSE file. namespace array { - transitioning javascript builtin - ArrayReduceRightPreLoopEagerDeoptContinuation( - js-implicit context: NativeContext, - receiver: JSAny)(callback: JSAny, length: JSAny): JSAny { - // All continuation points in the optimized every implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - // - // Also, this great mass of casts is necessary because the signature - // of Torque javascript builtins requires JSAny type for all parameters - // other than {context}. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - const initialK = numberLength - 1; - - // Simulate starting the loop at {length - 1}, but ensuring that the - // accumulator is the hole. The continuation stub will search for the - // last non-hole element, rightly throwing an exception if not found. - return ArrayReduceRightLoopContinuation( - jsreceiver, callbackfn, TheHole, jsreceiver, initialK, numberLength); - } - - transitioning javascript builtin - ArrayReduceRightLoopEagerDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, initialK: JSAny, length: JSAny, - accumulator: JSAny): JSAny { - // All continuation points in the optimized every implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - // - // Also, this great mass of casts is necessary because the signature - // of Torque javascript builtins requires JSAny type for all parameters - // other than {context}. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - return ArrayReduceRightLoopContinuation( - jsreceiver, callbackfn, accumulator, jsreceiver, numberK, numberLength); - } - - transitioning javascript builtin - ArrayReduceRightLoopLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, initialK: JSAny, length: JSAny, result: JSAny): JSAny { - // All continuation points in the optimized every implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - // The accumulator is the result from the callback call which just occured. - const r = ArrayReduceRightLoopContinuation( - jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength); - return r; - } +transitioning javascript builtin +ArrayReduceRightPreLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, length: JSAny): JSAny { + // All continuation points in the optimized every implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + // + // Also, this great mass of casts is necessary because the signature + // of Torque javascript builtins requires JSAny type for all parameters + // other than {context}. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + const initialK = numberLength - 1; + + // Simulate starting the loop at {length - 1}, but ensuring that the + // accumulator is the hole. The continuation stub will search for the + // last non-hole element, rightly throwing an exception if not found. + return ArrayReduceRightLoopContinuation( + jsreceiver, callbackfn, TheHole, jsreceiver, initialK, numberLength); +} - transitioning builtin ArrayReduceRightLoopContinuation(implicit context: - Context)( - _receiver: JSReceiver, callbackfn: Callable, - initialAccumulator: JSAny|TheHole, o: JSReceiver, initialK: Number, - _length: Number): JSAny { - let accumulator = initialAccumulator; - - // 8b and 9. Repeat, while k >= 0 - for (let k: Number = initialK; k >= 0; k--) { - // 8b i and 9a. Let Pk be ! ToString(k). - // k is guaranteed to be a positive integer, hence ToString is - // side-effect free and HasProperty/GetProperty do the conversion inline. - - // 8b ii and 9b. Set kPresent to ? HasProperty(O, Pk). - const present: Boolean = HasProperty_Inline(o, k); - - // 8b iii and 9c. If kPresent is true, then - if (present == True) { - // 8b iii and 9c i. Let kValue be ? Get(O, Pk). - const value: JSAny = GetProperty(o, k); - - typeswitch (accumulator) { - case (TheHole): { - // 8b iii 1. - accumulator = value; - } - case (accumulatorNotHole: JSAny): { - // 9c. ii. Set accumulator to ? Call(callbackfn, undefined, - // ). - accumulator = Call( - context, callbackfn, Undefined, accumulatorNotHole, value, k, - o); - } - } - } +transitioning javascript builtin +ArrayReduceRightLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, initialK: JSAny, length: JSAny, + accumulator: JSAny): JSAny { + // All continuation points in the optimized every implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + // + // Also, this great mass of casts is necessary because the signature + // of Torque javascript builtins requires JSAny type for all parameters + // other than {context}. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + return ArrayReduceRightLoopContinuation( + jsreceiver, callbackfn, accumulator, jsreceiver, numberK, numberLength); +} - // 8b iv and 9d. Decrease k by 1. (done by the loop). - } +transitioning javascript builtin +ArrayReduceRightLoopLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, initialK: JSAny, length: JSAny, result: JSAny): JSAny { + // All continuation points in the optimized every implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + // The accumulator is the result from the callback call which just occured. + const r = ArrayReduceRightLoopContinuation( + jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength); + return r; +} - // 8c. if kPresent is false, throw a TypeError exception. - // If the accumulator is discovered with the sentinel hole value, - // this means kPresent is false. - typeswitch (accumulator) { - case (TheHole): { - ThrowTypeError( - MessageTemplate::kReduceNoInitial, 'Array.prototype.reduceRight'); - } - case (accumulator: JSAny): { - return accumulator; - } - } - } +transitioning builtin ArrayReduceRightLoopContinuation( + implicit context: Context)( + _receiver: JSReceiver, callbackfn: Callable, + initialAccumulator: JSAny|TheHole, o: JSReceiver, initialK: Number, + _length: Number): JSAny { + let accumulator = initialAccumulator; - transitioning macro FastArrayReduceRight(implicit context: Context)( - o: JSReceiver, len: Number, callbackfn: Callable, - initialAccumulator: JSAny|TheHole): JSAny - labels Bailout(Number, JSAny|TheHole) { - let accumulator = initialAccumulator; - const smiLen = Cast(len) otherwise goto Bailout(len - 1, accumulator); - const fastO = Cast(o) - otherwise goto Bailout(len - 1, accumulator); - let fastOW = NewFastJSArrayForReadWitness(fastO); + // 8b and 9. Repeat, while k >= 0 + for (let k: Number = initialK; k >= 0; k--) { + // 8b i and 9a. Let Pk be ! ToString(k). + // k is guaranteed to be a positive integer, hence ToString is + // side-effect free and HasProperty/GetProperty do the conversion inline. - // Build a fast loop over the array. - for (let k: Smi = smiLen - 1; k >= 0; k--) { - fastOW.Recheck() otherwise goto Bailout(k, accumulator); + // 8b ii and 9b. Set kPresent to ? HasProperty(O, Pk). + const present: Boolean = HasProperty_Inline(o, k); - // Ensure that we haven't walked beyond a possibly updated length. - if (k >= fastOW.Get().length) goto Bailout(k, accumulator); + // 8b iii and 9c. If kPresent is true, then + if (present == True) { + // 8b iii and 9c i. Let kValue be ? Get(O, Pk). + const value: JSAny = GetProperty(o, k); - const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; typeswitch (accumulator) { case (TheHole): { + // 8b iii 1. accumulator = value; } case (accumulatorNotHole: JSAny): { + // 9c. ii. Set accumulator to ? Call(callbackfn, undefined, + // ). accumulator = Call( - context, callbackfn, Undefined, accumulatorNotHole, value, k, - fastOW.Get()); + context, callbackfn, Undefined, accumulatorNotHole, value, k, o); } } } + + // 8b iv and 9d. Decrease k by 1. (done by the loop). + } + + // 8c. if kPresent is false, throw a TypeError exception. + // If the accumulator is discovered with the sentinel hole value, + // this means kPresent is false. + typeswitch (accumulator) { + case (TheHole): { + ThrowTypeError( + MessageTemplate::kReduceNoInitial, 'Array.prototype.reduceRight'); + } + case (accumulator: JSAny): { + return accumulator; + } + } +} + +transitioning macro FastArrayReduceRight(implicit context: Context)( + o: JSReceiver, len: Number, callbackfn: Callable, + initialAccumulator: JSAny|TheHole): JSAny + labels Bailout(Number, JSAny | TheHole) { + let accumulator = initialAccumulator; + const smiLen = Cast(len) otherwise goto Bailout(len - 1, accumulator); + const fastO = Cast(o) + otherwise goto Bailout(len - 1, accumulator); + let fastOW = NewFastJSArrayForReadWitness(fastO); + + // Build a fast loop over the array. + for (let k: Smi = smiLen - 1; k >= 0; k--) { + fastOW.Recheck() otherwise goto Bailout(k, accumulator); + + // Ensure that we haven't walked beyond a possibly updated length. + if (k >= fastOW.Get().length) goto Bailout(k, accumulator); + + const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; typeswitch (accumulator) { case (TheHole): { - ThrowTypeError( - MessageTemplate::kReduceNoInitial, 'Array.prototype.reduceRight'); + accumulator = value; } - case (accumulator: JSAny): { - return accumulator; + case (accumulatorNotHole: JSAny): { + accumulator = Call( + context, callbackfn, Undefined, accumulatorNotHole, value, k, + fastOW.Get()); } } } + typeswitch (accumulator) { + case (TheHole): { + ThrowTypeError( + MessageTemplate::kReduceNoInitial, 'Array.prototype.reduceRight'); + } + case (accumulator: JSAny): { + return accumulator; + } + } +} - // https://tc39.github.io/ecma262/#sec-array.prototype.reduceRight - transitioning javascript builtin - ArrayReduceRight(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - try { - RequireObjectCoercible(receiver, 'Array.prototype.reduceRight'); +// https://tc39.github.io/ecma262/#sec-array.prototype.reduceRight +transitioning javascript builtin +ArrayReduceRight( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + RequireObjectCoercible(receiver, 'Array.prototype.reduceRight'); - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); - // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. - if (arguments.length == 0) { - goto NoCallableError; - } - const callbackfn = Cast(arguments[0]) otherwise NoCallableError; + // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + if (arguments.length == 0) { + goto NoCallableError; + } + const callbackfn = Cast(arguments[0]) otherwise NoCallableError; - // 4. If len is 0 and initialValue is not present, throw a TypeError - // exception. (This case is handled at the end of - // ArrayReduceRightLoopContinuation). + // 4. If len is 0 and initialValue is not present, throw a TypeError + // exception. (This case is handled at the end of + // ArrayReduceRightLoopContinuation). - const initialValue: JSAny|TheHole = - arguments.length > 1 ? arguments[1] : TheHole; + const initialValue: JSAny|TheHole = + arguments.length > 1 ? arguments[1] : TheHole; - try { - return FastArrayReduceRight(o, len, callbackfn, initialValue) - otherwise Bailout; - } - label Bailout(value: Number, accumulator: JSAny|TheHole) { - return ArrayReduceRightLoopContinuation( - o, callbackfn, accumulator, o, value, len); - } - } - label NoCallableError deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + try { + return FastArrayReduceRight(o, len, callbackfn, initialValue) + otherwise Bailout; + } label Bailout(value: Number, accumulator: JSAny|TheHole) { + return ArrayReduceRightLoopContinuation( + o, callbackfn, accumulator, o, value, len); } + } label NoCallableError deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); } } +} diff --git a/deps/v8/src/builtins/array-reduce.tq b/deps/v8/src/builtins/array-reduce.tq index 4a03776bd4e77a..8ab85a0cb61cfc 100644 --- a/deps/v8/src/builtins/array-reduce.tq +++ b/deps/v8/src/builtins/array-reduce.tq @@ -3,197 +3,194 @@ // found in the LICENSE file. namespace array { - transitioning javascript builtin - ArrayReducePreLoopEagerDeoptContinuation( - js-implicit context: NativeContext, - receiver: JSAny)(callback: JSAny, length: JSAny): JSAny { - // All continuation points in the optimized every implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - // - // Also, this great mass of casts is necessary because the signature - // of Torque javascript builtins requires JSAny type for all parameters - // other than {context}. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - // Simulate starting the loop at 0, but ensuring that the accumulator is - // the hole. The continuation stub will search for the initial non-hole - // element, rightly throwing an exception if not found. - return ArrayReduceLoopContinuation( - jsreceiver, callbackfn, TheHole, jsreceiver, 0, numberLength); - } +transitioning javascript builtin +ArrayReducePreLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, length: JSAny): JSAny { + // All continuation points in the optimized every implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + // + // Also, this great mass of casts is necessary because the signature + // of Torque javascript builtins requires JSAny type for all parameters + // other than {context}. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + // Simulate starting the loop at 0, but ensuring that the accumulator is + // the hole. The continuation stub will search for the initial non-hole + // element, rightly throwing an exception if not found. + return ArrayReduceLoopContinuation( + jsreceiver, callbackfn, TheHole, jsreceiver, 0, numberLength); +} - transitioning javascript builtin - ArrayReduceLoopEagerDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, initialK: JSAny, length: JSAny, - accumulator: JSAny): JSAny { - // All continuation points in the optimized every implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - // - // Also, this great mass of casts is necessary because the signature - // of Torque javascript builtins requires JSAny type for all parameters - // other than {context}. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - return ArrayReduceLoopContinuation( - jsreceiver, callbackfn, accumulator, jsreceiver, numberK, numberLength); - } +transitioning javascript builtin +ArrayReduceLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, initialK: JSAny, length: JSAny, + accumulator: JSAny): JSAny { + // All continuation points in the optimized every implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + // + // Also, this great mass of casts is necessary because the signature + // of Torque javascript builtins requires JSAny type for all parameters + // other than {context}. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + return ArrayReduceLoopContinuation( + jsreceiver, callbackfn, accumulator, jsreceiver, numberK, numberLength); +} - transitioning javascript builtin - ArrayReduceLoopLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, initialK: JSAny, length: JSAny, result: JSAny): JSAny { - // All continuation points in the optimized every implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - // The accumulator is the result from the callback call which just occured. - const r = ArrayReduceLoopContinuation( - jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength); - return r; - } +transitioning javascript builtin +ArrayReduceLoopLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, initialK: JSAny, length: JSAny, result: JSAny): JSAny { + // All continuation points in the optimized every implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + // The accumulator is the result from the callback call which just occured. + const r = ArrayReduceLoopContinuation( + jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength); + return r; +} - transitioning builtin ArrayReduceLoopContinuation(implicit context: Context)( - _receiver: JSReceiver, callbackfn: Callable, - initialAccumulator: JSAny|TheHole, o: JSReceiver, initialK: Number, - length: Number): JSAny { - let accumulator = initialAccumulator; - - // 8b and 9. Repeat, while k < len - for (let k: Number = initialK; k < length; k++) { - // 8b i and 9a. Let Pk be ! ToString(k). - // k is guaranteed to be a positive integer, hence ToString is - // side-effect free and HasProperty/GetProperty do the conversion inline. - - // 8b ii and 9b. Set kPresent to ? HasProperty(O, Pk). - const present: Boolean = HasProperty_Inline(o, k); - - // 6c. If kPresent is true, then - if (present == True) { - // 6c. i. Let kValue be ? Get(O, Pk). - const value: JSAny = GetProperty(o, k); - - typeswitch (accumulator) { - case (TheHole): { - // 8b. - accumulator = value; - } - case (accumulatorNotHole: JSAny): { - // 9c. ii. Set accumulator to ? Call(callbackfn, undefined, - // ). - accumulator = Call( - context, callbackfn, Undefined, accumulatorNotHole, value, k, - o); - } - } - } +transitioning builtin ArrayReduceLoopContinuation(implicit context: Context)( + _receiver: JSReceiver, callbackfn: Callable, + initialAccumulator: JSAny|TheHole, o: JSReceiver, initialK: Number, + length: Number): JSAny { + let accumulator = initialAccumulator; - // 8b iv and 9d. Increase k by 1. (done by the loop). - } + // 8b and 9. Repeat, while k < len + for (let k: Number = initialK; k < length; k++) { + // 8b i and 9a. Let Pk be ! ToString(k). + // k is guaranteed to be a positive integer, hence ToString is + // side-effect free and HasProperty/GetProperty do the conversion inline. - // 8c. if kPresent is false, throw a TypeError exception. - // If the accumulator is discovered with the sentinel hole value, - // this means kPresent is false. - typeswitch (accumulator) { - case (TheHole): { - ThrowTypeError( - MessageTemplate::kReduceNoInitial, 'Array.prototype.reduce'); - } - case (accumulator: JSAny): { - return accumulator; - } - } - } + // 8b ii and 9b. Set kPresent to ? HasProperty(O, Pk). + const present: Boolean = HasProperty_Inline(o, k); + + // 6c. If kPresent is true, then + if (present == True) { + // 6c. i. Let kValue be ? Get(O, Pk). + const value: JSAny = GetProperty(o, k); - transitioning macro FastArrayReduce(implicit context: Context)( - o: JSReceiver, len: Number, callbackfn: Callable, - initialAccumulator: JSAny|TheHole): JSAny - labels Bailout(Number, JSAny|TheHole) { - const k = 0; - let accumulator = initialAccumulator; - Cast(len) otherwise goto Bailout(k, accumulator); - const fastO = - Cast(o) otherwise goto Bailout(k, accumulator); - let fastOW = NewFastJSArrayForReadWitness(fastO); - - // Build a fast loop over the array. - for (let k: Smi = 0; k < len; k++) { - fastOW.Recheck() otherwise goto Bailout(k, accumulator); - - // Ensure that we haven't walked beyond a possibly updated length. - if (k >= fastOW.Get().length) goto Bailout(k, accumulator); - - const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; typeswitch (accumulator) { case (TheHole): { + // 8b. accumulator = value; } case (accumulatorNotHole: JSAny): { + // 9c. ii. Set accumulator to ? Call(callbackfn, undefined, + // ). accumulator = Call( - context, callbackfn, Undefined, accumulatorNotHole, value, k, - fastOW.Get()); + context, callbackfn, Undefined, accumulatorNotHole, value, k, o); } } } + + // 8b iv and 9d. Increase k by 1. (done by the loop). + } + + // 8c. if kPresent is false, throw a TypeError exception. + // If the accumulator is discovered with the sentinel hole value, + // this means kPresent is false. + typeswitch (accumulator) { + case (TheHole): { + ThrowTypeError( + MessageTemplate::kReduceNoInitial, 'Array.prototype.reduce'); + } + case (accumulator: JSAny): { + return accumulator; + } + } +} + +transitioning macro FastArrayReduce(implicit context: Context)( + o: JSReceiver, len: Number, callbackfn: Callable, + initialAccumulator: JSAny|TheHole): JSAny + labels Bailout(Number, JSAny | TheHole) { + const k = 0; + let accumulator = initialAccumulator; + Cast(len) otherwise goto Bailout(k, accumulator); + const fastO = + Cast(o) otherwise goto Bailout(k, accumulator); + let fastOW = NewFastJSArrayForReadWitness(fastO); + + // Build a fast loop over the array. + for (let k: Smi = 0; k < len; k++) { + fastOW.Recheck() otherwise goto Bailout(k, accumulator); + + // Ensure that we haven't walked beyond a possibly updated length. + if (k >= fastOW.Get().length) goto Bailout(k, accumulator); + + const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; typeswitch (accumulator) { case (TheHole): { - ThrowTypeError( - MessageTemplate::kReduceNoInitial, 'Array.prototype.reduce'); + accumulator = value; } - case (accumulator: JSAny): { - return accumulator; + case (accumulatorNotHole: JSAny): { + accumulator = Call( + context, callbackfn, Undefined, accumulatorNotHole, value, k, + fastOW.Get()); } } } + typeswitch (accumulator) { + case (TheHole): { + ThrowTypeError( + MessageTemplate::kReduceNoInitial, 'Array.prototype.reduce'); + } + case (accumulator: JSAny): { + return accumulator; + } + } +} - // https://tc39.github.io/ecma262/#sec-array.prototype.reduce - transitioning javascript builtin - ArrayReduce(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - try { - RequireObjectCoercible(receiver, 'Array.prototype.reduce'); +// https://tc39.github.io/ecma262/#sec-array.prototype.reduce +transitioning javascript builtin +ArrayReduce( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + RequireObjectCoercible(receiver, 'Array.prototype.reduce'); - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); - // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. - if (arguments.length == 0) { - goto NoCallableError; - } - const callbackfn = Cast(arguments[0]) otherwise NoCallableError; + // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + if (arguments.length == 0) { + goto NoCallableError; + } + const callbackfn = Cast(arguments[0]) otherwise NoCallableError; - // 4. If len is 0 and initialValue is not present, throw a TypeError - // exception. (This case is handled at the end of - // ArrayReduceLoopContinuation). + // 4. If len is 0 and initialValue is not present, throw a TypeError + // exception. (This case is handled at the end of + // ArrayReduceLoopContinuation). - const initialValue: JSAny|TheHole = - arguments.length > 1 ? arguments[1] : TheHole; + const initialValue: JSAny|TheHole = + arguments.length > 1 ? arguments[1] : TheHole; - try { - return FastArrayReduce(o, len, callbackfn, initialValue) - otherwise Bailout; - } - label Bailout(value: Number, accumulator: JSAny|TheHole) { - return ArrayReduceLoopContinuation( - o, callbackfn, accumulator, o, value, len); - } - } - label NoCallableError deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + try { + return FastArrayReduce(o, len, callbackfn, initialValue) + otherwise Bailout; + } label Bailout(value: Number, accumulator: JSAny|TheHole) { + return ArrayReduceLoopContinuation( + o, callbackfn, accumulator, o, value, len); } + } label NoCallableError deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); } } +} diff --git a/deps/v8/src/builtins/array-reverse.tq b/deps/v8/src/builtins/array-reverse.tq index 8c7c61f2ee94f9..11c325140ee442 100644 --- a/deps/v8/src/builtins/array-reverse.tq +++ b/deps/v8/src/builtins/array-reverse.tq @@ -3,175 +3,170 @@ // found in the LICENSE file. namespace array { - macro LoadElement( - elements: FixedArrayBase, index: Smi): T; +macro LoadElement( + elements: FixedArrayBase, index: Smi): T; - LoadElement(implicit context: Context)( - elements: FixedArrayBase, index: Smi): Smi { - const elements: FixedArray = UnsafeCast(elements); - return UnsafeCast(elements.objects[index]); - } +LoadElement(implicit context: Context)( + elements: FixedArrayBase, index: Smi): Smi { + const elements: FixedArray = UnsafeCast(elements); + return UnsafeCast(elements.objects[index]); +} - LoadElement( - implicit context: Context)(elements: FixedArrayBase, index: Smi): JSAny { - const elements: FixedArray = UnsafeCast(elements); - return UnsafeCast(elements.objects[index]); - } +LoadElement(implicit context: Context)( + elements: FixedArrayBase, index: Smi): JSAny { + const elements: FixedArray = UnsafeCast(elements); + return UnsafeCast(elements.objects[index]); +} - LoadElement( - implicit context: Context)(elements: FixedArrayBase, index: Smi): - float64 { - const elements: FixedDoubleArray = UnsafeCast(elements); - // This macro is only used for PACKED_DOUBLE, loading the hole should - // be impossible. - return elements.floats[index].Value() otherwise unreachable; - } +LoadElement( + implicit context: Context)(elements: FixedArrayBase, index: Smi): float64 { + const elements: FixedDoubleArray = UnsafeCast(elements); + // This macro is only used for PACKED_DOUBLE, loading the hole should + // be impossible. + return elements.floats[index].Value() otherwise unreachable; +} - macro StoreElement( - implicit context: - Context)(elements: FixedArrayBase, index: Smi, value: T); +macro StoreElement( + implicit context: Context)(elements: FixedArrayBase, index: Smi, value: T); - StoreElement(implicit context: Context)( - elements: FixedArrayBase, index: Smi, value: Smi) { - const elems: FixedArray = UnsafeCast(elements); - StoreFixedArrayElement(elems, index, value, SKIP_WRITE_BARRIER); - } +StoreElement(implicit context: Context)( + elements: FixedArrayBase, index: Smi, value: Smi) { + const elems: FixedArray = UnsafeCast(elements); + StoreFixedArrayElement(elems, index, value, SKIP_WRITE_BARRIER); +} - StoreElement( - implicit context: - Context)(elements: FixedArrayBase, index: Smi, value: JSAny) { - const elements: FixedArray = UnsafeCast(elements); - elements.objects[index] = value; - } +StoreElement(implicit context: Context)( + elements: FixedArrayBase, index: Smi, value: JSAny) { + const elements: FixedArray = UnsafeCast(elements); + elements.objects[index] = value; +} + +StoreElement( + implicit context: Context)( + elements: FixedArrayBase, index: Smi, value: float64) { + const elems: FixedDoubleArray = UnsafeCast(elements); + StoreFixedDoubleArrayElementSmi(elems, index, value); +} - StoreElement( - implicit context: - Context)(elements: FixedArrayBase, index: Smi, value: float64) { - const elems: FixedDoubleArray = UnsafeCast(elements); - StoreFixedDoubleArrayElementSmi(elems, index, value); +// Fast-path for all PACKED_* elements kinds. These do not need to check +// whether a property is present, so we can simply swap them using fast +// FixedArray loads/stores. +macro FastPackedArrayReverse( + implicit context: Context)(elements: FixedArrayBase, length: Smi) { + let lower: Smi = 0; + let upper: Smi = length - 1; + + while (lower < upper) { + const lowerValue: T = LoadElement(elements, lower); + const upperValue: T = LoadElement(elements, upper); + StoreElement(elements, lower, upperValue); + StoreElement(elements, upper, lowerValue); + ++lower; + --upper; } +} - // Fast-path for all PACKED_* elements kinds. These do not need to check - // whether a property is present, so we can simply swap them using fast - // FixedArray loads/stores. - macro FastPackedArrayReverse( - implicit context: Context)(elements: FixedArrayBase, length: Smi) { - let lower: Smi = 0; - let upper: Smi = length - 1; - - while (lower < upper) { - const lowerValue: T = LoadElement(elements, lower); - const upperValue: T = LoadElement(elements, upper); - StoreElement(elements, lower, upperValue); - StoreElement(elements, upper, lowerValue); - ++lower; - --upper; +transitioning macro GenericArrayReverse( + context: Context, receiver: JSAny): JSAny { + // 1. Let O be ? ToObject(this value). + const object: JSReceiver = ToObject_Inline(context, receiver); + + // 2. Let len be ? ToLength(? Get(O, "length")). + const length: Number = GetLengthProperty(object); + + // 3. Let middle be floor(len / 2). + // 4. Let lower be 0. + // 5. Repeat, while lower != middle. + // a. Let upper be len - lower - 1. + + // Instead of calculating the middle value, we simply initialize upper + // with len - 1 and decrement it after each iteration. + let lower: Number = 0; + let upper: Number = length - 1; + + while (lower < upper) { + let lowerValue: JSAny = Undefined; + let upperValue: JSAny = Undefined; + + // b. Let upperP be ! ToString(upper). + // c. Let lowerP be ! ToString(lower). + // d. Let lowerExists be ? HasProperty(O, lowerP). + const lowerExists: Boolean = HasProperty(object, lower); + + // e. If lowerExists is true, then. + if (lowerExists == True) { + // i. Let lowerValue be ? Get(O, lowerP). + lowerValue = GetProperty(object, lower); } - } - transitioning macro GenericArrayReverse(context: Context, receiver: JSAny): - JSAny { - // 1. Let O be ? ToObject(this value). - const object: JSReceiver = ToObject_Inline(context, receiver); - - // 2. Let len be ? ToLength(? Get(O, "length")). - const length: Number = GetLengthProperty(object); - - // 3. Let middle be floor(len / 2). - // 4. Let lower be 0. - // 5. Repeat, while lower != middle. - // a. Let upper be len - lower - 1. - - // Instead of calculating the middle value, we simply initialize upper - // with len - 1 and decrement it after each iteration. - let lower: Number = 0; - let upper: Number = length - 1; - - while (lower < upper) { - let lowerValue: JSAny = Undefined; - let upperValue: JSAny = Undefined; - - // b. Let upperP be ! ToString(upper). - // c. Let lowerP be ! ToString(lower). - // d. Let lowerExists be ? HasProperty(O, lowerP). - const lowerExists: Boolean = HasProperty(object, lower); - - // e. If lowerExists is true, then. - if (lowerExists == True) { - // i. Let lowerValue be ? Get(O, lowerP). - lowerValue = GetProperty(object, lower); - } - - // f. Let upperExists be ? HasProperty(O, upperP). - const upperExists: Boolean = HasProperty(object, upper); - - // g. If upperExists is true, then. - if (upperExists == True) { - // i. Let upperValue be ? Get(O, upperP). - upperValue = GetProperty(object, upper); - } - - // h. If lowerExists is true and upperExists is true, then - if (lowerExists == True && upperExists == True) { - // i. Perform ? Set(O, lowerP, upperValue, true). - SetProperty(object, lower, upperValue); - - // ii. Perform ? Set(O, upperP, lowerValue, true). - SetProperty(object, upper, lowerValue); - } else if (lowerExists == False && upperExists == True) { - // i. Perform ? Set(O, lowerP, upperValue, true). - SetProperty(object, lower, upperValue); - - // ii. Perform ? DeletePropertyOrThrow(O, upperP). - DeleteProperty(object, upper, LanguageMode::kStrict); - } else if (lowerExists == True && upperExists == False) { - // i. Perform ? DeletePropertyOrThrow(O, lowerP). - DeleteProperty(object, lower, LanguageMode::kStrict); - - // ii. Perform ? Set(O, upperP, lowerValue, true). - SetProperty(object, upper, lowerValue); - } - - // l. Increase lower by 1. - ++lower; - --upper; + // f. Let upperExists be ? HasProperty(O, upperP). + const upperExists: Boolean = HasProperty(object, upper); + + // g. If upperExists is true, then. + if (upperExists == True) { + // i. Let upperValue be ? Get(O, upperP). + upperValue = GetProperty(object, upper); } - // 6. Return O. - return object; + // h. If lowerExists is true and upperExists is true, then + if (lowerExists == True && upperExists == True) { + // i. Perform ? Set(O, lowerP, upperValue, true). + SetProperty(object, lower, upperValue); + + // ii. Perform ? Set(O, upperP, lowerValue, true). + SetProperty(object, upper, lowerValue); + } else if (lowerExists == False && upperExists == True) { + // i. Perform ? Set(O, lowerP, upperValue, true). + SetProperty(object, lower, upperValue); + + // ii. Perform ? DeletePropertyOrThrow(O, upperP). + DeleteProperty(object, upper, LanguageMode::kStrict); + } else if (lowerExists == True && upperExists == False) { + // i. Perform ? DeletePropertyOrThrow(O, lowerP). + DeleteProperty(object, lower, LanguageMode::kStrict); + + // ii. Perform ? Set(O, upperP, lowerValue, true). + SetProperty(object, upper, lowerValue); + } + + // l. Increase lower by 1. + ++lower; + --upper; } - macro TryFastPackedArrayReverse(implicit context: Context)(receiver: JSAny) - labels Slow { - const array: FastJSArray = Cast(receiver) otherwise Slow; - - const kind: ElementsKind = array.map.elements_kind; - if (kind == ElementsKind::PACKED_SMI_ELEMENTS) { - array::EnsureWriteableFastElements(array); - FastPackedArrayReverse( - array.elements, array.length); - } else if (kind == ElementsKind::PACKED_ELEMENTS) { - array::EnsureWriteableFastElements(array); - FastPackedArrayReverse( - array.elements, array.length); - } else if (kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) { - FastPackedArrayReverse( - array.elements, array.length); - } else { - goto Slow; - } + // 6. Return O. + return object; +} + +macro TryFastPackedArrayReverse(implicit context: Context)(receiver: JSAny) + labels Slow { + const array: FastJSArray = Cast(receiver) otherwise Slow; + + const kind: ElementsKind = array.map.elements_kind; + if (kind == ElementsKind::PACKED_SMI_ELEMENTS) { + array::EnsureWriteableFastElements(array); + FastPackedArrayReverse( + array.elements, array.length); + } else if (kind == ElementsKind::PACKED_ELEMENTS) { + array::EnsureWriteableFastElements(array); + FastPackedArrayReverse( + array.elements, array.length); + } else if (kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) { + FastPackedArrayReverse( + array.elements, array.length); + } else { + goto Slow; } +} - // https://tc39.github.io/ecma262/#sec-array.prototype.reverse - transitioning javascript builtin ArrayPrototypeReverse( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - try { - TryFastPackedArrayReverse(receiver) otherwise Baseline; - return receiver; - } - label Baseline { - return GenericArrayReverse(context, receiver); - } +// https://tc39.github.io/ecma262/#sec-array.prototype.reverse +transitioning javascript builtin ArrayPrototypeReverse( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + TryFastPackedArrayReverse(receiver) otherwise Baseline; + return receiver; + } label Baseline { + return GenericArrayReverse(context, receiver); } } +} diff --git a/deps/v8/src/builtins/array-shift.tq b/deps/v8/src/builtins/array-shift.tq index d32d6be32e3c72..ed1087a85afdf8 100644 --- a/deps/v8/src/builtins/array-shift.tq +++ b/deps/v8/src/builtins/array-shift.tq @@ -3,110 +3,107 @@ // found in the LICENSE file. namespace array { - extern builtin ArrayShift(Context, JSFunction, JSAny, int32): JSAny; +extern builtin ArrayShift(Context, JSFunction, JSAny, int32): JSAny; - macro TryFastArrayShift(implicit context: Context)(receiver: JSAny): JSAny - labels Slow, Runtime { - const array: FastJSArray = Cast(receiver) otherwise Slow; - let witness = NewFastJSArrayWitness(array); +macro TryFastArrayShift(implicit context: Context)(receiver: JSAny): JSAny + labels Slow, Runtime { + const array: FastJSArray = Cast(receiver) otherwise Slow; + let witness = NewFastJSArrayWitness(array); - witness.EnsureArrayPushable() otherwise Slow; + witness.EnsureArrayPushable() otherwise Slow; - if (array.length == 0) { - return Undefined; - } + if (array.length == 0) { + return Undefined; + } - const newLength = array.length - 1; + const newLength = array.length - 1; - // Check that we're not supposed to right-trim the backing store, as - // implemented in elements.cc:ElementsAccessorBase::SetLengthImpl. - if ((newLength + newLength + kMinAddedElementsCapacity) < - array.elements.length) { - goto Runtime; - } + // Check that we're not supposed to right-trim the backing store, as + // implemented in elements.cc:ElementsAccessorBase::SetLengthImpl. + if ((newLength + newLength + kMinAddedElementsCapacity) < + array.elements.length) { + goto Runtime; + } - // Check that we're not supposed to left-trim the backing store, as - // implemented in elements.cc:FastElementsAccessor::MoveElements. - if (newLength > kMaxCopyElements) goto Runtime; + // Check that we're not supposed to left-trim the backing store, as + // implemented in elements.cc:FastElementsAccessor::MoveElements. + if (newLength > kMaxCopyElements) goto Runtime; - const result = witness.LoadElementOrUndefined(0); - witness.ChangeLength(newLength); - witness.MoveElements(0, 1, Convert(newLength)); - witness.StoreHole(newLength); - return result; - } + const result = witness.LoadElementOrUndefined(0); + witness.ChangeLength(newLength); + witness.MoveElements(0, 1, Convert(newLength)); + witness.StoreHole(newLength); + return result; +} - transitioning macro GenericArrayShift(implicit context: - Context)(receiver: JSAny): JSAny { - // 1. Let O be ? ToObject(this value). - const object: JSReceiver = ToObject_Inline(context, receiver); +transitioning macro GenericArrayShift(implicit context: Context)( + receiver: JSAny): JSAny { + // 1. Let O be ? ToObject(this value). + const object: JSReceiver = ToObject_Inline(context, receiver); - // 2. Let len be ? ToLength(? Get(O, "length")). - const length: Number = GetLengthProperty(object); + // 2. Let len be ? ToLength(? Get(O, "length")). + const length: Number = GetLengthProperty(object); - // 3. If len is zero, then - if (length == 0) { - // a. Perform ? Set(O, "length", 0, true). - SetProperty(object, kLengthString, Convert(0)); - // b. Return undefined. - return Undefined; - } + // 3. If len is zero, then + if (length == 0) { + // a. Perform ? Set(O, "length", 0, true). + SetProperty(object, kLengthString, Convert(0)); + // b. Return undefined. + return Undefined; + } - // 4. Let first be ? Get(O, "0"). - const first = GetProperty(object, Convert(0)); - // 5. Let k be 1. - let k: Number = 1; - // 6. Repeat, while k < len - while (k < length) { - // a. Let from be ! ToString(k). - const from: Number = k; - - // b. Let to be ! ToString(k - 1). - const to: Number = k - 1; - - // c. Let fromPresent be ? HasProperty(O, from). - const fromPresent: Boolean = HasProperty(object, from); - - // d. If fromPresent is true, then - if (fromPresent == True) { - // i. Let fromVal be ? Get(O, from). - const fromValue: JSAny = GetProperty(object, from); - - // ii. Perform ? Set(O, to, fromValue, true). - SetProperty(object, to, fromValue); - } else { - // i. Perform ? DeletePropertyOrThrow(O, to). - DeleteProperty(object, to, LanguageMode::kStrict); - } - - // f. Increase k by 1. - k++; + // 4. Let first be ? Get(O, "0"). + const first = GetProperty(object, Convert(0)); + // 5. Let k be 1. + let k: Number = 1; + // 6. Repeat, while k < len + while (k < length) { + // a. Let from be ! ToString(k). + const from: Number = k; + + // b. Let to be ! ToString(k - 1). + const to: Number = k - 1; + + // c. Let fromPresent be ? HasProperty(O, from). + const fromPresent: Boolean = HasProperty(object, from); + + // d. If fromPresent is true, then + if (fromPresent == True) { + // i. Let fromVal be ? Get(O, from). + const fromValue: JSAny = GetProperty(object, from); + + // ii. Perform ? Set(O, to, fromValue, true). + SetProperty(object, to, fromValue); + } else { + // i. Perform ? DeletePropertyOrThrow(O, to). + DeleteProperty(object, to, LanguageMode::kStrict); } - // 7. Perform ? DeletePropertyOrThrow(O, ! ToString(len - 1)). - DeleteProperty(object, length - 1, LanguageMode::kStrict); + // f. Increase k by 1. + k++; + } - // 8. Perform ? Set(O, "length", len - 1, true). - SetProperty(object, kLengthString, length - 1); + // 7. Perform ? DeletePropertyOrThrow(O, ! ToString(len - 1)). + DeleteProperty(object, length - 1, LanguageMode::kStrict); - // 9. Return first. - return first; - } + // 8. Perform ? Set(O, "length", len - 1, true). + SetProperty(object, kLengthString, length - 1); - // https://tc39.github.io/ecma262/#sec-array.prototype.shift - transitioning javascript builtin ArrayPrototypeShift( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - try { - return TryFastArrayShift(receiver) otherwise Slow, Runtime; - } - label Slow { - return GenericArrayShift(receiver); - } - label Runtime { - tail ArrayShift( - context, LoadTargetFromFrame(), Undefined, - Convert(arguments.length)); - } + // 9. Return first. + return first; +} + +// https://tc39.github.io/ecma262/#sec-array.prototype.shift +transitioning javascript builtin ArrayPrototypeShift( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + return TryFastArrayShift(receiver) otherwise Slow, Runtime; + } label Slow { + return GenericArrayShift(receiver); + } label Runtime { + tail ArrayShift( + context, LoadTargetFromFrame(), Undefined, + Convert(arguments.length)); } } +} diff --git a/deps/v8/src/builtins/array-slice.tq b/deps/v8/src/builtins/array-slice.tq index b11b07e48be65d..147dae6f72f46b 100644 --- a/deps/v8/src/builtins/array-slice.tq +++ b/deps/v8/src/builtins/array-slice.tq @@ -3,225 +3,222 @@ // found in the LICENSE file. namespace array { - macro HandleSimpleArgumentsSlice( - context: NativeContext, args: JSArgumentsObjectWithLength, start: Smi, - count: Smi): JSArray - labels Bailout { - // If the resulting array doesn't fit in new space, use the slow path. - if (count >= kMaxNewSpaceFixedArrayElements) goto Bailout; - - const end: Smi = start + count; - const sourceElements: FixedArray = - Cast(args.elements) otherwise Bailout; - if (SmiAbove(end, sourceElements.length)) goto Bailout; - - const arrayMap: Map = - LoadJSArrayElementsMap(ElementsKind::HOLEY_ELEMENTS, context); - const result: JSArray = - AllocateJSArray(ElementsKind::HOLEY_ELEMENTS, arrayMap, count, count); - const newElements: FixedArray = - Cast(result.elements) otherwise Bailout; - CopyElements( - ElementsKind::PACKED_ELEMENTS, newElements, 0, sourceElements, - Convert(start), Convert(count)); - return result; - } - - macro HandleFastAliasedSloppyArgumentsSlice( - context: NativeContext, args: JSArgumentsObjectWithLength, start: Smi, - count: Smi): JSArray - labels Bailout { - // If the resulting array doesn't fit in new space, use the slow path. - if (count >= kMaxNewSpaceFixedArrayElements) goto Bailout; - - const sloppyElements: SloppyArgumentsElements = - Cast(args.elements) otherwise Bailout; - const sloppyElementsLength: Smi = sloppyElements.length; - const parameterMapLength: Smi = - sloppyElementsLength - kSloppyArgumentsParameterMapStart; - - // Check to make sure that the extraction will not access outside the - // defined arguments - const end: Smi = start + count; - const unmappedElements: FixedArray = - Cast(sloppyElements.objects[kSloppyArgumentsArgumentsIndex]) - otherwise Bailout; - const unmappedElementsLength: Smi = unmappedElements.length; - if (SmiAbove(end, unmappedElementsLength)) goto Bailout; - - const argumentsContext: Context = UnsafeCast( - sloppyElements.objects[kSloppyArgumentsContextIndex]); - - const arrayMap: Map = - LoadJSArrayElementsMap(ElementsKind::HOLEY_ELEMENTS, context); - const result: JSArray = - AllocateJSArray(ElementsKind::HOLEY_ELEMENTS, arrayMap, count, count); - - let indexOut: Smi = 0; - const resultElements: FixedArray = UnsafeCast(result.elements); - const to: Smi = SmiMin(parameterMapLength, end); - - // Fill in the part of the result that map to context-mapped parameters. - for (let current: Smi = start; current < to; ++current) { - const e: Object = - sloppyElements.objects[current + kSloppyArgumentsParameterMapStart]; - const newElement = UnsafeCast<(JSAny | TheHole)>( - e != TheHole ? argumentsContext[UnsafeCast(e)] : - unmappedElements.objects[current]); - // It is safe to skip the write barrier here because resultElements was - // allocated together with result in a folded allocation. - // TODO(tebbi): The verification of this fails at the moment due to - // missing load elimination. - StoreFixedArrayElement( - resultElements, indexOut++, newElement, UNSAFE_SKIP_WRITE_BARRIER); - } +macro HandleSimpleArgumentsSlice( + context: NativeContext, args: JSArgumentsObjectWithLength, start: Smi, + count: Smi): JSArray + labels Bailout { + // If the resulting array doesn't fit in new space, use the slow path. + if (count >= kMaxNewSpaceFixedArrayElements) goto Bailout; + + const end: Smi = start + count; + const sourceElements: FixedArray = + Cast(args.elements) otherwise Bailout; + if (SmiAbove(end, sourceElements.length)) goto Bailout; + + const arrayMap: Map = + LoadJSArrayElementsMap(ElementsKind::HOLEY_ELEMENTS, context); + const result: JSArray = + AllocateJSArray(ElementsKind::HOLEY_ELEMENTS, arrayMap, count, count); + const newElements: FixedArray = + Cast(result.elements) otherwise Bailout; + CopyElements( + ElementsKind::PACKED_ELEMENTS, newElements, 0, sourceElements, + Convert(start), Convert(count)); + return result; +} - // Fill in the rest of the result that contains the unmapped parameters - // above the formal parameters. - const unmappedFrom: Smi = SmiMin(SmiMax(parameterMapLength, start), end); - const restCount: Smi = end - unmappedFrom; - CopyElements( - ElementsKind::PACKED_ELEMENTS, resultElements, - Convert(indexOut), unmappedElements, - Convert(unmappedFrom), Convert(restCount)); - return result; +macro HandleFastAliasedSloppyArgumentsSlice( + context: NativeContext, args: JSArgumentsObjectWithLength, start: Smi, + count: Smi): JSArray + labels Bailout { + // If the resulting array doesn't fit in new space, use the slow path. + if (count >= kMaxNewSpaceFixedArrayElements) goto Bailout; + + const sloppyElements: SloppyArgumentsElements = + Cast(args.elements) otherwise Bailout; + const sloppyElementsLength: Smi = sloppyElements.length; + const parameterMapLength: Smi = + sloppyElementsLength - kSloppyArgumentsParameterMapStart; + + // Check to make sure that the extraction will not access outside the + // defined arguments + const end: Smi = start + count; + const unmappedElements: FixedArray = + Cast(sloppyElements.objects[kSloppyArgumentsArgumentsIndex]) + otherwise Bailout; + const unmappedElementsLength: Smi = unmappedElements.length; + if (SmiAbove(end, unmappedElementsLength)) goto Bailout; + + const argumentsContext: Context = + UnsafeCast(sloppyElements.objects[kSloppyArgumentsContextIndex]); + + const arrayMap: Map = + LoadJSArrayElementsMap(ElementsKind::HOLEY_ELEMENTS, context); + const result: JSArray = + AllocateJSArray(ElementsKind::HOLEY_ELEMENTS, arrayMap, count, count); + + let indexOut: Smi = 0; + const resultElements: FixedArray = UnsafeCast(result.elements); + const to: Smi = SmiMin(parameterMapLength, end); + + // Fill in the part of the result that map to context-mapped parameters. + for (let current: Smi = start; current < to; ++current) { + const e: Object = + sloppyElements.objects[current + kSloppyArgumentsParameterMapStart]; + const newElement = UnsafeCast<(JSAny | TheHole)>( + e != TheHole ? argumentsContext[UnsafeCast(e)] : + unmappedElements.objects[current]); + // It is safe to skip the write barrier here because resultElements was + // allocated together with result in a folded allocation. + // TODO(tebbi): The verification of this fails at the moment due to + // missing load elimination. + StoreFixedArrayElement( + resultElements, indexOut++, newElement, UNSAFE_SKIP_WRITE_BARRIER); } - macro HandleFastSlice( - context: NativeContext, o: JSAny, startNumber: Number, - countNumber: Number): JSArray - labels Bailout { - const start: Smi = Cast(startNumber) otherwise Bailout; - const count: Smi = Cast(countNumber) otherwise Bailout; - assert(start >= 0); - - try { - typeswitch (o) { - case (a: FastJSArrayForCopy): { - // It's possible to modify the array length from a valueOf - // callback between the original array length read and this - // point. That can change the length of the array backing store, - // in the worst case, making it smaller than the region that needs - // to be copied out. Therefore, re-check the length before calling - // the appropriate fast path. See regress-785804.js - if (SmiAbove(start + count, a.length)) goto Bailout; - return ExtractFastJSArray(context, a, start, count); - } - case (a: JSStrictArgumentsObject): { + // Fill in the rest of the result that contains the unmapped parameters + // above the formal parameters. + const unmappedFrom: Smi = SmiMin(SmiMax(parameterMapLength, start), end); + const restCount: Smi = end - unmappedFrom; + CopyElements( + ElementsKind::PACKED_ELEMENTS, resultElements, Convert(indexOut), + unmappedElements, Convert(unmappedFrom), + Convert(restCount)); + return result; +} + +macro HandleFastSlice( + context: NativeContext, o: JSAny, startNumber: Number, + countNumber: Number): JSArray + labels Bailout { + const start: Smi = Cast(startNumber) otherwise Bailout; + const count: Smi = Cast(countNumber) otherwise Bailout; + assert(start >= 0); + + try { + typeswitch (o) { + case (a: FastJSArrayForCopy): { + // It's possible to modify the array length from a valueOf + // callback between the original array length read and this + // point. That can change the length of the array backing store, + // in the worst case, making it smaller than the region that needs + // to be copied out. Therefore, re-check the length before calling + // the appropriate fast path. See regress-785804.js + if (SmiAbove(start + count, a.length)) goto Bailout; + return ExtractFastJSArray(context, a, start, count); + } + case (a: JSStrictArgumentsObject): { + goto HandleSimpleArgumentsSlice(a); + } + case (a: JSSloppyArgumentsObject): { + const map: Map = a.map; + if (IsFastAliasedArgumentsMap(map)) { + return HandleFastAliasedSloppyArgumentsSlice(context, a, start, count) + otherwise Bailout; + } else if (IsSloppyArgumentsMap(map)) { goto HandleSimpleArgumentsSlice(a); } - case (a: JSSloppyArgumentsObject): { - const map: Map = a.map; - if (IsFastAliasedArgumentsMap(map)) { - return HandleFastAliasedSloppyArgumentsSlice( - context, a, start, count) - otherwise Bailout; - } else if (IsSloppyArgumentsMap(map)) { - goto HandleSimpleArgumentsSlice(a); - } - goto Bailout; - } - case (JSAny): { - goto Bailout; - } + goto Bailout; + } + case (JSAny): { + goto Bailout; } } - label HandleSimpleArgumentsSlice(a: JSArgumentsObjectWithLength) { - return HandleSimpleArgumentsSlice(context, a, start, count) - otherwise Bailout; - } + } label HandleSimpleArgumentsSlice(a: JSArgumentsObjectWithLength) { + return HandleSimpleArgumentsSlice(context, a, start, count) + otherwise Bailout; } +} - // https://tc39.github.io/ecma262/#sec-array.prototype.slice - transitioning javascript builtin - ArrayPrototypeSlice(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - // Handle array cloning case if the receiver is a fast array. - if (arguments.length == 0) { - typeswitch (receiver) { - case (a: FastJSArrayForCopy): { - return CloneFastJSArray(context, a); - } - case (JSAny): { - } +// https://tc39.github.io/ecma262/#sec-array.prototype.slice +transitioning javascript builtin +ArrayPrototypeSlice( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // Handle array cloning case if the receiver is a fast array. + if (arguments.length == 0) { + typeswitch (receiver) { + case (a: FastJSArrayForCopy): { + return CloneFastJSArray(context, a); + } + case (JSAny): { } } + } - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); - - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); - - // 3. Let relativeStart be ? ToInteger(start). - const start: JSAny = arguments[0]; - const relativeStart: Number = ToInteger_Inline(start); + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); - // 4. If relativeStart < 0, let k be max((len + relativeStart), 0); - // else let k be min(relativeStart, len). - let k: Number = relativeStart < 0 ? Max((len + relativeStart), 0) : - Min(relativeStart, len); + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); - // 5. If end is undefined, let relativeEnd be len; - // else let relativeEnd be ? ToInteger(end). - const end: JSAny = arguments[1]; - const relativeEnd: Number = end == Undefined ? len : ToInteger_Inline(end); + // 3. Let relativeStart be ? ToInteger(start). + const start: JSAny = arguments[0]; + const relativeStart: Number = ToInteger_Inline(start); - // 6. If relativeEnd < 0, let final be max((len + relativeEnd), 0); - // else let final be min(relativeEnd, len). - const final: Number = - relativeEnd < 0 ? Max((len + relativeEnd), 0) : Min(relativeEnd, len); + // 4. If relativeStart < 0, let k be max((len + relativeStart), 0); + // else let k be min(relativeStart, len). + let k: Number = relativeStart < 0 ? Max((len + relativeStart), 0) : + Min(relativeStart, len); - // 7. Let count be max(final - k, 0). - const count: Number = Max(final - k, 0); + // 5. If end is undefined, let relativeEnd be len; + // else let relativeEnd be ? ToInteger(end). + const end: JSAny = arguments[1]; + const relativeEnd: Number = end == Undefined ? len : ToInteger_Inline(end); - assert(0 <= k); - assert(k <= len); - assert(0 <= final); - assert(final <= len); - assert(0 <= count); - assert(count <= len); + // 6. If relativeEnd < 0, let final be max((len + relativeEnd), 0); + // else let final be min(relativeEnd, len). + const final: Number = + relativeEnd < 0 ? Max((len + relativeEnd), 0) : Min(relativeEnd, len); - try { - return HandleFastSlice(context, o, k, count) - otherwise Slow; - } - label Slow {} + // 7. Let count be max(final - k, 0). + const count: Number = Max(final - k, 0); - // 8. Let A be ? ArraySpeciesCreate(O, count). - const a: JSReceiver = ArraySpeciesCreate(context, o, count); + assert(0 <= k); + assert(k <= len); + assert(0 <= final); + assert(final <= len); + assert(0 <= count); + assert(count <= len); - // 9. Let n be 0. - let n: Number = 0; + try { + return HandleFastSlice(context, o, k, count) + otherwise Slow; + } label Slow {} - // 10. Repeat, while k < final - while (k < final) { - // a. Let Pk be ! ToString(k). - const pK: Number = k; + // 8. Let A be ? ArraySpeciesCreate(O, count). + const a: JSReceiver = ArraySpeciesCreate(context, o, count); - // b. Let kPresent be ? HasProperty(O, Pk). - const fromPresent: Boolean = HasProperty(o, pK); + // 9. Let n be 0. + let n: Number = 0; - // c. If kPresent is true, then - if (fromPresent == True) { - // i. Let kValue be ? Get(O, Pk). - const kValue: JSAny = GetProperty(o, pK); + // 10. Repeat, while k < final + while (k < final) { + // a. Let Pk be ! ToString(k). + const pK: Number = k; - // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(n), kValue). - FastCreateDataProperty(a, n, kValue); - } + // b. Let kPresent be ? HasProperty(O, Pk). + const fromPresent: Boolean = HasProperty(o, pK); - // d. Increase k by 1. - k++; + // c. If kPresent is true, then + if (fromPresent == True) { + // i. Let kValue be ? Get(O, Pk). + const kValue: JSAny = GetProperty(o, pK); - // e. Increase n by 1. - n++; + // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(n), kValue). + FastCreateDataProperty(a, n, kValue); } - // 11. Perform ? Set(A, "length", n, true). - SetProperty(a, kLengthString, n); + // d. Increase k by 1. + k++; - // 12. Return A. - return a; + // e. Increase n by 1. + n++; } + + // 11. Perform ? Set(A, "length", n, true). + SetProperty(a, kLengthString, n); + + // 12. Return A. + return a; +} } diff --git a/deps/v8/src/builtins/array-some.tq b/deps/v8/src/builtins/array-some.tq index 59b8294f74d17b..69467bba276a12 100644 --- a/deps/v8/src/builtins/array-some.tq +++ b/deps/v8/src/builtins/array-some.tq @@ -3,145 +3,142 @@ // found in the LICENSE file. namespace array { - transitioning javascript builtin - ArraySomeLoopEagerDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { - // All continuation points in the optimized some implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - // - // Also, this great mass of casts is necessary because the signature - // of Torque javascript builtins requires JSAny type for all parameters - // other than {context}. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - const numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - return ArraySomeLoopContinuation( - jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, - numberLength, Undefined); +transitioning javascript builtin +ArraySomeLoopEagerDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { + // All continuation points in the optimized some implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + // + // Also, this great mass of casts is necessary because the signature + // of Torque javascript builtins requires JSAny type for all parameters + // other than {context}. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + const numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + return ArraySomeLoopContinuation( + jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, + numberLength, Undefined); +} + +transitioning javascript builtin +ArraySomeLoopLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, + result: JSAny): JSAny { + // All continuation points in the optimized some implementation are + // after the ToObject(O) call that ensures we are dealing with a + // JSReceiver. + const jsreceiver = Cast(receiver) otherwise unreachable; + const callbackfn = Cast(callback) otherwise unreachable; + let numberK = Cast(initialK) otherwise unreachable; + const numberLength = Cast(length) otherwise unreachable; + + // This custom lazy deopt point is right after the callback. some() needs + // to pick up at the next step: if the result is true, then return, + // otherwise, keep going through the array starting from k + 1. + if (ToBoolean(result)) { + return True; } - transitioning javascript builtin - ArraySomeLoopLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, - result: JSAny): JSAny { - // All continuation points in the optimized some implementation are - // after the ToObject(O) call that ensures we are dealing with a - // JSReceiver. - const jsreceiver = Cast(receiver) otherwise unreachable; - const callbackfn = Cast(callback) otherwise unreachable; - let numberK = Cast(initialK) otherwise unreachable; - const numberLength = Cast(length) otherwise unreachable; - - // This custom lazy deopt point is right after the callback. some() needs - // to pick up at the next step: if the result is true, then return, - // otherwise, keep going through the array starting from k + 1. - if (ToBoolean(result)) { - return True; - } + numberK = numberK + 1; - numberK = numberK + 1; + return ArraySomeLoopContinuation( + jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, + numberLength, Undefined); +} - return ArraySomeLoopContinuation( - jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK, - numberLength, Undefined); - } +transitioning builtin ArraySomeLoopContinuation(implicit context: Context)( + _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, _array: JSAny, + o: JSReceiver, initialK: Number, length: Number, _initialTo: JSAny): JSAny { + // 5. Let k be 0. + // 6. Repeat, while k < len + for (let k: Number = initialK; k < length; k++) { + // 6a. Let Pk be ! ToString(k). + // k is guaranteed to be a positive integer, hence ToString is + // side-effect free and HasProperty/GetProperty do the conversion inline. - transitioning builtin ArraySomeLoopContinuation(implicit context: Context)( - _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, - _array: JSAny, o: JSReceiver, initialK: Number, length: Number, - _initialTo: JSAny): JSAny { - // 5. Let k be 0. - // 6. Repeat, while k < len - for (let k: Number = initialK; k < length; k++) { - // 6a. Let Pk be ! ToString(k). - // k is guaranteed to be a positive integer, hence ToString is - // side-effect free and HasProperty/GetProperty do the conversion inline. - - // 6b. Let kPresent be ? HasProperty(O, Pk). - const kPresent: Boolean = HasProperty_Inline(o, k); - - // 6c. If kPresent is true, then - if (kPresent == True) { - // 6c. i. Let kValue be ? Get(O, Pk). - const kValue: JSAny = GetProperty(o, k); - - // 6c. ii. Perform ? Call(callbackfn, T, ). - const result: JSAny = Call(context, callbackfn, thisArg, kValue, k, o); - - // iii. If selected is true, then... - if (ToBoolean(result)) { - return True; - } - } + // 6b. Let kPresent be ? HasProperty(O, Pk). + const kPresent: Boolean = HasProperty_Inline(o, k); - // 6d. Increase k by 1. (done by the loop). - } - return False; - } + // 6c. If kPresent is true, then + if (kPresent == True) { + // 6c. i. Let kValue be ? Get(O, Pk). + const kValue: JSAny = GetProperty(o, k); + + // 6c. ii. Perform ? Call(callbackfn, T, ). + const result: JSAny = Call(context, callbackfn, thisArg, kValue, k, o); - transitioning macro FastArraySome(implicit context: Context)( - o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny - labels Bailout(Smi) { - let k: Smi = 0; - const smiLen = Cast(len) otherwise goto Bailout(k); - const fastO = Cast(o) otherwise goto Bailout(k); - let fastOW = NewFastJSArrayWitness(fastO); - - // Build a fast loop over the smi array. - for (; k < smiLen; k++) { - fastOW.Recheck() otherwise goto Bailout(k); - - // Ensure that we haven't walked beyond a possibly updated length. - if (k >= fastOW.Get().length) goto Bailout(k); - const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; - const result: JSAny = - Call(context, callbackfn, thisArg, value, k, fastOW.Get()); + // iii. If selected is true, then... if (ToBoolean(result)) { return True; } } - return False; - } - // https://tc39.github.io/ecma262/#sec-array.prototype.some - transitioning javascript builtin - ArraySome(js-implicit context: NativeContext, receiver: JSAny)(...arguments): - JSAny { - try { - RequireObjectCoercible(receiver, 'Array.prototype.some'); + // 6d. Increase k by 1. (done by the loop). + } + return False; +} - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject_Inline(context, receiver); +transitioning macro FastArraySome(implicit context: Context)( + o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny + labels Bailout(Smi) { + let k: Smi = 0; + const smiLen = Cast(len) otherwise goto Bailout(k); + const fastO = Cast(o) otherwise goto Bailout(k); + let fastOW = NewFastJSArrayWitness(fastO); + + // Build a fast loop over the smi array. + for (; k < smiLen; k++) { + fastOW.Recheck() otherwise goto Bailout(k); + + // Ensure that we haven't walked beyond a possibly updated length. + if (k >= fastOW.Get().length) goto Bailout(k); + const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; + const result: JSAny = + Call(context, callbackfn, thisArg, value, k, fastOW.Get()); + if (ToBoolean(result)) { + return True; + } + } + return False; +} - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); +// https://tc39.github.io/ecma262/#sec-array.prototype.some +transitioning javascript builtin +ArraySome( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + RequireObjectCoercible(receiver, 'Array.prototype.some'); - // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. - if (arguments.length == 0) { - goto TypeError; - } - const callbackfn = Cast(arguments[0]) otherwise TypeError; + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject_Inline(context, receiver); - // 4. If thisArg is present, let T be thisArg; else let T be undefined. - const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined; + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); - // Special cases. - try { - return FastArraySome(o, len, callbackfn, thisArg) - otherwise Bailout; - } - label Bailout(kValue: Smi) deferred { - return ArraySomeLoopContinuation( - o, callbackfn, thisArg, Undefined, o, kValue, len, Undefined); - } + // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + if (arguments.length == 0) { + goto TypeError; } - label TypeError deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + const callbackfn = Cast(arguments[0]) otherwise TypeError; + + // 4. If thisArg is present, let T be thisArg; else let T be undefined. + const thisArg: JSAny = arguments[1]; + + // Special cases. + try { + return FastArraySome(o, len, callbackfn, thisArg) + otherwise Bailout; + } label Bailout(kValue: Smi) deferred { + return ArraySomeLoopContinuation( + o, callbackfn, thisArg, Undefined, o, kValue, len, Undefined); } + } label TypeError deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); } } +} diff --git a/deps/v8/src/builtins/array-splice.tq b/deps/v8/src/builtins/array-splice.tq index 9d7a223d97411c..92eace071cbe20 100644 --- a/deps/v8/src/builtins/array-splice.tq +++ b/deps/v8/src/builtins/array-splice.tq @@ -3,416 +3,418 @@ // found in the LICENSE file. namespace array { - // Given {elements}, we want to create a non-zero length array of type - // FixedArrayType. Most of this behavior is outsourced to ExtractFixedArray(), - // but the special case of wanting to have a FixedDoubleArray when given a - // zero-length input FixedArray is handled here. - macro Extract(implicit context: Context)( - elements: FixedArray, first: Smi, count: Smi, capacity: Smi): FixedArray { - return ExtractFixedArray( - elements, Convert(first), Convert(count), - Convert(capacity)); - } +// Given {source}, we want to create a non-zero length array of type +// FixedArrayType with the specified {result_capacity}. Starting from +// {startIndex}, {count} number of elements are copied to the newly +// created result array. Most of this behavior is outsourced to +// ExtractFixedArray(). We handle the case where the {source} is +// EmptyFixedArray but result is expected to be a FixedDoubleArray. +macro Extract(implicit context: Context)( + source: FixedArray, startIndex: Smi, count: Smi, + resultCapacity: Smi): FixedArray { + return ExtractFixedArray( + source, Convert(startIndex), Convert(count), + Convert(resultCapacity)); +} - macro Extract(implicit context: Context)( - elements: FixedDoubleArray|EmptyFixedArray, first: Smi, count: Smi, - capacity: Smi): FixedDoubleArray|EmptyFixedArray { - typeswitch (elements) { - case (EmptyFixedArray): { - return AllocateZeroedFixedDoubleArray(Convert(capacity)); - } - case (elements: FixedDoubleArray): { - return ExtractFixedDoubleArray( - elements, Convert(first), Convert(count), - Convert(capacity)); - } +macro Extract(implicit context: Context)( + source: FixedDoubleArray|EmptyFixedArray, startIndex: Smi, count: Smi, + resultCapacity: Smi): FixedDoubleArray|EmptyFixedArray { + typeswitch (source) { + case (EmptyFixedArray): { + // ExtractFixedDoubleArray expects {source} to be a FixedDoubleArray. + // Handle the case where {source} is empty here. + return AllocateFixedDoubleArrayWithHoles( + Convert(resultCapacity), + AllocationFlag::kAllowLargeObjectAllocation); + } + case (source: FixedDoubleArray): { + return ExtractFixedDoubleArray( + source, Convert(startIndex), Convert(count), + Convert(resultCapacity)); } } +} - macro DoMoveElements( - elements: FixedArrayType, dstIndex: Smi, srcIndex: Smi, - count: Smi): void { - TorqueMoveElements( - elements, Convert(dstIndex), Convert(srcIndex), - Convert(count)); - } +macro DoMoveElements( + elements: FixedArrayType, dstIndex: Smi, srcIndex: Smi, count: Smi): void { + TorqueMoveElements( + elements, Convert(dstIndex), Convert(srcIndex), + Convert(count)); +} - macro StoreHoles( - elements: FixedArrayType, holeStartIndex: Smi, holeEndIndex: Smi): void { - for (let i: Smi = holeStartIndex; i < holeEndIndex; i++) { - array::StoreArrayHole(elements, i); - } +macro StoreHoles( + elements: FixedArrayType, holeStartIndex: Smi, holeEndIndex: Smi): void { + for (let i: Smi = holeStartIndex; i < holeEndIndex; i++) { + array::StoreArrayHole(elements, i); } +} - macro DoCopyElements( - dstElements: FixedArrayType, dstIndex: Smi, srcElements: FixedArrayType, - srcIndex: Smi, count: Smi): void { - TorqueCopyElements( - dstElements, Convert(dstIndex), srcElements, - Convert(srcIndex), Convert(count)); - } +macro DoCopyElements( + dstElements: FixedArrayType, dstIndex: Smi, srcElements: FixedArrayType, + srcIndex: Smi, count: Smi): void { + TorqueCopyElements( + dstElements, Convert(dstIndex), srcElements, + Convert(srcIndex), Convert(count)); +} - macro - FastSplice( - implicit context: Context)( - args: Arguments, a: JSArray, length: Smi, newLength: Smi, - actualStart: Smi, insertCount: Smi, actualDeleteCount: Smi): void { - // Make sure elements are writable. - array::EnsureWriteableFastElements(a); - - if (insertCount != actualDeleteCount) { - const elements = - UnsafeCast<(FixedArrayType | EmptyFixedArray)>(a.elements); - const dstIndex: Smi = actualStart + insertCount; - const srcIndex: Smi = actualStart + actualDeleteCount; - const count: Smi = length - actualDeleteCount - actualStart; - if (insertCount < actualDeleteCount) { - // Shrink. +macro +FastSplice( + implicit context: Context)( + args: Arguments, a: JSArray, length: Smi, newLength: Smi, actualStart: Smi, + insertCount: Smi, actualDeleteCount: Smi): void { + // Make sure elements are writable. + array::EnsureWriteableFastElements(a); + + if (insertCount != actualDeleteCount) { + const elements = UnsafeCast<(FixedArrayType | EmptyFixedArray)>(a.elements); + const dstIndex: Smi = actualStart + insertCount; + const srcIndex: Smi = actualStart + actualDeleteCount; + const count: Smi = length - actualDeleteCount - actualStart; + if (insertCount < actualDeleteCount) { + // Shrink. + DoMoveElements( + UnsafeCast(elements), dstIndex, srcIndex, count); + StoreHoles(UnsafeCast(elements), newLength, length); + } else if (insertCount > actualDeleteCount) { + // If the backing store is big enough, then moving elements is enough. + if (newLength <= elements.length) { DoMoveElements( UnsafeCast(elements), dstIndex, srcIndex, count); - StoreHoles(UnsafeCast(elements), newLength, length); - } else if (insertCount > actualDeleteCount) { - // If the backing store is big enough, then moving elements is enough. - if (newLength <= elements.length) { - DoMoveElements( - UnsafeCast(elements), dstIndex, srcIndex, count); - } else { - // Grow. - const capacity: Smi = CalculateNewElementsCapacity(newLength); - const newElements: FixedArrayType = UnsafeCast( - Extract(elements, 0, actualStart, capacity)); - a.elements = newElements; - if (elements.length > 0) { - DoCopyElements( - newElements, dstIndex, UnsafeCast(elements), - srcIndex, count); - } + } else { + // Grow. + const capacity: Smi = CalculateNewElementsCapacity(newLength); + const newElements: FixedArrayType = UnsafeCast( + Extract(elements, 0, actualStart, capacity)); + a.elements = newElements; + if (elements.length > 0) { + DoCopyElements( + newElements, dstIndex, UnsafeCast(elements), + srcIndex, count); } } } - - // Copy arguments. - let k: Smi = actualStart; - if (insertCount > 0) { - const typedNewElements: FixedArrayType = - UnsafeCast(a.elements); - for (let i: intptr = 2; i < args.length; ++i) { - const e: JSAny = args[i]; - // The argument elements were already validated to be an appropriate - // {ElementType} to store in {FixedArrayType}. - typedNewElements[k++] = UnsafeCast(e); - } - } - - // Update the array's length after all the FixedArray shuffling is done. - a.length = newLength; } - transitioning macro FastArraySplice( - context: Context, args: Arguments, o: JSReceiver, - originalLengthNumber: Number, actualStartNumber: Number, insertCount: Smi, - actualDeleteCountNumber: Number): JSAny - labels Bailout { - const originalLength: Smi = - Cast(originalLengthNumber) otherwise Bailout; - const actualStart: Smi = Cast(actualStartNumber) otherwise Bailout; - const actualDeleteCount: Smi = - Cast(actualDeleteCountNumber) otherwise Bailout; - const lengthDelta: Smi = insertCount - actualDeleteCount; - const newLength: Smi = originalLength + lengthDelta; - - const a: JSArray = Cast(o) otherwise Bailout; - - const map: Map = a.map; - if (!IsPrototypeInitialArrayPrototype(map)) goto Bailout; - if (IsNoElementsProtectorCellInvalid()) goto Bailout; - if (IsArraySpeciesProtectorCellInvalid()) goto Bailout; - - // Fast path only works on fast elements kind and with writable length. - let elementsKind: ElementsKind = EnsureArrayPushable(map) otherwise Bailout; - if (!IsFastElementsKind(elementsKind)) goto Bailout; - - const oldElementsKind: ElementsKind = elementsKind; + // Copy arguments. + let k: Smi = actualStart; + if (insertCount > 0) { + const typedNewElements: FixedArrayType = + UnsafeCast(a.elements); for (let i: intptr = 2; i < args.length; ++i) { const e: JSAny = args[i]; - if (IsFastSmiElementsKind(elementsKind)) { - if (TaggedIsNotSmi(e)) { - const heapObject: HeapObject = UnsafeCast(e); - elementsKind = IsHeapNumber(heapObject) ? - AllowDoubleElements(elementsKind) : - AllowNonNumberElements(elementsKind); - } - } else if (IsDoubleElementsKind(elementsKind)) { - if (!IsNumber(e)) { - elementsKind = AllowNonNumberElements(elementsKind); - } - } + // The argument elements were already validated to be an appropriate + // {ElementType} to store in {FixedArrayType}. + typedNewElements[k++] = UnsafeCast(e); } + } - if (elementsKind != oldElementsKind) { - const smiElementsKind: Smi = Convert(Convert(elementsKind)); - TransitionElementsKindWithKind(context, a, smiElementsKind); - } + // Update the array's length after all the FixedArray shuffling is done. + a.length = newLength; +} - // Make sure that the length hasn't been changed by side-effect. - const length: Smi = Cast(a.length) otherwise Bailout; - if (originalLength != length) goto Bailout; +transitioning macro FastArraySplice( + context: Context, args: Arguments, o: JSReceiver, + originalLengthNumber: Number, actualStartNumber: Number, insertCount: Smi, + actualDeleteCountNumber: Number): JSAny + labels Bailout { + const originalLength: Smi = Cast(originalLengthNumber) otherwise Bailout; + const actualStart: Smi = Cast(actualStartNumber) otherwise Bailout; + const actualDeleteCount: Smi = + Cast(actualDeleteCountNumber) otherwise Bailout; + const lengthDelta: Smi = insertCount - actualDeleteCount; + const newLength: Smi = originalLength + lengthDelta; + + const a: JSArray = Cast(o) otherwise Bailout; + + const map: Map = a.map; + if (!IsPrototypeInitialArrayPrototype(map)) goto Bailout; + if (IsNoElementsProtectorCellInvalid()) goto Bailout; + if (IsArraySpeciesProtectorCellInvalid()) goto Bailout; + + // Fast path only works on fast elements kind and with writable length. + let elementsKind: ElementsKind = EnsureArrayPushable(map) otherwise Bailout; + if (!IsFastElementsKind(elementsKind)) goto Bailout; + + const oldElementsKind: ElementsKind = elementsKind; + for (let i: intptr = 2; i < args.length; ++i) { + const e: JSAny = args[i]; + if (IsFastSmiElementsKind(elementsKind)) { + if (TaggedIsNotSmi(e)) { + const heapObject: HeapObject = UnsafeCast(e); + elementsKind = IsHeapNumber(heapObject) ? + AllowDoubleElements(elementsKind) : + AllowNonNumberElements(elementsKind); + } + } else if (IsDoubleElementsKind(elementsKind)) { + if (!IsNumber(e)) { + elementsKind = AllowNonNumberElements(elementsKind); + } + } + } - const deletedResult: JSArray = - ExtractFastJSArray(context, a, actualStart, actualDeleteCount); + if (elementsKind != oldElementsKind) { + const smiElementsKind: Smi = Convert(Convert(elementsKind)); + TransitionElementsKindWithKind(context, a, smiElementsKind); + } - if (newLength == 0) { - a.elements = kEmptyFixedArray; - a.length = 0; - return deletedResult; - } + // Make sure that the length hasn't been changed by side-effect. + const length: Smi = Cast(a.length) otherwise Bailout; + if (originalLength != length) goto Bailout; - if (IsFastSmiOrTaggedElementsKind(elementsKind)) { - FastSplice( - args, a, length, newLength, actualStart, insertCount, - actualDeleteCount); - } else { - FastSplice( - args, a, length, newLength, actualStart, insertCount, - actualDeleteCount); - } + const deletedResult: JSArray = + ExtractFastJSArray(context, a, actualStart, actualDeleteCount); + if (newLength == 0) { + a.elements = kEmptyFixedArray; + a.length = 0; return deletedResult; } - transitioning macro FillDeletedElementsArray( - context: Context, o: JSReceiver, actualStart: Number, - actualDeleteCount: Number, a: JSReceiver): JSAny { - // 10. Let k be 0. - let k: Number = 0; + if (IsFastSmiOrTaggedElementsKind(elementsKind)) { + FastSplice( + args, a, length, newLength, actualStart, insertCount, + actualDeleteCount); + } else { + FastSplice( + args, a, length, newLength, actualStart, insertCount, + actualDeleteCount); + } + + return deletedResult; +} - // 11. Repeat, while k < actualDeleteCount - while (k < actualDeleteCount) { - // a. Let from be ! ToString(actualStart + k). - const from: Number = actualStart + k; +transitioning macro FillDeletedElementsArray( + context: Context, o: JSReceiver, actualStart: Number, + actualDeleteCount: Number, a: JSReceiver): JSAny { + // 10. Let k be 0. + let k: Number = 0; - // b. Let fromPresent be ? HasProperty(O, from). - const fromPresent: Boolean = HasProperty(o, from); + // 11. Repeat, while k < actualDeleteCount + while (k < actualDeleteCount) { + // a. Let from be ! ToString(actualStart + k). + const from: Number = actualStart + k; - // c. If fromPresent is true, then - if (fromPresent == True) { - // i. Let fromValue be ? Get(O, from). - const fromValue: JSAny = GetProperty(o, from); + // b. Let fromPresent be ? HasProperty(O, from). + const fromPresent: Boolean = HasProperty(o, from); - // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(k), fromValue). - FastCreateDataProperty(a, k, fromValue); - } + // c. If fromPresent is true, then + if (fromPresent == True) { + // i. Let fromValue be ? Get(O, from). + const fromValue: JSAny = GetProperty(o, from); - // d. Increment k by 1. - k++; + // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(k), fromValue). + FastCreateDataProperty(a, k, fromValue); } - // 12. Perform ? Set(A, "length", actualDeleteCount, true). - SetProperty(a, kLengthString, actualDeleteCount); - return a; + + // d. Increment k by 1. + k++; } + // 12. Perform ? Set(A, "length", actualDeleteCount, true). + SetProperty(a, kLengthString, actualDeleteCount); + return a; +} - // HandleForwardCase implements step 15. "If itemCount < actualDeleteCount, - // then..."" - transitioning macro HandleForwardCase( - context: Context, o: JSReceiver, len: Number, itemCount: Number, - actualStart: Number, actualDeleteCount: Number): void { - // 15. If itemCount < actualDeleteCount, then - // a. Let k be actualStart. - let k: Number = actualStart; - - // b. Repeat, while k < (len - actualDeleteCount) - while (k < (len - actualDeleteCount)) { - // i. Let from be ! ToString(k + actualDeleteCount). - const from: Number = k + actualDeleteCount; - // ii. Let to be ! ToString(k + itemCount). - const to: Number = k + itemCount; - - // iii. Let fromPresent be ? HasProperty(O, from). - const fromPresent: Boolean = HasProperty(o, from); - - // iv. If fromPresent is true, then - if (fromPresent == True) { - // 1. Let fromValue be ? Get(O, from). - const fromValue: JSAny = GetProperty(o, from); - - // 2. Perform ? Set(O, to, fromValue, true). - SetProperty(o, to, fromValue); - - // v. Else fromPresent is false, - } else { - // 1. Perform ? DeletePropertyOrThrow(O, to). - DeleteProperty(o, to, LanguageMode::kStrict); - } - // vi. Increase k by 1. - k++; +// HandleForwardCase implements step 15. "If itemCount < actualDeleteCount, +// then..."" +transitioning macro HandleForwardCase( + context: Context, o: JSReceiver, len: Number, itemCount: Number, + actualStart: Number, actualDeleteCount: Number): void { + // 15. If itemCount < actualDeleteCount, then + // a. Let k be actualStart. + let k: Number = actualStart; + + // b. Repeat, while k < (len - actualDeleteCount) + while (k < (len - actualDeleteCount)) { + // i. Let from be ! ToString(k + actualDeleteCount). + const from: Number = k + actualDeleteCount; + // ii. Let to be ! ToString(k + itemCount). + const to: Number = k + itemCount; + + // iii. Let fromPresent be ? HasProperty(O, from). + const fromPresent: Boolean = HasProperty(o, from); + + // iv. If fromPresent is true, then + if (fromPresent == True) { + // 1. Let fromValue be ? Get(O, from). + const fromValue: JSAny = GetProperty(o, from); + + // 2. Perform ? Set(O, to, fromValue, true). + SetProperty(o, to, fromValue); + + // v. Else fromPresent is false, + } else { + // 1. Perform ? DeletePropertyOrThrow(O, to). + DeleteProperty(o, to, LanguageMode::kStrict); } + // vi. Increase k by 1. + k++; + } - // c. Let k be len. - k = len; + // c. Let k be len. + k = len; - // d. Repeat, while k > (len - actualDeleteCount + itemCount) - while (k > (len - actualDeleteCount + itemCount)) { - // i. Perform ? DeletePropertyOrThrow(O, ! ToString(k - 1)). - DeleteProperty(o, k - 1, LanguageMode::kStrict); - // ii. Decrease k by 1. - k--; - } + // d. Repeat, while k > (len - actualDeleteCount + itemCount) + while (k > (len - actualDeleteCount + itemCount)) { + // i. Perform ? DeletePropertyOrThrow(O, ! ToString(k - 1)). + DeleteProperty(o, k - 1, LanguageMode::kStrict); + // ii. Decrease k by 1. + k--; } +} - // HandleBackwardCase implements step 16. "Else if itemCount > - // actualDeleteCount, then..." - transitioning macro HandleBackwardCase( - context: Context, o: JSReceiver, len: Number, itemCount: Number, - actualStart: Number, actualDeleteCount: Number): void { - // 16. Else if itemCount > actualDeleteCount, then - // a. Let k be (len - actualDeleteCount). - let k: Number = len - actualDeleteCount; - - // b. Repeat, while k > actualStart - while (k > actualStart) { - // i. Let from be ! ToString(k + actualDeleteCount - 1). - const from: Number = k + actualDeleteCount - 1; +// HandleBackwardCase implements step 16. "Else if itemCount > +// actualDeleteCount, then..." +transitioning macro HandleBackwardCase( + context: Context, o: JSReceiver, len: Number, itemCount: Number, + actualStart: Number, actualDeleteCount: Number): void { + // 16. Else if itemCount > actualDeleteCount, then + // a. Let k be (len - actualDeleteCount). + let k: Number = len - actualDeleteCount; - // ii. Let to be ! ToString(k + itemCount - 1). - const to: Number = k + itemCount - 1; + // b. Repeat, while k > actualStart + while (k > actualStart) { + // i. Let from be ! ToString(k + actualDeleteCount - 1). + const from: Number = k + actualDeleteCount - 1; - // iii. Let fromPresent be ? HasProperty(O, from). - const fromPresent: Boolean = HasProperty(o, from); + // ii. Let to be ! ToString(k + itemCount - 1). + const to: Number = k + itemCount - 1; - // iv. If fromPresent is true, then - if (fromPresent == True) { - // 1. Let fromValue be ? Get(O, from). - const fromValue: JSAny = GetProperty(o, from); + // iii. Let fromPresent be ? HasProperty(O, from). + const fromPresent: Boolean = HasProperty(o, from); - // 2. Perform ? Set(O, to, fromValue, true). - SetProperty(o, to, fromValue); + // iv. If fromPresent is true, then + if (fromPresent == True) { + // 1. Let fromValue be ? Get(O, from). + const fromValue: JSAny = GetProperty(o, from); - // v. Else fromPresent is false, - } else { - // 1. Perform ? DeletePropertyOrThrow(O, to). - DeleteProperty(o, to, LanguageMode::kStrict); - } + // 2. Perform ? Set(O, to, fromValue, true). + SetProperty(o, to, fromValue); - // vi. Decrease k by 1. - k--; + // v. Else fromPresent is false, + } else { + // 1. Perform ? DeletePropertyOrThrow(O, to). + DeleteProperty(o, to, LanguageMode::kStrict); } + + // vi. Decrease k by 1. + k--; } +} - transitioning macro SlowSplice( - context: Context, arguments: Arguments, o: JSReceiver, len: Number, - actualStart: Number, insertCount: Smi, actualDeleteCount: Number): JSAny { - // 9. Let A be ? ArraySpeciesCreate(O, actualDeleteCount). - const a: JSReceiver = ArraySpeciesCreate(context, o, actualDeleteCount); - const itemCount: Number = insertCount; - - // Steps 9 through 12: creating the array of deleted elements. - FillDeletedElementsArray(context, o, actualStart, actualDeleteCount, a); - - // 13. Let items be a List whose elements are, in left-to-right order, - // the portion of the actual argument list starting with the third - // argument. The list is empty if fewer than three arguments were - // passed. - // 14. Let itemCount be the Number of elements in items. - // (done above). - - // 15. If itemCount < actualDeleteCount, then - if (itemCount < actualDeleteCount) { - HandleForwardCase( - context, o, len, itemCount, actualStart, actualDeleteCount); - // 16. Else if itemCount > actualDeleteCount, then - } else if (itemCount > actualDeleteCount) { - HandleBackwardCase( - context, o, len, itemCount, actualStart, actualDeleteCount); - } +transitioning macro SlowSplice( + context: Context, arguments: Arguments, o: JSReceiver, len: Number, + actualStart: Number, insertCount: Smi, actualDeleteCount: Number): JSAny { + // 9. Let A be ? ArraySpeciesCreate(O, actualDeleteCount). + const a: JSReceiver = ArraySpeciesCreate(context, o, actualDeleteCount); + const itemCount: Number = insertCount; + + // Steps 9 through 12: creating the array of deleted elements. + FillDeletedElementsArray(context, o, actualStart, actualDeleteCount, a); + + // 13. Let items be a List whose elements are, in left-to-right order, + // the portion of the actual argument list starting with the third + // argument. The list is empty if fewer than three arguments were + // passed. + // 14. Let itemCount be the Number of elements in items. + // (done above). + + // 15. If itemCount < actualDeleteCount, then + if (itemCount < actualDeleteCount) { + HandleForwardCase( + context, o, len, itemCount, actualStart, actualDeleteCount); + // 16. Else if itemCount > actualDeleteCount, then + } else if (itemCount > actualDeleteCount) { + HandleBackwardCase( + context, o, len, itemCount, actualStart, actualDeleteCount); + } - // 17. Let k be actualStart. - let k: Number = actualStart; + // 17. Let k be actualStart. + let k: Number = actualStart; - // 18. Repeat, while items is not empty - // a. Remove the first element from items and let E be the value of that - // element. - if (arguments.length > 2) { - for (let i: intptr = 2; i < arguments.length; ++i) { - const e: JSAny = arguments[i]; - // b. Perform ? Set(O, ! ToString(k), E, true). - SetProperty(o, k, e); + // 18. Repeat, while items is not empty + // a. Remove the first element from items and let E be the value of that + // element. + if (arguments.length > 2) { + for (let i: intptr = 2; i < arguments.length; ++i) { + const e: JSAny = arguments[i]; + // b. Perform ? Set(O, ! ToString(k), E, true). + SetProperty(o, k, e); - // c. Increase k by 1. - k = k + 1; - } + // c. Increase k by 1. + k = k + 1; } - - // 19. Perform ? Set(O, "length", len - actualDeleteCount + itemCount, - // true). - SetProperty(o, kLengthString, len - actualDeleteCount + itemCount); - - return a; } - // https://tc39.github.io/ecma262/#sec-array.prototype.splice - transitioning javascript builtin - ArrayPrototypeSplice(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - // 1. Let O be ? ToObject(this value). - const o: JSReceiver = ToObject(context, receiver); - - // 2. Let len be ? ToLength(? Get(O, "length")). - const len: Number = GetLengthProperty(o); - - // 3. Let relativeStart be ? ToInteger(start). - const start: JSAny = arguments[0]; - const relativeStart: Number = ToInteger_Inline(start); - - // 4. If relativeStart < 0, let actualStart be max((len + relativeStart), - // 0); - // else let actualStart be min(relativeStart, len). - const actualStart: Number = relativeStart < 0 ? - Max((len + relativeStart), 0) : - Min(relativeStart, len); - - let insertCount: Smi; - let actualDeleteCount: Number; - // 5. If the Number of actual arguments is 0, then - if (arguments.length == 0) { - // a. Let insertCount be 0. - insertCount = 0; - // b. Let actualDeleteCount be 0. - actualDeleteCount = 0; - // 6. Else if the Number of actual arguments is 1, then - } else if (arguments.length == 1) { - // a. Let insertCount be 0. - insertCount = 0; - // b. Let actualDeleteCount be len - actualStart. - actualDeleteCount = len - actualStart; - // 7. Else, - } else { - // a. Let insertCount be the Number of actual arguments minus 2. - insertCount = Convert(arguments.length) - 2; - // b. Let dc be ? ToInteger(deleteCount). - const deleteCount: JSAny = arguments[1]; - const dc: Number = ToInteger_Inline(deleteCount); - // c. Let actualDeleteCount be min(max(dc, 0), len - actualStart). - actualDeleteCount = Min(Max(dc, 0), len - actualStart); - } + // 19. Perform ? Set(O, "length", len - actualDeleteCount + itemCount, + // true). + SetProperty(o, kLengthString, len - actualDeleteCount + itemCount); - // 8. If len + insertCount - actualDeleteCount > 2^53-1, throw a - // Bailout exception. - const newLength: Number = len + insertCount - actualDeleteCount; - if (newLength > kMaxSafeInteger) { - ThrowTypeError(MessageTemplate::kInvalidArrayLength, start); - } + return a; +} - try { - return FastArraySplice( - context, arguments, o, len, actualStart, insertCount, - actualDeleteCount) otherwise Bailout; - } - label Bailout {} +// https://tc39.github.io/ecma262/#sec-array.prototype.splice +transitioning javascript builtin +ArrayPrototypeSplice( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // 1. Let O be ? ToObject(this value). + const o: JSReceiver = ToObject(context, receiver); + + // 2. Let len be ? ToLength(? Get(O, "length")). + const len: Number = GetLengthProperty(o); + + // 3. Let relativeStart be ? ToInteger(start). + const start: JSAny = arguments[0]; + const relativeStart: Number = ToInteger_Inline(start); + + // 4. If relativeStart < 0, let actualStart be max((len + relativeStart), + // 0); + // else let actualStart be min(relativeStart, len). + const actualStart: Number = relativeStart < 0 ? + Max((len + relativeStart), 0) : + Min(relativeStart, len); + + let insertCount: Smi; + let actualDeleteCount: Number; + // 5. If the Number of actual arguments is 0, then + if (arguments.length == 0) { + // a. Let insertCount be 0. + insertCount = 0; + // b. Let actualDeleteCount be 0. + actualDeleteCount = 0; + // 6. Else if the Number of actual arguments is 1, then + } else if (arguments.length == 1) { + // a. Let insertCount be 0. + insertCount = 0; + // b. Let actualDeleteCount be len - actualStart. + actualDeleteCount = len - actualStart; + // 7. Else, + } else { + // a. Let insertCount be the Number of actual arguments minus 2. + insertCount = Convert(arguments.length) - 2; + // b. Let dc be ? ToInteger(deleteCount). + const deleteCount: JSAny = arguments[1]; + const dc: Number = ToInteger_Inline(deleteCount); + // c. Let actualDeleteCount be min(max(dc, 0), len - actualStart). + actualDeleteCount = Min(Max(dc, 0), len - actualStart); + } - // If the fast case fails, just continue with the slow, correct, - // spec-compliant case. - return SlowSplice( - context, arguments, o, len, actualStart, insertCount, - actualDeleteCount); + // 8. If len + insertCount - actualDeleteCount > 2^53-1, throw a + // Bailout exception. + const newLength: Number = len + insertCount - actualDeleteCount; + if (newLength > kMaxSafeInteger) { + ThrowTypeError(MessageTemplate::kInvalidArrayLength, start); } + + try { + return FastArraySplice( + context, arguments, o, len, actualStart, insertCount, actualDeleteCount) + otherwise Bailout; + } label Bailout {} + + // If the fast case fails, just continue with the slow, correct, + // spec-compliant case. + return SlowSplice( + context, arguments, o, len, actualStart, insertCount, actualDeleteCount); +} } diff --git a/deps/v8/src/builtins/array-unshift.tq b/deps/v8/src/builtins/array-unshift.tq index 3b66015d3b32fd..7afeeb06271643 100644 --- a/deps/v8/src/builtins/array-unshift.tq +++ b/deps/v8/src/builtins/array-unshift.tq @@ -3,97 +3,95 @@ // found in the LICENSE file. namespace array { - extern builtin ArrayUnshift(Context, JSFunction, JSAny, int32): JSAny; +extern builtin ArrayUnshift(Context, JSFunction, JSAny, int32): JSAny; - transitioning macro GenericArrayUnshift( - context: Context, receiver: JSAny, arguments: Arguments): Number { - // 1. Let O be ? ToObject(this value). - const object: JSReceiver = ToObject_Inline(context, receiver); +transitioning macro GenericArrayUnshift( + context: Context, receiver: JSAny, arguments: Arguments): Number { + // 1. Let O be ? ToObject(this value). + const object: JSReceiver = ToObject_Inline(context, receiver); - // 2. Let len be ? ToLength(? Get(O, "length")). - const length: Number = GetLengthProperty(object); + // 2. Let len be ? ToLength(? Get(O, "length")). + const length: Number = GetLengthProperty(object); - // 3. Let argCount be the number of actual arguments. - const argCount: Smi = Convert(arguments.length); + // 3. Let argCount be the number of actual arguments. + const argCount: Smi = Convert(arguments.length); - // 4. If argCount > 0, then. - if (argCount > 0) { - // a. If len + argCount > 2**53 - 1, throw a TypeError exception. - if (length + argCount > kMaxSafeInteger) { - ThrowTypeError(MessageTemplate::kInvalidArrayLength); - } - - // b. Let k be len. - let k: Number = length; + // 4. If argCount > 0, then. + if (argCount > 0) { + // a. If len + argCount > 2**53 - 1, throw a TypeError exception. + if (length + argCount > kMaxSafeInteger) { + ThrowTypeError(MessageTemplate::kInvalidArrayLength); + } - // c. Repeat, while k > 0. - while (k > 0) { - // i. Let from be ! ToString(k - 1). - const from: Number = k - 1; + // b. Let k be len. + let k: Number = length; - // ii. Let to be ! ToString(k + argCount - 1). - const to: Number = k + argCount - 1; + // c. Repeat, while k > 0. + while (k > 0) { + // i. Let from be ! ToString(k - 1). + const from: Number = k - 1; - // iii. Let fromPresent be ? HasProperty(O, from). - const fromPresent: Boolean = HasProperty(object, from); + // ii. Let to be ! ToString(k + argCount - 1). + const to: Number = k + argCount - 1; - // iv. If fromPresent is true, then - if (fromPresent == True) { - // 1. Let fromValue be ? Get(O, from). - const fromValue: JSAny = GetProperty(object, from); + // iii. Let fromPresent be ? HasProperty(O, from). + const fromPresent: Boolean = HasProperty(object, from); - // 2. Perform ? Set(O, to, fromValue, true). - SetProperty(object, to, fromValue); - } else { - // 1. Perform ? DeletePropertyOrThrow(O, to). - DeleteProperty(object, to, LanguageMode::kStrict); - } + // iv. If fromPresent is true, then + if (fromPresent == True) { + // 1. Let fromValue be ? Get(O, from). + const fromValue: JSAny = GetProperty(object, from); - // vi. Decrease k by 1. - --k; + // 2. Perform ? Set(O, to, fromValue, true). + SetProperty(object, to, fromValue); + } else { + // 1. Perform ? DeletePropertyOrThrow(O, to). + DeleteProperty(object, to, LanguageMode::kStrict); } - // d. Let j be 0. - let j: Smi = 0; + // vi. Decrease k by 1. + --k; + } - // e. Let items be a List whose elements are, in left to right order, - // the arguments that were passed to this function invocation. - // f. Repeat, while items is not empty - while (j < argCount) { - // ii .Perform ? Set(O, ! ToString(j), E, true). - SetProperty(object, j, arguments[Convert(j)]); + // d. Let j be 0. + let j: Smi = 0; - // iii. Increase j by 1. - ++j; - } + // e. Let items be a List whose elements are, in left to right order, + // the arguments that were passed to this function invocation. + // f. Repeat, while items is not empty + while (j < argCount) { + // ii .Perform ? Set(O, ! ToString(j), E, true). + SetProperty(object, j, arguments[Convert(j)]); + + // iii. Increase j by 1. + ++j; } + } - // 5. Perform ? Set(O, "length", len + argCount, true). - const newLength: Number = length + argCount; - SetProperty(object, kLengthString, newLength); + // 5. Perform ? Set(O, "length", len + argCount, true). + const newLength: Number = length + argCount; + SetProperty(object, kLengthString, newLength); - // 6. Return length + argCount. - return newLength; - } + // 6. Return length + argCount. + return newLength; +} - // https://tc39.github.io/ecma262/#sec-array.prototype.unshift - transitioning javascript builtin ArrayPrototypeUnshift( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - try { - const array: FastJSArray = Cast(receiver) otherwise Slow; - array::EnsureWriteableFastElements(array); - - const map: Map = array.map; - if (!IsExtensibleMap(map)) goto Slow; - EnsureArrayLengthWritable(map) otherwise Slow; - - tail ArrayUnshift( - context, LoadTargetFromFrame(), Undefined, - Convert(arguments.length)); - } - label Slow { - return GenericArrayUnshift(context, receiver, arguments); - } +// https://tc39.github.io/ecma262/#sec-array.prototype.unshift +transitioning javascript builtin ArrayPrototypeUnshift( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + try { + const array: FastJSArray = Cast(receiver) otherwise Slow; + array::EnsureWriteableFastElements(array); + + const map: Map = array.map; + if (!IsExtensibleMap(map)) goto Slow; + EnsureArrayLengthWritable(map) otherwise Slow; + + tail ArrayUnshift( + context, LoadTargetFromFrame(), Undefined, + Convert(arguments.length)); + } label Slow { + return GenericArrayUnshift(context, receiver, arguments); } } +} diff --git a/deps/v8/src/builtins/array.tq b/deps/v8/src/builtins/array.tq index a5ffcfe40e90a9..92b2c520e28cce 100644 --- a/deps/v8/src/builtins/array.tq +++ b/deps/v8/src/builtins/array.tq @@ -5,78 +5,85 @@ #include 'src/builtins/builtins-array-gen.h' namespace array { - // Naming convention from elements.cc. We have a similar intent but implement - // fastpaths using generics instead of using a class hierarchy for elements - // kinds specific implementations. - type GenericElementsAccessor extends ElementsKind; - type FastPackedSmiElements extends ElementsKind; - type FastPackedObjectElements extends ElementsKind; - type FastPackedDoubleElements extends ElementsKind; - type FastSmiOrObjectElements extends ElementsKind; - type FastDoubleElements extends ElementsKind; - type DictionaryElements extends ElementsKind; +// Naming convention from elements.cc. We have a similar intent but implement +// fastpaths using generics instead of using a class hierarchy for elements +// kinds specific implementations. +type GenericElementsAccessor extends ElementsKind; +type FastPackedSmiElements extends ElementsKind; +type FastPackedObjectElements extends ElementsKind; +type FastPackedDoubleElements extends ElementsKind; +type FastSmiOrObjectElements extends ElementsKind; +type FastDoubleElements extends ElementsKind; +type DictionaryElements extends ElementsKind; - macro EnsureWriteableFastElements(implicit context: Context)(array: JSArray) { - assert(IsFastElementsKind(array.map.elements_kind)); +macro EnsureWriteableFastElements(implicit context: Context)(array: JSArray) { + assert(IsFastElementsKind(array.map.elements_kind)); - const elements: FixedArrayBase = array.elements; - if (elements.map != kCOWMap) return; + const elements: FixedArrayBase = array.elements; + if (elements.map != kCOWMap) return; - // There are no COW *_DOUBLE_ELEMENTS arrays, so we are allowed to always - // extract FixedArrays and don't have to worry about FixedDoubleArrays. - assert(IsFastSmiOrTaggedElementsKind(array.map.elements_kind)); + // There are no COW *_DOUBLE_ELEMENTS arrays, so we are allowed to always + // extract FixedArrays and don't have to worry about FixedDoubleArrays. + assert(IsFastSmiOrTaggedElementsKind(array.map.elements_kind)); - const length = - Convert(Cast(array.length) otherwise unreachable); - array.elements = - ExtractFixedArray(UnsafeCast(elements), 0, length, length); - assert(array.elements.map != kCOWMap); - } + const length = Convert(Cast(array.length) otherwise unreachable); + array.elements = + ExtractFixedArray(UnsafeCast(elements), 0, length, length); + assert(array.elements.map != kCOWMap); +} - macro LoadElementOrUndefined(implicit context: - Context)(a: FixedArray, i: Smi): JSAny { - const e = UnsafeCast<(JSAny | TheHole)>(a.objects[i]); - return ReplaceTheHoleWithUndefined(e); - } +macro LoadElementOrUndefined(implicit context: Context)( + a: FixedArray, i: Smi): JSAny { + const e = UnsafeCast<(JSAny | TheHole)>(a.objects[i]); + return ReplaceTheHoleWithUndefined(e); +} - macro LoadElementOrUndefined(a: FixedDoubleArray, i: Smi): NumberOrUndefined { - const f: float64 = a.floats[i].Value() otherwise return Undefined; - return AllocateHeapNumberWithValue(f); - } +macro LoadElementOrUndefined(a: FixedDoubleArray, i: Smi): NumberOrUndefined { + const f: float64 = a.floats[i].Value() otherwise return Undefined; + return AllocateHeapNumberWithValue(f); +} - macro StoreArrayHole(elements: FixedDoubleArray, k: Smi): void { - elements.floats[k] = kDoubleHole; - } +macro StoreArrayHole(elements: FixedDoubleArray, k: Smi): void { + elements.floats[k] = kDoubleHole; +} - macro StoreArrayHole(elements: FixedArray, k: Smi): void { - elements.objects[k] = TheHole; - } +macro StoreArrayHole(elements: FixedArray, k: Smi): void { + elements.objects[k] = TheHole; +} - extern macro SetPropertyLength(implicit context: Context)(JSAny, Number); +extern macro SetPropertyLength(implicit context: Context)(JSAny, Number); - const kLengthDescriptorIndex: - constexpr int31 generates 'JSArray::kLengthDescriptorIndex'; - const kAttributesReadOnlyMask: constexpr int31 - generates 'PropertyDetails::kAttributesReadOnlyMask'; +const kLengthDescriptorIndex: + constexpr int31 generates 'JSArray::kLengthDescriptorIndex'; +const kAttributesReadOnlyMask: constexpr int31 + generates 'PropertyDetails::kAttributesReadOnlyMask'; - @export - macro EnsureArrayLengthWritable(implicit context: Context)(map: Map): - void labels Bailout { - // Don't support arrays in dictionary named property mode. - if (IsDictionaryMap(map)) { - goto Bailout; - } +@export +macro EnsureArrayLengthWritable(implicit context: Context)(map: Map): + void labels Bailout { + // Don't support arrays in dictionary named property mode. + if (IsDictionaryMap(map)) { + goto Bailout; + } - // Check whether the length property is writable. The length property is the - // only default named property on arrays. It's nonconfigurable, hence is - // guaranteed to stay the first property. - const descriptors: DescriptorArray = map.instance_descriptors; - const descriptor:&DescriptorEntry = - & descriptors.descriptors[kLengthDescriptorIndex]; - assert(TaggedEqual(descriptor->key, LengthStringConstant())); - const details: Smi = UnsafeCast(descriptor->details); - if ((details & kAttributesReadOnlyMask) != 0) { - goto Bailout; - } + // Check whether the length property is writable. The length property is the + // only default named property on arrays. It's nonconfigurable, hence is + // guaranteed to stay the first property. + const descriptors: DescriptorArray = map.instance_descriptors; + const descriptor:&DescriptorEntry = + & descriptors.descriptors[kLengthDescriptorIndex]; + assert(TaggedEqual(descriptor->key, LengthStringConstant())); + const details: Smi = UnsafeCast(descriptor->details); + if ((details & kAttributesReadOnlyMask) != 0) { + goto Bailout; } } + +macro CreateJSArrayWithElements(implicit context: Context)(array: FixedArray): + JSArray { + const nativeContext: NativeContext = LoadNativeContext(context); + const map: Map = + LoadJSArrayElementsMap(ElementsKind::PACKED_ELEMENTS, nativeContext); + return AllocateJSArray(map, array, array.length); +} +} diff --git a/deps/v8/src/builtins/base.tq b/deps/v8/src/builtins/base.tq index 7d87a55e884db2..1d2c4546461cd8 100644 --- a/deps/v8/src/builtins/base.tq +++ b/deps/v8/src/builtins/base.tq @@ -52,6 +52,7 @@ extern macro MakeWeak(HeapObject): WeakHeapObject; extern macro GetHeapObjectAssumeWeak(WeakHeapObject): HeapObject labels ClearedWeakPointer; extern macro IsWeakOrCleared(MaybeObject): bool; +extern macro IsWeakReferenceToObject(MaybeObject, Object): bool; macro StrongToWeak(x: T): Weak { return %RawDownCast>(MakeWeak(x)); @@ -147,6 +148,8 @@ type ObjectHashTable extends HashTable extern class NumberDictionary extends HashTable; type RawPtr generates 'TNode' constexpr 'void*'; +type ExternalPointer + generates 'TNode' constexpr 'ExternalPointer_t'; extern class Code extends HeapObject; type BuiltinPtr extends Smi generates 'TNode'; @@ -253,10 +256,12 @@ constexpr 'CodeStubAssembler::ExtractFixedArrayFlag' { const kBigIntMaxLength: constexpr intptr generates 'BigInt::kMaxLength'; extern enum MessageTemplate { + kAllPromisesRejected, kInvalidArrayBufferLength, kInvalidArrayLength, kInvalidIndex, kNotConstructor, + kNotGeneric, kCalledNonCallable, kCalledOnNullOrUndefined, kProtoObjectOrNull, @@ -287,12 +292,11 @@ extern enum MessageTemplate { kPromiseNonCallable, kNotAPromise, kResolverNotAFunction, - kTooManyElementsInPromiseAll, + kTooManyElementsInPromiseCombinator, kToRadixFormatRange, kCalledOnNonObject, kRegExpGlobalInvokedOnNonGlobal, kProxyNonObject, - kProxyHandlerOrTargetRevoked, kProxyRevoked, kProxyTrapReturnedFalsishFor, kProxyPrivate, @@ -303,6 +307,24 @@ extern enum MessageTemplate { kProxyGetPrototypeOfNonExtensible, kProxySetPrototypeOfNonExtensible, kProxyDeletePropertyNonExtensible, + kWeakRefsCleanupMustBeCallable, + kWasmTrapUnreachable, + kWasmTrapMemOutOfBounds, + kWasmTrapUnalignedAccess, + kWasmTrapDivByZero, + kWasmTrapDivUnrepresentable, + kWasmTrapRemByZero, + kWasmTrapFloatUnrepresentable, + kWasmTrapFuncInvalid, + kWasmTrapFuncSigMismatch, + kWasmTrapDataSegmentDropped, + kWasmTrapElemSegmentDropped, + kWasmTrapTableOutOfBounds, + kWasmTrapBrOnExnNullRef, + kWasmTrapRethrowNullRef, + kWasmTrapNullDereference, + kWasmTrapIllegalCast, + kWasmTrapArrayOutOfBounds, ... } @@ -329,6 +351,8 @@ const kStringMaxLengthUintptr: constexpr uintptr generates 'String::kMaxLength'; const kFixedArrayMaxLength: constexpr int31 generates 'FixedArray::kMaxLength'; +const kFixedDoubleArrayMaxLength: + constexpr int31 generates 'FixedDoubleArray::kMaxLength'; const kObjectAlignmentMask: constexpr intptr generates 'kObjectAlignmentMask'; const kMinAddedElementsCapacity: @@ -363,19 +387,20 @@ type Boolean = True|False; type NumberOrUndefined = Number|Undefined; -extern macro TheHoleConstant(): TheHole; -extern macro NullConstant(): Null; -extern macro UndefinedConstant(): Undefined; -extern macro TrueConstant(): True; +extern macro EmptyStringConstant(): EmptyString; extern macro FalseConstant(): False; -extern macro Int32TrueConstant(): bool; extern macro Int32FalseConstant(): bool; -extern macro EmptyStringConstant(): EmptyString; -extern macro LengthStringConstant(): String; -extern macro NanConstant(): NaN; +extern macro Int32TrueConstant(): bool; extern macro IteratorSymbolConstant(): PublicSymbol; +extern macro LengthStringConstant(): String; extern macro MatchSymbolConstant(): Symbol; +extern macro MessageStringConstant(): String; +extern macro NanConstant(): NaN; +extern macro NullConstant(): Null; extern macro ReturnStringConstant(): String; +extern macro TheHoleConstant(): TheHole; +extern macro TrueConstant(): True; +extern macro UndefinedConstant(): Undefined; const TheHole: TheHole = TheHoleConstant(); const Null: Null = NullConstant(); @@ -384,6 +409,7 @@ const True: True = TrueConstant(); const False: False = FalseConstant(); const kEmptyString: EmptyString = EmptyStringConstant(); const kLengthString: String = LengthStringConstant(); +const kMessageString: String = MessageStringConstant(); const kReturnString: String = ReturnStringConstant(); const kNaN: NaN = NanConstant(); @@ -491,9 +517,9 @@ extern transitioning macro ToThisValue(implicit context: Context)( extern transitioning macro GetProperty(implicit context: Context)( JSAny, JSAny): JSAny; extern transitioning builtin SetProperty(implicit context: Context)( - JSAny, JSAny, JSAny); + JSAny, JSAny, JSAny): JSAny; extern transitioning builtin SetPropertyInLiteral(implicit context: Context)( - JSAny, JSAny, JSAny); + JSAny, JSAny, JSAny): JSAny; extern transitioning builtin DeleteProperty(implicit context: Context)( JSAny, JSAny | PrivateSymbol, LanguageModeSmi): Boolean; extern transitioning builtin HasProperty(implicit context: Context)( @@ -502,8 +528,6 @@ extern transitioning macro HasProperty_Inline(implicit context: Context)( JSReceiver, JSAny): Boolean; extern builtin LoadIC( Context, JSAny, JSAny, TaggedIndex, FeedbackVector): JSAny; -extern macro CollectCallFeedback( - JSAny, Context, Undefined | FeedbackVector, uintptr); extern macro ThrowRangeError(implicit context: Context)( constexpr MessageTemplate): never; @@ -640,6 +664,7 @@ extern macro IsFastAliasedArgumentsMap(implicit context: Context)(Map): bool; extern macro IsSlowAliasedArgumentsMap(implicit context: Context)(Map): bool; extern macro IsSloppyArgumentsMap(implicit context: Context)(Map): bool; extern macro IsStrictArgumentsMap(implicit context: Context)(Map): bool; +extern macro IsTuple2Map(Map): bool; extern macro SmiAbove(Smi, Smi): bool; @@ -701,7 +726,8 @@ macro Float64IsNaN(n: float64): bool { } // The type of all tagged values that can safely be compared with TaggedEqual. -type TaggedWithIdentity = JSReceiver|FixedArrayBase|Oddball|Map|EmptyString; +type TaggedWithIdentity = + JSReceiver|FixedArrayBase|Oddball|Map|WeakCell|Context|EmptyString; extern operator '==' macro TaggedEqual(TaggedWithIdentity, Object): bool; extern operator '==' macro TaggedEqual(Object, TaggedWithIdentity): bool; @@ -877,10 +903,14 @@ extern macro TruncateIntPtrToInt32(intptr): int32; extern macro SmiTag(intptr): Smi; extern macro SmiFromInt32(int32): Smi; extern macro SmiFromUint32(uint32): Smi; +extern macro SmiFromIntPtr(intptr): Smi; extern macro SmiUntag(Smi): intptr; macro SmiUntag(value: SmiTagged): T { return %RawDownCast(Unsigned(SmiToInt32(Convert(value)))); } +macro SmiTag(value: T): SmiTagged { + return %RawDownCast>(SmiFromUint32(value)); +} extern macro SmiToInt32(Smi): int32; extern macro TaggedIndexToIntPtr(TaggedIndex): intptr; extern macro IntPtrToTaggedIndex(intptr): TaggedIndex; @@ -889,9 +919,13 @@ extern macro SmiToTaggedIndex(Smi): TaggedIndex; extern macro RoundIntPtrToFloat64(intptr): float64; extern macro ChangeFloat32ToFloat64(float32): float64; extern macro ChangeNumberToFloat64(Number): float64; +extern macro ChangeTaggedNonSmiToInt32(implicit context: Context)(JSAnyNotSmi): + int32; +extern macro ChangeTaggedToFloat64(implicit context: Context)(JSAny): float64; extern macro ChangeFloat64ToTagged(float64): Number; extern macro ChangeFloat64ToUintPtr(float64): uintptr; extern macro ChangeFloat64ToIntPtr(float64): intptr; +extern macro ChangeInt32ToFloat64(int32): float64; extern macro ChangeInt32ToIntPtr(int32): intptr; // Sign-extends. extern macro ChangeUint32ToWord(uint32): uintptr; // Doesn't sign-extend. extern macro LoadNativeContext(Context): NativeContext; @@ -1241,8 +1275,7 @@ macro ChangeUintPtrNumberToUintPtr(value: Number): uintptr { try { return TryNumberToUintPtr(value, kModeValueIsSafeIntegerUintPtr) otherwise InvalidValue, InvalidValue, InvalidValue; - } - label InvalidValue { + } label InvalidValue { unreachable; } } @@ -1253,8 +1286,7 @@ macro ChangeSafeIntegerNumberToUintPtr(value: Number): try { return TryNumberToUintPtr(value, kModeValueIsSafeInteger) otherwise InvalidValue, IfUIntPtrOverflow, InvalidValue; - } - label InvalidValue { + } label InvalidValue { unreachable; } } @@ -1300,8 +1332,7 @@ transitioning macro GetLengthProperty(implicit context: Context)(o: JSAny): goto ToLength(GetProperty(o, kLengthString)); } } - } - label ToLength(length: JSAny) deferred { + } label ToLength(length: JSAny) deferred { return ToLength_Inline(length); } } @@ -1321,8 +1352,7 @@ transitioning macro GetMethod(implicit context: Context)( o: JSAny, name: String): Callable labels IfNullOrUndefined { try { return GetMethod(o, name) otherwise IfNullOrUndefined, IfMethodNotCallable; - } - label IfMethodNotCallable(value: JSAny) deferred { + } label IfMethodNotCallable(value: JSAny) deferred { ThrowTypeError(MessageTemplate::kPropertyNotFunction, value, name, o); } } @@ -1428,7 +1458,7 @@ macro ClampToIndexRange(indexNumber: Number, limit: uintptr): uintptr { } } -extern builtin ObjectToString(Context, JSAny): JSAny; +extern builtin ObjectToString(Context, JSAny): String; extern builtin StringRepeat(Context, String, Number): String; @export @@ -1485,8 +1515,8 @@ extern transitioning runtime CreateDataProperty(implicit context: Context)(JSReceiver, JSAny, JSAny); namespace runtime { - extern runtime - GetDerivedMap(Context, JSFunction, JSReceiver): Map; +extern runtime +GetDerivedMap(Context, JSFunction, JSReceiver): Map; } transitioning builtin FastCreateDataProperty(implicit context: Context)( @@ -1537,8 +1567,7 @@ transitioning builtin FastCreateDataProperty(implicit context: Context)( elements[index] = value; } } - } - label Slow { + } label Slow { CreateDataProperty(receiver, key, value); } return Undefined; diff --git a/deps/v8/src/builtins/bigint.tq b/deps/v8/src/builtins/bigint.tq index 02dca7543efabd..d52de7f84eab50 100644 --- a/deps/v8/src/builtins/bigint.tq +++ b/deps/v8/src/builtins/bigint.tq @@ -23,225 +23,218 @@ Convert(i: MutableBigInt): BigInt { namespace bigint { - const kPositiveSign: uint32 = 0; - const kNegativeSign: uint32 = 1; +const kPositiveSign: uint32 = 0; +const kNegativeSign: uint32 = 1; + +extern macro BigIntBuiltinsAssembler::CppAbsoluteAddAndCanonicalize( + MutableBigInt, BigIntBase, BigIntBase): void; +extern macro BigIntBuiltinsAssembler::CppAbsoluteSubAndCanonicalize( + MutableBigInt, BigIntBase, BigIntBase): void; +extern macro BigIntBuiltinsAssembler::CppAbsoluteCompare( + BigIntBase, BigIntBase): int32; + +extern macro BigIntBuiltinsAssembler::ReadBigIntSign(BigIntBase): uint32; +extern macro BigIntBuiltinsAssembler::ReadBigIntLength(BigIntBase): intptr; +extern macro BigIntBuiltinsAssembler::WriteBigIntSignAndLength( + MutableBigInt, uint32, intptr): void; + +extern macro CodeStubAssembler::AllocateBigInt(intptr): MutableBigInt; +extern macro CodeStubAssembler::StoreBigIntDigit( + MutableBigInt, intptr, uintptr): void; +extern macro CodeStubAssembler::LoadBigIntDigit(BigIntBase, intptr): uintptr; + +macro IsCanonicalized(bigint: BigIntBase): bool { + const length = ReadBigIntLength(bigint); + + if (length == 0) { + return ReadBigIntSign(bigint) == kPositiveSign; + } + + return LoadBigIntDigit(bigint, length - 1) != 0; +} + +macro InvertSign(sign: uint32): uint32 { + return sign == kPositiveSign ? kNegativeSign : kPositiveSign; +} + +macro AllocateEmptyBigIntNoThrow(implicit context: Context)( + sign: uint32, length: intptr): MutableBigInt labels BigIntTooBig { + if (length > kBigIntMaxLength) { + goto BigIntTooBig; + } + const result: MutableBigInt = AllocateBigInt(length); + + WriteBigIntSignAndLength(result, sign, length); + return result; +} + +macro AllocateEmptyBigInt(implicit context: Context)( + sign: uint32, length: intptr): MutableBigInt { + try { + return AllocateEmptyBigIntNoThrow(sign, length) otherwise BigIntTooBig; + } label BigIntTooBig { + ThrowRangeError(MessageTemplate::kBigIntTooBig); + } +} + +macro MutableBigIntAbsoluteCompare(x: BigIntBase, y: BigIntBase): int32 { + return CppAbsoluteCompare(x, y); +} + +macro MutableBigIntAbsoluteSub(implicit context: Context)( + x: BigInt, y: BigInt, resultSign: uint32): BigInt { + const xlength = ReadBigIntLength(x); + const ylength = ReadBigIntLength(y); + const xsign = ReadBigIntSign(x); + + assert(MutableBigIntAbsoluteCompare(x, y) >= 0); + if (xlength == 0) { + assert(ylength == 0); + return x; + } + + if (ylength == 0) { + return resultSign == xsign ? x : BigIntUnaryMinus(x); + } + + const result = AllocateEmptyBigInt(resultSign, xlength); + CppAbsoluteSubAndCanonicalize(result, x, y); + return Convert(result); +} + +macro MutableBigIntAbsoluteAdd(implicit context: Context)( + xBigint: BigInt, yBigint: BigInt, + resultSign: uint32): BigInt labels BigIntTooBig { + let xlength = ReadBigIntLength(xBigint); + let ylength = ReadBigIntLength(yBigint); + + let x = xBigint; + let y = yBigint; + if (xlength < ylength) { + // Swap x and y so that x is longer. + x = yBigint; + y = xBigint; + const tempLength = xlength; + xlength = ylength; + ylength = tempLength; + } + + // case: 0n + 0n + if (xlength == 0) { + assert(ylength == 0); + return x; + } + + // case: x + 0n + if (ylength == 0) { + return resultSign == ReadBigIntSign(x) ? x : BigIntUnaryMinus(x); + } - extern macro BigIntBuiltinsAssembler::CppAbsoluteAddAndCanonicalize( - MutableBigInt, BigIntBase, BigIntBase): void; - extern macro BigIntBuiltinsAssembler::CppAbsoluteSubAndCanonicalize( - MutableBigInt, BigIntBase, BigIntBase): void; - extern macro BigIntBuiltinsAssembler::CppAbsoluteCompare( - BigIntBase, BigIntBase): int32; - - extern macro BigIntBuiltinsAssembler::ReadBigIntSign(BigIntBase): uint32; - extern macro BigIntBuiltinsAssembler::ReadBigIntLength(BigIntBase): intptr; - extern macro BigIntBuiltinsAssembler::WriteBigIntSignAndLength( - MutableBigInt, uint32, intptr): void; + // case: x + y + const result = AllocateEmptyBigIntNoThrow(resultSign, xlength + 1) + otherwise BigIntTooBig; + CppAbsoluteAddAndCanonicalize(result, x, y); + return Convert(result); +} + +macro BigIntAddImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt + labels BigIntTooBig { + const xsign = ReadBigIntSign(x); + const ysign = ReadBigIntSign(y); + if (xsign == ysign) { + // x + y == x + y + // -x + -y == -(x + y) + return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig; + } + + // x + -y == x - y == -(y - x) + // -x + y == y - x == -(x - y) + if (MutableBigIntAbsoluteCompare(x, y) >= 0) { + return MutableBigIntAbsoluteSub(x, y, xsign); + } + return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign)); +} + +builtin BigIntAddNoThrow(implicit context: Context)( + x: BigInt, y: BigInt): Numeric { + try { + return BigIntAddImpl(x, y) otherwise BigIntTooBig; + } label BigIntTooBig { + // Smi sentinal is used to signal BigIntTooBig exception. + return Convert(0); + } +} + +builtin BigIntAdd(implicit context: Context)( + xNum: Numeric, yNum: Numeric): BigInt { + try { + const x = Cast(xNum) otherwise MixedTypes; + const y = Cast(yNum) otherwise MixedTypes; + + return BigIntAddImpl(x, y) otherwise BigIntTooBig; + } label MixedTypes { + ThrowTypeError(MessageTemplate::kBigIntMixedTypes); + } label BigIntTooBig { + ThrowRangeError(MessageTemplate::kBigIntTooBig); + } +} + +macro BigIntSubtractImpl(implicit context: Context)( + x: BigInt, y: BigInt): BigInt labels BigIntTooBig { + const xsign = ReadBigIntSign(x); + const ysign = ReadBigIntSign(y); + if (xsign != ysign) { + // x - (-y) == x + y + // (-x) - y == -(x + y) + return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig; + } - extern macro CodeStubAssembler::AllocateBigInt(intptr): MutableBigInt; - extern macro CodeStubAssembler::StoreBigIntDigit( - MutableBigInt, intptr, uintptr): void; - extern macro CodeStubAssembler::LoadBigIntDigit(BigIntBase, intptr): uintptr; - - macro IsCanonicalized(bigint: BigIntBase): bool { - const length = ReadBigIntLength(bigint); - - if (length == 0) { - return ReadBigIntSign(bigint) == kPositiveSign; - } - - return LoadBigIntDigit(bigint, length - 1) != 0; - } - - macro InvertSign(sign: uint32): uint32 { - return sign == kPositiveSign ? kNegativeSign : kPositiveSign; - } - - macro AllocateEmptyBigIntNoThrow(implicit context: Context)( - sign: uint32, length: intptr): MutableBigInt labels BigIntTooBig { - if (length > kBigIntMaxLength) { - goto BigIntTooBig; - } - const result: MutableBigInt = AllocateBigInt(length); - - WriteBigIntSignAndLength(result, sign, length); - return result; - } - - macro AllocateEmptyBigInt(implicit context: Context)( - sign: uint32, length: intptr): MutableBigInt { - try { - return AllocateEmptyBigIntNoThrow(sign, length) otherwise BigIntTooBig; - } - label BigIntTooBig { - ThrowRangeError(MessageTemplate::kBigIntTooBig); - } - } - - macro MutableBigIntAbsoluteCompare(x: BigIntBase, y: BigIntBase): int32 { - return CppAbsoluteCompare(x, y); - } - - macro MutableBigIntAbsoluteSub(implicit context: Context)( - x: BigInt, y: BigInt, resultSign: uint32): BigInt { - const xlength = ReadBigIntLength(x); - const ylength = ReadBigIntLength(y); - const xsign = ReadBigIntSign(x); - - assert(MutableBigIntAbsoluteCompare(x, y) >= 0); - if (xlength == 0) { - assert(ylength == 0); - return x; - } - - if (ylength == 0) { - return resultSign == xsign ? x : BigIntUnaryMinus(x); - } - - const result = AllocateEmptyBigInt(resultSign, xlength); - CppAbsoluteSubAndCanonicalize(result, x, y); - return Convert(result); - } - - macro MutableBigIntAbsoluteAdd(implicit context: Context)( - xBigint: BigInt, yBigint: BigInt, - resultSign: uint32): BigInt labels BigIntTooBig { - let xlength = ReadBigIntLength(xBigint); - let ylength = ReadBigIntLength(yBigint); - - let x = xBigint; - let y = yBigint; - if (xlength < ylength) { - // Swap x and y so that x is longer. - x = yBigint; - y = xBigint; - const tempLength = xlength; - xlength = ylength; - ylength = tempLength; - } - - // case: 0n + 0n - if (xlength == 0) { - assert(ylength == 0); - return x; - } - - // case: x + 0n - if (ylength == 0) { - return resultSign == ReadBigIntSign(x) ? x : BigIntUnaryMinus(x); - } - - // case: x + y - const result = AllocateEmptyBigIntNoThrow(resultSign, xlength + 1) - otherwise BigIntTooBig; - CppAbsoluteAddAndCanonicalize(result, x, y); - return Convert(result); - } - - macro BigIntAddImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt - labels BigIntTooBig { - const xsign = ReadBigIntSign(x); - const ysign = ReadBigIntSign(y); - if (xsign == ysign) { - // x + y == x + y - // -x + -y == -(x + y) - return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig; - } - - // x + -y == x - y == -(y - x) - // -x + y == y - x == -(x - y) - if (MutableBigIntAbsoluteCompare(x, y) >= 0) { - return MutableBigIntAbsoluteSub(x, y, xsign); - } - return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign)); - } - - builtin BigIntAddNoThrow(implicit context: Context)(x: BigInt, y: BigInt): - Numeric { - try { - return BigIntAddImpl(x, y) otherwise BigIntTooBig; - } - label BigIntTooBig { - // Smi sentinal is used to signal BigIntTooBig exception. - return Convert(0); - } - } - - builtin BigIntAdd(implicit context: Context)(xNum: Numeric, yNum: Numeric): - BigInt { - try { - const x = Cast(xNum) otherwise MixedTypes; - const y = Cast(yNum) otherwise MixedTypes; - - return BigIntAddImpl(x, y) otherwise BigIntTooBig; - } - label MixedTypes { - ThrowTypeError(MessageTemplate::kBigIntMixedTypes); - } - label BigIntTooBig { - ThrowRangeError(MessageTemplate::kBigIntTooBig); - } - } - - macro BigIntSubtractImpl(implicit context: Context)(x: BigInt, y: BigInt): - BigInt labels BigIntTooBig { - const xsign = ReadBigIntSign(x); - const ysign = ReadBigIntSign(y); - if (xsign != ysign) { - // x - (-y) == x + y - // (-x) - y == -(x + y) - return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig; - } - - // x - y == -(y - x) - // (-x) - (-y) == y - x == -(x - y) - if (MutableBigIntAbsoluteCompare(x, y) >= 0) { - return MutableBigIntAbsoluteSub(x, y, xsign); - } - return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign)); - } - - builtin BigIntSubtractNoThrow(implicit context: - Context)(x: BigInt, y: BigInt): Numeric { - try { - return BigIntSubtractImpl(x, y) otherwise BigIntTooBig; - } - label BigIntTooBig { - // Smi sentinal is used to signal BigIntTooBig exception. - return Convert(0); - } - } - - builtin BigIntSubtract(implicit context: - Context)(xNum: Numeric, yNum: Numeric): BigInt { - try { - const x = Cast(xNum) otherwise MixedTypes; - const y = Cast(yNum) otherwise MixedTypes; - - return BigIntSubtractImpl(x, y) otherwise BigIntTooBig; - } - label MixedTypes { - ThrowTypeError(MessageTemplate::kBigIntMixedTypes); - } - label BigIntTooBig { - ThrowRangeError(MessageTemplate::kBigIntTooBig); - } - } - - builtin BigIntUnaryMinus(implicit context: Context)(bigint: BigInt): BigInt { - const length = ReadBigIntLength(bigint); - - // There is no -0n. - if (length == 0) { - return bigint; - } - - const result = - AllocateEmptyBigInt(InvertSign(ReadBigIntSign(bigint)), length); - for (let i: intptr = 0; i < length; ++i) { - StoreBigIntDigit(result, i, LoadBigIntDigit(bigint, i)); - } - return Convert(result); + // x - y == -(y - x) + // (-x) - (-y) == y - x == -(x - y) + if (MutableBigIntAbsoluteCompare(x, y) >= 0) { + return MutableBigIntAbsoluteSub(x, y, xsign); } + return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign)); +} + +builtin BigIntSubtractNoThrow(implicit context: Context)( + x: BigInt, y: BigInt): Numeric { + try { + return BigIntSubtractImpl(x, y) otherwise BigIntTooBig; + } label BigIntTooBig { + // Smi sentinal is used to signal BigIntTooBig exception. + return Convert(0); + } +} + +builtin BigIntSubtract(implicit context: Context)( + xNum: Numeric, yNum: Numeric): BigInt { + try { + const x = Cast(xNum) otherwise MixedTypes; + const y = Cast(yNum) otherwise MixedTypes; + + return BigIntSubtractImpl(x, y) otherwise BigIntTooBig; + } label MixedTypes { + ThrowTypeError(MessageTemplate::kBigIntMixedTypes); + } label BigIntTooBig { + ThrowRangeError(MessageTemplate::kBigIntTooBig); + } +} + +builtin BigIntUnaryMinus(implicit context: Context)(bigint: BigInt): BigInt { + const length = ReadBigIntLength(bigint); + + // There is no -0n. + if (length == 0) { + return bigint; + } + + const result = + AllocateEmptyBigInt(InvertSign(ReadBigIntSign(bigint)), length); + for (let i: intptr = 0; i < length; ++i) { + StoreBigIntDigit(result, i, LoadBigIntDigit(bigint, i)); + } + return Convert(result); +} } // namespace bigint diff --git a/deps/v8/src/builtins/boolean.tq b/deps/v8/src/builtins/boolean.tq index c8f0d8134ac7b3..40a011d4e09e59 100644 --- a/deps/v8/src/builtins/boolean.tq +++ b/deps/v8/src/builtins/boolean.tq @@ -3,43 +3,43 @@ // found in the LICENSE file. namespace boolean { - transitioning macro ThisBooleanValue(implicit context: Context)( - receiver: JSAny, method: constexpr string): Boolean { - return UnsafeCast( - ToThisValue(receiver, PrimitiveType::kBoolean, method)); - } +transitioning macro ThisBooleanValue(implicit context: Context)( + receiver: JSAny, method: constexpr string): Boolean { + return UnsafeCast( + ToThisValue(receiver, PrimitiveType::kBoolean, method)); +} - javascript builtin - BooleanConstructor( - js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny, - target: JSFunction)(...arguments): JSAny { - const value = SelectBooleanConstant(ToBoolean(arguments[0])); +javascript builtin +BooleanConstructor( + js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny, + target: JSFunction)(...arguments): JSAny { + const value = SelectBooleanConstant(ToBoolean(arguments[0])); - if (newTarget == Undefined) { - return value; - } + if (newTarget == Undefined) { + return value; + } - const map = GetDerivedMap(target, UnsafeCast(newTarget)); + const map = GetDerivedMap(target, UnsafeCast(newTarget)); - const obj = - UnsafeCast(AllocateFastOrSlowJSObjectFromMap(map)); - obj.value = value; - return obj; - } + const obj = + UnsafeCast(AllocateFastOrSlowJSObjectFromMap(map)); + obj.value = value; + return obj; +} - // ES #sec-boolean.prototype.tostring - transitioning javascript builtin BooleanPrototypeToString( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - // 1. Let b be ? thisBooleanValue(this value). - const b = ThisBooleanValue(receiver, 'Boolean.prototype.toString'); - // 2. If b is true, return "true"; else return "false". - return b.to_string; - } +// ES #sec-boolean.prototype.tostring +transitioning javascript builtin BooleanPrototypeToString( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + // 1. Let b be ? thisBooleanValue(this value). + const b = ThisBooleanValue(receiver, 'Boolean.prototype.toString'); + // 2. If b is true, return "true"; else return "false". + return b.to_string; +} - // ES #sec-boolean.prototype.valueof - transitioning javascript builtin BooleanPrototypeValueOf( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - // 1. Return ? thisBooleanValue(this value). - return ThisBooleanValue(receiver, 'Boolean.prototype.valueOf'); - } +// ES #sec-boolean.prototype.valueof +transitioning javascript builtin BooleanPrototypeValueOf( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + // 1. Return ? thisBooleanValue(this value). + return ThisBooleanValue(receiver, 'Boolean.prototype.valueOf'); +} } diff --git a/deps/v8/src/builtins/builtins-array.cc b/deps/v8/src/builtins/builtins-array.cc index 40accae57a796a..3c2fe33c5b4b33 100644 --- a/deps/v8/src/builtins/builtins-array.cc +++ b/deps/v8/src/builtins/builtins-array.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/base/logging.h" #include "src/builtins/builtins-utils-inl.h" #include "src/builtins/builtins.h" #include "src/codegen/code-factory.h" @@ -471,6 +472,15 @@ BUILTIN(ArrayPop) { uint32_t new_length = len - 1; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, JSReceiver::GetElement(isolate, array, new_length)); + + // The length could have become read-only during the last GetElement() call, + // so check again. + if (JSArray::HasReadOnlyLength(array)) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewTypeError(MessageTemplate::kStrictReadOnlyProperty, + isolate->factory()->length_string(), + Object::TypeOf(isolate, array), array)); + } JSArray::SetLength(array, new_length); } diff --git a/deps/v8/src/builtins/builtins-async-function-gen.cc b/deps/v8/src/builtins/builtins-async-function-gen.cc index aec64b9ccd3a93..e84442295cfc90 100644 --- a/deps/v8/src/builtins/builtins-async-function-gen.cc +++ b/deps/v8/src/builtins/builtins-async-function-gen.cc @@ -271,10 +271,12 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait( Goto(&after_debug_hook); BIND(&after_debug_hook); - Await(context, async_function_object, value, outer_promise, - Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN, - Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN, - is_predicted_as_caught); + TNode on_resolve_sfi = + AsyncFunctionAwaitResolveSharedFunConstant(); + TNode on_reject_sfi = + AsyncFunctionAwaitRejectSharedFunConstant(); + Await(context, async_function_object, value, outer_promise, on_resolve_sfi, + on_reject_sfi, is_predicted_as_caught); // Return outer promise to avoid adding an load of the outer promise before // suspending in BytecodeGenerator. diff --git a/deps/v8/src/builtins/builtins-async-gen.cc b/deps/v8/src/builtins/builtins-async-gen.cc index 785408339e8ed0..383289fd0f3ea4 100644 --- a/deps/v8/src/builtins/builtins-async-gen.cc +++ b/deps/v8/src/builtins/builtins-async-gen.cc @@ -27,8 +27,8 @@ class ValueUnwrapContext { TNode AsyncBuiltinsAssembler::AwaitOld( TNode context, TNode generator, TNode value, TNode outer_promise, - TNode on_resolve_context_index, - TNode on_reject_context_index, + TNode on_resolve_sfi, + TNode on_reject_sfi, TNode is_predicted_as_caught) { const TNode native_context = LoadNativeContext(context); @@ -90,12 +90,12 @@ TNode AsyncBuiltinsAssembler::AwaitOld( // Initialize resolve handler TNode on_resolve = InnerAllocate(base, kResolveClosureOffset); InitializeNativeClosure(closure_context, native_context, on_resolve, - on_resolve_context_index); + on_resolve_sfi); // Initialize reject handler TNode on_reject = InnerAllocate(base, kRejectClosureOffset); InitializeNativeClosure(closure_context, native_context, on_reject, - on_reject_context_index); + on_reject_sfi); TVARIABLE(HeapObject, var_throwaway, UndefinedConstant()); @@ -122,8 +122,8 @@ TNode AsyncBuiltinsAssembler::AwaitOld( TNode AsyncBuiltinsAssembler::AwaitOptimized( TNode context, TNode generator, TNode promise, TNode outer_promise, - TNode on_resolve_context_index, - TNode on_reject_context_index, + TNode on_resolve_sfi, + TNode on_reject_sfi, TNode is_predicted_as_caught) { const TNode native_context = LoadNativeContext(context); @@ -161,12 +161,12 @@ TNode AsyncBuiltinsAssembler::AwaitOptimized( // Initialize resolve handler TNode on_resolve = InnerAllocate(base, kResolveClosureOffset); InitializeNativeClosure(closure_context, native_context, on_resolve, - on_resolve_context_index); + on_resolve_sfi); // Initialize reject handler TNode on_reject = InnerAllocate(base, kRejectClosureOffset); InitializeNativeClosure(closure_context, native_context, on_reject, - on_reject_context_index); + on_reject_sfi); TVARIABLE(HeapObject, var_throwaway, UndefinedConstant()); @@ -190,8 +190,8 @@ TNode AsyncBuiltinsAssembler::AwaitOptimized( TNode AsyncBuiltinsAssembler::Await( TNode context, TNode generator, TNode value, TNode outer_promise, - TNode on_resolve_context_index, - TNode on_reject_context_index, + TNode on_resolve_sfi, + TNode on_reject_sfi, TNode is_predicted_as_caught) { TVARIABLE(Object, result); Label if_old(this), if_new(this), done(this), @@ -230,15 +230,14 @@ TNode AsyncBuiltinsAssembler::Await( } BIND(&if_old); - result = AwaitOld(context, generator, value, outer_promise, - on_resolve_context_index, on_reject_context_index, - is_predicted_as_caught); + result = AwaitOld(context, generator, value, outer_promise, on_resolve_sfi, + on_reject_sfi, is_predicted_as_caught); Goto(&done); BIND(&if_new); - result = AwaitOptimized(context, generator, CAST(value), outer_promise, - on_resolve_context_index, on_reject_context_index, - is_predicted_as_caught); + result = + AwaitOptimized(context, generator, CAST(value), outer_promise, + on_resolve_sfi, on_reject_sfi, is_predicted_as_caught); Goto(&done); BIND(&done); @@ -247,7 +246,7 @@ TNode AsyncBuiltinsAssembler::Await( void AsyncBuiltinsAssembler::InitializeNativeClosure( TNode context, TNode native_context, - TNode function, TNode context_index) { + TNode function, TNode shared_info) { TNode function_map = CAST(LoadContextElement( native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)); // Ensure that we don't have to initialize prototype_or_initial_map field of @@ -265,8 +264,6 @@ void AsyncBuiltinsAssembler::InitializeNativeClosure( StoreObjectFieldRoot(function, JSFunction::kFeedbackCellOffset, RootIndex::kManyClosuresCell); - TNode shared_info = - CAST(LoadContextElement(native_context, context_index)); StoreObjectFieldNoWriteBarrier( function, JSFunction::kSharedFunctionInfoOffset, shared_info); StoreObjectFieldNoWriteBarrier(function, JSFunction::kContextOffset, context); @@ -286,8 +283,8 @@ TNode AsyncBuiltinsAssembler::CreateUnwrapClosure( TNode native_context, TNode done) { const TNode map = CAST(LoadContextElement( native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)); - const TNode on_fulfilled_shared = CAST(LoadContextElement( - native_context, Context::ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN)); + const TNode on_fulfilled_shared = + AsyncIteratorValueUnwrapSharedFunConstant(); const TNode closure_context = AllocateAsyncIteratorValueUnwrapContext(native_context, done); return AllocateFunctionWithMapAndContext(map, on_fulfilled_shared, diff --git a/deps/v8/src/builtins/builtins-async-gen.h b/deps/v8/src/builtins/builtins-async-gen.h index 7b9c944f4acaea..833e78d45d5be0 100644 --- a/deps/v8/src/builtins/builtins-async-gen.h +++ b/deps/v8/src/builtins/builtins-async-gen.h @@ -17,34 +17,23 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler { protected: // Perform steps to resume generator after `value` is resolved. - // `on_reject_context_index` is an index into the Native Context, which should - // point to a SharedFunctioninfo instance used to create the closure. The - // value following the reject index should be a similar value for the resolve - // closure. Returns the Promise-wrapped `value`. + // `on_reject` is the SharedFunctioninfo instance used to create the reject + // closure. `on_resolve` is the SharedFunctioninfo instance used to create the + // resolve closure. Returns the Promise-wrapped `value`. TNode Await(TNode context, TNode generator, TNode value, TNode outer_promise, - TNode on_resolve_context_index, - TNode on_reject_context_index, + TNode on_resolve_sfi, + TNode on_reject_sfi, TNode is_predicted_as_caught); TNode Await(TNode context, TNode generator, TNode value, TNode outer_promise, - int on_resolve_context_index, int on_reject_context_index, - TNode is_predicted_as_caught) { - return Await(context, generator, value, outer_promise, - IntPtrConstant(on_resolve_context_index), - IntPtrConstant(on_reject_context_index), - is_predicted_as_caught); - } - TNode Await(TNode context, - TNode generator, TNode value, - TNode outer_promise, - int on_resolve_context_index, int on_reject_context_index, + TNode on_resolve_sfi, + TNode on_reject_sfi, bool is_predicted_as_caught) { - return Await(context, generator, value, outer_promise, - on_resolve_context_index, on_reject_context_index, - BooleanConstant(is_predicted_as_caught)); + return Await(context, generator, value, outer_promise, on_resolve_sfi, + on_reject_sfi, BooleanConstant(is_predicted_as_caught)); } // Return a new built-in function object as defined in @@ -56,22 +45,22 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler { void InitializeNativeClosure(TNode context, TNode native_context, TNode function, - TNode context_index); + TNode shared_info); TNode AllocateAsyncIteratorValueUnwrapContext( TNode native_context, TNode done); TNode AwaitOld(TNode context, TNode generator, TNode value, TNode outer_promise, - TNode on_resolve_context_index, - TNode on_reject_context_index, + TNode on_resolve_sfi, + TNode on_reject_sfi, TNode is_predicted_as_caught); TNode AwaitOptimized(TNode context, TNode generator, TNode promise, TNode outer_promise, - TNode on_resolve_context_index, - TNode on_reject_context_index, + TNode on_resolve_sfi, + TNode on_reject_sfi, TNode is_predicted_as_caught); }; diff --git a/deps/v8/src/builtins/builtins-async-generator-gen.cc b/deps/v8/src/builtins/builtins-async-generator-gen.cc index 592400415b9f4b..2b6d72088083b8 100644 --- a/deps/v8/src/builtins/builtins-async-generator-gen.cc +++ b/deps/v8/src/builtins/builtins-async-generator-gen.cc @@ -242,12 +242,10 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwait(bool is_catchable) { TNode outer_promise = LoadObjectField( request, AsyncGeneratorRequest::kPromiseOffset); - const int resolve_index = Context::ASYNC_GENERATOR_AWAIT_RESOLVE_SHARED_FUN; - const int reject_index = Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN; - SetGeneratorAwaiting(async_generator_object); - Await(context, async_generator_object, value, outer_promise, resolve_index, - reject_index, is_catchable); + Await(context, async_generator_object, value, outer_promise, + AsyncGeneratorAwaitResolveSharedFunConstant(), + AsyncGeneratorAwaitRejectSharedFunConstant(), is_catchable); Return(UndefinedConstant()); } @@ -573,12 +571,10 @@ TF_BUILTIN(AsyncGeneratorYield, AsyncGeneratorBuiltinsAssembler) { const TNode outer_promise = LoadPromiseFromAsyncGeneratorRequest(request); - const int on_resolve = Context::ASYNC_GENERATOR_YIELD_RESOLVE_SHARED_FUN; - const int on_reject = Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN; - SetGeneratorAwaiting(generator); - Await(context, generator, value, outer_promise, on_resolve, on_reject, - is_caught); + Await(context, generator, value, outer_promise, + AsyncGeneratorYieldResolveSharedFunConstant(), + AsyncGeneratorAwaitRejectSharedFunConstant(), is_caught); Return(UndefinedConstant()); } @@ -623,19 +619,17 @@ TF_BUILTIN(AsyncGeneratorReturn, AsyncGeneratorBuiltinsAssembler) { CAST(LoadFirstAsyncGeneratorRequestFromQueue(generator)); Label perform_await(this); - TVARIABLE(IntPtrT, var_on_resolve, - IntPtrConstant( - Context::ASYNC_GENERATOR_RETURN_CLOSED_RESOLVE_SHARED_FUN)); - TVARIABLE( - IntPtrT, var_on_reject, - IntPtrConstant(Context::ASYNC_GENERATOR_RETURN_CLOSED_REJECT_SHARED_FUN)); + TVARIABLE(SharedFunctionInfo, var_on_resolve, + AsyncGeneratorReturnClosedResolveSharedFunConstant()); + + TVARIABLE(SharedFunctionInfo, var_on_reject, + AsyncGeneratorReturnClosedRejectSharedFunConstant()); const TNode state = LoadGeneratorState(generator); GotoIf(IsGeneratorStateClosed(state), &perform_await); - var_on_resolve = - IntPtrConstant(Context::ASYNC_GENERATOR_RETURN_RESOLVE_SHARED_FUN); - var_on_reject = - IntPtrConstant(Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN); + var_on_resolve = AsyncGeneratorReturnResolveSharedFunConstant(); + var_on_reject = AsyncGeneratorAwaitRejectSharedFunConstant(); + Goto(&perform_await); BIND(&perform_await); diff --git a/deps/v8/src/builtins/builtins-call-gen.cc b/deps/v8/src/builtins/builtins-call-gen.cc index 1b53e9ca8e8d07..d457e0331490f8 100644 --- a/deps/v8/src/builtins/builtins-call-gen.cc +++ b/deps/v8/src/builtins/builtins-call-gen.cc @@ -317,7 +317,9 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread( BIND(&if_generic); { Label if_iterator_fn_not_callable(this, Label::kDeferred), - if_iterator_is_null_or_undefined(this, Label::kDeferred); + if_iterator_is_null_or_undefined(this, Label::kDeferred), + throw_spread_error(this, Label::kDeferred); + TVARIABLE(Smi, message_id); GotoIf(IsNullOrUndefined(spread), &if_iterator_is_null_or_undefined); @@ -336,10 +338,18 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread( &if_smiorobject, &if_double); BIND(&if_iterator_fn_not_callable); - ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable); + message_id = SmiConstant( + static_cast(MessageTemplate::kIteratorSymbolNonCallable)), + Goto(&throw_spread_error); BIND(&if_iterator_is_null_or_undefined); - CallRuntime(Runtime::kThrowSpreadArgIsNullOrUndefined, context, spread); + message_id = SmiConstant( + static_cast(MessageTemplate::kNotIterableNoSymbolLoad)); + Goto(&throw_spread_error); + + BIND(&throw_spread_error); + CallRuntime(Runtime::kThrowSpreadArgError, context, message_id.value(), + spread); Unreachable(); } @@ -565,7 +575,7 @@ void CallOrConstructBuiltinsAssembler::CallFunctionTemplate( TNode foreign = LoadObjectField( call_handler_info, CallHandlerInfo::kJsCallbackOffset); TNode callback = - LoadObjectField(foreign, Foreign::kForeignAddressOffset); + DecodeExternalPointer(LoadForeignForeignAddress(foreign)); TNode call_data = LoadObjectField(call_handler_info, CallHandlerInfo::kDataOffset); TailCallStub(CodeFactory::CallApiCallback(isolate()), context, callback, argc, diff --git a/deps/v8/src/builtins/builtins-callsite.cc b/deps/v8/src/builtins/builtins-callsite.cc index d1082291ef1414..5b7807ed4a9e50 100644 --- a/deps/v8/src/builtins/builtins-callsite.cc +++ b/deps/v8/src/builtins/builtins-callsite.cc @@ -76,7 +76,11 @@ BUILTIN(CallSitePrototypeGetFunction) { GetFrameIndex(isolate, recv)); StackFrameBase* frame = it.Frame(); - if (frame->IsStrict()) return ReadOnlyRoots(isolate).undefined_value(); + if (frame->IsStrict() || + (frame->GetFunction()->IsJSFunction() && + JSFunction::cast(*frame->GetFunction()).shared().is_toplevel())) { + return ReadOnlyRoots(isolate).undefined_value(); + } isolate->CountUsage(v8::Isolate::kCallSiteAPIGetFunctionSloppyCall); diff --git a/deps/v8/src/builtins/builtins-collections-gen.cc b/deps/v8/src/builtins/builtins-collections-gen.cc index df0ebce993fc4f..2f0e5a756026b4 100644 --- a/deps/v8/src/builtins/builtins-collections-gen.cc +++ b/deps/v8/src/builtins/builtins-collections-gen.cc @@ -334,8 +334,9 @@ void BaseCollectionsAssembler::AddConstructorEntriesFromIterable( } BIND(&if_exception); { - iterator_assembler.IteratorCloseOnException(context, iterator, - var_exception.value()); + IteratorCloseOnException(context, iterator); + CallRuntime(Runtime::kReThrow, context, var_exception.value()); + Unreachable(); } BIND(&exit); } diff --git a/deps/v8/src/builtins/builtins-dataview.cc b/deps/v8/src/builtins/builtins-dataview.cc index 01f43c7fd9a8fa..1718ea97ad184a 100644 --- a/deps/v8/src/builtins/builtins-dataview.cc +++ b/deps/v8/src/builtins/builtins-dataview.cc @@ -102,6 +102,7 @@ BUILTIN(DataViewConstructor) { // 13. Set O's [[ByteOffset]] internal slot to offset. Handle::cast(result)->set_byte_offset(view_byte_offset); Handle::cast(result)->set_data_pointer( + isolate, static_cast(array_buffer->backing_store()) + view_byte_offset); // 14. Return O. diff --git a/deps/v8/src/builtins/builtins-date-gen.cc b/deps/v8/src/builtins/builtins-date-gen.cc index 98c1343d2c8f8e..a32003303508cf 100644 --- a/deps/v8/src/builtins/builtins-date-gen.cc +++ b/deps/v8/src/builtins/builtins-date-gen.cc @@ -50,11 +50,14 @@ void DateBuiltinsAssembler::Generate_DatePrototype_GetField( BIND(&stamp_mismatch); } + TNode isolate_ptr = + ExternalConstant(ExternalReference::isolate_address(isolate())); TNode field_index_smi = SmiConstant(field_index); TNode function = ExternalConstant(ExternalReference::get_date_field_function()); TNode result = CAST(CallCFunction( function, MachineType::AnyTagged(), + std::make_pair(MachineType::Pointer(), isolate_ptr), std::make_pair(MachineType::AnyTagged(), date_receiver), std::make_pair(MachineType::AnyTagged(), field_index_smi))); Return(result); diff --git a/deps/v8/src/builtins/builtins-definitions.h b/deps/v8/src/builtins/builtins-definitions.h index 7ed38062c810a5..84ddf55f6f47d3 100644 --- a/deps/v8/src/builtins/builtins-definitions.h +++ b/deps/v8/src/builtins/builtins-definitions.h @@ -498,11 +498,6 @@ namespace internal { CPP(ErrorConstructor) \ CPP(ErrorCaptureStackTrace) \ CPP(ErrorPrototypeToString) \ - CPP(MakeError) \ - CPP(MakeRangeError) \ - CPP(MakeSyntaxError) \ - CPP(MakeTypeError) \ - CPP(MakeURIError) \ \ /* Function */ \ CPP(FunctionConstructor) \ @@ -579,7 +574,9 @@ namespace internal { /* IterableToList */ \ /* ES #sec-iterabletolist */ \ TFS(IterableToList, kIterable, kIteratorFn) \ + TFS(IterableToFixedArray, kIterable, kIteratorFn) \ TFS(IterableToListWithSymbolLookup, kIterable) \ + TFS(IterableToFixedArrayWithSymbolLookupSlow, kIterable) \ TFS(IterableToListMayPreserveHoles, kIterable, kIteratorFn) \ TFS(IterableToFixedArrayForWasm, kIterable, kExpectedLength) \ \ @@ -678,18 +675,12 @@ namespace internal { TFJ(ObjectKeys, 1, kReceiver, kObject) \ CPP(ObjectLookupGetter) \ CPP(ObjectLookupSetter) \ - /* ES6 #sec-object.prototype.tostring */ \ - TFJ(ObjectPrototypeToString, 0, kReceiver) \ - /* ES6 #sec-object.prototype.valueof */ \ - TFJ(ObjectPrototypeValueOf, 0, kReceiver) \ /* ES6 #sec-object.prototype.hasownproperty */ \ TFJ(ObjectPrototypeHasOwnProperty, 1, kReceiver, kKey) \ TFJ(ObjectPrototypeIsPrototypeOf, 1, kReceiver, kValue) \ CPP(ObjectPrototypePropertyIsEnumerable) \ CPP(ObjectPrototypeGetProto) \ CPP(ObjectPrototypeSetProto) \ - /* ES #sec-object.prototype.tolocalestring */ \ - TFJ(ObjectPrototypeToLocaleString, 0, kReceiver) \ CPP(ObjectSeal) \ TFS(ObjectToString, kReceiver) \ TFJ(ObjectValues, 1, kReceiver, kObject) \ @@ -702,9 +693,6 @@ namespace internal { TFS(ForInEnumerate, kReceiver) \ TFS(ForInFilter, kKey, kObject) \ \ - /* Promise */ \ - CPP(IsPromise) \ - \ /* Reflect */ \ ASM(ReflectApply, JSTrampoline) \ ASM(ReflectConstruct, JSTrampoline) \ @@ -851,35 +839,17 @@ namespace internal { /* Wasm */ \ ASM(WasmCompileLazy, Dummy) \ ASM(WasmDebugBreak, Dummy) \ + TFC(WasmFloat32ToNumber, WasmFloat32ToNumber) \ + TFC(WasmFloat64ToNumber, WasmFloat64ToNumber) \ + TFS(WasmAllocateArray, kMapIndex, kLength, kElementSize) \ + TFS(WasmAllocateStruct, kMapIndex) \ TFC(WasmAtomicNotify, WasmAtomicNotify) \ TFC(WasmI32AtomicWait32, WasmI32AtomicWait32) \ TFC(WasmI32AtomicWait64, WasmI32AtomicWait64) \ TFC(WasmI64AtomicWait32, WasmI64AtomicWait32) \ TFC(WasmI64AtomicWait64, WasmI64AtomicWait64) \ - TFC(WasmMemoryGrow, WasmMemoryGrow) \ TFC(WasmTableInit, WasmTableInit) \ TFC(WasmTableCopy, WasmTableCopy) \ - TFC(WasmTableGet, WasmTableGet) \ - TFC(WasmTableSet, WasmTableSet) \ - TFC(WasmStackGuard, NoContext) \ - TFC(WasmStackOverflow, NoContext) \ - TFC(WasmThrow, WasmThrow) \ - TFC(WasmRethrow, WasmThrow) \ - TFS(WasmTraceMemory, kMemoryTracingInfo) \ - TFS(ThrowWasmTrapUnreachable) \ - TFS(ThrowWasmTrapMemOutOfBounds) \ - TFS(ThrowWasmTrapUnalignedAccess) \ - TFS(ThrowWasmTrapDivByZero) \ - TFS(ThrowWasmTrapDivUnrepresentable) \ - TFS(ThrowWasmTrapRemByZero) \ - TFS(ThrowWasmTrapFloatUnrepresentable) \ - TFS(ThrowWasmTrapFuncInvalid) \ - TFS(ThrowWasmTrapFuncSigMismatch) \ - TFS(ThrowWasmTrapDataSegmentDropped) \ - TFS(ThrowWasmTrapElemSegmentDropped) \ - TFS(ThrowWasmTrapTableOutOfBounds) \ - TFS(ThrowWasmTrapBrOnExnNullRef) \ - TFS(ThrowWasmTrapRethrowNullRef) \ \ /* WeakMap */ \ TFJ(WeakMapConstructor, kDontAdaptArgumentsSentinel) \ @@ -976,8 +946,6 @@ namespace internal { CPP(Trace) \ \ /* Weak refs */ \ - CPP(FinalizationRegistryCleanupIteratorNext) \ - CPP(FinalizationRegistryCleanupSome) \ CPP(FinalizationRegistryConstructor) \ CPP(FinalizationRegistryRegister) \ CPP(FinalizationRegistryUnregister) \ @@ -1164,6 +1132,7 @@ namespace internal { V(AsyncGeneratorAwaitCaught) \ V(AsyncGeneratorAwaitUncaught) \ V(PromiseAll) \ + V(PromiseAny) \ V(PromiseConstructor) \ V(PromiseConstructorLazyDeoptContinuation) \ V(PromiseFulfillReactionJob) \ diff --git a/deps/v8/src/builtins/builtins-error.cc b/deps/v8/src/builtins/builtins-error.cc index 3634362205c6f0..840298eacbf532 100644 --- a/deps/v8/src/builtins/builtins-error.cc +++ b/deps/v8/src/builtins/builtins-error.cc @@ -18,24 +18,9 @@ namespace internal { // ES6 section 19.5.1.1 Error ( message ) BUILTIN(ErrorConstructor) { HandleScope scope(isolate); - - FrameSkipMode mode = SKIP_FIRST; - Handle caller; - - // When we're passed a JSFunction as new target, we can skip frames until that - // specific function is seen instead of unconditionally skipping the first - // frame. - if (args.new_target()->IsJSFunction()) { - mode = SKIP_UNTIL_SEEN; - caller = args.new_target(); - } - RETURN_RESULT_OR_FAILURE( - isolate, - ErrorUtils::Construct(isolate, args.target(), - Handle::cast(args.new_target()), - args.atOrUndefined(isolate, 1), mode, caller, - ErrorUtils::StackTraceCollection::kDetailed)); + isolate, ErrorUtils::Construct(isolate, args.target(), args.new_target(), + args.atOrUndefined(isolate, 1))); } // static @@ -85,53 +70,5 @@ BUILTIN(ErrorPrototypeToString) { ErrorUtils::ToString(isolate, args.receiver())); } -namespace { - -Object MakeGenericError(Isolate* isolate, BuiltinArguments args, - Handle constructor) { - Handle template_index = args.atOrUndefined(isolate, 1); - Handle arg0 = args.atOrUndefined(isolate, 2); - Handle arg1 = args.atOrUndefined(isolate, 3); - Handle arg2 = args.atOrUndefined(isolate, 4); - - DCHECK(template_index->IsSmi()); - - return *ErrorUtils::MakeGenericError( - isolate, constructor, MessageTemplateFromInt(Smi::ToInt(*template_index)), - arg0, arg1, arg2, SKIP_NONE); -} - -} // namespace - -BUILTIN(MakeError) { - HandleScope scope(isolate); - return MakeGenericError(isolate, args, isolate->error_function()); -} - -BUILTIN(MakeRangeError) { - HandleScope scope(isolate); - return MakeGenericError(isolate, args, isolate->range_error_function()); -} - -BUILTIN(MakeSyntaxError) { - HandleScope scope(isolate); - return MakeGenericError(isolate, args, isolate->syntax_error_function()); -} - -BUILTIN(MakeTypeError) { - HandleScope scope(isolate); - return MakeGenericError(isolate, args, isolate->type_error_function()); -} - -BUILTIN(MakeURIError) { - HandleScope scope(isolate); - Handle constructor = isolate->uri_error_function(); - Handle undefined = isolate->factory()->undefined_value(); - MessageTemplate template_index = MessageTemplate::kURIMalformed; - return *ErrorUtils::MakeGenericError(isolate, constructor, template_index, - undefined, undefined, undefined, - SKIP_NONE); -} - } // namespace internal } // namespace v8 diff --git a/deps/v8/src/builtins/builtins-handler-gen.cc b/deps/v8/src/builtins/builtins-handler-gen.cc index 48a137abc620d2..0325ddab7c9745 100644 --- a/deps/v8/src/builtins/builtins-handler-gen.cc +++ b/deps/v8/src/builtins/builtins-handler-gen.cc @@ -158,31 +158,26 @@ TNode HandlerBuiltinsAssembler::EmitKeyedSloppyArguments( TNode backing_store_length = LoadAndUntagFixedArrayBaseLength(backing_store); - if (access_mode == ArgumentsAccessMode::kHas) { - Label out_of_bounds(this); - GotoIf(UintPtrGreaterThanOrEqual(key, backing_store_length), - &out_of_bounds); - TNode result = LoadFixedArrayElement(backing_store, key); - var_result = - SelectBooleanConstant(TaggedNotEqual(result, TheHoleConstant())); - Goto(&end); - - BIND(&out_of_bounds); - var_result = FalseConstant(); - Goto(&end); + + // Out-of-bounds access may involve prototype chain walk and is handled + // in runtime. + GotoIf(UintPtrGreaterThanOrEqual(key, backing_store_length), bailout); + + // The key falls into unmapped range. + if (access_mode == ArgumentsAccessMode::kStore) { + StoreFixedArrayElement(backing_store, key, *value); } else { - GotoIf(UintPtrGreaterThanOrEqual(key, backing_store_length), bailout); + TNode value = LoadFixedArrayElement(backing_store, key); + GotoIf(TaggedEqual(value, TheHoleConstant()), bailout); - // The key falls into unmapped range. - if (access_mode == ArgumentsAccessMode::kLoad) { - TNode result = LoadFixedArrayElement(backing_store, key); - GotoIf(TaggedEqual(result, TheHoleConstant()), bailout); - var_result = result; + if (access_mode == ArgumentsAccessMode::kHas) { + var_result = TrueConstant(); } else { - StoreFixedArrayElement(backing_store, key, *value); + DCHECK_EQ(access_mode, ArgumentsAccessMode::kLoad); + var_result = value; } - Goto(&end); } + Goto(&end); } BIND(&end); diff --git a/deps/v8/src/builtins/builtins-internal-gen.cc b/deps/v8/src/builtins/builtins-internal-gen.cc index 6f4f54656d6664..61f03b3f993380 100644 --- a/deps/v8/src/builtins/builtins-internal-gen.cc +++ b/deps/v8/src/builtins/builtins-internal-gen.cc @@ -7,7 +7,8 @@ #include "src/builtins/builtins.h" #include "src/codegen/code-stub-assembler.h" #include "src/codegen/macro-assembler.h" -#include "src/heap/heap-inl.h" // crbug.com/v8/8499 +#include "src/execution/frame-constants.h" +#include "src/heap/memory-chunk.h" #include "src/ic/accessor-assembler.h" #include "src/ic/keyed-store-generic.h" #include "src/logging/counters.h" diff --git a/deps/v8/src/builtins/builtins-intl.cc b/deps/v8/src/builtins/builtins-intl.cc index 3b624af91b1989..7c8cde70dd89bd 100644 --- a/deps/v8/src/builtins/builtins-intl.cc +++ b/deps/v8/src/builtins/builtins-intl.cc @@ -604,23 +604,35 @@ BUILTIN(ListFormatSupportedLocalesOf) { JSListFormat::GetAvailableLocales(), locales, options)); } -namespace { +// Intl.Locale implementation +BUILTIN(LocaleConstructor) { + HandleScope scope(isolate); + + isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocale); + + if (args.new_target()->IsUndefined(isolate)) { // [[Call]] + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, + isolate->factory()->NewStringFromAsciiChecked( + "Intl.Locale"))); + } + // [[Construct]] + Handle target = args.target(); + Handle new_target = Handle::cast(args.new_target()); + + Handle tag = args.atOrUndefined(isolate, 1); + Handle options = args.atOrUndefined(isolate, 2); -MaybeHandle CreateLocale(Isolate* isolate, - Handle constructor, - Handle new_target, - Handle tag, Handle options) { Handle map; // 6. Let locale be ? OrdinaryCreateFromConstructor(NewTarget, // %LocalePrototype%, internalSlotsList). - ASSIGN_RETURN_ON_EXCEPTION( - isolate, map, JSFunction::GetDerivedMap(isolate, constructor, new_target), - JSLocale); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target)); // 7. If Type(tag) is not String or Object, throw a TypeError exception. if (!tag->IsString() && !tag->IsJSReceiver()) { - THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kLocaleNotEmpty), - JSLocale); + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewTypeError(MessageTemplate::kLocaleNotEmpty)); } Handle locale_string; @@ -631,8 +643,8 @@ MaybeHandle CreateLocale(Isolate* isolate, locale_string = JSLocale::ToString(isolate, Handle::cast(tag)); } else { // 9. Else, // a. Let tag be ? ToString(tag). - ASSIGN_RETURN_ON_EXCEPTION(isolate, locale_string, - Object::ToString(isolate, tag), JSLocale); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, locale_string, + Object::ToString(isolate, tag)); } Handle options_object; @@ -642,60 +654,24 @@ MaybeHandle CreateLocale(Isolate* isolate, options_object = isolate->factory()->NewJSObjectWithNullProto(); } else { // 11. Else // a. Let options be ? ToObject(options). - ASSIGN_RETURN_ON_EXCEPTION(isolate, options_object, - Object::ToObject(isolate, options), JSLocale); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, options_object, + Object::ToObject(isolate, options)); } - return JSLocale::New(isolate, map, locale_string, options_object); -} - -} // namespace - -// Intl.Locale implementation -BUILTIN(LocaleConstructor) { - HandleScope scope(isolate); - - isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocale); - - if (args.new_target()->IsUndefined(isolate)) { // [[Call]] - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, - isolate->factory()->NewStringFromAsciiChecked( - "Intl.Locale"))); - } - // [[Construct]] - Handle target = args.target(); - Handle new_target = Handle::cast(args.new_target()); - - Handle tag = args.atOrUndefined(isolate, 1); - Handle options = args.atOrUndefined(isolate, 2); - RETURN_RESULT_OR_FAILURE( - isolate, CreateLocale(isolate, target, new_target, tag, options)); + isolate, JSLocale::New(isolate, map, locale_string, options_object)); } BUILTIN(LocalePrototypeMaximize) { HandleScope scope(isolate); CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.maximize"); - Handle constructor( - isolate->native_context()->intl_locale_function(), isolate); - Handle locale_str = JSLocale::ToString(isolate, locale); - RETURN_RESULT_OR_FAILURE( - isolate, CreateLocale(isolate, constructor, constructor, - JSLocale::Maximize(isolate, *locale_str), - isolate->factory()->NewJSObjectWithNullProto())); + RETURN_RESULT_OR_FAILURE(isolate, JSLocale::Maximize(isolate, locale)); } BUILTIN(LocalePrototypeMinimize) { HandleScope scope(isolate); CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.minimize"); - Handle constructor( - isolate->native_context()->intl_locale_function(), isolate); - Handle locale_str = JSLocale::ToString(isolate, locale); - RETURN_RESULT_OR_FAILURE( - isolate, CreateLocale(isolate, constructor, constructor, - JSLocale::Minimize(isolate, *locale_str), - isolate->factory()->NewJSObjectWithNullProto())); + RETURN_RESULT_OR_FAILURE(isolate, JSLocale::Minimize(isolate, locale)); } BUILTIN(RelativeTimeFormatSupportedLocalesOf) { diff --git a/deps/v8/src/builtins/builtins-iterator-gen.cc b/deps/v8/src/builtins/builtins-iterator-gen.cc index 94a79d2a32c29d..9f3ec5c32346f9 100644 --- a/deps/v8/src/builtins/builtins-iterator-gen.cc +++ b/deps/v8/src/builtins/builtins-iterator-gen.cc @@ -133,59 +133,34 @@ TNode IteratorBuiltinsAssembler::IteratorValue( return var_value.value(); } -void IteratorBuiltinsAssembler::IteratorCloseOnException( - TNode context, const IteratorRecord& iterator, Label* if_exception, - TVariable* exception) { - // Perform ES #sec-iteratorclose when an exception occurs. This simpler - // algorithm does not include redundant steps which are never reachable from - // the spec IteratorClose algorithm. - DCHECK((if_exception != nullptr && exception != nullptr)); - CSA_ASSERT(this, IsNotTheHole(exception->value())); - CSA_ASSERT(this, IsJSReceiver(iterator.object)); - - // Let return be ? GetMethod(iterator, "return"). - TNode method; - { - compiler::ScopedExceptionHandler handler(this, if_exception, exception); - method = GetProperty(context, iterator.object, factory()->return_string()); - } - - // If return is undefined, return Completion(completion). - GotoIf(Word32Or(IsUndefined(method), IsNull(method)), if_exception); - - { - // Let innerResult be Call(return, iterator, « »). - // If an exception occurs, the original exception remains bound. - compiler::ScopedExceptionHandler handler(this, if_exception, nullptr); - Call(context, method, iterator.object); - } - - // (If completion.[[Type]] is throw) return Completion(completion). - Goto(if_exception); +TNode IteratorBuiltinsAssembler::IterableToList( + TNode context, TNode iterable, TNode iterator_fn) { + GrowableFixedArray values(state()); + FillFixedArrayFromIterable(context, iterable, iterator_fn, &values); + return values.ToJSArray(context); } -void IteratorBuiltinsAssembler::IteratorCloseOnException( - TNode context, const IteratorRecord& iterator, - TNode exception) { - Label rethrow(this, Label::kDeferred); - TVARIABLE(Object, exception_variable, exception); - IteratorCloseOnException(context, iterator, &rethrow, &exception_variable); - - BIND(&rethrow); - CallRuntime(Runtime::kReThrow, context, exception_variable.value()); - Unreachable(); +TNode IteratorBuiltinsAssembler::IterableToFixedArray( + TNode context, TNode iterable, TNode iterator_fn) { + GrowableFixedArray values(state()); + FillFixedArrayFromIterable(context, iterable, iterator_fn, &values); + TNode new_array = values.ToFixedArray(); + return new_array; } -TNode IteratorBuiltinsAssembler::IterableToList( - TNode context, TNode iterable, TNode iterator_fn) { +void IteratorBuiltinsAssembler::FillFixedArrayFromIterable( + TNode context, TNode iterable, TNode iterator_fn, + GrowableFixedArray* values) { // 1. Let iteratorRecord be ? GetIterator(items, method). IteratorRecord iterator_record = GetIterator(context, iterable, iterator_fn); // 2. Let values be a new empty List. - GrowableFixedArray values(state()); - Label loop_start( - this, {values.var_array(), values.var_length(), values.var_capacity()}), + // The GrowableFixedArray has already been created. It's ok if we do this step + // out of order, since creating an empty List is not observable. + + Label loop_start(this, {values->var_array(), values->var_length(), + values->var_capacity()}), done(this); Goto(&loop_start); // 3. Let next be true. @@ -198,12 +173,11 @@ TNode IteratorBuiltinsAssembler::IterableToList( // i. Let nextValue be ? IteratorValue(next). TNode next_value = IteratorValue(context, next); // ii. Append nextValue to the end of the List values. - values.Push(next_value); + values->Push(next_value); Goto(&loop_start); } BIND(&done); - return values.ToJSArray(context); } TF_BUILTIN(IterableToList, IteratorBuiltinsAssembler) { @@ -214,31 +188,26 @@ TF_BUILTIN(IterableToList, IteratorBuiltinsAssembler) { Return(IterableToList(context, iterable, iterator_fn)); } +TF_BUILTIN(IterableToFixedArray, IteratorBuiltinsAssembler) { + TNode context = CAST(Parameter(Descriptor::kContext)); + TNode iterable = CAST(Parameter(Descriptor::kIterable)); + TNode iterator_fn = CAST(Parameter(Descriptor::kIteratorFn)); + + Return(IterableToFixedArray(context, iterable, iterator_fn)); +} + TF_BUILTIN(IterableToFixedArrayForWasm, IteratorBuiltinsAssembler) { TNode context = CAST(Parameter(Descriptor::kContext)); TNode iterable = CAST(Parameter(Descriptor::kIterable)); TNode expected_length = CAST(Parameter(Descriptor::kExpectedLength)); TNode iterator_fn = GetIteratorMethod(context, iterable); - - IteratorRecord iterator_record = GetIterator(context, iterable, iterator_fn); - GrowableFixedArray values(state()); - Label loop_start( - this, {values.var_array(), values.var_length(), values.var_capacity()}), - compare_length(this), done(this); - Goto(&loop_start); - BIND(&loop_start); - { - TNode next = - IteratorStep(context, iterator_record, &compare_length); - TNode next_value = IteratorValue(context, next); - values.Push(next_value); - Goto(&loop_start); - } + Label done(this); + + FillFixedArrayFromIterable(context, iterable, iterator_fn, &values); - BIND(&compare_length); GotoIf(WordEqual(SmiUntag(expected_length), values.var_length()->value()), &done); Return(CallRuntime( @@ -299,7 +268,9 @@ TNode IteratorBuiltinsAssembler::StringListFromIterable( // 2. Return ? IteratorClose(iteratorRecord, error). BIND(&if_exception); - IteratorCloseOnException(context, iterator_record, var_exception.value()); + IteratorCloseOnException(context, iterator_record); + CallRuntime(Runtime::kReThrow, context, var_exception.value()); + Unreachable(); } } @@ -452,5 +423,17 @@ TF_BUILTIN(GetIteratorWithFeedbackLazyDeoptContinuation, Return(result); } +// This builtin creates a FixedArray based on an Iterable and doesn't have a +// fast path for anything. +TF_BUILTIN(IterableToFixedArrayWithSymbolLookupSlow, + IteratorBuiltinsAssembler) { + TNode context = CAST(Parameter(Descriptor::kContext)); + TNode iterable = CAST(Parameter(Descriptor::kIterable)); + + TNode iterator_fn = GetIteratorMethod(context, iterable); + TailCallBuiltin(Builtins::kIterableToFixedArray, context, iterable, + iterator_fn); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/builtins/builtins-iterator-gen.h b/deps/v8/src/builtins/builtins-iterator-gen.h index 4d496fa3841bbf..6cea2c77ff4b37 100644 --- a/deps/v8/src/builtins/builtins-iterator-gen.h +++ b/deps/v8/src/builtins/builtins-iterator-gen.h @@ -12,6 +12,8 @@ namespace internal { using compiler::Node; +class GrowableFixedArray; + class IteratorBuiltinsAssembler : public CodeStubAssembler { public: explicit IteratorBuiltinsAssembler(compiler::CodeAssemblerState* state) @@ -50,21 +52,21 @@ class IteratorBuiltinsAssembler : public CodeStubAssembler { TNode context, TNode result, base::Optional> fast_iterator_result_map = base::nullopt); - // https://tc39.github.io/ecma262/#sec-iteratorclose - void IteratorCloseOnException(TNode context, - const IteratorRecord& iterator, - Label* if_exception, - TVariable* exception); - void IteratorCloseOnException(TNode context, - const IteratorRecord& iterator, - TNode exception); - // #sec-iterabletolist // Build a JSArray by iterating over {iterable} using {iterator_fn}, // following the ECMAscript operation with the same name. TNode IterableToList(TNode context, TNode iterable, TNode iterator_fn); + TNode IterableToFixedArray(TNode context, + TNode iterable, + TNode iterator_fn); + + void FillFixedArrayFromIterable(TNode context, + TNode iterable, + TNode iterator_fn, + GrowableFixedArray* values); + // Currently at https://tc39.github.io/proposal-intl-list-format/ // #sec-createstringlistfromiterable TNode StringListFromIterable(TNode context, diff --git a/deps/v8/src/builtins/builtins-microtask-queue-gen.cc b/deps/v8/src/builtins/builtins-microtask-queue-gen.cc index e6787b2da8c34b..e613ae9c08c2f4 100644 --- a/deps/v8/src/builtins/builtins-microtask-queue-gen.cc +++ b/deps/v8/src/builtins/builtins-microtask-queue-gen.cc @@ -53,8 +53,8 @@ class MicrotaskQueueBuiltinsAssembler : public CodeStubAssembler { TNode MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueue( TNode native_context) { CSA_ASSERT(this, IsNativeContext(native_context)); - return LoadObjectField(native_context, - NativeContext::kMicrotaskQueueOffset); + return DecodeExternalPointer(LoadObjectField( + native_context, NativeContext::kMicrotaskQueueOffset)); } TNode MicrotaskQueueBuiltinsAssembler::GetMicrotaskRingBuffer( @@ -198,18 +198,11 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask( const TNode thenable = LoadObjectField( microtask, PromiseResolveThenableJobTask::kThenableOffset); - RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context, - CAST(promise_to_resolve)); - { ScopedExceptionHandler handler(this, &if_exception, &var_exception); CallBuiltin(Builtins::kPromiseResolveThenableJob, native_context, promise_to_resolve, thenable, then); } - - RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context, - CAST(promise_to_resolve)); - RewindEnteredContext(saved_entered_context_count); SetCurrentContext(current_context); Goto(&done); diff --git a/deps/v8/src/builtins/builtins-object-gen.cc b/deps/v8/src/builtins/builtins-object-gen.cc index 9af4affa681585..060454955817bb 100644 --- a/deps/v8/src/builtins/builtins-object-gen.cc +++ b/deps/v8/src/builtins/builtins-object-gen.cc @@ -350,22 +350,6 @@ ObjectEntriesValuesBuiltinsAssembler::FinalizeValuesOrEntriesJSArray( return TNode::UncheckedCast(array); } -TF_BUILTIN(ObjectPrototypeToLocaleString, CodeStubAssembler) { - TNode context = CAST(Parameter(Descriptor::kContext)); - TNode receiver = CAST(Parameter(Descriptor::kReceiver)); - - Label if_null_or_undefined(this, Label::kDeferred); - GotoIf(IsNullOrUndefined(receiver), &if_null_or_undefined); - - TNode method = - GetProperty(context, receiver, factory()->toString_string()); - Return(Call(context, method, receiver)); - - BIND(&if_null_or_undefined); - ThrowTypeError(context, MessageTemplate::kCalledOnNullOrUndefined, - "Object.prototype.toLocaleString"); -} - TF_BUILTIN(ObjectPrototypeHasOwnProperty, ObjectBuiltinsAssembler) { TNode object = CAST(Parameter(Descriptor::kReceiver)); TNode key = CAST(Parameter(Descriptor::kKey)); @@ -724,20 +708,13 @@ TF_BUILTIN(ObjectPrototypeIsPrototypeOf, ObjectBuiltinsAssembler) { Return(FalseConstant()); } -// ES #sec-object.prototype.tostring -TF_BUILTIN(ObjectPrototypeToString, CodeStubAssembler) { - TNode receiver = CAST(Parameter(Descriptor::kReceiver)); - TNode context = CAST(Parameter(Descriptor::kContext)); - Return(CallBuiltin(Builtins::kObjectToString, context, receiver)); -} - TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) { - Label checkstringtag(this), if_apiobject(this, Label::kDeferred), - if_arguments(this), if_array(this), if_boolean(this), if_date(this), - if_error(this), if_function(this), if_number(this, Label::kDeferred), - if_object(this), if_primitive(this), if_proxy(this, Label::kDeferred), - if_regexp(this), if_string(this), if_symbol(this, Label::kDeferred), - if_value(this), if_bigint(this, Label::kDeferred); + Label checkstringtag(this), if_arguments(this), if_array(this), + if_boolean(this), if_date(this), if_error(this), if_function(this), + if_number(this, Label::kDeferred), if_object(this), if_primitive(this), + if_proxy(this, Label::kDeferred), if_regexp(this), if_string(this), + if_symbol(this, Label::kDeferred), if_value(this), + if_bigint(this, Label::kDeferred); TNode receiver = CAST(Parameter(Descriptor::kReceiver)); TNode context = CAST(Parameter(Descriptor::kContext)); @@ -763,8 +740,8 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) { {JS_ARGUMENTS_OBJECT_TYPE, &if_arguments}, {JS_DATE_TYPE, &if_date}, {JS_BOUND_FUNCTION_TYPE, &if_function}, - {JS_API_OBJECT_TYPE, &if_apiobject}, - {JS_SPECIAL_API_OBJECT_TYPE, &if_apiobject}, + {JS_API_OBJECT_TYPE, &if_object}, + {JS_SPECIAL_API_OBJECT_TYPE, &if_object}, {JS_PROXY_TYPE, &if_proxy}, {JS_ERROR_TYPE, &if_error}, {JS_PRIMITIVE_WRAPPER_TYPE, &if_value}}; @@ -778,25 +755,6 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) { Switch(receiver_instance_type, &if_object, case_values, case_labels, arraysize(case_values)); - BIND(&if_apiobject); - { - // Lookup the @@toStringTag property on the {receiver}. - TVARIABLE(Object, var_tag, - GetProperty(context, receiver, - isolate()->factory()->to_string_tag_symbol())); - Label if_tagisnotstring(this), if_tagisstring(this); - GotoIf(TaggedIsSmi(var_tag.value()), &if_tagisnotstring); - Branch(IsString(CAST(var_tag.value())), &if_tagisstring, - &if_tagisnotstring); - BIND(&if_tagisnotstring); - { - var_tag = CallRuntime(Runtime::kClassOf, context, receiver); - Goto(&if_tagisstring); - } - BIND(&if_tagisstring); - ReturnToStringFormat(context, CAST(var_tag.value())); - } - BIND(&if_arguments); { var_default = ArgumentsToStringConstant(); @@ -1053,14 +1011,6 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) { } } -// ES6 #sec-object.prototype.valueof -TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) { - TNode receiver = CAST(Parameter(Descriptor::kReceiver)); - TNode context = CAST(Parameter(Descriptor::kContext)); - - Return(ToObject_Inline(context, receiver)); -} - // ES #sec-object.create TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) { int const kPrototypeArg = 0; diff --git a/deps/v8/src/builtins/builtins-promise.cc b/deps/v8/src/builtins/builtins-promise.cc deleted file mode 100644 index 5eca1eb9c09896..00000000000000 --- a/deps/v8/src/builtins/builtins-promise.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2017 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "src/builtins/builtins-promise.h" - -#include "src/builtins/builtins-utils-inl.h" -#include "src/builtins/builtins.h" -#include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop. -#include "src/logging/counters.h" -#include "src/objects/objects-inl.h" - -namespace v8 { -namespace internal { - -BUILTIN(IsPromise) { - SealHandleScope scope(isolate); - - Handle object = args.atOrUndefined(isolate, 1); - return isolate->heap()->ToBoolean(object->IsJSPromise()); -} - -} // namespace internal -} // namespace v8 diff --git a/deps/v8/src/builtins/builtins-promise.h b/deps/v8/src/builtins/builtins-promise.h index a97ab7ad1dc466..fd938ff8418d94 100644 --- a/deps/v8/src/builtins/builtins-promise.h +++ b/deps/v8/src/builtins/builtins-promise.h @@ -40,6 +40,18 @@ class PromiseBuiltins { kPromiseAllResolveElementLength }; + enum PromiseAnyRejectElementContextSlots { + // Remaining elements count + kPromiseAnyRejectElementRemainingSlot = Context::MIN_CONTEXT_SLOTS, + + // Promise capability from Promise.any + kPromiseAnyRejectElementCapabilitySlot, + + // errors array from Promise.any + kPromiseAnyRejectElementErrorsArraySlot, + kPromiseAnyRejectElementLength + }; + enum FunctionContextSlot { kCapabilitySlot = Context::MIN_CONTEXT_SLOTS, diff --git a/deps/v8/src/builtins/builtins-proxy-gen.cc b/deps/v8/src/builtins/builtins-proxy-gen.cc index caafcf6506f646..f398a6c28254d0 100644 --- a/deps/v8/src/builtins/builtins-proxy-gen.cc +++ b/deps/v8/src/builtins/builtins-proxy-gen.cc @@ -76,8 +76,7 @@ TNode ProxiesCodeStubAssembler::AllocateProxyRevokeFunction( CreateProxyRevokeFunctionContext(proxy, native_context); const TNode revoke_map = CAST(LoadContextElement( native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)); - const TNode revoke_info = CAST( - LoadContextElement(native_context, Context::PROXY_REVOKE_SHARED_FUN)); + const TNode revoke_info = ProxyRevokeSharedFunConstant(); return AllocateFunctionWithMapAndContext(revoke_map, revoke_info, proxy_context); diff --git a/deps/v8/src/builtins/builtins-regexp-gen.cc b/deps/v8/src/builtins/builtins-regexp-gen.cc index d06ced76d2e9e2..b9c1b8980ea8db 100644 --- a/deps/v8/src/builtins/builtins-regexp-gen.cc +++ b/deps/v8/src/builtins/builtins-regexp-gen.cc @@ -528,7 +528,7 @@ TNode RegExpBuiltinsAssembler::RegExpExecInternal( data, JSRegExp::kIrregexpCaptureCountIndex)); // capture_count is the number of captures without the match itself. // Required registers = (capture_count + 1) * 2. - STATIC_ASSERT(Internals::IsValidSmi((JSRegExp::kMaxCaptures + 1) << 1)); + STATIC_ASSERT(Internals::IsValidSmi((JSRegExp::kMaxCaptures + 1) * 2)); TNode register_count = SmiShl(SmiAdd(capture_count, SmiConstant(1)), 1); @@ -729,13 +729,9 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp( // This should only be needed for String.p.(split||matchAll), but we are // conservative here. - // Note: we are using the current native context here, which may or may not - // match the object's native context. That's fine: in case of a mismatch, we - // will bail in the next step when comparing the object's map against the - // current native context's initial regexp map. - TNode native_context = LoadNativeContext(context); - GotoIf(IsRegExpSpeciesProtectorCellInvalid(native_context), if_ismodified); + GotoIf(IsRegExpSpeciesProtectorCellInvalid(), if_ismodified); + TNode native_context = LoadNativeContext(context); TNode regexp_fun = CAST(LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX)); TNode initial_map = CAST( @@ -1336,10 +1332,10 @@ TNode RegExpMatchAllAssembler::CreateRegExpStringIterator( // 9. Set iterator.[[Done]] to false. TNode global_flag = Word32Shl(ReinterpretCast(global), - Int32Constant(JSRegExpStringIterator::kGlobalBit)); + Int32Constant(JSRegExpStringIterator::GlobalBit::kShift)); TNode unicode_flag = Word32Shl(ReinterpretCast(full_unicode), - Int32Constant(JSRegExpStringIterator::kUnicodeBit)); + Int32Constant(JSRegExpStringIterator::UnicodeBit::kShift)); TNode iterator_flags = Word32Or(global_flag, unicode_flag); StoreObjectFieldNoWriteBarrier(iterator, JSRegExpStringIterator::kFlagsOffset, SmiFromInt32(iterator_flags)); diff --git a/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc b/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc index 3049b01d2f5b4c..010bf965cc6a6e 100644 --- a/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc +++ b/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc @@ -89,7 +89,7 @@ void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray( BIND(¬_float_or_clamped); *out_elements_kind = elements_kind; - TNode backing_store = LoadJSArrayBufferBackingStore(array_buffer); + TNode backing_store = LoadJSArrayBufferBackingStorePtr(array_buffer); TNode byte_offset = LoadJSArrayBufferViewByteOffset(array); *out_backing_store = RawPtrAdd(backing_store, Signed(byte_offset)); } diff --git a/deps/v8/src/builtins/builtins-string-gen.cc b/deps/v8/src/builtins/builtins-string-gen.cc index e2d1635274913c..7ccb99792eda55 100644 --- a/deps/v8/src/builtins/builtins-string-gen.cc +++ b/deps/v8/src/builtins/builtins-string-gen.cc @@ -20,10 +20,10 @@ namespace internal { using Node = compiler::Node; -TNode StringBuiltinsAssembler::DirectStringData( +TNode StringBuiltinsAssembler::DirectStringData( TNode string, TNode string_instance_type) { // Compute the effective offset of the first character. - TVARIABLE(IntPtrT, var_data); + TVARIABLE(RawPtrT, var_data); Label if_sequential(this), if_external(this), if_join(this); Branch(Word32Equal(Word32And(string_instance_type, Int32Constant(kStringRepresentationMask)), @@ -32,9 +32,9 @@ TNode StringBuiltinsAssembler::DirectStringData( BIND(&if_sequential); { - var_data = IntPtrAdd( - IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag), - BitcastTaggedToWord(string)); + var_data = RawPtrAdd( + ReinterpretCast(BitcastTaggedToWord(string)), + IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); Goto(&if_join); } @@ -47,7 +47,7 @@ TNode StringBuiltinsAssembler::DirectStringData( Int32Constant(kUncachedExternalStringMask)), Int32Constant(kUncachedExternalStringTag))); var_data = - LoadObjectField(string, ExternalString::kResourceDataOffset); + DecodeExternalPointer(LoadExternalStringResourceData(CAST(string))); Goto(&if_join); } @@ -254,8 +254,8 @@ void StringBuiltinsAssembler::StringEqual_Loop( CSA_ASSERT(this, WordEqual(LoadStringLengthAsWord(rhs), length)); // Compute the effective offset of the first character. - TNode lhs_data = DirectStringData(lhs, lhs_instance_type); - TNode rhs_data = DirectStringData(rhs, rhs_instance_type); + TNode lhs_data = DirectStringData(lhs, lhs_instance_type); + TNode rhs_data = DirectStringData(rhs, rhs_instance_type); // Loop over the {lhs} and {rhs} strings to see if they are equal. TVARIABLE(IntPtrT, var_offset, IntPtrConstant(0)); @@ -1635,6 +1635,12 @@ TNode StringBuiltinsAssembler::StringToArray( ToDirectStringAssembler to_direct(state(), subject_string); to_direct.TryToDirect(&call_runtime); + + // The extracted direct string may be two-byte even though the wrapping + // string is one-byte. + GotoIfNot(IsOneByteStringInstanceType(to_direct.instance_type()), + &call_runtime); + TNode elements = CAST(AllocateFixedArray( PACKED_ELEMENTS, length, AllocationFlag::kAllowLargeObjectAllocation)); // Don't allocate anything while {string_data} is live! diff --git a/deps/v8/src/builtins/builtins-string-gen.h b/deps/v8/src/builtins/builtins-string-gen.h index 93b2086dd7f61c..2b4dadbbb03773 100644 --- a/deps/v8/src/builtins/builtins-string-gen.h +++ b/deps/v8/src/builtins/builtins-string-gen.h @@ -67,7 +67,7 @@ class StringBuiltinsAssembler : public CodeStubAssembler { TNode rhs_instance_type, MachineType rhs_type, TNode length, Label* if_equal, Label* if_not_equal); - TNode DirectStringData(TNode string, + TNode DirectStringData(TNode string, TNode string_instance_type); void DispatchOnStringEncodings(const TNode lhs_instance_type, diff --git a/deps/v8/src/builtins/builtins-string.tq b/deps/v8/src/builtins/builtins-string.tq index 61cd984e7f4a13..a4edc94418cb1a 100644 --- a/deps/v8/src/builtins/builtins-string.tq +++ b/deps/v8/src/builtins/builtins-string.tq @@ -5,222 +5,215 @@ #include 'src/builtins/builtins-string-gen.h' namespace string { - extern macro StringBuiltinsAssembler::SubString(String, uintptr, uintptr): - String; - - // ES6 #sec-string.prototype.tostring - transitioning javascript builtin - StringPrototypeToString( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - return ToThisValue( - receiver, PrimitiveType::kString, 'String.prototype.toString'); - } - - // ES6 #sec-string.prototype.valueof - transitioning javascript builtin - StringPrototypeValueOf(js-implicit context: NativeContext, receiver: JSAny)(): - JSAny { - return ToThisValue( - receiver, PrimitiveType::kString, 'String.prototype.valueOf'); - } +extern macro StringBuiltinsAssembler::SubString( + String, uintptr, uintptr): String; + +// ES6 #sec-string.prototype.tostring +transitioning javascript builtin +StringPrototypeToString( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + return ToThisValue( + receiver, PrimitiveType::kString, 'String.prototype.toString'); +} - extern macro StringBuiltinsAssembler::LoadSurrogatePairAt( - String, intptr, intptr, constexpr UnicodeEncoding): int32; - extern macro StringBuiltinsAssembler::StringFromSingleUTF16EncodedCodePoint( - int32): String; - - // This function assumes StringPrimitiveWithNoCustomIteration is true. - transitioning builtin StringToList(implicit context: Context)(string: String): - JSArray { - const kind = ElementsKind::PACKED_ELEMENTS; - const stringLength: intptr = string.length_intptr; - - const nativeContext = LoadNativeContext(context); - const map: Map = LoadJSArrayElementsMap(kind, nativeContext); - const array: JSArray = AllocateJSArray( - kind, map, stringLength, SmiTag(stringLength), - AllocationFlag::kAllowLargeObjectAllocation); - const elements = UnsafeCast(array.elements); - const encoding = UnicodeEncoding::UTF16; - let arrayLength: Smi = 0; - let i: intptr = 0; - while (i < stringLength) { - const ch: int32 = LoadSurrogatePairAt(string, stringLength, i, encoding); - const value: String = StringFromSingleUTF16EncodedCodePoint(ch); - elements[arrayLength] = value; - // Increment and continue the loop. - i = i + value.length_intptr; - arrayLength++; - } - assert(arrayLength >= 0); - assert(SmiTag(stringLength) >= arrayLength); - array.length = arrayLength; +// ES6 #sec-string.prototype.valueof +transitioning javascript builtin +StringPrototypeValueOf( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + return ToThisValue( + receiver, PrimitiveType::kString, 'String.prototype.valueOf'); +} - return array; +extern macro StringBuiltinsAssembler::LoadSurrogatePairAt( + String, intptr, intptr, constexpr UnicodeEncoding): int32; +extern macro StringBuiltinsAssembler::StringFromSingleUTF16EncodedCodePoint( + int32): String; + +// This function assumes StringPrimitiveWithNoCustomIteration is true. +transitioning builtin StringToList(implicit context: Context)(string: String): + JSArray { + const kind = ElementsKind::PACKED_ELEMENTS; + const stringLength: intptr = string.length_intptr; + + const nativeContext = LoadNativeContext(context); + const map: Map = LoadJSArrayElementsMap(kind, nativeContext); + const array: JSArray = AllocateJSArray( + kind, map, stringLength, SmiTag(stringLength), + AllocationFlag::kAllowLargeObjectAllocation); + const elements = UnsafeCast(array.elements); + const encoding = UnicodeEncoding::UTF16; + let arrayLength: Smi = 0; + let i: intptr = 0; + while (i < stringLength) { + const ch: int32 = LoadSurrogatePairAt(string, stringLength, i, encoding); + const value: String = StringFromSingleUTF16EncodedCodePoint(ch); + elements[arrayLength] = value; + // Increment and continue the loop. + i = i + value.length_intptr; + arrayLength++; } + assert(arrayLength >= 0); + assert(SmiTag(stringLength) >= arrayLength); + array.length = arrayLength; - transitioning macro GenerateStringAt(implicit context: Context)( - receiver: JSAny, position: JSAny, - methodName: constexpr string): never labels - IfInBounds(String, uintptr, uintptr), IfOutOfBounds { - // 1. Let O be ? RequireObjectCoercible(this value). - // 2. Let S be ? ToString(O). - const string: String = ToThisString(receiver, methodName); - - // 3. Let position be ? ToInteger(pos). - const indexNumber: Number = ToInteger_Inline(position); - - // Convert the {position} to a uintptr and check that it's in bounds of - // the {string}. - typeswitch (indexNumber) { - case (indexSmi: Smi): { - const length: uintptr = string.length_uintptr; - const index: uintptr = Unsigned(Convert(indexSmi)); - // Max string length fits Smi range, so we can do an unsigned bounds - // check. - const kMaxStringLengthFitsSmi: constexpr bool = - kStringMaxLengthUintptr < kSmiMaxValue; - StaticAssert(kMaxStringLengthFitsSmi); - if (index >= length) goto IfOutOfBounds; - goto IfInBounds(string, index, length); - } - case (indexHeapNumber: HeapNumber): { - assert(IsNumberNormalized(indexHeapNumber)); - // Valid string indices fit into Smi range, so HeapNumber index is - // definitely an out of bounds case. - goto IfOutOfBounds; - } - } - } + return array; +} - // ES6 #sec-string.prototype.charat - transitioning javascript builtin StringPrototypeCharAt( - js-implicit context: NativeContext, - receiver: JSAny)(position: JSAny): JSAny { - try { - GenerateStringAt(receiver, position, 'String.prototype.charAt') - otherwise IfInBounds, IfOutOfBounds; - } - label IfInBounds(string: String, index: uintptr, _length: uintptr) { - const code: int32 = StringCharCodeAt(string, index); - return StringFromSingleCharCode(code); +transitioning macro GenerateStringAt(implicit context: Context)( + receiver: JSAny, position: JSAny, + methodName: constexpr string): never labels +IfInBounds(String, uintptr, uintptr), IfOutOfBounds { + // 1. Let O be ? RequireObjectCoercible(this value). + // 2. Let S be ? ToString(O). + const string: String = ToThisString(receiver, methodName); + + // 3. Let position be ? ToInteger(pos). + const indexNumber: Number = ToInteger_Inline(position); + + // Convert the {position} to a uintptr and check that it's in bounds of + // the {string}. + typeswitch (indexNumber) { + case (indexSmi: Smi): { + const length: uintptr = string.length_uintptr; + const index: uintptr = Unsigned(Convert(indexSmi)); + // Max string length fits Smi range, so we can do an unsigned bounds + // check. + const kMaxStringLengthFitsSmi: constexpr bool = + kStringMaxLengthUintptr < kSmiMaxValue; + StaticAssert(kMaxStringLengthFitsSmi); + if (index >= length) goto IfOutOfBounds; + goto IfInBounds(string, index, length); } - label IfOutOfBounds { - return kEmptyString; + case (indexHeapNumber: HeapNumber): { + assert(IsNumberNormalized(indexHeapNumber)); + // Valid string indices fit into Smi range, so HeapNumber index is + // definitely an out of bounds case. + goto IfOutOfBounds; } } +} - // ES6 #sec-string.prototype.charcodeat - transitioning javascript builtin StringPrototypeCharCodeAt( - js-implicit context: NativeContext, - receiver: JSAny)(position: JSAny): JSAny { - try { - GenerateStringAt(receiver, position, 'String.prototype.charCodeAt') - otherwise IfInBounds, IfOutOfBounds; - } - label IfInBounds(string: String, index: uintptr, _length: uintptr) { - const code: int32 = StringCharCodeAt(string, index); - return Convert(code); - } - label IfOutOfBounds { - return kNaN; - } +// ES6 #sec-string.prototype.charat +transitioning javascript builtin StringPrototypeCharAt( + js-implicit context: NativeContext, + receiver: JSAny)(position: JSAny): JSAny { + try { + GenerateStringAt(receiver, position, 'String.prototype.charAt') + otherwise IfInBounds, IfOutOfBounds; + } label IfInBounds(string: String, index: uintptr, _length: uintptr) { + const code: int32 = StringCharCodeAt(string, index); + return StringFromSingleCharCode(code); + } label IfOutOfBounds { + return kEmptyString; } +} - // ES6 #sec-string.prototype.codepointat - transitioning javascript builtin StringPrototypeCodePointAt( - js-implicit context: NativeContext, - receiver: JSAny)(position: JSAny): JSAny { - try { - GenerateStringAt(receiver, position, 'String.prototype.codePointAt') - otherwise IfInBounds, IfOutOfBounds; - } - label IfInBounds(string: String, index: uintptr, length: uintptr) { - // This is always a call to a builtin from Javascript, so we need to - // produce UTF32. - const code: int32 = LoadSurrogatePairAt( - string, Signed(length), Signed(index), UnicodeEncoding::UTF32); - return Convert(code); - } - label IfOutOfBounds { - return Undefined; - } +// ES6 #sec-string.prototype.charcodeat +transitioning javascript builtin StringPrototypeCharCodeAt( + js-implicit context: NativeContext, + receiver: JSAny)(position: JSAny): JSAny { + try { + GenerateStringAt(receiver, position, 'String.prototype.charCodeAt') + otherwise IfInBounds, IfOutOfBounds; + } label IfInBounds(string: String, index: uintptr, _length: uintptr) { + const code: int32 = StringCharCodeAt(string, index); + return Convert(code); + } label IfOutOfBounds { + return kNaN; } +} - // ES6 String.prototype.concat(...args) - // ES6 #sec-string.prototype.concat - transitioning javascript builtin StringPrototypeConcat( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - // Check that {receiver} is coercible to Object and convert it to a String. - let string: String = ToThisString(receiver, 'String.prototype.concat'); - - // Concatenate all the arguments passed to this builtin. - const length: intptr = Convert(arguments.length); - for (let i: intptr = 0; i < length; i++) { - const temp: String = ToString_Inline(arguments[i]); - string = string + temp; - } - return string; +// ES6 #sec-string.prototype.codepointat +transitioning javascript builtin StringPrototypeCodePointAt( + js-implicit context: NativeContext, + receiver: JSAny)(position: JSAny): JSAny { + try { + GenerateStringAt(receiver, position, 'String.prototype.codePointAt') + otherwise IfInBounds, IfOutOfBounds; + } label IfInBounds(string: String, index: uintptr, length: uintptr) { + // This is always a call to a builtin from Javascript, so we need to + // produce UTF32. + const code: int32 = LoadSurrogatePairAt( + string, Signed(length), Signed(index), UnicodeEncoding::UTF32); + return Convert(code); + } label IfOutOfBounds { + return Undefined; + } +} + +// ES6 String.prototype.concat(...args) +// ES6 #sec-string.prototype.concat +transitioning javascript builtin StringPrototypeConcat( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // Check that {receiver} is coercible to Object and convert it to a String. + let string: String = ToThisString(receiver, 'String.prototype.concat'); + + // Concatenate all the arguments passed to this builtin. + const length: intptr = Convert(arguments.length); + for (let i: intptr = 0; i < length; i++) { + const temp: String = ToString_Inline(arguments[i]); + string = string + temp; } + return string; +} - extern transitioning runtime - SymbolDescriptiveString(implicit context: Context)(Symbol): String; - - // ES #sec-string-constructor - // https://tc39.github.io/ecma262/#sec-string-constructor - transitioning javascript builtin StringConstructor( - js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny, - target: JSFunction)(...arguments): JSAny { - const length: intptr = Convert(arguments.length); - let s: String; - // 1. If no arguments were passed to this function invocation, let s be "". - if (length == 0) { - s = EmptyStringConstant(); - } else { - // 2. Else, - // 2. a. If NewTarget is undefined and Type(value) is Symbol, return - // SymbolDescriptiveString(value). - if (newTarget == Undefined) { - typeswitch (arguments[0]) { - case (value: Symbol): { - return SymbolDescriptiveString(value); - } - case (JSAny): { - } +extern transitioning runtime +SymbolDescriptiveString(implicit context: Context)(Symbol): String; + +// ES #sec-string-constructor +// https://tc39.github.io/ecma262/#sec-string-constructor +transitioning javascript builtin StringConstructor( + js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny, + target: JSFunction)(...arguments): JSAny { + const length: intptr = Convert(arguments.length); + let s: String; + // 1. If no arguments were passed to this function invocation, let s be "". + if (length == 0) { + s = EmptyStringConstant(); + } else { + // 2. Else, + // 2. a. If NewTarget is undefined and Type(value) is Symbol, return + // SymbolDescriptiveString(value). + if (newTarget == Undefined) { + typeswitch (arguments[0]) { + case (value: Symbol): { + return SymbolDescriptiveString(value); + } + case (JSAny): { } } - // 2. b. Let s be ? ToString(value). - s = ToString_Inline(arguments[0]); - } - // 3. If NewTarget is undefined, return s. - if (newTarget == Undefined) { - return s; } - // 4. Return ! StringCreate(s, ? GetPrototypeFromConstructor(NewTarget, - // "%String.prototype%")). - const map = GetDerivedMap(target, UnsafeCast(newTarget)); - const obj = - UnsafeCast(AllocateFastOrSlowJSObjectFromMap(map)); - obj.value = s; - return obj; + // 2. b. Let s be ? ToString(value). + s = ToString_Inline(arguments[0]); } - - transitioning builtin StringAddConvertLeft(implicit context: Context)( - left: JSAny, right: String): String { - return ToStringImpl(context, ToPrimitiveDefault(left)) + right; + // 3. If NewTarget is undefined, return s. + if (newTarget == Undefined) { + return s; } + // 4. Return ! StringCreate(s, ? GetPrototypeFromConstructor(NewTarget, + // "%String.prototype%")). + const map = GetDerivedMap(target, UnsafeCast(newTarget)); + const obj = + UnsafeCast(AllocateFastOrSlowJSObjectFromMap(map)); + obj.value = s; + return obj; +} - transitioning builtin StringAddConvertRight(implicit context: Context)( - left: String, right: JSAny): String { - return left + ToStringImpl(context, ToPrimitiveDefault(right)); - } +transitioning builtin StringAddConvertLeft(implicit context: Context)( + left: JSAny, right: String): String { + return ToStringImpl(context, ToPrimitiveDefault(left)) + right; +} - builtin StringCharAt(implicit context: Context)( - receiver: String, position: uintptr): String { - // Load the character code at the {position} from the {receiver}. - const code: int32 = StringCharCodeAt(receiver, position); - // And return the single character string with only that {code} - return StringFromSingleCharCode(code); - } +transitioning builtin StringAddConvertRight(implicit context: Context)( + left: String, right: JSAny): String { + return left + ToStringImpl(context, ToPrimitiveDefault(right)); +} + +builtin StringCharAt(implicit context: Context)( + receiver: String, position: uintptr): String { + // Load the character code at the {position} from the {receiver}. + const code: int32 = StringCharCodeAt(receiver, position); + // And return the single character string with only that {code} + return StringFromSingleCharCode(code); +} } diff --git a/deps/v8/src/builtins/builtins-trace.cc b/deps/v8/src/builtins/builtins-trace.cc index b067bb0249f5d1..e98b38d1a5d157 100644 --- a/deps/v8/src/builtins/builtins-trace.cc +++ b/deps/v8/src/builtins/builtins-trace.cc @@ -10,6 +10,10 @@ #include "src/logging/counters.h" #include "src/objects/objects-inl.h" +#if defined(V8_USE_PERFETTO) +#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h" +#endif + namespace v8 { namespace internal { @@ -69,6 +73,7 @@ class MaybeUtf8 { std::unique_ptr allocated_; }; +#if !defined(V8_USE_PERFETTO) class JsonTraceValue : public ConvertableToTraceFormat { public: explicit JsonTraceValue(Isolate* isolate, Handle object) { @@ -91,6 +96,7 @@ const uint8_t* GetCategoryGroupEnabled(Isolate* isolate, MaybeUtf8 category(isolate, string); return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(*category); } +#endif // !defined(V8_USE_PERFETTO) #undef MAX_STACK_LENGTH @@ -104,8 +110,15 @@ BUILTIN(IsTraceCategoryEnabled) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError)); } - return isolate->heap()->ToBoolean( - *GetCategoryGroupEnabled(isolate, Handle::cast(category))); + bool enabled; +#if defined(V8_USE_PERFETTO) + MaybeUtf8 category_str(isolate, Handle::cast(category)); + perfetto::DynamicCategory dynamic_category{*category_str}; + enabled = TRACE_EVENT_CATEGORY_ENABLED(dynamic_category); +#else + enabled = *GetCategoryGroupEnabled(isolate, Handle::cast(category)); +#endif + return isolate->heap()->ToBoolean(enabled); } // Builtins::kTrace(phase, category, name, id, data) : bool @@ -118,18 +131,23 @@ BUILTIN(Trace) { Handle id_arg = args.atOrUndefined(isolate, 4); Handle data_arg = args.atOrUndefined(isolate, 5); - const uint8_t* category_group_enabled = - GetCategoryGroupEnabled(isolate, Handle::cast(category)); - // Exit early if the category group is not enabled. - if (!*category_group_enabled) { +#if defined(V8_USE_PERFETTO) + MaybeUtf8 category_str(isolate, Handle::cast(category)); + perfetto::DynamicCategory dynamic_category{*category_str}; + if (!TRACE_EVENT_CATEGORY_ENABLED(dynamic_category)) return ReadOnlyRoots(isolate).false_value(); - } +#else + const uint8_t* category_group_enabled = + GetCategoryGroupEnabled(isolate, Handle::cast(category)); + if (!*category_group_enabled) return ReadOnlyRoots(isolate).false_value(); +#endif if (!phase_arg->IsNumber()) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError)); } + char phase = static_cast(DoubleToInt32(phase_arg->Number())); if (!category->IsString()) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError)); @@ -160,32 +178,67 @@ BUILTIN(Trace) { // We support passing one additional trace event argument with the // name "data". Any JSON serializable value may be passed. static const char* arg_name = "data"; + Handle arg_json; int32_t num_args = 0; - uint8_t arg_type; - uint64_t arg_value; - if (!data_arg->IsUndefined(isolate)) { // Serializes the data argument as a JSON string, which is then // copied into an object. This eliminates duplicated code but // could have perf costs. It is also subject to all the same // limitations as JSON.stringify() as it relates to circular // references and value limitations (e.g. BigInt is not supported). - Handle result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, + isolate, arg_json, JsonStringify(isolate, data_arg, isolate->factory()->undefined_value(), isolate->factory()->undefined_value())); - std::unique_ptr traced_value; - traced_value.reset( - new JsonTraceValue(isolate, Handle::cast(result))); - tracing::SetTraceValue(std::move(traced_value), &arg_type, &arg_value); num_args++; } +#if defined(V8_USE_PERFETTO) + auto trace_args = [&](perfetto::EventContext ctx) { + // TODO(skyostil): Use interned names to reduce trace size. + if (phase != TRACE_EVENT_PHASE_END) { + ctx.event()->set_name(*name); + } + if (num_args) { + MaybeUtf8 arg_contents(isolate, Handle::cast(arg_json)); + auto annotation = ctx.event()->add_debug_annotations(); + annotation->set_name(arg_name); + annotation->set_legacy_json_value(*arg_contents); + } + if (flags & TRACE_EVENT_FLAG_HAS_ID) { + auto legacy_event = ctx.event()->set_legacy_event(); + legacy_event->set_global_id(id); + } + }; + + switch (phase) { + case TRACE_EVENT_PHASE_BEGIN: + TRACE_EVENT_BEGIN(dynamic_category, nullptr, trace_args); + break; + case TRACE_EVENT_PHASE_END: + TRACE_EVENT_END(dynamic_category, trace_args); + break; + case TRACE_EVENT_PHASE_INSTANT: + TRACE_EVENT_INSTANT(dynamic_category, nullptr, trace_args); + break; + default: + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError)); + } + +#else // !defined(V8_USE_PERFETTO) + uint8_t arg_type; + uint64_t arg_value; + if (num_args) { + std::unique_ptr traced_value( + new JsonTraceValue(isolate, Handle::cast(arg_json))); + tracing::SetTraceValue(std::move(traced_value), &arg_type, &arg_value); + } + TRACE_EVENT_API_ADD_TRACE_EVENT( - static_cast(DoubleToInt32(phase_arg->Number())), - category_group_enabled, *name, tracing::kGlobalScope, id, tracing::kNoId, - num_args, &arg_name, &arg_type, &arg_value, flags); + phase, category_group_enabled, *name, tracing::kGlobalScope, id, + tracing::kNoId, num_args, &arg_name, &arg_type, &arg_value, flags); +#endif // !defined(V8_USE_PERFETTO) return ReadOnlyRoots(isolate).true_value(); } diff --git a/deps/v8/src/builtins/builtins-typed-array-gen.cc b/deps/v8/src/builtins/builtins-typed-array-gen.cc index 021a0e9240ceef..a6d3887ad31fa0 100644 --- a/deps/v8/src/builtins/builtins-typed-array-gen.cc +++ b/deps/v8/src/builtins/builtins-typed-array-gen.cc @@ -65,8 +65,9 @@ TNode TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer( StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset, byte_length); - StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset, - IntPtrConstant(0)); + StoreJSArrayBufferBackingStore( + buffer, + EncodeExternalPointer(ReinterpretCast(IntPtrConstant(0)))); if (V8_ARRAY_BUFFER_EXTENSION_BOOL) { StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kExtensionOffset, IntPtrConstant(0)); @@ -239,7 +240,7 @@ TNode TypedArrayBuiltinsAssembler::GetBuffer( TNode buffer = LoadJSArrayBufferViewBuffer(array); GotoIf(IsDetachedBuffer(buffer), &call_runtime); - TNode backing_store = LoadJSArrayBufferBackingStore(buffer); + TNode backing_store = LoadJSArrayBufferBackingStorePtr(buffer); GotoIf(WordEqual(backing_store, IntPtrConstant(0)), &call_runtime); var_result = buffer; Goto(&done); @@ -397,8 +398,8 @@ void TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr( } StoreObjectField(holder, JSTypedArray::kBasePointerOffset, base); - StoreObjectFieldNoWriteBarrier( - holder, JSTypedArray::kExternalPointerOffset, offset); + StoreJSTypedArrayExternalPointer( + holder, EncodeExternalPointer(ReinterpretCast(offset))); } void TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr( @@ -407,8 +408,7 @@ void TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr( SmiConstant(0)); base = RawPtrAdd(base, Signed(offset)); - StoreObjectFieldNoWriteBarrier( - holder, JSTypedArray::kExternalPointerOffset, base); + StoreJSTypedArrayExternalPointer(holder, EncodeExternalPointer(base)); } void TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric( diff --git a/deps/v8/src/builtins/builtins-wasm-gen.cc b/deps/v8/src/builtins/builtins-wasm-gen.cc index 770f5da97b3d07..28efa39c67dc10 100644 --- a/deps/v8/src/builtins/builtins-wasm-gen.cc +++ b/deps/v8/src/builtins/builtins-wasm-gen.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/builtins/builtins-wasm-gen.h" + #include "src/builtins/builtins-utils-gen.h" #include "src/codegen/code-stub-assembler.h" #include "src/codegen/interface-descriptors.h" @@ -12,71 +14,45 @@ namespace v8 { namespace internal { -class WasmBuiltinsAssembler : public CodeStubAssembler { - public: - explicit WasmBuiltinsAssembler(compiler::CodeAssemblerState* state) - : CodeStubAssembler(state) {} - - protected: - TNode LoadInstanceFromFrame() { - return CAST( - LoadFromParentFrame(WasmCompiledFrameConstants::kWasmInstanceOffset)); - } - - TNode LoadContextFromInstance(TNode instance) { - return CAST(Load(MachineType::AnyTagged(), instance, - IntPtrConstant(WasmInstanceObject::kNativeContextOffset - - kHeapObjectTag))); - } - - TNode SmiFromUint32WithSaturation(TNode value, uint32_t max) { - DCHECK_LE(max, static_cast(Smi::kMaxValue)); - TNode capped_value = SelectConstant( - Uint32LessThan(value, Uint32Constant(max)), value, Uint32Constant(max)); - return SmiFromUint32(capped_value); - } -}; - -TF_BUILTIN(WasmStackGuard, WasmBuiltinsAssembler) { - TNode instance = LoadInstanceFromFrame(); - TNode context = LoadContextFromInstance(instance); - TailCallRuntime(Runtime::kWasmStackGuard, context); +TNode WasmBuiltinsAssembler::LoadInstanceFromFrame() { + return CAST(LoadFromParentFrame(WasmFrameConstants::kWasmInstanceOffset)); } -TF_BUILTIN(WasmStackOverflow, WasmBuiltinsAssembler) { - TNode instance = LoadInstanceFromFrame(); - TNode context = LoadContextFromInstance(instance); - TailCallRuntime(Runtime::kThrowWasmStackOverflow, context); +TNode WasmBuiltinsAssembler::LoadContextFromInstance( + TNode instance) { + return CAST(Load(MachineType::AnyTagged(), instance, + IntPtrConstant(WasmInstanceObject::kNativeContextOffset - + kHeapObjectTag))); } -TF_BUILTIN(WasmThrow, WasmBuiltinsAssembler) { - TNode exception = CAST(Parameter(Descriptor::kException)); - TNode instance = LoadInstanceFromFrame(); - TNode context = LoadContextFromInstance(instance); - TailCallRuntime(Runtime::kThrow, context, exception); +TNode WasmBuiltinsAssembler::LoadTablesFromInstance( + TNode instance) { + return LoadObjectField(instance, + WasmInstanceObject::kTablesOffset); } -TF_BUILTIN(WasmRethrow, WasmBuiltinsAssembler) { - TNode exception = CAST(Parameter(Descriptor::kException)); - TNode instance = LoadInstanceFromFrame(); - TNode context = LoadContextFromInstance(instance); - - Label nullref(this, Label::kDeferred); - GotoIf(TaggedEqual(NullConstant(), exception), &nullref); +TNode WasmBuiltinsAssembler::LoadExternalFunctionsFromInstance( + TNode instance) { + return LoadObjectField( + instance, WasmInstanceObject::kWasmExternalFunctionsOffset); +} - TailCallRuntime(Runtime::kReThrow, context, exception); +TNode WasmBuiltinsAssembler::SmiFromUint32WithSaturation( + TNode value, uint32_t max) { + DCHECK_LE(max, static_cast(Smi::kMaxValue)); + TNode capped_value = SelectConstant( + Uint32LessThan(value, Uint32Constant(max)), value, Uint32Constant(max)); + return SmiFromUint32(capped_value); +} - BIND(&nullref); - MessageTemplate message_id = MessageTemplate::kWasmTrapRethrowNullRef; - TailCallRuntime(Runtime::kThrowWasmError, context, - SmiConstant(static_cast(message_id))); +TF_BUILTIN(WasmFloat32ToNumber, WasmBuiltinsAssembler) { + TNode val = UncheckedCast(Parameter(Descriptor::kValue)); + Return(ChangeFloat32ToTagged(val)); } -TF_BUILTIN(WasmTraceMemory, WasmBuiltinsAssembler) { - TNode info = CAST(Parameter(Descriptor::kMemoryTracingInfo)); - TNode instance = LoadInstanceFromFrame(); - TNode context = LoadContextFromInstance(instance); - TailCallRuntime(Runtime::kWasmTraceMemory, context, info); +TF_BUILTIN(WasmFloat64ToNumber, WasmBuiltinsAssembler) { + TNode val = UncheckedCast(Parameter(Descriptor::kValue)); + Return(ChangeFloat64ToTagged(val)); } TF_BUILTIN(WasmAtomicNotify, WasmBuiltinsAssembler) { @@ -210,26 +186,6 @@ TF_BUILTIN(WasmI64AtomicWait64, WasmBuiltinsAssembler) { Return(Unsigned(SmiToInt32(result_smi))); } -TF_BUILTIN(WasmMemoryGrow, WasmBuiltinsAssembler) { - TNode num_pages = - UncheckedCast(Parameter(Descriptor::kNumPages)); - Label num_pages_out_of_range(this, Label::kDeferred); - - TNode num_pages_fits_in_smi = - IsValidPositiveSmi(ChangeInt32ToIntPtr(num_pages)); - GotoIfNot(num_pages_fits_in_smi, &num_pages_out_of_range); - - TNode num_pages_smi = SmiFromInt32(num_pages); - TNode instance = LoadInstanceFromFrame(); - TNode context = LoadContextFromInstance(instance); - TNode ret_smi = CAST( - CallRuntime(Runtime::kWasmMemoryGrow, context, instance, num_pages_smi)); - Return(SmiToInt32(ret_smi)); - - BIND(&num_pages_out_of_range); - Return(Int32Constant(-1)); -} - TF_BUILTIN(WasmTableInit, WasmBuiltinsAssembler) { TNode dst_raw = UncheckedCast(Parameter(Descriptor::kDestination)); @@ -290,65 +246,42 @@ TF_BUILTIN(WasmTableCopy, WasmBuiltinsAssembler) { src_table, dst, src, size); } -TF_BUILTIN(WasmTableGet, WasmBuiltinsAssembler) { - TNode entry_index = - UncheckedCast(Parameter(Descriptor::kEntryIndex)); +TF_BUILTIN(WasmAllocateArray, WasmBuiltinsAssembler) { TNode instance = LoadInstanceFromFrame(); - TNode context = LoadContextFromInstance(instance); - Label entry_index_out_of_range(this, Label::kDeferred); - - TNode entry_index_fits_in_smi = - IsValidPositiveSmi(ChangeInt32ToIntPtr(entry_index)); - GotoIfNot(entry_index_fits_in_smi, &entry_index_out_of_range); - - TNode entry_index_smi = SmiFromInt32(entry_index); - TNode table_index_smi = CAST(Parameter(Descriptor::kTableIndex)); - - TailCallRuntime(Runtime::kWasmFunctionTableGet, context, instance, - table_index_smi, entry_index_smi); - - BIND(&entry_index_out_of_range); - MessageTemplate message_id = - wasm::WasmOpcodes::TrapReasonToMessageId(wasm::kTrapTableOutOfBounds); - TailCallRuntime(Runtime::kThrowWasmError, context, - SmiConstant(static_cast(message_id))); + TNode map_index = CAST(Parameter(Descriptor::kMapIndex)); + TNode length = CAST(Parameter(Descriptor::kLength)); + TNode element_size = CAST(Parameter(Descriptor::kElementSize)); + TNode maps_list = LoadObjectField( + instance, WasmInstanceObject::kManagedObjectMapsOffset); + TNode map = CAST(LoadFixedArrayElement(maps_list, map_index)); + TNode untagged_length = SmiUntag(length); + // instance_size = WasmArray::kHeaderSize + // + RoundUp(element_size * length, kObjectAlignment) + TNode raw_size = IntPtrMul(SmiUntag(element_size), untagged_length); + TNode rounded_size = + WordAnd(IntPtrAdd(raw_size, IntPtrConstant(kObjectAlignmentMask)), + IntPtrConstant(~kObjectAlignmentMask)); + TNode instance_size = + IntPtrAdd(IntPtrConstant(WasmArray::kHeaderSize), rounded_size); + TNode result = UncheckedCast(Allocate(instance_size)); + StoreMap(result, map); + StoreObjectFieldNoWriteBarrier(result, WasmArray::kLengthOffset, + TruncateIntPtrToInt32(untagged_length)); + Return(result); } -TF_BUILTIN(WasmTableSet, WasmBuiltinsAssembler) { - TNode entry_index = - UncheckedCast(Parameter(Descriptor::kEntryIndex)); +TF_BUILTIN(WasmAllocateStruct, WasmBuiltinsAssembler) { TNode instance = LoadInstanceFromFrame(); - TNode context = LoadContextFromInstance(instance); - Label entry_index_out_of_range(this, Label::kDeferred); - - TNode entry_index_fits_in_smi = - IsValidPositiveSmi(ChangeInt32ToIntPtr(entry_index)); - GotoIfNot(entry_index_fits_in_smi, &entry_index_out_of_range); - - TNode entry_index_smi = SmiFromInt32(entry_index); - TNode table_index_smi = CAST(Parameter(Descriptor::kTableIndex)); - TNode value = CAST(Parameter(Descriptor::kValue)); - TailCallRuntime(Runtime::kWasmFunctionTableSet, context, instance, - table_index_smi, entry_index_smi, value); - - BIND(&entry_index_out_of_range); - MessageTemplate message_id = - wasm::WasmOpcodes::TrapReasonToMessageId(wasm::kTrapTableOutOfBounds); - TailCallRuntime(Runtime::kThrowWasmError, context, - SmiConstant(static_cast(message_id))); + TNode map_index = CAST(Parameter(Descriptor::kMapIndex)); + TNode maps_list = LoadObjectField( + instance, WasmInstanceObject::kManagedObjectMapsOffset); + TNode map = CAST(LoadFixedArrayElement(maps_list, map_index)); + TNode instance_size = + TimesTaggedSize(LoadMapInstanceSizeInWords(map)); + TNode result = UncheckedCast(Allocate(instance_size)); + StoreMap(result, map); + Return(result); } -#define DECLARE_THROW_RUNTIME_FN(name) \ - TF_BUILTIN(ThrowWasm##name, WasmBuiltinsAssembler) { \ - TNode instance = LoadInstanceFromFrame(); \ - TNode context = LoadContextFromInstance(instance); \ - MessageTemplate message_id = \ - wasm::WasmOpcodes::TrapReasonToMessageId(wasm::k##name); \ - TailCallRuntime(Runtime::kThrowWasmError, context, \ - SmiConstant(static_cast(message_id))); \ - } -FOREACH_WASM_TRAPREASON(DECLARE_THROW_RUNTIME_FN) -#undef DECLARE_THROW_RUNTIME_FN - } // namespace internal } // namespace v8 diff --git a/deps/v8/src/builtins/builtins-wasm-gen.h b/deps/v8/src/builtins/builtins-wasm-gen.h new file mode 100644 index 00000000000000..3740560666d5ae --- /dev/null +++ b/deps/v8/src/builtins/builtins-wasm-gen.h @@ -0,0 +1,35 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BUILTINS_BUILTINS_WASM_GEN_H_ +#define V8_BUILTINS_BUILTINS_WASM_GEN_H_ + +#include "src/codegen/code-stub-assembler.h" + +namespace v8 { +namespace internal { + +class WasmBuiltinsAssembler : public CodeStubAssembler { + public: + explicit WasmBuiltinsAssembler(compiler::CodeAssemblerState* state) + : CodeStubAssembler(state) {} + + TNode LoadInstanceFromFrame(); + + TNode LoadContextFromInstance( + TNode instance); + + TNode LoadTablesFromInstance(TNode instance); + + TNode LoadExternalFunctionsFromInstance( + TNode instance); + + protected: + TNode SmiFromUint32WithSaturation(TNode value, uint32_t max); +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_BUILTINS_BUILTINS_WASM_GEN_H_ diff --git a/deps/v8/src/builtins/builtins-weak-refs.cc b/deps/v8/src/builtins/builtins-weak-refs.cc index e75c7fae9d1d30..d5cceda4541f89 100644 --- a/deps/v8/src/builtins/builtins-weak-refs.cc +++ b/deps/v8/src/builtins/builtins-weak-refs.cc @@ -36,7 +36,7 @@ BUILTIN(FinalizationRegistryConstructor) { finalization_registry->set_native_context(*isolate->native_context()); finalization_registry->set_cleanup(*cleanup); finalization_registry->set_flags( - JSFinalizationRegistry::ScheduledForCleanupField::encode(false)); + JSFinalizationRegistry::ScheduledForCleanupBit::encode(false)); DCHECK(finalization_registry->active_cells().IsUndefined(isolate)); DCHECK(finalization_registry->cleared_cells().IsUndefined(isolate)); @@ -122,61 +122,6 @@ BUILTIN(FinalizationRegistryUnregister) { return *isolate->factory()->ToBoolean(success); } -BUILTIN(FinalizationRegistryCleanupSome) { - HandleScope scope(isolate); - const char* method_name = "FinalizationRegistry.prototype.cleanupSome"; - - // 1. Let finalizationGroup be the this value. - // - // 2. If Type(finalizationGroup) is not Object, throw a TypeError - // exception. - // - // 3. If finalizationGroup does not have a [[Cells]] internal slot, - // throw a TypeError exception. - CHECK_RECEIVER(JSFinalizationRegistry, finalization_registry, method_name); - - Handle callback(finalization_registry->cleanup(), isolate); - Handle callback_obj = args.atOrUndefined(isolate, 1); - - // 4. If callback is not undefined and IsCallable(callback) is - // false, throw a TypeError exception. - if (!callback_obj->IsUndefined(isolate)) { - if (!callback_obj->IsCallable()) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, - NewTypeError(MessageTemplate::kWeakRefsCleanupMustBeCallable)); - } - callback = callback_obj; - } - - // Don't do set_scheduled_for_cleanup(false); we still have the task - // scheduled. - if (JSFinalizationRegistry::Cleanup(isolate, finalization_registry, callback) - .IsNothing()) { - DCHECK(isolate->has_pending_exception()); - return ReadOnlyRoots(isolate).exception(); - } - return ReadOnlyRoots(isolate).undefined_value(); -} - -BUILTIN(FinalizationRegistryCleanupIteratorNext) { - HandleScope scope(isolate); - CHECK_RECEIVER(JSFinalizationRegistryCleanupIterator, iterator, "next"); - - Handle finalization_registry( - iterator->finalization_registry(), isolate); - if (!finalization_registry->NeedsCleanup()) { - return *isolate->factory()->NewJSIteratorResult( - handle(ReadOnlyRoots(isolate).undefined_value(), isolate), true); - } - Handle holdings = - handle(JSFinalizationRegistry::PopClearedCellHoldings( - finalization_registry, isolate), - isolate); - - return *isolate->factory()->NewJSIteratorResult(holdings, false); -} - BUILTIN(WeakRefConstructor) { HandleScope scope(isolate); Handle target = args.target(); diff --git a/deps/v8/src/builtins/cast.tq b/deps/v8/src/builtins/cast.tq index cb7ff412dea2eb..dfac2035784ee3 100644 --- a/deps/v8/src/builtins/cast.tq +++ b/deps/v8/src/builtins/cast.tq @@ -2,44 +2,47 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -extern macro IsCallable(HeapObject): bool; +extern macro IsAllocationSite(HeapObject): bool; +extern macro IsBigInt(HeapObject): bool; extern macro IsConstructor(HeapObject): bool; +extern macro IsContext(HeapObject): bool; +extern macro IsCustomElementsReceiverInstanceType(int32): bool; +extern macro IsExtensibleMap(Map): bool; +extern macro IsFeedbackCell(HeapObject): bool; extern macro IsFeedbackVector(HeapObject): bool; +extern macro IsFixedArray(HeapObject): bool; +extern macro IsHeapNumber(HeapObject): bool; +extern macro IsJSAggregateError(HeapObject): bool; extern macro IsJSArray(HeapObject): bool; -extern macro IsJSProxy(HeapObject): bool; -extern macro IsJSRegExp(HeapObject): bool; -extern macro IsJSRegExpStringIterator(HeapObject): bool; -extern macro IsMap(HeapObject): bool; -extern macro IsJSFunction(HeapObject): bool; +extern macro IsJSArrayMap(Map): bool; extern macro IsJSBoundFunction(HeapObject): bool; +extern macro IsJSFinalizationRegistry(HeapObject): bool; +extern macro IsJSFunction(HeapObject): bool; extern macro IsJSObject(HeapObject): bool; +extern macro IsJSPrimitiveWrapper(HeapObject): bool; extern macro IsJSPromise(HeapObject): bool; -extern macro IsJSTypedArray(HeapObject): bool; -extern macro IsNumberDictionary(HeapObject): bool; -extern macro IsContext(HeapObject): bool; -extern macro IsNativeContext(HeapObject): bool; +extern macro IsJSProxy(HeapObject): bool; extern macro IsJSReceiver(HeapObject): bool; -extern macro TaggedIsCallable(Object): bool; -extern macro IsHeapNumber(HeapObject): bool; -extern macro IsBigInt(HeapObject): bool; -extern macro IsFixedArray(HeapObject): bool; +extern macro IsJSRegExp(HeapObject): bool; +extern macro IsJSRegExpStringIterator(HeapObject): bool; +extern macro IsJSTypedArray(HeapObject): bool; +extern macro IsMap(HeapObject): bool; extern macro IsName(HeapObject): bool; -extern macro IsPrivateSymbol(HeapObject): bool; -extern macro IsNumber(Object): bool; +extern macro IsNativeContext(HeapObject): bool; +extern macro IsNumberDictionary(HeapObject): bool; extern macro IsNumberNormalized(Number): bool; -extern macro IsSafeInteger(Object): bool; +extern macro IsNumber(Object): bool; extern macro IsOddball(HeapObject): bool; -extern macro IsSymbol(HeapObject): bool; -extern macro IsJSArrayMap(Map): bool; -extern macro IsExtensibleMap(Map): bool; -extern macro IsJSPrimitiveWrapper(HeapObject): bool; +extern macro IsPrivateSymbol(HeapObject): bool; extern macro IsPromiseCapability(HeapObject): bool; +extern macro IsPromiseFulfillReactionJobTask(HeapObject): bool; extern macro IsPromiseReaction(HeapObject): bool; extern macro IsPromiseReactionJobTask(HeapObject): bool; extern macro IsPromiseRejectReactionJobTask(HeapObject): bool; -extern macro IsPromiseFulfillReactionJobTask(HeapObject): bool; +extern macro IsSafeInteger(Object): bool; extern macro IsSharedFunctionInfo(HeapObject): bool; -extern macro IsCustomElementsReceiverInstanceType(int32): bool; +extern macro IsSymbol(HeapObject): bool; +extern macro IsTuple2(HeapObject): bool; extern macro HeapObjectToJSDataView(HeapObject): JSDataView labels CastError; @@ -57,6 +60,8 @@ extern macro TaggedToPositiveSmi(Object): PositiveSmi labels CastError; extern macro TaggedToDirectString(Object): DirectString labels CastError; +extern macro HeapObjectToJSAggregateError(HeapObject): JSAggregateError + labels CastError; extern macro HeapObjectToJSArray(HeapObject): JSArray labels CastError; extern macro HeapObjectToCallable(HeapObject): Callable @@ -278,6 +283,12 @@ Cast(o: HeapObject): Undefined return Cast(o) otherwise CastError; } +Cast(o: HeapObject): AllocationSite + labels CastError { + if (IsAllocationSite(o)) return %RawDownCast(o); + goto CastError; +} + Cast(o: HeapObject): FixedArray labels CastError { return HeapObjectToFixedArray(o) otherwise CastError; @@ -365,6 +376,11 @@ Cast(o: HeapObject): Undefined|Callable return HeapObjectToCallable(o) otherwise CastError; } +Cast(o: HeapObject): JSAggregateError + labels CastError { + return HeapObjectToJSAggregateError(o) otherwise CastError; +} + Cast(o: HeapObject): JSArray labels CastError { return HeapObjectToJSArray(o) otherwise CastError; @@ -481,6 +497,12 @@ Cast(implicit context: Context)(o: HeapObject): Map goto CastError; } +Cast(implicit context: Context)(o: HeapObject): FeedbackCell + labels CastError { + if (IsFeedbackCell(o)) return %RawDownCast(o); + goto CastError; +} + Cast(implicit context: Context)(o: HeapObject): FeedbackVector labels CastError { if (IsFeedbackVector(o)) return %RawDownCast(o); @@ -735,8 +757,21 @@ Cast(o: HeapObject): JSPromise labels CastError { goto CastError; } +Cast(o: HeapObject): + JSFinalizationRegistry labels CastError { + if (IsJSFinalizationRegistry(o)) { + return %RawDownCast(o); + } + goto CastError; +} + UnsafeCast(implicit context: Context)(o: Object): RegExpMatchInfo { assert(Is(o)); return %RawDownCast(o); } + +macro CastOrDefault( + implicit context: Context)(x: Arg, default: Default): T|Default { + return Cast(x) otherwise return default; +} diff --git a/deps/v8/src/builtins/collections.tq b/deps/v8/src/builtins/collections.tq index 60136af63365ec..c0d311a825f159 100644 --- a/deps/v8/src/builtins/collections.tq +++ b/deps/v8/src/builtins/collections.tq @@ -5,54 +5,53 @@ #include 'src/builtins/builtins-collections-gen.h' namespace collections { - @export - macro LoadKeyValuePairNoSideEffects(implicit context: Context)(o: JSAny): - KeyValuePair labels MayHaveSideEffects { - typeswitch (o) { - case (a: FastJSArray): { - const length: Smi = a.length; - typeswitch (a.elements) { - case (elements: FixedArray): { - return KeyValuePair{ - key: length > 0 ? array::LoadElementOrUndefined(elements, 0) : - Undefined, - value: length > 1 ? array::LoadElementOrUndefined(elements, 1) : - Undefined - }; - } - case (elements: FixedDoubleArray): { - return KeyValuePair{ - key: length > 0 ? array::LoadElementOrUndefined(elements, 0) : - Undefined, - value: length > 1 ? array::LoadElementOrUndefined(elements, 1) : - Undefined - }; - } - case (FixedArrayBase): deferred { - unreachable; - } +@export +macro LoadKeyValuePairNoSideEffects(implicit context: Context)(o: JSAny): + KeyValuePair labels MayHaveSideEffects { + typeswitch (o) { + case (a: FastJSArray): { + const length: Smi = a.length; + typeswitch (a.elements) { + case (elements: FixedArray): { + return KeyValuePair{ + key: length > 0 ? array::LoadElementOrUndefined(elements, 0) : + Undefined, + value: length > 1 ? array::LoadElementOrUndefined(elements, 1) : + Undefined + }; + } + case (elements: FixedDoubleArray): { + return KeyValuePair{ + key: length > 0 ? array::LoadElementOrUndefined(elements, 0) : + Undefined, + value: length > 1 ? array::LoadElementOrUndefined(elements, 1) : + Undefined + }; + } + case (FixedArrayBase): deferred { + unreachable; } - } - case (JSReceiver): { - goto MayHaveSideEffects; - } - case (o: JSAny): deferred { - ThrowTypeError(MessageTemplate::kIteratorValueNotAnObject, o); } } - } - - @export - transitioning macro LoadKeyValuePair(implicit context: Context)(o: JSAny): - KeyValuePair { - try { - return LoadKeyValuePairNoSideEffects(o) otherwise Generic; + case (JSReceiver): { + goto MayHaveSideEffects; } - label Generic { - return KeyValuePair{ - key: GetProperty(o, Convert(0)), - value: GetProperty(o, Convert(1)) - }; + case (o: JSAny): deferred { + ThrowTypeError(MessageTemplate::kIteratorValueNotAnObject, o); } } } + +@export +transitioning macro LoadKeyValuePair(implicit context: Context)(o: JSAny): + KeyValuePair { + try { + return LoadKeyValuePairNoSideEffects(o) otherwise Generic; + } label Generic { + return KeyValuePair{ + key: GetProperty(o, Convert(0)), + value: GetProperty(o, Convert(1)) + }; + } +} +} diff --git a/deps/v8/src/builtins/console.tq b/deps/v8/src/builtins/console.tq index 48d5d08abc4f87..c0daa19b6dfb7c 100644 --- a/deps/v8/src/builtins/console.tq +++ b/deps/v8/src/builtins/console.tq @@ -3,16 +3,16 @@ // found in the LICENSE file. namespace console { - extern builtin ConsoleAssert(implicit context: - Context)(JSFunction, JSAny, int32): JSAny; +extern builtin ConsoleAssert(implicit context: Context)( + JSFunction, JSAny, int32): JSAny; - javascript builtin FastConsoleAssert( - js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny, - target: JSFunction)(...arguments): JSAny { - if (ToBoolean(arguments[0])) { - return Undefined; - } else { - tail ConsoleAssert(target, newTarget, Convert(arguments.length)); - } +javascript builtin FastConsoleAssert( + js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny, + target: JSFunction)(...arguments): JSAny { + if (ToBoolean(arguments[0])) { + return Undefined; + } else { + tail ConsoleAssert(target, newTarget, Convert(arguments.length)); } } +} diff --git a/deps/v8/src/builtins/convert.tq b/deps/v8/src/builtins/convert.tq index ee9be1d411a434..e2c11120381aec 100644 --- a/deps/v8/src/builtins/convert.tq +++ b/deps/v8/src/builtins/convert.tq @@ -90,6 +90,10 @@ FromConstexpr( c: constexpr LanguageMode): LanguageModeSmi { return %RawDownCast(SmiConstant(c)); } +FromConstexpr(c: constexpr PromiseState): + PromiseState { + return %RawDownCast(Int32Constant(c)); +} macro Convert(i: From): To { return i; @@ -209,6 +213,9 @@ Convert(n: Number): float64 { Convert(n: Number): uintptr { return ChangeUintPtrNumberToUintPtr(n); } +Convert(f: int32): float64 { + return ChangeInt32ToFloat64(f); +} Convert(f: float32): float64 { return ChangeFloat32ToFloat64(f); } diff --git a/deps/v8/src/builtins/data-view.tq b/deps/v8/src/builtins/data-view.tq index c5808dfd9de727..5f61a194728210 100644 --- a/deps/v8/src/builtins/data-view.tq +++ b/deps/v8/src/builtins/data-view.tq @@ -6,877 +6,830 @@ namespace data_view { - macro MakeDataViewGetterNameString(kind: constexpr ElementsKind): String { - if constexpr (kind == ElementsKind::UINT8_ELEMENTS) { - return 'DataView.prototype.getUint8'; - } else if constexpr (kind == ElementsKind::INT8_ELEMENTS) { - return 'DataView.prototype.getInt8'; - } else if constexpr (kind == ElementsKind::UINT16_ELEMENTS) { - return 'DataView.prototype.getUint16'; - } else if constexpr (kind == ElementsKind::INT16_ELEMENTS) { - return 'DataView.prototype.getInt16'; - } else if constexpr (kind == ElementsKind::UINT32_ELEMENTS) { - return 'DataView.prototype.getUint32'; - } else if constexpr (kind == ElementsKind::INT32_ELEMENTS) { - return 'DataView.prototype.getInt32'; - } else if constexpr (kind == ElementsKind::FLOAT32_ELEMENTS) { - return 'DataView.prototype.getFloat32'; - } else if constexpr (kind == ElementsKind::FLOAT64_ELEMENTS) { - return 'DataView.prototype.getFloat64'; - } else if constexpr (kind == ElementsKind::BIGINT64_ELEMENTS) { - return 'DataView.prototype.getBigInt64'; - } else if constexpr (kind == ElementsKind::BIGUINT64_ELEMENTS) { - return 'DataView.prototype.getBigUint64'; - } else { - unreachable; - } +macro MakeDataViewGetterNameString(kind: constexpr ElementsKind): String { + if constexpr (kind == ElementsKind::UINT8_ELEMENTS) { + return 'DataView.prototype.getUint8'; + } else if constexpr (kind == ElementsKind::INT8_ELEMENTS) { + return 'DataView.prototype.getInt8'; + } else if constexpr (kind == ElementsKind::UINT16_ELEMENTS) { + return 'DataView.prototype.getUint16'; + } else if constexpr (kind == ElementsKind::INT16_ELEMENTS) { + return 'DataView.prototype.getInt16'; + } else if constexpr (kind == ElementsKind::UINT32_ELEMENTS) { + return 'DataView.prototype.getUint32'; + } else if constexpr (kind == ElementsKind::INT32_ELEMENTS) { + return 'DataView.prototype.getInt32'; + } else if constexpr (kind == ElementsKind::FLOAT32_ELEMENTS) { + return 'DataView.prototype.getFloat32'; + } else if constexpr (kind == ElementsKind::FLOAT64_ELEMENTS) { + return 'DataView.prototype.getFloat64'; + } else if constexpr (kind == ElementsKind::BIGINT64_ELEMENTS) { + return 'DataView.prototype.getBigInt64'; + } else if constexpr (kind == ElementsKind::BIGUINT64_ELEMENTS) { + return 'DataView.prototype.getBigUint64'; + } else { + unreachable; } +} - macro MakeDataViewSetterNameString(kind: constexpr ElementsKind): String { - if constexpr (kind == ElementsKind::UINT8_ELEMENTS) { - return 'DataView.prototype.setUint8'; - } else if constexpr (kind == ElementsKind::INT8_ELEMENTS) { - return 'DataView.prototype.setInt8'; - } else if constexpr (kind == ElementsKind::UINT16_ELEMENTS) { - return 'DataView.prototype.setUint16'; - } else if constexpr (kind == ElementsKind::INT16_ELEMENTS) { - return 'DataView.prototype.setInt16'; - } else if constexpr (kind == ElementsKind::UINT32_ELEMENTS) { - return 'DataView.prototype.setUint32'; - } else if constexpr (kind == ElementsKind::INT32_ELEMENTS) { - return 'DataView.prototype.setInt32'; - } else if constexpr (kind == ElementsKind::FLOAT32_ELEMENTS) { - return 'DataView.prototype.setFloat32'; - } else if constexpr (kind == ElementsKind::FLOAT64_ELEMENTS) { - return 'DataView.prototype.setFloat64'; - } else if constexpr (kind == ElementsKind::BIGINT64_ELEMENTS) { - return 'DataView.prototype.setBigInt64'; - } else if constexpr (kind == ElementsKind::BIGUINT64_ELEMENTS) { - return 'DataView.prototype.setBigUint64'; - } else { - unreachable; - } +macro MakeDataViewSetterNameString(kind: constexpr ElementsKind): String { + if constexpr (kind == ElementsKind::UINT8_ELEMENTS) { + return 'DataView.prototype.setUint8'; + } else if constexpr (kind == ElementsKind::INT8_ELEMENTS) { + return 'DataView.prototype.setInt8'; + } else if constexpr (kind == ElementsKind::UINT16_ELEMENTS) { + return 'DataView.prototype.setUint16'; + } else if constexpr (kind == ElementsKind::INT16_ELEMENTS) { + return 'DataView.prototype.setInt16'; + } else if constexpr (kind == ElementsKind::UINT32_ELEMENTS) { + return 'DataView.prototype.setUint32'; + } else if constexpr (kind == ElementsKind::INT32_ELEMENTS) { + return 'DataView.prototype.setInt32'; + } else if constexpr (kind == ElementsKind::FLOAT32_ELEMENTS) { + return 'DataView.prototype.setFloat32'; + } else if constexpr (kind == ElementsKind::FLOAT64_ELEMENTS) { + return 'DataView.prototype.setFloat64'; + } else if constexpr (kind == ElementsKind::BIGINT64_ELEMENTS) { + return 'DataView.prototype.setBigInt64'; + } else if constexpr (kind == ElementsKind::BIGUINT64_ELEMENTS) { + return 'DataView.prototype.setBigUint64'; + } else { + unreachable; } +} - macro WasDetached(view: JSArrayBufferView): bool { - return IsDetachedBuffer(view.buffer); - } +macro WasDetached(view: JSArrayBufferView): bool { + return IsDetachedBuffer(view.buffer); +} - macro ValidateDataView(context: Context, o: JSAny, method: String): - JSDataView { - try { - return Cast(o) otherwise CastError; - } - label CastError { - ThrowTypeError(MessageTemplate::kIncompatibleMethodReceiver, method); - } +macro ValidateDataView(context: Context, o: JSAny, method: String): JSDataView { + try { + return Cast(o) otherwise CastError; + } label CastError { + ThrowTypeError(MessageTemplate::kIncompatibleMethodReceiver, method); } +} - // ES6 section 24.2.4.1 get DataView.prototype.buffer - javascript builtin DataViewPrototypeGetBuffer( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSArrayBuffer { - const dataView: JSDataView = - ValidateDataView(context, receiver, 'get DataView.prototype.buffer'); - return dataView.buffer; - } +// ES6 section 24.2.4.1 get DataView.prototype.buffer +javascript builtin DataViewPrototypeGetBuffer( + js-implicit context: NativeContext, + receiver: JSAny)(...arguments): JSArrayBuffer { + const dataView: JSDataView = + ValidateDataView(context, receiver, 'get DataView.prototype.buffer'); + return dataView.buffer; +} - // ES6 section 24.2.4.2 get DataView.prototype.byteLength - javascript builtin DataViewPrototypeGetByteLength( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): Number { - const dataView: JSDataView = ValidateDataView( - context, receiver, 'get DataView.prototype.byte_length'); - if (WasDetached(dataView)) { - // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError - // here if the JSArrayBuffer of the {dataView} was detached. - return 0; - } - return Convert(dataView.byte_length); - } +// ES6 section 24.2.4.2 get DataView.prototype.byteLength +javascript builtin DataViewPrototypeGetByteLength( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): Number { + const dataView: JSDataView = + ValidateDataView(context, receiver, 'get DataView.prototype.byte_length'); + if (WasDetached(dataView)) { + // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError + // here if the JSArrayBuffer of the {dataView} was detached. + return 0; + } + return Convert(dataView.byte_length); +} - // ES6 section 24.2.4.3 get DataView.prototype.byteOffset - javascript builtin DataViewPrototypeGetByteOffset( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): Number { - const dataView: JSDataView = ValidateDataView( - context, receiver, 'get DataView.prototype.byte_offset'); - if (WasDetached(dataView)) { - // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError - // here if the JSArrayBuffer of the {dataView} was detached. - return 0; - } - return Convert(dataView.byte_offset); - } +// ES6 section 24.2.4.3 get DataView.prototype.byteOffset +javascript builtin DataViewPrototypeGetByteOffset( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): Number { + const dataView: JSDataView = + ValidateDataView(context, receiver, 'get DataView.prototype.byte_offset'); + if (WasDetached(dataView)) { + // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError + // here if the JSArrayBuffer of the {dataView} was detached. + return 0; + } + return Convert(dataView.byte_offset); +} - extern macro BitcastInt32ToFloat32(uint32): float32; - extern macro BitcastFloat32ToInt32(float32): uint32; - extern macro Float64ExtractLowWord32(float64): uint32; - extern macro Float64ExtractHighWord32(float64): uint32; - extern macro Float64InsertLowWord32(float64, uint32): float64; - extern macro Float64InsertHighWord32(float64, uint32): float64; +extern macro BitcastInt32ToFloat32(uint32): float32; +extern macro BitcastFloat32ToInt32(float32): uint32; +extern macro Float64ExtractLowWord32(float64): uint32; +extern macro Float64ExtractHighWord32(float64): uint32; +extern macro Float64InsertLowWord32(float64, uint32): float64; +extern macro Float64InsertHighWord32(float64, uint32): float64; - extern macro DataViewBuiltinsAssembler::LoadUint8(RawPtr, uintptr): uint32; - extern macro DataViewBuiltinsAssembler::LoadInt8(RawPtr, uintptr): int32; +extern macro DataViewBuiltinsAssembler::LoadUint8(RawPtr, uintptr): uint32; +extern macro DataViewBuiltinsAssembler::LoadInt8(RawPtr, uintptr): int32; - macro LoadDataView8( - buffer: JSArrayBuffer, offset: uintptr, signed: constexpr bool): Smi { - if constexpr (signed) { - return Convert(LoadInt8(buffer.backing_store, offset)); - } else { - return Convert(LoadUint8(buffer.backing_store, offset)); - } +macro LoadDataView8( + buffer: JSArrayBuffer, offset: uintptr, signed: constexpr bool): Smi { + if constexpr (signed) { + return Convert(LoadInt8(buffer.backing_store_ptr, offset)); + } else { + return Convert(LoadUint8(buffer.backing_store_ptr, offset)); } +} - macro LoadDataView16( - buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool, - signed: constexpr bool): Number { - const dataPointer: RawPtr = buffer.backing_store; +macro LoadDataView16( + buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool, + signed: constexpr bool): Number { + const dataPointer: RawPtr = buffer.backing_store_ptr; + + let b0: int32; + let b1: int32; + let result: int32; + + // Sign-extend the most significant byte by loading it as an Int8. + if (requestedLittleEndian) { + b0 = Signed(LoadUint8(dataPointer, offset)); + b1 = LoadInt8(dataPointer, offset + 1); + result = (b1 << 8) + b0; + } else { + b0 = LoadInt8(dataPointer, offset); + b1 = Signed(LoadUint8(dataPointer, offset + 1)); + result = (b0 << 8) + b1; + } + if constexpr (signed) { + return Convert(result); + } else { + // Bit-mask the higher bits to prevent sign extension if we're unsigned. + return Convert(result & 0xFFFF); + } +} - let b0: int32; - let b1: int32; - let result: int32; +macro LoadDataView32( + buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool, + kind: constexpr ElementsKind): Number { + const dataPointer: RawPtr = buffer.backing_store_ptr; - // Sign-extend the most significant byte by loading it as an Int8. - if (requestedLittleEndian) { - b0 = Signed(LoadUint8(dataPointer, offset)); - b1 = LoadInt8(dataPointer, offset + 1); - result = (b1 << 8) + b0; - } else { - b0 = LoadInt8(dataPointer, offset); - b1 = Signed(LoadUint8(dataPointer, offset + 1)); - result = (b0 << 8) + b1; - } - if constexpr (signed) { - return Convert(result); - } else { - // Bit-mask the higher bits to prevent sign extension if we're unsigned. - return Convert(result & 0xFFFF); - } + const b0: uint32 = LoadUint8(dataPointer, offset); + const b1: uint32 = LoadUint8(dataPointer, offset + 1); + const b2: uint32 = LoadUint8(dataPointer, offset + 2); + const b3: uint32 = LoadUint8(dataPointer, offset + 3); + let result: uint32; + + if (requestedLittleEndian) { + result = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; + } else { + result = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; } - macro LoadDataView32( - buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool, - kind: constexpr ElementsKind): Number { - const dataPointer: RawPtr = buffer.backing_store; + if constexpr (kind == ElementsKind::INT32_ELEMENTS) { + return Convert(Signed(result)); + } else if constexpr (kind == ElementsKind::UINT32_ELEMENTS) { + return Convert(result); + } else if constexpr (kind == ElementsKind::FLOAT32_ELEMENTS) { + const floatRes: float64 = Convert(BitcastInt32ToFloat32(result)); + return Convert(floatRes); + } else { + unreachable; + } +} - const b0: uint32 = LoadUint8(dataPointer, offset); - const b1: uint32 = LoadUint8(dataPointer, offset + 1); - const b2: uint32 = LoadUint8(dataPointer, offset + 2); - const b3: uint32 = LoadUint8(dataPointer, offset + 3); - let result: uint32; +macro LoadDataViewFloat64( + buffer: JSArrayBuffer, offset: uintptr, + requestedLittleEndian: bool): Number { + const dataPointer: RawPtr = buffer.backing_store_ptr; + + const b0: uint32 = LoadUint8(dataPointer, offset); + const b1: uint32 = LoadUint8(dataPointer, offset + 1); + const b2: uint32 = LoadUint8(dataPointer, offset + 2); + const b3: uint32 = LoadUint8(dataPointer, offset + 3); + const b4: uint32 = LoadUint8(dataPointer, offset + 4); + const b5: uint32 = LoadUint8(dataPointer, offset + 5); + const b6: uint32 = LoadUint8(dataPointer, offset + 6); + const b7: uint32 = LoadUint8(dataPointer, offset + 7); + let lowWord: uint32; + let highWord: uint32; + + if (requestedLittleEndian) { + lowWord = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; + highWord = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4; + } else { + highWord = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; + lowWord = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; + } + + let result: float64 = 0; + result = Float64InsertLowWord32(result, lowWord); + result = Float64InsertHighWord32(result, highWord); + + return Convert(result); +} - if (requestedLittleEndian) { - result = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; - } else { - result = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; - } +const kZeroDigitBigInt: constexpr int31 = 0; +const kOneDigitBigInt: constexpr int31 = 1; +const kTwoDigitBigInt: constexpr int31 = 2; - if constexpr (kind == ElementsKind::INT32_ELEMENTS) { - return Convert(Signed(result)); - } else if constexpr (kind == ElementsKind::UINT32_ELEMENTS) { - return Convert(result); - } else if constexpr (kind == ElementsKind::FLOAT32_ELEMENTS) { - const floatRes: float64 = Convert(BitcastInt32ToFloat32(result)); - return Convert(floatRes); - } else { - unreachable; - } +// Create a BigInt on a 64-bit architecture from two 32-bit values. +macro MakeBigIntOn64Bit(implicit context: Context)( + lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt { + // 0n is represented by a zero-length BigInt. + if (lowWord == 0 && highWord == 0) { + return Convert(bigint::AllocateBigInt(kZeroDigitBigInt)); } - macro LoadDataViewFloat64( - buffer: JSArrayBuffer, offset: uintptr, - requestedLittleEndian: bool): Number { - const dataPointer: RawPtr = buffer.backing_store; - - const b0: uint32 = LoadUint8(dataPointer, offset); - const b1: uint32 = LoadUint8(dataPointer, offset + 1); - const b2: uint32 = LoadUint8(dataPointer, offset + 2); - const b3: uint32 = LoadUint8(dataPointer, offset + 3); - const b4: uint32 = LoadUint8(dataPointer, offset + 4); - const b5: uint32 = LoadUint8(dataPointer, offset + 5); - const b6: uint32 = LoadUint8(dataPointer, offset + 6); - const b7: uint32 = LoadUint8(dataPointer, offset + 7); - let lowWord: uint32; - let highWord: uint32; - - if (requestedLittleEndian) { - lowWord = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; - highWord = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4; - } else { - highWord = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; - lowWord = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; + let sign: uint32 = bigint::kPositiveSign; + const highPart: intptr = Signed(Convert(highWord)); + const lowPart: intptr = Signed(Convert(lowWord)); + let rawValue: intptr = (highPart << 32) + lowPart; + + if constexpr (signed) { + if (rawValue < 0) { + sign = bigint::kNegativeSign; + // We have to store the absolute value of rawValue in the digit. + rawValue = 0 - rawValue; } + } - let result: float64 = 0; - result = Float64InsertLowWord32(result, lowWord); - result = Float64InsertHighWord32(result, highWord); + // Allocate the BigInt and store the absolute value. + const result: MutableBigInt = + bigint::AllocateEmptyBigInt(sign, kOneDigitBigInt); + bigint::StoreBigIntDigit(result, 0, Unsigned(rawValue)); + return Convert(result); +} - return Convert(result); +// Create a BigInt on a 32-bit architecture from two 32-bit values. +macro MakeBigIntOn32Bit(implicit context: Context)( + lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt { + // 0n is represented by a zero-length BigInt. + if (lowWord == 0 && highWord == 0) { + return Convert(bigint::AllocateBigInt(kZeroDigitBigInt)); } - const kZeroDigitBigInt: constexpr int31 = 0; - const kOneDigitBigInt: constexpr int31 = 1; - const kTwoDigitBigInt: constexpr int31 = 2; - - // Create a BigInt on a 64-bit architecture from two 32-bit values. - macro MakeBigIntOn64Bit(implicit context: Context)( - lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt { - // 0n is represented by a zero-length BigInt. - if (lowWord == 0 && highWord == 0) { - return Convert(bigint::AllocateBigInt(kZeroDigitBigInt)); - } + // On a 32-bit platform, we might need 1 or 2 digits to store the number. + let needTwoDigits: bool = false; + let sign: uint32 = bigint::kPositiveSign; - let sign: uint32 = bigint::kPositiveSign; - const highPart: intptr = Signed(Convert(highWord)); - const lowPart: intptr = Signed(Convert(lowWord)); - let rawValue: intptr = (highPart << 32) + lowPart; + // We need to do some math on lowWord and highWord, + // so Convert them to int32. + let lowPart: int32 = Signed(lowWord); + let highPart: int32 = Signed(highWord); + // If highWord == 0, the number is positive, and we only need 1 digit, + // so we don't have anything to do. + // Otherwise, all cases are possible. + if (highWord != 0) { if constexpr (signed) { - if (rawValue < 0) { + // If highPart < 0, the number is always negative. + if (highPart < 0) { sign = bigint::kNegativeSign; - // We have to store the absolute value of rawValue in the digit. - rawValue = 0 - rawValue; - } - } - // Allocate the BigInt and store the absolute value. - const result: MutableBigInt = - bigint::AllocateEmptyBigInt(sign, kOneDigitBigInt); - bigint::StoreBigIntDigit(result, 0, Unsigned(rawValue)); - return Convert(result); - } - - // Create a BigInt on a 32-bit architecture from two 32-bit values. - macro MakeBigIntOn32Bit(implicit context: Context)( - lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt { - // 0n is represented by a zero-length BigInt. - if (lowWord == 0 && highWord == 0) { - return Convert(bigint::AllocateBigInt(kZeroDigitBigInt)); - } + // We have to compute the absolute value by hand. + // There will be a negative carry from the low word + // to the high word iff low != 0. + highPart = 0 - highPart; + if (lowPart != 0) { + highPart = highPart - 1; + } + lowPart = 0 - lowPart; - // On a 32-bit platform, we might need 1 or 2 digits to store the number. - let needTwoDigits: bool = false; - let sign: uint32 = bigint::kPositiveSign; - - // We need to do some math on lowWord and highWord, - // so Convert them to int32. - let lowPart: int32 = Signed(lowWord); - let highPart: int32 = Signed(highWord); - - // If highWord == 0, the number is positive, and we only need 1 digit, - // so we don't have anything to do. - // Otherwise, all cases are possible. - if (highWord != 0) { - if constexpr (signed) { - // If highPart < 0, the number is always negative. - if (highPart < 0) { - sign = bigint::kNegativeSign; - - // We have to compute the absolute value by hand. - // There will be a negative carry from the low word - // to the high word iff low != 0. - highPart = 0 - highPart; - if (lowPart != 0) { - highPart = highPart - 1; - } - lowPart = 0 - lowPart; - - // Here, highPart could be 0 again so we might have 1 or 2 digits. - if (highPart != 0) { - needTwoDigits = true; - } - - } else { - // In this case, the number is positive, and we need 2 digits. + // Here, highPart could be 0 again so we might have 1 or 2 digits. + if (highPart != 0) { needTwoDigits = true; } } else { - // In this case, the number is positive (unsigned), - // and we need 2 digits. + // In this case, the number is positive, and we need 2 digits. needTwoDigits = true; } - } - // Allocate the BigInt with the right sign and length. - let result: MutableBigInt; - if (needTwoDigits) { - result = bigint::AllocateEmptyBigInt(sign, kTwoDigitBigInt); } else { - result = bigint::AllocateEmptyBigInt(sign, kOneDigitBigInt); - } - - // Finally, write the digit(s) to the BigInt. - bigint::StoreBigIntDigit(result, 0, Unsigned(Convert(lowPart))); - if (needTwoDigits) { - bigint::StoreBigIntDigit(result, 1, Unsigned(Convert(highPart))); + // In this case, the number is positive (unsigned), + // and we need 2 digits. + needTwoDigits = true; } - return Convert(result); } - macro MakeBigInt(implicit context: Context)( - lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt { - // A BigInt digit has the platform word size, so we only need one digit - // on 64-bit platforms but may need two on 32-bit. - if constexpr (Is64()) { - return MakeBigIntOn64Bit(lowWord, highWord, signed); - } else { - return MakeBigIntOn32Bit(lowWord, highWord, signed); - } + // Allocate the BigInt with the right sign and length. + let result: MutableBigInt; + if (needTwoDigits) { + result = bigint::AllocateEmptyBigInt(sign, kTwoDigitBigInt); + } else { + result = bigint::AllocateEmptyBigInt(sign, kOneDigitBigInt); } - macro LoadDataViewBigInt(implicit context: Context)( - buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool, - signed: constexpr bool): BigInt { - const dataPointer: RawPtr = buffer.backing_store; - - const b0: uint32 = LoadUint8(dataPointer, offset); - const b1: uint32 = LoadUint8(dataPointer, offset + 1); - const b2: uint32 = LoadUint8(dataPointer, offset + 2); - const b3: uint32 = LoadUint8(dataPointer, offset + 3); - const b4: uint32 = LoadUint8(dataPointer, offset + 4); - const b5: uint32 = LoadUint8(dataPointer, offset + 5); - const b6: uint32 = LoadUint8(dataPointer, offset + 6); - const b7: uint32 = LoadUint8(dataPointer, offset + 7); - let lowWord: uint32; - let highWord: uint32; - - if (requestedLittleEndian) { - lowWord = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; - highWord = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4; - } else { - highWord = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; - lowWord = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; - } + // Finally, write the digit(s) to the BigInt. + bigint::StoreBigIntDigit(result, 0, Unsigned(Convert(lowPart))); + if (needTwoDigits) { + bigint::StoreBigIntDigit(result, 1, Unsigned(Convert(highPart))); + } + return Convert(result); +} - return MakeBigInt(lowWord, highWord, signed); +macro MakeBigInt(implicit context: Context)( + lowWord: uint32, highWord: uint32, signed: constexpr bool): BigInt { + // A BigInt digit has the platform word size, so we only need one digit + // on 64-bit platforms but may need two on 32-bit. + if constexpr (Is64()) { + return MakeBigIntOn64Bit(lowWord, highWord, signed); + } else { + return MakeBigIntOn32Bit(lowWord, highWord, signed); } +} - extern macro DataViewBuiltinsAssembler::DataViewElementSize( - constexpr ElementsKind): constexpr int31; - - // GetViewValue ( view, requestIndex, isLittleEndian, type ) - // https://tc39.es/ecma262/#sec-getviewvalue - transitioning macro DataViewGet( - context: Context, receiver: JSAny, requestIndex: JSAny, - requestedLittleEndian: JSAny, kind: constexpr ElementsKind): Numeric { - // 1. Perform ? RequireInternalSlot(view, [[DataView]]). - // 2. Assert: view has a [[ViewedArrayBuffer]] internal slot. - const dataView: JSDataView = - ValidateDataView(context, receiver, MakeDataViewGetterNameString(kind)); - - try { - // 3. Let getIndex be ? ToIndex(requestIndex). - const getIndex: uintptr = ToIndex(requestIndex) otherwise RangeError; - - // 4. Set isLittleEndian to ! ToBoolean(isLittleEndian). - const littleEndian: bool = ToBoolean(requestedLittleEndian); - - // 5. Let buffer be view.[[ViewedArrayBuffer]]. - const buffer: JSArrayBuffer = dataView.buffer; - - // 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. - if (IsDetachedBuffer(buffer)) { - ThrowTypeError( - MessageTemplate::kDetachedOperation, - MakeDataViewGetterNameString(kind)); - } +macro LoadDataViewBigInt(implicit context: Context)( + buffer: JSArrayBuffer, offset: uintptr, requestedLittleEndian: bool, + signed: constexpr bool): BigInt { + const dataPointer: RawPtr = buffer.backing_store_ptr; + + const b0: uint32 = LoadUint8(dataPointer, offset); + const b1: uint32 = LoadUint8(dataPointer, offset + 1); + const b2: uint32 = LoadUint8(dataPointer, offset + 2); + const b3: uint32 = LoadUint8(dataPointer, offset + 3); + const b4: uint32 = LoadUint8(dataPointer, offset + 4); + const b5: uint32 = LoadUint8(dataPointer, offset + 5); + const b6: uint32 = LoadUint8(dataPointer, offset + 6); + const b7: uint32 = LoadUint8(dataPointer, offset + 7); + let lowWord: uint32; + let highWord: uint32; + + if (requestedLittleEndian) { + lowWord = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; + highWord = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4; + } else { + highWord = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; + lowWord = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; + } + + return MakeBigInt(lowWord, highWord, signed); +} - // 7. Let viewOffset be view.[[ByteOffset]]. - const viewOffset: uintptr = dataView.byte_offset; - - // 8. Let viewSize be view.[[ByteLength]]. - const viewSize: uintptr = dataView.byte_length; - - // 9. Let elementSize be the Element Size value specified in Table 62 - // for Element Type type. - const elementSize: uintptr = DataViewElementSize(kind); - - // 10. If getIndex + elementSize > viewSize, throw a RangeError exception. - CheckIntegerIndexAdditionOverflow(getIndex, elementSize, viewSize) - otherwise RangeError; - - // 11. Let bufferIndex be getIndex + viewOffset. - const bufferIndex: uintptr = getIndex + viewOffset; - - if constexpr (kind == ElementsKind::UINT8_ELEMENTS) { - return LoadDataView8(buffer, bufferIndex, false); - } else if constexpr (kind == ElementsKind::INT8_ELEMENTS) { - return LoadDataView8(buffer, bufferIndex, true); - } else if constexpr (kind == ElementsKind::UINT16_ELEMENTS) { - return LoadDataView16(buffer, bufferIndex, littleEndian, false); - } else if constexpr (kind == ElementsKind::INT16_ELEMENTS) { - return LoadDataView16(buffer, bufferIndex, littleEndian, true); - } else if constexpr (kind == ElementsKind::UINT32_ELEMENTS) { - return LoadDataView32(buffer, bufferIndex, littleEndian, kind); - } else if constexpr (kind == ElementsKind::INT32_ELEMENTS) { - return LoadDataView32(buffer, bufferIndex, littleEndian, kind); - } else if constexpr (kind == ElementsKind::FLOAT32_ELEMENTS) { - return LoadDataView32(buffer, bufferIndex, littleEndian, kind); - } else if constexpr (kind == ElementsKind::FLOAT64_ELEMENTS) { - return LoadDataViewFloat64(buffer, bufferIndex, littleEndian); - } else if constexpr (kind == ElementsKind::BIGUINT64_ELEMENTS) { - return LoadDataViewBigInt(buffer, bufferIndex, littleEndian, false); - } else if constexpr (kind == ElementsKind::BIGINT64_ELEMENTS) { - return LoadDataViewBigInt(buffer, bufferIndex, littleEndian, true); - } else { - unreachable; - } +extern macro DataViewBuiltinsAssembler::DataViewElementSize( + constexpr ElementsKind): constexpr int31; + +// GetViewValue ( view, requestIndex, isLittleEndian, type ) +// https://tc39.es/ecma262/#sec-getviewvalue +transitioning macro DataViewGet( + context: Context, receiver: JSAny, requestIndex: JSAny, + requestedLittleEndian: JSAny, kind: constexpr ElementsKind): Numeric { + // 1. Perform ? RequireInternalSlot(view, [[DataView]]). + // 2. Assert: view has a [[ViewedArrayBuffer]] internal slot. + const dataView: JSDataView = + ValidateDataView(context, receiver, MakeDataViewGetterNameString(kind)); + + try { + // 3. Let getIndex be ? ToIndex(requestIndex). + const getIndex: uintptr = ToIndex(requestIndex) otherwise RangeError; + + // 4. Set isLittleEndian to ! ToBoolean(isLittleEndian). + const littleEndian: bool = ToBoolean(requestedLittleEndian); + + // 5. Let buffer be view.[[ViewedArrayBuffer]]. + const buffer: JSArrayBuffer = dataView.buffer; + + // 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. + if (IsDetachedBuffer(buffer)) { + ThrowTypeError( + MessageTemplate::kDetachedOperation, + MakeDataViewGetterNameString(kind)); } - label RangeError { - ThrowRangeError(MessageTemplate::kInvalidDataViewAccessorOffset); + + // 7. Let viewOffset be view.[[ByteOffset]]. + const viewOffset: uintptr = dataView.byte_offset; + + // 8. Let viewSize be view.[[ByteLength]]. + const viewSize: uintptr = dataView.byte_length; + + // 9. Let elementSize be the Element Size value specified in Table 62 + // for Element Type type. + const elementSize: uintptr = DataViewElementSize(kind); + + // 10. If getIndex + elementSize > viewSize, throw a RangeError exception. + CheckIntegerIndexAdditionOverflow(getIndex, elementSize, viewSize) + otherwise RangeError; + + // 11. Let bufferIndex be getIndex + viewOffset. + const bufferIndex: uintptr = getIndex + viewOffset; + + if constexpr (kind == ElementsKind::UINT8_ELEMENTS) { + return LoadDataView8(buffer, bufferIndex, false); + } else if constexpr (kind == ElementsKind::INT8_ELEMENTS) { + return LoadDataView8(buffer, bufferIndex, true); + } else if constexpr (kind == ElementsKind::UINT16_ELEMENTS) { + return LoadDataView16(buffer, bufferIndex, littleEndian, false); + } else if constexpr (kind == ElementsKind::INT16_ELEMENTS) { + return LoadDataView16(buffer, bufferIndex, littleEndian, true); + } else if constexpr (kind == ElementsKind::UINT32_ELEMENTS) { + return LoadDataView32(buffer, bufferIndex, littleEndian, kind); + } else if constexpr (kind == ElementsKind::INT32_ELEMENTS) { + return LoadDataView32(buffer, bufferIndex, littleEndian, kind); + } else if constexpr (kind == ElementsKind::FLOAT32_ELEMENTS) { + return LoadDataView32(buffer, bufferIndex, littleEndian, kind); + } else if constexpr (kind == ElementsKind::FLOAT64_ELEMENTS) { + return LoadDataViewFloat64(buffer, bufferIndex, littleEndian); + } else if constexpr (kind == ElementsKind::BIGUINT64_ELEMENTS) { + return LoadDataViewBigInt(buffer, bufferIndex, littleEndian, false); + } else if constexpr (kind == ElementsKind::BIGINT64_ELEMENTS) { + return LoadDataViewBigInt(buffer, bufferIndex, littleEndian, true); + } else { + unreachable; } + } label RangeError { + ThrowRangeError(MessageTemplate::kInvalidDataViewAccessorOffset); } +} - transitioning javascript builtin DataViewPrototypeGetUint8( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - return DataViewGet( - context, receiver, offset, Undefined, ElementsKind::UINT8_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeGetUint8( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + return DataViewGet( + context, receiver, offset, Undefined, ElementsKind::UINT8_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeGetInt8( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - return DataViewGet( - context, receiver, offset, Undefined, ElementsKind::INT8_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeGetInt8( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + return DataViewGet( + context, receiver, offset, Undefined, ElementsKind::INT8_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeGetUint16( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 1 ? arguments[1] : Undefined; - return DataViewGet( - context, receiver, offset, isLittleEndian, - ElementsKind::UINT16_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeGetUint16( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const isLittleEndian: JSAny = arguments[1]; + return DataViewGet( + context, receiver, offset, isLittleEndian, ElementsKind::UINT16_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeGetInt16( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 1 ? arguments[1] : Undefined; - return DataViewGet( - context, receiver, offset, isLittleEndian, - ElementsKind::INT16_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeGetInt16( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const isLittleEndian: JSAny = arguments[1]; + return DataViewGet( + context, receiver, offset, isLittleEndian, ElementsKind::INT16_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeGetUint32( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 1 ? arguments[1] : Undefined; - return DataViewGet( - context, receiver, offset, isLittleEndian, - ElementsKind::UINT32_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeGetUint32( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const isLittleEndian: JSAny = arguments[1]; + return DataViewGet( + context, receiver, offset, isLittleEndian, ElementsKind::UINT32_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeGetInt32( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 1 ? arguments[1] : Undefined; - return DataViewGet( - context, receiver, offset, isLittleEndian, - ElementsKind::INT32_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeGetInt32( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const isLittleEndian: JSAny = arguments[1]; + return DataViewGet( + context, receiver, offset, isLittleEndian, ElementsKind::INT32_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeGetFloat32( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 1 ? arguments[1] : Undefined; - return DataViewGet( - context, receiver, offset, isLittleEndian, - ElementsKind::FLOAT32_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeGetFloat32( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const isLittleEndian: JSAny = arguments[1]; + return DataViewGet( + context, receiver, offset, isLittleEndian, + ElementsKind::FLOAT32_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeGetFloat64( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 1 ? arguments[1] : Undefined; - return DataViewGet( - context, receiver, offset, isLittleEndian, - ElementsKind::FLOAT64_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeGetFloat64( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const isLittleEndian: JSAny = arguments[1]; + return DataViewGet( + context, receiver, offset, isLittleEndian, + ElementsKind::FLOAT64_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeGetBigUint64( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 1 ? arguments[1] : Undefined; - return DataViewGet( - context, receiver, offset, isLittleEndian, - ElementsKind::BIGUINT64_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeGetBigUint64( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const isLittleEndian: JSAny = arguments[1]; + return DataViewGet( + context, receiver, offset, isLittleEndian, + ElementsKind::BIGUINT64_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeGetBigInt64( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 1 ? arguments[1] : Undefined; - return DataViewGet( - context, receiver, offset, isLittleEndian, - ElementsKind::BIGINT64_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeGetBigInt64( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const isLittleEndian: JSAny = arguments[1]; + return DataViewGet( + context, receiver, offset, isLittleEndian, + ElementsKind::BIGINT64_ELEMENTS); +} - extern macro ToNumber(Context, JSAny): Number; - extern macro ToBigInt(Context, JSAny): BigInt; - extern macro TruncateFloat64ToWord32(float64): uint32; +extern macro ToNumber(Context, JSAny): Number; +extern macro ToBigInt(Context, JSAny): BigInt; +extern macro TruncateFloat64ToWord32(float64): uint32; - extern macro DataViewBuiltinsAssembler::StoreWord8(RawPtr, uintptr, uint32): - void; +extern macro DataViewBuiltinsAssembler::StoreWord8( + RawPtr, uintptr, uint32): void; - macro StoreDataView8(buffer: JSArrayBuffer, offset: uintptr, value: uint32) { - StoreWord8(buffer.backing_store, offset, value & 0xFF); - } +macro StoreDataView8(buffer: JSArrayBuffer, offset: uintptr, value: uint32) { + StoreWord8(buffer.backing_store_ptr, offset, value & 0xFF); +} - macro StoreDataView16( - buffer: JSArrayBuffer, offset: uintptr, value: uint32, - requestedLittleEndian: bool) { - const dataPointer: RawPtr = buffer.backing_store; +macro StoreDataView16( + buffer: JSArrayBuffer, offset: uintptr, value: uint32, + requestedLittleEndian: bool) { + const dataPointer: RawPtr = buffer.backing_store_ptr; - const b0: uint32 = value & 0xFF; - const b1: uint32 = (value >>> 8) & 0xFF; + const b0: uint32 = value & 0xFF; + const b1: uint32 = (value >>> 8) & 0xFF; - if (requestedLittleEndian) { - StoreWord8(dataPointer, offset, b0); - StoreWord8(dataPointer, offset + 1, b1); - } else { - StoreWord8(dataPointer, offset, b1); - StoreWord8(dataPointer, offset + 1, b0); - } + if (requestedLittleEndian) { + StoreWord8(dataPointer, offset, b0); + StoreWord8(dataPointer, offset + 1, b1); + } else { + StoreWord8(dataPointer, offset, b1); + StoreWord8(dataPointer, offset + 1, b0); } +} - macro StoreDataView32( - buffer: JSArrayBuffer, offset: uintptr, value: uint32, - requestedLittleEndian: bool) { - const dataPointer: RawPtr = buffer.backing_store; - - const b0: uint32 = value & 0xFF; - const b1: uint32 = (value >>> 8) & 0xFF; - const b2: uint32 = (value >>> 16) & 0xFF; - const b3: uint32 = value >>> 24; // We don't need to mask here. - - if (requestedLittleEndian) { - StoreWord8(dataPointer, offset, b0); - StoreWord8(dataPointer, offset + 1, b1); - StoreWord8(dataPointer, offset + 2, b2); - StoreWord8(dataPointer, offset + 3, b3); - } else { - StoreWord8(dataPointer, offset, b3); - StoreWord8(dataPointer, offset + 1, b2); - StoreWord8(dataPointer, offset + 2, b1); - StoreWord8(dataPointer, offset + 3, b0); - } +macro StoreDataView32( + buffer: JSArrayBuffer, offset: uintptr, value: uint32, + requestedLittleEndian: bool) { + const dataPointer: RawPtr = buffer.backing_store_ptr; + + const b0: uint32 = value & 0xFF; + const b1: uint32 = (value >>> 8) & 0xFF; + const b2: uint32 = (value >>> 16) & 0xFF; + const b3: uint32 = value >>> 24; // We don't need to mask here. + + if (requestedLittleEndian) { + StoreWord8(dataPointer, offset, b0); + StoreWord8(dataPointer, offset + 1, b1); + StoreWord8(dataPointer, offset + 2, b2); + StoreWord8(dataPointer, offset + 3, b3); + } else { + StoreWord8(dataPointer, offset, b3); + StoreWord8(dataPointer, offset + 1, b2); + StoreWord8(dataPointer, offset + 2, b1); + StoreWord8(dataPointer, offset + 3, b0); } +} - macro StoreDataView64( - buffer: JSArrayBuffer, offset: uintptr, lowWord: uint32, highWord: uint32, - requestedLittleEndian: bool) { - const dataPointer: RawPtr = buffer.backing_store; - - const b0: uint32 = lowWord & 0xFF; - const b1: uint32 = (lowWord >>> 8) & 0xFF; - const b2: uint32 = (lowWord >>> 16) & 0xFF; - const b3: uint32 = lowWord >>> 24; - - const b4: uint32 = highWord & 0xFF; - const b5: uint32 = (highWord >>> 8) & 0xFF; - const b6: uint32 = (highWord >>> 16) & 0xFF; - const b7: uint32 = highWord >>> 24; - - if (requestedLittleEndian) { - StoreWord8(dataPointer, offset, b0); - StoreWord8(dataPointer, offset + 1, b1); - StoreWord8(dataPointer, offset + 2, b2); - StoreWord8(dataPointer, offset + 3, b3); - StoreWord8(dataPointer, offset + 4, b4); - StoreWord8(dataPointer, offset + 5, b5); - StoreWord8(dataPointer, offset + 6, b6); - StoreWord8(dataPointer, offset + 7, b7); - } else { - StoreWord8(dataPointer, offset, b7); - StoreWord8(dataPointer, offset + 1, b6); - StoreWord8(dataPointer, offset + 2, b5); - StoreWord8(dataPointer, offset + 3, b4); - StoreWord8(dataPointer, offset + 4, b3); - StoreWord8(dataPointer, offset + 5, b2); - StoreWord8(dataPointer, offset + 6, b1); - StoreWord8(dataPointer, offset + 7, b0); - } +macro StoreDataView64( + buffer: JSArrayBuffer, offset: uintptr, lowWord: uint32, highWord: uint32, + requestedLittleEndian: bool) { + const dataPointer: RawPtr = buffer.backing_store_ptr; + + const b0: uint32 = lowWord & 0xFF; + const b1: uint32 = (lowWord >>> 8) & 0xFF; + const b2: uint32 = (lowWord >>> 16) & 0xFF; + const b3: uint32 = lowWord >>> 24; + + const b4: uint32 = highWord & 0xFF; + const b5: uint32 = (highWord >>> 8) & 0xFF; + const b6: uint32 = (highWord >>> 16) & 0xFF; + const b7: uint32 = highWord >>> 24; + + if (requestedLittleEndian) { + StoreWord8(dataPointer, offset, b0); + StoreWord8(dataPointer, offset + 1, b1); + StoreWord8(dataPointer, offset + 2, b2); + StoreWord8(dataPointer, offset + 3, b3); + StoreWord8(dataPointer, offset + 4, b4); + StoreWord8(dataPointer, offset + 5, b5); + StoreWord8(dataPointer, offset + 6, b6); + StoreWord8(dataPointer, offset + 7, b7); + } else { + StoreWord8(dataPointer, offset, b7); + StoreWord8(dataPointer, offset + 1, b6); + StoreWord8(dataPointer, offset + 2, b5); + StoreWord8(dataPointer, offset + 3, b4); + StoreWord8(dataPointer, offset + 4, b3); + StoreWord8(dataPointer, offset + 5, b2); + StoreWord8(dataPointer, offset + 6, b1); + StoreWord8(dataPointer, offset + 7, b0); } +} - extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntLength( - BigIntBase): uint32; - extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntSign(BigIntBase): - uint32; - - // We might get here a BigInt that is bigger than 64 bits, but we're only - // interested in the 64 lowest ones. This means the lowest BigInt digit - // on 64-bit platforms, and the 2 lowest BigInt digits on 32-bit ones. - macro StoreDataViewBigInt( - buffer: JSArrayBuffer, offset: uintptr, bigIntValue: BigInt, - requestedLittleEndian: bool) { - const length: uint32 = DataViewDecodeBigIntLength(bigIntValue); - const sign: uint32 = DataViewDecodeBigIntSign(bigIntValue); - - // The 32-bit words that will hold the BigInt's value in - // two's complement representation. - let lowWord: uint32 = 0; - let highWord: uint32 = 0; - - // The length is nonzero if and only if the BigInt's value is nonzero. - if (length != 0) { - if constexpr (Is64()) { - // There is always exactly 1 BigInt digit to load in this case. - const value: uintptr = bigint::LoadBigIntDigit(bigIntValue, 0); - lowWord = Convert(value); // Truncates value to 32 bits. - highWord = Convert(value >>> 32); - } else { // There might be either 1 or 2 BigInt digits we need to load. - lowWord = Convert(bigint::LoadBigIntDigit(bigIntValue, 0)); - if (length >= 2) { // Only load the second digit if there is one. - highWord = Convert(bigint::LoadBigIntDigit(bigIntValue, 1)); - } +extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntLength(BigIntBase): + uint32; +extern macro DataViewBuiltinsAssembler::DataViewDecodeBigIntSign(BigIntBase): + uint32; + +// We might get here a BigInt that is bigger than 64 bits, but we're only +// interested in the 64 lowest ones. This means the lowest BigInt digit +// on 64-bit platforms, and the 2 lowest BigInt digits on 32-bit ones. +macro StoreDataViewBigInt( + buffer: JSArrayBuffer, offset: uintptr, bigIntValue: BigInt, + requestedLittleEndian: bool) { + const length: uint32 = DataViewDecodeBigIntLength(bigIntValue); + const sign: uint32 = DataViewDecodeBigIntSign(bigIntValue); + + // The 32-bit words that will hold the BigInt's value in + // two's complement representation. + let lowWord: uint32 = 0; + let highWord: uint32 = 0; + + // The length is nonzero if and only if the BigInt's value is nonzero. + if (length != 0) { + if constexpr (Is64()) { + // There is always exactly 1 BigInt digit to load in this case. + const value: uintptr = bigint::LoadBigIntDigit(bigIntValue, 0); + lowWord = Convert(value); // Truncates value to 32 bits. + highWord = Convert(value >>> 32); + } else { // There might be either 1 or 2 BigInt digits we need to load. + lowWord = Convert(bigint::LoadBigIntDigit(bigIntValue, 0)); + if (length >= 2) { // Only load the second digit if there is one. + highWord = Convert(bigint::LoadBigIntDigit(bigIntValue, 1)); } } + } - if (sign != 0) { // The number is negative, Convert it. - highWord = Unsigned(0 - Signed(highWord)); - if (lowWord != 0) { - highWord = Unsigned(Signed(highWord) - 1); - } - lowWord = Unsigned(0 - Signed(lowWord)); + if (sign != 0) { // The number is negative, Convert it. + highWord = Unsigned(0 - Signed(highWord)); + if (lowWord != 0) { + highWord = Unsigned(Signed(highWord) - 1); } - - StoreDataView64(buffer, offset, lowWord, highWord, requestedLittleEndian); + lowWord = Unsigned(0 - Signed(lowWord)); } - // SetViewValue ( view, requestIndex, isLittleEndian, type, value ) - // https://tc39.es/ecma262/#sec-setviewvalue - transitioning macro DataViewSet( - context: Context, receiver: JSAny, requestIndex: JSAny, value: JSAny, - requestedLittleEndian: JSAny, kind: constexpr ElementsKind): JSAny { - // 1. Perform ? RequireInternalSlot(view, [[DataView]]). - // 2. Assert: view has a [[ViewedArrayBuffer]] internal slot. - const dataView: JSDataView = - ValidateDataView(context, receiver, MakeDataViewSetterNameString(kind)); - - try { - // 3. Let getIndex be ? ToIndex(requestIndex). - const getIndex: uintptr = ToIndex(requestIndex) otherwise RangeError; + StoreDataView64(buffer, offset, lowWord, highWord, requestedLittleEndian); +} - const littleEndian: bool = ToBoolean(requestedLittleEndian); - const buffer: JSArrayBuffer = dataView.buffer; +// SetViewValue ( view, requestIndex, isLittleEndian, type, value ) +// https://tc39.es/ecma262/#sec-setviewvalue +transitioning macro DataViewSet( + context: Context, receiver: JSAny, requestIndex: JSAny, value: JSAny, + requestedLittleEndian: JSAny, kind: constexpr ElementsKind): JSAny { + // 1. Perform ? RequireInternalSlot(view, [[DataView]]). + // 2. Assert: view has a [[ViewedArrayBuffer]] internal slot. + const dataView: JSDataView = + ValidateDataView(context, receiver, MakeDataViewSetterNameString(kind)); + + try { + // 3. Let getIndex be ? ToIndex(requestIndex). + const getIndex: uintptr = ToIndex(requestIndex) otherwise RangeError; + + const littleEndian: bool = ToBoolean(requestedLittleEndian); + const buffer: JSArrayBuffer = dataView.buffer; + + let numberValue: Numeric; + if constexpr ( + kind == ElementsKind::BIGUINT64_ELEMENTS || + kind == ElementsKind::BIGINT64_ELEMENTS) { + // 4. If ! IsBigIntElementType(type) is true, let numberValue be + // ? ToBigInt(value). + numberValue = ToBigInt(context, value); + } else { + // 5. Otherwise, let numberValue be ? ToNumber(value). + numberValue = ToNumber(context, value); + } - let numberValue: Numeric; - if constexpr ( - kind == ElementsKind::BIGUINT64_ELEMENTS || - kind == ElementsKind::BIGINT64_ELEMENTS) { - // 4. If ! IsBigIntElementType(type) is true, let numberValue be - // ? ToBigInt(value). - numberValue = ToBigInt(context, value); - } else { - // 5. Otherwise, let numberValue be ? ToNumber(value). - numberValue = ToNumber(context, value); - } + // 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. + if (IsDetachedBuffer(buffer)) { + ThrowTypeError( + MessageTemplate::kDetachedOperation, + MakeDataViewSetterNameString(kind)); + } - // 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. - if (IsDetachedBuffer(buffer)) { - ThrowTypeError( - MessageTemplate::kDetachedOperation, - MakeDataViewSetterNameString(kind)); - } + // 9. Let viewOffset be view.[[ByteOffset]]. + const viewOffset: uintptr = dataView.byte_offset; - // 9. Let viewOffset be view.[[ByteOffset]]. - const viewOffset: uintptr = dataView.byte_offset; + // 10. Let viewSize be view.[[ByteLength]]. + const viewSize: uintptr = dataView.byte_length; - // 10. Let viewSize be view.[[ByteLength]]. - const viewSize: uintptr = dataView.byte_length; + // 11. Let elementSize be the Element Size value specified in Table 62 + // for Element Type type. + const elementSize: uintptr = DataViewElementSize(kind); - // 11. Let elementSize be the Element Size value specified in Table 62 - // for Element Type type. - const elementSize: uintptr = DataViewElementSize(kind); + // 12. If getIndex + elementSize > viewSize, throw a RangeError exception. + CheckIntegerIndexAdditionOverflow(getIndex, elementSize, viewSize) + otherwise RangeError; - // 12. If getIndex + elementSize > viewSize, throw a RangeError exception. - CheckIntegerIndexAdditionOverflow(getIndex, elementSize, viewSize) - otherwise RangeError; + // 13. Let bufferIndex be getIndex + viewOffset. + const bufferIndex: uintptr = getIndex + viewOffset; - // 13. Let bufferIndex be getIndex + viewOffset. - const bufferIndex: uintptr = getIndex + viewOffset; + if constexpr ( + kind == ElementsKind::BIGUINT64_ELEMENTS || + kind == ElementsKind::BIGINT64_ELEMENTS) { + // For these elements kinds numberValue is BigInt. + const bigIntValue: BigInt = %RawDownCast(numberValue); + StoreDataViewBigInt(buffer, bufferIndex, bigIntValue, littleEndian); + } else { + // For these elements kinds numberValue is Number. + const numValue: Number = %RawDownCast(numberValue); + const doubleValue: float64 = ChangeNumberToFloat64(numValue); if constexpr ( - kind == ElementsKind::BIGUINT64_ELEMENTS || - kind == ElementsKind::BIGINT64_ELEMENTS) { - // For these elements kinds numberValue is BigInt. - const bigIntValue: BigInt = %RawDownCast(numberValue); - StoreDataViewBigInt(buffer, bufferIndex, bigIntValue, littleEndian); - } else { - // For these elements kinds numberValue is Number. - const numValue: Number = %RawDownCast(numberValue); - const doubleValue: float64 = ChangeNumberToFloat64(numValue); - - if constexpr ( - kind == ElementsKind::UINT8_ELEMENTS || - kind == ElementsKind::INT8_ELEMENTS) { - StoreDataView8( - buffer, bufferIndex, TruncateFloat64ToWord32(doubleValue)); - } else if constexpr ( - kind == ElementsKind::UINT16_ELEMENTS || - kind == ElementsKind::INT16_ELEMENTS) { - StoreDataView16( - buffer, bufferIndex, TruncateFloat64ToWord32(doubleValue), - littleEndian); - } else if constexpr ( - kind == ElementsKind::UINT32_ELEMENTS || - kind == ElementsKind::INT32_ELEMENTS) { - StoreDataView32( - buffer, bufferIndex, TruncateFloat64ToWord32(doubleValue), - littleEndian); - } else if constexpr (kind == ElementsKind::FLOAT32_ELEMENTS) { - const floatValue: float32 = TruncateFloat64ToFloat32(doubleValue); - StoreDataView32( - buffer, bufferIndex, BitcastFloat32ToInt32(floatValue), - littleEndian); - } else if constexpr (kind == ElementsKind::FLOAT64_ELEMENTS) { - const lowWord: uint32 = Float64ExtractLowWord32(doubleValue); - const highWord: uint32 = Float64ExtractHighWord32(doubleValue); - StoreDataView64(buffer, bufferIndex, lowWord, highWord, littleEndian); - } + kind == ElementsKind::UINT8_ELEMENTS || + kind == ElementsKind::INT8_ELEMENTS) { + StoreDataView8( + buffer, bufferIndex, TruncateFloat64ToWord32(doubleValue)); + } else if constexpr ( + kind == ElementsKind::UINT16_ELEMENTS || + kind == ElementsKind::INT16_ELEMENTS) { + StoreDataView16( + buffer, bufferIndex, TruncateFloat64ToWord32(doubleValue), + littleEndian); + } else if constexpr ( + kind == ElementsKind::UINT32_ELEMENTS || + kind == ElementsKind::INT32_ELEMENTS) { + StoreDataView32( + buffer, bufferIndex, TruncateFloat64ToWord32(doubleValue), + littleEndian); + } else if constexpr (kind == ElementsKind::FLOAT32_ELEMENTS) { + const floatValue: float32 = TruncateFloat64ToFloat32(doubleValue); + StoreDataView32( + buffer, bufferIndex, BitcastFloat32ToInt32(floatValue), + littleEndian); + } else if constexpr (kind == ElementsKind::FLOAT64_ELEMENTS) { + const lowWord: uint32 = Float64ExtractLowWord32(doubleValue); + const highWord: uint32 = Float64ExtractHighWord32(doubleValue); + StoreDataView64(buffer, bufferIndex, lowWord, highWord, littleEndian); } - return Undefined; - } - label RangeError { - ThrowRangeError(MessageTemplate::kInvalidDataViewAccessorOffset); } + return Undefined; + } label RangeError { + ThrowRangeError(MessageTemplate::kInvalidDataViewAccessorOffset); } +} - transitioning javascript builtin DataViewPrototypeSetUint8( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - return DataViewSet( - context, receiver, offset, value, Undefined, - ElementsKind::UINT8_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeSetUint8( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const value: JSAny = arguments[1]; + return DataViewSet( + context, receiver, offset, value, Undefined, + ElementsKind::UINT8_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeSetInt8( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - return DataViewSet( - context, receiver, offset, value, Undefined, - ElementsKind::INT8_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeSetInt8( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const value: JSAny = arguments[1]; + return DataViewSet( + context, receiver, offset, value, Undefined, ElementsKind::INT8_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeSetUint16( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 2 ? arguments[2] : Undefined; - return DataViewSet( - context, receiver, offset, value, isLittleEndian, - ElementsKind::UINT16_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeSetUint16( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const value: JSAny = arguments[1]; + const isLittleEndian: JSAny = arguments[2]; + return DataViewSet( + context, receiver, offset, value, isLittleEndian, + ElementsKind::UINT16_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeSetInt16( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 2 ? arguments[2] : Undefined; - return DataViewSet( - context, receiver, offset, value, isLittleEndian, - ElementsKind::INT16_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeSetInt16( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const value: JSAny = arguments[1]; + const isLittleEndian: JSAny = arguments[2]; + return DataViewSet( + context, receiver, offset, value, isLittleEndian, + ElementsKind::INT16_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeSetUint32( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 2 ? arguments[2] : Undefined; - return DataViewSet( - context, receiver, offset, value, isLittleEndian, - ElementsKind::UINT32_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeSetUint32( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const value: JSAny = arguments[1]; + const isLittleEndian: JSAny = arguments[2]; + return DataViewSet( + context, receiver, offset, value, isLittleEndian, + ElementsKind::UINT32_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeSetInt32( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 2 ? arguments[2] : Undefined; - return DataViewSet( - context, receiver, offset, value, isLittleEndian, - ElementsKind::INT32_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeSetInt32( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const value: JSAny = arguments[1]; + const isLittleEndian: JSAny = arguments[2]; + return DataViewSet( + context, receiver, offset, value, isLittleEndian, + ElementsKind::INT32_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeSetFloat32( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 2 ? arguments[2] : Undefined; - return DataViewSet( - context, receiver, offset, value, isLittleEndian, - ElementsKind::FLOAT32_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeSetFloat32( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const value: JSAny = arguments[1]; + const isLittleEndian: JSAny = arguments[2]; + return DataViewSet( + context, receiver, offset, value, isLittleEndian, + ElementsKind::FLOAT32_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeSetFloat64( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 2 ? arguments[2] : Undefined; - return DataViewSet( - context, receiver, offset, value, isLittleEndian, - ElementsKind::FLOAT64_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeSetFloat64( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const value: JSAny = arguments[1]; + const isLittleEndian: JSAny = arguments[2]; + return DataViewSet( + context, receiver, offset, value, isLittleEndian, + ElementsKind::FLOAT64_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeSetBigUint64( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 2 ? arguments[2] : Undefined; - return DataViewSet( - context, receiver, offset, value, isLittleEndian, - ElementsKind::BIGUINT64_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeSetBigUint64( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const value: JSAny = arguments[1]; + const isLittleEndian: JSAny = arguments[2]; + return DataViewSet( + context, receiver, offset, value, isLittleEndian, + ElementsKind::BIGUINT64_ELEMENTS); +} - transitioning javascript builtin DataViewPrototypeSetBigInt64( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined; - const isLittleEndian: JSAny = - arguments.length > 2 ? arguments[2] : Undefined; - return DataViewSet( - context, receiver, offset, value, isLittleEndian, - ElementsKind::BIGINT64_ELEMENTS); - } +transitioning javascript builtin DataViewPrototypeSetBigInt64( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const offset: JSAny = arguments[0]; + const value: JSAny = arguments[1]; + const isLittleEndian: JSAny = arguments[2]; + return DataViewSet( + context, receiver, offset, value, isLittleEndian, + ElementsKind::BIGINT64_ELEMENTS); +} } diff --git a/deps/v8/src/builtins/finalization-registry.tq b/deps/v8/src/builtins/finalization-registry.tq new file mode 100644 index 00000000000000..143486c73768f1 --- /dev/null +++ b/deps/v8/src/builtins/finalization-registry.tq @@ -0,0 +1,105 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +namespace runtime { +extern runtime +ShrinkFinalizationRegistryUnregisterTokenMap( + Context, JSFinalizationRegistry): void; +} + +namespace weakref { +extern transitioning macro +RemoveFinalizationRegistryCellFromUnregisterTokenMap( + JSFinalizationRegistry, WeakCell): void; + +macro SplitOffTail(weakCell: WeakCell): WeakCell|Undefined { + const weakCellTail = weakCell.next; + weakCell.next = Undefined; + typeswitch (weakCellTail) { + case (Undefined): { + } + case (tailIsNowAHead: WeakCell): { + assert(tailIsNowAHead.prev == weakCell); + tailIsNowAHead.prev = Undefined; + } + } + return weakCellTail; +} + +transitioning macro +PopClearedCell(finalizationRegistry: JSFinalizationRegistry): WeakCell| + Undefined { + typeswitch (finalizationRegistry.cleared_cells) { + case (Undefined): { + return Undefined; + } + case (weakCell: WeakCell): { + assert(weakCell.prev == Undefined); + finalizationRegistry.cleared_cells = SplitOffTail(weakCell); + + // If the WeakCell has an unregister token, remove the cell from the + // unregister token linked lists and and the unregister token from + // key_map. This doesn't shrink key_map, which is done manually after + // the cleanup loop to avoid a runtime call. + if (weakCell.unregister_token != Undefined) { + RemoveFinalizationRegistryCellFromUnregisterTokenMap( + finalizationRegistry, weakCell); + } + + return weakCell; + } + } +} + +transitioning macro +FinalizationRegistryCleanupLoop(implicit context: Context)( + finalizationRegistry: JSFinalizationRegistry, callback: Callable) { + while (true) { + const weakCellHead = PopClearedCell(finalizationRegistry); + typeswitch (weakCellHead) { + case (Undefined): { + break; + } + case (weakCell: WeakCell): { + try { + Call(context, callback, Undefined, weakCell.holdings); + } catch (e) { + runtime::ShrinkFinalizationRegistryUnregisterTokenMap( + context, finalizationRegistry); + ReThrow(context, e); + } + } + } + } + + runtime::ShrinkFinalizationRegistryUnregisterTokenMap( + context, finalizationRegistry); +} + +transitioning javascript builtin +FinalizationRegistryPrototypeCleanupSome( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // 1. Let finalizationRegistry be the this value. + // + // 2. Perform ? RequireInternalSlot(finalizationRegistry, [[Cells]]). + const methodName: constexpr string = + 'FinalizationRegistry.prototype.cleanupSome'; + const finalizationRegistry = + Cast(receiver) otherwise ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, methodName, receiver); + + let callback: Callable; + if (arguments[0] != Undefined) { + // 4. If callback is not undefined and IsCallable(callback) is + // false, throw a TypeError exception. + callback = Cast(arguments[0]) otherwise ThrowTypeError( + MessageTemplate::kWeakRefsCleanupMustBeCallable, arguments[0]); + } else { + callback = finalizationRegistry.cleanup; + } + + FinalizationRegistryCleanupLoop(finalizationRegistry, callback); + return Undefined; +} +} diff --git a/deps/v8/src/builtins/growable-fixed-array-gen.cc b/deps/v8/src/builtins/growable-fixed-array-gen.cc index 487d01c060a0ec..042207bff6a6c6 100644 --- a/deps/v8/src/builtins/growable-fixed-array-gen.cc +++ b/deps/v8/src/builtins/growable-fixed-array-gen.cc @@ -33,6 +33,10 @@ void GrowableFixedArray::Push(const TNode value) { } } +TNode GrowableFixedArray::ToFixedArray() { + return ResizeFixedArray(length(), length()); +} + TNode GrowableFixedArray::ToJSArray(const TNode context) { const ElementsKind kind = PACKED_ELEMENTS; diff --git a/deps/v8/src/builtins/growable-fixed-array-gen.h b/deps/v8/src/builtins/growable-fixed-array-gen.h index 6e5d2ac7683b76..e61fce37e8d49c 100644 --- a/deps/v8/src/builtins/growable-fixed-array-gen.h +++ b/deps/v8/src/builtins/growable-fixed-array-gen.h @@ -32,6 +32,7 @@ class GrowableFixedArray : public CodeStubAssembler { void Push(const TNode value); + TNode ToFixedArray(); TNode ToJSArray(const TNode context); private: diff --git a/deps/v8/src/builtins/growable-fixed-array.tq b/deps/v8/src/builtins/growable-fixed-array.tq index 0666c39fd75e53..094e051a65acd2 100644 --- a/deps/v8/src/builtins/growable-fixed-array.tq +++ b/deps/v8/src/builtins/growable-fixed-array.tq @@ -3,44 +3,48 @@ // found in the LICENSE file. namespace growable_fixed_array { - // TODO(pwong): Support FixedTypedArrays. - struct GrowableFixedArray { - macro Push(obj: Object) { - this.EnsureCapacity(); - this.array.objects[this.length++] = obj; - } - macro ResizeFixedArray(newCapacity: intptr): FixedArray { - assert(this.length >= 0); - assert(newCapacity >= 0); - assert(newCapacity >= this.length); - const first: intptr = 0; - return ExtractFixedArray(this.array, first, this.length, newCapacity); - } - macro EnsureCapacity() { - assert(this.length <= this.capacity); - if (this.capacity == this.length) { - // Growth rate is analog to JSObject::NewElementsCapacity: - // new_capacity = (current_capacity + (current_capacity >> 1)) + 16. - this.capacity = this.capacity + (this.capacity >> 1) + 16; - this.array = this.ResizeFixedArray(this.capacity); - } - } - macro ToJSArray(implicit context: Context)(): JSArray { - const nativeContext: NativeContext = LoadNativeContext(context); - const map: Map = - LoadJSArrayElementsMap(ElementsKind::PACKED_ELEMENTS, nativeContext); - const fixedArray: FixedArray = this.ResizeFixedArray(this.length); - const lengthSmi = Convert(this.length); - return AllocateJSArray(map, fixedArray, lengthSmi); +// TODO(pwong): Support FixedTypedArrays. +struct GrowableFixedArray { + macro Push(obj: Object) { + this.EnsureCapacity(); + this.array.objects[this.length++] = obj; + } + macro ResizeFixedArray(newCapacity: intptr): FixedArray { + assert(this.length >= 0); + assert(newCapacity >= 0); + assert(newCapacity >= this.length); + const first: intptr = 0; + return ExtractFixedArray(this.array, first, this.length, newCapacity); + } + macro EnsureCapacity() { + assert(this.length <= this.capacity); + if (this.capacity == this.length) { + // Growth rate is analog to JSObject::NewElementsCapacity: + // new_capacity = (current_capacity + (current_capacity >> 1)) + 16. + this.capacity = this.capacity + (this.capacity >> 1) + 16; + this.array = this.ResizeFixedArray(this.capacity); } - - array: FixedArray; - // TODO(v8:4153): make capacity and length uintptr - capacity: intptr; - length: intptr; + } + macro ToFixedArray(): FixedArray { + return this.ResizeFixedArray(this.length); } - macro NewGrowableFixedArray(): GrowableFixedArray { - return GrowableFixedArray{array: kEmptyFixedArray, capacity: 0, length: 0}; + macro ToJSArray(implicit context: Context)(): JSArray { + const nativeContext: NativeContext = LoadNativeContext(context); + const map: Map = + LoadJSArrayElementsMap(ElementsKind::PACKED_ELEMENTS, nativeContext); + const fixedArray: FixedArray = this.ResizeFixedArray(this.length); + const lengthSmi = Convert(this.length); + return AllocateJSArray(map, fixedArray, lengthSmi); } + + array: FixedArray; + // TODO(v8:4153): make capacity and length uintptr + capacity: intptr; + length: intptr; +} + +macro NewGrowableFixedArray(): GrowableFixedArray { + return GrowableFixedArray{array: kEmptyFixedArray, capacity: 0, length: 0}; +} } diff --git a/deps/v8/src/builtins/ia32/builtins-ia32.cc b/deps/v8/src/builtins/ia32/builtins-ia32.cc index 5bea93214cc1f5..04a1fa9e0db4d9 100644 --- a/deps/v8/src/builtins/ia32/builtins-ia32.cc +++ b/deps/v8/src/builtins/ia32/builtins-ia32.cc @@ -130,31 +130,22 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { __ push(eax); __ SmiUntag(eax); +#ifdef V8_REVERSE_JSARGS + // Set up pointer to first argument (skip receiver). + __ lea(esi, Operand(ebp, StandardFrameConstants::kCallerSPOffset + + kSystemPointerSize)); + // Copy arguments to the expression stack. + __ PushArray(esi, eax, ecx); + // The receiver for the builtin/api call. + __ PushRoot(RootIndex::kTheHoleValue); +#else // The receiver for the builtin/api call. __ PushRoot(RootIndex::kTheHoleValue); - // Set up pointer to last argument. We are using esi as scratch register. __ lea(esi, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); - - // Copy arguments and receiver to the expression stack. - Label loop, entry; - __ mov(ecx, eax); - // ----------- S t a t e ------------- - // -- eax: number of arguments (untagged) - // -- edi: constructor function - // -- edx: new target - // -- esi: pointer to last argument - // -- ecx: counter - // -- sp[0*kSystemPointerSize]: the hole (receiver) - // -- sp[1*kSystemPointerSize]: number of arguments (tagged) - // -- sp[2*kSystemPointerSize]: context - // ----------------------------------- - __ jmp(&entry); - __ bind(&loop); - __ push(Operand(esi, ecx, times_system_pointer_size, 0)); - __ bind(&entry); - __ dec(ecx); - __ j(greater_equal, &loop); + // Copy arguments to the expression stack. + __ PushArray(esi, eax, ecx); +#endif // Call the function. // eax: number of arguments (untagged) @@ -254,29 +245,34 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // Restore new target. __ Pop(edx); - // Push the allocated receiver to the stack. We need two copies - // because we may have to return the original one and the calling - // conventions dictate that the called function pops the receiver. + // Push the allocated receiver to the stack. __ Push(eax); + +#ifdef V8_REVERSE_JSARGS + // We need two copies because we may have to return the original one + // and the calling conventions dictate that the called function pops the + // receiver. The second copy is pushed after the arguments, we saved in r8 + // since rax needs to store the number of arguments before + // InvokingFunction. + __ movd(xmm0, eax); + + // Set up pointer to first argument (skip receiver). + __ lea(edi, Operand(ebp, StandardFrameConstants::kCallerSPOffset + + kSystemPointerSize)); +#else + // We need two copies because we may have to return the original one + // and the calling conventions dictate that the called function pops the + // receiver. __ Push(eax); - // ----------- S t a t e ------------- - // -- edx: new target - // -- sp[0*kSystemPointerSize]: implicit receiver - // -- sp[1*kSystemPointerSize]: implicit receiver - // -- sp[2*kSystemPointerSize]: padding - // -- sp[3*kSystemPointerSize]: constructor function - // -- sp[4*kSystemPointerSize]: number of arguments (tagged) - // -- sp[5*kSystemPointerSize]: context - // ----------------------------------- + // Set up pointer to last argument. + __ lea(edi, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); +#endif // Restore argument count. __ mov(eax, Operand(ebp, ConstructFrameConstants::kLengthOffset)); __ SmiUntag(eax); - // Set up pointer to last argument. - __ lea(edi, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); - // Check if we have enough stack space to push all arguments. // Argument count in eax. Clobbers ecx. Label enough_stack_space, stack_overflow; @@ -292,27 +288,14 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ bind(&enough_stack_space); - // Copy arguments and receiver to the expression stack. - Label loop, entry; - __ mov(ecx, eax); - // ----------- S t a t e ------------- - // -- eax: number of arguments (untagged) - // -- edx: new target - // -- edi: pointer to last argument - // -- ecx: counter (tagged) - // -- sp[0*kSystemPointerSize]: implicit receiver - // -- sp[1*kSystemPointerSize]: implicit receiver - // -- sp[2*kSystemPointerSize]: padding - // -- sp[3*kSystemPointerSize]: constructor function - // -- sp[4*kSystemPointerSize]: number of arguments (tagged) - // -- sp[5*kSystemPointerSize]: context - // ----------------------------------- - __ jmp(&entry, Label::kNear); - __ bind(&loop); - __ Push(Operand(edi, ecx, times_system_pointer_size, 0)); - __ bind(&entry); - __ dec(ecx); - __ j(greater_equal, &loop); + // Copy arguments to the expression stack. + __ PushArray(edi, eax, ecx); + +#ifdef V8_REVERSE_JSARGS + // Push implicit receiver. + __ movd(ecx, xmm0); + __ Push(ecx); +#endif // Restore and and call the constructor function. __ mov(edi, Operand(ebp, ConstructFrameConstants::kConstructorOffset)); @@ -536,9 +519,13 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // Load the previous frame pointer (edx) to access C arguments __ mov(scratch1, Operand(ebp, 0)); - // Push the function and the receiver onto the stack. + // Push the function. __ push(Operand(scratch1, EntryFrameConstants::kFunctionArgOffset)); + +#ifndef V8_REVERSE_JSARGS + // And the receiver onto the stack. __ push(Operand(scratch1, EntryFrameConstants::kReceiverArgOffset)); +#endif // Load the number of arguments and setup pointer to the arguments. __ mov(eax, Operand(scratch1, EntryFrameConstants::kArgcOffset)); @@ -558,6 +545,18 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, __ bind(&enough_stack_space); // Copy arguments to the stack in a loop. +#ifdef V8_REVERSE_JSARGS + Label loop, entry; + __ Move(ecx, eax); + __ jmp(&entry, Label::kNear); + __ bind(&loop); + // Push the parameter from argv. + __ mov(scratch2, Operand(scratch1, ecx, times_system_pointer_size, 0)); + __ push(Operand(scratch2, 0)); // dereference handle + __ bind(&entry); + __ dec(ecx); + __ j(greater_equal, &loop); +#else Label loop, entry; __ Move(ecx, Immediate(0)); __ jmp(&entry, Label::kNear); @@ -569,10 +568,16 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, __ bind(&entry); __ cmp(ecx, eax); __ j(not_equal, &loop); +#endif - // Load the previous frame pointer (ebx) to access C arguments + // Load the previous frame pointer to access C arguments __ mov(scratch2, Operand(ebp, 0)); +#ifdef V8_REVERSE_JSARGS + // Push the receiver onto the stack. + __ push(Operand(scratch2, EntryFrameConstants::kReceiverArgOffset)); +#endif + // Get the new.target and function from the frame. __ mov(edx, Operand(scratch2, EntryFrameConstants::kNewTargetArgOffset)); __ mov(edi, Operand(scratch2, EntryFrameConstants::kFunctionArgOffset)); @@ -662,15 +667,17 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { // Pop return address. __ PopReturnAddressTo(eax); +#ifndef V8_REVERSE_JSARGS // Push receiver. __ Push(FieldOperand(edx, JSGeneratorObject::kReceiverOffset)); +#endif // ----------- S t a t e ------------- // -- eax : return address // -- edx : the JSGeneratorObject to resume // -- edi : generator function // -- esi : generator context - // -- esp[0] : generator receiver + // -- esp[0] : generator receiver, if V8_REVERSE_JSARGS is not set // ----------------------------------- { @@ -682,6 +689,24 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { ecx, SharedFunctionInfo::kFormalParameterCountOffset)); __ mov(ebx, FieldOperand(edx, JSGeneratorObject::kParametersAndRegistersOffset)); +#ifdef V8_REVERSE_JSARGS + { + Label done_loop, loop; + __ mov(edi, ecx); + + __ bind(&loop); + __ dec(edi); + __ j(less, &done_loop); + __ Push( + FieldOperand(ebx, edi, times_tagged_size, FixedArray::kHeaderSize)); + __ jmp(&loop); + + __ bind(&done_loop); + } + + // Push receiver. + __ Push(FieldOperand(edx, JSGeneratorObject::kReceiverOffset)); +#else { Label done_loop, loop; __ Set(edi, 0); @@ -689,13 +714,14 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { __ bind(&loop); __ cmp(edi, ecx); __ j(greater_equal, &done_loop); - __ Push(FieldOperand(ebx, edi, times_system_pointer_size, - FixedArray::kHeaderSize)); + __ Push( + FieldOperand(ebx, edi, times_tagged_size, FixedArray::kHeaderSize)); __ add(edi, Immediate(1)); __ jmp(&loop); __ bind(&done_loop); } +#endif // Restore registers. __ mov(edi, FieldOperand(edx, JSGeneratorObject::kFunctionOffset)); @@ -1211,11 +1237,19 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, Label loop_header, loop_check; __ jmp(&loop_check); __ bind(&loop_header); +#ifdef V8_REVERSE_JSARGS + __ Push(Operand(array_limit, 0)); + __ bind(&loop_check); + __ add(array_limit, Immediate(kSystemPointerSize)); + __ cmp(array_limit, start_address); + __ j(below_equal, &loop_header, Label::kNear); +#else __ Push(Operand(start_address, 0)); __ sub(start_address, Immediate(kSystemPointerSize)); __ bind(&loop_check); __ cmp(start_address, array_limit); __ j(above, &loop_header, Label::kNear); +#endif } // static @@ -1235,6 +1269,14 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl( const Register argv = ecx; Label stack_overflow; + +#ifdef V8_REVERSE_JSARGS + if (mode == InterpreterPushArgsMode::kWithFinalSpread) { + // The spread argument should not be pushed. + __ dec(eax); + } +#endif + // Add a stack check before pushing the arguments. Generate_StackOverflowCheck(masm, eax, scratch, &stack_overflow, true); @@ -1242,11 +1284,37 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl( // Compute the expected number of arguments. __ mov(scratch, eax); - __ add(scratch, Immediate(1)); // Add one for receiver. // Pop return address to allow tail-call after pushing arguments. __ PopReturnAddressTo(eax); +#ifdef V8_REVERSE_JSARGS + if (receiver_mode != ConvertReceiverMode::kNullOrUndefined) { + __ add(scratch, Immediate(1)); // Add one for receiver. + } + + // Find the address of the last argument. + __ shl(scratch, kSystemPointerSizeLog2); + __ neg(scratch); + __ add(scratch, argv); + + if (mode == InterpreterPushArgsMode::kWithFinalSpread) { + __ movd(xmm1, scratch); + Generate_InterpreterPushArgs(masm, scratch, argv); + // Pass the spread in the register ecx. + __ movd(ecx, xmm1); + __ mov(ecx, Operand(ecx, 0)); + } else { + Generate_InterpreterPushArgs(masm, scratch, argv); + } + + // Push "undefined" as the receiver arg if we need to. + if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { + __ PushRoot(RootIndex::kUndefinedValue); + } +#else + __ add(scratch, Immediate(1)); // Add one for receiver. + // Push "undefined" as the receiver arg if we need to. if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { __ PushRoot(RootIndex::kUndefinedValue); @@ -1259,18 +1327,22 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl( __ add(scratch, argv); Generate_InterpreterPushArgs(masm, scratch, argv); - // Call the target. - if (mode == InterpreterPushArgsMode::kWithFinalSpread) { __ Pop(ecx); // Pass the spread in a register - __ PushReturnAddressFrom(eax); - __ movd(eax, xmm0); // Restore number of arguments. + } +#endif + + __ PushReturnAddressFrom(eax); + __ movd(eax, xmm0); // Restore number of arguments. + + // Call the target. + if (mode == InterpreterPushArgsMode::kWithFinalSpread) { +#ifndef V8_REVERSE_JSARGS __ sub(eax, Immediate(1)); // Subtract one for spread +#endif __ Jump(BUILTIN_CODE(masm->isolate(), CallWithSpread), RelocInfo::CODE_TARGET); } else { - __ PushReturnAddressFrom(eax); - __ movd(eax, xmm0); // Restore number of arguments. __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny), RelocInfo::CODE_TARGET); } @@ -1328,6 +1400,25 @@ void Generate_InterpreterPushZeroAndArgsAndReturnAddress( // Step 3 copy arguments to correct locations. // Slot meant for receiver contains return address. Reset it so that // we will not incorrectly interpret return address as an object. +#ifdef V8_REVERSE_JSARGS + __ mov(Operand(esp, (num_slots_to_move + 1) * kSystemPointerSize), + Immediate(0)); + __ mov(scratch1, Immediate(0)); + + Label loop_header, loop_check; + __ jmp(&loop_check); + __ bind(&loop_header); + __ mov(scratch2, Operand(start_addr, 0)); + __ mov(Operand(esp, scratch1, times_system_pointer_size, + (num_slots_to_move + 1) * kSystemPointerSize), + scratch2); + __ sub(start_addr, Immediate(kSystemPointerSize)); + __ bind(&loop_check); + __ inc(scratch1); + __ cmp(scratch1, eax); + __ j(less_equal, &loop_header, Label::kNear); + +#else __ mov(Operand(esp, num_args, times_system_pointer_size, (num_slots_to_move + 1) * kSystemPointerSize), Immediate(0)); @@ -1345,6 +1436,7 @@ void Generate_InterpreterPushZeroAndArgsAndReturnAddress( __ bind(&loop_check); __ cmp(scratch1, Immediate(0)); __ j(greater, &loop_header, Label::kNear); +#endif } } // end anonymous namespace @@ -1362,9 +1454,15 @@ void Builtins::Generate_InterpreterPushArgsThenConstructImpl( // -- esp[8] : the new target // -- esp[12] : the constructor // ----------------------------------- - Label stack_overflow; +#ifdef V8_REVERSE_JSARGS + if (mode == InterpreterPushArgsMode::kWithFinalSpread) { + // The spread argument should not be pushed. + __ dec(eax); + } +#endif + // Push arguments and move return address and stack spill slots to the top of // stack. The eax register is readonly. The ecx register will be modified. edx // and edi are used as scratch registers. @@ -1399,11 +1497,17 @@ void Builtins::Generate_InterpreterPushArgsThenConstructImpl( __ Drop(1); // The allocation site is unused. __ Pop(kJavaScriptCallNewTargetRegister); __ Pop(kJavaScriptCallTargetRegister); +#ifdef V8_REVERSE_JSARGS + // Pass the spread in the register ecx, overwriting ecx. + __ mov(ecx, Operand(ecx, 0)); + __ PushReturnAddressFrom(eax); + __ movd(eax, xmm0); // Reload number of arguments. +#else __ Pop(ecx); // Pop the spread (i.e. the first argument), overwriting ecx. __ PushReturnAddressFrom(eax); __ movd(eax, xmm0); // Reload number of arguments. __ sub(eax, Immediate(1)); // The actual argc thus decrements by one. - +#endif __ Jump(BUILTIN_CODE(masm->isolate(), ConstructWithSpread), RelocInfo::CODE_TARGET); } else { @@ -1705,9 +1809,35 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { // ... // esp[8 * n] : Argument 1 // esp[8 * (n + 1)] : Receiver (callable to call) - // + // NOTE: The order of args are reversed if V8_REVERSE_JSARGS // eax contains the number of arguments, n, not counting the receiver. - // + +#ifdef V8_REVERSE_JSARGS + // 1. Get the callable to call (passed as receiver) from the stack. + { + StackArgumentsAccessor args(eax); + __ mov(edi, args.GetReceiverOperand()); + } + + // 2. Save the return address and drop the callable. + __ PopReturnAddressTo(edx); + __ Pop(ecx); + + // 3. Make sure we have at least one argument. + { + Label done; + __ test(eax, eax); + __ j(not_zero, &done, Label::kNear); + __ PushRoot(RootIndex::kUndefinedValue); + __ inc(eax); + __ bind(&done); + } + + // 4. Push back the return address one slot down on the stack (overwriting the + // original callable), making the original first argument the new receiver. + __ PushReturnAddressFrom(edx); + __ dec(eax); // One fewer argument (first argument is new receiver). +#else // 1. Make sure we have at least one argument. { Label done; @@ -1741,6 +1871,7 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { __ pop(edx); // Discard copy of return address. __ dec(eax); // One fewer argument (first argument is new receiver). } +#endif // 4. Call the callable. __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); @@ -1956,6 +2087,56 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, Label stack_overflow; Generate_StackOverflowCheck(masm, kArgumentsLength, edx, &stack_overflow); +#ifdef V8_REVERSE_JSARGS + __ movd(xmm4, kArgumentsList); // Spill the arguments list. + + // Move the arguments already in the stack, + // including the receiver and the return address. + { + Label copy, check; + Register src = edx, current = edi, tmp = esi; + // Update stack pointer. + __ mov(src, esp); + __ lea(tmp, Operand(kArgumentsLength, times_system_pointer_size, 0)); + __ AllocateStackSpace(tmp); + // Include return address and receiver. + __ add(eax, Immediate(2)); + __ mov(current, Immediate(0)); + __ jmp(&check); + // Loop. + __ bind(©); + __ mov(tmp, Operand(src, current, times_system_pointer_size, 0)); + __ mov(Operand(esp, current, times_system_pointer_size, 0), tmp); + __ inc(current); + __ bind(&check); + __ cmp(current, eax); + __ j(less, ©); + __ lea(edx, Operand(esp, eax, times_system_pointer_size, 0)); + } + + __ movd(kArgumentsList, xmm4); // Recover arguments list. + + // Push additional arguments onto the stack. + { + __ Move(eax, Immediate(0)); + Label done, push, loop; + __ bind(&loop); + __ cmp(eax, kArgumentsLength); + __ j(equal, &done, Label::kNear); + // Turn the hole into undefined as we go. + __ mov(edi, FieldOperand(kArgumentsList, eax, times_tagged_size, + FixedArray::kHeaderSize)); + __ CompareRoot(edi, RootIndex::kTheHoleValue); + __ j(not_equal, &push, Label::kNear); + __ LoadRoot(edi, RootIndex::kUndefinedValue); + __ bind(&push); + __ mov(Operand(edx, 0), edi); + __ add(edx, Immediate(kSystemPointerSize)); + __ inc(eax); + __ jmp(&loop); + __ bind(&done); + } +#else // !V8_REVERSE_JSARGS // Push additional arguments onto the stack. { __ PopReturnAddressTo(edx); @@ -1965,7 +2146,7 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, __ cmp(eax, kArgumentsLength); __ j(equal, &done, Label::kNear); // Turn the hole into undefined as we go. - __ mov(edi, FieldOperand(kArgumentsList, eax, times_system_pointer_size, + __ mov(edi, FieldOperand(kArgumentsList, eax, times_tagged_size, FixedArray::kHeaderSize)); __ CompareRoot(edi, RootIndex::kTheHoleValue); __ j(not_equal, &push, Label::kNear); @@ -1977,6 +2158,7 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, __ bind(&done); __ PushReturnAddressFrom(edx); } +#endif // !V8_REVERSE_JSARGS // Restore eax, edi and edx. __ movd(esi, xmm3); // Restore the context. @@ -2203,7 +2385,6 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { // -- edx : new.target (only in case of [[Construct]]) // -- edi : target (checked to be a JSBoundFunction) // ----------------------------------- - __ movd(xmm0, edx); // Spill edx. // Load [[BoundArguments]] into ecx and length of that into edx. @@ -2213,6 +2394,67 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { __ SmiUntag(edx); __ test(edx, edx); __ j(zero, &no_bound_arguments); +#ifdef V8_REVERSE_JSARGS + { + // ----------- S t a t e ------------- + // -- eax : the number of arguments (not including the receiver) + // -- xmm0 : new.target (only in case of [[Construct]]) + // -- edi : target (checked to be a JSBoundFunction) + // -- ecx : the [[BoundArguments]] (implemented as FixedArray) + // -- edx : the number of [[BoundArguments]] + // ----------------------------------- + + // Check the stack for overflow. + { + Label done, stack_overflow; + Generate_StackOverflowCheck(masm, edx, ecx, &stack_overflow); + __ jmp(&done); + __ bind(&stack_overflow); + { + FrameScope frame(masm, StackFrame::MANUAL); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ int3(); + } + __ bind(&done); + } + + // Spill context. + __ movd(xmm3, esi); + + // Save Return Adress and Receiver into registers. + __ pop(esi); + __ movd(xmm1, esi); + __ pop(esi); + __ movd(xmm2, esi); + + // Push [[BoundArguments]] to the stack. + { + Label loop; + __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset)); + __ mov(edx, FieldOperand(ecx, FixedArray::kLengthOffset)); + __ SmiUntag(edx); + // Adjust effective number of arguments (eax contains the number of + // arguments from the call not including receiver plus the number of + // [[BoundArguments]]). + __ add(eax, edx); + __ bind(&loop); + __ dec(edx); + __ mov(esi, FieldOperand(ecx, edx, times_tagged_size, + FixedArray::kHeaderSize)); + __ push(esi); + __ j(greater, &loop); + } + + // Restore Receiver and Return Address. + __ movd(esi, xmm2); + __ push(esi); + __ movd(esi, xmm1); + __ push(esi); + + // Restore context. + __ movd(esi, xmm3); + } +#else // !V8_REVERSE_JSARGS { // ----------- S t a t e ------------- // -- eax : the number of arguments (not including the receiver) @@ -2241,7 +2483,6 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { } __ bind(&done); } - #if V8_OS_WIN // Correctly allocate the stack space that was checked above. { @@ -2291,6 +2532,7 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { // [[BoundArguments]]), so we need to subtract one for the return address. __ dec(eax); } +#endif // !V8_REVERSE_JSARGS __ bind(&no_bound_arguments); __ movd(edx, xmm0); // Reload edx. @@ -2518,7 +2760,11 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // Copy receiver and all expected arguments. const int offset = StandardFrameConstants::kCallerSPOffset; +#ifdef V8_REVERSE_JSARGS + __ lea(edi, Operand(ebp, ecx, times_system_pointer_size, offset)); +#else __ lea(edi, Operand(ebp, eax, times_system_pointer_size, offset)); +#endif __ mov(eax, -1); // account for receiver Label copy; @@ -2543,6 +2789,35 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // Remember expected arguments in xmm0. __ movd(xmm0, kExpectedNumberOfArgumentsRegister); +#ifdef V8_REVERSE_JSARGS + // Remember new target. + __ movd(xmm1, edx); + + // Fill remaining expected arguments with undefined values. + Label fill; + __ mov(edx, ecx); + __ sub(edx, eax); + __ bind(&fill); + __ Push(Immediate(masm->isolate()->factory()->undefined_value())); + __ dec(edx); + __ j(greater, &fill); + + // Copy receiver and all actual arguments. + const int offset = StandardFrameConstants::kCallerSPOffset; + __ lea(edi, Operand(ebp, eax, times_system_pointer_size, offset)); + __ mov(edx, Immediate(-1)); + + Label copy; + __ bind(©); + __ inc(edx); + __ push(Operand(edi, 0)); + __ sub(edi, Immediate(kSystemPointerSize)); + __ cmp(edx, eax); + __ j(less, ©); + + // Restore new.target + __ movd(edx, xmm1); +#else // !V8_REVERSE_JSARGS // Copy receiver and all actual arguments. const int offset = StandardFrameConstants::kCallerSPOffset; __ lea(edi, Operand(ebp, eax, times_system_pointer_size, offset)); @@ -2567,6 +2842,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { __ Push(Immediate(masm->isolate()->factory()->undefined_value())); __ cmp(eax, kExpectedNumberOfArgumentsRegister); __ j(less, &fill); +#endif // !V8_REVERSE_JSARGS // Restore expected arguments. __ movd(eax, xmm0); @@ -3153,6 +3429,7 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) { // -- esp[argc * 4] : first argument // -- esp[(argc + 1) * 4] : receiver // ----------------------------------- + // NOTE: The order of args are reversed if V8_REVERSE_JSARGS Register api_function_address = edx; Register argc = ecx; @@ -3222,8 +3499,13 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) { // FunctionCallbackInfo::values_ (points at the first varargs argument passed // on the stack). +#ifdef V8_REVERSE_JSARGS + __ lea(scratch, + Operand(scratch, (FCA::kArgsLength + 1) * kSystemPointerSize)); +#else __ lea(scratch, Operand(scratch, argc, times_system_pointer_size, (FCA::kArgsLength - 1) * kSystemPointerSize)); +#endif __ mov(ApiParameterOperand(kApiArgc + 1), scratch); // FunctionCallbackInfo::length_. diff --git a/deps/v8/src/builtins/ic-callable.tq b/deps/v8/src/builtins/ic-callable.tq new file mode 100644 index 00000000000000..95e107a9a69f89 --- /dev/null +++ b/deps/v8/src/builtins/ic-callable.tq @@ -0,0 +1,183 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +namespace ic { +namespace callable { + +extern macro IncrementCallCount(FeedbackVector, uintptr): void; + +macro IsMonomorphic(feedback: MaybeObject, target: JSAny): bool { + return IsWeakReferenceToObject(feedback, target); +} + +macro InSameNativeContext(lhs: Context, rhs: Context): bool { + return LoadNativeContext(lhs) == LoadNativeContext(rhs); +} + +macro MaybeObjectToStrong(maybeObject: MaybeObject): + HeapObject labels IfCleared { + assert(IsWeakOrCleared(maybeObject)); + const weakObject = %RawDownCast>(maybeObject); + return WeakToStrong(weakObject) otherwise IfCleared; +} + +macro TryInitializeAsMonomorphic(implicit context: Context)( + maybeTarget: JSAny, feedbackVector: FeedbackVector, + slotId: uintptr): void labels TransitionToMegamorphic { + const targetHeapObject = + Cast(maybeTarget) otherwise TransitionToMegamorphic; + + let unwrappedTarget = targetHeapObject; + while (Is(unwrappedTarget)) { + unwrappedTarget = + UnsafeCast(unwrappedTarget).bound_target_function; + } + + const unwrappedTargetJSFunction = + Cast(unwrappedTarget) otherwise TransitionToMegamorphic; + if (!InSameNativeContext(unwrappedTargetJSFunction.context, context)) { + goto TransitionToMegamorphic; + } + + StoreWeakReferenceInFeedbackVector(feedbackVector, slotId, targetHeapObject); + ReportFeedbackUpdate(feedbackVector, slotId, 'Call:Initialize'); +} + +macro TransitionToMegamorphic(implicit context: Context)( + feedbackVector: FeedbackVector, slotId: uintptr): void { + StoreFeedbackVectorSlot(feedbackVector, slotId, kMegamorphicSymbol); + ReportFeedbackUpdate(feedbackVector, slotId, 'Call:TransitionMegamorphic'); +} + +macro CollectCallFeedback( + maybeTarget: JSAny, context: Context, + maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr): void { + const feedbackVector = + Cast(maybeFeedbackVector) otherwise return; + IncrementCallCount(feedbackVector, slotId); + + try { + const feedback: MaybeObject = + LoadFeedbackVectorSlot(feedbackVector, slotId); + if (IsMonomorphic(feedback, maybeTarget)) return; + if (IsMegamorphic(feedback)) return; + if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic; + + // If cleared, we have a new chance to become monomorphic. + const feedbackValue: HeapObject = + MaybeObjectToStrong(feedback) otherwise TryInitializeAsMonomorphic; + + // Try transitioning to a feedback cell. + // Check if {target}s feedback cell matches the {feedbackValue}. + const target = + Cast(maybeTarget) otherwise TransitionToMegamorphic; + const targetFeedbackCell: FeedbackCell = target.feedback_cell; + if (TaggedEqual(feedbackValue, targetFeedbackCell)) return; + + // Check if {target} and {feedbackValue} are both JSFunctions with + // the same feedback vector cell, and that those functions were + // actually compiled already. + const feedbackValueJSFunction = + Cast(feedbackValue) otherwise TransitionToMegamorphic; + const feedbackCell: FeedbackCell = feedbackValueJSFunction.feedback_cell; + if (!TaggedEqual(feedbackCell, targetFeedbackCell)) + goto TransitionToMegamorphic; + + StoreWeakReferenceInFeedbackVector(feedbackVector, slotId, feedbackCell); + ReportFeedbackUpdate(feedbackVector, slotId, 'Call:FeedbackVectorCell'); + } label TryInitializeAsMonomorphic { + TryInitializeAsMonomorphic(maybeTarget, feedbackVector, slotId) + otherwise TransitionToMegamorphic; + } label TransitionToMegamorphic { + TransitionToMegamorphic(feedbackVector, slotId); + } +} + +macro CollectInstanceOfFeedback( + maybeTarget: JSAny, context: Context, + maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr): void { + const feedbackVector = + Cast(maybeFeedbackVector) otherwise return; + // Note: The call count is not incremented. + + try { + const feedback: MaybeObject = + LoadFeedbackVectorSlot(feedbackVector, slotId); + if (IsMonomorphic(feedback, maybeTarget)) return; + if (IsMegamorphic(feedback)) return; + if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic; + + // If cleared, we have a new chance to become monomorphic. + const _feedbackValue: HeapObject = + MaybeObjectToStrong(feedback) otherwise TryInitializeAsMonomorphic; + + goto TransitionToMegamorphic; + } label TryInitializeAsMonomorphic { + TryInitializeAsMonomorphic(maybeTarget, feedbackVector, slotId) + otherwise TransitionToMegamorphic; + } label TransitionToMegamorphic { + TransitionToMegamorphic(feedbackVector, slotId); + } +} + +macro BothTaggedEqualArrayFunction(implicit context: Context)( + first: JSAny, second: JSAny): bool { + return TaggedEqual(first, second) && TaggedEqual(second, GetArrayFunction()); +} + +extern macro CreateAllocationSiteInFeedbackVector( + FeedbackVector, uintptr): AllocationSite; + +macro CollectConstructFeedback(implicit context: Context)( + target: JSAny, newTarget: JSAny, + maybeFeedbackVector: Undefined|FeedbackVector, + slotId: uintptr): never labels ConstructGeneric, + ConstructArray(AllocationSite) { + const feedbackVector = Cast(maybeFeedbackVector) + otherwise goto ConstructGeneric; + IncrementCallCount(feedbackVector, slotId); + + try { + const feedback: MaybeObject = + LoadFeedbackVectorSlot(feedbackVector, slotId); + if (IsMonomorphic(feedback, newTarget)) goto ConstructGeneric; + if (IsMegamorphic(feedback)) goto ConstructGeneric; + if (IsUninitialized(feedback)) goto TryInitializeAsMonomorphic; + + if (!IsWeakOrCleared(feedback)) { + const feedbackAsStrong = %RawDownCast(feedback); + if (Is(feedbackAsStrong)) { + if (BothTaggedEqualArrayFunction(target, newTarget)) { + goto ConstructArray(UnsafeCast(feedbackAsStrong)); + } + goto TransitionToMegamorphic; + } + } + + // If cleared, we have a new chance to become monomorphic. + const _feedbackValue: HeapObject = + MaybeObjectToStrong(feedback) otherwise TryInitializeAsMonomorphic; + + goto TransitionToMegamorphic; + } label TryInitializeAsMonomorphic { + if (BothTaggedEqualArrayFunction(target, newTarget)) { + // In this case we can skip unwrapping and context validation since we + // know the target is the current context's array function. + const allocationSite = + CreateAllocationSiteInFeedbackVector(feedbackVector, slotId); + ReportFeedbackUpdate( + feedbackVector, slotId, 'Construct:CreateAllocationSite'); + goto ConstructArray(allocationSite); + } + + TryInitializeAsMonomorphic(newTarget, feedbackVector, slotId) + otherwise TransitionToMegamorphic; + } label TransitionToMegamorphic { + TransitionToMegamorphic(feedbackVector, slotId); + } + goto ConstructGeneric; +} + +} // namespace callable +} // namespace ic diff --git a/deps/v8/src/builtins/ic.tq b/deps/v8/src/builtins/ic.tq new file mode 100644 index 00000000000000..f6fecc557f479f --- /dev/null +++ b/deps/v8/src/builtins/ic.tq @@ -0,0 +1,59 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +namespace ic { + +// --- The public interface (forwards to the actual implementation). + +@export +macro CollectCallFeedback( + maybeTarget: JSAny, context: Context, + maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr): void { + callable::CollectCallFeedback( + maybeTarget, context, maybeFeedbackVector, slotId); +} + +@export +macro CollectInstanceOfFeedback( + maybeTarget: JSAny, context: Context, + maybeFeedbackVector: Undefined|FeedbackVector, slotId: uintptr): void { + callable::CollectInstanceOfFeedback( + maybeTarget, context, maybeFeedbackVector, slotId); +} + +@export +macro CollectConstructFeedback(implicit context: Context)( + target: JSAny, newTarget: JSAny, + maybeFeedbackVector: Undefined|FeedbackVector, + slotId: uintptr): never labels ConstructGeneric, + ConstructArray(AllocationSite) { + callable::CollectConstructFeedback( + target, newTarget, maybeFeedbackVector, slotId) + otherwise ConstructGeneric, ConstructArray; +} + +// --- Common functionality. + +extern macro MegamorphicSymbolConstant(): Symbol; +extern macro UninitializedSymbolConstant(): Symbol; + +const kMegamorphicSymbol: Symbol = MegamorphicSymbolConstant(); +const kUninitializedSymbol: Symbol = UninitializedSymbolConstant(); + +macro IsMegamorphic(feedback: MaybeObject): bool { + return TaggedEqual(feedback, kMegamorphicSymbol); +} + +macro IsUninitialized(feedback: MaybeObject): bool { + return TaggedEqual(feedback, kUninitializedSymbol); +} + +extern macro LoadFeedbackVectorSlot(FeedbackVector, uintptr): MaybeObject; +extern macro StoreFeedbackVectorSlot( + FeedbackVector, uintptr, MaybeObject): void; +extern macro StoreWeakReferenceInFeedbackVector( + FeedbackVector, uintptr, HeapObject): MaybeObject; +extern macro ReportFeedbackUpdate(FeedbackVector, uintptr, constexpr string); + +} // namespace ic diff --git a/deps/v8/src/builtins/internal-coverage.tq b/deps/v8/src/builtins/internal-coverage.tq index 65cb207eaae8d0..07bfc40d8f277c 100644 --- a/deps/v8/src/builtins/internal-coverage.tq +++ b/deps/v8/src/builtins/internal-coverage.tq @@ -6,33 +6,34 @@ namespace internal_coverage { - macro GetCoverageInfo(implicit context: Context)(function: JSFunction): - CoverageInfo labels IfNoCoverageInfo { - const shared: SharedFunctionInfo = function.shared_function_info; - const debugInfo = Cast(shared.script_or_debug_info) - otherwise goto IfNoCoverageInfo; - - if (!SmiUntag(debugInfo.flags).has_coverage_info) goto IfNoCoverageInfo; - return UnsafeCast(debugInfo.coverage_info); - } - - macro IncrementBlockCount(implicit context: Context)( - coverageInfo: CoverageInfo, slot: Smi) { - assert(Convert(slot) < coverageInfo.slot_count); - ++coverageInfo.slots[slot].block_count; - } - - builtin IncBlockCounter(implicit context: Context)( - function: JSFunction, coverageArraySlotIndex: Smi): Undefined { - // It's quite possible that a function contains IncBlockCounter bytecodes, - // but no coverage info exists. This happens e.g. by selecting the - // best-effort coverage collection mode, which triggers deletion of all - // coverage infos in order to avoid memory leaks. - - const coverageInfo: CoverageInfo = - GetCoverageInfo(function) otherwise return Undefined; - IncrementBlockCount(coverageInfo, coverageArraySlotIndex); - return Undefined; - } +macro GetCoverageInfo(implicit context: Context)(function: JSFunction): + CoverageInfo labels IfNoCoverageInfo { + const shared: SharedFunctionInfo = function.shared_function_info; + const debugInfo = Cast(shared.script_or_debug_info) + otherwise goto IfNoCoverageInfo; + + if (!debugInfo.flags.has_coverage_info) goto IfNoCoverageInfo; + return UnsafeCast(debugInfo.coverage_info); +} + +macro IncrementBlockCount(implicit context: Context)( + coverageInfo: CoverageInfo, slot: Smi) { + assert(Convert(slot) < coverageInfo.slot_count); + ++coverageInfo.slots[slot].block_count; +} + +builtin IncBlockCounter( + implicit context: + Context)(function: JSFunction, coverageArraySlotIndex: Smi): Undefined { + // It's quite possible that a function contains IncBlockCounter bytecodes, + // but no coverage info exists. This happens e.g. by selecting the + // best-effort coverage collection mode, which triggers deletion of all + // coverage infos in order to avoid memory leaks. + + const coverageInfo: CoverageInfo = + GetCoverageInfo(function) otherwise return Undefined; + IncrementBlockCount(coverageInfo, coverageArraySlotIndex); + return Undefined; +} } // namespace internal_coverage diff --git a/deps/v8/src/builtins/iterator.tq b/deps/v8/src/builtins/iterator.tq index 272a2a7db83d5b..1354c434e7f51a 100644 --- a/deps/v8/src/builtins/iterator.tq +++ b/deps/v8/src/builtins/iterator.tq @@ -5,105 +5,98 @@ #include 'src/builtins/builtins-iterator-gen.h' namespace iterator { - // Returned from IteratorBuiltinsAssembler::GetIterator(). - @export - struct IteratorRecord { - // iteratorRecord.[[Iterator]] - object: JSReceiver; - - // iteratorRecord.[[NextMethod]] - next: JSAny; - } +// Returned from IteratorBuiltinsAssembler::GetIterator(). +@export +struct IteratorRecord { + // iteratorRecord.[[Iterator]] + object: JSReceiver; + + // iteratorRecord.[[NextMethod]] + next: JSAny; +} - extern macro IteratorBuiltinsAssembler::FastIterableToList( - implicit context: Context)(JSAny): JSArray labels Slow; - - extern macro IteratorBuiltinsAssembler::GetIteratorMethod( - implicit context: Context)(JSAny): JSAny; - extern macro IteratorBuiltinsAssembler::GetIterator( - implicit context: Context)(JSAny): IteratorRecord; - extern macro IteratorBuiltinsAssembler::GetIterator( - implicit context: Context)(JSAny, JSAny): IteratorRecord; - - extern macro IteratorBuiltinsAssembler::IteratorStep( - implicit context: Context)(IteratorRecord): JSReceiver - labels Done; - extern macro IteratorBuiltinsAssembler::IteratorStep( - implicit context: Context)(IteratorRecord, Map): JSReceiver - labels Done; - - extern macro IteratorBuiltinsAssembler::IteratorValue( - implicit context: Context)(JSReceiver): JSAny; - extern macro IteratorBuiltinsAssembler::IteratorValue( - implicit context: Context)(JSReceiver, Map): JSAny; - - extern macro IteratorBuiltinsAssembler::IteratorCloseOnException( - implicit context: Context)(IteratorRecord, JSAny): never; - - extern macro IteratorBuiltinsAssembler::IterableToList( - implicit context: Context)(JSAny, JSAny): JSArray; - - extern macro IteratorBuiltinsAssembler::StringListFromIterable( - implicit context: Context)(JSAny): JSArray; - - extern builtin IterableToListMayPreserveHoles(implicit context: - Context)(JSAny, JSAny); - extern builtin IterableToListWithSymbolLookup(implicit context: - Context)(JSAny); - - transitioning builtin GetIteratorWithFeedback( - context: Context, receiver: JSAny, loadSlot: TaggedIndex, - callSlot: TaggedIndex, feedback: Undefined|FeedbackVector): JSAny { - let iteratorMethod: JSAny; - typeswitch (feedback) { - case (Undefined): { - iteratorMethod = GetProperty(receiver, IteratorSymbolConstant()); - } - case (feedback: FeedbackVector): { - iteratorMethod = LoadIC( - context, receiver, IteratorSymbolConstant(), loadSlot, feedback); - } +extern macro IteratorBuiltinsAssembler::FastIterableToList( + implicit context: Context)(JSAny): JSArray labels Slow; + +extern macro IteratorBuiltinsAssembler::GetIteratorMethod( + implicit context: Context)(JSAny): JSAny; +extern macro IteratorBuiltinsAssembler::GetIterator(implicit context: Context)( + JSAny): IteratorRecord; +extern macro IteratorBuiltinsAssembler::GetIterator(implicit context: Context)( + JSAny, JSAny): IteratorRecord; + +extern macro IteratorBuiltinsAssembler::IteratorStep(implicit context: Context)( + IteratorRecord): JSReceiver + labels Done; +extern macro IteratorBuiltinsAssembler::IteratorStep(implicit context: Context)( + IteratorRecord, Map): JSReceiver + labels Done; + +extern macro IteratorBuiltinsAssembler::IteratorValue( + implicit context: Context)(JSReceiver): JSAny; +extern macro IteratorBuiltinsAssembler::IteratorValue( + implicit context: Context)(JSReceiver, Map): JSAny; + +extern macro IteratorBuiltinsAssembler::IterableToList( + implicit context: Context)(JSAny, JSAny): JSArray; + +extern macro IteratorBuiltinsAssembler::StringListFromIterable( + implicit context: Context)(JSAny): JSArray; + +extern builtin IterableToListWithSymbolLookup(implicit context: Context)(JSAny): + JSArray; +extern builtin IterableToFixedArrayWithSymbolLookupSlow( + implicit context: Context)(JSAny): FixedArray; + +transitioning builtin GetIteratorWithFeedback( + context: Context, receiver: JSAny, loadSlot: TaggedIndex, + callSlot: TaggedIndex, feedback: Undefined|FeedbackVector): JSAny { + let iteratorMethod: JSAny; + typeswitch (feedback) { + case (Undefined): { + iteratorMethod = GetProperty(receiver, IteratorSymbolConstant()); + } + case (feedback: FeedbackVector): { + iteratorMethod = LoadIC( + context, receiver, IteratorSymbolConstant(), loadSlot, feedback); } - // TODO(v8:10047): Use TaggedIndex here once TurboFan supports it. - const callSlotSmi: Smi = TaggedIndexToSmi(callSlot); - return CallIteratorWithFeedback( - context, receiver, iteratorMethod, callSlotSmi, feedback); } + // TODO(v8:10047): Use TaggedIndex here once TurboFan supports it. + const callSlotSmi: Smi = TaggedIndexToSmi(callSlot); + return CallIteratorWithFeedback( + context, receiver, iteratorMethod, callSlotSmi, feedback); +} - transitioning builtin CallIteratorWithFeedback( - context: Context, receiver: JSAny, iteratorMethod: JSAny, callSlot: Smi, - feedback: Undefined|FeedbackVector): JSAny { - const callSlotUnTagged: uintptr = Unsigned(SmiUntag(callSlot)); - CollectCallFeedback(iteratorMethod, context, feedback, callSlotUnTagged); - const iteratorCallable: Callable = Cast(iteratorMethod) - otherwise ThrowCalledNonCallable(iteratorMethod); - return Call(context, iteratorCallable, receiver); - } +transitioning builtin CallIteratorWithFeedback( + context: Context, receiver: JSAny, iteratorMethod: JSAny, callSlot: Smi, + feedback: Undefined|FeedbackVector): JSAny { + const callSlotUnTagged: uintptr = Unsigned(SmiUntag(callSlot)); + ic::CollectCallFeedback(iteratorMethod, context, feedback, callSlotUnTagged); + const iteratorCallable: Callable = Cast(iteratorMethod) + otherwise ThrowCalledNonCallable(iteratorMethod); + return Call(context, iteratorCallable, receiver); +} - transitioning - macro IteratorCloseOnException(implicit context: Context)( - iterator: IteratorRecord, exception: Object): never labels - IfException(Object) { - // Let return be ? GetMethod(iterator, "return"). - let method: JSAny; - try { - method = GetProperty(iterator.object, kReturnString); - } catch (e) { - goto IfException(e); - } +// https://tc39.es/ecma262/#sec-iteratorclose +@export +transitioning macro IteratorCloseOnException(implicit context: Context)( + iterator: IteratorRecord) { + try { + // 4. Let innerResult be GetMethod(iterator, "return"). + const method = GetProperty(iterator.object, kReturnString); - // If return is undefined, return Completion(completion). - if (method == Undefined || method == Null) goto IfException(exception); + // 5. If innerResult.[[Type]] is normal, then + // a. Let return be innerResult.[[Value]]. + // b. If return is undefined, return Completion(completion). + if (method == Undefined || method == Null) return; - // Let innerResult be Call(return, iterator, « »). + // c. Set innerResult to Call(return, iterator). // If an exception occurs, the original exception remains bound - try { - Call(context, method, iterator.object); - } catch (_e) { - goto IfException(exception); - } - - // (If completion.[[Type]] is throw) return Completion(completion). - goto IfException(exception); + Call(context, method, iterator.object); + } catch (_e) { + // Swallow the exception. } + + // (If completion.[[Type]] is throw) return Completion(completion). +} } diff --git a/deps/v8/src/builtins/math.tq b/deps/v8/src/builtins/math.tq index 8c9998906a533e..0586f432f5b0ec 100644 --- a/deps/v8/src/builtins/math.tq +++ b/deps/v8/src/builtins/math.tq @@ -4,468 +4,456 @@ namespace math { - extern transitioning builtin - NonNumberToNumber(implicit context: Context)(HeapObject): Number; - - transitioning macro ReduceToSmiOrFloat64(implicit context: Context)(x: JSAny): - never - labels SmiResult(Smi), Float64Result(float64) { - let x1: JSAny = x; - while (true) { - typeswitch (x1) { - case (s: Smi): { - goto SmiResult(s); - } - case (h: HeapNumber): { - goto Float64Result(Convert(h)); - } - case (a: JSAnyNotNumber): { - x1 = NonNumberToNumber(a); - } +extern transitioning builtin +NonNumberToNumber(implicit context: Context)(HeapObject): Number; + +transitioning macro ReduceToSmiOrFloat64(implicit context: Context)(x: JSAny): + never + labels SmiResult(Smi), Float64Result(float64) { + let x1: JSAny = x; + while (true) { + typeswitch (x1) { + case (s: Smi): { + goto SmiResult(s); + } + case (h: HeapNumber): { + goto Float64Result(Convert(h)); + } + case (a: JSAnyNotNumber): { + x1 = NonNumberToNumber(a); } } - VerifiedUnreachable(); } + VerifiedUnreachable(); +} - // ES6 #sec-math.abs - extern macro IsIntPtrAbsWithOverflowSupported(): constexpr bool; - extern macro TrySmiSub(Smi, Smi): Smi labels Overflow; - extern macro TrySmiAbs(Smi): Smi labels Overflow; - extern macro Float64Abs(float64): float64; - const kSmiMaxValuePlusOne: - constexpr float64 generates '0.0 - kSmiMinValue'; - - transitioning javascript builtin - MathAbs(js-implicit context: NativeContext)(x: JSAny): Number { +// ES6 #sec-math.abs +extern macro IsIntPtrAbsWithOverflowSupported(): constexpr bool; +extern macro TrySmiSub(Smi, Smi): Smi labels Overflow; +extern macro TrySmiAbs(Smi): Smi labels Overflow; +extern macro Float64Abs(float64): float64; +const kSmiMaxValuePlusOne: + constexpr float64 generates '0.0 - kSmiMinValue'; + +transitioning javascript builtin +MathAbs(js-implicit context: NativeContext)(x: JSAny): Number { + try { + ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; + } label SmiResult(s: Smi) { try { - ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; - } - label SmiResult(s: Smi) { - try { - if constexpr (IsIntPtrAbsWithOverflowSupported()) { - const result: Smi = TrySmiAbs(s) - otherwise SmiOverflow; - return result; + if constexpr (IsIntPtrAbsWithOverflowSupported()) { + const result: Smi = TrySmiAbs(s) + otherwise SmiOverflow; + return result; + } else { + if (0 <= s) { + return s; } else { - if (0 <= s) { - return s; - } else { - const result: Smi = TrySmiSub(0, s) otherwise SmiOverflow; - return result; - } + const result: Smi = TrySmiSub(0, s) otherwise SmiOverflow; + return result; } } - label SmiOverflow { - return NumberConstant(kSmiMaxValuePlusOne); - } - } - label Float64Result(f: float64) { - return Convert(Float64Abs(f)); + } label SmiOverflow { + return NumberConstant(kSmiMaxValuePlusOne); } + } label Float64Result(f: float64) { + return Convert(Float64Abs(f)); } +} - // ES6 #sec-math.ceil - extern macro Float64Ceil(float64): float64; - transitioning javascript builtin - MathCeil(js-implicit context: NativeContext)(x: JSAny): Number { - try { - ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; - } - label SmiResult(s: Smi) { - return s; - } - label Float64Result(f: float64) { - return Convert(Float64Ceil(f)); - } +// ES6 #sec-math.ceil +extern macro Float64Ceil(float64): float64; +transitioning javascript builtin +MathCeil(js-implicit context: NativeContext)(x: JSAny): Number { + try { + ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; + } label SmiResult(s: Smi) { + return s; + } label Float64Result(f: float64) { + return Convert(Float64Ceil(f)); } +} - // ES6 #sec-math.floor - extern macro Float64Floor(float64): float64; - transitioning javascript builtin - MathFloor(js-implicit context: NativeContext)(x: JSAny): Number { - try { - ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; - } - label SmiResult(s: Smi) { - return s; - } - label Float64Result(f: float64) { - return Convert(Float64Floor(f)); - } +// ES6 #sec-math.floor +extern macro Float64Floor(float64): float64; +transitioning javascript builtin +MathFloor(js-implicit context: NativeContext)(x: JSAny): Number { + try { + ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; + } label SmiResult(s: Smi) { + return s; + } label Float64Result(f: float64) { + return Convert(Float64Floor(f)); } +} - // ES6 #sec-math.round - extern macro Float64Round(float64): float64; - transitioning javascript builtin - MathRound(js-implicit context: NativeContext)(x: JSAny): Number { - try { - ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; - } - label SmiResult(s: Smi) { - return s; - } - label Float64Result(f: float64) { - return Convert(Float64Round(f)); - } +// ES6 #sec-math.round +extern macro Float64Round(float64): float64; +transitioning javascript builtin +MathRound(js-implicit context: NativeContext)(x: JSAny): Number { + try { + ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; + } label SmiResult(s: Smi) { + return s; + } label Float64Result(f: float64) { + return Convert(Float64Round(f)); } +} - // ES6 #sec-math.trunc - extern macro Float64Trunc(float64): float64; - transitioning javascript builtin - MathTrunc(js-implicit context: NativeContext)(x: JSAny): Number { - try { - ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; - } - label SmiResult(s: Smi) { - return s; - } - label Float64Result(f: float64) { - return Convert(Float64Trunc(f)); - } +// ES6 #sec-math.trunc +extern macro Float64Trunc(float64): float64; +transitioning javascript builtin +MathTrunc(js-implicit context: NativeContext)(x: JSAny): Number { + try { + ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; + } label SmiResult(s: Smi) { + return s; + } label Float64Result(f: float64) { + return Convert(Float64Trunc(f)); } +} - // ES6 #sec-math.pow - extern macro Float64Pow(float64, float64): float64; - extern macro TruncateTaggedToFloat64(implicit context: Context)(JSAny): - float64; - - @export - macro MathPowImpl(implicit context: Context)(base: JSAny, exponent: JSAny): - Number { - const baseValue: float64 = TruncateTaggedToFloat64(base); - const exponentValue: float64 = TruncateTaggedToFloat64(exponent); - const result: float64 = Float64Pow(baseValue, exponentValue); - return Convert(result); - } +// ES6 #sec-math.pow +extern macro Float64Pow(float64, float64): float64; +extern macro TruncateTaggedToFloat64(implicit context: Context)(JSAny): float64; + +@export +macro MathPowImpl(implicit context: Context)(base: JSAny, exponent: JSAny): + Number { + const baseValue: float64 = TruncateTaggedToFloat64(base); + const exponentValue: float64 = TruncateTaggedToFloat64(exponent); + const result: float64 = Float64Pow(baseValue, exponentValue); + return Convert(result); +} - transitioning javascript builtin - MathPow(js-implicit context: NativeContext)(base: JSAny, exponent: JSAny): - Number { - return MathPowImpl(base, exponent); - } +transitioning javascript builtin +MathPow(js-implicit context: NativeContext)( + base: JSAny, exponent: JSAny): Number { + return MathPowImpl(base, exponent); +} - // ES6 #sec-math.max - extern macro Float64Max(float64, float64): float64; - transitioning javascript builtin - MathMax(js-implicit context: NativeContext)(...arguments): Number { - let result: float64 = MINUS_V8_INFINITY; - const argCount = arguments.length; - for (let i: intptr = 0; i < argCount; i++) { - const doubleValue = TruncateTaggedToFloat64(arguments[i]); - result = Float64Max(result, doubleValue); - } - return Convert(result); - } +// ES6 #sec-math.max +extern macro Float64Max(float64, float64): float64; +transitioning javascript builtin +MathMax(js-implicit context: NativeContext)(...arguments): Number { + let result: float64 = MINUS_V8_INFINITY; + const argCount = arguments.length; + for (let i: intptr = 0; i < argCount; i++) { + const doubleValue = TruncateTaggedToFloat64(arguments[i]); + result = Float64Max(result, doubleValue); + } + return Convert(result); +} - // ES6 #sec-math.min - extern macro Float64Min(float64, float64): float64; - transitioning javascript builtin - MathMin(js-implicit context: NativeContext)(...arguments): Number { - let result: float64 = V8_INFINITY; - const argCount = arguments.length; - for (let i: intptr = 0; i < argCount; i++) { - const doubleValue = TruncateTaggedToFloat64(arguments[i]); - result = Float64Min(result, doubleValue); - } - return Convert(result); - } +// ES6 #sec-math.min +extern macro Float64Min(float64, float64): float64; +transitioning javascript builtin +MathMin(js-implicit context: NativeContext)(...arguments): Number { + let result: float64 = V8_INFINITY; + const argCount = arguments.length; + for (let i: intptr = 0; i < argCount; i++) { + const doubleValue = TruncateTaggedToFloat64(arguments[i]); + result = Float64Min(result, doubleValue); + } + return Convert(result); +} - // ES6 #sec-math.acos - extern macro Float64Acos(float64): float64; +// ES6 #sec-math.acos +extern macro Float64Acos(float64): float64; - transitioning javascript builtin - MathAcos(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Acos(value)); - } +transitioning javascript builtin +MathAcos(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Acos(value)); +} - // ES6 #sec-math.acosh - extern macro Float64Acosh(float64): float64; +// ES6 #sec-math.acosh +extern macro Float64Acosh(float64): float64; - transitioning javascript builtin - MathAcosh(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Acosh(value)); - } +transitioning javascript builtin +MathAcosh(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Acosh(value)); +} - // ES6 #sec-math.asin - extern macro Float64Asin(float64): float64; +// ES6 #sec-math.asin +extern macro Float64Asin(float64): float64; - transitioning javascript builtin - MathAsin(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Asin(value)); - } +transitioning javascript builtin +MathAsin(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Asin(value)); +} - // ES6 #sec-math.asinh - extern macro Float64Asinh(float64): float64; +// ES6 #sec-math.asinh +extern macro Float64Asinh(float64): float64; - transitioning javascript builtin - MathAsinh(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Asinh(value)); - } +transitioning javascript builtin +MathAsinh(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Asinh(value)); +} - // ES6 #sec-math.atan - extern macro Float64Atan(float64): float64; +// ES6 #sec-math.atan +extern macro Float64Atan(float64): float64; - transitioning javascript builtin - MathAtan(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Atan(value)); - } +transitioning javascript builtin +MathAtan(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Atan(value)); +} - // ES6 #sec-math.atan2 - extern macro Float64Atan2(float64, float64): float64; +// ES6 #sec-math.atan2 +extern macro Float64Atan2(float64, float64): float64; - transitioning javascript builtin - MathAtan2(js-implicit context: NativeContext)(y: JSAny, x: JSAny): Number { - const yValue = Convert(ToNumber_Inline(y)); - const xValue = Convert(ToNumber_Inline(x)); - return Convert(Float64Atan2(yValue, xValue)); - } +transitioning javascript builtin +MathAtan2(js-implicit context: NativeContext)(y: JSAny, x: JSAny): Number { + const yValue = Convert(ToNumber_Inline(y)); + const xValue = Convert(ToNumber_Inline(x)); + return Convert(Float64Atan2(yValue, xValue)); +} - // ES6 #sec-math.atanh - extern macro Float64Atanh(float64): float64; +// ES6 #sec-math.atanh +extern macro Float64Atanh(float64): float64; - transitioning javascript builtin - MathAtanh(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Atanh(value)); - } +transitioning javascript builtin +MathAtanh(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Atanh(value)); +} - // ES6 #sec-math.cbrt - extern macro Float64Cbrt(float64): float64; +// ES6 #sec-math.cbrt +extern macro Float64Cbrt(float64): float64; - transitioning javascript builtin - MathCbrt(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Cbrt(value)); - } +transitioning javascript builtin +MathCbrt(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Cbrt(value)); +} - // ES6 #sec-math.clz32 - extern macro Word32Clz(int32): int32; +// ES6 #sec-math.clz32 +extern macro Word32Clz(int32): int32; - transitioning javascript builtin - MathClz32(js-implicit context: NativeContext)(x: JSAny): Number { - const value: int32 = Convert(ToNumber_Inline(x)); - return Convert(Word32Clz(value)); - } +transitioning javascript builtin +MathClz32(js-implicit context: NativeContext)(x: JSAny): Number { + const value: int32 = Convert(ToNumber_Inline(x)); + return Convert(Word32Clz(value)); +} - // ES6 #sec-math.cos - extern macro Float64Cos(float64): float64; +// ES6 #sec-math.cos +extern macro Float64Cos(float64): float64; - transitioning javascript builtin - MathCos(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Cos(value)); - } +transitioning javascript builtin +MathCos(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Cos(value)); +} - // ES6 #sec-math.cosh - extern macro Float64Cosh(float64): float64; +// ES6 #sec-math.cosh +extern macro Float64Cosh(float64): float64; - transitioning javascript builtin - MathCosh(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Cosh(value)); - } +transitioning javascript builtin +MathCosh(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Cosh(value)); +} - // ES6 #sec-math.exp - extern macro Float64Exp(float64): float64; +// ES6 #sec-math.exp +extern macro Float64Exp(float64): float64; - transitioning javascript builtin - MathExp(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Exp(value)); - } +transitioning javascript builtin +MathExp(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Exp(value)); +} - // ES6 #sec-math.expm1 - extern macro Float64Expm1(float64): float64; +// ES6 #sec-math.expm1 +extern macro Float64Expm1(float64): float64; - transitioning javascript builtin - MathExpm1(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Expm1(value)); - } +transitioning javascript builtin +MathExpm1(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Expm1(value)); +} - // ES6 #sec-math.fround - transitioning javascript builtin - MathFround(js-implicit context: NativeContext)(x: JSAny): Number { - const x32 = Convert(ToNumber_Inline(x)); - const x64 = Convert(x32); - return Convert(x64); - } +// ES6 #sec-math.fround +transitioning javascript builtin +MathFround(js-implicit context: NativeContext)(x: JSAny): Number { + const x32 = Convert(ToNumber_Inline(x)); + const x64 = Convert(x32); + return Convert(x64); +} - // ES6 #sec-math.imul - transitioning javascript builtin - MathImul(js-implicit context: NativeContext)(x: JSAny, y: JSAny): Number { - const x = Convert(ToNumber_Inline(x)); - const y = Convert(ToNumber_Inline(y)); - return Convert(x * y); - } +// ES6 #sec-math.imul +transitioning javascript builtin +MathImul(js-implicit context: NativeContext)(x: JSAny, y: JSAny): Number { + const x = Convert(ToNumber_Inline(x)); + const y = Convert(ToNumber_Inline(y)); + return Convert(x * y); +} - // ES6 #sec-math.log - extern macro Float64Log(float64): float64; +// ES6 #sec-math.log +extern macro Float64Log(float64): float64; - transitioning javascript builtin - MathLog(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Log(value)); - } +transitioning javascript builtin +MathLog(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Log(value)); +} - // ES6 #sec-math.log1p - extern macro Float64Log1p(float64): float64; +// ES6 #sec-math.log1p +extern macro Float64Log1p(float64): float64; - transitioning javascript builtin - MathLog1p(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Log1p(value)); - } +transitioning javascript builtin +MathLog1p(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Log1p(value)); +} - // ES6 #sec-math.log10 - extern macro Float64Log10(float64): float64; +// ES6 #sec-math.log10 +extern macro Float64Log10(float64): float64; - transitioning javascript builtin - MathLog10(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Log10(value)); - } +transitioning javascript builtin +MathLog10(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Log10(value)); +} - // ES6 #sec-math.log2 - extern macro Float64Log2(float64): float64; +// ES6 #sec-math.log2 +extern macro Float64Log2(float64): float64; - transitioning javascript builtin - MathLog2(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Log2(value)); - } +transitioning javascript builtin +MathLog2(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Log2(value)); +} - // ES6 #sec-math.sin - extern macro Float64Sin(float64): float64; +// ES6 #sec-math.sin +extern macro Float64Sin(float64): float64; - transitioning javascript builtin - MathSin(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Sin(value)); - } +transitioning javascript builtin +MathSin(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Sin(value)); +} - // ES6 #sec-math.sign - transitioning javascript builtin - MathSign(js-implicit context: NativeContext)(x: JSAny): Number { - const num = ToNumber_Inline(x); - const value = Convert(num); +// ES6 #sec-math.sign +transitioning javascript builtin +MathSign(js-implicit context: NativeContext)(x: JSAny): Number { + const num = ToNumber_Inline(x); + const value = Convert(num); - if (value < 0) { - return -1; - } else if (value > 0) { - return 1; - } else { - return num; - } + if (value < 0) { + return -1; + } else if (value > 0) { + return 1; + } else { + return num; } +} - // ES6 #sec-math.sinh - extern macro Float64Sinh(float64): float64; +// ES6 #sec-math.sinh +extern macro Float64Sinh(float64): float64; - transitioning javascript builtin - MathSinh(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Sinh(value)); - } +transitioning javascript builtin +MathSinh(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Sinh(value)); +} - // ES6 #sec-math.sqrt - extern macro Float64Sqrt(float64): float64; +// ES6 #sec-math.sqrt +extern macro Float64Sqrt(float64): float64; - transitioning javascript builtin - MathSqrt(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Sqrt(value)); - } +transitioning javascript builtin +MathSqrt(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Sqrt(value)); +} - // ES6 #sec-math.tan - extern macro Float64Tan(float64): float64; +// ES6 #sec-math.tan +extern macro Float64Tan(float64): float64; - transitioning javascript builtin - MathTan(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Tan(value)); - } +transitioning javascript builtin +MathTan(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Tan(value)); +} - // ES6 #sec-math.tanh - extern macro Float64Tanh(float64): float64; +// ES6 #sec-math.tanh +extern macro Float64Tanh(float64): float64; - transitioning javascript builtin - MathTanh(js-implicit context: NativeContext)(x: JSAny): Number { - const value = Convert(ToNumber_Inline(x)); - return Convert(Float64Tanh(value)); - } +transitioning javascript builtin +MathTanh(js-implicit context: NativeContext)(x: JSAny): Number { + const value = Convert(ToNumber_Inline(x)); + return Convert(Float64Tanh(value)); +} - // ES6 #sec-math.hypot - transitioning javascript builtin - MathHypot(js-implicit context: NativeContext, receiver: JSAny)(...arguments): - Number { - const length = arguments.length; - if (length == 0) { - return 0; - } - const absValues = AllocateZeroedFixedDoubleArray(length); - let oneArgIsNaN: bool = false; - let max: float64 = 0; - for (let i: intptr = 0; i < length; ++i) { - const value = Convert(ToNumber_Inline(arguments[i])); - if (Float64IsNaN(value)) { - oneArgIsNaN = true; - } else { - const absValue = Float64Abs(value); - absValues.floats[i] = Convert(absValue); - if (absValue > max) { - max = absValue; - } +// ES6 #sec-math.hypot +transitioning javascript builtin +MathHypot( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): Number { + const length = arguments.length; + if (length == 0) { + return 0; + } + const absValues = AllocateZeroedFixedDoubleArray(length); + let oneArgIsNaN: bool = false; + let max: float64 = 0; + for (let i: intptr = 0; i < length; ++i) { + const value = Convert(ToNumber_Inline(arguments[i])); + if (Float64IsNaN(value)) { + oneArgIsNaN = true; + } else { + const absValue = Float64Abs(value); + absValues.floats[i] = Convert(absValue); + if (absValue > max) { + max = absValue; } } - if (max == V8_INFINITY) { - return V8_INFINITY; - } else if (oneArgIsNaN) { - return kNaN; - } else if (max == 0) { - return 0; - } - assert(max > 0); - - // Kahan summation to avoid rounding errors. - // Normalize the numbers to the largest one to avoid overflow. - let sum: float64 = 0; - let compensation: float64 = 0; - for (let i: intptr = 0; i < length; ++i) { - const n = absValues.floats[i].ValueUnsafeAssumeNotHole() / max; - const summand = n * n - compensation; - const preliminary = sum + summand; - compensation = (preliminary - sum) - summand; - sum = preliminary; - } - return Convert(Float64Sqrt(sum) * max); } + if (max == V8_INFINITY) { + return V8_INFINITY; + } else if (oneArgIsNaN) { + return kNaN; + } else if (max == 0) { + return 0; + } + assert(max > 0); + + // Kahan summation to avoid rounding errors. + // Normalize the numbers to the largest one to avoid overflow. + let sum: float64 = 0; + let compensation: float64 = 0; + for (let i: intptr = 0; i < length; ++i) { + const n = absValues.floats[i].ValueUnsafeAssumeNotHole() / max; + const summand = n * n - compensation; + const preliminary = sum + summand; + compensation = (preliminary - sum) - summand; + sum = preliminary; + } + return Convert(Float64Sqrt(sum) * max); +} - // ES6 #sec-math.random - extern macro RefillMathRandom(NativeContext): Smi; - - transitioning javascript builtin - MathRandom(js-implicit context: NativeContext, receiver: JSAny)(): Number { - let smiIndex: Smi = - Cast(context[NativeContextSlot::MATH_RANDOM_INDEX_INDEX]) - otherwise unreachable; - if (smiIndex == 0) { - // refill math random. - smiIndex = RefillMathRandom(context); - } - const newSmiIndex: Smi = smiIndex - 1; - context[NativeContextSlot::MATH_RANDOM_INDEX_INDEX] = newSmiIndex; - - const array: FixedDoubleArray = Cast( - context[NativeContextSlot::MATH_RANDOM_CACHE_INDEX]) - otherwise unreachable; - const random: float64 = - array.floats[Convert(newSmiIndex)].ValueUnsafeAssumeNotHole(); - return AllocateHeapNumberWithValue(random); - } +// ES6 #sec-math.random +extern macro RefillMathRandom(NativeContext): Smi; + +transitioning javascript builtin +MathRandom(js-implicit context: NativeContext, receiver: JSAny)(): Number { + let smiIndex: Smi = + Cast(context[NativeContextSlot::MATH_RANDOM_INDEX_INDEX]) + otherwise unreachable; + if (smiIndex == 0) { + // refill math random. + smiIndex = RefillMathRandom(context); + } + const newSmiIndex: Smi = smiIndex - 1; + context[NativeContextSlot::MATH_RANDOM_INDEX_INDEX] = newSmiIndex; + + const array: FixedDoubleArray = Cast( + context[NativeContextSlot::MATH_RANDOM_CACHE_INDEX]) + otherwise unreachable; + const random: float64 = + array.floats[Convert(newSmiIndex)].ValueUnsafeAssumeNotHole(); + return AllocateHeapNumberWithValue(random); +} } diff --git a/deps/v8/src/builtins/mips/builtins-mips.cc b/deps/v8/src/builtins/mips/builtins-mips.cc index cb1a86db2f4734..c98961f2ad4556 100644 --- a/deps/v8/src/builtins/mips/builtins-mips.cc +++ b/deps/v8/src/builtins/mips/builtins-mips.cc @@ -911,16 +911,25 @@ static void MaybeOptimizeCode(MacroAssembler* masm, Register feedback_vector, // Advance the current bytecode offset. This simulates what all bytecode // handlers do upon completion of the underlying operation. Will bail out to a -// label if the bytecode (without prefix) is a return bytecode. +// label if the bytecode (without prefix) is a return bytecode. Will not advance +// the bytecode offset if the current bytecode is a JumpLoop, instead just +// re-executing the JumpLoop to jump to the correct bytecode. static void AdvanceBytecodeOffsetOrReturn(MacroAssembler* masm, Register bytecode_array, Register bytecode_offset, Register bytecode, Register scratch1, - Register scratch2, Label* if_return) { + Register scratch2, Register scratch3, + Label* if_return) { Register bytecode_size_table = scratch1; - DCHECK(!AreAliased(bytecode_array, bytecode_offset, bytecode_size_table, - bytecode)); + // The bytecode offset value will be increased by one in wide and extra wide + // cases. In the case of having a wide or extra wide JumpLoop bytecode, we + // will restore the original bytecode. In order to simplify the code, we have + // a backup of it. + Register original_bytecode_offset = scratch3; + DCHECK(!AreAliased(bytecode_array, bytecode_offset, bytecode, + bytecode_size_table, original_bytecode_offset)); + __ Move(original_bytecode_offset, bytecode_offset); __ li(bytecode_size_table, ExternalReference::bytecode_size_table_address()); // Check if the bytecode is a Wide or ExtraWide prefix bytecode. @@ -959,10 +968,23 @@ static void AdvanceBytecodeOffsetOrReturn(MacroAssembler* masm, RETURN_BYTECODE_LIST(JUMP_IF_EQUAL) #undef JUMP_IF_EQUAL + // If this is a JumpLoop, re-execute it to perform the jump to the beginning + // of the loop. + Label end, not_jump_loop; + __ Branch(¬_jump_loop, ne, bytecode, + Operand(static_cast(interpreter::Bytecode::kJumpLoop))); + // We need to restore the original bytecode_offset since we might have + // increased it to skip the wide / extra-wide prefix bytecode. + __ Move(bytecode_offset, original_bytecode_offset); + __ jmp(&end); + + __ bind(¬_jump_loop); // Otherwise, load the size of the current bytecode and advance the offset. __ Lsa(scratch2, bytecode_size_table, bytecode, 2); __ lw(scratch2, MemOperand(scratch2)); __ Addu(bytecode_offset, bytecode_offset, scratch2); + + __ bind(&end); } // Generate code for entering a JS function with the interpreter. @@ -1134,7 +1156,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { __ lbu(a1, MemOperand(a1)); AdvanceBytecodeOffsetOrReturn(masm, kInterpreterBytecodeArrayRegister, kInterpreterBytecodeOffsetRegister, a1, a2, a3, - &do_return); + t0, &do_return); __ jmp(&do_dispatch); __ bind(&do_return); @@ -1412,7 +1434,7 @@ void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { Label if_return; AdvanceBytecodeOffsetOrReturn(masm, kInterpreterBytecodeArrayRegister, kInterpreterBytecodeOffsetRegister, a1, a2, a3, - &if_return); + t0, &if_return); __ bind(&enter_bytecode); // Convert new bytecode offset to a Smi and save in the stackframe. diff --git a/deps/v8/src/builtins/mips64/builtins-mips64.cc b/deps/v8/src/builtins/mips64/builtins-mips64.cc index baf2d5bfec80e2..babe084bb057ce 100644 --- a/deps/v8/src/builtins/mips64/builtins-mips64.cc +++ b/deps/v8/src/builtins/mips64/builtins-mips64.cc @@ -930,15 +930,25 @@ static void MaybeOptimizeCode(MacroAssembler* masm, Register feedback_vector, // Advance the current bytecode offset. This simulates what all bytecode // handlers do upon completion of the underlying operation. Will bail out to a -// label if the bytecode (without prefix) is a return bytecode. +// label if the bytecode (without prefix) is a return bytecode. Will not advance +// the bytecode offset if the current bytecode is a JumpLoop, instead just +// re-executing the JumpLoop to jump to the correct bytecode. static void AdvanceBytecodeOffsetOrReturn(MacroAssembler* masm, Register bytecode_array, Register bytecode_offset, Register bytecode, Register scratch1, - Register scratch2, Label* if_return) { + Register scratch2, Register scratch3, + Label* if_return) { Register bytecode_size_table = scratch1; - DCHECK(!AreAliased(bytecode_array, bytecode_offset, bytecode_size_table, - bytecode)); + + // The bytecode offset value will be increased by one in wide and extra wide + // cases. In the case of having a wide or extra wide JumpLoop bytecode, we + // will restore the original bytecode. In order to simplify the code, we have + // a backup of it. + Register original_bytecode_offset = scratch3; + DCHECK(!AreAliased(bytecode_array, bytecode_offset, bytecode, + bytecode_size_table, original_bytecode_offset)); + __ Move(original_bytecode_offset, bytecode_offset); __ li(bytecode_size_table, ExternalReference::bytecode_size_table_address()); // Check if the bytecode is a Wide or ExtraWide prefix bytecode. @@ -977,10 +987,23 @@ static void AdvanceBytecodeOffsetOrReturn(MacroAssembler* masm, RETURN_BYTECODE_LIST(JUMP_IF_EQUAL) #undef JUMP_IF_EQUAL + // If this is a JumpLoop, re-execute it to perform the jump to the beginning + // of the loop. + Label end, not_jump_loop; + __ Branch(¬_jump_loop, ne, bytecode, + Operand(static_cast(interpreter::Bytecode::kJumpLoop))); + // We need to restore the original bytecode_offset since we might have + // increased it to skip the wide / extra-wide prefix bytecode. + __ Move(bytecode_offset, original_bytecode_offset); + __ jmp(&end); + + __ bind(¬_jump_loop); // Otherwise, load the size of the current bytecode and advance the offset. __ Dlsa(scratch2, bytecode_size_table, bytecode, 2); __ Lw(scratch2, MemOperand(scratch2)); __ Daddu(bytecode_offset, bytecode_offset, scratch2); + + __ bind(&end); } // Generate code for entering a JS function with the interpreter. @@ -1153,7 +1176,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { __ Lbu(a1, MemOperand(a1)); AdvanceBytecodeOffsetOrReturn(masm, kInterpreterBytecodeArrayRegister, kInterpreterBytecodeOffsetRegister, a1, a2, a3, - &do_return); + a4, &do_return); __ jmp(&do_dispatch); __ bind(&do_return); @@ -1430,7 +1453,7 @@ void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { Label if_return; AdvanceBytecodeOffsetOrReturn(masm, kInterpreterBytecodeArrayRegister, kInterpreterBytecodeOffsetRegister, a1, a2, a3, - &if_return); + a4, &if_return); __ bind(&enter_bytecode); // Convert new bytecode offset to a Smi and save in the stackframe. diff --git a/deps/v8/src/builtins/number.tq b/deps/v8/src/builtins/number.tq index 958cd5f5f65fb2..98680cf5533c5f 100644 --- a/deps/v8/src/builtins/number.tq +++ b/deps/v8/src/builtins/number.tq @@ -3,73 +3,71 @@ // LICENSE file. namespace runtime { - extern transitioning runtime - DoubleToStringWithRadix(implicit context: Context)(Number, Number): String; +extern transitioning runtime +DoubleToStringWithRadix(implicit context: Context)(Number, Number): String; } // namespace runtime namespace number { - extern macro NaNStringConstant(): String; - extern macro ZeroStringConstant(): String; - extern macro InfinityStringConstant(): String; - extern macro MinusInfinityStringConstant(): String; +extern macro NaNStringConstant(): String; +extern macro ZeroStringConstant(): String; +extern macro InfinityStringConstant(): String; +extern macro MinusInfinityStringConstant(): String; - const kAsciiZero: constexpr int32 = 48; // '0' (ascii) - const kAsciiLowerCaseA: constexpr int32 = 97; // 'a' (ascii) +const kAsciiZero: constexpr int32 = 48; // '0' (ascii) +const kAsciiLowerCaseA: constexpr int32 = 97; // 'a' (ascii) - transitioning macro ThisNumberValue(implicit context: Context)( - receiver: JSAny, method: constexpr string): Number { - return UnsafeCast( - ToThisValue(receiver, PrimitiveType::kNumber, method)); - } - - // https://tc39.github.io/ecma262/#sec-number.prototype.tostring - transitioning javascript builtin NumberPrototypeToString( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): String { - // 1. Let x be ? thisNumberValue(this value). - const x = ThisNumberValue(receiver, 'Number.prototype.toString'); +transitioning macro ThisNumberValue(implicit context: Context)( + receiver: JSAny, method: constexpr string): Number { + return UnsafeCast( + ToThisValue(receiver, PrimitiveType::kNumber, method)); +} - // 2. If radix is not present, let radixNumber be 10. - // 3. Else if radix is undefined, let radixNumber be 10. - // 4. Else, let radixNumber be ? ToInteger(radix). - const radix: JSAny = arguments[0]; - const radixNumber: Number = - radix == Undefined ? 10 : ToInteger_Inline(radix); +// https://tc39.github.io/ecma262/#sec-number.prototype.tostring +transitioning javascript builtin NumberPrototypeToString( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + // 1. Let x be ? thisNumberValue(this value). + const x = ThisNumberValue(receiver, 'Number.prototype.toString'); - // 5. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception. - if (radixNumber < 2 || radixNumber > 36) { - ThrowRangeError(MessageTemplate::kToRadixFormatRange); - } + // 2. If radix is not present, let radixNumber be 10. + // 3. Else if radix is undefined, let radixNumber be 10. + // 4. Else, let radixNumber be ? ToInteger(radix). + const radix: JSAny = arguments[0]; + const radixNumber: Number = radix == Undefined ? 10 : ToInteger_Inline(radix); - // 6. If radixNumber = 10, return ! ToString(x). - if (radixNumber == 10) { - return NumberToString(x); - } + // 5. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception. + if (radixNumber < 2 || radixNumber > 36) { + ThrowRangeError(MessageTemplate::kToRadixFormatRange); + } - // 7. Return the String representation of this Number - // value using the radix specified by radixNumber. + // 6. If radixNumber = 10, return ! ToString(x). + if (radixNumber == 10) { + return NumberToString(x); + } - // Fast case where the result is a one character string. - if (TaggedIsPositiveSmi(x) && x < radixNumber) { - let charCode = Convert(UnsafeCast(x)); - if (charCode < 10) { - charCode += kAsciiZero; - } else { - charCode = charCode - 10 + kAsciiLowerCaseA; - } - return StringFromSingleCharCode(charCode); - } + // 7. Return the String representation of this Number + // value using the radix specified by radixNumber. - if (x == -0) { - return ZeroStringConstant(); - } else if (NumberIsNaN(x)) { - return NaNStringConstant(); - } else if (x == V8_INFINITY) { - return InfinityStringConstant(); - } else if (x == MINUS_V8_INFINITY) { - return MinusInfinityStringConstant(); + // Fast case where the result is a one character string. + if (TaggedIsPositiveSmi(x) && x < radixNumber) { + let charCode = Convert(UnsafeCast(x)); + if (charCode < 10) { + charCode += kAsciiZero; + } else { + charCode = charCode - 10 + kAsciiLowerCaseA; } + return StringFromSingleCharCode(charCode); + } - return runtime::DoubleToStringWithRadix(x, radixNumber); + if (x == -0) { + return ZeroStringConstant(); + } else if (NumberIsNaN(x)) { + return NaNStringConstant(); + } else if (x == V8_INFINITY) { + return InfinityStringConstant(); + } else if (x == MINUS_V8_INFINITY) { + return MinusInfinityStringConstant(); } + + return runtime::DoubleToStringWithRadix(x, radixNumber); +} } diff --git a/deps/v8/src/builtins/object-fromentries.tq b/deps/v8/src/builtins/object-fromentries.tq index 2dbe9beacf1a05..32d4dea1574943 100644 --- a/deps/v8/src/builtins/object-fromentries.tq +++ b/deps/v8/src/builtins/object-fromentries.tq @@ -4,65 +4,63 @@ namespace object { - transitioning macro ObjectFromEntriesFastCase(implicit context: Context)( - iterable: JSAny): JSObject labels IfSlow { - typeswitch (iterable) { - case (array: FastJSArrayWithNoCustomIteration): { - const elements: FixedArray = - Cast(array.elements) otherwise IfSlow; - const length: Smi = array.length; - const result: JSObject = NewJSObject(); +transitioning macro ObjectFromEntriesFastCase(implicit context: Context)( + iterable: JSAny): JSObject labels IfSlow { + typeswitch (iterable) { + case (array: FastJSArrayWithNoCustomIteration): { + const elements: FixedArray = + Cast(array.elements) otherwise IfSlow; + const length: Smi = array.length; + const result: JSObject = NewJSObject(); - for (let k: Smi = 0; k < length; ++k) { - const value: JSAny = array::LoadElementOrUndefined(elements, k); - const pair: KeyValuePair = - collections::LoadKeyValuePairNoSideEffects(value) - otherwise IfSlow; - // Bail out if ToPropertyKey will attempt to load and call - // Symbol.toPrimitive, toString, and valueOf, which could - // invalidate assumptions about the iterable. - if (Is(pair.key)) goto IfSlow; - FastCreateDataProperty(result, pair.key, pair.value); - } - return result; - } - case (JSAny): { - goto IfSlow; + for (let k: Smi = 0; k < length; ++k) { + const value: JSAny = array::LoadElementOrUndefined(elements, k); + const pair: KeyValuePair = + collections::LoadKeyValuePairNoSideEffects(value) + otherwise IfSlow; + // Bail out if ToPropertyKey will attempt to load and call + // Symbol.toPrimitive, toString, and valueOf, which could + // invalidate assumptions about the iterable. + if (Is(pair.key)) goto IfSlow; + FastCreateDataProperty(result, pair.key, pair.value); } + return result; + } + case (JSAny): { + goto IfSlow; } } +} - transitioning javascript builtin - ObjectFromEntries(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - const iterable: JSAny = arguments[0]; +transitioning javascript builtin +ObjectFromEntries( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const iterable: JSAny = arguments[0]; + try { + if (IsNullOrUndefined(iterable)) goto Throw; + return ObjectFromEntriesFastCase(iterable) otherwise IfSlow; + } label IfSlow { + const result: JSObject = NewJSObject(); + const fastIteratorResultMap: Map = GetIteratorResultMap(); + let i: iterator::IteratorRecord = iterator::GetIterator(iterable); try { - if (IsNullOrUndefined(iterable)) goto Throw; - return ObjectFromEntriesFastCase(iterable) otherwise IfSlow; - } - label IfSlow { - const result: JSObject = NewJSObject(); - const fastIteratorResultMap: Map = GetIteratorResultMap(); - let i: iterator::IteratorRecord = iterator::GetIterator(iterable); - try { - assert(!IsNullOrUndefined(i.object)); - while (true) { - const step: JSReceiver = - iterator::IteratorStep(i, fastIteratorResultMap) - otherwise return result; - const iteratorValue: JSAny = - iterator::IteratorValue(step, fastIteratorResultMap); - const pair: KeyValuePair = - collections::LoadKeyValuePair(iteratorValue); - FastCreateDataProperty(result, pair.key, pair.value); - } - return result; - } catch (e) deferred { - iterator::IteratorCloseOnException(i, e); + assert(!IsNullOrUndefined(i.object)); + while (true) { + const step: JSReceiver = + iterator::IteratorStep(i, fastIteratorResultMap) + otherwise return result; + const iteratorValue: JSAny = + iterator::IteratorValue(step, fastIteratorResultMap); + const pair: KeyValuePair = collections::LoadKeyValuePair(iteratorValue); + FastCreateDataProperty(result, pair.key, pair.value); } + return result; + } catch (e) deferred { + iterator::IteratorCloseOnException(i); + ReThrow(context, e); } - label Throw deferred { - ThrowTypeError(MessageTemplate::kNotIterable); - } + } label Throw deferred { + ThrowTypeError(MessageTemplate::kNotIterable); } +} } // namespace object diff --git a/deps/v8/src/builtins/object.tq b/deps/v8/src/builtins/object.tq index c6d3e922797a75..931972024cf97f 100644 --- a/deps/v8/src/builtins/object.tq +++ b/deps/v8/src/builtins/object.tq @@ -3,179 +3,199 @@ // found in the LICENSE file. namespace runtime { - extern transitioning runtime - ObjectIsExtensible(implicit context: Context)(JSAny): JSAny; +extern transitioning runtime +ObjectIsExtensible(implicit context: Context)(JSAny): JSAny; - extern transitioning runtime - JSReceiverPreventExtensionsThrow(implicit context: Context)(JSReceiver): - JSAny; +extern transitioning runtime +JSReceiverPreventExtensionsThrow(implicit context: Context)(JSReceiver): JSAny; - extern transitioning runtime - JSReceiverPreventExtensionsDontThrow(implicit context: Context)(JSReceiver): - JSAny; +extern transitioning runtime +JSReceiverPreventExtensionsDontThrow(implicit context: Context)(JSReceiver): + JSAny; - extern transitioning runtime - JSReceiverGetPrototypeOf(implicit context: Context)(JSReceiver): JSAny; +extern transitioning runtime +JSReceiverGetPrototypeOf(implicit context: Context)(JSReceiver): JSAny; - extern transitioning runtime - JSReceiverSetPrototypeOfThrow(implicit context: Context)(JSReceiver, JSAny): - JSAny; +extern transitioning runtime +JSReceiverSetPrototypeOfThrow(implicit context: Context)( + JSReceiver, JSAny): JSAny; - extern transitioning runtime - JSReceiverSetPrototypeOfDontThrow(implicit context: - Context)(JSReceiver, JSAny): JSAny; +extern transitioning runtime +JSReceiverSetPrototypeOfDontThrow(implicit context: Context)( + JSReceiver, JSAny): JSAny; - extern transitioning runtime ObjectCreate(implicit context: - Context)(JSAny, JSAny): JSAny; +extern transitioning runtime ObjectCreate(implicit context: Context)( + JSAny, JSAny): JSAny; } // namespace runtime namespace object { - transitioning macro - ObjectIsExtensibleImpl(implicit context: Context)(object: JSAny): JSAny { - const objectJSReceiver = Cast(object) otherwise return False; - const objectJSProxy = Cast(objectJSReceiver) - otherwise return runtime::ObjectIsExtensible(objectJSReceiver); - return proxy::ProxyIsExtensible(objectJSProxy); - } - - transitioning macro - ObjectPreventExtensionsThrow(implicit context: Context)(object: JSAny): - JSAny { - const objectJSReceiver = Cast(object) otherwise return object; - const objectJSProxy = Cast(objectJSReceiver) - otherwise return runtime::JSReceiverPreventExtensionsThrow( - objectJSReceiver); - proxy::ProxyPreventExtensions(objectJSProxy, True); - return objectJSReceiver; - } - - transitioning macro - ObjectPreventExtensionsDontThrow(implicit context: Context)(object: JSAny): - JSAny { - const objectJSReceiver = Cast(object) otherwise return False; - const objectJSProxy = Cast(objectJSReceiver) - otherwise return runtime::JSReceiverPreventExtensionsDontThrow( - objectJSReceiver); - return proxy::ProxyPreventExtensions(objectJSProxy, False); - } - - transitioning macro - ObjectGetPrototypeOfImpl(implicit context: Context)(object: JSAny): JSAny { - const objectJSReceiver: JSReceiver = ToObject_Inline(context, object); - return object::JSReceiverGetPrototypeOf(objectJSReceiver); - } - - transitioning macro - JSReceiverGetPrototypeOf(implicit context: Context)(object: JSReceiver): - JSAny { - const objectJSProxy = Cast(object) - otherwise return runtime::JSReceiverGetPrototypeOf(object); - return proxy::ProxyGetPrototypeOf(objectJSProxy); - } - - transitioning macro - ObjectSetPrototypeOfThrow(implicit context: Context)( - object: JSAny, proto: JSReceiver|Null): JSAny { - const objectJSReceiver = Cast(object) otherwise return object; - const objectJSProxy = Cast(objectJSReceiver) - otherwise return runtime::JSReceiverSetPrototypeOfThrow( - objectJSReceiver, proto); - proxy::ProxySetPrototypeOf(objectJSProxy, proto, True); - return objectJSReceiver; - } - - transitioning macro - ObjectSetPrototypeOfDontThrow(implicit context: Context)( - object: JSAny, proto: JSReceiver|Null): JSAny { - const objectJSReceiver = Cast(object) otherwise return False; - const objectJSProxy = Cast(objectJSReceiver) - otherwise return runtime::JSReceiverSetPrototypeOfDontThrow( - objectJSReceiver, proto); - return proxy::ProxySetPrototypeOf(objectJSProxy, proto, False); - } - - transitioning builtin CreateObjectWithoutProperties( - implicit context: Context)(prototype: JSAny): JSAny { - const nativeContext = LoadNativeContext(context); - - try { - let map: Map; - let properties: NameDictionary|EmptyFixedArray; - typeswitch (prototype) { - case (Null): { - map = UnsafeCast( - nativeContext - [NativeContextSlot::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP]); - properties = AllocateNameDictionary(kNameDictionaryInitialCapacity); - } - case (prototype: JSReceiver): { - properties = kEmptyFixedArray; - const objectFunction = UnsafeCast( - nativeContext[NativeContextSlot::OBJECT_FUNCTION_INDEX]); - map = UnsafeCast(objectFunction.prototype_or_initial_map); - if (prototype != map.prototype) { - const prototypeInfo = - prototype.map.PrototypeInfo() otherwise Runtime; - typeswitch (prototypeInfo.object_create_map) { - case (Undefined): { - goto Runtime; - } - case (weak_map: Weak): { - map = WeakToStrong(weak_map) otherwise Runtime; - } +transitioning macro +ObjectIsExtensibleImpl(implicit context: Context)(object: JSAny): JSAny { + const objectJSReceiver = Cast(object) otherwise return False; + const objectJSProxy = Cast(objectJSReceiver) + otherwise return runtime::ObjectIsExtensible(objectJSReceiver); + return proxy::ProxyIsExtensible(objectJSProxy); +} + +transitioning macro +ObjectPreventExtensionsThrow(implicit context: Context)(object: JSAny): JSAny { + const objectJSReceiver = Cast(object) otherwise return object; + const objectJSProxy = Cast(objectJSReceiver) + otherwise return runtime::JSReceiverPreventExtensionsThrow(objectJSReceiver); + proxy::ProxyPreventExtensions(objectJSProxy, True); + return objectJSReceiver; +} + +transitioning macro +ObjectPreventExtensionsDontThrow(implicit context: Context)(object: JSAny): + JSAny { + const objectJSReceiver = Cast(object) otherwise return False; + const objectJSProxy = Cast(objectJSReceiver) + otherwise return runtime::JSReceiverPreventExtensionsDontThrow( + objectJSReceiver); + return proxy::ProxyPreventExtensions(objectJSProxy, False); +} + +transitioning macro +ObjectGetPrototypeOfImpl(implicit context: Context)(object: JSAny): JSAny { + const objectJSReceiver: JSReceiver = ToObject_Inline(context, object); + return object::JSReceiverGetPrototypeOf(objectJSReceiver); +} + +transitioning macro +JSReceiverGetPrototypeOf(implicit context: Context)(object: JSReceiver): JSAny { + const objectJSProxy = Cast(object) + otherwise return runtime::JSReceiverGetPrototypeOf(object); + return proxy::ProxyGetPrototypeOf(objectJSProxy); +} + +transitioning macro +ObjectSetPrototypeOfThrow(implicit context: Context)( + object: JSAny, proto: JSReceiver|Null): JSAny { + const objectJSReceiver = Cast(object) otherwise return object; + const objectJSProxy = Cast(objectJSReceiver) + otherwise return runtime::JSReceiverSetPrototypeOfThrow( + objectJSReceiver, proto); + proxy::ProxySetPrototypeOf(objectJSProxy, proto, True); + return objectJSReceiver; +} + +transitioning macro +ObjectSetPrototypeOfDontThrow(implicit context: Context)( + object: JSAny, proto: JSReceiver|Null): JSAny { + const objectJSReceiver = Cast(object) otherwise return False; + const objectJSProxy = Cast(objectJSReceiver) + otherwise return runtime::JSReceiverSetPrototypeOfDontThrow( + objectJSReceiver, proto); + return proxy::ProxySetPrototypeOf(objectJSProxy, proto, False); +} + +transitioning builtin CreateObjectWithoutProperties(implicit context: Context)( + prototype: JSAny): JSAny { + const nativeContext = LoadNativeContext(context); + + try { + let map: Map; + let properties: NameDictionary|EmptyFixedArray; + typeswitch (prototype) { + case (Null): { + map = UnsafeCast( + nativeContext + [NativeContextSlot::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP]); + properties = AllocateNameDictionary(kNameDictionaryInitialCapacity); + } + case (prototype: JSReceiver): { + properties = kEmptyFixedArray; + const objectFunction = UnsafeCast( + nativeContext[NativeContextSlot::OBJECT_FUNCTION_INDEX]); + map = UnsafeCast(objectFunction.prototype_or_initial_map); + if (prototype != map.prototype) { + const prototypeInfo = prototype.map.PrototypeInfo() otherwise Runtime; + typeswitch (prototypeInfo.object_create_map) { + case (Undefined): { + goto Runtime; + } + case (weak_map: Weak): { + map = WeakToStrong(weak_map) otherwise Runtime; } } } - case (JSAny): { - goto Runtime; - } - } - return AllocateJSObjectFromMap(map, properties); - } - label Runtime deferred { - return runtime::ObjectCreate(prototype, Undefined); - } - } - - // ES6 section 19.1.2.11 Object.isExtensible ( O ) - transitioning javascript builtin - ObjectIsExtensible(js-implicit context: NativeContext)(object: JSAny): JSAny { - return object::ObjectIsExtensibleImpl(object); - } - - // ES6 section 19.1.2.18 Object.preventExtensions ( O ) - transitioning javascript builtin - ObjectPreventExtensions(js-implicit context: NativeContext)(object: JSAny): - JSAny { - return object::ObjectPreventExtensionsThrow(object); - } - - // ES6 section 19.1.2.9 Object.getPrototypeOf ( O ) - transitioning javascript builtin - ObjectGetPrototypeOf(js-implicit context: NativeContext)(object: JSAny): - JSAny { - return object::ObjectGetPrototypeOfImpl(object); - } - - // ES6 section 19.1.2.21 Object.setPrototypeOf ( O, proto ) - transitioning javascript builtin ObjectSetPrototypeOf( - js-implicit context: NativeContext)(object: JSAny, proto: JSAny): JSAny { - // 1. Set O to ? RequireObjectCoercible(O). - RequireObjectCoercible(object, 'Object.setPrototypeOf'); - - // 2. If Type(proto) is neither Object nor Null, throw a TypeError - // exception. - // 3. If Type(O) is not Object, return O. - // 4. Let status be ? O.[[SetPrototypeOf]](proto). - // 5. If status is false, throw a TypeError exception. - // 6. Return O. - typeswitch (proto) { - case (proto: JSReceiver|Null): { - return object::ObjectSetPrototypeOfThrow(object, proto); } case (JSAny): { - ThrowTypeError(MessageTemplate::kProtoObjectOrNull, proto); + goto Runtime; } } + return AllocateJSObjectFromMap(map, properties); + } label Runtime deferred { + return runtime::ObjectCreate(prototype, Undefined); } +} + +// ES6 section 19.1.2.11 Object.isExtensible ( O ) +transitioning javascript builtin +ObjectIsExtensible(js-implicit context: NativeContext)(object: JSAny): JSAny { + return object::ObjectIsExtensibleImpl(object); +} + +// ES6 section 19.1.2.18 Object.preventExtensions ( O ) +transitioning javascript builtin +ObjectPreventExtensions(js-implicit context: NativeContext)(object: JSAny): + JSAny { + return object::ObjectPreventExtensionsThrow(object); +} + +// ES6 section 19.1.2.9 Object.getPrototypeOf ( O ) +transitioning javascript builtin +ObjectGetPrototypeOf(js-implicit context: NativeContext)(object: JSAny): JSAny { + return object::ObjectGetPrototypeOfImpl(object); +} + +// ES6 section 19.1.2.21 Object.setPrototypeOf ( O, proto ) +transitioning javascript builtin ObjectSetPrototypeOf( + js-implicit context: NativeContext)(object: JSAny, proto: JSAny): JSAny { + // 1. Set O to ? RequireObjectCoercible(O). + RequireObjectCoercible(object, 'Object.setPrototypeOf'); + + // 2. If Type(proto) is neither Object nor Null, throw a TypeError + // exception. + // 3. If Type(O) is not Object, return O. + // 4. Let status be ? O.[[SetPrototypeOf]](proto). + // 5. If status is false, throw a TypeError exception. + // 6. Return O. + typeswitch (proto) { + case (proto: JSReceiver|Null): { + return object::ObjectSetPrototypeOfThrow(object, proto); + } + case (JSAny): { + ThrowTypeError(MessageTemplate::kProtoObjectOrNull, proto); + } + } +} + +// ES #sec-object.prototype.tostring +transitioning javascript builtin ObjectPrototypeToString( + js-implicit context: Context, receiver: JSAny)(): String { + return ObjectToString(context, receiver); +} + +// ES #sec-object.prototype.valueof +transitioning javascript builtin ObjectPrototypeValueOf( + js-implicit context: Context, receiver: JSAny)(): JSReceiver { + // 1. Return ? ToObject(this value). + return ToObject_Inline(context, receiver); +} + +// ES #sec-object.prototype.tolocalestring +transitioning javascript builtin ObjectPrototypeToLocaleString( + js-implicit context: Context, receiver: JSAny)(): JSAny { + // 1. Let O be the this value. + // 2. Return ? Invoke(O, "toString"). + if (receiver == Null || receiver == Undefined) deferred { + ThrowTypeError( + MessageTemplate::kCalledOnNullOrUndefined, + 'Object.prototype.toLocaleString'); + } + const method = GetProperty(receiver, 'toString'); + return Call(context, method, receiver); +} } // namespace object diff --git a/deps/v8/src/builtins/ppc/builtins-ppc.cc b/deps/v8/src/builtins/ppc/builtins-ppc.cc index 460d7492970726..367838f82cc87d 100644 --- a/deps/v8/src/builtins/ppc/builtins-ppc.cc +++ b/deps/v8/src/builtins/ppc/builtins-ppc.cc @@ -87,7 +87,7 @@ void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, // here which will cause scratch to become negative. __ sub(scratch, sp, scratch); // Check if the arguments will overflow the stack. - __ ShiftLeftImm(r0, num_args, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r0, num_args, Operand(kSystemPointerSizeLog2)); __ cmp(scratch, r0); __ ble(stack_overflow); // Signed comparison. } @@ -130,16 +130,16 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { // -- r6: new target // -- r7: pointer to last argument // -- cr0: condition indicating whether r3 is zero - // -- sp[0*kPointerSize]: the hole (receiver) - // -- sp[1*kPointerSize]: number of arguments (tagged) - // -- sp[2*kPointerSize]: context + // -- sp[0*kSystemPointerSize]: the hole (receiver) + // -- sp[1*kSystemPointerSize]: number of arguments (tagged) + // -- sp[2*kSystemPointerSize]: context // ----------------------------------- __ beq(&no_args, cr0); - __ ShiftLeftImm(scratch, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(scratch, r3, Operand(kSystemPointerSizeLog2)); __ sub(sp, sp, scratch); __ mtctr(r3); __ bind(&loop); - __ subi(scratch, scratch, Operand(kPointerSize)); + __ subi(scratch, scratch, Operand(kSystemPointerSize)); __ LoadPX(r0, MemOperand(r7, scratch)); __ StorePX(r0, MemOperand(sp, scratch)); __ bdnz(&loop); @@ -166,7 +166,7 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { __ SmiToPtrArrayOffset(r4, r4); __ add(sp, sp, r4); - __ addi(sp, sp, Operand(kPointerSize)); + __ addi(sp, sp, Operand(kSystemPointerSize)); __ blr(); __ bind(&stack_overflow); @@ -202,14 +202,15 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ Push(r6); // ----------- S t a t e ------------- - // -- sp[0*kPointerSize]: new target - // -- sp[1*kPointerSize]: padding - // -- r4 and sp[2*kPointerSize]: constructor function - // -- sp[3*kPointerSize]: number of arguments (tagged) - // -- sp[4*kPointerSize]: context + // -- sp[0*kSystemPointerSize]: new target + // -- sp[1*kSystemPointerSize]: padding + // -- r4 and sp[2*kSystemPointerSize]: constructor function + // -- sp[3*kSystemPointerSize]: number of arguments (tagged) + // -- sp[4*kSystemPointerSize]: context // ----------------------------------- - __ LoadP(r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); + __ LoadTaggedPointerField( + r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); __ lwz(r7, FieldMemOperand(r7, SharedFunctionInfo::kFlagsOffset)); __ DecodeField(r7); __ JumpIfIsInRange(r7, kDefaultDerivedConstructor, kDerivedConstructor, @@ -228,11 +229,11 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r3: receiver - // -- Slot 4 / sp[0*kPointerSize]: new target - // -- Slot 3 / sp[1*kPointerSize]: padding - // -- Slot 2 / sp[2*kPointerSize]: constructor function - // -- Slot 1 / sp[3*kPointerSize]: number of arguments (tagged) - // -- Slot 0 / sp[4*kPointerSize]: context + // -- Slot 4 / sp[0*kSystemPointerSize]: new target + // -- Slot 3 / sp[1*kSystemPointerSize]: padding + // -- Slot 2 / sp[2*kSystemPointerSize]: constructor function + // -- Slot 1 / sp[3*kSystemPointerSize]: number of arguments (tagged) + // -- Slot 0 / sp[4*kSystemPointerSize]: context // ----------------------------------- // Deoptimizer enters here. masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset( @@ -248,12 +249,12 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r6: new target - // -- sp[0*kPointerSize]: implicit receiver - // -- sp[1*kPointerSize]: implicit receiver - // -- sp[2*kPointerSize]: padding - // -- sp[3*kPointerSize]: constructor function - // -- sp[4*kPointerSize]: number of arguments (tagged) - // -- sp[5*kPointerSize]: context + // -- sp[0*kSystemPointerSize]: implicit receiver + // -- sp[1*kSystemPointerSize]: implicit receiver + // -- sp[2*kSystemPointerSize]: padding + // -- sp[3*kSystemPointerSize]: constructor function + // -- sp[4*kSystemPointerSize]: number of arguments (tagged) + // -- sp[5*kSystemPointerSize]: context // ----------------------------------- // Restore constructor function and argument count. @@ -284,20 +285,20 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // -- r6: new target // -- r7: pointer to last argument // -- cr0: condition indicating whether r3 is zero - // -- sp[0*kPointerSize]: implicit receiver - // -- sp[1*kPointerSize]: implicit receiver - // -- sp[2*kPointerSize]: padding - // -- r4 and sp[3*kPointerSize]: constructor function - // -- sp[4*kPointerSize]: number of arguments (tagged) - // -- sp[5*kPointerSize]: context + // -- sp[0*kSystemPointerSize]: implicit receiver + // -- sp[1*kSystemPointerSize]: implicit receiver + // -- sp[2*kSystemPointerSize]: padding + // -- r4 and sp[3*kSystemPointerSize]: constructor function + // -- sp[4*kSystemPointerSize]: number of arguments (tagged) + // -- sp[5*kSystemPointerSize]: context // ----------------------------------- __ cmpi(r3, Operand::Zero()); __ beq(&no_args); - __ ShiftLeftImm(r9, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r9, r3, Operand(kSystemPointerSizeLog2)); __ sub(sp, sp, r9); __ mtctr(r3); __ bind(&loop); - __ subi(r9, r9, Operand(kPointerSize)); + __ subi(r9, r9, Operand(kSystemPointerSize)); __ LoadPX(r0, MemOperand(r7, r9)); __ StorePX(r0, MemOperand(sp, r9)); __ bdnz(&loop); @@ -311,11 +312,11 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0: constructor result - // -- sp[0*kPointerSize]: implicit receiver - // -- sp[1*kPointerSize]: padding - // -- sp[2*kPointerSize]: constructor function - // -- sp[3*kPointerSize]: number of arguments - // -- sp[4*kPointerSize]: context + // -- sp[0*kSystemPointerSize]: implicit receiver + // -- sp[1*kSystemPointerSize]: padding + // -- sp[2*kSystemPointerSize]: constructor function + // -- sp[3*kSystemPointerSize]: number of arguments + // -- sp[4*kSystemPointerSize]: context // ----------------------------------- // Store offset of return address for deoptimizer. @@ -366,7 +367,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ SmiToPtrArrayOffset(r4, r4); __ add(sp, sp, r4); - __ addi(sp, sp, Operand(kPointerSize)); + __ addi(sp, sp, Operand(kSystemPointerSize)); __ blr(); } @@ -381,8 +382,9 @@ static void GetSharedFunctionInfoBytecode(MacroAssembler* masm, __ CompareObjectType(sfi_data, scratch1, scratch1, INTERPRETER_DATA_TYPE); __ bne(&done); - __ LoadP(sfi_data, - FieldMemOperand(sfi_data, InterpreterData::kBytecodeArrayOffset)); + __ LoadTaggedPointerField( + sfi_data, + FieldMemOperand(sfi_data, InterpreterData::kBytecodeArrayOffset)); __ bind(&done); } @@ -396,14 +398,16 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { __ AssertGeneratorObject(r4); // Store input value into generator object. - __ StoreP(r3, FieldMemOperand(r4, JSGeneratorObject::kInputOrDebugPosOffset), - r0); + __ StoreTaggedField( + r3, FieldMemOperand(r4, JSGeneratorObject::kInputOrDebugPosOffset), r0); __ RecordWriteField(r4, JSGeneratorObject::kInputOrDebugPosOffset, r3, r6, kLRHasNotBeenSaved, kDontSaveFPRegs); // Load suspended function and context. - __ LoadP(r7, FieldMemOperand(r4, JSGeneratorObject::kFunctionOffset)); - __ LoadP(cp, FieldMemOperand(r7, JSFunction::kContextOffset)); + __ LoadTaggedPointerField( + r7, FieldMemOperand(r4, JSGeneratorObject::kFunctionOffset)); + __ LoadTaggedPointerField(cp, + FieldMemOperand(r7, JSFunction::kContextOffset)); // Flood function if we are stepping. Label prepare_step_in_if_stepping, prepare_step_in_suspended_generator; @@ -436,7 +440,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { __ blt(&stack_overflow); // Push receiver. - __ LoadP(scratch, FieldMemOperand(r4, JSGeneratorObject::kReceiverOffset)); + __ LoadTaggedPointerField( + scratch, FieldMemOperand(r4, JSGeneratorObject::kReceiverOffset)); __ Push(scratch); // ----------- S t a t e ------------- @@ -448,23 +453,26 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { // ----------------------------------- // Copy the function arguments from the generator object's register file. - __ LoadP(r6, FieldMemOperand(r7, JSFunction::kSharedFunctionInfoOffset)); + __ LoadTaggedPointerField( + r6, FieldMemOperand(r7, JSFunction::kSharedFunctionInfoOffset)); __ LoadHalfWord( r6, FieldMemOperand(r6, SharedFunctionInfo::kFormalParameterCountOffset)); - __ LoadP(r5, FieldMemOperand( - r4, JSGeneratorObject::kParametersAndRegistersOffset)); + __ LoadTaggedPointerField( + r5, + FieldMemOperand(r4, JSGeneratorObject::kParametersAndRegistersOffset)); { Label loop, done_loop; __ cmpi(r6, Operand::Zero()); __ ble(&done_loop); - // setup r9 to first element address - kPointerSize + // setup r9 to first element address - kTaggedSize __ addi(r9, r5, - Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize)); + Operand(FixedArray::kHeaderSize - kHeapObjectTag - kTaggedSize)); __ mtctr(r6); __ bind(&loop); - __ LoadPU(scratch, MemOperand(r9, kPointerSize)); + __ LoadAnyTaggedField(scratch, MemOperand(r9, kTaggedSize)); + __ addi(r9, r9, Operand(kTaggedSize)); __ push(scratch); __ bdnz(&loop); @@ -473,8 +481,10 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { // Underlying function needs to have bytecode available. if (FLAG_debug_code) { - __ LoadP(r6, FieldMemOperand(r7, JSFunction::kSharedFunctionInfoOffset)); - __ LoadP(r6, FieldMemOperand(r6, SharedFunctionInfo::kFunctionDataOffset)); + __ LoadTaggedPointerField( + r6, FieldMemOperand(r7, JSFunction::kSharedFunctionInfoOffset)); + __ LoadTaggedPointerField( + r6, FieldMemOperand(r6, SharedFunctionInfo::kFunctionDataOffset)); GetSharedFunctionInfoBytecode(masm, r6, r3); __ CompareObjectType(r6, r6, r6, BYTECODE_ARRAY_TYPE); __ Assert(eq, AbortReason::kMissingBytecodeArray); @@ -488,7 +498,7 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { __ mr(r6, r4); __ mr(r4, r7); static_assert(kJavaScriptCallCodeStartRegister == r5, "ABI mismatch"); - __ LoadP(r5, FieldMemOperand(r4, JSFunction::kCodeOffset)); + __ LoadTaggedPointerField(r5, FieldMemOperand(r4, JSFunction::kCodeOffset)); __ JumpCodeObject(r5); } @@ -500,7 +510,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { __ PushRoot(RootIndex::kTheHoleValue); __ CallRuntime(Runtime::kDebugOnFunctionCall); __ Pop(r4); - __ LoadP(r7, FieldMemOperand(r4, JSGeneratorObject::kFunctionOffset)); + __ LoadTaggedPointerField( + r7, FieldMemOperand(r4, JSGeneratorObject::kFunctionOffset)); } __ b(&stepping_prepared); @@ -510,7 +521,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { __ Push(r4); __ CallRuntime(Runtime::kDebugPrepareStepInSuspendedGenerator); __ Pop(r4); - __ LoadP(r7, FieldMemOperand(r4, JSGeneratorObject::kFunctionOffset)); + __ LoadTaggedPointerField( + r7, FieldMemOperand(r4, JSGeneratorObject::kFunctionOffset)); } __ b(&stepping_prepared); @@ -560,7 +572,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type, // PPC LINUX ABI: // preserve LR in pre-reserved slot in caller's frame __ mflr(r0); - __ StoreP(r0, MemOperand(sp, kStackFrameLRSlot * kPointerSize)); + __ StoreP(r0, MemOperand(sp, kStackFrameLRSlot * kSystemPointerSize)); // Save callee saved registers on the stack. __ MultiPush(kCalleeSaved); @@ -695,7 +707,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type, __ MultiPop(kCalleeSaved); // Return - __ LoadP(r0, MemOperand(sp, kStackFrameLRSlot * kPointerSize)); + __ LoadP(r0, MemOperand(sp, kStackFrameLRSlot * kSystemPointerSize)); __ mtlr(r0); __ blr(); } @@ -729,7 +741,7 @@ static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc, // here which will cause scratch1 to become negative. __ sub(scratch1, sp, scratch1); // Check if the arguments will overflow the stack. - __ ShiftLeftImm(scratch2, argc, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(scratch2, argc, Operand(kSystemPointerSizeLog2)); __ cmp(scratch1, scratch2); __ bgt(&okay); // Signed comparison. @@ -787,13 +799,13 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // r3: argc // r8: argv, i.e. points to first arg Label loop, entry; - __ ShiftLeftImm(r0, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r0, r3, Operand(kSystemPointerSizeLog2)); __ add(r5, r8, r0); // r5 points past last arg. __ b(&entry); __ bind(&loop); __ LoadP(r9, MemOperand(r8)); // read next parameter - __ addi(r8, r8, Operand(kPointerSize)); + __ addi(r8, r8, Operand(kSystemPointerSize)); __ LoadP(r0, MemOperand(r9)); // dereference handle __ push(r0); // push parameter __ bind(&entry); @@ -851,8 +863,8 @@ static void ReplaceClosureCodeWithOptimizedCode(MacroAssembler* masm, Register scratch1, Register scratch2) { // Store code entry in the closure. - __ StoreP(optimized_code, FieldMemOperand(closure, JSFunction::kCodeOffset), - r0); + __ StoreTaggedField(optimized_code, + FieldMemOperand(closure, JSFunction::kCodeOffset), r0); __ mr(scratch1, optimized_code); // Write barrier clobbers scratch1 below. __ RecordWriteField(closure, JSFunction::kCodeOffset, scratch1, scratch2, kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, @@ -900,8 +912,9 @@ static void TailCallOptimizedCodeSlot(MacroAssembler* masm, // Check if the optimized code is marked for deopt. If it is, call the // runtime to clear it. Label found_deoptimized_code; - __ LoadP(scratch, FieldMemOperand(optimized_code_entry, - Code::kCodeDataContainerOffset)); + __ LoadTaggedPointerField( + scratch, + FieldMemOperand(optimized_code_entry, Code::kCodeDataContainerOffset)); __ LoadWordArith( scratch, FieldMemOperand(scratch, CodeDataContainer::kKindSpecificFlagsOffset)); @@ -1057,10 +1070,12 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { // Get the bytecode array from the function object and load it into // kInterpreterBytecodeArrayRegister. - __ LoadP(r3, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset)); + __ LoadTaggedPointerField( + r3, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset)); // Load original bytecode array or the debug copy. - __ LoadP(kInterpreterBytecodeArrayRegister, - FieldMemOperand(r3, SharedFunctionInfo::kFunctionDataOffset)); + __ LoadTaggedPointerField( + kInterpreterBytecodeArrayRegister, + FieldMemOperand(r3, SharedFunctionInfo::kFunctionDataOffset)); GetSharedFunctionInfoBytecode(masm, kInterpreterBytecodeArrayRegister, r7); // The bytecode array could have been flushed from the shared function info, @@ -1071,15 +1086,17 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { __ bne(&compile_lazy); // Load the feedback vector from the closure. - __ LoadP(feedback_vector, - FieldMemOperand(closure, JSFunction::kFeedbackCellOffset)); - __ LoadP(feedback_vector, - FieldMemOperand(feedback_vector, Cell::kValueOffset)); + __ LoadTaggedPointerField( + feedback_vector, + FieldMemOperand(closure, JSFunction::kFeedbackCellOffset)); + __ LoadTaggedPointerField( + feedback_vector, FieldMemOperand(feedback_vector, Cell::kValueOffset)); Label push_stack_frame; // Check if feedback vector is valid. If valid, check for optimized code // and update invocation count. Otherwise, setup the stack frame. - __ LoadP(r7, FieldMemOperand(feedback_vector, HeapObject::kMapOffset)); + __ LoadTaggedPointerField( + r7, FieldMemOperand(feedback_vector, HeapObject::kMapOffset)); __ LoadHalfWord(r7, FieldMemOperand(r7, Map::kInstanceTypeOffset)); __ cmpi(r7, Operand(FEEDBACK_VECTOR_TYPE)); __ bne(&push_stack_frame); @@ -1087,9 +1104,10 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { Register optimized_code_entry = r7; // Read off the optimized code slot in the feedback vector. - __ LoadP(optimized_code_entry, - FieldMemOperand(feedback_vector, - FeedbackVector::kOptimizedCodeWeakOrSmiOffset)); + __ LoadAnyTaggedField( + optimized_code_entry, + FieldMemOperand(feedback_vector, + FeedbackVector::kOptimizedCodeWeakOrSmiOffset)); // Check if the optimized code slot is not empty. Label optimized_code_slot_not_empty; __ CmpSmiLiteral(optimized_code_entry, @@ -1156,7 +1174,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { // TODO(rmcilroy): Consider doing more than one push per loop iteration. Label loop, no_args; __ LoadRoot(kInterpreterAccumulatorRegister, RootIndex::kUndefinedValue); - __ ShiftRightImm(r5, r5, Operand(kPointerSizeLog2), SetRC); + __ ShiftRightImm(r5, r5, Operand(kSystemPointerSizeLog2), SetRC); __ beq(&no_args, cr0); __ mtctr(r5); __ bind(&loop); @@ -1174,7 +1192,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { BytecodeArray::kIncomingNewTargetOrGeneratorRegisterOffset)); __ cmpi(r8, Operand::Zero()); __ beq(&no_incoming_new_target_or_generator_register); - __ ShiftLeftImm(r8, r8, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r8, r8, Operand(kSystemPointerSizeLog2)); __ StorePX(r6, MemOperand(fp, r8)); __ bind(&no_incoming_new_target_or_generator_register); @@ -1197,7 +1215,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { ExternalReference::interpreter_dispatch_table_address(masm->isolate())); __ lbzx(r6, MemOperand(kInterpreterBytecodeArrayRegister, kInterpreterBytecodeOffsetRegister)); - __ ShiftLeftImm(r6, r6, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r6, r6, Operand(kSystemPointerSizeLog2)); __ LoadPX(kJavaScriptCallCodeStartRegister, MemOperand(kInterpreterDispatchTableRegister, r6)); __ Call(kJavaScriptCallCodeStartRegister); @@ -1282,10 +1300,10 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, Label loop, skip; __ cmpi(count, Operand::Zero()); __ beq(&skip); - __ addi(index, index, Operand(kPointerSize)); // Bias up for LoadPU + __ addi(index, index, Operand(kSystemPointerSize)); // Bias up for LoadPU __ mtctr(count); __ bind(&loop); - __ LoadPU(scratch, MemOperand(index, -kPointerSize)); + __ LoadPU(scratch, MemOperand(index, -kSystemPointerSize)); __ push(scratch); __ bdnz(&loop); __ bind(&skip); @@ -1409,15 +1427,17 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { // get the custom trampoline, otherwise grab the entry address of the global // trampoline. __ LoadP(r5, MemOperand(fp, StandardFrameConstants::kFunctionOffset)); - __ LoadP(r5, FieldMemOperand(r5, JSFunction::kSharedFunctionInfoOffset)); - __ LoadP(r5, FieldMemOperand(r5, SharedFunctionInfo::kFunctionDataOffset)); + __ LoadTaggedPointerField( + r5, FieldMemOperand(r5, JSFunction::kSharedFunctionInfoOffset)); + __ LoadTaggedPointerField( + r5, FieldMemOperand(r5, SharedFunctionInfo::kFunctionDataOffset)); __ CompareObjectType(r5, kInterpreterDispatchTableRegister, kInterpreterDispatchTableRegister, INTERPRETER_DATA_TYPE); __ bne(&builtin_trampoline); - __ LoadP(r5, - FieldMemOperand(r5, InterpreterData::kInterpreterTrampolineOffset)); + __ LoadTaggedPointerField( + r5, FieldMemOperand(r5, InterpreterData::kInterpreterTrampolineOffset)); __ addi(r5, r5, Operand(Code::kHeaderSize - kHeapObjectTag)); __ b(&trampoline_loaded); @@ -1472,7 +1492,7 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { Register scratch = temps.Acquire(); __ lbzx(ip, MemOperand(kInterpreterBytecodeArrayRegister, kInterpreterBytecodeOffsetRegister)); - __ ShiftLeftImm(scratch, scratch, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(scratch, scratch, Operand(kSystemPointerSizeLog2)); __ LoadPX(kJavaScriptCallCodeStartRegister, MemOperand(kInterpreterDispatchTableRegister, scratch)); __ Jump(kJavaScriptCallCodeStartRegister); @@ -1538,9 +1558,10 @@ void Generate_ContinueToBuiltinHelper(MacroAssembler* masm, // Overwrite the hole inserted by the deoptimizer with the return value from // the LAZY deopt point. __ StoreP( - r3, MemOperand( - sp, config->num_allocatable_general_registers() * kPointerSize + - BuiltinContinuationFrameConstants::kFixedFrameSize)); + r3, + MemOperand(sp, config->num_allocatable_general_registers() * + kSystemPointerSize + + BuiltinContinuationFrameConstants::kFixedFrameSize)); } for (int i = allocatable_register_count - 1; i >= 0; --i) { int code = config->GetAllocatableGeneralCode(i); @@ -1591,8 +1612,8 @@ void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { } DCHECK_EQ(kInterpreterAccumulatorRegister.code(), r3.code()); - __ LoadP(r3, MemOperand(sp, 0 * kPointerSize)); - __ addi(sp, sp, Operand(1 * kPointerSize)); + __ LoadP(r3, MemOperand(sp, 0 * kSystemPointerSize)); + __ addi(sp, sp, Operand(1 * kSystemPointerSize)); __ Ret(); } @@ -1616,7 +1637,8 @@ void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { // Load deoptimization data from the code object. // = [#deoptimization_data_offset] - __ LoadP(r4, FieldMemOperand(r3, Code::kDeoptimizationDataOffset)); + __ LoadTaggedPointerField( + r4, FieldMemOperand(r3, Code::kDeoptimizationDataOffset)); { ConstantPoolUnavailableScope constant_pool_unavailable(masm); @@ -1628,10 +1650,9 @@ void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { // Load the OSR entrypoint offset from the deoptimization data. // = [#header_size + #osr_pc_offset] - __ LoadP(r4, - FieldMemOperand(r4, FixedArray::OffsetOfElementAt( - DeoptimizationData::kOsrPcOffsetIndex))); - __ SmiUntag(r4); + __ SmiUntagField( + r4, FieldMemOperand(r4, FixedArray::OffsetOfElementAt( + DeoptimizationData::kOsrPcOffsetIndex))); // Compute the target address = code start + osr_offset __ add(r0, r3, r4); @@ -1659,16 +1680,16 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { Register arg_size = r8; Register new_sp = r6; Register scratch = r7; - __ ShiftLeftImm(arg_size, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(arg_size, r3, Operand(kSystemPointerSizeLog2)); __ add(new_sp, sp, arg_size); __ LoadRoot(scratch, RootIndex::kUndefinedValue); __ mr(r5, scratch); __ LoadP(r4, MemOperand(new_sp, 0)); // receiver - __ cmpi(arg_size, Operand(kPointerSize)); + __ cmpi(arg_size, Operand(kSystemPointerSize)); __ blt(&skip); - __ LoadP(scratch, MemOperand(new_sp, 1 * -kPointerSize)); // thisArg + __ LoadP(scratch, MemOperand(new_sp, 1 * -kSystemPointerSize)); // thisArg __ beq(&skip); - __ LoadP(r5, MemOperand(new_sp, 2 * -kPointerSize)); // argArray + __ LoadP(r5, MemOperand(new_sp, 2 * -kSystemPointerSize)); // argArray __ bind(&skip); __ mr(sp, new_sp); __ StoreP(scratch, MemOperand(sp, 0)); @@ -1717,7 +1738,7 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { // 2. Get the callable to call (passed as receiver) from the stack. // r3: actual number of arguments - __ ShiftLeftImm(r5, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r5, r3, Operand(kSystemPointerSizeLog2)); __ LoadPX(r4, MemOperand(sp, r5)); // 3. Shift arguments and return address one slot down on the stack @@ -1733,9 +1754,9 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { __ mtctr(r3); __ bind(&loop); - __ LoadP(scratch, MemOperand(r5, -kPointerSize)); + __ LoadP(scratch, MemOperand(r5, -kSystemPointerSize)); __ StoreP(scratch, MemOperand(r5)); - __ subi(r5, r5, Operand(kPointerSize)); + __ subi(r5, r5, Operand(kSystemPointerSize)); __ bdnz(&loop); // Adjust the actual number of arguments and remove the top element // (which is a copy of the last argument). @@ -1764,19 +1785,20 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) { Register arg_size = r8; Register new_sp = r6; Register scratch = r7; - __ ShiftLeftImm(arg_size, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(arg_size, r3, Operand(kSystemPointerSizeLog2)); __ add(new_sp, sp, arg_size); __ LoadRoot(r4, RootIndex::kUndefinedValue); __ mr(scratch, r4); __ mr(r5, r4); - __ cmpi(arg_size, Operand(kPointerSize)); + __ cmpi(arg_size, Operand(kSystemPointerSize)); __ blt(&skip); - __ LoadP(r4, MemOperand(new_sp, 1 * -kPointerSize)); // target + __ LoadP(r4, MemOperand(new_sp, 1 * -kSystemPointerSize)); // target __ beq(&skip); - __ LoadP(scratch, MemOperand(new_sp, 2 * -kPointerSize)); // thisArgument - __ cmpi(arg_size, Operand(2 * kPointerSize)); + __ LoadP(scratch, + MemOperand(new_sp, 2 * -kSystemPointerSize)); // thisArgument + __ cmpi(arg_size, Operand(2 * kSystemPointerSize)); __ beq(&skip); - __ LoadP(r5, MemOperand(new_sp, 3 * -kPointerSize)); // argumentsList + __ LoadP(r5, MemOperand(new_sp, 3 * -kSystemPointerSize)); // argumentsList __ bind(&skip); __ mr(sp, new_sp); __ StoreP(scratch, MemOperand(sp, 0)); @@ -1814,21 +1836,21 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { Label skip; Register arg_size = r8; Register new_sp = r7; - __ ShiftLeftImm(arg_size, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(arg_size, r3, Operand(kSystemPointerSizeLog2)); __ add(new_sp, sp, arg_size); __ LoadRoot(r4, RootIndex::kUndefinedValue); __ mr(r5, r4); __ mr(r6, r4); __ StoreP(r4, MemOperand(new_sp, 0)); // receiver (undefined) - __ cmpi(arg_size, Operand(kPointerSize)); + __ cmpi(arg_size, Operand(kSystemPointerSize)); __ blt(&skip); - __ LoadP(r4, MemOperand(new_sp, 1 * -kPointerSize)); // target + __ LoadP(r4, MemOperand(new_sp, 1 * -kSystemPointerSize)); // target __ mr(r6, r4); // new.target defaults to target __ beq(&skip); - __ LoadP(r5, MemOperand(new_sp, 2 * -kPointerSize)); // argumentsList - __ cmpi(arg_size, Operand(2 * kPointerSize)); + __ LoadP(r5, MemOperand(new_sp, 2 * -kSystemPointerSize)); // argumentsList + __ cmpi(arg_size, Operand(2 * kSystemPointerSize)); __ beq(&skip); - __ LoadP(r6, MemOperand(new_sp, 3 * -kPointerSize)); // new.target + __ LoadP(r6, MemOperand(new_sp, 3 * -kSystemPointerSize)); // new.target __ bind(&skip); __ mr(sp, new_sp); } @@ -1875,7 +1897,7 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { // Get the number of arguments passed (as a smi), tear down the frame and // then tear down the parameters. __ LoadP(r4, MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); - int stack_adjustment = kPointerSize; // adjust for receiver + int stack_adjustment = kSystemPointerSize; // adjust for receiver __ LeaveFrame(StackFrame::ARGUMENTS_ADAPTOR, stack_adjustment); __ SmiToPtrArrayOffset(r0, r4); __ add(sp, sp, r0); @@ -1898,7 +1920,8 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, // Allow r5 to be a FixedArray, or a FixedDoubleArray if r7 == 0. Label ok, fail; __ AssertNotSmi(r5); - __ LoadP(scratch, FieldMemOperand(r5, HeapObject::kMapOffset)); + __ LoadTaggedPointerField(scratch, + FieldMemOperand(r5, HeapObject::kMapOffset)); __ LoadHalfWord(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); __ cmpi(scratch, Operand(FIXED_ARRAY_TYPE)); @@ -1924,10 +1947,11 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, __ cmpi(r7, Operand::Zero()); __ beq(&no_args); __ addi(r5, r5, - Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize)); + Operand(FixedArray::kHeaderSize - kHeapObjectTag - kTaggedSize)); __ mtctr(r7); __ bind(&loop); - __ LoadPU(scratch, MemOperand(r5, kPointerSize)); + __ LoadTaggedPointerField(scratch, MemOperand(r5, kTaggedSize)); + __ addi(r5, r5, Operand(kTaggedSize)); __ CompareRoot(scratch, RootIndex::kTheHoleValue); __ bne(&skip); __ LoadRoot(scratch, RootIndex::kUndefinedValue); @@ -1961,7 +1985,8 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm, if (mode == CallOrConstructMode::kConstruct) { Label new_target_constructor, new_target_not_constructor; __ JumpIfSmi(r6, &new_target_not_constructor); - __ LoadP(scratch, FieldMemOperand(r6, HeapObject::kMapOffset)); + __ LoadTaggedPointerField(scratch, + FieldMemOperand(r6, HeapObject::kMapOffset)); __ lbz(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); __ TestBit(scratch, Map::Bits1::IsConstructorBit::kShift, r0); __ bne(&new_target_constructor, cr0); @@ -1985,7 +2010,8 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm, __ beq(&arguments_adaptor); { __ LoadP(r8, MemOperand(fp, StandardFrameConstants::kFunctionOffset)); - __ LoadP(r8, FieldMemOperand(r8, JSFunction::kSharedFunctionInfoOffset)); + __ LoadTaggedPointerField( + r8, FieldMemOperand(r8, JSFunction::kSharedFunctionInfoOffset)); __ LoadHalfWord( r8, FieldMemOperand(r8, SharedFunctionInfo::kFormalParameterCountOffset)); @@ -2011,11 +2037,11 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm, // Forward the arguments from the caller frame. { Label loop; - __ addi(r7, r7, Operand(kPointerSize)); + __ addi(r7, r7, Operand(kSystemPointerSize)); __ add(r3, r3, r8); __ bind(&loop); { - __ ShiftLeftImm(scratch, r8, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(scratch, r8, Operand(kSystemPointerSizeLog2)); __ LoadPX(scratch, MemOperand(r7, scratch)); __ push(scratch); __ subi(r8, r8, Operand(1)); @@ -2045,7 +2071,8 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) // Check that the function is not a "classConstructor". Label class_constructor; - __ LoadP(r5, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); + __ LoadTaggedPointerField( + r5, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); __ lwz(r6, FieldMemOperand(r5, SharedFunctionInfo::kFlagsOffset)); __ TestBitMask(r6, SharedFunctionInfo::IsClassConstructorBit::kMask, r0); __ bne(&class_constructor, cr0); @@ -2053,7 +2080,8 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, // Enter the context of the function; ToObject has to run in the function // context, and we also need to take the global proxy from the function // context in case of conversion. - __ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset)); + __ LoadTaggedPointerField(cp, + FieldMemOperand(r4, JSFunction::kContextOffset)); // We need to convert the receiver for non-native sloppy mode functions. Label done_convert; __ andi(r0, r6, @@ -2073,7 +2101,7 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, __ LoadGlobalProxy(r6); } else { Label convert_to_object, convert_receiver; - __ ShiftLeftImm(r6, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r6, r3, Operand(kSystemPointerSizeLog2)); __ LoadPX(r6, MemOperand(sp, r6)); __ JumpIfSmi(r6, &convert_to_object); STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); @@ -2107,10 +2135,11 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, __ Pop(r3, r4); __ SmiUntag(r3); } - __ LoadP(r5, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); + __ LoadTaggedPointerField( + r5, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); __ bind(&convert_receiver); } - __ ShiftLeftImm(r7, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r7, r3, Operand(kSystemPointerSizeLog2)); __ StorePX(r6, MemOperand(sp, r7)); } __ bind(&done_convert); @@ -2146,9 +2175,9 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { // Load [[BoundArguments]] into r5 and length of that into r7. Label no_bound_arguments; - __ LoadP(r5, FieldMemOperand(r4, JSBoundFunction::kBoundArgumentsOffset)); - __ LoadP(r7, FieldMemOperand(r5, FixedArray::kLengthOffset)); - __ SmiUntag(r7, SetRC); + __ LoadTaggedPointerField( + r5, FieldMemOperand(r4, JSBoundFunction::kBoundArgumentsOffset)); + __ SmiUntagField(r7, FieldMemOperand(r5, FixedArray::kLengthOffset), SetRC); __ beq(&no_bound_arguments, cr0); { // ----------- S t a t e ------------- @@ -2163,9 +2192,8 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { // Reserve stack space for the [[BoundArguments]]. { Label done; - __ mr(scratch, sp); // preserve previous stack pointer - __ ShiftLeftImm(r10, r7, Operand(kPointerSizeLog2)); - __ sub(sp, sp, r10); + __ ShiftLeftImm(r10, r7, Operand(kSystemPointerSizeLog2)); + __ sub(r0, sp, r10); // Check the stack for overflow. We are not trying to catch interruptions // (i.e. debug break and preemption) here, so check the "real stack // limit". @@ -2173,11 +2201,9 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { UseScratchRegisterScope temps(masm); Register scratch = temps.Acquire(); LoadStackLimit(masm, scratch, StackLimitKind::kRealStackLimit); - __ cmpl(sp, scratch); + __ cmpl(r0, scratch); } __ bgt(&done); // Signed comparison. - // Restore the stack pointer. - __ mr(sp, scratch); { FrameScope scope(masm, StackFrame::MANUAL); __ EnterFrame(StackFrame::INTERNAL); @@ -2186,6 +2212,9 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { __ bind(&done); } + __ mr(scratch, sp); + __ mr(sp, r0); + // Relocate arguments down the stack. // -- r3 : the number of arguments (not including the receiver) // -- r9 : the previous stack pointer @@ -2199,7 +2228,7 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { __ bind(&loop); __ LoadPX(r0, MemOperand(scratch, r8)); __ StorePX(r0, MemOperand(sp, r8)); - __ addi(r8, r8, Operand(kPointerSize)); + __ addi(r8, r8, Operand(kSystemPointerSize)); __ bdnz(&loop); __ bind(&skip); } @@ -2207,13 +2236,15 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { // Copy [[BoundArguments]] to the stack (below the arguments). { Label loop; - __ addi(r5, r5, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ ShiftLeftImm(r10, r7, Operand(kTaggedSizeLog2)); + __ addi(r10, r10, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ add(r5, r5, r10); __ mtctr(r7); __ bind(&loop); - __ LoadPU(r0, MemOperand(r5, -kPointerSize)); - __ StorePX(r0, MemOperand(sp, r8)); - __ addi(r8, r8, Operand(kPointerSize)); + __ LoadAnyTaggedField(ip, MemOperand(r5, -kTaggedSize), r0); + __ StorePX(ip, MemOperand(sp, r8)); + __ addi(r8, r8, Operand(kSystemPointerSize)); + __ addi(r5, r5, Operand(-kTaggedSize)); __ bdnz(&loop); __ add(r3, r3, r7); } @@ -2232,16 +2263,17 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) { __ AssertBoundFunction(r4); // Patch the receiver to [[BoundThis]]. - __ LoadP(r6, FieldMemOperand(r4, JSBoundFunction::kBoundThisOffset)); - __ ShiftLeftImm(r0, r3, Operand(kPointerSizeLog2)); + __ LoadAnyTaggedField(r6, + FieldMemOperand(r4, JSBoundFunction::kBoundThisOffset)); + __ ShiftLeftImm(r0, r3, Operand(kSystemPointerSizeLog2)); __ StorePX(r6, MemOperand(sp, r0)); // Push the [[BoundArguments]] onto the stack. Generate_PushBoundArguments(masm); // Call the [[BoundTargetFunction]] via the Call builtin. - __ LoadP(r4, - FieldMemOperand(r4, JSBoundFunction::kBoundTargetFunctionOffset)); + __ LoadTaggedPointerField( + r4, FieldMemOperand(r4, JSBoundFunction::kBoundTargetFunctionOffset)); __ Jump(BUILTIN_CODE(masm->isolate(), Call_ReceiverIsAny), RelocInfo::CODE_TARGET); } @@ -2275,7 +2307,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { // 2. Call to something else, which might have a [[Call]] internal method (if // not we raise an exception). // Overwrite the original receiver the (original) target. - __ ShiftLeftImm(r8, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r8, r3, Operand(kSystemPointerSizeLog2)); __ StorePX(r4, MemOperand(sp, r8)); // Let the "call_as_function_delegate" take care of the rest. __ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, r4); @@ -2309,7 +2341,8 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { Label call_generic_stub; // Jump to JSBuiltinsConstructStub or JSConstructStubGeneric. - __ LoadP(r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); + __ LoadTaggedPointerField( + r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); __ lwz(r7, FieldMemOperand(r7, SharedFunctionInfo::kFlagsOffset)); __ mov(ip, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); __ and_(r7, r7, ip, SetRC); @@ -2338,15 +2371,15 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) { // Patch new.target to [[BoundTargetFunction]] if new.target equals target. Label skip; - __ cmp(r4, r6); + __ CompareTagged(r4, r6); __ bne(&skip); - __ LoadP(r6, - FieldMemOperand(r4, JSBoundFunction::kBoundTargetFunctionOffset)); + __ LoadTaggedPointerField( + r6, FieldMemOperand(r4, JSBoundFunction::kBoundTargetFunctionOffset)); __ bind(&skip); // Construct the [[BoundTargetFunction]] via the Construct builtin. - __ LoadP(r4, - FieldMemOperand(r4, JSBoundFunction::kBoundTargetFunctionOffset)); + __ LoadTaggedPointerField( + r4, FieldMemOperand(r4, JSBoundFunction::kBoundTargetFunctionOffset)); __ Jump(BUILTIN_CODE(masm->isolate(), Construct), RelocInfo::CODE_TARGET); } @@ -2364,7 +2397,7 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { __ JumpIfSmi(r4, &non_constructor); // Check if target has a [[Construct]] internal method. - __ LoadP(r7, FieldMemOperand(r4, HeapObject::kMapOffset)); + __ LoadTaggedPointerField(r7, FieldMemOperand(r4, HeapObject::kMapOffset)); __ lbz(r5, FieldMemOperand(r7, Map::kBitFieldOffset)); __ TestBit(r5, Map::Bits1::IsConstructorBit::kShift, r0); __ beq(&non_constructor, cr0); @@ -2390,7 +2423,7 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { __ bind(&non_proxy); { // Overwrite the original receiver with the (original) target. - __ ShiftLeftImm(r8, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r8, r3, Operand(kSystemPointerSizeLog2)); __ StorePX(r4, MemOperand(sp, r8)); // Let the "call_as_constructor_delegate" take care of the rest. __ LoadNativeContextSlot(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, r4); @@ -2416,7 +2449,8 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { Label dont_adapt_arguments, stack_overflow, skip_adapt_arguments; __ cmpli(r5, Operand(kDontAdaptArgumentsSentinel)); __ beq(&dont_adapt_arguments); - __ LoadP(r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); + __ LoadTaggedPointerField( + r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); __ lwz(r7, FieldMemOperand(r7, SharedFunctionInfo::kFlagsOffset)); __ TestBitMask(r7, SharedFunctionInfo::IsSafeToSkipArgumentsAdaptorBit::kMask, r0); @@ -2444,8 +2478,8 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { __ SmiToPtrArrayOffset(r3, r3); __ add(r3, r3, fp); // adjust for return address and receiver - __ addi(r3, r3, Operand(2 * kPointerSize)); - __ ShiftLeftImm(r7, r5, Operand(kPointerSizeLog2)); + __ addi(r3, r3, Operand(2 * kSystemPointerSize)); + __ ShiftLeftImm(r7, r5, Operand(kSystemPointerSizeLog2)); __ sub(r7, r3, r7); // Copy the arguments (including the receiver) to the new stack frame. @@ -2460,7 +2494,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { __ LoadP(r0, MemOperand(r3, 0)); __ push(r0); __ cmp(r3, r7); // Compare before moving to next argument. - __ subi(r3, r3, Operand(kPointerSize)); + __ subi(r3, r3, Operand(kSystemPointerSize)); __ bne(©); __ b(&invoke); @@ -2488,10 +2522,10 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { Label copy; __ bind(©); // Adjust load for return address and receiver. - __ LoadP(r0, MemOperand(r3, 2 * kPointerSize)); + __ LoadP(r0, MemOperand(r3, 2 * kSystemPointerSize)); __ push(r0); __ cmp(r3, fp); // Compare before moving to next argument. - __ subi(r3, r3, Operand(kPointerSize)); + __ subi(r3, r3, Operand(kSystemPointerSize)); __ bne(©); // Fill the remaining expected arguments with undefined. @@ -2499,12 +2533,12 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // r5: expected number of arguments // r6: new target (passed through to callee) __ LoadRoot(r0, RootIndex::kUndefinedValue); - __ ShiftLeftImm(r7, r5, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r7, r5, Operand(kSystemPointerSizeLog2)); __ sub(r7, fp, r7); // Adjust for frame. __ subi(r7, r7, Operand(ArgumentsAdaptorFrameConstants::kFixedFrameSizeFromFp + - kPointerSize)); + kSystemPointerSize)); Label fill; __ bind(&fill); @@ -2520,7 +2554,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // r4 : function (passed through to callee) // r6 : new target (passed through to callee) static_assert(kJavaScriptCallCodeStartRegister == r5, "ABI mismatch"); - __ LoadP(r5, FieldMemOperand(r4, JSFunction::kCodeOffset)); + __ LoadTaggedPointerField(r5, FieldMemOperand(r4, JSFunction::kCodeOffset)); __ CallCodeObject(r5); // Store offset of return address for deoptimizer. @@ -2549,7 +2583,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // Remove superfluous parameters from the stack. __ sub(r7, r3, r5); __ mr(r3, r5); - __ ShiftLeftImm(r7, r7, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r7, r7, Operand(kSystemPointerSizeLog2)); __ add(sp, sp, r7); __ b(&dont_adapt_arguments); } @@ -2572,8 +2606,9 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // Dont adapt arguments. // ------------------------------------------- __ bind(&dont_adapt_arguments); + __ RecordComment("-- Call without adapting args --"); static_assert(kJavaScriptCallCodeStartRegister == r5, "ABI mismatch"); - __ LoadP(r5, FieldMemOperand(r4, JSFunction::kCodeOffset)); + __ LoadTaggedPointerField(r5, FieldMemOperand(r4, JSFunction::kCodeOffset)); __ JumpCodeObject(r5); __ bind(&stack_overflow); @@ -2663,9 +2698,9 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, __ mr(r4, r5); } else { // Compute the argv pointer. - __ ShiftLeftImm(r4, r3, Operand(kPointerSizeLog2)); + __ ShiftLeftImm(r4, r3, Operand(kSystemPointerSizeLog2)); __ add(r4, r4, sp); - __ subi(r4, r4, Operand(kPointerSize)); + __ subi(r4, r4, Operand(kSystemPointerSize)); } // Enter the exit frame that transitions from JavaScript to C++. @@ -2701,7 +2736,8 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, // buffer as implicit first argument. __ mr(r5, r4); __ mr(r4, r3); - __ addi(r3, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize)); + __ addi(r3, sp, + Operand((kStackFrameExtraParamSlot + 1) * kSystemPointerSize)); isolate_reg = r6; } @@ -2713,7 +2749,7 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, // If return value is on the stack, pop it to registers. if (needs_return_buffer) { - __ LoadP(r4, MemOperand(r3, kPointerSize)); + __ LoadP(r4, MemOperand(r3, kSystemPointerSize)); __ LoadP(r3, MemOperand(r3)); } @@ -2828,7 +2864,7 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) { __ Push(result_reg, scratch); // Account for saved regs. - int argument_offset = 2 * kPointerSize; + int argument_offset = 2 * kSystemPointerSize; // Load double input. __ lfd(double_scratch, MemOperand(sp, argument_offset)); @@ -2850,7 +2886,7 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) { __ Push(scratch_high, scratch_low); // Account for saved regs. - argument_offset += 2 * kPointerSize; + argument_offset += 2 * kSystemPointerSize; __ lwz(scratch_high, MemOperand(sp, argument_offset + Register::kExponentOffset)); @@ -2921,7 +2957,7 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) { __ bind(&done); __ Pop(scratch_high, scratch_low); // Account for saved regs. - argument_offset -= 2 * kPointerSize; + argument_offset -= 2 * kSystemPointerSize; __ bind(&fastpath_done); __ StoreP(result_reg, MemOperand(sp, argument_offset)); @@ -3092,33 +3128,33 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) { // Set up FunctionCallbackInfo's implicit_args on the stack as follows: // // Target state: - // sp[0 * kPointerSize]: kHolder - // sp[1 * kPointerSize]: kIsolate - // sp[2 * kPointerSize]: undefined (kReturnValueDefaultValue) - // sp[3 * kPointerSize]: undefined (kReturnValue) - // sp[4 * kPointerSize]: kData - // sp[5 * kPointerSize]: undefined (kNewTarget) + // sp[0 * kSystemPointerSize]: kHolder + // sp[1 * kSystemPointerSize]: kIsolate + // sp[2 * kSystemPointerSize]: undefined (kReturnValueDefaultValue) + // sp[3 * kSystemPointerSize]: undefined (kReturnValue) + // sp[4 * kSystemPointerSize]: kData + // sp[5 * kSystemPointerSize]: undefined (kNewTarget) // Reserve space on the stack. - __ subi(sp, sp, Operand(FCA::kArgsLength * kPointerSize)); + __ subi(sp, sp, Operand(FCA::kArgsLength * kSystemPointerSize)); // kHolder. - __ StoreP(holder, MemOperand(sp, 0 * kPointerSize)); + __ StoreP(holder, MemOperand(sp, 0 * kSystemPointerSize)); // kIsolate. __ Move(scratch, ExternalReference::isolate_address(masm->isolate())); - __ StoreP(scratch, MemOperand(sp, 1 * kPointerSize)); + __ StoreP(scratch, MemOperand(sp, 1 * kSystemPointerSize)); // kReturnValueDefaultValue and kReturnValue. __ LoadRoot(scratch, RootIndex::kUndefinedValue); - __ StoreP(scratch, MemOperand(sp, 2 * kPointerSize)); - __ StoreP(scratch, MemOperand(sp, 3 * kPointerSize)); + __ StoreP(scratch, MemOperand(sp, 2 * kSystemPointerSize)); + __ StoreP(scratch, MemOperand(sp, 3 * kSystemPointerSize)); // kData. - __ StoreP(call_data, MemOperand(sp, 4 * kPointerSize)); + __ StoreP(call_data, MemOperand(sp, 4 * kSystemPointerSize)); // kNewTarget. - __ StoreP(scratch, MemOperand(sp, 5 * kPointerSize)); + __ StoreP(scratch, MemOperand(sp, 5 * kSystemPointerSize)); // Keep a pointer to kHolder (= implicit_args) in a scratch register. // We use it below to set up the FunctionCallbackInfo object. @@ -3140,31 +3176,34 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) { // FunctionCallbackInfo::implicit_args_ (points at kHolder as set up above). // Arguments are after the return address (pushed by EnterExitFrame()). - __ StoreP(scratch, - MemOperand(sp, (kStackFrameExtraParamSlot + 1) * kPointerSize)); + __ StoreP(scratch, MemOperand(sp, (kStackFrameExtraParamSlot + 1) * + kSystemPointerSize)); // FunctionCallbackInfo::values_ (points at the first varargs argument passed // on the stack). - __ addi(scratch, scratch, Operand((FCA::kArgsLength - 1) * kPointerSize)); - __ ShiftLeftImm(ip, argc, Operand(kPointerSizeLog2)); + __ addi(scratch, scratch, + Operand((FCA::kArgsLength - 1) * kSystemPointerSize)); + __ ShiftLeftImm(ip, argc, Operand(kSystemPointerSizeLog2)); __ add(scratch, scratch, ip); - __ StoreP(scratch, - MemOperand(sp, (kStackFrameExtraParamSlot + 2) * kPointerSize)); + __ StoreP(scratch, MemOperand(sp, (kStackFrameExtraParamSlot + 2) * + kSystemPointerSize)); // FunctionCallbackInfo::length_. - __ stw(argc, MemOperand(sp, (kStackFrameExtraParamSlot + 3) * kPointerSize)); + __ stw(argc, + MemOperand(sp, (kStackFrameExtraParamSlot + 3) * kSystemPointerSize)); // We also store the number of bytes to drop from the stack after returning // from the API function here. __ mov(scratch, - Operand((FCA::kArgsLength + 1 /* receiver */) * kPointerSize)); - __ ShiftLeftImm(ip, argc, Operand(kPointerSizeLog2)); + Operand((FCA::kArgsLength + 1 /* receiver */) * kSystemPointerSize)); + __ ShiftLeftImm(ip, argc, Operand(kSystemPointerSizeLog2)); __ add(scratch, scratch, ip); - __ StoreP(scratch, - MemOperand(sp, (kStackFrameExtraParamSlot + 4) * kPointerSize)); + __ StoreP(scratch, MemOperand(sp, (kStackFrameExtraParamSlot + 4) * + kSystemPointerSize)); // v8::InvocationCallback's argument. - __ addi(r3, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize)); + __ addi(r3, sp, + Operand((kStackFrameExtraParamSlot + 1) * kSystemPointerSize)); ExternalReference thunk_ref = ExternalReference::invoke_function_callback(); @@ -3172,11 +3211,11 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) { // TODO(jgruber): Document what these arguments are. static constexpr int kStackSlotsAboveFCA = 2; MemOperand return_value_operand( - fp, (kStackSlotsAboveFCA + FCA::kReturnValueOffset) * kPointerSize); + fp, (kStackSlotsAboveFCA + FCA::kReturnValueOffset) * kSystemPointerSize); static constexpr int kUseStackSpaceOperand = 0; MemOperand stack_space_operand( - sp, (kStackFrameExtraParamSlot + 4) * kPointerSize); + sp, (kStackFrameExtraParamSlot + 4) * kSystemPointerSize); AllowExternalCallThatCantCauseGC scope(masm); CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, @@ -3210,14 +3249,16 @@ void Builtins::Generate_CallApiGetter(MacroAssembler* masm) { __ push(receiver); // Push data from AccessorInfo. - __ LoadP(scratch, FieldMemOperand(callback, AccessorInfo::kDataOffset)); + __ LoadAnyTaggedField(scratch, + FieldMemOperand(callback, AccessorInfo::kDataOffset)); __ push(scratch); __ LoadRoot(scratch, RootIndex::kUndefinedValue); __ Push(scratch, scratch); __ Move(scratch, ExternalReference::isolate_address(masm->isolate())); __ Push(scratch, holder); __ Push(Smi::zero()); // should_throw_on_error -> false - __ LoadP(scratch, FieldMemOperand(callback, AccessorInfo::kNameOffset)); + __ LoadTaggedPointerField( + scratch, FieldMemOperand(callback, AccessorInfo::kNameOffset)); __ push(scratch); // v8::PropertyCallbackInfo::args_ array and name handle. @@ -3225,20 +3266,20 @@ void Builtins::Generate_CallApiGetter(MacroAssembler* masm) { // Load address of v8::PropertyAccessorInfo::args_ array and name handle. __ mr(r3, sp); // r3 = Handle - __ addi(r4, r3, Operand(1 * kPointerSize)); // r4 = v8::PCI::args_ + __ addi(r4, r3, Operand(1 * kSystemPointerSize)); // r4 = v8::PCI::args_ -// If ABI passes Handles (pointer-sized struct) in a register: -// -// Create 2 extra slots on stack: -// [0] space for DirectCEntryStub's LR save -// [1] AccessorInfo& -// -// Otherwise: -// -// Create 3 extra slots on stack: -// [0] space for DirectCEntryStub's LR save -// [1] copy of Handle (first arg) -// [2] AccessorInfo& + // If ABI passes Handles (pointer-sized struct) in a register: + // + // Create 2 extra slots on stack: + // [0] space for DirectCEntryStub's LR save + // [1] AccessorInfo& + // + // Otherwise: + // + // Create 3 extra slots on stack: + // [0] space for DirectCEntryStub's LR save + // [1] copy of Handle (first arg) + // [2] AccessorInfo& if (ABI_PASSES_HANDLES_IN_REGS) { accessorInfoSlot = kStackFrameExtraParamSlot + 1; apiStackSpace = 2; @@ -3253,26 +3294,28 @@ void Builtins::Generate_CallApiGetter(MacroAssembler* masm) { if (!ABI_PASSES_HANDLES_IN_REGS) { // pass 1st arg by reference - __ StoreP(r3, MemOperand(sp, arg0Slot * kPointerSize)); - __ addi(r3, sp, Operand(arg0Slot * kPointerSize)); + __ StoreP(r3, MemOperand(sp, arg0Slot * kSystemPointerSize)); + __ addi(r3, sp, Operand(arg0Slot * kSystemPointerSize)); } // Create v8::PropertyCallbackInfo object on the stack and initialize // it's args_ field. - __ StoreP(r4, MemOperand(sp, accessorInfoSlot * kPointerSize)); - __ addi(r4, sp, Operand(accessorInfoSlot * kPointerSize)); + __ StoreP(r4, MemOperand(sp, accessorInfoSlot * kSystemPointerSize)); + __ addi(r4, sp, Operand(accessorInfoSlot * kSystemPointerSize)); // r4 = v8::PropertyCallbackInfo& ExternalReference thunk_ref = ExternalReference::invoke_accessor_getter_callback(); - __ LoadP(scratch, FieldMemOperand(callback, AccessorInfo::kJsGetterOffset)); + __ LoadTaggedPointerField( + scratch, FieldMemOperand(callback, AccessorInfo::kJsGetterOffset)); __ LoadP(api_function_address, FieldMemOperand(scratch, Foreign::kForeignAddressOffset)); // +3 is to skip prolog, return address and name handle. MemOperand return_value_operand( - fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize); + fp, + (PropertyCallbackArguments::kReturnValueOffset + 3) * kSystemPointerSize); MemOperand* const kUseStackSpaceConstant = nullptr; CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, kStackUnwindSpace, kUseStackSpaceConstant, @@ -3285,16 +3328,17 @@ void Builtins::Generate_DirectCEntry(MacroAssembler* masm) { // Place the return address on the stack, making the call // GC safe. The RegExp backend also relies on this. __ mflr(r0); - __ StoreP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize)); + __ StoreP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kSystemPointerSize)); if (ABI_USES_FUNCTION_DESCRIPTORS) { // AIX/PPC64BE Linux use a function descriptor; - __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(temp2, kPointerSize)); + __ LoadP(ToRegister(ABI_TOC_REGISTER), + MemOperand(temp2, kSystemPointerSize)); __ LoadP(temp2, MemOperand(temp2, 0)); // Instruction address } __ Call(temp2); // Call the C++ function. - __ LoadP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize)); + __ LoadP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kSystemPointerSize)); __ mtlr(r0); __ blr(); } diff --git a/deps/v8/src/builtins/promise-abstract-operations.tq b/deps/v8/src/builtins/promise-abstract-operations.tq index 95ca356a0ceb85..9cf6da102b8eec 100644 --- a/deps/v8/src/builtins/promise-abstract-operations.tq +++ b/deps/v8/src/builtins/promise-abstract-operations.tq @@ -6,544 +6,534 @@ #include 'src/builtins/builtins-promise-gen.h' namespace runtime { - extern transitioning runtime - RejectPromise(implicit context: Context)(JSPromise, JSAny, Boolean): JSAny; +extern transitioning runtime +RejectPromise(implicit context: Context)(JSPromise, JSAny, Boolean): JSAny; - extern transitioning runtime - PromiseRevokeReject(implicit context: Context)(JSPromise): JSAny; +extern transitioning runtime +PromiseRevokeReject(implicit context: Context)(JSPromise): JSAny; - extern transitioning runtime - PromiseRejectAfterResolved(implicit context: Context)(JSPromise, JSAny): - JSAny; +extern transitioning runtime +PromiseRejectAfterResolved(implicit context: Context)(JSPromise, JSAny): JSAny; - extern transitioning runtime - PromiseResolveAfterResolved(implicit context: Context)(JSPromise, JSAny): - JSAny; +extern transitioning runtime +PromiseResolveAfterResolved(implicit context: Context)(JSPromise, JSAny): JSAny; - extern transitioning runtime - PromiseRejectEventFromStack(implicit context: Context)(JSPromise, JSAny): - JSAny; +extern transitioning runtime +PromiseRejectEventFromStack(implicit context: Context)(JSPromise, JSAny): JSAny; } // https://tc39.es/ecma262/#sec-promise-abstract-operations namespace promise { - extern macro AllocateFunctionWithMapAndContext( - Map, SharedFunctionInfo, Context): JSFunction; - - extern macro PromiseReactionMapConstant(): Map; - extern macro PromiseFulfillReactionJobTaskMapConstant(): Map; - extern macro PromiseRejectReactionJobTaskMapConstant(): Map; - extern transitioning builtin - ResolvePromise(Context, JSPromise, JSAny): JSAny; - - extern transitioning builtin - EnqueueMicrotask(Context, Microtask): Undefined; - - macro - ExtractHandlerContextInternal(implicit context: Context)(handler: Callable| - Undefined): - Context labels NotFound { - let iter: JSAny = handler; - while (true) { - typeswitch (iter) { - case (b: JSBoundFunction): { - iter = b.bound_target_function; - } - case (p: JSProxy): { - iter = p.target; - } - case (f: JSFunction): { - return f.context; - } - case (JSAny): { - break; - } +extern macro AllocateFunctionWithMapAndContext( + Map, SharedFunctionInfo, Context): JSFunction; + +extern macro PromiseReactionMapConstant(): Map; +extern macro PromiseFulfillReactionJobTaskMapConstant(): Map; +extern macro PromiseRejectReactionJobTaskMapConstant(): Map; +extern transitioning builtin +ResolvePromise(Context, JSPromise, JSAny): JSAny; + +extern transitioning builtin +EnqueueMicrotask(Context, Microtask): Undefined; + +macro +ExtractHandlerContextInternal(implicit context: Context)( + handler: Callable|Undefined): Context labels NotFound { + let iter: JSAny = handler; + while (true) { + typeswitch (iter) { + case (b: JSBoundFunction): { + iter = b.bound_target_function; + } + case (p: JSProxy): { + iter = p.target; + } + case (f: JSFunction): { + return f.context; + } + case (JSAny): { + break; } } - goto NotFound; } + goto NotFound; +} - macro - ExtractHandlerContext(implicit context: Context)(handler: Callable| - Undefined): Context { - try { - return ExtractHandlerContextInternal(handler) otherwise NotFound; - } - label NotFound deferred { - return context; - } +macro +ExtractHandlerContext(implicit context: Context)(handler: Callable| + Undefined): Context { + try { + return ExtractHandlerContextInternal(handler) otherwise NotFound; + } label NotFound deferred { + return context; } +} - macro - ExtractHandlerContext(implicit context: Context)( - primary: Callable|Undefined, secondary: Callable|Undefined): Context { - try { - return ExtractHandlerContextInternal(primary) otherwise NotFound; - } - label NotFound deferred { - return ExtractHandlerContextInternal(secondary) otherwise Default; - } - label Default deferred { - return context; - } +macro +ExtractHandlerContext(implicit context: Context)( + primary: Callable|Undefined, secondary: Callable|Undefined): Context { + try { + return ExtractHandlerContextInternal(primary) otherwise NotFound; + } label NotFound deferred { + return ExtractHandlerContextInternal(secondary) otherwise Default; + } label Default deferred { + return context; } +} - transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)( - promiseReaction: PromiseReaction, argument: JSAny, - reactionType: constexpr PromiseReactionType): void { - let primaryHandler: Callable|Undefined; - let secondaryHandler: Callable|Undefined; - if constexpr (reactionType == kPromiseReactionFulfill) { - primaryHandler = promiseReaction.fulfill_handler; - secondaryHandler = promiseReaction.reject_handler; - } else { - StaticAssert(reactionType == kPromiseReactionReject); - primaryHandler = promiseReaction.reject_handler; - secondaryHandler = promiseReaction.fulfill_handler; - } - - // According to HTML, we use the context of the appropriate handler as the - // context of the microtask. See step 3 of HTML's EnqueueJob: - // https://html.spec.whatwg.org/C/#enqueuejob(queuename,-job,-arguments) - const handlerContext: Context = - ExtractHandlerContext(primaryHandler, secondaryHandler); +transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)( + promiseReaction: PromiseReaction, argument: JSAny, + reactionType: constexpr PromiseReactionType): void { + let primaryHandler: Callable|Undefined; + let secondaryHandler: Callable|Undefined; + if constexpr (reactionType == kPromiseReactionFulfill) { + primaryHandler = promiseReaction.fulfill_handler; + secondaryHandler = promiseReaction.reject_handler; + } else { + StaticAssert(reactionType == kPromiseReactionReject); + primaryHandler = promiseReaction.reject_handler; + secondaryHandler = promiseReaction.fulfill_handler; + } - // Morph {current} from a PromiseReaction into a PromiseReactionJobTask - // and schedule that on the microtask queue. We try to minimize the number - // of stores here to avoid screwing up the store buffer. + // According to HTML, we use the context of the appropriate handler as the + // context of the microtask. See step 3 of HTML's EnqueueJob: + // https://html.spec.whatwg.org/C/#enqueuejob(queuename,-job,-arguments) + const handlerContext: Context = + ExtractHandlerContext(primaryHandler, secondaryHandler); + + // Morph {current} from a PromiseReaction into a PromiseReactionJobTask + // and schedule that on the microtask queue. We try to minimize the number + // of stores here to avoid screwing up the store buffer. + StaticAssert( + kPromiseReactionSize == + kPromiseReactionJobTaskSizeOfAllPromiseReactionJobTasks); + if constexpr (reactionType == kPromiseReactionFulfill) { + * UnsafeConstCast(& promiseReaction.map) = + PromiseFulfillReactionJobTaskMapConstant(); + const promiseReactionJobTask = + UnsafeCast(promiseReaction); + promiseReactionJobTask.argument = argument; + promiseReactionJobTask.context = handlerContext; + EnqueueMicrotask(handlerContext, promiseReactionJobTask); StaticAssert( - kPromiseReactionSize == - kPromiseReactionJobTaskSizeOfAllPromiseReactionJobTasks); - if constexpr (reactionType == kPromiseReactionFulfill) { - * UnsafeConstCast(& promiseReaction.map) = - PromiseFulfillReactionJobTaskMapConstant(); - const promiseReactionJobTask = - UnsafeCast(promiseReaction); - promiseReactionJobTask.argument = argument; - promiseReactionJobTask.context = handlerContext; - EnqueueMicrotask(handlerContext, promiseReactionJobTask); - StaticAssert( - kPromiseReactionFulfillHandlerOffset == - kPromiseReactionJobTaskHandlerOffset); - StaticAssert( - kPromiseReactionPromiseOrCapabilityOffset == - kPromiseReactionJobTaskPromiseOrCapabilityOffset); - } else { - StaticAssert(reactionType == kPromiseReactionReject); - * UnsafeConstCast(& promiseReaction.map) = - PromiseRejectReactionJobTaskMapConstant(); - const promiseReactionJobTask = - UnsafeCast(promiseReaction); - promiseReactionJobTask.argument = argument; - promiseReactionJobTask.context = handlerContext; - promiseReactionJobTask.handler = primaryHandler; - EnqueueMicrotask(handlerContext, promiseReactionJobTask); - StaticAssert( - kPromiseReactionPromiseOrCapabilityOffset == - kPromiseReactionJobTaskPromiseOrCapabilityOffset); - } + kPromiseReactionFulfillHandlerOffset == + kPromiseReactionJobTaskHandlerOffset); + StaticAssert( + kPromiseReactionPromiseOrCapabilityOffset == + kPromiseReactionJobTaskPromiseOrCapabilityOffset); + } else { + StaticAssert(reactionType == kPromiseReactionReject); + * UnsafeConstCast(& promiseReaction.map) = + PromiseRejectReactionJobTaskMapConstant(); + const promiseReactionJobTask = + UnsafeCast(promiseReaction); + promiseReactionJobTask.argument = argument; + promiseReactionJobTask.context = handlerContext; + promiseReactionJobTask.handler = primaryHandler; + EnqueueMicrotask(handlerContext, promiseReactionJobTask); + StaticAssert( + kPromiseReactionPromiseOrCapabilityOffset == + kPromiseReactionJobTaskPromiseOrCapabilityOffset); } +} - // https://tc39.es/ecma262/#sec-triggerpromisereactions - transitioning macro TriggerPromiseReactions(implicit context: Context)( - reactions: Zero|PromiseReaction, argument: JSAny, - reactionType: constexpr PromiseReactionType): void { - // We need to reverse the {reactions} here, since we record them on the - // JSPromise in the reverse order. - let current = reactions; - let reversed: Zero|PromiseReaction = kZero; - - // As an additional safety net against misuse of the V8 Extras API, we - // sanity check the {reactions} to make sure that they are actually - // PromiseReaction instances and not actual JavaScript values (which - // would indicate that we're rejecting or resolving an already settled - // promise), see https://crbug.com/931640 for details on this. - while (true) { - typeswitch (current) { - case (Zero): { - break; - } - case (currentReaction: PromiseReaction): { - current = currentReaction.next; - currentReaction.next = reversed; - reversed = currentReaction; - } +// https://tc39.es/ecma262/#sec-triggerpromisereactions +transitioning macro TriggerPromiseReactions(implicit context: Context)( + reactions: Zero|PromiseReaction, argument: JSAny, + reactionType: constexpr PromiseReactionType): void { + // We need to reverse the {reactions} here, since we record them on the + // JSPromise in the reverse order. + let current = reactions; + let reversed: Zero|PromiseReaction = kZero; + + // As an additional safety net against misuse of the V8 Extras API, we + // sanity check the {reactions} to make sure that they are actually + // PromiseReaction instances and not actual JavaScript values (which + // would indicate that we're rejecting or resolving an already settled + // promise), see https://crbug.com/931640 for details on this. + while (true) { + typeswitch (current) { + case (Zero): { + break; + } + case (currentReaction: PromiseReaction): { + current = currentReaction.next; + currentReaction.next = reversed; + reversed = currentReaction; } } - // Morph the {reactions} into PromiseReactionJobTasks and push them - // onto the microtask queue. - current = reversed; - while (true) { - typeswitch (current) { - case (Zero): { - break; - } - case (currentReaction: PromiseReaction): { - current = currentReaction.next; - MorphAndEnqueuePromiseReaction( - currentReaction, argument, reactionType); - } + } + // Morph the {reactions} into PromiseReactionJobTasks and push them + // onto the microtask queue. + current = reversed; + while (true) { + typeswitch (current) { + case (Zero): { + break; + } + case (currentReaction: PromiseReaction): { + current = currentReaction.next; + MorphAndEnqueuePromiseReaction(currentReaction, argument, reactionType); } } } +} - // https://tc39.es/ecma262/#sec-fulfillpromise - transitioning builtin - FulfillPromise(implicit context: Context)(promise: JSPromise, value: JSAny): - Undefined { - // Assert: The value of promise.[[PromiseState]] is "pending". - assert(promise.Status() == PromiseState::kPending); +// https://tc39.es/ecma262/#sec-fulfillpromise +transitioning builtin +FulfillPromise(implicit context: Context)( + promise: JSPromise, value: JSAny): Undefined { + // Assert: The value of promise.[[PromiseState]] is "pending". + assert(promise.Status() == PromiseState::kPending); - // 2. Let reactions be promise.[[PromiseFulfillReactions]]. - const reactions = - UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); + // 2. Let reactions be promise.[[PromiseFulfillReactions]]. + const reactions = + UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); - // 3. Set promise.[[PromiseResult]] to value. - // 4. Set promise.[[PromiseFulfillReactions]] to undefined. - // 5. Set promise.[[PromiseRejectReactions]] to undefined. - promise.reactions_or_result = value; + // 3. Set promise.[[PromiseResult]] to value. + // 4. Set promise.[[PromiseFulfillReactions]] to undefined. + // 5. Set promise.[[PromiseRejectReactions]] to undefined. + promise.reactions_or_result = value; - // 6. Set promise.[[PromiseState]] to "fulfilled". - promise.SetStatus(PromiseState::kFulfilled); + // 6. Set promise.[[PromiseState]] to "fulfilled". + promise.SetStatus(PromiseState::kFulfilled); + + // 7. Return TriggerPromiseReactions(reactions, value). + TriggerPromiseReactions(reactions, value, kPromiseReactionFulfill); + return Undefined; +} - // 7. Return TriggerPromiseReactions(reactions, value). - TriggerPromiseReactions(reactions, value, kPromiseReactionFulfill); - return Undefined; +extern macro PromiseBuiltinsAssembler:: + IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(): bool; + +// https://tc39.es/ecma262/#sec-rejectpromise +transitioning builtin +RejectPromise(implicit context: Context)( + promise: JSPromise, reason: JSAny, debugEvent: Boolean): JSAny { + // If promise hook is enabled or the debugger is active, let + // the runtime handle this operation, which greatly reduces + // the complexity here and also avoids a couple of back and + // forth between JavaScript and C++ land. + if (IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() || + !promise.HasHandler()) { + // 7. If promise.[[PromiseIsHandled]] is false, perform + // HostPromiseRejectionTracker(promise, "reject"). + // We don't try to handle rejecting {promise} without handler + // here, but we let the C++ code take care of this completely. + return runtime::RejectPromise(promise, reason, debugEvent); } - extern macro PromiseBuiltinsAssembler:: - IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(): bool; - - // https://tc39.es/ecma262/#sec-rejectpromise - transitioning builtin - RejectPromise(implicit context: Context)( - promise: JSPromise, reason: JSAny, debugEvent: Boolean): JSAny { - // If promise hook is enabled or the debugger is active, let - // the runtime handle this operation, which greatly reduces - // the complexity here and also avoids a couple of back and - // forth between JavaScript and C++ land. - if (IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() || - !promise.HasHandler()) { - // 7. If promise.[[PromiseIsHandled]] is false, perform - // HostPromiseRejectionTracker(promise, "reject"). - // We don't try to handle rejecting {promise} without handler - // here, but we let the C++ code take care of this completely. - return runtime::RejectPromise(promise, reason, debugEvent); - } + // 2. Let reactions be promise.[[PromiseRejectReactions]]. + const reactions = + UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); - // 2. Let reactions be promise.[[PromiseRejectReactions]]. - const reactions = - UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); + // 3. Set promise.[[PromiseResult]] to reason. + // 4. Set promise.[[PromiseFulfillReactions]] to undefined. + // 5. Set promise.[[PromiseRejectReactions]] to undefined. + promise.reactions_or_result = reason; - // 3. Set promise.[[PromiseResult]] to reason. - // 4. Set promise.[[PromiseFulfillReactions]] to undefined. - // 5. Set promise.[[PromiseRejectReactions]] to undefined. - promise.reactions_or_result = reason; + // 6. Set promise.[[PromiseState]] to "rejected". + promise.SetStatus(PromiseState::kRejected); - // 6. Set promise.[[PromiseState]] to "rejected". - promise.SetStatus(PromiseState::kRejected); + // 8. Return TriggerPromiseReactions(reactions, reason). + TriggerPromiseReactions(reactions, reason, kPromiseReactionReject); + return Undefined; +} - // 8. Return TriggerPromiseReactions(reactions, reason). - TriggerPromiseReactions(reactions, reason, kPromiseReactionReject); - return Undefined; - } +const kPromiseCapabilitySize: + constexpr int31 generates 'PromiseCapability::kSize'; +const kPromiseBuiltinsCapabilitiesContextLength: constexpr int31 + generates 'PromiseBuiltins::kCapabilitiesContextLength'; +const kPromiseBuiltinsCapabilitySlot: constexpr ContextSlot + generates 'PromiseBuiltins::kCapabilitySlot'; +const kPromiseBuiltinsPromiseSlot: constexpr ContextSlot + generates 'PromiseBuiltins::kPromiseSlot'; +const kPromiseBuiltinsAlreadyResolvedSlot: constexpr ContextSlot + generates 'PromiseBuiltins::kAlreadyResolvedSlot'; +const kPromiseBuiltinsDebugEventSlot: constexpr ContextSlot + generates 'PromiseBuiltins::kDebugEventSlot'; + +@export +macro CreatePromiseCapabilitiesExecutorContext( + nativeContext: NativeContext, capability: PromiseCapability): Context { + const executorContext = AllocateSyntheticFunctionContext( + nativeContext, kPromiseBuiltinsCapabilitiesContextLength); + + executorContext[kPromiseBuiltinsCapabilitySlot] = capability; + return executorContext; +} - const kPromiseCapabilitySize: - constexpr int31 generates 'PromiseCapability::kSize'; - const kPromiseBuiltinsCapabilitiesContextLength: constexpr int31 - generates 'PromiseBuiltins::kCapabilitiesContextLength'; - const kPromiseBuiltinsCapabilitySlot: constexpr ContextSlot - generates 'PromiseBuiltins::kCapabilitySlot'; - const kPromiseBuiltinsPromiseSlot: constexpr ContextSlot - generates 'PromiseBuiltins::kPromiseSlot'; - const kPromiseBuiltinsAlreadyResolvedSlot: constexpr ContextSlot - generates 'PromiseBuiltins::kAlreadyResolvedSlot'; - const kPromiseBuiltinsDebugEventSlot: constexpr ContextSlot - generates 'PromiseBuiltins::kDebugEventSlot'; - - @export - macro CreatePromiseCapabilitiesExecutorContext( - nativeContext: NativeContext, capability: PromiseCapability): Context { - const executorContext = AllocateSyntheticFunctionContext( - nativeContext, kPromiseBuiltinsCapabilitiesContextLength); - - executorContext[kPromiseBuiltinsCapabilitySlot] = capability; - return executorContext; - } +@export +macro CreatePromiseCapability( + promise: JSReceiver|Undefined, resolve: JSFunction|Undefined, + reject: JSFunction|Undefined): PromiseCapability { + return new PromiseCapability{ + map: kPromiseCapabilityMap, + promise: promise, + resolve: resolve, + reject: reject + }; +} - @export - macro CreatePromiseCapability( - promise: JSReceiver|Undefined, resolve: JSFunction|Undefined, - reject: JSFunction|Undefined): PromiseCapability { - return new PromiseCapability{ - map: kPromiseCapabilityMap, - promise: promise, - resolve: resolve, - reject: reject - }; - } +@export +struct PromiseResolvingFunctions { + resolve: JSFunction; + reject: JSFunction; +} - @export - struct PromiseResolvingFunctions { - resolve: JSFunction; - reject: JSFunction; - } +@export +macro CreatePromiseResolvingFunctions(implicit context: Context)( + promise: JSPromise, debugEvent: Object, nativeContext: NativeContext): + PromiseResolvingFunctions { + const promiseContext = CreatePromiseResolvingFunctionsContext( + promise, debugEvent, nativeContext); + const map = UnsafeCast( + nativeContext + [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); + const resolveInfo = PromiseCapabilityDefaultResolveSharedFunConstant(); + + const resolve: JSFunction = + AllocateFunctionWithMapAndContext(map, resolveInfo, promiseContext); + const rejectInfo = PromiseCapabilityDefaultRejectSharedFunConstant(); + const reject: JSFunction = + AllocateFunctionWithMapAndContext(map, rejectInfo, promiseContext); + return PromiseResolvingFunctions{resolve: resolve, reject: reject}; +} - @export - macro CreatePromiseResolvingFunctions(implicit context: Context)( - promise: JSPromise, debugEvent: Object, nativeContext: NativeContext): - PromiseResolvingFunctions { - const promiseContext = CreatePromiseResolvingFunctionsContext( - promise, debugEvent, nativeContext); - const map = UnsafeCast( +transitioning macro +InnerNewPromiseCapability(implicit context: Context)( + constructor: HeapObject, debugEvent: Object): PromiseCapability { + const nativeContext = LoadNativeContext(context); + if (TaggedEqual( + constructor, + nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX])) { + const promise = NewJSPromise(); + + const pair = + CreatePromiseResolvingFunctions(promise, debugEvent, nativeContext); + + return CreatePromiseCapability(promise, pair.resolve, pair.reject); + } else { + // We have to create the capability before the associated promise + // because the builtin PromiseConstructor uses the executor. + const capability = CreatePromiseCapability(Undefined, Undefined, Undefined); + const executorContext = + CreatePromiseCapabilitiesExecutorContext(nativeContext, capability); + + const executorInfo = PromiseGetCapabilitiesExecutorSharedFunConstant(); + const functionMap = UnsafeCast( nativeContext [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); - const resolveInfo = UnsafeCast( - nativeContext[NativeContextSlot:: - PROMISE_CAPABILITY_DEFAULT_RESOLVE_SHARED_FUN_INDEX]); - const resolve: JSFunction = - AllocateFunctionWithMapAndContext(map, resolveInfo, promiseContext); - const rejectInfo = UnsafeCast( - nativeContext[NativeContextSlot:: - PROMISE_CAPABILITY_DEFAULT_REJECT_SHARED_FUN_INDEX]); - const reject: JSFunction = - AllocateFunctionWithMapAndContext(map, rejectInfo, promiseContext); - return PromiseResolvingFunctions{resolve: resolve, reject: reject}; - } + const executor = AllocateFunctionWithMapAndContext( + functionMap, executorInfo, executorContext); - transitioning macro - InnerNewPromiseCapability(implicit context: Context)( - constructor: HeapObject, debugEvent: Object): PromiseCapability { - const nativeContext = LoadNativeContext(context); - if (TaggedEqual( - constructor, - nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX])) { - const promise = NewJSPromise(); - - const pair = - CreatePromiseResolvingFunctions(promise, debugEvent, nativeContext); - - return CreatePromiseCapability(promise, pair.resolve, pair.reject); - } else { - // We have to create the capability before the associated promise - // because the builtin PromiseConstructor uses the executor. - const capability = - CreatePromiseCapability(Undefined, Undefined, Undefined); - const executorContext = - CreatePromiseCapabilitiesExecutorContext(nativeContext, capability); - - const executorInfo = UnsafeCast( - nativeContext[NativeContextSlot:: - PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN]); - const functionMap = UnsafeCast( - nativeContext - [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); - const executor = AllocateFunctionWithMapAndContext( - functionMap, executorInfo, executorContext); - - const promiseConstructor = UnsafeCast(constructor); - const promise = Construct(promiseConstructor, executor); - capability.promise = promise; - - if (!TaggedIsCallable(capability.resolve) || - !TaggedIsCallable(capability.reject)) { - ThrowTypeError(MessageTemplate::kPromiseNonCallable); - } - return capability; + const promiseConstructor = UnsafeCast(constructor); + const promise = Construct(promiseConstructor, executor); + capability.promise = promise; + + if (!Is(capability.resolve) || !Is(capability.reject)) { + ThrowTypeError(MessageTemplate::kPromiseNonCallable); } + return capability; } +} - // https://tc39.es/ecma262/#sec-newpromisecapability - transitioning builtin - NewPromiseCapability(implicit context: Context)( - maybeConstructor: Object, debugEvent: Object): PromiseCapability { - typeswitch (maybeConstructor) { - case (Smi): { +// https://tc39.es/ecma262/#sec-newpromisecapability +transitioning builtin +NewPromiseCapability(implicit context: Context)( + maybeConstructor: Object, debugEvent: Object): PromiseCapability { + typeswitch (maybeConstructor) { + case (Smi): { + ThrowTypeError(MessageTemplate::kNotConstructor, maybeConstructor); + } + case (constructor: HeapObject): { + if (!IsConstructor(constructor)) { ThrowTypeError(MessageTemplate::kNotConstructor, maybeConstructor); } - case (constructor: HeapObject): { - if (!IsConstructor(constructor)) { - ThrowTypeError(MessageTemplate::kNotConstructor, maybeConstructor); - } - return InnerNewPromiseCapability(constructor, debugEvent); - } + return InnerNewPromiseCapability(constructor, debugEvent); } } +} - // https://tc39.es/ecma262/#sec-promise-reject-functions - transitioning javascript builtin - PromiseCapabilityDefaultReject( - js-implicit context: NativeContext, - receiver: JSAny)(reason: JSAny): JSAny { - // 2. Let promise be F.[[Promise]]. - const promise = UnsafeCast(context[kPromiseBuiltinsPromiseSlot]); - - // 3. Let alreadyResolved be F.[[AlreadyResolved]]. - const alreadyResolved = - UnsafeCast(context[kPromiseBuiltinsAlreadyResolvedSlot]); - - // 4. If alreadyResolved.[[Value]] is true, return undefined. - if (alreadyResolved == True) { - return runtime::PromiseRejectAfterResolved(promise, reason); - } +// https://tc39.es/ecma262/#sec-promise-reject-functions +transitioning javascript builtin +PromiseCapabilityDefaultReject( + js-implicit context: NativeContext, receiver: JSAny)(reason: JSAny): JSAny { + // 2. Let promise be F.[[Promise]]. + const promise = UnsafeCast(context[kPromiseBuiltinsPromiseSlot]); - // 5. Set alreadyResolved.[[Value]] to true. - context[kPromiseBuiltinsAlreadyResolvedSlot] = True; + // 3. Let alreadyResolved be F.[[AlreadyResolved]]. + const alreadyResolved = + UnsafeCast(context[kPromiseBuiltinsAlreadyResolvedSlot]); - // 6. Return RejectPromise(promise, reason). - const debugEvent = - UnsafeCast(context[kPromiseBuiltinsDebugEventSlot]); - return RejectPromise(promise, reason, debugEvent); + // 4. If alreadyResolved.[[Value]] is true, return undefined. + if (alreadyResolved == True) { + return runtime::PromiseRejectAfterResolved(promise, reason); } - // https://tc39.es/ecma262/#sec-promise-resolve-functions - transitioning javascript builtin - PromiseCapabilityDefaultResolve( - js-implicit context: NativeContext, - receiver: JSAny)(resolution: JSAny): JSAny { - // 2. Let promise be F.[[Promise]]. - const promise = UnsafeCast(context[kPromiseBuiltinsPromiseSlot]); - - // 3. Let alreadyResolved be F.[[AlreadyResolved]]. - const alreadyResolved = - UnsafeCast(context[kPromiseBuiltinsAlreadyResolvedSlot]); - - // 4. If alreadyResolved.[[Value]] is true, return undefined. - if (alreadyResolved == True) { - return runtime::PromiseResolveAfterResolved(promise, resolution); - } + // 5. Set alreadyResolved.[[Value]] to true. + context[kPromiseBuiltinsAlreadyResolvedSlot] = True; - // 5. Set alreadyResolved.[[Value]] to true. - context[kPromiseBuiltinsAlreadyResolvedSlot] = True; + // 6. Return RejectPromise(promise, reason). + const debugEvent = + UnsafeCast(context[kPromiseBuiltinsDebugEventSlot]); + return RejectPromise(promise, reason, debugEvent); +} - // The rest of the logic (and the catch prediction) is - // encapsulated in the dedicated ResolvePromise builtin. - return ResolvePromise(context, promise, resolution); +// https://tc39.es/ecma262/#sec-promise-resolve-functions +transitioning javascript builtin +PromiseCapabilityDefaultResolve( + js-implicit context: NativeContext, + receiver: JSAny)(resolution: JSAny): JSAny { + // 2. Let promise be F.[[Promise]]. + const promise = UnsafeCast(context[kPromiseBuiltinsPromiseSlot]); + + // 3. Let alreadyResolved be F.[[AlreadyResolved]]. + const alreadyResolved = + UnsafeCast(context[kPromiseBuiltinsAlreadyResolvedSlot]); + + // 4. If alreadyResolved.[[Value]] is true, return undefined. + if (alreadyResolved == True) { + return runtime::PromiseResolveAfterResolved(promise, resolution); } - @export - transitioning macro PerformPromiseThenImpl(implicit context: Context)( - promise: JSPromise, onFulfilled: Callable|Undefined, - onRejected: Callable|Undefined, - resultPromiseOrCapability: JSPromise|PromiseCapability|Undefined): void { - if (promise.Status() == PromiseState::kPending) { - // The {promise} is still in "Pending" state, so we just record a new - // PromiseReaction holding both the onFulfilled and onRejected callbacks. - // Once the {promise} is resolved we decide on the concrete handler to - // push onto the microtask queue. - const handlerContext = ExtractHandlerContext(onFulfilled, onRejected); - const promiseReactions = - UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); - const reaction = NewPromiseReaction( - handlerContext, promiseReactions, resultPromiseOrCapability, - onFulfilled, onRejected); - promise.reactions_or_result = reaction; - } else { - const reactionsOrResult = promise.reactions_or_result; - let microtask: PromiseReactionJobTask; - let handlerContext: Context; - if (promise.Status() == PromiseState::kFulfilled) { - handlerContext = ExtractHandlerContext(onFulfilled, onRejected); - microtask = NewPromiseFulfillReactionJobTask( - handlerContext, reactionsOrResult, onFulfilled, + // 5. Set alreadyResolved.[[Value]] to true. + context[kPromiseBuiltinsAlreadyResolvedSlot] = True; + + // The rest of the logic (and the catch prediction) is + // encapsulated in the dedicated ResolvePromise builtin. + return ResolvePromise(context, promise, resolution); +} + +@export +transitioning macro PerformPromiseThenImpl(implicit context: Context)( + promise: JSPromise, onFulfilled: Callable|Undefined, + onRejected: Callable|Undefined, + resultPromiseOrCapability: JSPromise|PromiseCapability|Undefined): void { + if (promise.Status() == PromiseState::kPending) { + // The {promise} is still in "Pending" state, so we just record a new + // PromiseReaction holding both the onFulfilled and onRejected callbacks. + // Once the {promise} is resolved we decide on the concrete handler to + // push onto the microtask queue. + const handlerContext = ExtractHandlerContext(onFulfilled, onRejected); + const promiseReactions = + UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); + const reaction = NewPromiseReaction( + handlerContext, promiseReactions, resultPromiseOrCapability, + onFulfilled, onRejected); + promise.reactions_or_result = reaction; + } else { + const reactionsOrResult = promise.reactions_or_result; + let microtask: PromiseReactionJobTask; + let handlerContext: Context; + if (promise.Status() == PromiseState::kFulfilled) { + handlerContext = ExtractHandlerContext(onFulfilled, onRejected); + microtask = NewPromiseFulfillReactionJobTask( + handlerContext, reactionsOrResult, onFulfilled, + resultPromiseOrCapability); + } else + deferred { + assert(promise.Status() == PromiseState::kRejected); + handlerContext = ExtractHandlerContext(onRejected, onFulfilled); + microtask = NewPromiseRejectReactionJobTask( + handlerContext, reactionsOrResult, onRejected, resultPromiseOrCapability); - } else - deferred { - assert(promise.Status() == PromiseState::kRejected); - handlerContext = ExtractHandlerContext(onRejected, onFulfilled); - microtask = NewPromiseRejectReactionJobTask( - handlerContext, reactionsOrResult, onRejected, - resultPromiseOrCapability); - if (!promise.HasHandler()) { - runtime::PromiseRevokeReject(promise); - } + if (!promise.HasHandler()) { + runtime::PromiseRevokeReject(promise); } - EnqueueMicrotask(handlerContext, microtask); - } - promise.SetHasHandler(); + } + EnqueueMicrotask(handlerContext, microtask); } + promise.SetHasHandler(); +} - // https://tc39.es/ecma262/#sec-performpromisethen - transitioning builtin - PerformPromiseThen(implicit context: Context)( - promise: JSPromise, onFulfilled: Callable|Undefined, - onRejected: Callable|Undefined, - resultPromise: JSPromise|Undefined): JSAny { - PerformPromiseThenImpl(promise, onFulfilled, onRejected, resultPromise); - return resultPromise; - } +// https://tc39.es/ecma262/#sec-performpromisethen +transitioning builtin +PerformPromiseThen(implicit context: Context)( + promise: JSPromise, onFulfilled: Callable|Undefined, + onRejected: Callable|Undefined, resultPromise: JSPromise|Undefined): JSAny { + PerformPromiseThenImpl(promise, onFulfilled, onRejected, resultPromise); + return resultPromise; +} - // https://tc39.es/ecma262/#sec-promise-reject-functions - transitioning javascript builtin - PromiseReject(js-implicit context: NativeContext, receiver: JSAny)( - reason: JSAny): JSAny { - // 1. Let C be the this value. - // 2. If Type(C) is not Object, throw a TypeError exception. - const receiver = Cast(receiver) otherwise - ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'PromiseReject'); - - const promiseFun = context[NativeContextSlot::PROMISE_FUNCTION_INDEX]; - if (promiseFun == receiver) { - const promise = NewJSPromise(PromiseState::kRejected, reason); - runtime::PromiseRejectEventFromStack(promise, reason); - return promise; - } else { - // 3. Let promiseCapability be ? NewPromiseCapability(C). - const capability = NewPromiseCapability(receiver, True); - - // 4. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »). - const reject = UnsafeCast(capability.reject); - Call(context, reject, Undefined, reason); - - // 5. Return promiseCapability.[[Promise]]. - return capability.promise; - } - } +// https://tc39.es/ecma262/#sec-promise-reject-functions +transitioning javascript builtin +PromiseReject( + js-implicit context: NativeContext, receiver: JSAny)(reason: JSAny): JSAny { + // 1. Let C be the this value. + // 2. If Type(C) is not Object, throw a TypeError exception. + const receiver = Cast(receiver) otherwise + ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'PromiseReject'); + + const promiseFun = context[NativeContextSlot::PROMISE_FUNCTION_INDEX]; + if (promiseFun == receiver) { + const promise = NewJSPromise(PromiseState::kRejected, reason); + runtime::PromiseRejectEventFromStack(promise, reason); + return promise; + } else { + // 3. Let promiseCapability be ? NewPromiseCapability(C). + const capability = NewPromiseCapability(receiver, True); - const kPromiseExecutorAlreadyInvoked: constexpr MessageTemplate - generates 'MessageTemplate::kPromiseExecutorAlreadyInvoked'; - - // https://tc39.es/ecma262/#sec-getcapabilitiesexecutor-functions - transitioning javascript builtin - PromiseGetCapabilitiesExecutor( - js-implicit context: NativeContext, - receiver: JSAny)(resolve: JSAny, reject: JSAny): JSAny { - const capability = - UnsafeCast(context[kPromiseBuiltinsCapabilitySlot]); - if (capability.resolve != Undefined || capability.reject != Undefined) - deferred { - ThrowTypeError(kPromiseExecutorAlreadyInvoked); - } + // 4. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »). + const reject = UnsafeCast(capability.reject); + Call(context, reject, Undefined, reason); - capability.resolve = resolve; - capability.reject = reject; - return Undefined; + // 5. Return promiseCapability.[[Promise]]. + return capability.promise; } +} - transitioning macro CallResolve(implicit context: Context)( - constructor: Constructor, resolve: JSAny, value: JSAny): JSAny { - // Undefined can never be a valid value for the resolve function, - // instead it is used as a special marker for the fast path. - if (resolve == Undefined) { - return PromiseResolve(constructor, value); - } else - deferred { - return Call(context, UnsafeCast(resolve), constructor, value); - } - } +const kPromiseExecutorAlreadyInvoked: constexpr MessageTemplate + generates 'MessageTemplate::kPromiseExecutorAlreadyInvoked'; + +// https://tc39.es/ecma262/#sec-getcapabilitiesexecutor-functions +transitioning javascript builtin +PromiseGetCapabilitiesExecutor( + js-implicit context: NativeContext, receiver: JSAny)( + resolve: JSAny, reject: JSAny): JSAny { + const capability = + UnsafeCast(context[kPromiseBuiltinsCapabilitySlot]); + if (capability.resolve != Undefined || capability.reject != Undefined) + deferred { + ThrowTypeError(kPromiseExecutorAlreadyInvoked); + } - transitioning javascript builtin - PromiseConstructorLazyDeoptContinuation( - js-implicit context: NativeContext, receiver: JSAny)( - promise: JSAny, reject: JSAny, exception: JSAny|TheHole, - _result: JSAny): JSAny { - typeswitch (exception) { - case (TheHole): { - } - case (e: JSAny): { - Call(context, reject, Undefined, e); - } + capability.resolve = resolve; + capability.reject = reject; + return Undefined; +} + +transitioning macro CallResolve(implicit context: Context)( + constructor: Constructor, resolve: JSAny, value: JSAny): JSAny { + // Undefined can never be a valid value for the resolve function, + // instead it is used as a special marker for the fast path. + if (resolve == Undefined) { + return PromiseResolve(constructor, value); + } else + deferred { + return Call(context, UnsafeCast(resolve), constructor, value); + } +} + +transitioning javascript builtin +PromiseConstructorLazyDeoptContinuation( + js-implicit context: NativeContext, receiver: JSAny)( + promise: JSAny, reject: JSAny, exception: JSAny|TheHole, + _result: JSAny): JSAny { + typeswitch (exception) { + case (TheHole): { + } + case (e: JSAny): { + Call(context, reject, Undefined, e); } - return promise; } + return promise; +} + +extern macro PromiseCapabilityDefaultRejectSharedFunConstant(): + SharedFunctionInfo; +extern macro PromiseCapabilityDefaultResolveSharedFunConstant(): + SharedFunctionInfo; +extern macro PromiseGetCapabilitiesExecutorSharedFunConstant(): + SharedFunctionInfo; } diff --git a/deps/v8/src/builtins/promise-all-element-closure.tq b/deps/v8/src/builtins/promise-all-element-closure.tq index c320b24f036c1c..0b870ea3b185bc 100644 --- a/deps/v8/src/builtins/promise-all-element-closure.tq +++ b/deps/v8/src/builtins/promise-all-element-closure.tq @@ -8,182 +8,180 @@ namespace promise { - struct PromiseAllWrapResultAsFulfilledFunctor { - macro Call(_nativeContext: NativeContext, value: JSAny): JSAny { - return value; - } +struct PromiseAllWrapResultAsFulfilledFunctor { + macro Call(_nativeContext: NativeContext, value: JSAny): JSAny { + return value; } +} - struct PromiseAllSettledWrapResultAsFulfilledFunctor { - transitioning - macro Call(implicit context: Context)( - nativeContext: NativeContext, value: JSAny): JSAny { - // TODO(gsathya): Optimize the creation using a cached map to - // prevent transitions here. - // 9. Let obj be ! ObjectCreate(%ObjectPrototype%). - const objectFunction = UnsafeCast( - nativeContext[NativeContextSlot::OBJECT_FUNCTION_INDEX]); - const objectFunctionMap = - UnsafeCast(objectFunction.prototype_or_initial_map); - const obj = AllocateJSObjectFromMap(objectFunctionMap); - - // 10. Perform ! CreateDataProperty(obj, "status", "fulfilled"). - FastCreateDataProperty( - obj, StringConstant('status'), StringConstant('fulfilled')); - - // 11. Perform ! CreateDataProperty(obj, "value", x). - FastCreateDataProperty(obj, StringConstant('value'), value); - return obj; - } +struct PromiseAllSettledWrapResultAsFulfilledFunctor { + transitioning + macro Call(implicit context: Context)( + nativeContext: NativeContext, value: JSAny): JSAny { + // TODO(gsathya): Optimize the creation using a cached map to + // prevent transitions here. + // 9. Let obj be ! ObjectCreate(%ObjectPrototype%). + const objectFunction = UnsafeCast( + nativeContext[NativeContextSlot::OBJECT_FUNCTION_INDEX]); + const objectFunctionMap = + UnsafeCast(objectFunction.prototype_or_initial_map); + const obj = AllocateJSObjectFromMap(objectFunctionMap); + + // 10. Perform ! CreateDataProperty(obj, "status", "fulfilled"). + FastCreateDataProperty( + obj, StringConstant('status'), StringConstant('fulfilled')); + + // 11. Perform ! CreateDataProperty(obj, "value", x). + FastCreateDataProperty(obj, StringConstant('value'), value); + return obj; } +} - struct PromiseAllSettledWrapResultAsRejectedFunctor { - transitioning - macro Call(implicit context: Context)( - nativeContext: NativeContext, value: JSAny): JSAny { - // TODO(gsathya): Optimize the creation using a cached map to - // prevent transitions here. - // 9. Let obj be ! ObjectCreate(%ObjectPrototype%). - const objectFunction = UnsafeCast( - nativeContext[NativeContextSlot::OBJECT_FUNCTION_INDEX]); - const objectFunctionMap = - UnsafeCast(objectFunction.prototype_or_initial_map); - const obj = AllocateJSObjectFromMap(objectFunctionMap); - - // 10. Perform ! CreateDataProperty(obj, "status", "rejected"). - FastCreateDataProperty( - obj, StringConstant('status'), StringConstant('rejected')); - - // 11. Perform ! CreateDataProperty(obj, "reason", x). - FastCreateDataProperty(obj, StringConstant('reason'), value); - return obj; - } +struct PromiseAllSettledWrapResultAsRejectedFunctor { + transitioning + macro Call(implicit context: Context)( + nativeContext: NativeContext, value: JSAny): JSAny { + // TODO(gsathya): Optimize the creation using a cached map to + // prevent transitions here. + // 9. Let obj be ! ObjectCreate(%ObjectPrototype%). + const objectFunction = UnsafeCast( + nativeContext[NativeContextSlot::OBJECT_FUNCTION_INDEX]); + const objectFunctionMap = + UnsafeCast(objectFunction.prototype_or_initial_map); + const obj = AllocateJSObjectFromMap(objectFunctionMap); + + // 10. Perform ! CreateDataProperty(obj, "status", "rejected"). + FastCreateDataProperty( + obj, StringConstant('status'), StringConstant('rejected')); + + // 11. Perform ! CreateDataProperty(obj, "reason", x). + FastCreateDataProperty(obj, StringConstant('reason'), value); + return obj; } +} - extern macro LoadJSReceiverIdentityHash(Object): intptr labels IfNoHash; +extern macro LoadJSReceiverIdentityHash(Object): intptr labels IfNoHash; - extern enum PromiseAllResolveElementContextSlots extends int31 - constexpr 'PromiseBuiltins::PromiseAllResolveElementContextSlots' { - kPromiseAllResolveElementRemainingSlot, - kPromiseAllResolveElementCapabilitySlot, - kPromiseAllResolveElementValuesArraySlot, - kPromiseAllResolveElementLength - } - extern operator '[]=' macro StoreContextElement( - Context, constexpr PromiseAllResolveElementContextSlots, Object): void; - extern operator '[]' macro LoadContextElement( - Context, constexpr PromiseAllResolveElementContextSlots): Object; - - const kPropertyArrayNoHashSentinel: constexpr int31 - generates 'PropertyArray::kNoHashSentinel'; - - const kPropertyArrayHashFieldMax: constexpr int31 - generates 'PropertyArray::HashField::kMax'; - - transitioning macro PromiseAllResolveElementClosure( - implicit context: - Context)(value: JSAny, function: JSFunction, wrapResultFunctor: F): - JSAny { - // We use the {function}s context as the marker to remember whether this - // resolve element closure was already called. It points to the resolve - // element context (which is a FunctionContext) until it was called the - // first time, in which case we make it point to the native context here - // to mark this resolve element closure as done. - if (IsNativeContext(context)) deferred { - return Undefined; - } +extern enum PromiseAllResolveElementContextSlots extends int31 +constexpr 'PromiseBuiltins::PromiseAllResolveElementContextSlots' { + kPromiseAllResolveElementRemainingSlot, + kPromiseAllResolveElementCapabilitySlot, + kPromiseAllResolveElementValuesArraySlot, + kPromiseAllResolveElementLength +} +extern operator '[]=' macro StoreContextElement( + Context, constexpr PromiseAllResolveElementContextSlots, Object): void; +extern operator '[]' macro LoadContextElement( + Context, constexpr PromiseAllResolveElementContextSlots): Object; + +const kPropertyArrayNoHashSentinel: constexpr int31 + generates 'PropertyArray::kNoHashSentinel'; + +const kPropertyArrayHashFieldMax: constexpr int31 + generates 'PropertyArray::HashField::kMax'; + +transitioning macro PromiseAllResolveElementClosure( + implicit context: Context)( + value: JSAny, function: JSFunction, wrapResultFunctor: F): JSAny { + // We use the {function}s context as the marker to remember whether this + // resolve element closure was already called. It points to the resolve + // element context (which is a FunctionContext) until it was called the + // first time, in which case we make it point to the native context here + // to mark this resolve element closure as done. + if (IsNativeContext(context)) deferred { + return Undefined; + } - assert( - context.length == - PromiseAllResolveElementContextSlots::kPromiseAllResolveElementLength); - const nativeContext = LoadNativeContext(context); - function.context = nativeContext; - - // Update the value depending on whether Promise.all or - // Promise.allSettled is called. - const updatedValue = wrapResultFunctor.Call(nativeContext, value); - - // Determine the index from the {function}. - assert(kPropertyArrayNoHashSentinel == 0); - const identityHash = - LoadJSReceiverIdentityHash(function) otherwise unreachable; - assert(identityHash > 0); - const index = identityHash - 1; - - // Check if we need to grow the [[ValuesArray]] to store {value} at {index}. - const valuesArray = UnsafeCast( - context[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementValuesArraySlot]); - const elements = UnsafeCast(valuesArray.elements); - const valuesLength = Convert(valuesArray.length); - if (index < valuesLength) { - // The {index} is in bounds of the {values_array}, - // just store the {value} and continue. + assert( + context.length == + PromiseAllResolveElementContextSlots::kPromiseAllResolveElementLength); + const nativeContext = LoadNativeContext(context); + function.context = nativeContext; + + // Update the value depending on whether Promise.all or + // Promise.allSettled is called. + const updatedValue = wrapResultFunctor.Call(nativeContext, value); + + // Determine the index from the {function}. + assert(kPropertyArrayNoHashSentinel == 0); + const identityHash = + LoadJSReceiverIdentityHash(function) otherwise unreachable; + assert(identityHash > 0); + const index = identityHash - 1; + + // Check if we need to grow the [[ValuesArray]] to store {value} at {index}. + const valuesArray = UnsafeCast( + context[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementValuesArraySlot]); + const elements = UnsafeCast(valuesArray.elements); + const valuesLength = Convert(valuesArray.length); + if (index < valuesLength) { + // The {index} is in bounds of the {values_array}, + // just store the {value} and continue. + elements.objects[index] = updatedValue; + } else { + // Check if we need to grow the backing store. + const newLength = index + 1; + const elementsLength = elements.length_intptr; + if (index < elementsLength) { + // The {index} is within bounds of the {elements} backing store, so + // just store the {value} and update the "length" of the {values_array}. + valuesArray.length = Convert(newLength); elements.objects[index] = updatedValue; - } else { - // Check if we need to grow the backing store. - const newLength = index + 1; - const elementsLength = elements.length_intptr; - if (index < elementsLength) { - // The {index} is within bounds of the {elements} backing store, so - // just store the {value} and update the "length" of the {values_array}. + } else + deferred { + // We need to grow the backing store to fit the {index} as well. + const newElementsLength = IntPtrMin( + CalculateNewElementsCapacity(newLength), + kPropertyArrayHashFieldMax + 1); + assert(index < newElementsLength); + assert(elementsLength < newElementsLength); + const newElements = + ExtractFixedArray(elements, 0, elementsLength, newElementsLength); + newElements.objects[index] = updatedValue; + + // Update backing store and "length" on {values_array}. + valuesArray.elements = newElements; valuesArray.length = Convert(newLength); - elements.objects[index] = updatedValue; - } else - deferred { - // We need to grow the backing store to fit the {index} as well. - const newElementsLength = IntPtrMin( - CalculateNewElementsCapacity(newLength), - kPropertyArrayHashFieldMax + 1); - assert(index < newElementsLength); - assert(elementsLength < newElementsLength); - const newElements = - ExtractFixedArray(elements, 0, elementsLength, newElementsLength); - newElements.objects[index] = updatedValue; - - // Update backing store and "length" on {values_array}. - valuesArray.elements = newElements; - valuesArray.length = Convert(newLength); - } - } - let remainingElementsCount = - UnsafeCast(context[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementRemainingSlot]); - remainingElementsCount = remainingElementsCount - 1; - context[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementRemainingSlot] = - remainingElementsCount; - if (remainingElementsCount == 0) { - const capability = UnsafeCast( - context[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementCapabilitySlot]); - const resolve = UnsafeCast(capability.resolve); - Call(context, resolve, Undefined, valuesArray); - } - return Undefined; + } } - - transitioning javascript builtin - PromiseAllResolveElementClosure( - js-implicit context: Context, receiver: JSAny, - target: JSFunction)(value: JSAny): JSAny { - return PromiseAllResolveElementClosure( - value, target, PromiseAllWrapResultAsFulfilledFunctor{}); + let remainingElementsCount = + UnsafeCast(context[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementRemainingSlot]); + remainingElementsCount = remainingElementsCount - 1; + context[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementRemainingSlot] = remainingElementsCount; + if (remainingElementsCount == 0) { + const capability = UnsafeCast( + context[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementCapabilitySlot]); + const resolve = UnsafeCast(capability.resolve); + Call(context, resolve, Undefined, valuesArray); } + return Undefined; +} - transitioning javascript builtin - PromiseAllSettledResolveElementClosure( - js-implicit context: Context, receiver: JSAny, - target: JSFunction)(value: JSAny): JSAny { - return PromiseAllResolveElementClosure( - value, target, PromiseAllSettledWrapResultAsFulfilledFunctor{}); - } +transitioning javascript builtin +PromiseAllResolveElementClosure( + js-implicit context: Context, receiver: JSAny, + target: JSFunction)(value: JSAny): JSAny { + return PromiseAllResolveElementClosure( + value, target, PromiseAllWrapResultAsFulfilledFunctor{}); +} - transitioning javascript builtin - PromiseAllSettledRejectElementClosure( - js-implicit context: Context, receiver: JSAny, - target: JSFunction)(value: JSAny): JSAny { - return PromiseAllResolveElementClosure( - value, target, PromiseAllSettledWrapResultAsRejectedFunctor{}); - } +transitioning javascript builtin +PromiseAllSettledResolveElementClosure( + js-implicit context: Context, receiver: JSAny, + target: JSFunction)(value: JSAny): JSAny { + return PromiseAllResolveElementClosure( + value, target, PromiseAllSettledWrapResultAsFulfilledFunctor{}); +} + +transitioning javascript builtin +PromiseAllSettledRejectElementClosure( + js-implicit context: Context, receiver: JSAny, + target: JSFunction)(value: JSAny): JSAny { + return PromiseAllResolveElementClosure( + value, target, PromiseAllSettledWrapResultAsRejectedFunctor{}); +} } diff --git a/deps/v8/src/builtins/promise-all.tq b/deps/v8/src/builtins/promise-all.tq index 19a16d8da858f1..b7fad88f6fc891 100644 --- a/deps/v8/src/builtins/promise-all.tq +++ b/deps/v8/src/builtins/promise-all.tq @@ -6,165 +6,160 @@ #include 'src/builtins/builtins-promise-gen.h' namespace promise { - const kPromiseBuiltinsPromiseContextLength: constexpr int31 - generates 'PromiseBuiltins::kPromiseContextLength'; - - // Creates the context used by all Promise.all resolve element closures, - // together with the values array. Since all closures for a single Promise.all - // call use the same context, we need to store the indices for the individual - // closures somewhere else (we put them into the identity hash field of the - // closures), and we also need to have a separate marker for when the closure - // was called already (we slap the native context onto the closure in that - // case to mark it's done). - macro CreatePromiseAllResolveElementContext(implicit context: Context)( - capability: PromiseCapability, nativeContext: NativeContext): Context { - // TODO(bmeurer): Manually fold this into a single allocation. - const arrayMap = UnsafeCast( - nativeContext[NativeContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX]); - const valuesArray = AllocateJSArray( - ElementsKind::PACKED_ELEMENTS, arrayMap, IntPtrConstant(0), - SmiConstant(0)); - const resolveContext = AllocateSyntheticFunctionContext( - nativeContext, - PromiseAllResolveElementContextSlots::kPromiseAllResolveElementLength); - resolveContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementRemainingSlot] = SmiConstant(1); - resolveContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementCapabilitySlot] = capability; - resolveContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementValuesArraySlot] = valuesArray; - return resolveContext; - } +const kPromiseBuiltinsPromiseContextLength: constexpr int31 + generates 'PromiseBuiltins::kPromiseContextLength'; + +// Creates the context used by all Promise.all resolve element closures, +// together with the values array. Since all closures for a single Promise.all +// call use the same context, we need to store the indices for the individual +// closures somewhere else (we put them into the identity hash field of the +// closures), and we also need to have a separate marker for when the closure +// was called already (we slap the native context onto the closure in that +// case to mark it's done). +macro CreatePromiseAllResolveElementContext(implicit context: Context)( + capability: PromiseCapability, nativeContext: NativeContext): Context { + // TODO(bmeurer): Manually fold this into a single allocation. + const arrayMap = UnsafeCast( + nativeContext[NativeContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX]); + const valuesArray = AllocateJSArray( + ElementsKind::PACKED_ELEMENTS, arrayMap, IntPtrConstant(0), + SmiConstant(0)); + const resolveContext = AllocateSyntheticFunctionContext( + nativeContext, + PromiseAllResolveElementContextSlots::kPromiseAllResolveElementLength); + resolveContext[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementRemainingSlot] = SmiConstant(1); + resolveContext[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementCapabilitySlot] = capability; + resolveContext[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementValuesArraySlot] = valuesArray; + return resolveContext; +} - macro CreatePromiseAllResolveElementFunction(implicit context: Context)( - resolveElementContext: Context, index: Smi, nativeContext: NativeContext, - slotIndex: constexpr NativeContextSlot): JSFunction { - assert(index > 0); - assert(index < kPropertyArrayHashFieldMax); - - const map = UnsafeCast( - nativeContext - [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); - const resolveInfo = - UnsafeCast(nativeContext[slotIndex]); - const resolve = AllocateFunctionWithMapAndContext( - map, resolveInfo, resolveElementContext); - - assert(kPropertyArrayNoHashSentinel == 0); - resolve.properties_or_hash = index; - return resolve; - } +macro CreatePromiseAllResolveElementFunction(implicit context: Context)( + resolveElementContext: Context, index: Smi, nativeContext: NativeContext, + resolveFunction: SharedFunctionInfo): JSFunction { + assert(index > 0); + assert(index < kPropertyArrayHashFieldMax); + + const map = UnsafeCast( + nativeContext + [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); + const resolve = AllocateFunctionWithMapAndContext( + map, resolveFunction, resolveElementContext); + + assert(kPropertyArrayNoHashSentinel == 0); + resolve.properties_or_hash = index; + return resolve; +} - @export - macro CreatePromiseResolvingFunctionsContext(implicit context: Context)( - promise: JSPromise, debugEvent: Object, nativeContext: NativeContext): - Context { - const resolveContext = AllocateSyntheticFunctionContext( - nativeContext, kPromiseBuiltinsPromiseContextLength); - resolveContext[kPromiseBuiltinsPromiseSlot] = promise; - resolveContext[kPromiseBuiltinsAlreadyResolvedSlot] = False; - resolveContext[kPromiseBuiltinsDebugEventSlot] = debugEvent; - return resolveContext; - } +@export +macro CreatePromiseResolvingFunctionsContext(implicit context: Context)( + promise: JSPromise, debugEvent: Object, nativeContext: NativeContext): + Context { + const resolveContext = AllocateSyntheticFunctionContext( + nativeContext, kPromiseBuiltinsPromiseContextLength); + resolveContext[kPromiseBuiltinsPromiseSlot] = promise; + resolveContext[kPromiseBuiltinsAlreadyResolvedSlot] = False; + resolveContext[kPromiseBuiltinsDebugEventSlot] = debugEvent; + return resolveContext; +} - macro IsPromiseThenLookupChainIntact(implicit context: Context)( - nativeContext: NativeContext, receiverMap: Map): bool { - if (IsForceSlowPath()) return false; - if (!IsJSPromiseMap(receiverMap)) return false; - if (receiverMap.prototype != - nativeContext[NativeContextSlot::PROMISE_PROTOTYPE_INDEX]) - return false; - return !IsPromiseThenProtectorCellInvalid(); - } +macro IsPromiseThenLookupChainIntact(implicit context: Context)( + nativeContext: NativeContext, receiverMap: Map): bool { + if (IsForceSlowPath()) return false; + if (!IsJSPromiseMap(receiverMap)) return false; + if (receiverMap.prototype != + nativeContext[NativeContextSlot::PROMISE_PROTOTYPE_INDEX]) + return false; + return !IsPromiseThenProtectorCellInvalid(); +} - struct PromiseAllResolveElementFunctor { - macro Call(implicit context: Context)( - resolveElementContext: Context, nativeContext: NativeContext, - index: Smi, _capability: PromiseCapability): Callable { - return CreatePromiseAllResolveElementFunction( - resolveElementContext, index, nativeContext, - NativeContextSlot::PROMISE_ALL_RESOLVE_ELEMENT_SHARED_FUN); - } +struct PromiseAllResolveElementFunctor { + macro Call(implicit context: Context)( + resolveElementContext: Context, nativeContext: NativeContext, index: Smi, + _capability: PromiseCapability): Callable { + return CreatePromiseAllResolveElementFunction( + resolveElementContext, index, nativeContext, + PromiseAllResolveElementSharedFunConstant()); } +} - struct PromiseAllRejectElementFunctor { - macro Call(implicit context: Context)( - _resolveElementContext: Context, _nativeContext: NativeContext, - _index: Smi, capability: PromiseCapability): Callable { - return UnsafeCast(capability.reject); - } +struct PromiseAllRejectElementFunctor { + macro Call(implicit context: Context)( + _resolveElementContext: Context, _nativeContext: NativeContext, + _index: Smi, capability: PromiseCapability): Callable { + return UnsafeCast(capability.reject); } +} - struct PromiseAllSettledResolveElementFunctor { - macro Call(implicit context: Context)( - resolveElementContext: Context, nativeContext: NativeContext, - index: Smi, _capability: PromiseCapability): Callable { - return CreatePromiseAllResolveElementFunction( - resolveElementContext, index, nativeContext, - NativeContextSlot::PROMISE_ALL_SETTLED_RESOLVE_ELEMENT_SHARED_FUN); - } +struct PromiseAllSettledResolveElementFunctor { + macro Call(implicit context: Context)( + resolveElementContext: Context, nativeContext: NativeContext, index: Smi, + _capability: PromiseCapability): Callable { + return CreatePromiseAllResolveElementFunction( + resolveElementContext, index, nativeContext, + PromiseAllSettledResolveElementSharedFunConstant()); } +} - struct PromiseAllSettledRejectElementFunctor { - macro Call(implicit context: Context)( - resolveElementContext: Context, nativeContext: NativeContext, - index: Smi, _capability: PromiseCapability): Callable { - return CreatePromiseAllResolveElementFunction( - resolveElementContext, index, nativeContext, - NativeContextSlot::PROMISE_ALL_SETTLED_REJECT_ELEMENT_SHARED_FUN); - } +struct PromiseAllSettledRejectElementFunctor { + macro Call(implicit context: Context)( + resolveElementContext: Context, nativeContext: NativeContext, index: Smi, + _capability: PromiseCapability): Callable { + return CreatePromiseAllResolveElementFunction( + resolveElementContext, index, nativeContext, + PromiseAllSettledRejectElementSharedFunConstant()); } +} - transitioning macro PerformPromiseAll(implicit context: - Context)( - constructor: JSReceiver, capability: PromiseCapability, - iter: iterator::IteratorRecord, createResolveElementFunctor: F1, - createRejectElementFunctor: F2): JSAny labels Reject(Object) { - const nativeContext = LoadNativeContext(context); - const promise = capability.promise; - const resolve = capability.resolve; - const reject = capability.reject; - - // For catch prediction, don't treat the .then calls as handling it; - // instead, recurse outwards. - if (IsDebugActive()) deferred { - SetPropertyStrict( - context, reject, kPromiseForwardingHandlerSymbol, True); - } +transitioning macro PerformPromiseAll( + implicit context: Context)( + constructor: JSReceiver, capability: PromiseCapability, + iter: iterator::IteratorRecord, createResolveElementFunctor: F1, + createRejectElementFunctor: F2): JSAny labels +Reject(Object) { + const nativeContext = LoadNativeContext(context); + const promise = capability.promise; + const resolve = capability.resolve; + const reject = capability.reject; + + // For catch prediction, don't treat the .then calls as handling it; + // instead, recurse outwards. + if (IsDebugActive()) deferred { + SetPropertyStrict(context, reject, kPromiseForwardingHandlerSymbol, True); + } - const resolveElementContext = - CreatePromiseAllResolveElementContext(capability, nativeContext); + const resolveElementContext = + CreatePromiseAllResolveElementContext(capability, nativeContext); - let index: Smi = 1; + let index: Smi = 1; - // We can skip the "resolve" lookup on {constructor} if it's the - // Promise constructor and the Promise.resolve protector is intact, - // as that guards the lookup path for the "resolve" property on the - // Promise constructor. - let promiseResolveFunction: JSAny = Undefined; + // We can skip the "resolve" lookup on {constructor} if it's the + // Promise constructor and the Promise.resolve protector is intact, + // as that guards the lookup path for the "resolve" property on the + // Promise constructor. + let promiseResolveFunction: JSAny = Undefined; + try { try { - try { - if (!IsPromiseResolveLookupChainIntact(nativeContext, constructor)) { - // 5. Let _promiseResolve_ be ? Get(_constructor_, `"resolve"`). - let promiseResolve: JSAny; - try { - promiseResolve = GetProperty(constructor, kResolveString); - } catch (e) deferred { - iterator::IteratorCloseOnException(iter, e) otherwise Reject; - } - - // 6. If IsCallable(_promiseResolve_) is *false*, throw a *TypeError* - // exception. - promiseResolveFunction = Cast(promiseResolve) - otherwise ThrowTypeError( - MessageTemplate::kCalledNonCallable, 'resolve'); - } + if (!IsPromiseResolveLookupChainIntact(nativeContext, constructor)) { + let promiseResolve: JSAny; + + // 5. Let _promiseResolve_ be ? Get(_constructor_, `"resolve"`). + promiseResolve = GetProperty(constructor, kResolveString); - const fastIteratorResultMap = UnsafeCast( - nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]); - while (true) { - let nextValue: JSAny; + // 6. If IsCallable(_promiseResolve_) is *false*, throw a *TypeError* + // exception. + promiseResolveFunction = + Cast(promiseResolve) otherwise ThrowTypeError( + MessageTemplate::kCalledNonCallable, 'resolve'); + } + const fastIteratorResultMap = UnsafeCast( + nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]); + while (true) { + let nextValue: JSAny; + try { // Let next be IteratorStep(iteratorRecord.[[Iterator]]). // If next is an abrupt completion, set iteratorRecord.[[Done]] to // true. ReturnIfAbrupt(next). @@ -176,209 +171,207 @@ namespace promise { // to true. // ReturnIfAbrupt(nextValue). nextValue = iterator::IteratorValue(next, fastIteratorResultMap); + } catch (e) { + goto Reject(e); + } - // Check if we reached the limit. - if (index == kPropertyArrayHashFieldMax) { - // If there are too many elements (currently more than 2**21-1), - // raise a RangeError here (which is caught directly and turned into - // a rejection) of the resulting promise. We could gracefully handle - // this case as well and support more than this number of elements - // by going to a separate function and pass the larger indices via a - // separate context, but it doesn't seem likely that we need this, - // and it's unclear how the rest of the system deals with 2**21 live - // Promises anyways. - try { - ThrowRangeError(MessageTemplate::kTooManyElementsInPromiseAll); - } catch (e) deferred { - iterator::IteratorCloseOnException(iter, e) otherwise Reject; - } - } - - // Set remainingElementsCount.[[Value]] to - // remainingElementsCount.[[Value]] + 1. - const remainingElementsCount = - UnsafeCast(resolveElementContext - [PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementRemainingSlot]); - resolveElementContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementRemainingSlot] = - remainingElementsCount + 1; - - // Let resolveElement be CreateBuiltinFunction(steps, - // « [[AlreadyCalled]], - // [[Index]], - // [[Values]], - // [[Capability]], - // [[RemainingElements]] - // »). - // Set resolveElement.[[AlreadyCalled]] to a Record { [[Value]]: false - // }. Set resolveElement.[[Index]] to index. Set - // resolveElement.[[Values]] to values. Set - // resolveElement.[[Capability]] to resultCapability. Set - // resolveElement.[[RemainingElements]] to remainingElementsCount. - const resolveElementFun = createResolveElementFunctor.Call( - resolveElementContext, nativeContext, index, capability); - const rejectElementFun = createRejectElementFunctor.Call( - resolveElementContext, nativeContext, index, capability); - - // We can skip the "resolve" lookup on the {constructor} as well as - // the "then" lookup on the result of the "resolve" call, and - // immediately chain continuation onto the {next_value} if: - // - // (a) The {constructor} is the intrinsic %Promise% function, and - // looking up "resolve" on {constructor} yields the initial - // Promise.resolve() builtin, and - // (b) the promise @@species protector cell is valid, meaning that - // no one messed with the Symbol.species property on any - // intrinsic promise or on the Promise.prototype, and - // (c) the {next_value} is a JSPromise whose [[Prototype]] field - // contains the intrinsic %PromisePrototype%, and - // (d) we're not running with async_hooks or DevTools enabled. - // - // In that case we also don't need to allocate a chained promise for - // the PromiseReaction (aka we can pass undefined to - // PerformPromiseThen), since this is only necessary for DevTools and - // PromiseHooks. - if (promiseResolveFunction != Undefined || - IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() || - IsPromiseSpeciesProtectorCellInvalid() || Is(nextValue) || - !IsPromiseThenLookupChainIntact( - nativeContext, UnsafeCast(nextValue).map)) { - try { - // Let nextPromise be ? Call(constructor, _promiseResolve_, « - // nextValue »). - const nextPromise = CallResolve( - UnsafeCast(constructor), promiseResolveFunction, - nextValue); - - // Perform ? Invoke(nextPromise, "then", « resolveElement, - // resultCapability.[[Reject]] »). - const then = GetProperty(nextPromise, kThenString); - const thenResult = Call( - nativeContext, then, nextPromise, resolveElementFun, - rejectElementFun); - - // For catch prediction, mark that rejections here are - // semantically handled by the combined Promise. - if (IsDebugActive() && Is(thenResult)) deferred { - SetPropertyStrict( - context, thenResult, kPromiseHandledBySymbol, promise); - } - } catch (e) deferred { - iterator::IteratorCloseOnException(iter, e) otherwise Reject; + // Check if we reached the limit. + if (index == kPropertyArrayHashFieldMax) { + // If there are too many elements (currently more than 2**21-1), + // raise a RangeError here (which is caught below and turned into + // a rejection of the resulting promise). We could gracefully handle + // this case as well and support more than this number of elements + // by going to a separate function and pass the larger indices via a + // separate context, but it doesn't seem likely that we need this, + // and it's unclear how the rest of the system deals with 2**21 live + // Promises anyway. + ThrowRangeError( + MessageTemplate::kTooManyElementsInPromiseCombinator, 'all'); + } + + // Set remainingElementsCount.[[Value]] to + // remainingElementsCount.[[Value]] + 1. + const remainingElementsCount = UnsafeCast( + resolveElementContext[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementRemainingSlot]); + resolveElementContext[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementRemainingSlot] = + remainingElementsCount + 1; + + // Let resolveElement be CreateBuiltinFunction(steps, + // « [[AlreadyCalled]], + // [[Index]], + // [[Values]], + // [[Capability]], + // [[RemainingElements]] + // »). + // Set resolveElement.[[AlreadyCalled]] to a Record { [[Value]]: false + // }. Set resolveElement.[[Index]] to index. Set + // resolveElement.[[Values]] to values. Set + // resolveElement.[[Capability]] to resultCapability. Set + // resolveElement.[[RemainingElements]] to remainingElementsCount. + const resolveElementFun = createResolveElementFunctor.Call( + resolveElementContext, nativeContext, index, capability); + const rejectElementFun = createRejectElementFunctor.Call( + resolveElementContext, nativeContext, index, capability); + + // We can skip the "resolve" lookup on the {constructor} as well as + // the "then" lookup on the result of the "resolve" call, and + // immediately chain continuation onto the {next_value} if: + // + // (a) The {constructor} is the intrinsic %Promise% function, and + // looking up "resolve" on {constructor} yields the initial + // Promise.resolve() builtin, and + // (b) the promise @@species protector cell is valid, meaning that + // no one messed with the Symbol.species property on any + // intrinsic promise or on the Promise.prototype, and + // (c) the {next_value} is a JSPromise whose [[Prototype]] field + // contains the intrinsic %PromisePrototype%, and + // (d) we're not running with async_hooks or DevTools enabled. + // + // In that case we also don't need to allocate a chained promise for + // the PromiseReaction (aka we can pass undefined to + // PerformPromiseThen), since this is only necessary for DevTools and + // PromiseHooks. + if (promiseResolveFunction != Undefined || + IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() || + IsPromiseSpeciesProtectorCellInvalid() || Is(nextValue) || + !IsPromiseThenLookupChainIntact( + nativeContext, UnsafeCast(nextValue).map)) { + // Let nextPromise be ? Call(constructor, _promiseResolve_, « + // nextValue »). + const nextPromise = CallResolve( + UnsafeCast(constructor), promiseResolveFunction, + nextValue); + + // Perform ? Invoke(nextPromise, "then", « resolveElement, + // resultCapability.[[Reject]] »). + const then = GetProperty(nextPromise, kThenString); + const thenResult = Call( + nativeContext, then, nextPromise, resolveElementFun, + rejectElementFun); + + // For catch prediction, mark that rejections here are + // semantically handled by the combined Promise. + if (IsDebugActive() && Is(thenResult)) deferred { + SetPropertyStrict( + context, thenResult, kPromiseHandledBySymbol, promise); } - } else { - PerformPromiseThenImpl( - UnsafeCast(nextValue), resolveElementFun, - rejectElementFun, Undefined); - } - - // Set index to index + 1. - index += 1; + } else { + PerformPromiseThenImpl( + UnsafeCast(nextValue), resolveElementFun, + rejectElementFun, Undefined); } + + // Set index to index + 1. + index += 1; } + } catch (e) deferred { + iterator::IteratorCloseOnException(iter); + goto Reject(e); } - label Done {} - - // Set iteratorRecord.[[Done]] to true. - // Set remainingElementsCount.[[Value]] to - // remainingElementsCount.[[Value]] - 1. - let remainingElementsCount = UnsafeCast( + } label Done {} + + // Set iteratorRecord.[[Done]] to true. + // Set remainingElementsCount.[[Value]] to + // remainingElementsCount.[[Value]] - 1. + let remainingElementsCount = UnsafeCast( + resolveElementContext[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementRemainingSlot]); + remainingElementsCount -= 1; + resolveElementContext[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementRemainingSlot] = + remainingElementsCount; + if (remainingElementsCount > 0) { + // Pre-allocate the backing store for the {values_array} to the desired + // capacity here. We may already have elements here in case of some + // fancy Thenable that calls the resolve callback immediately, so we need + // to handle that correctly here. + const valuesArray = UnsafeCast( resolveElementContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementRemainingSlot]); - remainingElementsCount -= 1; - resolveElementContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementRemainingSlot] = - remainingElementsCount; - if (remainingElementsCount > 0) { - // Pre-allocate the backing store for the {values_array} to the desired - // capacity here. We may already have elements here in case of some - // fancy Thenable that calls the resolve callback immediately, so we need - // to handle that correctly here. - const valuesArray = UnsafeCast( + kPromiseAllResolveElementValuesArraySlot]); + const oldElements = UnsafeCast(valuesArray.elements); + const oldCapacity = oldElements.length_intptr; + const newCapacity = SmiUntag(index); + if (oldCapacity < newCapacity) { + valuesArray.elements = + ExtractFixedArray(oldElements, 0, oldCapacity, newCapacity); + } + } else + deferred { + // If remainingElementsCount.[[Value]] is 0, then + // Let valuesArray be CreateArrayFromList(values). + // Perform ? Call(resultCapability.[[Resolve]], undefined, + // « valuesArray »). + assert(remainingElementsCount == 0); + const valuesArray = UnsafeCast( resolveElementContext[PromiseAllResolveElementContextSlots:: kPromiseAllResolveElementValuesArraySlot]); - const oldElements = UnsafeCast(valuesArray.elements); - const oldCapacity = oldElements.length_intptr; - const newCapacity = SmiUntag(index); - if (oldCapacity < newCapacity) { - valuesArray.elements = - ExtractFixedArray(oldElements, 0, oldCapacity, newCapacity); - } - } else - deferred { - // If remainingElementsCount.[[Value]] is 0, then - // Let valuesArray be CreateArrayFromList(values). - // Perform ? Call(resultCapability.[[Resolve]], undefined, - // « valuesArray »). - assert(remainingElementsCount == 0); - const valuesArray = UnsafeCast( - resolveElementContext - [PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementValuesArraySlot]); - Call(nativeContext, UnsafeCast(resolve), Undefined, valuesArray); - } - - // Return resultCapability.[[Promise]]. - return promise; - } + Call(nativeContext, UnsafeCast(resolve), Undefined, valuesArray); + } - transitioning macro GeneratePromiseAll(implicit context: - Context)( - receiver: JSAny, iterable: JSAny, createResolveElementFunctor: F1, - createRejectElementFunctor: F2): JSAny { - // Let C be the this value. - // If Type(C) is not Object, throw a TypeError exception. - const receiver = Cast(receiver) - otherwise ThrowTypeError( - MessageTemplate::kCalledOnNonObject, 'Promise.all'); - - // Let promiseCapability be ? NewPromiseCapability(C). - // Don't fire debugEvent so that forwarding the rejection through all does - // not trigger redundant ExceptionEvents - const capability = NewPromiseCapability(receiver, False); + // Return resultCapability.[[Promise]]. + return promise; +} - try { - try { - // Let iterator be GetIterator(iterable). - // IfAbruptRejectPromise(iterator, promiseCapability). - let i = iterator::GetIterator(iterable); - - // Let result be PerformPromiseAll(iteratorRecord, C, - // promiseCapability). If result is an abrupt completion, then - // If iteratorRecord.[[Done]] is false, let result be - // IteratorClose(iterator, result). - // IfAbruptRejectPromise(result, promiseCapability). - return PerformPromiseAll( - receiver, capability, i, createResolveElementFunctor, - createRejectElementFunctor) otherwise Reject; - } catch (e) deferred { - goto Reject(e); - } - } - label Reject(e: Object) deferred { - // Exception must be bound to a JS value. - const e = UnsafeCast(e); - const reject = UnsafeCast(capability.reject); - Call(context, reject, Undefined, e); - return capability.promise; - } +transitioning macro GeneratePromiseAll( + implicit context: Context)( + receiver: JSAny, iterable: JSAny, createResolveElementFunctor: F1, + createRejectElementFunctor: F2): JSAny { + // Let C be the this value. + // If Type(C) is not Object, throw a TypeError exception. + const receiver = Cast(receiver) + otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.all'); + + // Let promiseCapability be ? NewPromiseCapability(C). + // Don't fire debugEvent so that forwarding the rejection through all does + // not trigger redundant ExceptionEvents + const capability = NewPromiseCapability(receiver, False); + + try { + // Let iterator be GetIterator(iterable). + // IfAbruptRejectPromise(iterator, promiseCapability). + let i = iterator::GetIterator(iterable); + + // Let result be PerformPromiseAll(iteratorRecord, C, + // promiseCapability). If result is an abrupt completion, then + // If iteratorRecord.[[Done]] is false, let result be + // IteratorClose(iterator, result). + // IfAbruptRejectPromise(result, promiseCapability). + return PerformPromiseAll( + receiver, capability, i, createResolveElementFunctor, + createRejectElementFunctor) otherwise Reject; + } catch (e) deferred { + goto Reject(e); + } label Reject(e: Object) deferred { + // Exception must be bound to a JS value. + const e = UnsafeCast(e); + const reject = UnsafeCast(capability.reject); + Call(context, reject, Undefined, e); + return capability.promise; } +} - // ES#sec-promise.all - transitioning javascript builtin PromiseAll( - js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny { - return GeneratePromiseAll( - receiver, iterable, PromiseAllResolveElementFunctor{}, - PromiseAllRejectElementFunctor{}); - } +// ES#sec-promise.all +transitioning javascript builtin PromiseAll( + js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny { + return GeneratePromiseAll( + receiver, iterable, PromiseAllResolveElementFunctor{}, + PromiseAllRejectElementFunctor{}); +} - // ES#sec-promise.allsettled - // Promise.allSettled ( iterable ) - transitioning javascript builtin PromiseAllSettled( - js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny { - return GeneratePromiseAll( - receiver, iterable, PromiseAllSettledResolveElementFunctor{}, - PromiseAllSettledRejectElementFunctor{}); - } +// ES#sec-promise.allsettled +// Promise.allSettled ( iterable ) +transitioning javascript builtin PromiseAllSettled( + js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny { + return GeneratePromiseAll( + receiver, iterable, PromiseAllSettledResolveElementFunctor{}, + PromiseAllSettledRejectElementFunctor{}); +} + +extern macro PromiseAllResolveElementSharedFunConstant(): SharedFunctionInfo; +extern macro PromiseAllSettledRejectElementSharedFunConstant(): + SharedFunctionInfo; +extern macro PromiseAllSettledResolveElementSharedFunConstant(): + SharedFunctionInfo; } diff --git a/deps/v8/src/builtins/promise-any.tq b/deps/v8/src/builtins/promise-any.tq new file mode 100644 index 00000000000000..1046ed0a89c4cf --- /dev/null +++ b/deps/v8/src/builtins/promise-any.tq @@ -0,0 +1,372 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include 'src/builtins/builtins-promise-gen.h' + +namespace promise { +extern enum PromiseAnyRejectElementContextSlots extends int31 +constexpr 'PromiseBuiltins::PromiseAnyRejectElementContextSlots' { + kPromiseAnyRejectElementRemainingSlot, + kPromiseAnyRejectElementCapabilitySlot, + kPromiseAnyRejectElementErrorsArraySlot, + kPromiseAnyRejectElementLength +} + +extern operator '[]=' macro StoreContextElement( + Context, constexpr PromiseAnyRejectElementContextSlots, Object): void; +extern operator '[]' macro LoadContextElement( + Context, constexpr PromiseAnyRejectElementContextSlots): Object; + +// Creates the context used by all Promise.any reject element closures, +// together with the errors array. Since all closures for a single Promise.any +// call use the same context, we need to store the indices for the individual +// closures somewhere else (we put them into the identity hash field of the +// closures), and we also need to have a separate marker for when the closure +// was called already (we slap the native context onto the closure in that +// case to mark it's done). See Promise.all which uses the same approach. +transitioning macro CreatePromiseAnyRejectElementContext( + implicit context: Context)( + capability: PromiseCapability, nativeContext: NativeContext): Context { + const rejectContext = AllocateSyntheticFunctionContext( + nativeContext, + PromiseAnyRejectElementContextSlots::kPromiseAnyRejectElementLength); + rejectContext[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementRemainingSlot] = SmiConstant(1); + rejectContext[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementCapabilitySlot] = capability; + // Will be set later. + rejectContext[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementErrorsArraySlot] = Undefined; + return rejectContext; +} + +macro CreatePromiseAnyRejectElementFunction(implicit context: Context)( + rejectElementContext: Context, index: Smi, + nativeContext: NativeContext): JSFunction { + assert(index > 0); + assert(index < kPropertyArrayHashFieldMax); + const map = UnsafeCast( + nativeContext + [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); + const rejectInfo = PromiseAnyRejectElementSharedFunConstant(); + const reject = + AllocateFunctionWithMapAndContext(map, rejectInfo, rejectElementContext); + assert(kPropertyArrayNoHashSentinel == 0); + reject.properties_or_hash = index; + return reject; +} + +// https://tc39.es/proposal-promise-any/#sec-promise.any-reject-element-functions +transitioning javascript builtin +PromiseAnyRejectElementClosure( + js-implicit context: Context, receiver: JSAny, + target: JSFunction)(value: JSAny): JSAny { + // 1. Let F be the active function object. + + // 2. Let alreadyCalled be F.[[AlreadyCalled]]. + + // 3. If alreadyCalled.[[Value]] is true, return undefined. + + // We use the function's context as the marker to remember whether this + // reject element closure was already called. It points to the reject + // element context (which is a FunctionContext) until it was called the + // first time, in which case we make it point to the native context here + // to mark this reject element closure as done. + if (IsNativeContext(context)) deferred { + return Undefined; + } + + assert( + context.length == + PromiseAnyRejectElementContextSlots::kPromiseAnyRejectElementLength); + + // 4. Set alreadyCalled.[[Value]] to true. + const nativeContext = LoadNativeContext(context); + target.context = nativeContext; + + // 5. Let index be F.[[Index]]. + assert(kPropertyArrayNoHashSentinel == 0); + const identityHash = LoadJSReceiverIdentityHash(target) otherwise unreachable; + assert(identityHash > 0); + const index = identityHash - 1; + + // 6. Let errors be F.[[Errors]]. + if (context[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementErrorsArraySlot] == Undefined) { + // We're going to reject the Promise with a more fundamental error (e.g., + // something went wrong with iterating the Promises). We don't need to + // construct the "errors" array. + return Undefined; + } + + const errorsArray = UnsafeCast( + context[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementErrorsArraySlot]); + + // 7. Let promiseCapability be F.[[Capability]]. + + // 8. Let remainingElementsCount be F.[[RemainingElements]]. + let remainingElementsCount = + UnsafeCast(context[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementRemainingSlot]); + // 9. Set errors[index] to x. + errorsArray.objects[index] = value; + + // 10. Set remainingElementsCount.[[Value]] to + // remainingElementsCount.[[Value]] - 1. + remainingElementsCount = remainingElementsCount - 1; + context[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementRemainingSlot] = remainingElementsCount; + + // 11. If remainingElementsCount.[[Value]] is 0, then + if (remainingElementsCount == 0) { + // a. Let error be a newly created AggregateError object. + + // b. Set error.[[AggregateErrors]] to errors. + const error = ConstructAggregateError(errorsArray); + // c. Return ? Call(promiseCapability.[[Reject]], undefined, « error »). + const capability = UnsafeCast( + context[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementCapabilitySlot]); + Call(context, UnsafeCast(capability.reject), Undefined, error); + } + + // 12. Return undefined. + return Undefined; +} + +transitioning macro PerformPromiseAny(implicit context: Context)( + iteratorRecord: iterator::IteratorRecord, constructor: Constructor, + resultCapability: PromiseCapability): JSAny labels +Reject(Object) { + // 1. Assert: ! IsConstructor(constructor) is true. + // 2. Assert: resultCapability is a PromiseCapability Record. + + const nativeContext = LoadNativeContext(context); + + // 3. Let errors be a new empty List. + let growableErrorsArray = growable_fixed_array::NewGrowableFixedArray(); + + // 4. Let remainingElementsCount be a new Record { [[Value]]: 1 }. + const rejectElementContext = + CreatePromiseAnyRejectElementContext(resultCapability, nativeContext); + + // 5. Let index be 0. + // (We subtract 1 in the PromiseAnyRejectElementClosure). + let index: Smi = 1; + + try { + // We can skip the "resolve" lookup on {constructor} if it's the + // Promise constructor and the Promise.resolve protector is intact, + // as that guards the lookup path for the "resolve" property on the + // Promise constructor. + let promiseResolveFunction: JSAny = Undefined; + if (!IsPromiseResolveLookupChainIntact(nativeContext, constructor)) + deferred { + // 6. Let promiseResolve be ? Get(constructor, `"resolve"`). + const promiseResolve = GetProperty(constructor, kResolveString); + // 7. If IsCallable(promiseResolve) is false, throw a + // TypeError exception. + promiseResolveFunction = Cast(promiseResolve) + otherwise ThrowTypeError( + MessageTemplate::kCalledNonCallable, 'resolve'); + } + const fastIteratorResultMap = UnsafeCast( + nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]); + // 8. Repeat, + while (true) { + let nextValue: JSAny; + try { + // a. Let next be IteratorStep(iteratorRecord). + + // b. If next is an abrupt completion, set + // iteratorRecord.[[Done]] to true. + + // c. ReturnIfAbrupt(next). + + // d. if next is false, then [continues below in "Done"] + const next: JSReceiver = iterator::IteratorStep( + iteratorRecord, fastIteratorResultMap) otherwise goto Done; + // e. Let nextValue be IteratorValue(next). + + // f. If nextValue is an abrupt completion, set + // iteratorRecord.[[Done]] to true. + + // g. ReturnIfAbrupt(nextValue). + nextValue = iterator::IteratorValue(next, fastIteratorResultMap); + } catch (e) { + goto Reject(e); + } + + // We store the indices as identity hash on the reject element + // closures. Thus, we need this limit. + if (index == kPropertyArrayHashFieldMax) { + // If there are too many elements (currently more than + // 2**21-1), raise a RangeError here (which is caught later and + // turned into a rejection of the resulting promise). We could + // gracefully handle this case as well and support more than + // this number of elements by going to a separate function and + // pass the larger indices via a separate context, but it + // doesn't seem likely that we need this, and it's unclear how + // the rest of the system deals with 2**21 live Promises + // anyway. + ThrowRangeError( + MessageTemplate::kTooManyElementsInPromiseCombinator, 'any'); + } + + // h. Append undefined to errors. + growableErrorsArray.Push(Undefined); + + let nextPromise: JSAny; + // i. Let nextPromise be ? Call(constructor, promiseResolve, + // «nextValue »). + nextPromise = CallResolve(constructor, promiseResolveFunction, nextValue); + + // j. Let steps be the algorithm steps defined in Promise.any + // Reject Element Functions. + + // k. Let rejectElement be ! CreateBuiltinFunction(steps, « + // [[AlreadyCalled]], [[Index]], + // [[Errors]], [[Capability]], [[RemainingElements]] »). + + // l. Set rejectElement.[[AlreadyCalled]] to a new Record { + // [[Value]]: false }. + + // m. Set rejectElement.[[Index]] to index. + + // n. Set rejectElement.[[Errors]] to errors. + + // o. Set rejectElement.[[Capability]] to resultCapability. + + // p. Set rejectElement.[[RemainingElements]] to + // remainingElementsCount. + const rejectElement = CreatePromiseAnyRejectElementFunction( + rejectElementContext, index, nativeContext); + // q. Set remainingElementsCount.[[Value]] to + // remainingElementsCount.[[Value]] + 1. + const remainingElementsCount = UnsafeCast( + rejectElementContext[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementRemainingSlot]); + rejectElementContext[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementRemainingSlot] = + remainingElementsCount + 1; + + // r. Perform ? Invoke(nextPromise, "then", « + // resultCapability.[[Resolve]], rejectElement »). + let thenResult: JSAny; + + const then = GetProperty(nextPromise, kThenString); + thenResult = Call( + context, then, nextPromise, + UnsafeCast(resultCapability.resolve), rejectElement); + + // s. Increase index by 1. + index += 1; + + // For catch prediction, mark that rejections here are + // semantically handled by the combined Promise. + if (IsDebugActive() && Is(thenResult)) deferred { + SetPropertyStrict( + context, thenResult, kPromiseHandledBySymbol, + resultCapability.promise); + SetPropertyStrict( + context, rejectElement, kPromiseForwardingHandlerSymbol, True); + } + } + } catch (e) deferred { + iterator::IteratorCloseOnException(iteratorRecord); + goto Reject(e); + } label Done {} + + // (8.d) + // i. Set iteratorRecord.[[Done]] to true. + // ii. Set remainingElementsCount.[[Value]] to + // remainingElementsCount.[[Value]] - 1. + let remainingElementsCount = UnsafeCast( + rejectElementContext[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementRemainingSlot]); + remainingElementsCount -= 1; + rejectElementContext[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementRemainingSlot] = + remainingElementsCount; + + const errorsArray = growableErrorsArray.ToFixedArray(); + rejectElementContext[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementErrorsArraySlot] = + errorsArray; + + // iii. If remainingElementsCount.[[Value]] is 0, then + if (remainingElementsCount == 0) deferred { + // 1. Let error be a newly created AggregateError object. + // 2. Set error.[[AggregateErrors]] to errors. + const error = ConstructAggregateError(errorsArray); + // 3. Return ThrowCompletion(error). + goto Reject(error); + } + // iv. Return resultCapability.[[Promise]]. + return resultCapability.promise; +} + +// https://tc39.es/proposal-promise-any/#sec-promise.any +transitioning javascript builtin +PromiseAny( + js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny { + // 1. Let C be the this value. + const receiver = Cast(receiver) + otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.any'); + + // 2. Let promiseCapability be ? NewPromiseCapability(C). + const capability = NewPromiseCapability(receiver, False); + + // NewPromiseCapability guarantees that receiver is Constructor + assert(Is(receiver)); + const constructor = UnsafeCast(receiver); + + try { + let iteratorRecord: iterator::IteratorRecord; + try { + // 3. Let iteratorRecord be GetIterator(iterable). + + // 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability). + // (catch below) + iteratorRecord = iterator::GetIterator(iterable); + + // 5. Let result be PerformPromiseAny(iteratorRecord, C, + // promiseCapability). + + // 6. If result is an abrupt completion, then + + // a. If iteratorRecord.[[Done]] is false, set result to + // IteratorClose(iteratorRecord, result). + + // b. IfAbruptRejectPromise(result, promiseCapability). + + // [Iterator closing handled by PerformPromiseAny] + + // 7. Return Completion(result). + return PerformPromiseAny(iteratorRecord, constructor, capability) + otherwise Reject; + } catch (e) deferred { + goto Reject(e); + } + } label Reject(e: Object) deferred { + // Exception must be bound to a JS value. + assert(e != TheHole); + Call( + context, UnsafeCast(capability.reject), Undefined, + UnsafeCast(e)); + return capability.promise; + } +} + +transitioning macro ConstructAggregateError(implicit context: Context)( + errorsArray: FixedArray): JSObject { + const obj: JSAggregateError = error::ConstructInternalAggregateErrorHelper( + context, SmiConstant(MessageTemplate::kAllPromisesRejected)); + obj.errors = errorsArray; + return obj; +} + +extern macro PromiseAnyRejectElementSharedFunConstant(): SharedFunctionInfo; +} diff --git a/deps/v8/src/builtins/promise-constructor.tq b/deps/v8/src/builtins/promise-constructor.tq index dc0e077485cabe..dbf1fe2f4ded26 100644 --- a/deps/v8/src/builtins/promise-constructor.tq +++ b/deps/v8/src/builtins/promise-constructor.tq @@ -6,104 +6,104 @@ #include 'src/builtins/builtins-promise-gen.h' namespace runtime { - extern transitioning runtime - DebugPushPromise(implicit context: Context)(JSAny): JSAny; +extern transitioning runtime +DebugPushPromise(implicit context: Context)(JSAny): JSAny; - extern transitioning runtime - DebugPopPromise(implicit context: Context)(): JSAny; +extern transitioning runtime +DebugPopPromise(implicit context: Context)(): JSAny; - extern transitioning runtime - PromiseHookInit(implicit context: Context)(Object, Object): JSAny; +extern transitioning runtime +PromiseHookInit(implicit context: Context)(Object, Object): JSAny; } // https://tc39.es/ecma262/#sec-promise-constructor namespace promise { - extern runtime IncrementUseCounter(Context, Smi): void; - type UseCounterFeature extends int31 - constexpr 'v8::Isolate::UseCounterFeature'; - const kPromiseConstructorReturnedUndefined: constexpr UseCounterFeature - generates 'v8::Isolate::kPromiseConstructorReturnedUndefined'; - - extern macro - IsDebugActive(): bool; - - transitioning macro - HasAccessCheckFailed(implicit context: Context)( - nativeContext: NativeContext, promiseFun: JSAny, executor: JSAny): bool { - BranchIfAccessCheckFailed(nativeContext, promiseFun, executor) - otherwise return true; - return false; - } +extern runtime IncrementUseCounter(Context, Smi): void; +type UseCounterFeature extends int31 +constexpr 'v8::Isolate::UseCounterFeature'; +const kPromiseConstructorReturnedUndefined: constexpr UseCounterFeature + generates 'v8::Isolate::kPromiseConstructorReturnedUndefined'; + +extern macro +IsDebugActive(): bool; + +transitioning macro +HasAccessCheckFailed(implicit context: Context)( + nativeContext: NativeContext, promiseFun: JSAny, executor: JSAny): bool { + BranchIfAccessCheckFailed(nativeContext, promiseFun, executor) + otherwise return true; + return false; +} - extern macro ConstructorBuiltinsAssembler::EmitFastNewObject( - Context, JSFunction, JSReceiver): JSObject; +extern macro ConstructorBuiltinsAssembler::EmitFastNewObject( + Context, JSFunction, JSReceiver): JSObject; - extern macro - PromiseBuiltinsAssembler::IsPromiseHookEnabledOrHasAsyncEventDelegate(): bool; +extern macro +PromiseBuiltinsAssembler::IsPromiseHookEnabledOrHasAsyncEventDelegate(): bool; - // https://tc39.es/ecma262/#sec-promise-executor - transitioning javascript builtin - PromiseConstructor( - js-implicit context: NativeContext, receiver: JSAny, - newTarget: JSAny)(executor: JSAny): JSAny { - // 1. If NewTarget is undefined, throw a TypeError exception. - if (newTarget == Undefined) { - ThrowTypeError(MessageTemplate::kNotAPromise, newTarget); - } +// https://tc39.es/ecma262/#sec-promise-executor +transitioning javascript builtin +PromiseConstructor( + js-implicit context: NativeContext, receiver: JSAny, + newTarget: JSAny)(executor: JSAny): JSAny { + // 1. If NewTarget is undefined, throw a TypeError exception. + if (newTarget == Undefined) { + ThrowTypeError(MessageTemplate::kNotAPromise, newTarget); + } - // 2. If IsCallable(executor) is false, throw a TypeError exception. - if (!TaggedIsCallable(executor)) { - ThrowTypeError(MessageTemplate::kResolverNotAFunction, executor); - } + // 2. If IsCallable(executor) is false, throw a TypeError exception. + if (!Is(executor)) { + ThrowTypeError(MessageTemplate::kResolverNotAFunction, executor); + } - const promiseFun = UnsafeCast( - context[NativeContextSlot::PROMISE_FUNCTION_INDEX]); + const promiseFun = UnsafeCast( + context[NativeContextSlot::PROMISE_FUNCTION_INDEX]); - // Silently fail if the stack looks fishy. - if (HasAccessCheckFailed(context, promiseFun, executor)) { - IncrementUseCounter( - context, SmiConstant(kPromiseConstructorReturnedUndefined)); - return Undefined; - } + // Silently fail if the stack looks fishy. + if (HasAccessCheckFailed(context, promiseFun, executor)) { + IncrementUseCounter( + context, SmiConstant(kPromiseConstructorReturnedUndefined)); + return Undefined; + } - let result: JSPromise; - if (promiseFun == newTarget) { - result = NewJSPromise(); - } else { - result = UnsafeCast(EmitFastNewObject( - context, promiseFun, UnsafeCast(newTarget))); - PromiseInit(result); - if (IsPromiseHookEnabledOrHasAsyncEventDelegate()) { - runtime::PromiseHookInit(result, Undefined); - } + let result: JSPromise; + if (promiseFun == newTarget) { + result = NewJSPromise(); + } else { + result = UnsafeCast(EmitFastNewObject( + context, promiseFun, UnsafeCast(newTarget))); + PromiseInit(result); + if (IsPromiseHookEnabledOrHasAsyncEventDelegate()) { + runtime::PromiseHookInit(result, Undefined); } + } - const isDebugActive = IsDebugActive(); - if (isDebugActive) runtime::DebugPushPromise(result); - - const funcs = CreatePromiseResolvingFunctions(result, True, context); - const resolve = funcs.resolve; - const reject = funcs.reject; - try { - Call(context, UnsafeCast(executor), Undefined, resolve, reject); - } catch (e) { - Call(context, reject, Undefined, e); - } + const isDebugActive = IsDebugActive(); + if (isDebugActive) runtime::DebugPushPromise(result); - if (isDebugActive) runtime::DebugPopPromise(); - return result; + const funcs = CreatePromiseResolvingFunctions(result, True, context); + const resolve = funcs.resolve; + const reject = funcs.reject; + try { + Call(context, UnsafeCast(executor), Undefined, resolve, reject); + } catch (e) { + Call(context, reject, Undefined, e); } - // Promise.prototype.catch ( onRejected ) - // https://tc39.es/ecma262/#sec-promise.prototype.catch - transitioning javascript builtin - PromisePrototypeCatch(js-implicit context: Context, receiver: JSAny)( - onRejected: JSAny): JSAny { - // 1. Let promise be the this value. - // 2. Return ? Invoke(promise, "then", « undefined, onRejected »). - const nativeContext = LoadNativeContext(context); - return UnsafeCast( - InvokeThen(nativeContext, receiver, Undefined, onRejected)); - } + if (isDebugActive) runtime::DebugPopPromise(); + return result; +} + +// Promise.prototype.catch ( onRejected ) +// https://tc39.es/ecma262/#sec-promise.prototype.catch +transitioning javascript builtin +PromisePrototypeCatch( + js-implicit context: Context, receiver: JSAny)(onRejected: JSAny): JSAny { + // 1. Let promise be the this value. + // 2. Return ? Invoke(promise, "then", « undefined, onRejected »). + const nativeContext = LoadNativeContext(context); + return UnsafeCast( + InvokeThen(nativeContext, receiver, Undefined, onRejected)); +} } diff --git a/deps/v8/src/builtins/promise-finally.tq b/deps/v8/src/builtins/promise-finally.tq index 32028b819dabdf..48928ca4ce7ef3 100644 --- a/deps/v8/src/builtins/promise-finally.tq +++ b/deps/v8/src/builtins/promise-finally.tq @@ -7,201 +7,201 @@ namespace promise { - // TODO(joshualitt): The below ContextSlots are only available on synthetic - // contexts created by the promise pipeline for use in the promise pipeline. - // However, with Torque we should type the context and its slots to prevent - // accidentially using these slots on contexts which don't support them. - const kPromiseBuiltinsValueSlot: constexpr ContextSlot - generates 'PromiseBuiltins::kValueSlot'; - const kPromiseBuiltinsOnFinallySlot: constexpr ContextSlot - generates 'PromiseBuiltins::kOnFinallySlot'; - const kPromiseBuiltinsConstructorSlot: constexpr ContextSlot - generates 'PromiseBuiltins::kConstructorSlot'; - const kPromiseBuiltinsPromiseValueThunkOrReasonContextLength: constexpr int31 - generates 'PromiseBuiltins::kPromiseValueThunkOrReasonContextLength'; - const kPromiseBuiltinsPromiseFinallyContextLength: constexpr int31 - generates 'PromiseBuiltins::kPromiseFinallyContextLength'; - - transitioning javascript builtin - PromiseValueThunkFinally(js-implicit context: Context, receiver: JSAny)(): - JSAny { - return UnsafeCast(context[kPromiseBuiltinsValueSlot]); - } +// TODO(joshualitt): The below ContextSlots are only available on synthetic +// contexts created by the promise pipeline for use in the promise pipeline. +// However, with Torque we should type the context and its slots to prevent +// accidentially using these slots on contexts which don't support them. +const kPromiseBuiltinsValueSlot: constexpr ContextSlot + generates 'PromiseBuiltins::kValueSlot'; +const kPromiseBuiltinsOnFinallySlot: constexpr ContextSlot + generates 'PromiseBuiltins::kOnFinallySlot'; +const kPromiseBuiltinsConstructorSlot: constexpr ContextSlot + generates 'PromiseBuiltins::kConstructorSlot'; +const kPromiseBuiltinsPromiseValueThunkOrReasonContextLength: constexpr int31 + generates 'PromiseBuiltins::kPromiseValueThunkOrReasonContextLength'; +const kPromiseBuiltinsPromiseFinallyContextLength: constexpr int31 + generates 'PromiseBuiltins::kPromiseFinallyContextLength'; + +transitioning javascript builtin +PromiseValueThunkFinally( + js-implicit context: Context, receiver: JSAny)(): JSAny { + return UnsafeCast(context[kPromiseBuiltinsValueSlot]); +} - transitioning javascript builtin - PromiseThrowerFinally(js-implicit context: Context, receiver: JSAny)(): - never { - const reason = UnsafeCast(context[kPromiseBuiltinsValueSlot]); - Throw(reason); - } +transitioning javascript builtin +PromiseThrowerFinally(js-implicit context: Context, receiver: JSAny)(): never { + const reason = UnsafeCast(context[kPromiseBuiltinsValueSlot]); + Throw(reason); +} - macro CreateThrowerFunction(implicit context: Context)( - nativeContext: NativeContext, reason: JSAny): JSFunction { - const throwerContext = AllocateSyntheticFunctionContext( - nativeContext, kPromiseBuiltinsPromiseValueThunkOrReasonContextLength); - throwerContext[kPromiseBuiltinsValueSlot] = reason; - const map = UnsafeCast( - nativeContext - [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); - const throwerInfo = UnsafeCast( - nativeContext[NativeContextSlot::PROMISE_THROWER_FINALLY_SHARED_FUN]); - return AllocateFunctionWithMapAndContext(map, throwerInfo, throwerContext); - } +macro CreateThrowerFunction(implicit context: Context)( + nativeContext: NativeContext, reason: JSAny): JSFunction { + const throwerContext = AllocateSyntheticFunctionContext( + nativeContext, kPromiseBuiltinsPromiseValueThunkOrReasonContextLength); + throwerContext[kPromiseBuiltinsValueSlot] = reason; + const map = UnsafeCast( + nativeContext + [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); + const throwerInfo = PromiseThrowerFinallySharedFunConstant(); + return AllocateFunctionWithMapAndContext(map, throwerInfo, throwerContext); +} - transitioning javascript builtin - PromiseCatchFinally(js-implicit context: Context, receiver: JSAny)( - reason: JSAny): JSAny { - // 1. Let onFinally be F.[[OnFinally]]. - // 2. Assert: IsCallable(onFinally) is true. - const onFinally = - UnsafeCast(context[kPromiseBuiltinsOnFinallySlot]); +transitioning javascript builtin +PromiseCatchFinally( + js-implicit context: Context, receiver: JSAny)(reason: JSAny): JSAny { + // 1. Let onFinally be F.[[OnFinally]]. + // 2. Assert: IsCallable(onFinally) is true. + const onFinally = + UnsafeCast(context[kPromiseBuiltinsOnFinallySlot]); - // 3. Let result be ? Call(onFinally). - const result = Call(context, onFinally, Undefined); + // 3. Let result be ? Call(onFinally). + const result = Call(context, onFinally, Undefined); - // 4. Let C be F.[[Constructor]]. - const constructor = - UnsafeCast(context[kPromiseBuiltinsConstructorSlot]); + // 4. Let C be F.[[Constructor]]. + const constructor = + UnsafeCast(context[kPromiseBuiltinsConstructorSlot]); - // 5. Assert: IsConstructor(C) is true. - assert(IsConstructor(constructor)); + // 5. Assert: IsConstructor(C) is true. + assert(IsConstructor(constructor)); - // 6. Let promise be ? PromiseResolve(C, result). - const promise = PromiseResolve(constructor, result); + // 6. Let promise be ? PromiseResolve(C, result). + const promise = PromiseResolve(constructor, result); - // 7. Let thrower be equivalent to a function that throws reason. - const nativeContext = LoadNativeContext(context); - const thrower = CreateThrowerFunction(nativeContext, reason); + // 7. Let thrower be equivalent to a function that throws reason. + const nativeContext = LoadNativeContext(context); + const thrower = CreateThrowerFunction(nativeContext, reason); - // 8. Return ? Invoke(promise, "then", « thrower »). - return UnsafeCast(InvokeThen(nativeContext, promise, thrower)); - } + // 8. Return ? Invoke(promise, "then", « thrower »). + return UnsafeCast(InvokeThen(nativeContext, promise, thrower)); +} - macro CreateValueThunkFunction(implicit context: Context)( - nativeContext: NativeContext, value: JSAny): JSFunction { - const valueThunkContext = AllocateSyntheticFunctionContext( - nativeContext, kPromiseBuiltinsPromiseValueThunkOrReasonContextLength); - valueThunkContext[kPromiseBuiltinsValueSlot] = value; - const map = UnsafeCast( - nativeContext - [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); - const valueThunkInfo = UnsafeCast( - nativeContext - [NativeContextSlot::PROMISE_VALUE_THUNK_FINALLY_SHARED_FUN]); - return AllocateFunctionWithMapAndContext( - map, valueThunkInfo, valueThunkContext); - } +macro CreateValueThunkFunction(implicit context: Context)( + nativeContext: NativeContext, value: JSAny): JSFunction { + const valueThunkContext = AllocateSyntheticFunctionContext( + nativeContext, kPromiseBuiltinsPromiseValueThunkOrReasonContextLength); + valueThunkContext[kPromiseBuiltinsValueSlot] = value; + const map = UnsafeCast( + nativeContext + [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); + const valueThunkInfo = PromiseValueThunkFinallySharedFunConstant(); + return AllocateFunctionWithMapAndContext( + map, valueThunkInfo, valueThunkContext); +} - transitioning javascript builtin - PromiseThenFinally(js-implicit context: Context, receiver: JSAny)( - value: JSAny): JSAny { - // 1. Let onFinally be F.[[OnFinally]]. - // 2. Assert: IsCallable(onFinally) is true. - const onFinally = - UnsafeCast(context[kPromiseBuiltinsOnFinallySlot]); +transitioning javascript builtin +PromiseThenFinally( + js-implicit context: Context, receiver: JSAny)(value: JSAny): JSAny { + // 1. Let onFinally be F.[[OnFinally]]. + // 2. Assert: IsCallable(onFinally) is true. + const onFinally = + UnsafeCast(context[kPromiseBuiltinsOnFinallySlot]); - // 3. Let result be ? Call(onFinally). - const result = Call(context, onFinally, Undefined); + // 3. Let result be ? Call(onFinally). + const result = Call(context, onFinally, Undefined); - // 4. Let C be F.[[Constructor]]. - const constructor = - UnsafeCast(context[kPromiseBuiltinsConstructorSlot]); + // 4. Let C be F.[[Constructor]]. + const constructor = + UnsafeCast(context[kPromiseBuiltinsConstructorSlot]); - // 5. Assert: IsConstructor(C) is true. - assert(IsConstructor(constructor)); + // 5. Assert: IsConstructor(C) is true. + assert(IsConstructor(constructor)); - // 6. Let promise be ? PromiseResolve(C, result). - const promise = PromiseResolve(constructor, result); + // 6. Let promise be ? PromiseResolve(C, result). + const promise = PromiseResolve(constructor, result); - // 7. Let valueThunk be equivalent to a function that returns value. - const nativeContext = LoadNativeContext(context); - const valueThunk = CreateValueThunkFunction(nativeContext, value); + // 7. Let valueThunk be equivalent to a function that returns value. + const nativeContext = LoadNativeContext(context); + const valueThunk = CreateValueThunkFunction(nativeContext, value); - // 8. Return ? Invoke(promise, "then", « valueThunk »). - return UnsafeCast(InvokeThen(nativeContext, promise, valueThunk)); - } + // 8. Return ? Invoke(promise, "then", « valueThunk »). + return UnsafeCast(InvokeThen(nativeContext, promise, valueThunk)); +} - struct PromiseFinallyFunctions { - then_finally: JSFunction; - catch_finally: JSFunction; - } +struct PromiseFinallyFunctions { + then_finally: JSFunction; + catch_finally: JSFunction; +} - macro CreatePromiseFinallyFunctions(implicit context: Context)( - nativeContext: NativeContext, onFinally: Callable, - constructor: JSReceiver): PromiseFinallyFunctions { - const promiseContext = AllocateSyntheticFunctionContext( - nativeContext, kPromiseBuiltinsPromiseFinallyContextLength); - promiseContext[kPromiseBuiltinsOnFinallySlot] = onFinally; - promiseContext[kPromiseBuiltinsConstructorSlot] = constructor; - const map = UnsafeCast( - nativeContext - [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); - const thenFinallyInfo = UnsafeCast( - nativeContext[NativeContextSlot::PROMISE_THEN_FINALLY_SHARED_FUN]); - const thenFinally = - AllocateFunctionWithMapAndContext(map, thenFinallyInfo, promiseContext); - const catchFinallyInfo = UnsafeCast( - nativeContext[NativeContextSlot::PROMISE_CATCH_FINALLY_SHARED_FUN]); - const catchFinally = AllocateFunctionWithMapAndContext( - map, catchFinallyInfo, promiseContext); - return PromiseFinallyFunctions{ - then_finally: thenFinally, - catch_finally: catchFinally - }; - } +macro CreatePromiseFinallyFunctions(implicit context: Context)( + nativeContext: NativeContext, onFinally: Callable, + constructor: JSReceiver): PromiseFinallyFunctions { + const promiseContext = AllocateSyntheticFunctionContext( + nativeContext, kPromiseBuiltinsPromiseFinallyContextLength); + promiseContext[kPromiseBuiltinsOnFinallySlot] = onFinally; + promiseContext[kPromiseBuiltinsConstructorSlot] = constructor; + const map = UnsafeCast( + nativeContext + [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]); + const thenFinallyInfo = PromiseThenFinallySharedFunConstant(); + const thenFinally = + AllocateFunctionWithMapAndContext(map, thenFinallyInfo, promiseContext); + const catchFinallyInfo = PromiseCatchFinallySharedFunConstant(); + const catchFinally = + AllocateFunctionWithMapAndContext(map, catchFinallyInfo, promiseContext); + return PromiseFinallyFunctions{ + then_finally: thenFinally, + catch_finally: catchFinally + }; +} - transitioning javascript builtin - PromisePrototypeFinally(js-implicit context: Context, receiver: JSAny)( - onFinally: JSAny): JSAny { - // 1. Let promise be the this value. - // 2. If Type(promise) is not Object, throw a TypeError exception. - const jsReceiver = Cast(receiver) otherwise ThrowTypeError( - MessageTemplate::kCalledOnNonObject, 'Promise.prototype.finally'); - - // 3. Let C be ? SpeciesConstructor(promise, %Promise%). - const nativeContext = LoadNativeContext(context); - const promiseFun = UnsafeCast( - nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]); - - let constructor: JSReceiver = promiseFun; - const receiverMap = jsReceiver.map; - if (!IsJSPromiseMap(receiverMap) || - !IsPromiseSpeciesLookupChainIntact(nativeContext, receiverMap)) - deferred { - constructor = SpeciesConstructor(jsReceiver, promiseFun); - } - - // 4. Assert: IsConstructor(C) is true. - assert(IsConstructor(constructor)); - - // 5. If IsCallable(onFinally) is not true, - // a. Let thenFinally be onFinally. - // b. Let catchFinally be onFinally. - // 6. Else, - // a. Let thenFinally be a new built-in function object as defined - // in ThenFinally Function. - // b. Let catchFinally be a new built-in function object as - // defined in CatchFinally Function. - // c. Set thenFinally and catchFinally's [[Constructor]] internal - // slots to C. - // d. Set thenFinally and catchFinally's [[OnFinally]] internal - // slots to onFinally. - let thenFinally: JSAny; - let catchFinally: JSAny; - if (!TaggedIsSmi(onFinally) && - IsCallable(UnsafeCast(onFinally))) { - const pair = CreatePromiseFinallyFunctions( - nativeContext, UnsafeCast(onFinally), constructor); +transitioning javascript builtin +PromisePrototypeFinally( + js-implicit context: Context, receiver: JSAny)(onFinally: JSAny): JSAny { + // 1. Let promise be the this value. + // 2. If Type(promise) is not Object, throw a TypeError exception. + const jsReceiver = Cast(receiver) otherwise ThrowTypeError( + MessageTemplate::kCalledOnNonObject, 'Promise.prototype.finally'); + + // 3. Let C be ? SpeciesConstructor(promise, %Promise%). + const nativeContext = LoadNativeContext(context); + const promiseFun = UnsafeCast( + nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]); + + let constructor: JSReceiver = promiseFun; + const receiverMap = jsReceiver.map; + if (!IsJSPromiseMap(receiverMap) || + !IsPromiseSpeciesLookupChainIntact(nativeContext, receiverMap)) + deferred { + constructor = SpeciesConstructor(jsReceiver, promiseFun); + } + + // 4. Assert: IsConstructor(C) is true. + assert(IsConstructor(constructor)); + + // 5. If IsCallable(onFinally) is not true, + // a. Let thenFinally be onFinally. + // b. Let catchFinally be onFinally. + // 6. Else, + // a. Let thenFinally be a new built-in function object as defined + // in ThenFinally Function. + // b. Let catchFinally be a new built-in function object as + // defined in CatchFinally Function. + // c. Set thenFinally and catchFinally's [[Constructor]] internal + // slots to C. + // d. Set thenFinally and catchFinally's [[OnFinally]] internal + // slots to onFinally. + let thenFinally: JSAny; + let catchFinally: JSAny; + typeswitch (onFinally) { + case (onFinally: Callable): { + const pair = + CreatePromiseFinallyFunctions(nativeContext, onFinally, constructor); thenFinally = pair.then_finally; catchFinally = pair.catch_finally; - } else - deferred { - thenFinally = onFinally; - catchFinally = onFinally; - } - - // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »). - return UnsafeCast( - InvokeThen(nativeContext, receiver, thenFinally, catchFinally)); + } + case (JSAny): deferred { + thenFinally = onFinally; + catchFinally = onFinally; + } } + + // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »). + return UnsafeCast( + InvokeThen(nativeContext, receiver, thenFinally, catchFinally)); +} + +extern macro PromiseCatchFinallySharedFunConstant(): SharedFunctionInfo; +extern macro PromiseThenFinallySharedFunConstant(): SharedFunctionInfo; +extern macro PromiseThrowerFinallySharedFunConstant(): SharedFunctionInfo; +extern macro PromiseValueThunkFinallySharedFunConstant(): SharedFunctionInfo; } diff --git a/deps/v8/src/builtins/promise-jobs.tq b/deps/v8/src/builtins/promise-jobs.tq index ee049605e1afb4..6c64baf22d19ba 100644 --- a/deps/v8/src/builtins/promise-jobs.tq +++ b/deps/v8/src/builtins/promise-jobs.tq @@ -6,68 +6,68 @@ // https://tc39.es/ecma262/#sec-promise-jobs namespace promise { - extern macro IsJSPromiseMap(Map): bool; +extern macro IsJSPromiseMap(Map): bool; - // https://tc39.es/ecma262/#sec-promiseresolvethenablejob - transitioning builtin - PromiseResolveThenableJob(implicit context: Context)( - promiseToResolve: JSPromise, thenable: JSReceiver, then: JSAny): JSAny { - // We can use a simple optimization here if we know that {then} is the - // initial Promise.prototype.then method, and {thenable} is a JSPromise - // whose - // @@species lookup chain is intact: We can connect {thenable} and - // {promise_to_resolve} directly in that case and avoid the allocation of a - // temporary JSPromise and the closures plus context. +// https://tc39.es/ecma262/#sec-promiseresolvethenablejob +transitioning builtin +PromiseResolveThenableJob(implicit context: Context)( + promiseToResolve: JSPromise, thenable: JSReceiver, then: JSAny): JSAny { + // We can use a simple optimization here if we know that {then} is the + // initial Promise.prototype.then method, and {thenable} is a JSPromise + // whose + // @@species lookup chain is intact: We can connect {thenable} and + // {promise_to_resolve} directly in that case and avoid the allocation of a + // temporary JSPromise and the closures plus context. + // + // We take the generic (slow-)path if a PromiseHook is enabled or the + // debugger is active, to make sure we expose spec compliant behavior. + const nativeContext = LoadNativeContext(context); + const promiseThen = nativeContext[NativeContextSlot::PROMISE_THEN_INDEX]; + const thenableMap = thenable.map; + if (TaggedEqual(then, promiseThen) && IsJSPromiseMap(thenableMap) && + !IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() && + IsPromiseSpeciesLookupChainIntact(nativeContext, thenableMap)) { + // We know that the {thenable} is a JSPromise, which doesn't require + // any special treatment and that {then} corresponds to the initial + // Promise.prototype.then method. So instead of allocating a temporary + // JSPromise to connect the {thenable} with the {promise_to_resolve}, + // we can directly schedule the {promise_to_resolve} with default + // handlers onto the {thenable} promise. This does not only save the + // JSPromise allocation, but also avoids the allocation of the two + // resolving closures and the shared context. // - // We take the generic (slow-)path if a PromiseHook is enabled or the - // debugger is active, to make sure we expose spec compliant behavior. - const nativeContext = LoadNativeContext(context); - const promiseThen = nativeContext[NativeContextSlot::PROMISE_THEN_INDEX]; - const thenableMap = thenable.map; - if (TaggedEqual(then, promiseThen) && IsJSPromiseMap(thenableMap) && - !IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() && - IsPromiseSpeciesLookupChainIntact(nativeContext, thenableMap)) { - // We know that the {thenable} is a JSPromise, which doesn't require - // any special treatment and that {then} corresponds to the initial - // Promise.prototype.then method. So instead of allocating a temporary - // JSPromise to connect the {thenable} with the {promise_to_resolve}, - // we can directly schedule the {promise_to_resolve} with default - // handlers onto the {thenable} promise. This does not only save the - // JSPromise allocation, but also avoids the allocation of the two - // resolving closures and the shared context. - // - // What happens normally in this case is - // - // resolve, reject = CreateResolvingFunctions(promise_to_resolve) - // result_capability = NewPromiseCapability(%Promise%) - // PerformPromiseThen(thenable, resolve, reject, result_capability) - // - // which means that PerformPromiseThen will either schedule a new - // PromiseReaction with resolve and reject or a PromiseReactionJob - // with resolve or reject based on the state of {thenable}. And - // resolve or reject will just invoke the default [[Resolve]] or - // [[Reject]] functions on the {promise_to_resolve}. - // - // This is the same as just doing - // - // PerformPromiseThen(thenable, undefined, undefined, - // promise_to_resolve) - // - // which performs exactly the same (observable) steps. - return PerformPromiseThen( - UnsafeCast(thenable), UndefinedConstant(), - UndefinedConstant(), promiseToResolve); - } else { - const funcs = CreatePromiseResolvingFunctions( - promiseToResolve, False, nativeContext); - const resolve = funcs.resolve; - const reject = funcs.reject; - try { - return Call( - context, UnsafeCast(then), thenable, resolve, reject); - } catch (e) { - return Call(context, UnsafeCast(reject), Undefined, e); - } + // What happens normally in this case is + // + // resolve, reject = CreateResolvingFunctions(promise_to_resolve) + // result_capability = NewPromiseCapability(%Promise%) + // PerformPromiseThen(thenable, resolve, reject, result_capability) + // + // which means that PerformPromiseThen will either schedule a new + // PromiseReaction with resolve and reject or a PromiseReactionJob + // with resolve or reject based on the state of {thenable}. And + // resolve or reject will just invoke the default [[Resolve]] or + // [[Reject]] functions on the {promise_to_resolve}. + // + // This is the same as just doing + // + // PerformPromiseThen(thenable, undefined, undefined, + // promise_to_resolve) + // + // which performs exactly the same (observable) steps. + return PerformPromiseThen( + UnsafeCast(thenable), UndefinedConstant(), + UndefinedConstant(), promiseToResolve); + } else { + const funcs = + CreatePromiseResolvingFunctions(promiseToResolve, False, nativeContext); + const resolve = funcs.resolve; + const reject = funcs.reject; + try { + return Call( + context, UnsafeCast(then), thenable, resolve, reject); + } catch (e) { + return Call(context, UnsafeCast(reject), Undefined, e); } } } +} diff --git a/deps/v8/src/builtins/promise-misc.tq b/deps/v8/src/builtins/promise-misc.tq index 61461de29fe091..7ed2f7909a88c1 100644 --- a/deps/v8/src/builtins/promise-misc.tq +++ b/deps/v8/src/builtins/promise-misc.tq @@ -6,246 +6,267 @@ #include 'src/builtins/builtins-promise-gen.h' namespace runtime { - extern transitioning runtime - AllowDynamicFunction(implicit context: Context)(JSAny): JSAny; +extern transitioning runtime +AllowDynamicFunction(implicit context: Context)(JSAny): JSAny; } // Unsafe functions that should be used very carefully. namespace promise_internal { - extern macro PromiseBuiltinsAssembler::ZeroOutEmbedderOffsets(JSPromise): - void; +extern macro PromiseBuiltinsAssembler::ZeroOutEmbedderOffsets(JSPromise): void; - extern macro PromiseBuiltinsAssembler::AllocateJSPromise(Context): HeapObject; +extern macro PromiseBuiltinsAssembler::AllocateJSPromise(Context): HeapObject; } namespace promise { - extern macro IsFunctionWithPrototypeSlotMap(Map): bool; +extern macro IsFunctionWithPrototypeSlotMap(Map): bool; - @export - macro PromiseHasHandler(promise: JSPromise): bool { - return promise.HasHandler(); - } +@export +macro PromiseHasHandler(promise: JSPromise): bool { + return promise.HasHandler(); +} - @export - macro PromiseInit(promise: JSPromise): void { - assert(PromiseState::kPending == 0); - promise.reactions_or_result = kZero; - promise.flags = 0; - promise_internal::ZeroOutEmbedderOffsets(promise); - } +@export +macro PromiseInit(promise: JSPromise): void { + promise.reactions_or_result = kZero; + promise.flags = SmiTag(JSPromiseFlags{ + status: PromiseState::kPending, + has_handler: false, + handled_hint: false, + async_task_id: 0 + }); + promise_internal::ZeroOutEmbedderOffsets(promise); +} - macro InnerNewJSPromise(implicit context: Context)(): JSPromise { - const nativeContext = LoadNativeContext(context); - const promiseFun = UnsafeCast( - nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]); - assert(IsFunctionWithPrototypeSlotMap(promiseFun.map)); - const promiseMap = UnsafeCast(promiseFun.prototype_or_initial_map); - const promiseHeapObject = promise_internal::AllocateJSPromise(context); - * UnsafeConstCast(& promiseHeapObject.map) = promiseMap; - const promise = UnsafeCast(promiseHeapObject); - promise.properties_or_hash = kEmptyFixedArray; - promise.elements = kEmptyFixedArray; - promise.reactions_or_result = kZero; - promise.flags = 0; - return promise; - } +macro InnerNewJSPromise(implicit context: Context)(): JSPromise { + const nativeContext = LoadNativeContext(context); + const promiseFun = UnsafeCast( + nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]); + assert(IsFunctionWithPrototypeSlotMap(promiseFun.map)); + const promiseMap = UnsafeCast(promiseFun.prototype_or_initial_map); + const promiseHeapObject = promise_internal::AllocateJSPromise(context); + * UnsafeConstCast(& promiseHeapObject.map) = promiseMap; + const promise = UnsafeCast(promiseHeapObject); + promise.properties_or_hash = kEmptyFixedArray; + promise.elements = kEmptyFixedArray; + promise.reactions_or_result = kZero; + promise.flags = SmiTag(JSPromiseFlags{ + status: PromiseState::kPending, + has_handler: false, + handled_hint: false, + async_task_id: 0 + }); + return promise; +} - macro NewPromiseFulfillReactionJobTask(implicit context: Context)( - handlerContext: Context, argument: Object, handler: Callable|Undefined, - promiseOrCapability: JSPromise|PromiseCapability| - Undefined): PromiseFulfillReactionJobTask { - const nativeContext = LoadNativeContext(handlerContext); - return new PromiseFulfillReactionJobTask{ - map: PromiseFulfillReactionJobTaskMapConstant(), - argument, - context: handlerContext, - handler, - promise_or_capability: promiseOrCapability, - continuation_preserved_embedder_data: nativeContext - [NativeContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX] - }; - } +macro NewPromiseFulfillReactionJobTask(implicit context: Context)( + handlerContext: Context, argument: Object, handler: Callable|Undefined, + promiseOrCapability: JSPromise|PromiseCapability| + Undefined): PromiseFulfillReactionJobTask { + const nativeContext = LoadNativeContext(handlerContext); + return new PromiseFulfillReactionJobTask{ + map: PromiseFulfillReactionJobTaskMapConstant(), + argument, + context: handlerContext, + handler, + promise_or_capability: promiseOrCapability, + continuation_preserved_embedder_data: nativeContext + [NativeContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX] + }; +} - macro NewPromiseRejectReactionJobTask(implicit context: Context)( - handlerContext: Context, argument: Object, handler: Callable|Undefined, - promiseOrCapability: JSPromise|PromiseCapability| - Undefined): PromiseRejectReactionJobTask { - const nativeContext = LoadNativeContext(handlerContext); - return new PromiseRejectReactionJobTask{ - map: PromiseRejectReactionJobTaskMapConstant(), - argument, - context: handlerContext, - handler, - promise_or_capability: promiseOrCapability, - continuation_preserved_embedder_data: nativeContext - [NativeContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX] - }; - } +macro NewPromiseRejectReactionJobTask(implicit context: Context)( + handlerContext: Context, argument: Object, handler: Callable|Undefined, + promiseOrCapability: JSPromise|PromiseCapability| + Undefined): PromiseRejectReactionJobTask { + const nativeContext = LoadNativeContext(handlerContext); + return new PromiseRejectReactionJobTask{ + map: PromiseRejectReactionJobTaskMapConstant(), + argument, + context: handlerContext, + handler, + promise_or_capability: promiseOrCapability, + continuation_preserved_embedder_data: nativeContext + [NativeContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX] + }; +} - // These allocate and initialize a promise with pending state and - // undefined fields. - // - // This uses the given parent as the parent promise for the promise - // init hook. - @export - transitioning macro NewJSPromise(implicit context: Context)(parent: Object): - JSPromise { - const instance = InnerNewJSPromise(); - PromiseInit(instance); - if (IsPromiseHookEnabledOrHasAsyncEventDelegate()) { - runtime::PromiseHookInit(instance, parent); - } - return instance; +// These allocate and initialize a promise with pending state and +// undefined fields. +// +// This uses the given parent as the parent promise for the promise +// init hook. +@export +transitioning macro NewJSPromise(implicit context: Context)(parent: Object): + JSPromise { + const instance = InnerNewJSPromise(); + PromiseInit(instance); + if (IsPromiseHookEnabledOrHasAsyncEventDelegate()) { + runtime::PromiseHookInit(instance, parent); } + return instance; +} - // This uses undefined as the parent promise for the promise init - // hook. - @export - transitioning macro NewJSPromise(implicit context: Context)(): JSPromise { - return NewJSPromise(Undefined); - } +// This uses undefined as the parent promise for the promise init +// hook. +@export +transitioning macro NewJSPromise(implicit context: Context)(): JSPromise { + return NewJSPromise(Undefined); +} - // This allocates and initializes a promise with the given state and - // fields. - @export - transitioning macro NewJSPromise(implicit context: Context)( - status: constexpr PromiseState, result: JSAny): JSPromise { - assert(status != PromiseState::kPending); - assert(kJSPromiseStatusShift == 0); - - const instance = InnerNewJSPromise(); - instance.reactions_or_result = result; - instance.SetStatus(status); - promise_internal::ZeroOutEmbedderOffsets(instance); - - if (IsPromiseHookEnabledOrHasAsyncEventDelegate()) { - runtime::PromiseHookInit(instance, Undefined); - } - return instance; - } +// This allocates and initializes a promise with the given state and +// fields. +@export +transitioning macro NewJSPromise(implicit context: Context)( + status: constexpr PromiseState, result: JSAny): JSPromise { + assert(status != PromiseState::kPending); - macro NewPromiseReaction(implicit context: Context)( - handlerContext: Context, next: Zero|PromiseReaction, - promiseOrCapability: JSPromise|PromiseCapability|Undefined, - fulfillHandler: Callable|Undefined, - rejectHandler: Callable|Undefined): PromiseReaction { - const nativeContext = LoadNativeContext(handlerContext); - return new PromiseReaction{ - map: PromiseReactionMapConstant(), - next: next, - reject_handler: rejectHandler, - fulfill_handler: fulfillHandler, - promise_or_capability: promiseOrCapability, - continuation_preserved_embedder_data: nativeContext - [NativeContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX] - }; - } + const instance = InnerNewJSPromise(); + instance.reactions_or_result = result; + instance.SetStatus(status); + promise_internal::ZeroOutEmbedderOffsets(instance); - extern macro PromiseResolveThenableJobTaskMapConstant(): Map; - - macro NewPromiseResolveThenableJobTask(implicit context: Context)( - promiseToResolve: JSPromise, then: JSReceiver, thenable: JSReceiver, - thenContext: Context): PromiseResolveThenableJobTask { - return new PromiseResolveThenableJobTask{ - map: PromiseResolveThenableJobTaskMapConstant(), - context: thenContext, - promise_to_resolve: promiseToResolve, - then: then, - thenable: thenable - }; + if (IsPromiseHookEnabledOrHasAsyncEventDelegate()) { + runtime::PromiseHookInit(instance, Undefined); } + return instance; +} - struct InvokeThenOneArgFunctor { - transitioning - macro Call( - nativeContext: NativeContext, then: JSAny, receiver: JSAny, arg1: JSAny, - _arg2: JSAny): JSAny { - return Call(nativeContext, then, receiver, arg1); - } - } +macro NewPromiseReaction(implicit context: Context)( + handlerContext: Context, next: Zero|PromiseReaction, + promiseOrCapability: JSPromise|PromiseCapability|Undefined, + fulfillHandler: Callable|Undefined, + rejectHandler: Callable|Undefined): PromiseReaction { + const nativeContext = LoadNativeContext(handlerContext); + return new PromiseReaction{ + map: PromiseReactionMapConstant(), + next: next, + reject_handler: rejectHandler, + fulfill_handler: fulfillHandler, + promise_or_capability: promiseOrCapability, + continuation_preserved_embedder_data: nativeContext + [NativeContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX] + }; +} - struct InvokeThenTwoArgFunctor { - transitioning - macro Call( - nativeContext: NativeContext, then: JSAny, receiver: JSAny, arg1: JSAny, - arg2: JSAny): JSAny { - return Call(nativeContext, then, receiver, arg1, arg2); - } - } +extern macro PromiseResolveThenableJobTaskMapConstant(): Map; - transitioning - macro InvokeThen(implicit context: Context)( - nativeContext: NativeContext, receiver: JSAny, arg1: JSAny, arg2: JSAny, - callFunctor: F): JSAny { - // We can skip the "then" lookup on {receiver} if it's [[Prototype]] - // is the (initial) Promise.prototype and the Promise#then protector - // is intact, as that guards the lookup path for the "then" property - // on JSPromise instances which have the (initial) %PromisePrototype%. - if (!Is(receiver) && - IsPromiseThenLookupChainIntact( - nativeContext, UnsafeCast(receiver).map)) { - const then = UnsafeCast( - nativeContext[NativeContextSlot::PROMISE_THEN_INDEX]); - return callFunctor.Call(nativeContext, then, receiver, arg1, arg2); - } else - deferred { - const then = UnsafeCast(GetProperty(receiver, kThenString)); - return callFunctor.Call(nativeContext, then, receiver, arg1, arg2); - } - } +// https://tc39.es/ecma262/#sec-newpromiseresolvethenablejob +macro NewPromiseResolveThenableJobTask(implicit context: Context)( + promiseToResolve: JSPromise, thenable: JSReceiver, + then: Callable): PromiseResolveThenableJobTask { + // 2. Let getThenRealmResult be GetFunctionRealm(then). + // 3. If getThenRealmResult is a normal completion, then let thenRealm be + // getThenRealmResult.[[Value]]. + // 4. Otherwise, let thenRealm be null. + // + // The only cases where |thenRealm| can be null is when |then| is a revoked + // Proxy object, which would throw when it is called anyway. So instead of + // setting the context to null as the spec does, we just use the current + // realm. + const thenContext: Context = ExtractHandlerContext(then); + const nativeContext = LoadNativeContext(thenContext); + + // 1. Let job be a new Job abstract closure with no parameters that + // captures promiseToResolve, thenable, and then... + // 5. Return { [[Job]]: job, [[Realm]]: thenRealm }. + return new PromiseResolveThenableJobTask{ + map: PromiseResolveThenableJobTaskMapConstant(), + context: nativeContext, + promise_to_resolve: promiseToResolve, + thenable, + then + }; +} +struct InvokeThenOneArgFunctor { transitioning - macro InvokeThen(implicit context: Context)( - nativeContext: NativeContext, receiver: JSAny, arg: JSAny): JSAny { - return InvokeThen( - nativeContext, receiver, arg, Undefined, InvokeThenOneArgFunctor{}); + macro Call( + nativeContext: NativeContext, then: JSAny, receiver: JSAny, arg1: JSAny, + _arg2: JSAny): JSAny { + return Call(nativeContext, then, receiver, arg1); } +} +struct InvokeThenTwoArgFunctor { transitioning - macro InvokeThen(implicit context: Context)( - nativeContext: NativeContext, receiver: JSAny, arg1: JSAny, + macro Call( + nativeContext: NativeContext, then: JSAny, receiver: JSAny, arg1: JSAny, arg2: JSAny): JSAny { - return InvokeThen( - nativeContext, receiver, arg1, arg2, InvokeThenTwoArgFunctor{}); + return Call(nativeContext, then, receiver, arg1, arg2); } +} - transitioning - macro BranchIfAccessCheckFailed(implicit context: Context)( - nativeContext: NativeContext, promiseConstructor: JSAny, - executor: JSAny): void labels IfNoAccess { - try { - // If executor is a bound function, load the bound function until we've - // reached an actual function. - let foundExecutor = executor; - while (true) { - typeswitch (foundExecutor) { - case (f: JSFunction): { - // Load the context from the function and compare it to the Promise - // constructor's context. If they match, everything is fine, - // otherwise, bail out to the runtime. - const functionContext = f.context; - const nativeFunctionContext = LoadNativeContext(functionContext); - if (TaggedEqual(nativeContext, nativeFunctionContext)) { - goto HasAccess; - } else { - goto CallRuntime; - } - } - case (b: JSBoundFunction): { - foundExecutor = b.bound_target_function; - } - case (Object): { +transitioning +macro InvokeThen(implicit context: Context)( + nativeContext: NativeContext, receiver: JSAny, arg1: JSAny, arg2: JSAny, + callFunctor: F): JSAny { + // We can skip the "then" lookup on {receiver} if it's [[Prototype]] + // is the (initial) Promise.prototype and the Promise#then protector + // is intact, as that guards the lookup path for the "then" property + // on JSPromise instances which have the (initial) %PromisePrototype%. + if (!Is(receiver) && + IsPromiseThenLookupChainIntact( + nativeContext, UnsafeCast(receiver).map)) { + const then = + UnsafeCast(nativeContext[NativeContextSlot::PROMISE_THEN_INDEX]); + return callFunctor.Call(nativeContext, then, receiver, arg1, arg2); + } else + deferred { + const then = UnsafeCast(GetProperty(receiver, kThenString)); + return callFunctor.Call(nativeContext, then, receiver, arg1, arg2); + } +} + +transitioning +macro InvokeThen(implicit context: Context)( + nativeContext: NativeContext, receiver: JSAny, arg: JSAny): JSAny { + return InvokeThen( + nativeContext, receiver, arg, Undefined, InvokeThenOneArgFunctor{}); +} + +transitioning +macro InvokeThen(implicit context: Context)( + nativeContext: NativeContext, receiver: JSAny, arg1: JSAny, + arg2: JSAny): JSAny { + return InvokeThen( + nativeContext, receiver, arg1, arg2, InvokeThenTwoArgFunctor{}); +} + +transitioning +macro BranchIfAccessCheckFailed(implicit context: Context)( + nativeContext: NativeContext, promiseConstructor: JSAny, + executor: JSAny): void labels IfNoAccess { + try { + // If executor is a bound function, load the bound function until we've + // reached an actual function. + let foundExecutor = executor; + while (true) { + typeswitch (foundExecutor) { + case (f: JSFunction): { + // Load the context from the function and compare it to the Promise + // constructor's context. If they match, everything is fine, + // otherwise, bail out to the runtime. + const functionContext = f.context; + const nativeFunctionContext = LoadNativeContext(functionContext); + if (TaggedEqual(nativeContext, nativeFunctionContext)) { + goto HasAccess; + } else { goto CallRuntime; } } + case (b: JSBoundFunction): { + foundExecutor = b.bound_target_function; + } + case (Object): { + goto CallRuntime; + } } } - label CallRuntime deferred { - const result = runtime::AllowDynamicFunction(promiseConstructor); - if (result != True) { - goto IfNoAccess; - } + } label CallRuntime deferred { + const result = runtime::AllowDynamicFunction(promiseConstructor); + if (result != True) { + goto IfNoAccess; } - label HasAccess {} - } + } label HasAccess {} +} } diff --git a/deps/v8/src/builtins/promise-race.tq b/deps/v8/src/builtins/promise-race.tq index 7e56a08c8443ad..27d2038398ab4b 100644 --- a/deps/v8/src/builtins/promise-race.tq +++ b/deps/v8/src/builtins/promise-race.tq @@ -6,126 +6,124 @@ namespace promise { - extern macro PromiseForwardingHandlerSymbolConstant(): Symbol; - const kPromiseForwardingHandlerSymbol: Symbol = - PromiseForwardingHandlerSymbolConstant(); - extern macro PromiseHandledBySymbolConstant(): Symbol; - const kPromiseHandledBySymbol: Symbol = PromiseHandledBySymbolConstant(); - extern macro ResolveStringConstant(): String; - const kResolveString: String = ResolveStringConstant(); - extern macro SetPropertyStrict(Context, Object, Object, Object): Object; - extern macro IsPromiseResolveProtectorCellInvalid(): bool; +extern macro PromiseForwardingHandlerSymbolConstant(): Symbol; +const kPromiseForwardingHandlerSymbol: Symbol = + PromiseForwardingHandlerSymbolConstant(); +extern macro PromiseHandledBySymbolConstant(): Symbol; +const kPromiseHandledBySymbol: Symbol = PromiseHandledBySymbolConstant(); +extern macro ResolveStringConstant(): String; +const kResolveString: String = ResolveStringConstant(); +extern macro SetPropertyStrict(Context, Object, Object, Object): Object; +extern macro IsPromiseResolveProtectorCellInvalid(): bool; - macro IsPromiseResolveLookupChainIntact(implicit context: Context)( - nativeContext: NativeContext, constructor: JSReceiver): bool { - if (IsForceSlowPath()) return false; - const promiseFun = UnsafeCast( - nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]); - return promiseFun == constructor && !IsPromiseResolveProtectorCellInvalid(); - } +macro IsPromiseResolveLookupChainIntact(implicit context: Context)( + nativeContext: NativeContext, constructor: JSReceiver): bool { + if (IsForceSlowPath()) return false; + const promiseFun = UnsafeCast( + nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]); + return promiseFun == constructor && !IsPromiseResolveProtectorCellInvalid(); +} - // https://tc39.es/ecma262/#sec-promise.race - transitioning javascript builtin - PromiseRace(js-implicit context: Context, receiver: JSAny)(iterable: JSAny): - JSAny { - const receiver = Cast(receiver) - otherwise ThrowTypeError( - MessageTemplate::kCalledOnNonObject, 'Promise.race'); +// https://tc39.es/ecma262/#sec-promise.race +transitioning javascript builtin +PromiseRace( + js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny { + const receiver = Cast(receiver) + otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.race'); - // Let promiseCapability be ? NewPromiseCapability(C). - // Don't fire debugEvent so that forwarding the rejection through all does - // not trigger redundant ExceptionEvents - const capability = NewPromiseCapability(receiver, False); - const resolve = capability.resolve; - const reject = capability.reject; - const promise = capability.promise; + // Let promiseCapability be ? NewPromiseCapability(C). + // Don't fire debugEvent so that forwarding the rejection through all does + // not trigger redundant ExceptionEvents + const capability = NewPromiseCapability(receiver, False); + const resolve = capability.resolve; + const reject = capability.reject; + const promise = capability.promise; - // For catch prediction, don't treat the .then calls as handling it; - // instead, recurse outwards. - if (IsDebugActive()) deferred { - SetPropertyStrict( - context, reject, kPromiseForwardingHandlerSymbol, True); - } + // For catch prediction, don't treat the .then calls as handling it; + // instead, recurse outwards. + if (IsDebugActive()) deferred { + SetPropertyStrict(context, reject, kPromiseForwardingHandlerSymbol, True); + } + try { + // Let iterator be GetIterator(iterable). + // IfAbruptRejectPromise(iterator, promiseCapability). + let i: iterator::IteratorRecord; try { - // Let iterator be GetIterator(iterable). - // IfAbruptRejectPromise(iterator, promiseCapability). - let i: iterator::IteratorRecord; - try { - i = iterator::GetIterator(iterable); - } catch (e) deferred { - goto Reject(e); - } + i = iterator::GetIterator(iterable); + } catch (e) deferred { + goto Reject(e); + } - // Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability). - try { - // We can skip the "resolve" lookup on {constructor} if it's the - // Promise constructor and the Promise.resolve protector is intact, - // as that guards the lookup path for the "resolve" property on the - // Promise constructor. - const nativeContext = LoadNativeContext(context); - let promiseResolveFunction: JSAny = Undefined; - if (!IsPromiseResolveLookupChainIntact(nativeContext, receiver)) - deferred { - // 3. Let _promiseResolve_ be ? Get(_constructor_, `"resolve"`). - const resolve = GetProperty(receiver, kResolveString); + // Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability). + try { + // We can skip the "resolve" lookup on {constructor} if it's the + // Promise constructor and the Promise.resolve protector is intact, + // as that guards the lookup path for the "resolve" property on the + // Promise constructor. + const nativeContext = LoadNativeContext(context); + let promiseResolveFunction: JSAny = Undefined; + if (!IsPromiseResolveLookupChainIntact(nativeContext, receiver)) + deferred { + // 3. Let _promiseResolve_ be ? Get(_constructor_, `"resolve"`). + const resolve = GetProperty(receiver, kResolveString); - // 4. If IsCallable(_promiseResolve_) is *false*, throw a - // *TypeError* exception. - promiseResolveFunction = Cast(resolve) - otherwise ThrowTypeError( - MessageTemplate::kCalledNonCallable, 'resolve'); - } + // 4. If IsCallable(_promiseResolve_) is *false*, throw a + // *TypeError* exception. + promiseResolveFunction = Cast(resolve) + otherwise ThrowTypeError( + MessageTemplate::kCalledNonCallable, 'resolve'); + } - const fastIteratorResultMap = UnsafeCast( - nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]); - while (true) { - let nextValue: JSAny; - try { - // Let next be IteratorStep(iteratorRecord.[[Iterator]]). - // If next is an abrupt completion, set iteratorRecord.[[Done]] to - // true. ReturnIfAbrupt(next). - const next: JSReceiver = iterator::IteratorStep( - i, fastIteratorResultMap) otherwise return promise; + const fastIteratorResultMap = UnsafeCast( + nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]); + while (true) { + let nextValue: JSAny; + try { + // Let next be IteratorStep(iteratorRecord.[[Iterator]]). + // If next is an abrupt completion, set iteratorRecord.[[Done]] to + // true. ReturnIfAbrupt(next). + const next: JSReceiver = iterator::IteratorStep( + i, fastIteratorResultMap) otherwise return promise; - // Let nextValue be IteratorValue(next). - // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] - // to true. - // ReturnIfAbrupt(nextValue). - nextValue = iterator::IteratorValue(next, fastIteratorResultMap); - } catch (e) { - goto Reject(e); - } - // Let nextPromise be ? Call(constructor, _promiseResolve_, « - // nextValue »). - const nextPromise = CallResolve( - UnsafeCast(receiver), promiseResolveFunction, - nextValue); + // Let nextValue be IteratorValue(next). + // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] + // to true. + // ReturnIfAbrupt(nextValue). + nextValue = iterator::IteratorValue(next, fastIteratorResultMap); + } catch (e) { + goto Reject(e); + } + // Let nextPromise be ? Call(constructor, _promiseResolve_, « + // nextValue »). + const nextPromise = CallResolve( + UnsafeCast(receiver), promiseResolveFunction, + nextValue); - // Perform ? Invoke(nextPromise, "then", « resolveElement, - // resultCapability.[[Reject]] »). - const then = GetProperty(nextPromise, kThenString); - const thenResult = Call( - context, then, nextPromise, UnsafeCast(resolve), - UnsafeCast(reject)); + // Perform ? Invoke(nextPromise, "then", « resolveElement, + // resultCapability.[[Reject]] »). + const then = GetProperty(nextPromise, kThenString); + const thenResult = Call( + context, then, nextPromise, UnsafeCast(resolve), + UnsafeCast(reject)); - // For catch prediction, mark that rejections here are semantically - // handled by the combined Promise. - if (IsDebugActive() && !Is(promise)) deferred { - SetPropertyStrict( - context, thenResult, kPromiseHandledBySymbol, promise); - } - } - } catch (e) deferred { - iterator::IteratorCloseOnException(i, e) otherwise Reject; + // For catch prediction, mark that rejections here are semantically + // handled by the combined Promise. + if (IsDebugActive() && !Is(promise)) deferred { + SetPropertyStrict( + context, thenResult, kPromiseHandledBySymbol, promise); + } } + } catch (e) deferred { + iterator::IteratorCloseOnException(i); + goto Reject(e); } - label Reject(exception: Object) deferred { - Call( - context, UnsafeCast(reject), Undefined, - UnsafeCast(exception)); - return promise; - } - unreachable; + } label Reject(exception: Object) deferred { + Call( + context, UnsafeCast(reject), Undefined, + UnsafeCast(exception)); + return promise; } + unreachable; +} } diff --git a/deps/v8/src/builtins/promise-reaction-job.tq b/deps/v8/src/builtins/promise-reaction-job.tq index f17886c0d18643..1e89da02617dc9 100644 --- a/deps/v8/src/builtins/promise-reaction-job.tq +++ b/deps/v8/src/builtins/promise-reaction-job.tq @@ -6,118 +6,118 @@ namespace promise { - transitioning - macro RejectPromiseReactionJob( - context: Context, - promiseOrCapability: JSPromise|PromiseCapability|Undefined, reason: JSAny, - reactionType: constexpr PromiseReactionType): JSAny { - if constexpr (reactionType == kPromiseReactionReject) { - typeswitch (promiseOrCapability) { - case (promise: JSPromise): { - // For fast native promises we can skip the indirection via the - // promiseCapability.[[Reject]] function and run the resolve logic - // directly from here. - return RejectPromise(promise, reason, False); - } - case (Undefined): { - return Undefined; - } - case (capability: PromiseCapability): { - // In the general case we need to call the (user provided) - // promiseCapability.[[Reject]] function. - const reject = UnsafeCast(capability.reject); - return Call(context, reject, Undefined, reason); - } - } - } else { - StaticAssert(reactionType == kPromiseReactionFulfill); - // We have to call out to the dedicated PromiseRejectReactionJob - // builtin here, instead of just doing the work inline, as otherwise - // the catch predictions in the debugger will be wrong, which just - // walks the stack and checks for certain builtins. - return PromiseRejectReactionJob(reason, Undefined, promiseOrCapability); - } - } - - transitioning - macro FuflfillPromiseReactionJob( - context: Context, - promiseOrCapability: JSPromise|PromiseCapability|Undefined, result: JSAny, - reactionType: constexpr PromiseReactionType): JSAny { +transitioning +macro RejectPromiseReactionJob( + context: Context, + promiseOrCapability: JSPromise|PromiseCapability|Undefined, reason: JSAny, + reactionType: constexpr PromiseReactionType): JSAny { + if constexpr (reactionType == kPromiseReactionReject) { typeswitch (promiseOrCapability) { case (promise: JSPromise): { // For fast native promises we can skip the indirection via the - // promiseCapability.[[Resolve]] function and run the resolve logic + // promiseCapability.[[Reject]] function and run the resolve logic // directly from here. - return ResolvePromise(context, promise, result); + return RejectPromise(promise, reason, False); } case (Undefined): { return Undefined; } case (capability: PromiseCapability): { // In the general case we need to call the (user provided) - // promiseCapability.[[Resolve]] function. - const resolve = UnsafeCast(capability.resolve); - try { - return Call(context, resolve, Undefined, result); - } catch (e) { - return RejectPromiseReactionJob( - context, promiseOrCapability, e, reactionType); - } + // promiseCapability.[[Reject]] function. + const reject = UnsafeCast(capability.reject); + return Call(context, reject, Undefined, reason); } } + } else { + StaticAssert(reactionType == kPromiseReactionFulfill); + // We have to call out to the dedicated PromiseRejectReactionJob + // builtin here, instead of just doing the work inline, as otherwise + // the catch predictions in the debugger will be wrong, which just + // walks the stack and checks for certain builtins. + return PromiseRejectReactionJob(reason, Undefined, promiseOrCapability); } +} - // https://tc39.es/ecma262/#sec-promisereactionjob - transitioning - macro PromiseReactionJob( - context: Context, argument: JSAny, handler: Callable|Undefined, - promiseOrCapability: JSPromise|PromiseCapability|Undefined, - reactionType: constexpr PromiseReactionType): JSAny { - if (handler == Undefined) { - if constexpr (reactionType == kPromiseReactionFulfill) { - return FuflfillPromiseReactionJob( - context, promiseOrCapability, argument, reactionType); - } else { - StaticAssert(reactionType == kPromiseReactionReject); - return RejectPromiseReactionJob( - context, promiseOrCapability, argument, reactionType); - } - } else { +transitioning +macro FuflfillPromiseReactionJob( + context: Context, + promiseOrCapability: JSPromise|PromiseCapability|Undefined, result: JSAny, + reactionType: constexpr PromiseReactionType): JSAny { + typeswitch (promiseOrCapability) { + case (promise: JSPromise): { + // For fast native promises we can skip the indirection via the + // promiseCapability.[[Resolve]] function and run the resolve logic + // directly from here. + return ResolvePromise(context, promise, result); + } + case (Undefined): { + return Undefined; + } + case (capability: PromiseCapability): { + // In the general case we need to call the (user provided) + // promiseCapability.[[Resolve]] function. + const resolve = UnsafeCast(capability.resolve); try { - const result = - Call(context, UnsafeCast(handler), Undefined, argument); - if (promiseOrCapability == Undefined) { - // There's no [[Capability]] for this promise reaction job, which - // means that this is a specification-internal operation (aka - // await) where the result does not matter (see the specification - // change in https://github.com/tc39/ecma262/pull/1146 for - // details). - return Undefined; - } else { - return FuflfillPromiseReactionJob( - context, promiseOrCapability, result, reactionType); - } + return Call(context, resolve, Undefined, result); } catch (e) { return RejectPromiseReactionJob( context, promiseOrCapability, e, reactionType); } } } +} - transitioning builtin - PromiseFulfillReactionJob(implicit context: Context)( - value: JSAny, handler: Callable|Undefined, - promiseOrCapability: JSPromise|PromiseCapability|Undefined): JSAny { - return PromiseReactionJob( - context, value, handler, promiseOrCapability, kPromiseReactionFulfill); +// https://tc39.es/ecma262/#sec-promisereactionjob +transitioning +macro PromiseReactionJob( + context: Context, argument: JSAny, handler: Callable|Undefined, + promiseOrCapability: JSPromise|PromiseCapability|Undefined, + reactionType: constexpr PromiseReactionType): JSAny { + if (handler == Undefined) { + if constexpr (reactionType == kPromiseReactionFulfill) { + return FuflfillPromiseReactionJob( + context, promiseOrCapability, argument, reactionType); + } else { + StaticAssert(reactionType == kPromiseReactionReject); + return RejectPromiseReactionJob( + context, promiseOrCapability, argument, reactionType); + } + } else { + try { + const result = + Call(context, UnsafeCast(handler), Undefined, argument); + if (promiseOrCapability == Undefined) { + // There's no [[Capability]] for this promise reaction job, which + // means that this is a specification-internal operation (aka + // await) where the result does not matter (see the specification + // change in https://github.com/tc39/ecma262/pull/1146 for + // details). + return Undefined; + } else { + return FuflfillPromiseReactionJob( + context, promiseOrCapability, result, reactionType); + } + } catch (e) { + return RejectPromiseReactionJob( + context, promiseOrCapability, e, reactionType); + } } +} - transitioning builtin - PromiseRejectReactionJob(implicit context: Context)( - reason: JSAny, handler: Callable|Undefined, - promiseOrCapability: JSPromise|PromiseCapability|Undefined): JSAny { - return PromiseReactionJob( - context, reason, handler, promiseOrCapability, kPromiseReactionReject); - } +transitioning builtin +PromiseFulfillReactionJob(implicit context: Context)( + value: JSAny, handler: Callable|Undefined, + promiseOrCapability: JSPromise|PromiseCapability|Undefined): JSAny { + return PromiseReactionJob( + context, value, handler, promiseOrCapability, kPromiseReactionFulfill); +} + +transitioning builtin +PromiseRejectReactionJob(implicit context: Context)( + reason: JSAny, handler: Callable|Undefined, + promiseOrCapability: JSPromise|PromiseCapability|Undefined): JSAny { + return PromiseReactionJob( + context, reason, handler, promiseOrCapability, kPromiseReactionReject); +} } diff --git a/deps/v8/src/builtins/promise-resolve.tq b/deps/v8/src/builtins/promise-resolve.tq index 0fc98b556b2297..dbb60720c04416 100644 --- a/deps/v8/src/builtins/promise-resolve.tq +++ b/deps/v8/src/builtins/promise-resolve.tq @@ -5,190 +5,180 @@ #include 'src/builtins/builtins-promise-gen.h' namespace runtime { - extern transitioning runtime - ResolvePromise(implicit context: Context)(JSPromise, JSAny): JSAny; +extern transitioning runtime +ResolvePromise(implicit context: Context)(JSPromise, JSAny): JSAny; } namespace promise { - extern macro ConstructorStringConstant(): String; - const kConstructorString: String = ConstructorStringConstant(); - - // https://tc39.es/ecma262/#sec-promise.resolve - transitioning javascript builtin - PromiseResolveTrampoline(js-implicit context: NativeContext, receiver: JSAny)( - value: JSAny): JSAny { - // 1. Let C be the this value. - // 2. If Type(C) is not Object, throw a TypeError exception. - const receiver = Cast(receiver) otherwise - ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'PromiseResolve'); - - // 3. Return ? PromiseResolve(C, x). - return PromiseResolve(receiver, value); - } - - transitioning builtin - PromiseResolve(implicit context: - Context)(constructor: JSReceiver, value: JSAny): JSAny { - const nativeContext = LoadNativeContext(context); - const promiseFun = nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]; - try { - // Check if {value} is a JSPromise. - const value = Cast(value) otherwise NeedToAllocate; - - // We can skip the "constructor" lookup on {value} if it's [[Prototype]] - // is the (initial) Promise.prototype and the @@species protector is - // intact, as that guards the lookup path for "constructor" on - // JSPromise instances which have the (initial) Promise.prototype. - const promisePrototype = - nativeContext[NativeContextSlot::PROMISE_PROTOTYPE_INDEX]; - if (value.map.prototype != promisePrototype) { - goto SlowConstructor; - } - - if (IsPromiseSpeciesProtectorCellInvalid()) goto SlowConstructor; +extern macro ConstructorStringConstant(): String; +const kConstructorString: String = ConstructorStringConstant(); + +// https://tc39.es/ecma262/#sec-promise.resolve +transitioning javascript builtin +PromiseResolveTrampoline( + js-implicit context: NativeContext, receiver: JSAny)(value: JSAny): JSAny { + // 1. Let C be the this value. + // 2. If Type(C) is not Object, throw a TypeError exception. + const receiver = Cast(receiver) otherwise + ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'PromiseResolve'); + + // 3. Return ? PromiseResolve(C, x). + return PromiseResolve(receiver, value); +} - // If the {constructor} is the Promise function, we just immediately - // return the {value} here and don't bother wrapping it into a - // native Promise. - if (promiseFun != constructor) goto SlowConstructor; - return value; - } - label SlowConstructor deferred { - // At this point, value or/and constructor are not native promises, but - // they could be of the same subclass. - const valueConstructor = GetProperty(value, kConstructorString); - if (valueConstructor != constructor) goto NeedToAllocate; - return value; - } - label NeedToAllocate { - if (promiseFun == constructor) { - // This adds a fast path for native promises that don't need to - // create NewPromiseCapability. - const result = NewJSPromise(); - ResolvePromise(context, result, value); - return result; - } else - deferred { - const capability = NewPromiseCapability(constructor, True); - const resolve = UnsafeCast(capability.resolve); - Call(context, resolve, Undefined, value); - return capability.promise; - } +transitioning builtin +PromiseResolve(implicit context: Context)( + constructor: JSReceiver, value: JSAny): JSAny { + const nativeContext = LoadNativeContext(context); + const promiseFun = nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]; + try { + // Check if {value} is a JSPromise. + const value = Cast(value) otherwise NeedToAllocate; + + // We can skip the "constructor" lookup on {value} if it's [[Prototype]] + // is the (initial) Promise.prototype and the @@species protector is + // intact, as that guards the lookup path for "constructor" on + // JSPromise instances which have the (initial) Promise.prototype. + const promisePrototype = + nativeContext[NativeContextSlot::PROMISE_PROTOTYPE_INDEX]; + if (value.map.prototype != promisePrototype) { + goto SlowConstructor; } - } - - extern macro IsJSReceiverMap(Map): bool; - extern macro IsPromiseThenProtectorCellInvalid(): bool; - - extern macro ThenStringConstant(): String; - - const kThenString: String = ThenStringConstant(); - - transitioning builtin - ResolvePromise(implicit context: - Context)(promise: JSPromise, resolution: JSAny): JSAny { - // 6. If SameValue(resolution, promise) is true, then - // If promise hook is enabled or the debugger is active, let - // the runtime handle this operation, which greatly reduces - // the complexity here and also avoids a couple of back and - // forth between JavaScript and C++ land. - // We also let the runtime handle it if promise == resolution. - // We can use pointer comparison here, since the {promise} is guaranteed - // to be a JSPromise inside this function and thus is reference comparable. - if (IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() || - TaggedEqual(promise, resolution)) + if (IsPromiseSpeciesProtectorCellInvalid()) goto SlowConstructor; + + // If the {constructor} is the Promise function, we just immediately + // return the {value} here and don't bother wrapping it into a + // native Promise. + if (promiseFun != constructor) goto SlowConstructor; + return value; + } label SlowConstructor deferred { + // At this point, value or/and constructor are not native promises, but + // they could be of the same subclass. + const valueConstructor = GetProperty(value, kConstructorString); + if (valueConstructor != constructor) goto NeedToAllocate; + return value; + } label NeedToAllocate { + if (promiseFun == constructor) { + // This adds a fast path for native promises that don't need to + // create NewPromiseCapability. + const result = NewJSPromise(); + ResolvePromise(context, result, value); + return result; + } else deferred { - return runtime::ResolvePromise(promise, resolution); - } - - let then: Object = Undefined; - try { - // 7. If Type(resolution) is not Object, then - // 7.b Return FulfillPromise(promise, resolution). - if (TaggedIsSmi(resolution)) { - return FulfillPromise(promise, resolution); + const capability = NewPromiseCapability(constructor, True); + const resolve = UnsafeCast(capability.resolve); + Call(context, resolve, Undefined, value); + return capability.promise; } + } +} - const heapResolution = UnsafeCast(resolution); - const resolutionMap = heapResolution.map; - if (!IsJSReceiverMap(resolutionMap)) { - return FulfillPromise(promise, resolution); - } +extern macro IsJSReceiverMap(Map): bool; + +extern macro IsPromiseThenProtectorCellInvalid(): bool; + +extern macro ThenStringConstant(): String; + +const kThenString: String = ThenStringConstant(); + +// https://tc39.es/ecma262/#sec-promise-resolve-functions +transitioning builtin +ResolvePromise(implicit context: Context)( + promise: JSPromise, resolution: JSAny): JSAny { + // 7. If SameValue(resolution, promise) is true, then + // If promise hook is enabled or the debugger is active, let + // the runtime handle this operation, which greatly reduces + // the complexity here and also avoids a couple of back and + // forth between JavaScript and C++ land. + // We also let the runtime handle it if promise == resolution. + // We can use pointer comparison here, since the {promise} is guaranteed + // to be a JSPromise inside this function and thus is reference comparable. + if (IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() || + TaggedEqual(promise, resolution)) + deferred { + return runtime::ResolvePromise(promise, resolution); + } - // We can skip the "then" lookup on {resolution} if its [[Prototype]] - // is the (initial) Promise.prototype and the Promise#then protector - // is intact, as that guards the lookup path for the "then" property - // on JSPromise instances which have the (initial) %PromisePrototype%. - if (IsForceSlowPath()) { - goto Slow; - } + let then: Object = Undefined; + try { + // 8. If Type(resolution) is not Object, then + // 8.a Return FulfillPromise(promise, resolution). + if (TaggedIsSmi(resolution)) { + return FulfillPromise(promise, resolution); + } - if (IsPromiseThenProtectorCellInvalid()) { - goto Slow; - } + const heapResolution = UnsafeCast(resolution); + const resolutionMap = heapResolution.map; + if (!IsJSReceiverMap(resolutionMap)) { + return FulfillPromise(promise, resolution); + } - const nativeContext = LoadNativeContext(context); - if (!IsJSPromiseMap(resolutionMap)) { - // We can skip the lookup of "then" if the {resolution} is a (newly - // created) IterResultObject, as the Promise#then() protector also - // ensures that the intrinsic %ObjectPrototype% doesn't contain any - // "then" property. This helps to avoid negative lookups on iterator - // results from async generators. - assert(IsJSReceiverMap(resolutionMap)); - assert(!IsPromiseThenProtectorCellInvalid()); - if (resolutionMap == - nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]) { - return FulfillPromise(promise, resolution); - } else { - goto Slow; - } - } + // We can skip the "then" lookup on {resolution} if its [[Prototype]] + // is the (initial) Promise.prototype and the Promise#then protector + // is intact, as that guards the lookup path for the "then" property + // on JSPromise instances which have the (initial) %PromisePrototype%. + if (IsForceSlowPath()) { + goto Slow; + } - const promisePrototype = - nativeContext[NativeContextSlot::PROMISE_PROTOTYPE_INDEX]; - if (resolutionMap.prototype == promisePrototype) { - // The {resolution} is a native Promise in this case. - then = nativeContext[NativeContextSlot::PROMISE_THEN_INDEX]; - goto Enqueue; - } + if (IsPromiseThenProtectorCellInvalid()) { goto Slow; } - label Slow deferred { - // 8. Let then be Get(resolution, "then"). - // 9. If then is an abrupt completion, then - // 9.a Return RejectPromise(promise, then.[[Value]]). - try { - then = GetProperty(resolution, kThenString); - } catch (e) { - return RejectPromise(promise, e, False); - } - // 11. If IsCallable(thenAction) is false, then - if (TaggedIsSmi(then)) { + const nativeContext = LoadNativeContext(context); + if (!IsJSPromiseMap(resolutionMap)) { + // We can skip the lookup of "then" if the {resolution} is a (newly + // created) IterResultObject, as the Promise#then() protector also + // ensures that the intrinsic %ObjectPrototype% doesn't contain any + // "then" property. This helps to avoid negative lookups on iterator + // results from async generators. + assert(IsJSReceiverMap(resolutionMap)); + assert(!IsPromiseThenProtectorCellInvalid()); + if (resolutionMap == + nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]) { return FulfillPromise(promise, resolution); + } else { + goto Slow; } + } - if (!IsCallable(UnsafeCast(then))) { - return FulfillPromise(promise, resolution); - } + const promisePrototype = + nativeContext[NativeContextSlot::PROMISE_PROTOTYPE_INDEX]; + if (resolutionMap.prototype == promisePrototype) { + // The {resolution} is a native Promise in this case. + then = nativeContext[NativeContextSlot::PROMISE_THEN_INDEX]; goto Enqueue; } - label Enqueue { - // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob, - // «promise, resolution, thenAction»). - - // According to HTML, we use the context of the then function - // (|thenAction|) as the context of the microtask. See step 3 of HTML's - // EnqueueJob: - // https://html.spec.whatwg.org/C/#enqueuejob(queuename,-job,-arguments) - const thenContext: Context = - ExtractHandlerContext(UnsafeCast(then)); - const nativeContext = LoadNativeContext(thenContext); - const task = NewPromiseResolveThenableJobTask( - promise, UnsafeCast(then), - UnsafeCast(resolution), nativeContext); - return EnqueueMicrotask(nativeContext, task); + goto Slow; + } label Slow deferred { + // 9. Let then be Get(resolution, "then"). + // 10. If then is an abrupt completion, then + try { + then = GetProperty(resolution, kThenString); + } catch (e) { + // a. Return RejectPromise(promise, then.[[Value]]). + return RejectPromise(promise, e, False); } + + // 11. Let thenAction be then.[[Value]]. + // 12. If IsCallable(thenAction) is false, then + if (!Is(then)) { + // a. Return FulfillPromise(promise, resolution). + return FulfillPromise(promise, resolution); + } + goto Enqueue; + } label Enqueue { + // 13. Let job be NewPromiseResolveThenableJob(promise, resolution, + // thenAction). + const task = NewPromiseResolveThenableJobTask( + promise, UnsafeCast(resolution), + UnsafeCast(then)); + + // 14. Perform HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]). + // 15. Return undefined. + return EnqueueMicrotask(task.context, task); } } +} diff --git a/deps/v8/src/builtins/promise-then.tq b/deps/v8/src/builtins/promise-then.tq index 45f8fd0c81f6d0..3de6d277d840ca 100644 --- a/deps/v8/src/builtins/promise-then.tq +++ b/deps/v8/src/builtins/promise-then.tq @@ -6,74 +6,69 @@ namespace promise { - macro - IsPromiseSpeciesLookupChainIntact( - nativeContext: NativeContext, promiseMap: Map): bool { - const promisePrototype = - nativeContext[NativeContextSlot::PROMISE_PROTOTYPE_INDEX]; - if (IsForceSlowPath()) return false; - if (promiseMap.prototype != promisePrototype) return false; - return !IsPromiseSpeciesProtectorCellInvalid(); - } - - // https://tc39.es/ecma262/#sec-promise.prototype.then - transitioning javascript builtin - PromisePrototypeThen(js-implicit context: NativeContext, receiver: JSAny)( - onFulfilled: JSAny, onRejected: JSAny): JSAny { - // 1. Let promise be the this value. - // 2. If IsPromise(promise) is false, throw a TypeError exception. - const promise = Cast(receiver) otherwise ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, 'Promise.prototype.then', - receiver); +macro +IsPromiseSpeciesLookupChainIntact( + nativeContext: NativeContext, promiseMap: Map): bool { + const promisePrototype = + nativeContext[NativeContextSlot::PROMISE_PROTOTYPE_INDEX]; + if (IsForceSlowPath()) return false; + if (promiseMap.prototype != promisePrototype) return false; + return !IsPromiseSpeciesProtectorCellInvalid(); +} - // 3. Let C be ? SpeciesConstructor(promise, %Promise%). - const promiseFun = UnsafeCast( - context[NativeContextSlot::PROMISE_FUNCTION_INDEX]); +// https://tc39.es/ecma262/#sec-promise.prototype.then +transitioning javascript builtin +PromisePrototypeThen(js-implicit context: NativeContext, receiver: JSAny)( + onFulfilled: JSAny, onRejected: JSAny): JSAny { + // 1. Let promise be the this value. + // 2. If IsPromise(promise) is false, throw a TypeError exception. + const promise = Cast(receiver) otherwise ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, 'Promise.prototype.then', + receiver); - // 4. Let resultCapability be ? NewPromiseCapability(C). - let resultPromiseOrCapability: JSPromise|PromiseCapability; - let resultPromise: JSAny; - try { - if (IsPromiseSpeciesLookupChainIntact(context, promise.map)) { - goto AllocateAndInit; - } + // 3. Let C be ? SpeciesConstructor(promise, %Promise%). + const promiseFun = UnsafeCast( + context[NativeContextSlot::PROMISE_FUNCTION_INDEX]); - const constructor = SpeciesConstructor(promise, promiseFun); - if (TaggedEqual(constructor, promiseFun)) { - goto AllocateAndInit; - } else { - const promiseCapability = NewPromiseCapability(constructor, True); - resultPromiseOrCapability = promiseCapability; - resultPromise = promiseCapability.promise; - } + // 4. Let resultCapability be ? NewPromiseCapability(C). + let resultPromiseOrCapability: JSPromise|PromiseCapability; + let resultPromise: JSAny; + try { + if (IsPromiseSpeciesLookupChainIntact(context, promise.map)) { + goto AllocateAndInit; } - label AllocateAndInit { - const resultJSPromise = NewJSPromise(promise); - resultPromiseOrCapability = resultJSPromise; - resultPromise = resultJSPromise; + + const constructor = SpeciesConstructor(promise, promiseFun); + if (TaggedEqual(constructor, promiseFun)) { + goto AllocateAndInit; + } else { + const promiseCapability = NewPromiseCapability(constructor, True); + resultPromiseOrCapability = promiseCapability; + resultPromise = promiseCapability.promise; } + } label AllocateAndInit { + const resultJSPromise = NewJSPromise(promise); + resultPromiseOrCapability = resultJSPromise; + resultPromise = resultJSPromise; + } - // We do some work of the PerformPromiseThen operation here, in that - // we check the handlers and turn non-callable handlers into undefined. - // This is because this is the one and only callsite of PerformPromiseThen - // that has to do this. + // We do some work of the PerformPromiseThen operation here, in that + // we check the handlers and turn non-callable handlers into undefined. + // This is because this is the one and only callsite of PerformPromiseThen + // that has to do this. - // 3. If IsCallable(onFulfilled) is false, then - // a. Set onFulfilled to undefined. - const onFulfilled = TaggedIsCallable(onFulfilled) ? - UnsafeCast(onFulfilled) : - Undefined; + // 3. If IsCallable(onFulfilled) is false, then + // a. Set onFulfilled to undefined. + const onFulfilled = CastOrDefault(onFulfilled, Undefined); - // 4. If IsCallable(onRejected) is false, then - // a. Set onRejected to undefined. - const onRejected = TaggedIsCallable(onRejected) ? - UnsafeCast(onRejected) : - Undefined; + // 4. If IsCallable(onRejected) is false, then + // a. Set onRejected to undefined. + const onRejected = CastOrDefault(onRejected, Undefined); - // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, - // resultCapability). - PerformPromiseThenImpl( - promise, onFulfilled, onRejected, resultPromiseOrCapability); - return resultPromise; - } + // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, + // resultCapability). + PerformPromiseThenImpl( + promise, onFulfilled, onRejected, resultPromiseOrCapability); + return resultPromise; +} } diff --git a/deps/v8/src/builtins/proxy-constructor.tq b/deps/v8/src/builtins/proxy-constructor.tq index ef886e4f2878c2..ea31ff6db87fd4 100644 --- a/deps/v8/src/builtins/proxy-constructor.tq +++ b/deps/v8/src/builtins/proxy-constructor.tq @@ -6,55 +6,40 @@ namespace proxy { - // ES #sec-proxy-constructor - // https://tc39.github.io/ecma262/#sec-proxy-constructor - transitioning javascript builtin - ProxyConstructor( - js-implicit context: NativeContext, receiver: JSAny, - newTarget: JSAny)(target: JSAny, handler: JSAny): JSProxy { - try { - // 1. If NewTarget is undefined, throw a TypeError exception. - if (newTarget == Undefined) { - ThrowTypeError(MessageTemplate::kConstructorNotFunction, 'Proxy'); - } - - // 2. Return ? ProxyCreate(target, handler). - // https://tc39.github.io/ecma262/#sec-proxycreate - // 1. If Type(target) is not Object, throw a TypeError exception. - // 2. If target is a Proxy exotic object and target.[[ProxyHandler]] is - // null, throw a TypeError exception. - // 3. If Type(handler) is not Object, throw a TypeError exception. - // 4. If handler is a Proxy exotic object and handler.[[ProxyHandler]] - // is null, throw a TypeError exception. - const targetJSReceiver = - Cast(target) otherwise ThrowProxyNonObject; - if (IsRevokedProxy(targetJSReceiver)) { - goto ThrowProxyHandlerOrTargetRevoked; - } +// ES #sec-proxy-constructor +// https://tc39.github.io/ecma262/#sec-proxy-constructor +transitioning javascript builtin +ProxyConstructor( + js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny)( + target: JSAny, handler: JSAny): JSProxy { + try { + // 1. If NewTarget is undefined, throw a TypeError exception. + if (newTarget == Undefined) { + ThrowTypeError(MessageTemplate::kConstructorNotFunction, 'Proxy'); + } - const handlerJSReceiver = - Cast(handler) otherwise ThrowProxyNonObject; - if (IsRevokedProxy(handlerJSReceiver)) { - goto ThrowProxyHandlerOrTargetRevoked; - } + // 2. Return ? ProxyCreate(target, handler). + // https://tc39.github.io/ecma262/#sec-proxycreate + // 1. If Type(target) is not Object, throw a TypeError exception. + // 2. If Type(handler) is not Object, throw a TypeError exception. + const targetJSReceiver = + Cast(target) otherwise ThrowProxyNonObject; + const handlerJSReceiver = + Cast(handler) otherwise ThrowProxyNonObject; - // 5. Let P be a newly created object. - // 6. Set P's essential internal methods (except for [[Call]] and - // [[Construct]]) to the definitions specified in 9.5. - // 7. If IsCallable(target) is true, then - // a. Set P.[[Call]] as specified in 9.5.12. - // b. If IsConstructor(target) is true, then - // 1. Set P.[[Construct]] as specified in 9.5.13. - // 8. Set P.[[ProxyTarget]] to target. - // 9. Set P.[[ProxyHandler]] to handler. - // 10. Return P. - return AllocateProxy(targetJSReceiver, handlerJSReceiver); - } - label ThrowProxyNonObject deferred { - ThrowTypeError(MessageTemplate::kProxyNonObject); - } - label ThrowProxyHandlerOrTargetRevoked deferred { - ThrowTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked); - } + // 5. Let P be a newly created object. + // 6. Set P's essential internal methods (except for [[Call]] and + // [[Construct]]) to the definitions specified in 9.5. + // 7. If IsCallable(target) is true, then + // a. Set P.[[Call]] as specified in 9.5.12. + // b. If IsConstructor(target) is true, then + // 1. Set P.[[Construct]] as specified in 9.5.13. + // 8. Set P.[[ProxyTarget]] to target. + // 9. Set P.[[ProxyHandler]] to handler. + // 10. Return P. + return AllocateProxy(targetJSReceiver, handlerJSReceiver); + } label ThrowProxyNonObject deferred { + ThrowTypeError(MessageTemplate::kProxyNonObject); } } +} diff --git a/deps/v8/src/builtins/proxy-delete-property.tq b/deps/v8/src/builtins/proxy-delete-property.tq index b068f3afb1a19b..45914a6ed55950 100644 --- a/deps/v8/src/builtins/proxy-delete-property.tq +++ b/deps/v8/src/builtins/proxy-delete-property.tq @@ -6,66 +6,64 @@ namespace proxy { - // ES #sec-proxy-object-internal-methods-and-internal-slots-delete-p - // https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-delete-p - transitioning builtin - ProxyDeleteProperty(implicit context: Context)( - proxy: JSProxy, name: PropertyKey, languageMode: LanguageModeSmi): JSAny { - const kTrapName: constexpr string = 'deleteProperty'; - // Handle deeply nested proxy. - PerformStackCheck(); - // 1. Assert: IsPropertyKey(P) is true. - assert(TaggedIsNotSmi(name)); - assert(IsName(name)); - assert(!IsPrivateSymbol(name)); +// ES #sec-proxy-object-internal-methods-and-internal-slots-delete-p +// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-delete-p +transitioning builtin +ProxyDeleteProperty(implicit context: Context)( + proxy: JSProxy, name: PropertyKey, languageMode: LanguageModeSmi): JSAny { + const kTrapName: constexpr string = 'deleteProperty'; + // Handle deeply nested proxy. + PerformStackCheck(); + // 1. Assert: IsPropertyKey(P) is true. + assert(TaggedIsNotSmi(name)); + assert(IsName(name)); + assert(!IsPrivateSymbol(name)); - try { - // 2. Let handler be O.[[ProxyHandler]]. - // 3. If handler is null, throw a TypeError exception. - // 4. Assert: Type(handler) is Object. - assert(proxy.handler == Null || Is(proxy.handler)); - const handler = - Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; + try { + // 2. Let handler be O.[[ProxyHandler]]. + // 3. If handler is null, throw a TypeError exception. + // 4. Assert: Type(handler) is Object. + assert(proxy.handler == Null || Is(proxy.handler)); + const handler = + Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; - // 5. Let target be O.[[ProxyTarget]]. - const target = UnsafeCast(proxy.target); + // 5. Let target be O.[[ProxyTarget]]. + const target = UnsafeCast(proxy.target); - // 6. Let trap be ? GetMethod(handler, "deleteProperty"). - // 7. If trap is undefined, then (see 7.a below). - const trap: Callable = GetMethod(handler, kTrapName) - otherwise goto TrapUndefined(target); + // 6. Let trap be ? GetMethod(handler, "deleteProperty"). + // 7. If trap is undefined, then (see 7.a below). + const trap: Callable = GetMethod(handler, kTrapName) + otherwise goto TrapUndefined(target); - // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, - // « target, P »)). - const trapResult = Call(context, trap, handler, target, name); + // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, + // « target, P »)). + const trapResult = Call(context, trap, handler, target, name); - // 9. If booleanTrapResult is false, return false. - if (!ToBoolean(trapResult)) { - const strictValue: LanguageModeSmi = LanguageMode::kStrict; - if (languageMode == strictValue) { - ThrowTypeError( - MessageTemplate::kProxyTrapReturnedFalsishFor, kTrapName, name); - } - return False; + // 9. If booleanTrapResult is false, return false. + if (!ToBoolean(trapResult)) { + const strictValue: LanguageModeSmi = LanguageMode::kStrict; + if (languageMode == strictValue) { + ThrowTypeError( + MessageTemplate::kProxyTrapReturnedFalsishFor, kTrapName, name); } + return False; + } - // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). - // 11. If targetDesc is undefined, return true. - // 12. If targetDesc.[[Configurable]] is false, throw a TypeError - // exception. - // 13. Let extensibleTarget be ? IsExtensible(target). - // 14. If extensibleTarget is false, throw a TypeError exception. - CheckDeleteTrapResult(target, proxy, name); + // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). + // 11. If targetDesc is undefined, return true. + // 12. If targetDesc.[[Configurable]] is false, throw a TypeError + // exception. + // 13. Let extensibleTarget be ? IsExtensible(target). + // 14. If extensibleTarget is false, throw a TypeError exception. + CheckDeleteTrapResult(target, proxy, name); - // 15. Return true. - return True; - } - label TrapUndefined(target: JSAny) { - // 7.a. Return ? target.[[Delete]](P). - return DeleteProperty(target, name, languageMode); - } - label ThrowProxyHandlerRevoked deferred { - ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName); - } + // 15. Return true. + return True; + } label TrapUndefined(target: JSAny) { + // 7.a. Return ? target.[[Delete]](P). + return DeleteProperty(target, name, languageMode); + } label ThrowProxyHandlerRevoked deferred { + ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName); } } +} diff --git a/deps/v8/src/builtins/proxy-get-property.tq b/deps/v8/src/builtins/proxy-get-property.tq index 7138648a851d4e..2d6a1edee68869 100644 --- a/deps/v8/src/builtins/proxy-get-property.tq +++ b/deps/v8/src/builtins/proxy-get-property.tq @@ -6,60 +6,59 @@ namespace proxy { - extern transitioning builtin GetPropertyWithReceiver( - implicit context: Context)(JSAny, Name, JSAny, Smi): JSAny; +extern transitioning builtin GetPropertyWithReceiver(implicit context: Context)( + JSAny, Name, JSAny, Smi): JSAny; - // ES #sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver - // https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver - transitioning builtin - ProxyGetProperty(implicit context: Context)( - proxy: JSProxy, name: PropertyKey, receiverValue: JSAny, - onNonExistent: Smi): JSAny { - PerformStackCheck(); - // 1. Assert: IsPropertyKey(P) is true. - assert(TaggedIsNotSmi(name)); - assert(IsName(name)); - assert(!IsPrivateSymbol(name)); +// ES #sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver +// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver +transitioning builtin +ProxyGetProperty(implicit context: Context)( + proxy: JSProxy, name: PropertyKey, receiverValue: JSAny, + onNonExistent: Smi): JSAny { + PerformStackCheck(); + // 1. Assert: IsPropertyKey(P) is true. + assert(TaggedIsNotSmi(name)); + assert(IsName(name)); + assert(!IsPrivateSymbol(name)); - // 2. Let handler be O.[[ProxyHandler]]. - // 3. If handler is null, throw a TypeError exception. - // 4. Assert: Type(handler) is Object. - let handler: JSReceiver; - typeswitch (proxy.handler) { - case (Null): { - ThrowTypeError(MessageTemplate::kProxyRevoked, 'get'); - } - case (h: JSReceiver): { - handler = h; - } + // 2. Let handler be O.[[ProxyHandler]]. + // 3. If handler is null, throw a TypeError exception. + // 4. Assert: Type(handler) is Object. + let handler: JSReceiver; + typeswitch (proxy.handler) { + case (Null): { + ThrowTypeError(MessageTemplate::kProxyRevoked, 'get'); } + case (h: JSReceiver): { + handler = h; + } + } - // 5. Let target be O.[[ProxyTarget]]. - const target = Cast(proxy.target) otherwise unreachable; + // 5. Let target be O.[[ProxyTarget]]. + const target = Cast(proxy.target) otherwise unreachable; - // 6. Let trap be ? GetMethod(handler, "get"). - // 7. If trap is undefined, then (see 7.a below). - // 7.a. Return ? target.[[Get]](P, Receiver). - const trap: Callable = GetMethod(handler, 'get') - otherwise return GetPropertyWithReceiver( - target, name, receiverValue, onNonExistent); + // 6. Let trap be ? GetMethod(handler, "get"). + // 7. If trap is undefined, then (see 7.a below). + // 7.a. Return ? target.[[Get]](P, Receiver). + const trap: Callable = GetMethod(handler, 'get') + otherwise return GetPropertyWithReceiver( + target, name, receiverValue, onNonExistent); - // 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »). - const trapResult = - Call(context, trap, handler, target, name, receiverValue); + // 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »). + const trapResult = Call(context, trap, handler, target, name, receiverValue); - // 9. Let targetDesc be ? target.[[GetOwnProperty]](P). - // 10. If targetDesc is not undefined and targetDesc.[[Configurable]] is - // false, then - // a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] - // is false, then - // i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a - // TypeError exception. - // b. If IsAccessorDescriptor(targetDesc) is true and targetDesc.[[Get]] - // is undefined, then - // i. If trapResult is not undefined, throw a TypeError exception. - // 11. Return trapResult. - CheckGetSetTrapResult(target, proxy, name, trapResult, kProxyGet); - return trapResult; - } + // 9. Let targetDesc be ? target.[[GetOwnProperty]](P). + // 10. If targetDesc is not undefined and targetDesc.[[Configurable]] is + // false, then + // a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] + // is false, then + // i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a + // TypeError exception. + // b. If IsAccessorDescriptor(targetDesc) is true and targetDesc.[[Get]] + // is undefined, then + // i. If trapResult is not undefined, throw a TypeError exception. + // 11. Return trapResult. + CheckGetSetTrapResult(target, proxy, name, trapResult, kProxyGet); + return trapResult; +} } diff --git a/deps/v8/src/builtins/proxy-get-prototype-of.tq b/deps/v8/src/builtins/proxy-get-prototype-of.tq index 8c556e27c2bf45..152489ecb6a25a 100644 --- a/deps/v8/src/builtins/proxy-get-prototype-of.tq +++ b/deps/v8/src/builtins/proxy-get-prototype-of.tq @@ -6,65 +6,62 @@ namespace proxy { - // ES #sec-proxy-object-internal-methods-and-internal-slots-isextensible - // https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-isextensible - transitioning builtin - ProxyGetPrototypeOf(implicit context: Context)(proxy: JSProxy): JSAny { - PerformStackCheck(); - const kTrapName: constexpr string = 'getPrototypeOf'; - try { - // 1. Let handler be O.[[ProxyHandler]]. - // 2. If handler is null, throw a TypeError exception. - // 3. Assert: Type(handler) is Object. - assert(proxy.handler == Null || Is(proxy.handler)); - const handler = - Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; +// ES #sec-proxy-object-internal-methods-and-internal-slots-isextensible +// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-isextensible +transitioning builtin +ProxyGetPrototypeOf(implicit context: Context)(proxy: JSProxy): JSAny { + PerformStackCheck(); + const kTrapName: constexpr string = 'getPrototypeOf'; + try { + // 1. Let handler be O.[[ProxyHandler]]. + // 2. If handler is null, throw a TypeError exception. + // 3. Assert: Type(handler) is Object. + assert(proxy.handler == Null || Is(proxy.handler)); + const handler = + Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; - // 4. Let target be O.[[ProxyTarget]]. - const target = proxy.target; + // 4. Let target be O.[[ProxyTarget]]. + const target = proxy.target; - // 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). - // 6. If trap is undefined, then (see 6.a below). - const trap: Callable = GetMethod(handler, kTrapName) - otherwise goto TrapUndefined(target); + // 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). + // 6. If trap is undefined, then (see 6.a below). + const trap: Callable = GetMethod(handler, kTrapName) + otherwise goto TrapUndefined(target); - // 7. Let handlerProto be ? Call(trap, handler, « target »). - const handlerProto = Call(context, trap, handler, target); + // 7. Let handlerProto be ? Call(trap, handler, « target »). + const handlerProto = Call(context, trap, handler, target); - // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError - // exception. - if (!Is(handlerProto) && handlerProto != Null) { - goto ThrowProxyGetPrototypeOfInvalid; - } + // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError + // exception. + if (!Is(handlerProto) && handlerProto != Null) { + goto ThrowProxyGetPrototypeOfInvalid; + } - // 9. Let extensibleTarget be ? IsExtensible(target). - // 10. If extensibleTarget is true, return handlerProto. - const extensibleTarget: JSAny = object::ObjectIsExtensibleImpl(target); - assert(extensibleTarget == True || extensibleTarget == False); - if (extensibleTarget == True) { - return handlerProto; - } + // 9. Let extensibleTarget be ? IsExtensible(target). + // 10. If extensibleTarget is true, return handlerProto. + const extensibleTarget: JSAny = object::ObjectIsExtensibleImpl(target); + assert(extensibleTarget == True || extensibleTarget == False); + if (extensibleTarget == True) { + return handlerProto; + } - // 11. Let targetProto be ? target.[[GetPrototypeOf]](). - const targetProto = object::ObjectGetPrototypeOfImpl(target); + // 11. Let targetProto be ? target.[[GetPrototypeOf]](). + const targetProto = object::ObjectGetPrototypeOfImpl(target); - // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError - // exception. - // 13. Return handlerProto. - if (SameValue(targetProto, handlerProto)) { - return handlerProto; - } - ThrowTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible); - } - label TrapUndefined(target: JSAny) { - // 6.a. Return ? target.[[GetPrototypeOf]](). - return object::ObjectGetPrototypeOfImpl(target); - } - label ThrowProxyHandlerRevoked deferred { - ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName); - } - label ThrowProxyGetPrototypeOfInvalid deferred { - ThrowTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid); + // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError + // exception. + // 13. Return handlerProto. + if (SameValue(targetProto, handlerProto)) { + return handlerProto; } + ThrowTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible); + } label TrapUndefined(target: JSAny) { + // 6.a. Return ? target.[[GetPrototypeOf]](). + return object::ObjectGetPrototypeOfImpl(target); + } label ThrowProxyHandlerRevoked deferred { + ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName); + } label ThrowProxyGetPrototypeOfInvalid deferred { + ThrowTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid); } } +} diff --git a/deps/v8/src/builtins/proxy-has-property.tq b/deps/v8/src/builtins/proxy-has-property.tq index 286314666714dd..488f6fabb31cc6 100644 --- a/deps/v8/src/builtins/proxy-has-property.tq +++ b/deps/v8/src/builtins/proxy-has-property.tq @@ -6,52 +6,50 @@ namespace proxy { - // ES #sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p - // https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p - transitioning builtin ProxyHasProperty(implicit context: Context)( - proxy: JSProxy, name: PropertyKey): JSAny { - assert(IsJSProxy(proxy)); - - PerformStackCheck(); - - // 1. Assert: IsPropertyKey(P) is true. - assert(IsName(name)); - assert(!IsPrivateSymbol(name)); - - try { - // 2. Let handler be O.[[ProxyHandler]]. - // 3. If handler is null, throw a TypeError exception. - // 4. Assert: Type(handler) is Object. - assert(proxy.handler == Null || Is(proxy.handler)); - const handler = - Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; - - // 5. Let target be O.[[ProxyTarget]]. - const target = Cast(proxy.target) otherwise unreachable; - - // 6. Let trap be ? GetMethod(handler, "has"). - // 7. If trap is undefined, then (see 7.a below). - const trap: Callable = GetMethod(handler, 'has') - otherwise goto TrapUndefined(target); - - // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « - // target»)). - // 9. If booleanTrapResult is false, then (see 9.a. in - // CheckHasTrapResult). - // 10. Return booleanTrapResult. - const trapResult = Call(context, trap, handler, target, name); - if (ToBoolean(trapResult)) { - return True; - } - CheckHasTrapResult(target, proxy, name); - return False; - } - label TrapUndefined(target: JSAny) { - // 7.a. Return ? target.[[HasProperty]](P). - tail HasProperty(target, name); - } - label ThrowProxyHandlerRevoked deferred { - ThrowTypeError(MessageTemplate::kProxyRevoked, 'has'); +// ES #sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p +// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p +transitioning builtin ProxyHasProperty(implicit context: Context)( + proxy: JSProxy, name: PropertyKey): JSAny { + assert(IsJSProxy(proxy)); + + PerformStackCheck(); + + // 1. Assert: IsPropertyKey(P) is true. + assert(IsName(name)); + assert(!IsPrivateSymbol(name)); + + try { + // 2. Let handler be O.[[ProxyHandler]]. + // 3. If handler is null, throw a TypeError exception. + // 4. Assert: Type(handler) is Object. + assert(proxy.handler == Null || Is(proxy.handler)); + const handler = + Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; + + // 5. Let target be O.[[ProxyTarget]]. + const target = Cast(proxy.target) otherwise unreachable; + + // 6. Let trap be ? GetMethod(handler, "has"). + // 7. If trap is undefined, then (see 7.a below). + const trap: Callable = GetMethod(handler, 'has') + otherwise goto TrapUndefined(target); + + // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « + // target»)). + // 9. If booleanTrapResult is false, then (see 9.a. in + // CheckHasTrapResult). + // 10. Return booleanTrapResult. + const trapResult = Call(context, trap, handler, target, name); + if (ToBoolean(trapResult)) { + return True; } + CheckHasTrapResult(target, proxy, name); + return False; + } label TrapUndefined(target: JSAny) { + // 7.a. Return ? target.[[HasProperty]](P). + tail HasProperty(target, name); + } label ThrowProxyHandlerRevoked deferred { + ThrowTypeError(MessageTemplate::kProxyRevoked, 'has'); } } +} diff --git a/deps/v8/src/builtins/proxy-is-extensible.tq b/deps/v8/src/builtins/proxy-is-extensible.tq index 9c0d45c5294950..a7c2c56d441b33 100644 --- a/deps/v8/src/builtins/proxy-is-extensible.tq +++ b/deps/v8/src/builtins/proxy-is-extensible.tq @@ -6,52 +6,50 @@ namespace proxy { - // ES #sec-proxy-object-internal-methods-and-internal-slots-isextensible - // https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-isextensible - transitioning builtin ProxyIsExtensible(implicit context: - Context)(proxy: JSProxy): JSAny { - PerformStackCheck(); - const kTrapName: constexpr string = 'isExtensible'; - try { - // 1. Let handler be O.[[ProxyHandler]]. - // 2. If handler is null, throw a TypeError exception. - // 3. Assert: Type(handler) is Object. - assert(proxy.handler == Null || Is(proxy.handler)); - const handler = - Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; - - // 4. Let target be O.[[ProxyTarget]]. - const target = proxy.target; - - // 5. Let trap be ? GetMethod(handler, "isExtensible"). - // 6. If trap is undefined, then (see 6.a below). - const trap: Callable = GetMethod(handler, kTrapName) - otherwise goto TrapUndefined(target); - - // 7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « - // target»)). - const trapResult = ToBoolean(Call(context, trap, handler, target)); - - // 8. Let targetResult be ? IsExtensible(target). - const targetResult: bool = - ToBoolean(object::ObjectIsExtensibleImpl(target)); - - // 9. If SameValue(booleanTrapResult, targetResult) is false, throw a - // TypeError exception. - if (trapResult != targetResult) { - ThrowTypeError( - MessageTemplate::kProxyIsExtensibleInconsistent, - SelectBooleanConstant(targetResult)); - } - // 10. Return booleanTrapResult. - return SelectBooleanConstant(trapResult); - } - label TrapUndefined(target: JSAny) { - // 6.a. Return ? IsExtensible(target). - return object::ObjectIsExtensibleImpl(target); - } - label ThrowProxyHandlerRevoked deferred { - ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName); +// ES #sec-proxy-object-internal-methods-and-internal-slots-isextensible +// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-isextensible +transitioning builtin ProxyIsExtensible(implicit context: Context)( + proxy: JSProxy): JSAny { + PerformStackCheck(); + const kTrapName: constexpr string = 'isExtensible'; + try { + // 1. Let handler be O.[[ProxyHandler]]. + // 2. If handler is null, throw a TypeError exception. + // 3. Assert: Type(handler) is Object. + assert(proxy.handler == Null || Is(proxy.handler)); + const handler = + Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; + + // 4. Let target be O.[[ProxyTarget]]. + const target = proxy.target; + + // 5. Let trap be ? GetMethod(handler, "isExtensible"). + // 6. If trap is undefined, then (see 6.a below). + const trap: Callable = GetMethod(handler, kTrapName) + otherwise goto TrapUndefined(target); + + // 7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « + // target»)). + const trapResult = ToBoolean(Call(context, trap, handler, target)); + + // 8. Let targetResult be ? IsExtensible(target). + const targetResult: bool = + ToBoolean(object::ObjectIsExtensibleImpl(target)); + + // 9. If SameValue(booleanTrapResult, targetResult) is false, throw a + // TypeError exception. + if (trapResult != targetResult) { + ThrowTypeError( + MessageTemplate::kProxyIsExtensibleInconsistent, + SelectBooleanConstant(targetResult)); } + // 10. Return booleanTrapResult. + return SelectBooleanConstant(trapResult); + } label TrapUndefined(target: JSAny) { + // 6.a. Return ? IsExtensible(target). + return object::ObjectIsExtensibleImpl(target); + } label ThrowProxyHandlerRevoked deferred { + ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName); } } +} diff --git a/deps/v8/src/builtins/proxy-prevent-extensions.tq b/deps/v8/src/builtins/proxy-prevent-extensions.tq index 10bd1f45f0145e..a5a3d93da4498c 100644 --- a/deps/v8/src/builtins/proxy-prevent-extensions.tq +++ b/deps/v8/src/builtins/proxy-prevent-extensions.tq @@ -6,61 +6,59 @@ namespace proxy { - // ES #sec-proxy-object-internal-methods-and-internal-slots-preventextensions - // https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-preventextensions - transitioning builtin - ProxyPreventExtensions(implicit context: - Context)(proxy: JSProxy, doThrow: Boolean): JSAny { - PerformStackCheck(); - const kTrapName: constexpr string = 'preventExtensions'; - try { - // 1. Let handler be O.[[ProxyHandler]]. - // 2. If handler is null, throw a TypeError exception. - // 3. Assert: Type(handler) is Object. - assert(proxy.handler == Null || Is(proxy.handler)); - const handler = - Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; +// ES #sec-proxy-object-internal-methods-and-internal-slots-preventextensions +// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-preventextensions +transitioning builtin +ProxyPreventExtensions(implicit context: Context)( + proxy: JSProxy, doThrow: Boolean): JSAny { + PerformStackCheck(); + const kTrapName: constexpr string = 'preventExtensions'; + try { + // 1. Let handler be O.[[ProxyHandler]]. + // 2. If handler is null, throw a TypeError exception. + // 3. Assert: Type(handler) is Object. + assert(proxy.handler == Null || Is(proxy.handler)); + const handler = + Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; - // 4. Let target be O.[[ProxyTarget]]. - const target = proxy.target; + // 4. Let target be O.[[ProxyTarget]]. + const target = proxy.target; - // 5. Let trap be ? GetMethod(handler, "preventExtensions"). - // 6. If trap is undefined, then (see 6.a below). - const trap: Callable = GetMethod(handler, kTrapName) - otherwise goto TrapUndefined(target); + // 5. Let trap be ? GetMethod(handler, "preventExtensions"). + // 6. If trap is undefined, then (see 6.a below). + const trap: Callable = GetMethod(handler, kTrapName) + otherwise goto TrapUndefined(target); - // 7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « - // target»)). - const trapResult = Call(context, trap, handler, target); + // 7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « + // target»)). + const trapResult = Call(context, trap, handler, target); - // 8. If booleanTrapResult is true, then - // 8.a. Let extensibleTarget be ? IsExtensible(target). - // 8.b If extensibleTarget is true, throw a TypeError exception. - if (ToBoolean(trapResult)) { - const extensibleTarget: JSAny = object::ObjectIsExtensibleImpl(target); - assert(extensibleTarget == True || extensibleTarget == False); - if (extensibleTarget == True) { - ThrowTypeError(MessageTemplate::kProxyPreventExtensionsExtensible); - } - } else { - if (doThrow == True) { - ThrowTypeError(MessageTemplate::kProxyTrapReturnedFalsish, kTrapName); - } - return False; + // 8. If booleanTrapResult is true, then + // 8.a. Let extensibleTarget be ? IsExtensible(target). + // 8.b If extensibleTarget is true, throw a TypeError exception. + if (ToBoolean(trapResult)) { + const extensibleTarget: JSAny = object::ObjectIsExtensibleImpl(target); + assert(extensibleTarget == True || extensibleTarget == False); + if (extensibleTarget == True) { + ThrowTypeError(MessageTemplate::kProxyPreventExtensionsExtensible); } - - // 9. Return booleanTrapResult. - return True; - } - label TrapUndefined(target: JSAny) { - // 6.a. Return ? target.[[PreventExtensions]](). + } else { if (doThrow == True) { - return object::ObjectPreventExtensionsThrow(target); + ThrowTypeError(MessageTemplate::kProxyTrapReturnedFalsish, kTrapName); } - return object::ObjectPreventExtensionsDontThrow(target); + return False; } - label ThrowProxyHandlerRevoked deferred { - ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName); + + // 9. Return booleanTrapResult. + return True; + } label TrapUndefined(target: JSAny) { + // 6.a. Return ? target.[[PreventExtensions]](). + if (doThrow == True) { + return object::ObjectPreventExtensionsThrow(target); } + return object::ObjectPreventExtensionsDontThrow(target); + } label ThrowProxyHandlerRevoked deferred { + ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName); } +} } // namespace proxy diff --git a/deps/v8/src/builtins/proxy-revocable.tq b/deps/v8/src/builtins/proxy-revocable.tq index 2b853afefea618..989db1c04c6129 100644 --- a/deps/v8/src/builtins/proxy-revocable.tq +++ b/deps/v8/src/builtins/proxy-revocable.tq @@ -6,48 +6,35 @@ namespace proxy { - extern macro ProxiesCodeStubAssembler::AllocateProxyRevokeFunction( - implicit context: Context)(JSProxy): JSFunction; - - // Proxy.revocable(target, handler) - // https://tc39.github.io/ecma262/#sec-proxy.revocable - transitioning javascript builtin - ProxyRevocable(js-implicit context: NativeContext)( - target: JSAny, handler: JSAny): JSProxyRevocableResult { - try { - const targetJSReceiver = - Cast(target) otherwise ThrowProxyNonObject; - if (IsRevokedProxy(targetJSReceiver)) { - goto ThrowProxyHandlerOrTargetRevoked; - } - - const handlerJSReceiver = - Cast(handler) otherwise ThrowProxyNonObject; - if (IsRevokedProxy(handlerJSReceiver)) { - goto ThrowProxyHandlerOrTargetRevoked; - } - - // 1. Let p be ? ProxyCreate(target, handler). - const proxy: JSProxy = AllocateProxy(targetJSReceiver, handlerJSReceiver); - - // 2. Let steps be the algorithm steps defined in Proxy Revocation - // Functions. - // 3. Let revoker be CreateBuiltinFunction(steps, « [[RevocableProxy]] »). - // 4. Set revoker.[[RevocableProxy]] to p. - const revoke: JSFunction = AllocateProxyRevokeFunction(proxy); - - // 5. Let result be ObjectCreate(%ObjectPrototype%). - // 6. Perform CreateDataProperty(result, "proxy", p). - // 7. Perform CreateDataProperty(result, "revoke", revoker). - // 8. Return result. - return NewJSProxyRevocableResult(proxy, revoke); - } - label ThrowProxyNonObject deferred { - ThrowTypeError(MessageTemplate::kProxyNonObject, 'Proxy.revocable'); - } - label ThrowProxyHandlerOrTargetRevoked deferred { - ThrowTypeError( - MessageTemplate::kProxyHandlerOrTargetRevoked, 'Proxy.revocable'); - } +extern macro ProxiesCodeStubAssembler::AllocateProxyRevokeFunction( + implicit context: Context)(JSProxy): JSFunction; + +// Proxy.revocable(target, handler) +// https://tc39.github.io/ecma262/#sec-proxy.revocable +transitioning javascript builtin +ProxyRevocable(js-implicit context: NativeContext)( + target: JSAny, handler: JSAny): JSProxyRevocableResult { + try { + // 1. Let p be ? ProxyCreate(target, handler). + const targetJSReceiver = + Cast(target) otherwise ThrowProxyNonObject; + const handlerJSReceiver = + Cast(handler) otherwise ThrowProxyNonObject; + const proxy: JSProxy = AllocateProxy(targetJSReceiver, handlerJSReceiver); + + // 2. Let steps be the algorithm steps defined in Proxy Revocation + // Functions. + // 3. Let revoker be CreateBuiltinFunction(steps, « [[RevocableProxy]] »). + // 4. Set revoker.[[RevocableProxy]] to p. + const revoke: JSFunction = AllocateProxyRevokeFunction(proxy); + + // 5. Let result be ObjectCreate(%ObjectPrototype%). + // 6. Perform CreateDataProperty(result, "proxy", p). + // 7. Perform CreateDataProperty(result, "revoke", revoker). + // 8. Return result. + return NewJSProxyRevocableResult(proxy, revoke); + } label ThrowProxyNonObject deferred { + ThrowTypeError(MessageTemplate::kProxyNonObject, 'Proxy.revocable'); } } +} diff --git a/deps/v8/src/builtins/proxy-revoke.tq b/deps/v8/src/builtins/proxy-revoke.tq index 7300f4d7179e70..5d2071b931bc8b 100644 --- a/deps/v8/src/builtins/proxy-revoke.tq +++ b/deps/v8/src/builtins/proxy-revoke.tq @@ -6,31 +6,31 @@ namespace proxy { - // Proxy Revocation Functions - // https://tc39.github.io/ecma262/#sec-proxy-revocation-functions - transitioning javascript builtin - ProxyRevoke(js-implicit context: NativeContext)(): Undefined { - // 1. Let p be F.[[RevocableProxy]]. - const proxyObject: Object = context[PROXY_SLOT]; - - // 2. If p is null, return undefined - if (proxyObject == Null) { - return Undefined; - } +// Proxy Revocation Functions +// https://tc39.github.io/ecma262/#sec-proxy-revocation-functions +transitioning javascript builtin +ProxyRevoke(js-implicit context: NativeContext)(): Undefined { + // 1. Let p be F.[[RevocableProxy]]. + const proxyObject: Object = context[PROXY_SLOT]; + + // 2. If p is null, return undefined + if (proxyObject == Null) { + return Undefined; + } - // 3. Set F.[[RevocableProxy]] to null. - context[PROXY_SLOT] = Null; + // 3. Set F.[[RevocableProxy]] to null. + context[PROXY_SLOT] = Null; - // 4. Assert: p is a Proxy object. - const proxy: JSProxy = UnsafeCast(proxyObject); + // 4. Assert: p is a Proxy object. + const proxy: JSProxy = UnsafeCast(proxyObject); - // 5. Set p.[[ProxyTarget]] to null. - proxy.target = Null; + // 5. Set p.[[ProxyTarget]] to null. + proxy.target = Null; - // 6. Set p.[[ProxyHandler]] to null. - proxy.handler = Null; + // 6. Set p.[[ProxyHandler]] to null. + proxy.handler = Null; - // 7. Return undefined. - return Undefined; - } + // 7. Return undefined. + return Undefined; +} } diff --git a/deps/v8/src/builtins/proxy-set-property.tq b/deps/v8/src/builtins/proxy-set-property.tq index 2d084eac7a5666..49f55fcd336527 100644 --- a/deps/v8/src/builtins/proxy-set-property.tq +++ b/deps/v8/src/builtins/proxy-set-property.tq @@ -6,84 +6,82 @@ namespace proxy { - extern transitioning runtime - SetPropertyWithReceiver(implicit context: - Context)(Object, Name, Object, Object): void; +extern transitioning runtime +SetPropertyWithReceiver(implicit context: Context)( + Object, Name, Object, Object): void; - transitioning macro CallThrowTypeErrorIfStrict(implicit context: Context)( - message: constexpr MessageTemplate) { - ThrowTypeErrorIfStrict(SmiConstant(message), Null, Null); - } +transitioning macro CallThrowTypeErrorIfStrict(implicit context: Context)( + message: constexpr MessageTemplate) { + ThrowTypeErrorIfStrict(SmiConstant(message), Null, Null); +} - // ES #sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver - // https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver - transitioning builtin - ProxySetProperty(implicit context: Context)( - proxy: JSProxy, name: PropertyKey|PrivateSymbol, value: JSAny, - receiverValue: JSAny): JSAny { - // 1. Assert: IsPropertyKey(P) is true. - assert(TaggedIsNotSmi(name)); - assert(IsName(name)); +// ES #sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver +// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver +transitioning builtin +ProxySetProperty(implicit context: Context)( + proxy: JSProxy, name: PropertyKey|PrivateSymbol, value: JSAny, + receiverValue: JSAny): JSAny { + // 1. Assert: IsPropertyKey(P) is true. + assert(TaggedIsNotSmi(name)); + assert(IsName(name)); - let key: PropertyKey; - typeswitch (name) { - case (PrivateSymbol): { - CallThrowTypeErrorIfStrict(MessageTemplate::kProxyPrivate); - return Undefined; - } - case (name: PropertyKey): { - key = name; - } + let key: PropertyKey; + typeswitch (name) { + case (PrivateSymbol): { + CallThrowTypeErrorIfStrict(MessageTemplate::kProxyPrivate); + return Undefined; } + case (name: PropertyKey): { + key = name; + } + } - try { - // 2. Let handler be O.[[ProxyHandler]]. - // 3. If handler is null, throw a TypeError exception. - // 4. Assert: Type(handler) is Object. - assert(proxy.handler == Null || Is(proxy.handler)); - const handler = - Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; + try { + // 2. Let handler be O.[[ProxyHandler]]. + // 3. If handler is null, throw a TypeError exception. + // 4. Assert: Type(handler) is Object. + assert(proxy.handler == Null || Is(proxy.handler)); + const handler = + Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; - // 5. Let target be O.[[ProxyTarget]]. - const target = UnsafeCast(proxy.target); + // 5. Let target be O.[[ProxyTarget]]. + const target = UnsafeCast(proxy.target); - // 6. Let trap be ? GetMethod(handler, "set"). - // 7. If trap is undefined, then (see 7.a below). - const trap: Callable = GetMethod(handler, 'set') - otherwise goto TrapUndefined(target); + // 6. Let trap be ? GetMethod(handler, "set"). + // 7. If trap is undefined, then (see 7.a below). + const trap: Callable = GetMethod(handler, 'set') + otherwise goto TrapUndefined(target); - // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, - // « target, P, V, Receiver »)). - // 9. If booleanTrapResult is false, return false. - // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). - // 11. If targetDesc is not undefined and targetDesc.[[Configurable]] is - // false, then - // a. If IsDataDescriptor(targetDesc) is true and - // targetDesc.[[Writable]] is false, then - // i. If SameValue(V, targetDesc.[[Value]]) is false, throw a - // TypeError exception. - // b. If IsAccessorDescriptor(targetDesc) is true, then - // i. If targetDesc.[[Set]] is undefined, throw a TypeError - // exception. - // 12. Return true. - const trapResult = - Call(context, trap, handler, target, key, value, receiverValue); - if (ToBoolean(trapResult)) { - CheckGetSetTrapResult(target, proxy, name, value, kProxySet); - return value; - } - ThrowTypeErrorIfStrict( - SmiConstant(MessageTemplate::kProxyTrapReturnedFalsishFor), 'set', - name); + // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, + // « target, P, V, Receiver »)). + // 9. If booleanTrapResult is false, return false. + // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). + // 11. If targetDesc is not undefined and targetDesc.[[Configurable]] is + // false, then + // a. If IsDataDescriptor(targetDesc) is true and + // targetDesc.[[Writable]] is false, then + // i. If SameValue(V, targetDesc.[[Value]]) is false, throw a + // TypeError exception. + // b. If IsAccessorDescriptor(targetDesc) is true, then + // i. If targetDesc.[[Set]] is undefined, throw a TypeError + // exception. + // 12. Return true. + const trapResult = + Call(context, trap, handler, target, key, value, receiverValue); + if (ToBoolean(trapResult)) { + CheckGetSetTrapResult(target, proxy, name, value, kProxySet); return value; } - label TrapUndefined(target: Object) { - // 7.a. Return ? target.[[Set]](P, V, Receiver). - SetPropertyWithReceiver(target, name, value, receiverValue); - return value; - } - label ThrowProxyHandlerRevoked deferred { - ThrowTypeError(MessageTemplate::kProxyRevoked, 'set'); - } + ThrowTypeErrorIfStrict( + SmiConstant(MessageTemplate::kProxyTrapReturnedFalsishFor), 'set', + name); + return value; + } label TrapUndefined(target: Object) { + // 7.a. Return ? target.[[Set]](P, V, Receiver). + SetPropertyWithReceiver(target, name, value, receiverValue); + return value; + } label ThrowProxyHandlerRevoked deferred { + ThrowTypeError(MessageTemplate::kProxyRevoked, 'set'); } } +} diff --git a/deps/v8/src/builtins/proxy-set-prototype-of.tq b/deps/v8/src/builtins/proxy-set-prototype-of.tq index a7a76b753551b5..ec68cef44c839d 100644 --- a/deps/v8/src/builtins/proxy-set-prototype-of.tq +++ b/deps/v8/src/builtins/proxy-set-prototype-of.tq @@ -6,73 +6,71 @@ namespace proxy { - // ES #sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v - // https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v - transitioning builtin - ProxySetPrototypeOf(implicit context: Context)( - proxy: JSProxy, proto: Null|JSReceiver, doThrow: Boolean): JSAny { - PerformStackCheck(); - const kTrapName: constexpr string = 'setPrototypeOf'; - try { - // 1. Assert: Either Type(V) is Object or Type(V) is Null. - assert(proto == Null || Is(proto)); +// ES #sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v +// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v +transitioning builtin +ProxySetPrototypeOf(implicit context: Context)( + proxy: JSProxy, proto: Null|JSReceiver, doThrow: Boolean): JSAny { + PerformStackCheck(); + const kTrapName: constexpr string = 'setPrototypeOf'; + try { + // 1. Assert: Either Type(V) is Object or Type(V) is Null. + assert(proto == Null || Is(proto)); - // 2. Let handler be O.[[ProxyHandler]]. - // 3. If handler is null, throw a TypeError exception. - // 4. Assert: Type(handler) is Object. - assert(proxy.handler == Null || Is(proxy.handler)); - const handler = - Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; + // 2. Let handler be O.[[ProxyHandler]]. + // 3. If handler is null, throw a TypeError exception. + // 4. Assert: Type(handler) is Object. + assert(proxy.handler == Null || Is(proxy.handler)); + const handler = + Cast(proxy.handler) otherwise ThrowProxyHandlerRevoked; - // 5. Let target be O.[[ProxyTarget]]. - const target = proxy.target; + // 5. Let target be O.[[ProxyTarget]]. + const target = proxy.target; - // 6. Let trap be ? GetMethod(handler, "setPrototypeOf"). - // 7. If trap is undefined, then (see 7.a below). - const trap: Callable = GetMethod(handler, kTrapName) - otherwise goto TrapUndefined(target, proto); + // 6. Let trap be ? GetMethod(handler, "setPrototypeOf"). + // 7. If trap is undefined, then (see 7.a below). + const trap: Callable = GetMethod(handler, kTrapName) + otherwise goto TrapUndefined(target, proto); - // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, V - // »)). - const trapResult = Call(context, trap, handler, target, proto); + // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, V + // »)). + const trapResult = Call(context, trap, handler, target, proto); - // 9. If booleanTrapResult is false, return false. - if (!ToBoolean(trapResult)) { - if (doThrow == True) { - ThrowTypeError( - MessageTemplate::kProxyTrapReturnedFalsishFor, kTrapName); - } - return False; + // 9. If booleanTrapResult is false, return false. + if (!ToBoolean(trapResult)) { + if (doThrow == True) { + ThrowTypeError( + MessageTemplate::kProxyTrapReturnedFalsishFor, kTrapName); } + return False; + } - // 10. Let extensibleTarget be ? IsExtensible(target). - // 11. If extensibleTarget is true, return true. - const extensibleTarget: Object = object::ObjectIsExtensibleImpl(target); - assert(extensibleTarget == True || extensibleTarget == False); - if (extensibleTarget == True) { - return True; - } + // 10. Let extensibleTarget be ? IsExtensible(target). + // 11. If extensibleTarget is true, return true. + const extensibleTarget: Object = object::ObjectIsExtensibleImpl(target); + assert(extensibleTarget == True || extensibleTarget == False); + if (extensibleTarget == True) { + return True; + } - // 12. Let targetProto be ? target.[[GetPrototypeOf]](). - const targetProto = object::ObjectGetPrototypeOfImpl(target); + // 12. Let targetProto be ? target.[[GetPrototypeOf]](). + const targetProto = object::ObjectGetPrototypeOfImpl(target); - // 13. If SameValue(V, targetProto) is false, throw a TypeError - // exception. - // 14. Return true. - if (SameValue(proto, targetProto)) { - return True; - } - ThrowTypeError(MessageTemplate::kProxySetPrototypeOfNonExtensible); + // 13. If SameValue(V, targetProto) is false, throw a TypeError + // exception. + // 14. Return true. + if (SameValue(proto, targetProto)) { + return True; } - label TrapUndefined(target: JSAny, proto: JSReceiver|Null) { - // 7.a. Return ? target.[[SetPrototypeOf]](). - if (doThrow == True) { - return object::ObjectSetPrototypeOfThrow(target, proto); - } - return object::ObjectSetPrototypeOfDontThrow(target, proto); - } - label ThrowProxyHandlerRevoked deferred { - ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName); + ThrowTypeError(MessageTemplate::kProxySetPrototypeOfNonExtensible); + } label TrapUndefined(target: JSAny, proto: JSReceiver|Null) { + // 7.a. Return ? target.[[SetPrototypeOf]](). + if (doThrow == True) { + return object::ObjectSetPrototypeOfThrow(target, proto); } + return object::ObjectSetPrototypeOfDontThrow(target, proto); + } label ThrowProxyHandlerRevoked deferred { + ThrowTypeError(MessageTemplate::kProxyRevoked, kTrapName); } } +} diff --git a/deps/v8/src/builtins/proxy.tq b/deps/v8/src/builtins/proxy.tq index 2db794e8e80c83..8f662a9f4d15ac 100644 --- a/deps/v8/src/builtins/proxy.tq +++ b/deps/v8/src/builtins/proxy.tq @@ -6,27 +6,21 @@ namespace proxy { - extern macro ProxiesCodeStubAssembler::AllocateProxy( - implicit context: Context)(JSReceiver, JSReceiver): JSProxy; +extern macro ProxiesCodeStubAssembler::AllocateProxy(implicit context: Context)( + JSReceiver, JSReceiver): JSProxy; - macro IsRevokedProxy(implicit context: Context)(o: JSReceiver): bool { - const proxy: JSProxy = Cast(o) otherwise return false; - Cast(proxy.handler) otherwise return true; - return false; - } +extern transitioning macro ProxiesCodeStubAssembler::CheckGetSetTrapResult( + implicit context: Context)( + JSReceiver, JSProxy, Name, Object, constexpr int31); - extern transitioning macro ProxiesCodeStubAssembler::CheckGetSetTrapResult( - implicit context: - Context)(JSReceiver, JSProxy, Name, Object, constexpr int31); +extern transitioning macro ProxiesCodeStubAssembler::CheckDeleteTrapResult( + implicit context: Context)(JSReceiver, JSProxy, Name); - extern transitioning macro ProxiesCodeStubAssembler::CheckDeleteTrapResult( - implicit context: Context)(JSReceiver, JSProxy, Name); +extern transitioning macro ProxiesCodeStubAssembler::CheckHasTrapResult( + implicit context: Context)(JSReceiver, JSProxy, Name); - extern transitioning macro ProxiesCodeStubAssembler::CheckHasTrapResult( - implicit context: Context)(JSReceiver, JSProxy, Name); - - const kProxyGet: constexpr int31 - generates 'JSProxy::AccessKind::kGet'; - const kProxySet: constexpr int31 - generates 'JSProxy::AccessKind::kSet'; +const kProxyGet: constexpr int31 + generates 'JSProxy::AccessKind::kGet'; +const kProxySet: constexpr int31 + generates 'JSProxy::AccessKind::kSet'; } diff --git a/deps/v8/src/builtins/reflect.tq b/deps/v8/src/builtins/reflect.tq index f1818ed32d7310..477c586403c022 100644 --- a/deps/v8/src/builtins/reflect.tq +++ b/deps/v8/src/builtins/reflect.tq @@ -3,92 +3,88 @@ // found in the LICENSE file. namespace reflect { - // ES6 section 26.1.10 Reflect.isExtensible - transitioning javascript builtin - ReflectIsExtensible(js-implicit context: NativeContext)(object: JSAny): - JSAny { - const objectJSReceiver = Cast(object) - otherwise ThrowTypeError( - MessageTemplate::kCalledOnNonObject, 'Reflect.isExtensible'); - return object::ObjectIsExtensibleImpl(objectJSReceiver); - } +// ES6 section 26.1.10 Reflect.isExtensible +transitioning javascript builtin +ReflectIsExtensible(js-implicit context: NativeContext)(object: JSAny): JSAny { + const objectJSReceiver = Cast(object) + otherwise ThrowTypeError( + MessageTemplate::kCalledOnNonObject, 'Reflect.isExtensible'); + return object::ObjectIsExtensibleImpl(objectJSReceiver); +} - // ES6 section 26.1.12 Reflect.preventExtensions - transitioning javascript builtin - ReflectPreventExtensions(js-implicit context: NativeContext)(object: JSAny): - JSAny { - const objectJSReceiver = Cast(object) - otherwise ThrowTypeError( - MessageTemplate::kCalledOnNonObject, 'Reflect.preventExtensions'); - return object::ObjectPreventExtensionsDontThrow(objectJSReceiver); - } +// ES6 section 26.1.12 Reflect.preventExtensions +transitioning javascript builtin +ReflectPreventExtensions(js-implicit context: NativeContext)(object: JSAny): + JSAny { + const objectJSReceiver = Cast(object) + otherwise ThrowTypeError( + MessageTemplate::kCalledOnNonObject, 'Reflect.preventExtensions'); + return object::ObjectPreventExtensionsDontThrow(objectJSReceiver); +} - // ES6 section 26.1.8 Reflect.getPrototypeOf - transitioning javascript builtin - ReflectGetPrototypeOf(js-implicit context: NativeContext)(object: JSAny): - JSAny { - const objectJSReceiver = Cast(object) - otherwise ThrowTypeError( - MessageTemplate::kCalledOnNonObject, 'Reflect.getPrototypeOf'); - return object::JSReceiverGetPrototypeOf(objectJSReceiver); - } +// ES6 section 26.1.8 Reflect.getPrototypeOf +transitioning javascript builtin +ReflectGetPrototypeOf(js-implicit context: NativeContext)(object: JSAny): + JSAny { + const objectJSReceiver = Cast(object) + otherwise ThrowTypeError( + MessageTemplate::kCalledOnNonObject, 'Reflect.getPrototypeOf'); + return object::JSReceiverGetPrototypeOf(objectJSReceiver); +} - // ES6 section 26.1.14 Reflect.setPrototypeOf - transitioning javascript builtin ReflectSetPrototypeOf( - js-implicit context: NativeContext)(object: JSAny, proto: JSAny): JSAny { - const objectJSReceiver = Cast(object) - otherwise ThrowTypeError( - MessageTemplate::kCalledOnNonObject, 'Reflect.setPrototypeOf'); - typeswitch (proto) { - case (proto: JSReceiver|Null): { - return object::ObjectSetPrototypeOfDontThrow(objectJSReceiver, proto); - } - case (JSAny): { - ThrowTypeError(MessageTemplate::kProtoObjectOrNull, proto); - } +// ES6 section 26.1.14 Reflect.setPrototypeOf +transitioning javascript builtin ReflectSetPrototypeOf( + js-implicit context: NativeContext)(object: JSAny, proto: JSAny): JSAny { + const objectJSReceiver = Cast(object) + otherwise ThrowTypeError( + MessageTemplate::kCalledOnNonObject, 'Reflect.setPrototypeOf'); + typeswitch (proto) { + case (proto: JSReceiver|Null): { + return object::ObjectSetPrototypeOfDontThrow(objectJSReceiver, proto); + } + case (JSAny): { + ThrowTypeError(MessageTemplate::kProtoObjectOrNull, proto); } } +} - extern transitioning builtin ToName(implicit context: Context)(JSAny): - AnyName; - type OnNonExistent constexpr 'OnNonExistent'; - const kReturnUndefined: constexpr OnNonExistent - generates 'OnNonExistent::kReturnUndefined'; - extern macro SmiConstant(constexpr OnNonExistent): Smi; - extern transitioning builtin GetPropertyWithReceiver( - implicit context: Context)(JSAny, Name, JSAny, Smi): JSAny; +extern transitioning builtin ToName(implicit context: Context)(JSAny): AnyName; +type OnNonExistent constexpr 'OnNonExistent'; +const kReturnUndefined: constexpr OnNonExistent + generates 'OnNonExistent::kReturnUndefined'; +extern macro SmiConstant(constexpr OnNonExistent): Smi; +extern transitioning builtin GetPropertyWithReceiver(implicit context: Context)( + JSAny, Name, JSAny, Smi): JSAny; - // ES6 section 26.1.6 Reflect.get - transitioning javascript builtin - ReflectGet(js-implicit context: NativeContext)(...arguments): JSAny { - const length = arguments.length; - const object: JSAny = length > 0 ? arguments[0] : Undefined; - const objectJSReceiver = Cast(object) - otherwise ThrowTypeError( - MessageTemplate::kCalledOnNonObject, 'Reflect.get'); - const propertyKey: JSAny = length > 1 ? arguments[1] : Undefined; - const name: AnyName = ToName(propertyKey); - const receiver: JSAny = length > 2 ? arguments[2] : objectJSReceiver; - return GetPropertyWithReceiver( - objectJSReceiver, name, receiver, SmiConstant(kReturnUndefined)); - } +// ES6 section 26.1.6 Reflect.get +transitioning javascript builtin +ReflectGet(js-implicit context: NativeContext)(...arguments): JSAny { + const object: JSAny = arguments[0]; + const objectJSReceiver = Cast(object) + otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Reflect.get'); + const propertyKey: JSAny = arguments[1]; + const name: AnyName = ToName(propertyKey); + const receiver: JSAny = + arguments.length > 2 ? arguments[2] : objectJSReceiver; + return GetPropertyWithReceiver( + objectJSReceiver, name, receiver, SmiConstant(kReturnUndefined)); +} - // ES6 section 26.1.4 Reflect.deleteProperty - transitioning javascript builtin ReflectDeleteProperty( - js-implicit context: NativeContext)(object: JSAny, key: JSAny): JSAny { - const objectJSReceiver = Cast(object) - otherwise ThrowTypeError( - MessageTemplate::kCalledOnNonObject, 'Reflect.deleteProperty'); - return DeleteProperty(objectJSReceiver, key, LanguageMode::kSloppy); - } +// ES6 section 26.1.4 Reflect.deleteProperty +transitioning javascript builtin ReflectDeleteProperty( + js-implicit context: NativeContext)(object: JSAny, key: JSAny): JSAny { + const objectJSReceiver = Cast(object) + otherwise ThrowTypeError( + MessageTemplate::kCalledOnNonObject, 'Reflect.deleteProperty'); + return DeleteProperty(objectJSReceiver, key, LanguageMode::kSloppy); +} - // ES section #sec-reflect.has - transitioning javascript builtin - ReflectHas(js-implicit context: NativeContext)(object: JSAny, key: JSAny): - JSAny { - const objectJSReceiver = Cast(object) - otherwise ThrowTypeError( - MessageTemplate::kCalledOnNonObject, 'Reflect.has'); - return HasProperty(objectJSReceiver, key); - } +// ES section #sec-reflect.has +transitioning javascript builtin +ReflectHas(js-implicit context: NativeContext)( + object: JSAny, key: JSAny): JSAny { + const objectJSReceiver = Cast(object) + otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Reflect.has'); + return HasProperty(objectJSReceiver, key); +} } // namespace reflect diff --git a/deps/v8/src/builtins/regexp-exec.tq b/deps/v8/src/builtins/regexp-exec.tq index 0b11c42fbf7f01..87b00c1fdcdfc7 100644 --- a/deps/v8/src/builtins/regexp-exec.tq +++ b/deps/v8/src/builtins/regexp-exec.tq @@ -6,40 +6,39 @@ namespace regexp { - @export - transitioning macro RegExpPrototypeExecBodyFast(implicit context: Context)( - receiver: JSReceiver, string: String): JSAny { - return RegExpPrototypeExecBody(receiver, string, true); - } - - transitioning macro RegExpPrototypeExecBodySlow(implicit context: Context)( - receiver: JSReceiver, string: String): JSAny { - return RegExpPrototypeExecBody(receiver, string, false); - } - - // Slow path stub for RegExpPrototypeExec to decrease code size. - transitioning builtin - RegExpPrototypeExecSlow(implicit context: Context)( - regexp: JSRegExp, string: String): JSAny { - return RegExpPrototypeExecBodySlow(regexp, string); - } - - extern macro RegExpBuiltinsAssembler::IsFastRegExpNoPrototype( - implicit context: Context)(Object): bool; - - // ES#sec-regexp.prototype.exec - // RegExp.prototype.exec ( string ) - transitioning javascript builtin RegExpPrototypeExec( - js-implicit context: NativeContext, - receiver: JSAny)(string: JSAny): JSAny { - // Ensure {receiver} is a JSRegExp. - const receiver = Cast(receiver) otherwise ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, 'RegExp.prototype.exec', - receiver); - const string = ToString_Inline(string); - - return IsFastRegExpNoPrototype(receiver) ? - RegExpPrototypeExecBodyFast(receiver, string) : - RegExpPrototypeExecSlow(receiver, string); - } +@export +transitioning macro RegExpPrototypeExecBodyFast(implicit context: Context)( + receiver: JSReceiver, string: String): JSAny { + return RegExpPrototypeExecBody(receiver, string, true); +} + +transitioning macro RegExpPrototypeExecBodySlow(implicit context: Context)( + receiver: JSReceiver, string: String): JSAny { + return RegExpPrototypeExecBody(receiver, string, false); +} + +// Slow path stub for RegExpPrototypeExec to decrease code size. +transitioning builtin +RegExpPrototypeExecSlow(implicit context: Context)( + regexp: JSRegExp, string: String): JSAny { + return RegExpPrototypeExecBodySlow(regexp, string); +} + +extern macro RegExpBuiltinsAssembler::IsFastRegExpNoPrototype( + implicit context: Context)(Object): bool; + +// ES#sec-regexp.prototype.exec +// RegExp.prototype.exec ( string ) +transitioning javascript builtin RegExpPrototypeExec( + js-implicit context: NativeContext, receiver: JSAny)(string: JSAny): JSAny { + // Ensure {receiver} is a JSRegExp. + const receiver = Cast(receiver) otherwise ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, 'RegExp.prototype.exec', + receiver); + const string = ToString_Inline(string); + + return IsFastRegExpNoPrototype(receiver) ? + RegExpPrototypeExecBodyFast(receiver, string) : + RegExpPrototypeExecSlow(receiver, string); +} } diff --git a/deps/v8/src/builtins/regexp-match-all.tq b/deps/v8/src/builtins/regexp-match-all.tq index 022f8bc53f101d..932972d8440632 100644 --- a/deps/v8/src/builtins/regexp-match-all.tq +++ b/deps/v8/src/builtins/regexp-match-all.tq @@ -6,247 +6,217 @@ namespace regexp { - extern transitioning macro - RegExpMatchAllAssembler::CreateRegExpStringIterator( - NativeContext, Object, String, bool, bool): JSAny; - - @export - transitioning macro RegExpPrototypeMatchAllImpl(implicit context: Context)( - nativeContext: NativeContext, receiver: JSAny, string: JSAny): JSAny { - // 1. Let R be the this value. - // 2. If Type(R) is not Object, throw a TypeError exception. - ThrowIfNotJSReceiver( - receiver, MessageTemplate::kIncompatibleMethodReceiver, - 'RegExp.prototype.@@matchAll'); - const receiver = UnsafeCast(receiver); - - // 3. Let S be ? ToString(O). - const string: String = ToString_Inline(string); - - let matcher: Object; - let global: bool; - let unicode: bool; - - // 'FastJSRegExp' uses the strict fast path check because following code - // uses the flags property. - // TODO(jgruber): Handle slow flag accesses on the fast path and make this - // permissive. - typeswitch (receiver) { - case (fastRegExp: FastJSRegExp): { - const source = fastRegExp.source; - - // 4. Let C be ? SpeciesConstructor(R, %RegExp%). - // 5. Let flags be ? ToString(? Get(R, "flags")). - // 6. Let matcher be ? Construct(C, « R, flags »). - const flags: String = FastFlagsGetter(fastRegExp); - matcher = RegExpCreate(nativeContext, source, flags); - const matcherRegExp = UnsafeCast(matcher); - assert(IsFastRegExpPermissive(matcherRegExp)); - - // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")). - // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true). - const fastRegExp = UnsafeCast(receiver); - FastStoreLastIndex(matcherRegExp, fastRegExp.lastIndex); - - // 9. If flags contains "g", let global be true. - // 10. Else, let global be false. - global = FastFlagGetter(matcherRegExp, Flag::kGlobal); - - // 11. If flags contains "u", let fullUnicode be true. - // 12. Else, let fullUnicode be false. - unicode = FastFlagGetter(matcherRegExp, Flag::kUnicode); - } - case (Object): { - // 4. Let C be ? SpeciesConstructor(R, %RegExp%). - const regexpFun = LoadRegExpFunction(nativeContext); - const speciesConstructor = - UnsafeCast(SpeciesConstructor(receiver, regexpFun)); - - // 5. Let flags be ? ToString(? Get(R, "flags")). - const flags = GetProperty(receiver, 'flags'); - const flagsString = ToString_Inline(flags); - - // 6. Let matcher be ? Construct(C, « R, flags »). - matcher = Construct(speciesConstructor, receiver, flagsString); - - // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")). - const lastIndex: Number = ToLength_Inline(SlowLoadLastIndex(receiver)); - - // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true). - SlowStoreLastIndex(UnsafeCast(matcher), lastIndex); - - // 9. If flags contains "g", let global be true. - // 10. Else, let global be false. - const globalCharString: String = StringConstant('g'); - const globalIndex: Smi = - StringIndexOf(flagsString, globalCharString, 0); - global = globalIndex != -1; - - // 11. If flags contains "u", let fullUnicode be true. - // 12. Else, let fullUnicode be false. - const unicodeCharString = StringConstant('u'); - const unicodeIndex: Smi = - StringIndexOf(flagsString, unicodeCharString, 0); - unicode = unicodeIndex != -1; - } +extern transitioning macro +RegExpMatchAllAssembler::CreateRegExpStringIterator( + NativeContext, Object, String, bool, bool): JSAny; + +@export +transitioning macro RegExpPrototypeMatchAllImpl(implicit context: Context)( + nativeContext: NativeContext, receiver: JSAny, string: JSAny): JSAny { + // 1. Let R be the this value. + // 2. If Type(R) is not Object, throw a TypeError exception. + ThrowIfNotJSReceiver( + receiver, MessageTemplate::kIncompatibleMethodReceiver, + 'RegExp.prototype.@@matchAll'); + const receiver = UnsafeCast(receiver); + + // 3. Let S be ? ToString(O). + const string: String = ToString_Inline(string); + + let matcher: Object; + let global: bool; + let unicode: bool; + + // 'FastJSRegExp' uses the strict fast path check because following code + // uses the flags property. + // TODO(jgruber): Handle slow flag accesses on the fast path and make this + // permissive. + typeswitch (receiver) { + case (fastRegExp: FastJSRegExp): { + const source = fastRegExp.source; + + // 4. Let C be ? SpeciesConstructor(R, %RegExp%). + // 5. Let flags be ? ToString(? Get(R, "flags")). + // 6. Let matcher be ? Construct(C, « R, flags »). + const flags: String = FastFlagsGetter(fastRegExp); + matcher = RegExpCreate(nativeContext, source, flags); + const matcherRegExp = UnsafeCast(matcher); + assert(IsFastRegExpPermissive(matcherRegExp)); + + // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")). + // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true). + const fastRegExp = UnsafeCast(receiver); + FastStoreLastIndex(matcherRegExp, fastRegExp.lastIndex); + + // 9. If flags contains "g", let global be true. + // 10. Else, let global be false. + global = FastFlagGetter(matcherRegExp, Flag::kGlobal); + + // 11. If flags contains "u", let fullUnicode be true. + // 12. Else, let fullUnicode be false. + unicode = FastFlagGetter(matcherRegExp, Flag::kUnicode); + } + case (Object): { + // 4. Let C be ? SpeciesConstructor(R, %RegExp%). + const regexpFun = LoadRegExpFunction(nativeContext); + const speciesConstructor = + UnsafeCast(SpeciesConstructor(receiver, regexpFun)); + + // 5. Let flags be ? ToString(? Get(R, "flags")). + const flags = GetProperty(receiver, 'flags'); + const flagsString = ToString_Inline(flags); + + // 6. Let matcher be ? Construct(C, « R, flags »). + matcher = Construct(speciesConstructor, receiver, flagsString); + + // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")). + const lastIndex: Number = ToLength_Inline(SlowLoadLastIndex(receiver)); + + // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true). + SlowStoreLastIndex(UnsafeCast(matcher), lastIndex); + + // 9. If flags contains "g", let global be true. + // 10. Else, let global be false. + const globalCharString: String = StringConstant('g'); + const globalIndex: Smi = StringIndexOf(flagsString, globalCharString, 0); + global = globalIndex != -1; + + // 11. If flags contains "u", let fullUnicode be true. + // 12. Else, let fullUnicode be false. + const unicodeCharString = StringConstant('u'); + const unicodeIndex: Smi = + StringIndexOf(flagsString, unicodeCharString, 0); + unicode = unicodeIndex != -1; } - - // 13. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode). - return CreateRegExpStringIterator( - nativeContext, matcher, string, global, unicode); - } - - // https://tc39.github.io/proposal-string-matchall/ - // RegExp.prototype [ @@matchAll ] ( string ) - transitioning javascript builtin RegExpPrototypeMatchAll( - js-implicit context: NativeContext, - receiver: JSAny)(string: JSAny): JSAny { - return RegExpPrototypeMatchAllImpl(context, receiver, string); - } - - const kJSRegExpStringIteratorDone: - constexpr int31 generates '1 << JSRegExpStringIterator::kDoneBit'; - const kJSRegExpStringIteratorGlobal: constexpr int31 - generates '1 << JSRegExpStringIterator::kGlobalBit'; - const kJSRegExpStringIteratorUnicode: constexpr int31 - generates '1 << JSRegExpStringIterator::kUnicodeBit'; - - extern macro IsSetSmi(Smi, constexpr int31): bool; - - macro HasDoneFlag(flags: Smi): bool { - return IsSetSmi(flags, kJSRegExpStringIteratorDone); - } - - macro HasGlobalFlag(flags: Smi): bool { - return IsSetSmi(flags, kJSRegExpStringIteratorGlobal); - } - - macro HasUnicodeFlag(flags: Smi): bool { - return IsSetSmi(flags, kJSRegExpStringIteratorUnicode); } - macro SetDoneFlag(iterator: JSRegExpStringIterator, flags: Smi) { - const newFlags: Smi = flags | kJSRegExpStringIteratorDone; - iterator.flags = newFlags; - } + // 13. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode). + return CreateRegExpStringIterator( + nativeContext, matcher, string, global, unicode); +} - // https://tc39.github.io/proposal-string-matchall/ - // %RegExpStringIteratorPrototype%.next ( ) - transitioning javascript builtin RegExpStringIteratorPrototypeNext( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - // 1. Let O be the this value. - // 2. If Type(O) is not Object, throw a TypeError exception. - // 3. If O does not have all of the internal slots of a RegExp String - // Iterator Object Instance (see 5.3), throw a TypeError exception. - const methodName: constexpr string = - '%RegExpStringIterator%.prototype.next'; - const receiver = Cast(receiver) otherwise - ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, methodName, receiver); +// https://tc39.github.io/proposal-string-matchall/ +// RegExp.prototype [ @@matchAll ] ( string ) +transitioning javascript builtin RegExpPrototypeMatchAll( + js-implicit context: NativeContext, receiver: JSAny)(string: JSAny): JSAny { + return RegExpPrototypeMatchAllImpl(context, receiver, string); +} +// https://tc39.github.io/proposal-string-matchall/ +// %RegExpStringIteratorPrototype%.next ( ) +transitioning javascript builtin RegExpStringIteratorPrototypeNext( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + // 1. Let O be the this value. + // 2. If Type(O) is not Object, throw a TypeError exception. + // 3. If O does not have all of the internal slots of a RegExp String + // Iterator Object Instance (see 5.3), throw a TypeError exception. + const methodName: constexpr string = '%RegExpStringIterator%.prototype.next'; + const receiver = Cast(receiver) otherwise + ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, methodName, receiver); + + try { + // 4. If O.[[Done]] is true, then + // a. Return ! CreateIterResultObject(undefined, true). + const flags: SmiTagged = receiver.flags; + if (flags.done) goto ReturnEmptyDoneResult; + + // 5. Let R be O.[[iteratingRegExp]]. + const iteratingRegExp: JSReceiver = receiver.iterating_reg_exp; + + // 6. Let S be O.[[IteratedString]]. + const iteratingString: String = receiver.iterated_string; + + // 7. Let global be O.[[Global]]. + // 8. Let fullUnicode be O.[[Unicode]]. + // 9. Let match be ? RegExpExec(R, S). + let match: Object; + let isFastRegExp: bool = false; try { - // 4. If O.[[Done]] is true, then - // a. Return ! CreateIterResultObject(undefined, true). - const flags: Smi = receiver.flags; - if (HasDoneFlag(flags)) goto ReturnEmptyDoneResult; - - // 5. Let R be O.[[iteratingRegExp]]. - const iteratingRegExp: JSReceiver = receiver.iterating_reg_exp; - - // 6. Let S be O.[[IteratedString]]. - const iteratingString: String = receiver.iterated_string; - - // 7. Let global be O.[[Global]]. - // 8. Let fullUnicode be O.[[Unicode]]. - // 9. Let match be ? RegExpExec(R, S). - let match: Object; - let isFastRegExp: bool = false; - try { - if (IsFastRegExpPermissive(iteratingRegExp)) { - const regexp = UnsafeCast(iteratingRegExp); - const lastIndex = LoadLastIndexAsLength(regexp, true); - const matchIndices: RegExpMatchInfo = - RegExpPrototypeExecBodyWithoutResultFast( - regexp, iteratingString, lastIndex) - otherwise IfNoMatch; - match = ConstructNewResultFromMatchInfo( - regexp, matchIndices, iteratingString, lastIndex); - isFastRegExp = true; - } else { - match = RegExpExec(iteratingRegExp, iteratingString); - if (match == Null) { - goto IfNoMatch; - } + if (IsFastRegExpPermissive(iteratingRegExp)) { + const regexp = UnsafeCast(iteratingRegExp); + const lastIndex = LoadLastIndexAsLength(regexp, true); + const matchIndices: RegExpMatchInfo = + RegExpPrototypeExecBodyWithoutResultFast( + regexp, iteratingString, lastIndex) + otherwise IfNoMatch; + match = ConstructNewResultFromMatchInfo( + regexp, matchIndices, iteratingString, lastIndex); + isFastRegExp = true; + } else { + match = RegExpExec(iteratingRegExp, iteratingString); + if (match == Null) { + goto IfNoMatch; } - // 11. Else, - // b. Else, handle non-global case first. - if (!HasGlobalFlag(flags)) { - // i. Set O.[[Done]] to true. - SetDoneFlag(receiver, flags); - - // ii. Return ! CreateIterResultObject(match, false). - return AllocateJSIteratorResult(UnsafeCast(match), False); - } - // a. If global is true, - assert(HasGlobalFlag(flags)); - if (isFastRegExp) { - // i. Let matchStr be ? ToString(? Get(match, "0")). - const match = UnsafeCast(match); - const resultFixedArray = UnsafeCast(match.elements); - const matchStr = UnsafeCast(resultFixedArray.objects[0]); - - // When iterating_regexp is fast, we assume it stays fast even after - // accessing the first match from the RegExp result. - assert(IsFastRegExpPermissive(iteratingRegExp)); - const iteratingRegExp = UnsafeCast(iteratingRegExp); - if (matchStr == kEmptyString) { - // 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")). - const thisIndex: Smi = FastLoadLastIndex(iteratingRegExp); - - // 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, - // fullUnicode). - const nextIndex: Smi = AdvanceStringIndexFast( - iteratingString, thisIndex, HasUnicodeFlag(flags)); - - // 3. Perform ? Set(R, "lastIndex", nextIndex, true). - FastStoreLastIndex(iteratingRegExp, nextIndex); - } - - // iii. Return ! CreateIterResultObject(match, false). - return AllocateJSIteratorResult(match, False); - } - assert(!isFastRegExp); + } + // 11. Else, + // b. Else, handle non-global case first. + if (!flags.global) { + // i. Set O.[[Done]] to true. + receiver.flags.done = true; + + // ii. Return ! CreateIterResultObject(match, false). + return AllocateJSIteratorResult(UnsafeCast(match), False); + } + // a. If global is true, + assert(flags.global); + if (isFastRegExp) { // i. Let matchStr be ? ToString(? Get(match, "0")). - const match = UnsafeCast(match); - const matchStr = ToString_Inline(GetProperty(match, SmiConstant(0))); - + const match = UnsafeCast(match); + const resultFixedArray = UnsafeCast(match.elements); + const matchStr = UnsafeCast(resultFixedArray.objects[0]); + + // When iterating_regexp is fast, we assume it stays fast even after + // accessing the first match from the RegExp result. + assert(IsFastRegExpPermissive(iteratingRegExp)); + const iteratingRegExp = UnsafeCast(iteratingRegExp); if (matchStr == kEmptyString) { // 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")). - const lastIndex: JSAny = SlowLoadLastIndex(iteratingRegExp); - const thisIndex: Number = ToLength_Inline(lastIndex); + const thisIndex: Smi = FastLoadLastIndex(iteratingRegExp); // 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, // fullUnicode). - const nextIndex: Number = AdvanceStringIndexSlow( - iteratingString, thisIndex, HasUnicodeFlag(flags)); + const nextIndex: Smi = + AdvanceStringIndexFast(iteratingString, thisIndex, flags.unicode); // 3. Perform ? Set(R, "lastIndex", nextIndex, true). - SlowStoreLastIndex(iteratingRegExp, nextIndex); + FastStoreLastIndex(iteratingRegExp, nextIndex); } + // iii. Return ! CreateIterResultObject(match, false). return AllocateJSIteratorResult(match, False); } - // 10. If match is null, then - label IfNoMatch { - // a. Set O.[[Done]] to true. - SetDoneFlag(receiver, flags); - - // b. Return ! CreateIterResultObject(undefined, true). - goto ReturnEmptyDoneResult; + assert(!isFastRegExp); + // i. Let matchStr be ? ToString(? Get(match, "0")). + const match = UnsafeCast(match); + const matchStr = ToString_Inline(GetProperty(match, SmiConstant(0))); + + if (matchStr == kEmptyString) { + // 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")). + const lastIndex: JSAny = SlowLoadLastIndex(iteratingRegExp); + const thisIndex: Number = ToLength_Inline(lastIndex); + + // 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, + // fullUnicode). + const nextIndex: Number = + AdvanceStringIndexSlow(iteratingString, thisIndex, flags.unicode); + + // 3. Perform ? Set(R, "lastIndex", nextIndex, true). + SlowStoreLastIndex(iteratingRegExp, nextIndex); } + // iii. Return ! CreateIterResultObject(match, false). + return AllocateJSIteratorResult(match, False); } - label ReturnEmptyDoneResult { - return AllocateJSIteratorResult(Undefined, True); + // 10. If match is null, then + label IfNoMatch { + // a. Set O.[[Done]] to true. + receiver.flags.done = true; + + // b. Return ! CreateIterResultObject(undefined, true). + goto ReturnEmptyDoneResult; } + } label ReturnEmptyDoneResult { + return AllocateJSIteratorResult(Undefined, True); } } +} diff --git a/deps/v8/src/builtins/regexp-match.tq b/deps/v8/src/builtins/regexp-match.tq index 9b0255762c0f8a..d5581e050936f9 100644 --- a/deps/v8/src/builtins/regexp-match.tq +++ b/deps/v8/src/builtins/regexp-match.tq @@ -6,160 +6,157 @@ namespace regexp { - const kATOM: constexpr int31 - generates 'JSRegExp::ATOM'; - const kTagIndex: constexpr int31 - generates 'JSRegExp::kTagIndex'; - const kAtomPatternIndex: constexpr int31 - generates 'JSRegExp::kAtomPatternIndex'; - - extern transitioning macro RegExpBuiltinsAssembler::FlagGetter( - implicit context: Context)(Object, constexpr Flag, constexpr bool): bool; - - extern macro UnsafeLoadFixedArrayElement(RegExpMatchInfo, constexpr int31): - Object; - - transitioning macro RegExpPrototypeMatchBody(implicit context: Context)( - regexp: JSReceiver, string: String, isFastPath: constexpr bool): JSAny { - if constexpr (isFastPath) { - assert(Is(regexp)); - } +const kATOM: constexpr int31 + generates 'JSRegExp::ATOM'; +const kTagIndex: constexpr int31 + generates 'JSRegExp::kTagIndex'; +const kAtomPatternIndex: constexpr int31 + generates 'JSRegExp::kAtomPatternIndex'; + +extern transitioning macro RegExpBuiltinsAssembler::FlagGetter( + implicit context: Context)(Object, constexpr Flag, constexpr bool): bool; + +extern macro UnsafeLoadFixedArrayElement( + RegExpMatchInfo, constexpr int31): Object; + +transitioning macro RegExpPrototypeMatchBody(implicit context: Context)( + regexp: JSReceiver, string: String, isFastPath: constexpr bool): JSAny { + if constexpr (isFastPath) { + assert(Is(regexp)); + } - const isGlobal: bool = FlagGetter(regexp, Flag::kGlobal, isFastPath); + const isGlobal: bool = FlagGetter(regexp, Flag::kGlobal, isFastPath); - if (!isGlobal) { - return isFastPath ? RegExpPrototypeExecBodyFast(regexp, string) : - RegExpExec(regexp, string); - } + if (!isGlobal) { + return isFastPath ? RegExpPrototypeExecBodyFast(regexp, string) : + RegExpExec(regexp, string); + } - assert(isGlobal); - const isUnicode: bool = FlagGetter(regexp, Flag::kUnicode, isFastPath); + assert(isGlobal); + const isUnicode: bool = FlagGetter(regexp, Flag::kUnicode, isFastPath); - StoreLastIndex(regexp, 0, isFastPath); + StoreLastIndex(regexp, 0, isFastPath); - // Allocate an array to store the resulting match strings. + // Allocate an array to store the resulting match strings. - let array = growable_fixed_array::NewGrowableFixedArray(); + let array = growable_fixed_array::NewGrowableFixedArray(); - // Check if the regexp is an ATOM type. If so, then keep the literal string - // to search for so that we can avoid calling substring in the loop below. - let atom: bool = false; - let searchString: String = EmptyStringConstant(); - if constexpr (isFastPath) { - const maybeAtomRegexp = UnsafeCast(regexp); - const data = UnsafeCast(maybeAtomRegexp.data); - if (UnsafeCast(data.objects[kTagIndex]) == kATOM) { - searchString = UnsafeCast(data.objects[kAtomPatternIndex]); - atom = true; - } + // Check if the regexp is an ATOM type. If so, then keep the literal string + // to search for so that we can avoid calling substring in the loop below. + let atom: bool = false; + let searchString: String = EmptyStringConstant(); + if constexpr (isFastPath) { + const maybeAtomRegexp = UnsafeCast(regexp); + const data = UnsafeCast(maybeAtomRegexp.data); + if (UnsafeCast(data.objects[kTagIndex]) == kATOM) { + searchString = UnsafeCast(data.objects[kAtomPatternIndex]); + atom = true; } + } - while (true) { - let match: String = EmptyStringConstant(); - try { - if constexpr (isFastPath) { - // On the fast path, grab the matching string from the raw match index - // array. - const matchIndices: RegExpMatchInfo = - RegExpPrototypeExecBodyWithoutResultFast( - UnsafeCast(regexp), string) otherwise IfDidNotMatch; - if (atom) { - match = searchString; - } else { - const matchFrom = UnsafeLoadFixedArrayElement( - matchIndices, kRegExpMatchInfoFirstCaptureIndex); - const matchTo = UnsafeLoadFixedArrayElement( - matchIndices, kRegExpMatchInfoFirstCaptureIndex + 1); - match = SubString( - string, UnsafeCast(matchFrom), UnsafeCast(matchTo)); - } + while (true) { + let match: String = EmptyStringConstant(); + try { + if constexpr (isFastPath) { + // On the fast path, grab the matching string from the raw match index + // array. + const matchIndices: RegExpMatchInfo = + RegExpPrototypeExecBodyWithoutResultFast( + UnsafeCast(regexp), string) otherwise IfDidNotMatch; + if (atom) { + match = searchString; } else { - assert(!isFastPath); - const resultTemp = RegExpExec(regexp, string); - if (resultTemp == Null) { - goto IfDidNotMatch; - } - match = ToString_Inline(GetProperty(resultTemp, SmiConstant(0))); + const matchFrom = UnsafeLoadFixedArrayElement( + matchIndices, kRegExpMatchInfoFirstCaptureIndex); + const matchTo = UnsafeLoadFixedArrayElement( + matchIndices, kRegExpMatchInfoFirstCaptureIndex + 1); + match = SubString( + string, UnsafeCast(matchFrom), UnsafeCast(matchTo)); + } + } else { + assert(!isFastPath); + const resultTemp = RegExpExec(regexp, string); + if (resultTemp == Null) { + goto IfDidNotMatch; } - goto IfDidMatch; + match = ToString_Inline(GetProperty(resultTemp, SmiConstant(0))); } - label IfDidNotMatch { - return array.length == 0 ? Null : array.ToJSArray(); + goto IfDidMatch; + } label IfDidNotMatch { + return array.length == 0 ? Null : array.ToJSArray(); + } label IfDidMatch { + // Store the match, growing the fixed array if needed. + + array.Push(match); + + // Advance last index if the match is the empty string. + const matchLength: Smi = match.length_smi; + if (matchLength != 0) { + continue; + } + let lastIndex = LoadLastIndex(regexp, isFastPath); + if constexpr (isFastPath) { + assert(TaggedIsPositiveSmi(lastIndex)); + } else { + lastIndex = ToLength_Inline(lastIndex); } - label IfDidMatch { - // Store the match, growing the fixed array if needed. - - array.Push(match); - - // Advance last index if the match is the empty string. - const matchLength: Smi = match.length_smi; - if (matchLength != 0) { - continue; - } - let lastIndex = LoadLastIndex(regexp, isFastPath); - if constexpr (isFastPath) { - assert(TaggedIsPositiveSmi(lastIndex)); - } else { - lastIndex = ToLength_Inline(lastIndex); - } - - const newLastIndex: Number = AdvanceStringIndex( - string, UnsafeCast(lastIndex), isUnicode, isFastPath); - - if constexpr (isFastPath) { - // On the fast path, we can be certain that lastIndex can never be - // incremented to overflow the Smi range since the maximal string - // length is less than the maximal Smi value. - const kMaxStringLengthFitsSmi: constexpr bool = - kStringMaxLengthUintptr < kSmiMaxValue; - StaticAssert(kMaxStringLengthFitsSmi); - assert(TaggedIsPositiveSmi(newLastIndex)); - } - StoreLastIndex(regexp, newLastIndex, isFastPath); + const newLastIndex: Number = AdvanceStringIndex( + string, UnsafeCast(lastIndex), isUnicode, isFastPath); + + if constexpr (isFastPath) { + // On the fast path, we can be certain that lastIndex can never be + // incremented to overflow the Smi range since the maximal string + // length is less than the maximal Smi value. + const kMaxStringLengthFitsSmi: constexpr bool = + kStringMaxLengthUintptr < kSmiMaxValue; + StaticAssert(kMaxStringLengthFitsSmi); + assert(TaggedIsPositiveSmi(newLastIndex)); } - } - VerifiedUnreachable(); + StoreLastIndex(regexp, newLastIndex, isFastPath); + } } - transitioning macro FastRegExpPrototypeMatchBody(implicit context: Context)( - receiver: FastJSRegExp, string: String): JSAny { - return RegExpPrototypeMatchBody(receiver, string, true); - } + VerifiedUnreachable(); +} - transitioning macro SlowRegExpPrototypeMatchBody(implicit context: Context)( - receiver: JSReceiver, string: String): JSAny { - return RegExpPrototypeMatchBody(receiver, string, false); - } +transitioning macro FastRegExpPrototypeMatchBody(implicit context: Context)( + receiver: FastJSRegExp, string: String): JSAny { + return RegExpPrototypeMatchBody(receiver, string, true); +} - // Helper that skips a few initial checks. and assumes... - // 1) receiver is a "fast" RegExp - // 2) pattern is a string - transitioning builtin RegExpMatchFast(implicit context: Context)( - receiver: FastJSRegExp, string: String): JSAny { - return FastRegExpPrototypeMatchBody(receiver, string); - } +transitioning macro SlowRegExpPrototypeMatchBody(implicit context: Context)( + receiver: JSReceiver, string: String): JSAny { + return RegExpPrototypeMatchBody(receiver, string, false); +} - // ES#sec-regexp.prototype-@@match - // RegExp.prototype [ @@match ] ( string ) - transitioning javascript builtin RegExpPrototypeMatch( - js-implicit context: NativeContext, - receiver: JSAny)(string: JSAny): JSAny { - ThrowIfNotJSReceiver( - receiver, MessageTemplate::kIncompatibleMethodReceiver, - 'RegExp.prototype.@@match'); - const receiver = UnsafeCast(receiver); - const string: String = ToString_Inline(string); - - // Strict: Reads global and unicode properties. - // TODO(jgruber): Handle slow flag accesses on the fast path and make this - // permissive. - const fastRegExp = Cast(receiver) - otherwise return SlowRegExpPrototypeMatchBody(receiver, string); - - // TODO(pwong): Could be optimized to remove the overhead of calling the - // builtin (at the cost of a larger builtin). - return RegExpMatchFast(fastRegExp, string); - } +// Helper that skips a few initial checks. and assumes... +// 1) receiver is a "fast" RegExp +// 2) pattern is a string +transitioning builtin RegExpMatchFast(implicit context: Context)( + receiver: FastJSRegExp, string: String): JSAny { + return FastRegExpPrototypeMatchBody(receiver, string); +} + +// ES#sec-regexp.prototype-@@match +// RegExp.prototype [ @@match ] ( string ) +transitioning javascript builtin RegExpPrototypeMatch( + js-implicit context: NativeContext, receiver: JSAny)(string: JSAny): JSAny { + ThrowIfNotJSReceiver( + receiver, MessageTemplate::kIncompatibleMethodReceiver, + 'RegExp.prototype.@@match'); + const receiver = UnsafeCast(receiver); + const string: String = ToString_Inline(string); + + // Strict: Reads global and unicode properties. + // TODO(jgruber): Handle slow flag accesses on the fast path and make this + // permissive. + const fastRegExp = Cast(receiver) + otherwise return SlowRegExpPrototypeMatchBody(receiver, string); + + // TODO(pwong): Could be optimized to remove the overhead of calling the + // builtin (at the cost of a larger builtin). + return RegExpMatchFast(fastRegExp, string); +} } diff --git a/deps/v8/src/builtins/regexp-replace.tq b/deps/v8/src/builtins/regexp-replace.tq index fc9d13cf3c6237..c59a41b27f6653 100644 --- a/deps/v8/src/builtins/regexp-replace.tq +++ b/deps/v8/src/builtins/regexp-replace.tq @@ -6,259 +6,252 @@ namespace regexp { - extern builtin - SubString(implicit context: Context)(String, Smi, Smi): String; - - extern runtime RegExpExecMultiple(implicit context: Context)( - JSRegExp, String, RegExpMatchInfo, JSArray): Null|JSArray; - extern transitioning runtime - RegExpReplaceRT(Context, JSReceiver, String, Object): String; - extern transitioning runtime - StringBuilderConcat(implicit context: Context)(JSArray, Smi, String): String; - extern transitioning runtime - StringReplaceNonGlobalRegExpWithFunction(implicit context: Context)( - String, JSRegExp, Callable): String; - - transitioning macro RegExpReplaceCallableNoExplicitCaptures(implicit context: - Context)( - matchesElements: FixedArray, matchesLength: intptr, string: String, - replaceFn: Callable) { - let matchStart: Smi = 0; - for (let i: intptr = 0; i < matchesLength; i++) { - typeswitch (matchesElements.objects[i]) { - // Element represents a slice. - case (elSmi: Smi): { - // The slice's match start and end is either encoded as one or two - // smis. A positive smi indicates a single smi encoding (see - // ReplacementStringBuilder::AddSubjectSlice()). - if (elSmi > 0) { - // For single smi encoding, see - // StringBuilderSubstringLength::encode() and - // StringBuilderSubstringPosition::encode(). - const elInt: intptr = Convert(elSmi); - const newMatchStart: intptr = (elInt >> 11) + (elInt & 0x7FF); - matchStart = Convert(newMatchStart); - } else { - // For two smi encoding, the length is negative followed by the - // match start. - const nextEl: Smi = UnsafeCast(matchesElements.objects[++i]); - matchStart = nextEl - elSmi; - } - } - // Element represents the matched substring, which is then passed to the - // replace function. - case (elString: String): { - const replacementObj: JSAny = - Call(context, replaceFn, Undefined, elString, matchStart, string); - const replacement: String = ToString_Inline(replacementObj); - matchesElements.objects[i] = replacement; - matchStart += elString.length_smi; - } - case (Object): deferred { - unreachable; +extern builtin +SubString(implicit context: Context)(String, Smi, Smi): String; + +extern runtime RegExpExecMultiple(implicit context: Context)( + JSRegExp, String, RegExpMatchInfo, JSArray): Null|JSArray; +extern transitioning runtime +RegExpReplaceRT(Context, JSReceiver, String, Object): String; +extern transitioning runtime +StringBuilderConcat(implicit context: Context)(JSArray, Smi, String): String; +extern transitioning runtime +StringReplaceNonGlobalRegExpWithFunction(implicit context: Context)( + String, JSRegExp, Callable): String; + +transitioning macro RegExpReplaceCallableNoExplicitCaptures( + implicit context: Context)( + matchesElements: FixedArray, matchesLength: intptr, string: String, + replaceFn: Callable) { + let matchStart: Smi = 0; + for (let i: intptr = 0; i < matchesLength; i++) { + typeswitch (matchesElements.objects[i]) { + // Element represents a slice. + case (elSmi: Smi): { + // The slice's match start and end is either encoded as one or two + // smis. A positive smi indicates a single smi encoding (see + // ReplacementStringBuilder::AddSubjectSlice()). + if (elSmi > 0) { + // For single smi encoding, see + // StringBuilderSubstringLength::encode() and + // StringBuilderSubstringPosition::encode(). + const elInt: intptr = Convert(elSmi); + const newMatchStart: intptr = (elInt >> 11) + (elInt & 0x7FF); + matchStart = Convert(newMatchStart); + } else { + // For two smi encoding, the length is negative followed by the + // match start. + const nextEl: Smi = UnsafeCast(matchesElements.objects[++i]); + matchStart = nextEl - elSmi; } } + // Element represents the matched substring, which is then passed to the + // replace function. + case (elString: String): { + const replacementObj: JSAny = + Call(context, replaceFn, Undefined, elString, matchStart, string); + const replacement: String = ToString_Inline(replacementObj); + matchesElements.objects[i] = replacement; + matchStart += elString.length_smi; + } + case (Object): deferred { + unreachable; + } } } +} - transitioning macro - RegExpReplaceCallableWithExplicitCaptures(implicit context: Context)( - matchesElements: FixedArray, matchesLength: intptr, replaceFn: Callable) { - for (let i: intptr = 0; i < matchesLength; i++) { - const elArray = - Cast(matchesElements.objects[i]) otherwise continue; - - // The JSArray is expanded into the function args by Reflect.apply(). - // TODO(jgruber): Remove indirection through Call->ReflectApply. - const replacementObj: JSAny = Call( - context, GetReflectApply(), Undefined, replaceFn, Undefined, elArray); - - // Overwrite the i'th element in the results with the string - // we got back from the callback function. - matchesElements.objects[i] = ToString_Inline(replacementObj); - } +transitioning macro +RegExpReplaceCallableWithExplicitCaptures(implicit context: Context)( + matchesElements: FixedArray, matchesLength: intptr, replaceFn: Callable) { + for (let i: intptr = 0; i < matchesLength; i++) { + const elArray = + Cast(matchesElements.objects[i]) otherwise continue; + + // The JSArray is expanded into the function args by Reflect.apply(). + // TODO(jgruber): Remove indirection through Call->ReflectApply. + const replacementObj: JSAny = Call( + context, GetReflectApply(), Undefined, replaceFn, Undefined, elArray); + + // Overwrite the i'th element in the results with the string + // we got back from the callback function. + matchesElements.objects[i] = ToString_Inline(replacementObj); } +} - transitioning macro RegExpReplaceFastGlobalCallable(implicit context: - Context)( - regexp: FastJSRegExp, string: String, replaceFn: Callable): String { - regexp.lastIndex = 0; - - const kInitialCapacity: intptr = 16; - const kInitialLength: Smi = 0; - const result: Null|JSArray = RegExpExecMultiple( - regexp, string, GetRegExpLastMatchInfo(), - AllocateJSArray( - ElementsKind::PACKED_ELEMENTS, GetFastPackedElementsJSArrayMap(), - kInitialCapacity, kInitialLength)); - - regexp.lastIndex = 0; - - // If no matches, return the subject string. - if (result == Null) return string; - - const matches: JSArray = UnsafeCast(result); - const matchesLength: Smi = Cast(matches.length) otherwise unreachable; - const matchesLengthInt: intptr = Convert(matchesLength); - const matchesElements: FixedArray = - UnsafeCast(matches.elements); - - // Reload last match info since it might have changed. - const nofCaptures: Smi = GetRegExpLastMatchInfo().NumberOfCaptures(); - - // If the number of captures is two then there are no explicit captures in - // the regexp, just the implicit capture that captures the whole match. In - // this case we can simplify quite a bit and end up with something faster. - if (nofCaptures == 2) { - RegExpReplaceCallableNoExplicitCaptures( - matchesElements, matchesLengthInt, string, replaceFn); - } else { - RegExpReplaceCallableWithExplicitCaptures( - matchesElements, matchesLengthInt, replaceFn); - } - - return StringBuilderConcat(matches, matchesLength, string); +transitioning macro RegExpReplaceFastGlobalCallable(implicit context: Context)( + regexp: FastJSRegExp, string: String, replaceFn: Callable): String { + regexp.lastIndex = 0; + + const kInitialCapacity: intptr = 16; + const kInitialLength: Smi = 0; + const result: Null|JSArray = RegExpExecMultiple( + regexp, string, GetRegExpLastMatchInfo(), + AllocateJSArray( + ElementsKind::PACKED_ELEMENTS, GetFastPackedElementsJSArrayMap(), + kInitialCapacity, kInitialLength)); + + regexp.lastIndex = 0; + + // If no matches, return the subject string. + if (result == Null) return string; + + const matches: JSArray = UnsafeCast(result); + const matchesLength: Smi = Cast(matches.length) otherwise unreachable; + const matchesLengthInt: intptr = Convert(matchesLength); + const matchesElements: FixedArray = UnsafeCast(matches.elements); + + // Reload last match info since it might have changed. + const nofCaptures: Smi = GetRegExpLastMatchInfo().NumberOfCaptures(); + + // If the number of captures is two then there are no explicit captures in + // the regexp, just the implicit capture that captures the whole match. In + // this case we can simplify quite a bit and end up with something faster. + if (nofCaptures == 2) { + RegExpReplaceCallableNoExplicitCaptures( + matchesElements, matchesLengthInt, string, replaceFn); + } else { + RegExpReplaceCallableWithExplicitCaptures( + matchesElements, matchesLengthInt, replaceFn); } - transitioning macro RegExpReplaceFastString(implicit context: Context)( - regexp: JSRegExp, string: String, replaceString: String): String { - // The fast path is reached only if {receiver} is an unmodified JSRegExp - // instance, {replace_value} is non-callable, and ToString({replace_value}) - // does not contain '$', i.e. we're doing a simple string replacement. - let result: String = kEmptyString; - let lastMatchEnd: Smi = 0; - let unicode: bool = false; - const replaceLength: Smi = replaceString.length_smi; - const fastRegexp = UnsafeCast(regexp); - const global: bool = fastRegexp.global; - - if (global) { - unicode = fastRegexp.unicode; - fastRegexp.lastIndex = 0; - } - - while (true) { - const match: RegExpMatchInfo = - RegExpPrototypeExecBodyWithoutResultFast(regexp, string) - otherwise break; - const matchStart: Smi = match.GetStartOfCapture(0); - const matchEnd: Smi = match.GetEndOfCapture(0); - - // TODO(jgruber): We could skip many of the checks that using SubString - // here entails. - result = result + SubString(string, lastMatchEnd, matchStart); - lastMatchEnd = matchEnd; - - if (replaceLength != 0) result = result + replaceString; - - // Non-global case ends here after the first replacement. - if (!global) break; - - // If match is the empty string, we have to increment lastIndex. - if (matchEnd == matchStart) { - typeswitch (regexp) { - case (fastRegexp: FastJSRegExp): { - fastRegexp.lastIndex = - AdvanceStringIndexFast(string, fastRegexp.lastIndex, unicode); - } - case (Object): { - const lastIndex: JSAny = SlowLoadLastIndex(regexp); - const thisIndex: Number = ToLength_Inline(lastIndex); - const nextIndex: Number = - AdvanceStringIndexSlow(string, thisIndex, unicode); - SlowStoreLastIndex(regexp, nextIndex); - } - } - } - } + return StringBuilderConcat(matches, matchesLength, string); +} - return result + SubString(string, lastMatchEnd, string.length_smi); +transitioning macro RegExpReplaceFastString(implicit context: Context)( + regexp: JSRegExp, string: String, replaceString: String): String { + // The fast path is reached only if {receiver} is an unmodified JSRegExp + // instance, {replace_value} is non-callable, and ToString({replace_value}) + // does not contain '$', i.e. we're doing a simple string replacement. + let result: String = kEmptyString; + let lastMatchEnd: Smi = 0; + let unicode: bool = false; + const replaceLength: Smi = replaceString.length_smi; + const fastRegexp = UnsafeCast(regexp); + const global: bool = fastRegexp.global; + + if (global) { + unicode = fastRegexp.unicode; + fastRegexp.lastIndex = 0; } - transitioning builtin RegExpReplace(implicit context: Context)( - regexp: FastJSRegExp, string: String, replaceValue: JSAny): String { - // TODO(pwong): Remove assert when all callers (StringPrototypeReplace) are - // from Torque. - assert(Is(regexp)); - - // 2. Is {replace_value} callable? - typeswitch (replaceValue) { - case (replaceFn: Callable): { - return regexp.global ? - RegExpReplaceFastGlobalCallable(regexp, string, replaceFn) : - StringReplaceNonGlobalRegExpWithFunction(string, regexp, replaceFn); - } - case (JSAny): { - const stableRegexp: JSRegExp = regexp; - const replaceString: String = ToString_Inline(replaceValue); - - try { - // ToString(replaceValue) could potentially change the shape of the - // RegExp object. Recheck that we are still on the fast path and bail - // to runtime otherwise. - const fastRegexp = Cast(stableRegexp) otherwise Runtime; - if (StringIndexOf( - replaceString, SingleCharacterStringConstant('$'), 0) != -1) { - goto Runtime; - } - - return RegExpReplaceFastString(fastRegexp, string, replaceString); + while (true) { + const match: RegExpMatchInfo = + RegExpPrototypeExecBodyWithoutResultFast(regexp, string) + otherwise break; + const matchStart: Smi = match.GetStartOfCapture(0); + const matchEnd: Smi = match.GetEndOfCapture(0); + + // TODO(jgruber): We could skip many of the checks that using SubString + // here entails. + result = result + SubString(string, lastMatchEnd, matchStart); + lastMatchEnd = matchEnd; + + if (replaceLength != 0) result = result + replaceString; + + // Non-global case ends here after the first replacement. + if (!global) break; + + // If match is the empty string, we have to increment lastIndex. + if (matchEnd == matchStart) { + typeswitch (regexp) { + case (fastRegexp: FastJSRegExp): { + fastRegexp.lastIndex = + AdvanceStringIndexFast(string, fastRegexp.lastIndex, unicode); } - label Runtime deferred { - return RegExpReplaceRT(context, stableRegexp, string, replaceString); + case (Object): { + const lastIndex: JSAny = SlowLoadLastIndex(regexp); + const thisIndex: Number = ToLength_Inline(lastIndex); + const nextIndex: Number = + AdvanceStringIndexSlow(string, thisIndex, unicode); + SlowStoreLastIndex(regexp, nextIndex); } } } } - const kRegExpReplaceCalledOnSlowRegExp: constexpr int31 - generates 'v8::Isolate::kRegExpReplaceCalledOnSlowRegExp'; - - transitioning javascript builtin RegExpPrototypeReplace( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - const methodName: constexpr string = 'RegExp.prototype.@@replace'; - - // RegExpPrototypeReplace is a bit of a beast - a summary of dispatch logic: - // - // if (!IsFastRegExp(receiver)) CallRuntime(RegExpReplace) - // if (IsCallable(replace)) { - // if (IsGlobal(receiver)) { - // // Called 'fast-path' but contains several runtime calls. - // RegExpReplaceFastGlobalCallable() - // } else { - // CallRuntime(StringReplaceNonGlobalRegExpWithFunction) - // } - // } else { - // if (replace.contains("$")) { - // CallRuntime(RegExpReplace) - // } else { - // RegExpReplaceFastString() - // } - // } - - const string: JSAny = arguments[0]; - const replaceValue: JSAny = arguments[1]; - - // Let rx be the this value. - // If Type(rx) is not Object, throw a TypeError exception. - const rx = Cast(receiver) - otherwise ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, methodName); - - // Let S be ? ToString(string). - const s = ToString_Inline(string); - - // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? - try { - const fastRx: FastJSRegExp = Cast(rx) otherwise Runtime; - return RegExpReplace(fastRx, s, replaceValue); + return result + SubString(string, lastMatchEnd, string.length_smi); +} + +transitioning builtin RegExpReplace(implicit context: Context)( + regexp: FastJSRegExp, string: String, replaceValue: JSAny): String { + // TODO(pwong): Remove assert when all callers (StringPrototypeReplace) are + // from Torque. + assert(Is(regexp)); + + // 2. Is {replace_value} callable? + typeswitch (replaceValue) { + case (replaceFn: Callable): { + return regexp.global ? + RegExpReplaceFastGlobalCallable(regexp, string, replaceFn) : + StringReplaceNonGlobalRegExpWithFunction(string, regexp, replaceFn); } - label Runtime deferred { - IncrementUseCounter( - context, SmiConstant(kRegExpReplaceCalledOnSlowRegExp)); - return RegExpReplaceRT(context, rx, s, replaceValue); + case (JSAny): { + const stableRegexp: JSRegExp = regexp; + const replaceString: String = ToString_Inline(replaceValue); + + try { + // ToString(replaceValue) could potentially change the shape of the + // RegExp object. Recheck that we are still on the fast path and bail + // to runtime otherwise. + const fastRegexp = Cast(stableRegexp) otherwise Runtime; + if (StringIndexOf( + replaceString, SingleCharacterStringConstant('$'), 0) != -1) { + goto Runtime; + } + + return RegExpReplaceFastString(fastRegexp, string, replaceString); + } label Runtime deferred { + return RegExpReplaceRT(context, stableRegexp, string, replaceString); + } } } +} +const kRegExpReplaceCalledOnSlowRegExp: constexpr int31 + generates 'v8::Isolate::kRegExpReplaceCalledOnSlowRegExp'; + +transitioning javascript builtin RegExpPrototypeReplace( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + const methodName: constexpr string = 'RegExp.prototype.@@replace'; + + // RegExpPrototypeReplace is a bit of a beast - a summary of dispatch logic: + // + // if (!IsFastRegExp(receiver)) CallRuntime(RegExpReplace) + // if (IsCallable(replace)) { + // if (IsGlobal(receiver)) { + // // Called 'fast-path' but contains several runtime calls. + // RegExpReplaceFastGlobalCallable() + // } else { + // CallRuntime(StringReplaceNonGlobalRegExpWithFunction) + // } + // } else { + // if (replace.contains("$")) { + // CallRuntime(RegExpReplace) + // } else { + // RegExpReplaceFastString() + // } + // } + + const string: JSAny = arguments[0]; + const replaceValue: JSAny = arguments[1]; + + // Let rx be the this value. + // If Type(rx) is not Object, throw a TypeError exception. + const rx = Cast(receiver) + otherwise ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, methodName); + + // Let S be ? ToString(string). + const s = ToString_Inline(string); + + // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? + try { + const fastRx: FastJSRegExp = Cast(rx) otherwise Runtime; + return RegExpReplace(fastRx, s, replaceValue); + } label Runtime deferred { + IncrementUseCounter(context, SmiConstant(kRegExpReplaceCalledOnSlowRegExp)); + return RegExpReplaceRT(context, rx, s, replaceValue); + } +} } diff --git a/deps/v8/src/builtins/regexp-search.tq b/deps/v8/src/builtins/regexp-search.tq index 14fb9f9b03c202..b70d23a0dd5a0b 100644 --- a/deps/v8/src/builtins/regexp-search.tq +++ b/deps/v8/src/builtins/regexp-search.tq @@ -6,103 +6,101 @@ namespace regexp { - transitioning macro - RegExpPrototypeSearchBodyFast(implicit context: Context)( - regexp: JSRegExp, string: String): JSAny { - assert(IsFastRegExpPermissive(regexp)); - - // Grab the initial value of last index. - const previousLastIndex: Smi = FastLoadLastIndex(regexp); - - // Ensure last index is 0. - FastStoreLastIndex(regexp, 0); - - // Call exec. - try { - const matchIndices: RegExpMatchInfo = - RegExpPrototypeExecBodyWithoutResultFast( - UnsafeCast(regexp), string) - otherwise DidNotMatch; - - // Successful match. - // Reset last index. - FastStoreLastIndex(regexp, previousLastIndex); - - // Return the index of the match. - return UnsafeCast( - matchIndices.objects[kRegExpMatchInfoFirstCaptureIndex]); - } - label DidNotMatch { - // Reset last index and return -1. - FastStoreLastIndex(regexp, previousLastIndex); - return SmiConstant(-1); - } - } +transitioning macro +RegExpPrototypeSearchBodyFast(implicit context: Context)( + regexp: JSRegExp, string: String): JSAny { + assert(IsFastRegExpPermissive(regexp)); + + // Grab the initial value of last index. + const previousLastIndex: Smi = FastLoadLastIndex(regexp); + + // Ensure last index is 0. + FastStoreLastIndex(regexp, 0); + + // Call exec. + try { + const matchIndices: RegExpMatchInfo = + RegExpPrototypeExecBodyWithoutResultFast( + UnsafeCast(regexp), string) + otherwise DidNotMatch; - extern macro RegExpBuiltinsAssembler::BranchIfRegExpResult( - implicit context: Context)(Object): never labels IsUnmodified, - IsModified; + // Successful match. + // Reset last index. + FastStoreLastIndex(regexp, previousLastIndex); - macro - IsRegExpResult(implicit context: Context)(execResult: HeapObject): bool { - BranchIfRegExpResult(execResult) otherwise return true, return false; + // Return the index of the match. + return UnsafeCast( + matchIndices.objects[kRegExpMatchInfoFirstCaptureIndex]); + } label DidNotMatch { + // Reset last index and return -1. + FastStoreLastIndex(regexp, previousLastIndex); + return SmiConstant(-1); } +} - transitioning macro RegExpPrototypeSearchBodySlow(implicit context: Context)( - regexp: JSReceiver, string: String): JSAny { - // Grab the initial value of last index. - const previousLastIndex = SlowLoadLastIndex(regexp); - const smiZero: Smi = 0; +extern macro RegExpBuiltinsAssembler::BranchIfRegExpResult( + implicit context: Context)(Object): never labels IsUnmodified, + IsModified; - // Ensure last index is 0. - if (!SameValue(previousLastIndex, smiZero)) { - SlowStoreLastIndex(regexp, smiZero); - } +macro +IsRegExpResult(implicit context: Context)(execResult: HeapObject): bool { + BranchIfRegExpResult(execResult) otherwise return true, return false; +} - // Call exec. - const execResult = RegExpExec(regexp, string); +transitioning macro RegExpPrototypeSearchBodySlow(implicit context: Context)( + regexp: JSReceiver, string: String): JSAny { + // Grab the initial value of last index. + const previousLastIndex = SlowLoadLastIndex(regexp); + const smiZero: Smi = 0; - // Reset last index if necessary. - const currentLastIndex = SlowLoadLastIndex(regexp); - if (!SameValue(currentLastIndex, previousLastIndex)) { - SlowStoreLastIndex(regexp, previousLastIndex); - } + // Ensure last index is 0. + if (!SameValue(previousLastIndex, smiZero)) { + SlowStoreLastIndex(regexp, smiZero); + } - // Return -1 if no match was found. - if (execResult == Null) { - return SmiConstant(-1); - } + // Call exec. + const execResult = RegExpExec(regexp, string); - // Return the index of the match. - const fastExecResult = Cast(execResult) - otherwise return GetProperty(execResult, 'index'); - return fastExecResult.index; + // Reset last index if necessary. + const currentLastIndex = SlowLoadLastIndex(regexp); + if (!SameValue(currentLastIndex, previousLastIndex)) { + SlowStoreLastIndex(regexp, previousLastIndex); } - // Helper that skips a few initial checks. and assumes... - // 1) receiver is a "fast permissive" RegExp - // 2) pattern is a string - transitioning builtin RegExpSearchFast(implicit context: Context)( - receiver: JSRegExp, string: String): JSAny { - return RegExpPrototypeSearchBodyFast(receiver, string); + // Return -1 if no match was found. + if (execResult == Null) { + return SmiConstant(-1); } - // ES#sec-regexp.prototype-@@search - // RegExp.prototype [ @@search ] ( string ) - transitioning javascript builtin RegExpPrototypeSearch( - js-implicit context: NativeContext, - receiver: JSAny)(string: JSAny): JSAny { - ThrowIfNotJSReceiver( - receiver, MessageTemplate::kIncompatibleMethodReceiver, - 'RegExp.prototype.@@search'); - const receiver = UnsafeCast(receiver); - const string: String = ToString_Inline(string); - - if (IsFastRegExpPermissive(receiver)) { - // TODO(pwong): Could be optimized to remove the overhead of calling the - // builtin (at the cost of a larger builtin). - return RegExpSearchFast(UnsafeCast(receiver), string); - } - return RegExpPrototypeSearchBodySlow(receiver, string); + // Return the index of the match. + const fastExecResult = Cast(execResult) + otherwise return GetProperty(execResult, 'index'); + return fastExecResult.index; +} + +// Helper that skips a few initial checks. and assumes... +// 1) receiver is a "fast permissive" RegExp +// 2) pattern is a string +transitioning builtin RegExpSearchFast(implicit context: Context)( + receiver: JSRegExp, string: String): JSAny { + return RegExpPrototypeSearchBodyFast(receiver, string); +} + +// ES#sec-regexp.prototype-@@search +// RegExp.prototype [ @@search ] ( string ) +transitioning javascript builtin RegExpPrototypeSearch( + js-implicit context: NativeContext, receiver: JSAny)(string: JSAny): JSAny { + ThrowIfNotJSReceiver( + receiver, MessageTemplate::kIncompatibleMethodReceiver, + 'RegExp.prototype.@@search'); + const receiver = UnsafeCast(receiver); + const string: String = ToString_Inline(string); + + if (IsFastRegExpPermissive(receiver)) { + // TODO(pwong): Could be optimized to remove the overhead of calling the + // builtin (at the cost of a larger builtin). + return RegExpSearchFast(UnsafeCast(receiver), string); } + return RegExpPrototypeSearchBodySlow(receiver, string); +} } diff --git a/deps/v8/src/builtins/regexp-source.tq b/deps/v8/src/builtins/regexp-source.tq index 009e5181dc2190..5f9c6b22c3a973 100644 --- a/deps/v8/src/builtins/regexp-source.tq +++ b/deps/v8/src/builtins/regexp-source.tq @@ -6,22 +6,22 @@ namespace regexp { - // ES6 21.2.5.10. - // ES #sec-get-regexp.prototype.source - transitioning javascript builtin RegExpPrototypeSourceGetter( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - typeswitch (receiver) { - case (receiver: JSRegExp): { - return receiver.source; - } - case (Object): { - } +// ES6 21.2.5.10. +// ES #sec-get-regexp.prototype.source +transitioning javascript builtin RegExpPrototypeSourceGetter( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + typeswitch (receiver) { + case (receiver: JSRegExp): { + return receiver.source; } - if (!IsReceiverInitialRegExpPrototype(receiver)) { - const methodName: constexpr string = 'RegExp.prototype.source'; - ThrowTypeError(MessageTemplate::kRegExpNonRegExp, methodName); + case (Object): { } - IncrementUseCounter(context, SmiConstant(kRegExpPrototypeSourceGetter)); - return '(?:)'; } + if (!IsReceiverInitialRegExpPrototype(receiver)) { + const methodName: constexpr string = 'RegExp.prototype.source'; + ThrowTypeError(MessageTemplate::kRegExpNonRegExp, methodName); + } + IncrementUseCounter(context, SmiConstant(kRegExpPrototypeSourceGetter)); + return '(?:)'; +} } diff --git a/deps/v8/src/builtins/regexp-split.tq b/deps/v8/src/builtins/regexp-split.tq index e4092803eeae9d..47ff214130f142 100644 --- a/deps/v8/src/builtins/regexp-split.tq +++ b/deps/v8/src/builtins/regexp-split.tq @@ -5,70 +5,68 @@ #include 'src/builtins/builtins-regexp-gen.h' namespace runtime { - extern transitioning runtime - RegExpSplit(implicit context: Context)(JSReceiver, String, Object): JSAny; +extern transitioning runtime +RegExpSplit(implicit context: Context)(JSReceiver, String, Object): JSAny; } // namespace runtime namespace regexp { - const kMaxValueSmi: constexpr int31 - generates 'Smi::kMaxValue'; +const kMaxValueSmi: constexpr int31 + generates 'Smi::kMaxValue'; - extern transitioning macro RegExpBuiltinsAssembler::RegExpPrototypeSplitBody( - implicit context: Context)(JSRegExp, String, Smi): JSArray; +extern transitioning macro RegExpBuiltinsAssembler::RegExpPrototypeSplitBody( + implicit context: Context)(JSRegExp, String, Smi): JSArray; - // Helper that skips a few initial checks. - transitioning builtin - RegExpSplit(implicit context: Context)( - regexp: FastJSRegExp, string: String, limit: JSAny): JSAny { - let sanitizedLimit: Smi; +// Helper that skips a few initial checks. +transitioning builtin +RegExpSplit(implicit context: Context)( + regexp: FastJSRegExp, string: String, limit: JSAny): JSAny { + let sanitizedLimit: Smi; - // We need to be extra-strict and require the given limit to be either - // undefined or a positive smi. We can't call ToUint32(maybe_limit) since - // that might move us onto the slow path, resulting in ordering spec - // violations (see https://crbug.com/801171). + // We need to be extra-strict and require the given limit to be either + // undefined or a positive smi. We can't call ToUint32(maybe_limit) since + // that might move us onto the slow path, resulting in ordering spec + // violations (see https://crbug.com/801171). - if (limit == Undefined) { - // TODO(jgruber): In this case, we can probably avoid generation of limit - // checks in Generate_RegExpPrototypeSplitBody. - sanitizedLimit = SmiConstant(kMaxValueSmi); - } else if (!TaggedIsPositiveSmi(limit)) { - return runtime::RegExpSplit(regexp, string, limit); - } else { - sanitizedLimit = UnsafeCast(limit); - } - - // Due to specific shortcuts we take on the fast path (specifically, we - // don't allocate a new regexp instance as specced), we need to ensure that - // the given regexp is non-sticky to avoid invalid results. See - // crbug.com/v8/6706. + if (limit == Undefined) { + // TODO(jgruber): In this case, we can probably avoid generation of limit + // checks in Generate_RegExpPrototypeSplitBody. + sanitizedLimit = SmiConstant(kMaxValueSmi); + } else if (!TaggedIsPositiveSmi(limit)) { + return runtime::RegExpSplit(regexp, string, limit); + } else { + sanitizedLimit = UnsafeCast(limit); + } - if (FastFlagGetter(regexp, Flag::kSticky)) { - return runtime::RegExpSplit(regexp, string, sanitizedLimit); - } + // Due to specific shortcuts we take on the fast path (specifically, we + // don't allocate a new regexp instance as specced), we need to ensure that + // the given regexp is non-sticky to avoid invalid results. See + // crbug.com/v8/6706. - // We're good to go on the fast path, which is inlined here. - return RegExpPrototypeSplitBody(regexp, string, sanitizedLimit); + if (FastFlagGetter(regexp, Flag::kSticky)) { + return runtime::RegExpSplit(regexp, string, sanitizedLimit); } - // ES#sec-regexp.prototype-@@split - // RegExp.prototype [ @@split ] ( string, limit ) - transitioning javascript builtin RegExpPrototypeSplit( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - ThrowIfNotJSReceiver( - receiver, MessageTemplate::kIncompatibleMethodReceiver, - 'RegExp.prototype.@@split'); - const receiver = UnsafeCast(receiver); - const string: String = ToString_Inline(arguments[0]); - const limit = arguments[1]; + // We're good to go on the fast path, which is inlined here. + return RegExpPrototypeSplitBody(regexp, string, sanitizedLimit); +} - // Strict: Reads the flags property. - // TODO(jgruber): Handle slow flag accesses on the fast path and make this - // permissive. - const fastRegExp = Cast(receiver) - otherwise return runtime::RegExpSplit(receiver, string, limit); - return RegExpSplit(fastRegExp, string, limit); - } +// ES#sec-regexp.prototype-@@split +// RegExp.prototype [ @@split ] ( string, limit ) +transitioning javascript builtin RegExpPrototypeSplit( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + ThrowIfNotJSReceiver( + receiver, MessageTemplate::kIncompatibleMethodReceiver, + 'RegExp.prototype.@@split'); + const receiver = UnsafeCast(receiver); + const string: String = ToString_Inline(arguments[0]); + const limit = arguments[1]; + // Strict: Reads the flags property. + // TODO(jgruber): Handle slow flag accesses on the fast path and make this + // permissive. + const fastRegExp = Cast(receiver) + otherwise return runtime::RegExpSplit(receiver, string, limit); + return RegExpSplit(fastRegExp, string, limit); +} } diff --git a/deps/v8/src/builtins/regexp-test.tq b/deps/v8/src/builtins/regexp-test.tq index cd418239757185..c83afd602de85c 100644 --- a/deps/v8/src/builtins/regexp-test.tq +++ b/deps/v8/src/builtins/regexp-test.tq @@ -6,30 +6,29 @@ namespace regexp { - // ES#sec-regexp.prototype.test - // RegExp.prototype.test ( S ) - transitioning javascript builtin RegExpPrototypeTest( - js-implicit context: NativeContext, - receiver: JSAny)(string: JSAny): JSAny { - const methodName: constexpr string = 'RegExp.prototype.test'; - const receiver = Cast(receiver) - otherwise ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, methodName); - const str: String = ToString_Inline(string); - if (IsFastRegExpPermissive(receiver)) { - RegExpPrototypeExecBodyWithoutResultFast( - UnsafeCast(receiver), str) - otherwise return False; - return True; - } - const matchIndices = RegExpExec(receiver, str); - return SelectBooleanConstant(matchIndices != Null); - } - - transitioning builtin RegExpPrototypeTestFast(implicit context: Context)( - receiver: JSRegExp, string: String): Object { - RegExpPrototypeExecBodyWithoutResultFast(receiver, string) +// ES#sec-regexp.prototype.test +// RegExp.prototype.test ( S ) +transitioning javascript builtin RegExpPrototypeTest( + js-implicit context: NativeContext, receiver: JSAny)(string: JSAny): JSAny { + const methodName: constexpr string = 'RegExp.prototype.test'; + const receiver = Cast(receiver) + otherwise ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, methodName); + const str: String = ToString_Inline(string); + if (IsFastRegExpPermissive(receiver)) { + RegExpPrototypeExecBodyWithoutResultFast( + UnsafeCast(receiver), str) otherwise return False; return True; } + const matchIndices = RegExpExec(receiver, str); + return SelectBooleanConstant(matchIndices != Null); +} + +transitioning builtin RegExpPrototypeTestFast(implicit context: Context)( + receiver: JSRegExp, string: String): Object { + RegExpPrototypeExecBodyWithoutResultFast(receiver, string) + otherwise return False; + return True; +} } diff --git a/deps/v8/src/builtins/regexp.tq b/deps/v8/src/builtins/regexp.tq index a48dce3863bacb..21577b47634569 100644 --- a/deps/v8/src/builtins/regexp.tq +++ b/deps/v8/src/builtins/regexp.tq @@ -6,417 +6,415 @@ namespace regexp { - extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp_Strict( - implicit context: Context)(HeapObject): never labels IsFast, - IsSlow; - macro IsFastRegExpStrict(implicit context: Context)(o: HeapObject): bool { - BranchIfFastRegExp_Strict(o) otherwise return true, return false; - } +extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp_Strict( + implicit context: Context)(HeapObject): never labels IsFast, + IsSlow; +macro IsFastRegExpStrict(implicit context: Context)(o: HeapObject): bool { + BranchIfFastRegExp_Strict(o) otherwise return true, return false; +} - extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp_Permissive( - implicit context: Context)(HeapObject): never labels IsFast, - IsSlow; +extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp_Permissive( + implicit context: Context)(HeapObject): never labels IsFast, + IsSlow; - @export - macro IsFastRegExpPermissive(implicit context: Context)(o: HeapObject): bool { - BranchIfFastRegExp_Permissive(o) otherwise return true, return false; - } +@export +macro IsFastRegExpPermissive(implicit context: Context)(o: HeapObject): bool { + BranchIfFastRegExp_Permissive(o) otherwise return true, return false; +} - // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) - @export - transitioning macro RegExpExec(implicit context: Context)( - receiver: JSReceiver, string: String): JSAny { - // Take the slow path of fetching the exec property, calling it, and - // verifying its return value. - - const exec = GetProperty(receiver, 'exec'); - - // Is {exec} callable? - typeswitch (exec) { - case (execCallable: Callable): { - const result = Call(context, execCallable, receiver, string); - if (result != Null) { - ThrowIfNotJSReceiver( - result, MessageTemplate::kInvalidRegExpExecResult, ''); - } - return result; - } - case (Object): { - const regexp = Cast(receiver) otherwise ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, - 'RegExp.prototype.exec', receiver); - return RegExpPrototypeExecSlow(regexp, string); +// ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) +@export +transitioning macro RegExpExec(implicit context: Context)( + receiver: JSReceiver, string: String): JSAny { + // Take the slow path of fetching the exec property, calling it, and + // verifying its return value. + + const exec = GetProperty(receiver, 'exec'); + + // Is {exec} callable? + typeswitch (exec) { + case (execCallable: Callable): { + const result = Call(context, execCallable, receiver, string); + if (result != Null) { + ThrowIfNotJSReceiver( + result, MessageTemplate::kInvalidRegExpExecResult, ''); } + return result; } - } - - extern macro RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo( - implicit context: Context)(JSRegExp, RegExpMatchInfo, String, Number): - JSRegExpResult; - - const kGlobalOrSticky: constexpr int31 - generates 'JSRegExp::kGlobal | JSRegExp::kSticky'; - - extern macro RegExpBuiltinsAssembler::RegExpExecInternal( - implicit context: Context)(JSRegExp, String, Number, RegExpMatchInfo): - HeapObject; - - // ES#sec-regexp.prototype.exec - // RegExp.prototype.exec ( string ) - // Implements the core of RegExp.prototype.exec but without actually - // constructing the JSRegExpResult. Returns a fixed array containing match - // indices as returned by RegExpExecStub on successful match, and jumps to - // IfDidNotMatch otherwise. - transitioning macro RegExpPrototypeExecBodyWithoutResult(implicit context: - Context)( - regexp: JSRegExp, string: String, regexpLastIndex: Number, - isFastPath: constexpr bool): RegExpMatchInfo labels IfDidNotMatch { - if (isFastPath) { - assert(HasInitialRegExpMap(regexp)); - } else { - IncrementUseCounter(context, SmiConstant(kRegExpExecCalledOnSlowRegExp)); + case (Object): { + const regexp = Cast(receiver) otherwise ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, 'RegExp.prototype.exec', + receiver); + return RegExpPrototypeExecSlow(regexp, string); } + } +} - let lastIndex = regexpLastIndex; +extern macro RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo( + implicit context: Context)( + JSRegExp, RegExpMatchInfo, String, Number): JSRegExpResult; + +const kGlobalOrSticky: constexpr int31 + generates 'JSRegExp::kGlobal | JSRegExp::kSticky'; + +extern macro RegExpBuiltinsAssembler::RegExpExecInternal( + implicit context: Context)( + JSRegExp, String, Number, RegExpMatchInfo): HeapObject; + +// ES#sec-regexp.prototype.exec +// RegExp.prototype.exec ( string ) +// Implements the core of RegExp.prototype.exec but without actually +// constructing the JSRegExpResult. Returns a fixed array containing match +// indices as returned by RegExpExecStub on successful match, and jumps to +// IfDidNotMatch otherwise. +transitioning macro RegExpPrototypeExecBodyWithoutResult( + implicit context: Context)( + regexp: JSRegExp, string: String, regexpLastIndex: Number, + isFastPath: constexpr bool): RegExpMatchInfo labels IfDidNotMatch { + if (isFastPath) { + assert(HasInitialRegExpMap(regexp)); + } else { + IncrementUseCounter(context, SmiConstant(kRegExpExecCalledOnSlowRegExp)); + } - // Check whether the regexp is global or sticky, which determines whether we - // update last index later on. - const flags = UnsafeCast(regexp.flags); - const isGlobalOrSticky: intptr = - SmiUntag(flags) & IntPtrConstant(kGlobalOrSticky); - const shouldUpdateLastIndex: bool = isGlobalOrSticky != 0; + let lastIndex = regexpLastIndex; - // Grab and possibly update last index. - if (shouldUpdateLastIndex) { - if (!TaggedIsSmi(lastIndex) || (lastIndex > string.length_smi)) { - StoreLastIndex(regexp, SmiConstant(0), isFastPath); - goto IfDidNotMatch; - } - } else { - lastIndex = SmiConstant(0); - } + // Check whether the regexp is global or sticky, which determines whether we + // update last index later on. + const flags = UnsafeCast(regexp.flags); + const isGlobalOrSticky: intptr = + SmiUntag(flags) & IntPtrConstant(kGlobalOrSticky); + const shouldUpdateLastIndex: bool = isGlobalOrSticky != 0; - const lastMatchInfo: RegExpMatchInfo = GetRegExpLastMatchInfo(); - - const matchIndices = - RegExpExecInternal(regexp, string, lastIndex, lastMatchInfo); - - // {match_indices} is either null or the RegExpMatchInfo array. - // Return early if exec failed, possibly updating last index. - if (matchIndices != Null) { - const matchIndicesRegExpMatchInfo = - UnsafeCast(matchIndices); - if (shouldUpdateLastIndex) { - // Update the new last index from {match_indices}. - const newLastIndex: Smi = - matchIndicesRegExpMatchInfo.GetEndOfCapture(0); - StoreLastIndex(regexp, newLastIndex, isFastPath); - } - return matchIndicesRegExpMatchInfo; - } - if (shouldUpdateLastIndex) { + // Grab and possibly update last index. + if (shouldUpdateLastIndex) { + if (!TaggedIsSmi(lastIndex) || (lastIndex > string.length_smi)) { StoreLastIndex(regexp, SmiConstant(0), isFastPath); + goto IfDidNotMatch; } - goto IfDidNotMatch; + } else { + lastIndex = SmiConstant(0); } - @export - transitioning macro RegExpPrototypeExecBodyWithoutResultFast( - implicit context: Context)(regexp: JSRegExp, string: String): - RegExpMatchInfo labels IfDidNotMatch { - const lastIndex = LoadLastIndexAsLength(regexp, true); - return RegExpPrototypeExecBodyWithoutResult(regexp, string, lastIndex, true) - otherwise IfDidNotMatch; - } + const lastMatchInfo: RegExpMatchInfo = GetRegExpLastMatchInfo(); - transitioning macro RegExpPrototypeExecBodyWithoutResultFast( - implicit context: - Context)(regexp: JSRegExp, string: String, lastIndex: Number): - RegExpMatchInfo labels IfDidNotMatch { - return RegExpPrototypeExecBodyWithoutResult(regexp, string, lastIndex, true) - otherwise IfDidNotMatch; - } + const matchIndices = + RegExpExecInternal(regexp, string, lastIndex, lastMatchInfo); - // ES#sec-regexp.prototype.exec - // RegExp.prototype.exec ( string ) - transitioning macro RegExpPrototypeExecBody(implicit context: Context)( - receiver: JSReceiver, string: String, isFastPath: constexpr bool): JSAny { - let regexp: JSRegExp; - if constexpr (isFastPath) { - regexp = UnsafeCast(receiver); - } else { - regexp = Cast(receiver) otherwise ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, 'RegExp.prototype.exec', - receiver); + // {match_indices} is either null or the RegExpMatchInfo array. + // Return early if exec failed, possibly updating last index. + if (matchIndices != Null) { + const matchIndicesRegExpMatchInfo = + UnsafeCast(matchIndices); + if (shouldUpdateLastIndex) { + // Update the new last index from {match_indices}. + const newLastIndex: Smi = matchIndicesRegExpMatchInfo.GetEndOfCapture(0); + StoreLastIndex(regexp, newLastIndex, isFastPath); } - const lastIndex = LoadLastIndexAsLength(regexp, isFastPath); - const matchIndices: RegExpMatchInfo = RegExpPrototypeExecBodyWithoutResult( - regexp, string, lastIndex, isFastPath) otherwise return Null; - return ConstructNewResultFromMatchInfo( - regexp, matchIndices, string, lastIndex); + return matchIndicesRegExpMatchInfo; } - - macro LoadRegExpFunction(implicit context: Context)( - nativeContext: NativeContext): JSFunction { - return UnsafeCast( - nativeContext[NativeContextSlot::REGEXP_FUNCTION_INDEX]); + if (shouldUpdateLastIndex) { + StoreLastIndex(regexp, SmiConstant(0), isFastPath); } + goto IfDidNotMatch; +} - // Note this doesn't guarantee const-ness of object properties, just - // unchanged object layout. - macro HasInitialRegExpMap(implicit context: Context)(o: HeapObject): bool { - const nativeContext = LoadNativeContext(context); - const function = LoadRegExpFunction(nativeContext); - const initialMap = UnsafeCast(function.prototype_or_initial_map); - return initialMap == o.map; - } +@export +transitioning macro RegExpPrototypeExecBodyWithoutResultFast( + implicit context: Context)(regexp: JSRegExp, string: String): + RegExpMatchInfo labels IfDidNotMatch { + const lastIndex = LoadLastIndexAsLength(regexp, true); + return RegExpPrototypeExecBodyWithoutResult(regexp, string, lastIndex, true) + otherwise IfDidNotMatch; +} - macro IsReceiverInitialRegExpPrototype(implicit context: - Context)(receiver: Object): bool { - const nativeContext = LoadNativeContext(context); - const regexpFun = LoadRegExpFunction(nativeContext); - const initialMap = UnsafeCast(regexpFun.prototype_or_initial_map); - const initialPrototype: HeapObject = initialMap.prototype; - return TaggedEqual(receiver, initialPrototype); - } +transitioning macro RegExpPrototypeExecBodyWithoutResultFast( + implicit context: Context)( + regexp: JSRegExp, string: String, + lastIndex: Number): RegExpMatchInfo labels IfDidNotMatch { + return RegExpPrototypeExecBodyWithoutResult(regexp, string, lastIndex, true) + otherwise IfDidNotMatch; +} - extern enum Flag constexpr 'JSRegExp::Flag' { - kNone, - kGlobal, - kIgnoreCase, - kMultiline, - kSticky, - kUnicode, - kDotAll, - kInvalid +// ES#sec-regexp.prototype.exec +// RegExp.prototype.exec ( string ) +transitioning macro RegExpPrototypeExecBody(implicit context: Context)( + receiver: JSReceiver, string: String, isFastPath: constexpr bool): JSAny { + let regexp: JSRegExp; + if constexpr (isFastPath) { + regexp = UnsafeCast(receiver); + } else { + regexp = Cast(receiver) otherwise ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, 'RegExp.prototype.exec', + receiver); } + const lastIndex = LoadLastIndexAsLength(regexp, isFastPath); + const matchIndices: RegExpMatchInfo = RegExpPrototypeExecBodyWithoutResult( + regexp, string, lastIndex, isFastPath) otherwise return Null; + return ConstructNewResultFromMatchInfo( + regexp, matchIndices, string, lastIndex); +} - const kRegExpPrototypeOldFlagGetter: constexpr int31 - generates 'v8::Isolate::kRegExpPrototypeOldFlagGetter'; - const kRegExpPrototypeStickyGetter: constexpr int31 - generates 'v8::Isolate::kRegExpPrototypeStickyGetter'; - const kRegExpPrototypeUnicodeGetter: constexpr int31 - generates 'v8::Isolate::kRegExpPrototypeUnicodeGetter'; - - extern macro RegExpBuiltinsAssembler::FastFlagGetter( - JSRegExp, constexpr Flag): bool; - extern runtime IncrementUseCounter(Context, Smi): void; - - macro FlagGetter(implicit context: Context)( - receiver: Object, flag: constexpr Flag, counter: constexpr int31, - methodName: constexpr string): JSAny { - typeswitch (receiver) { - case (receiver: JSRegExp): { - return SelectBooleanConstant(FastFlagGetter(receiver, flag)); - } - case (Object): { - } - } - if (!IsReceiverInitialRegExpPrototype(receiver)) { - ThrowTypeError(MessageTemplate::kRegExpNonRegExp, methodName); +macro LoadRegExpFunction(implicit context: Context)( + nativeContext: NativeContext): JSFunction { + return UnsafeCast( + nativeContext[NativeContextSlot::REGEXP_FUNCTION_INDEX]); +} + +// Note this doesn't guarantee const-ness of object properties, just +// unchanged object layout. +macro HasInitialRegExpMap(implicit context: Context)(o: HeapObject): bool { + const nativeContext = LoadNativeContext(context); + const function = LoadRegExpFunction(nativeContext); + const initialMap = UnsafeCast(function.prototype_or_initial_map); + return initialMap == o.map; +} + +macro IsReceiverInitialRegExpPrototype(implicit context: Context)( + receiver: Object): bool { + const nativeContext = LoadNativeContext(context); + const regexpFun = LoadRegExpFunction(nativeContext); + const initialMap = UnsafeCast(regexpFun.prototype_or_initial_map); + const initialPrototype: HeapObject = initialMap.prototype; + return TaggedEqual(receiver, initialPrototype); +} + +extern enum Flag constexpr 'JSRegExp::Flag' { + kNone, + kGlobal, + kIgnoreCase, + kMultiline, + kSticky, + kUnicode, + kDotAll, + kInvalid +} + +const kRegExpPrototypeOldFlagGetter: constexpr int31 + generates 'v8::Isolate::kRegExpPrototypeOldFlagGetter'; +const kRegExpPrototypeStickyGetter: constexpr int31 + generates 'v8::Isolate::kRegExpPrototypeStickyGetter'; +const kRegExpPrototypeUnicodeGetter: constexpr int31 + generates 'v8::Isolate::kRegExpPrototypeUnicodeGetter'; + +extern macro RegExpBuiltinsAssembler::FastFlagGetter( + JSRegExp, constexpr Flag): bool; +extern runtime IncrementUseCounter(Context, Smi): void; + +macro FlagGetter(implicit context: Context)( + receiver: Object, flag: constexpr Flag, counter: constexpr int31, + methodName: constexpr string): JSAny { + typeswitch (receiver) { + case (receiver: JSRegExp): { + return SelectBooleanConstant(FastFlagGetter(receiver, flag)); } - if constexpr (counter != -1) { - IncrementUseCounter(context, SmiConstant(counter)); + case (Object): { } - return Undefined; } - - // ES6 21.2.5.4. - // ES #sec-get-regexp.prototype.global - transitioning javascript builtin RegExpPrototypeGlobalGetter( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - return FlagGetter( - receiver, Flag::kGlobal, kRegExpPrototypeOldFlagGetter, - 'RegExp.prototype.global'); + if (!IsReceiverInitialRegExpPrototype(receiver)) { + ThrowTypeError(MessageTemplate::kRegExpNonRegExp, methodName); } - - // ES6 21.2.5.5. - // ES #sec-get-regexp.prototype.ignorecase - transitioning javascript builtin RegExpPrototypeIgnoreCaseGetter( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - return FlagGetter( - receiver, Flag::kIgnoreCase, kRegExpPrototypeOldFlagGetter, - 'RegExp.prototype.ignoreCase'); + if constexpr (counter != -1) { + IncrementUseCounter(context, SmiConstant(counter)); } + return Undefined; +} - // ES6 21.2.5.7. - // ES #sec-get-regexp.prototype.multiline - transitioning javascript builtin RegExpPrototypeMultilineGetter( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - return FlagGetter( - receiver, Flag::kMultiline, kRegExpPrototypeOldFlagGetter, - 'RegExp.prototype.multiline'); - } +// ES6 21.2.5.4. +// ES #sec-get-regexp.prototype.global +transitioning javascript builtin RegExpPrototypeGlobalGetter( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + return FlagGetter( + receiver, Flag::kGlobal, kRegExpPrototypeOldFlagGetter, + 'RegExp.prototype.global'); +} - // ES #sec-get-regexp.prototype.dotAll - transitioning javascript builtin RegExpPrototypeDotAllGetter( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - const kNoCounter: constexpr int31 = -1; - return FlagGetter( - receiver, Flag::kDotAll, kNoCounter, 'RegExp.prototype.dotAll'); - } +// ES6 21.2.5.5. +// ES #sec-get-regexp.prototype.ignorecase +transitioning javascript builtin RegExpPrototypeIgnoreCaseGetter( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + return FlagGetter( + receiver, Flag::kIgnoreCase, kRegExpPrototypeOldFlagGetter, + 'RegExp.prototype.ignoreCase'); +} - // ES6 21.2.5.12. - // ES #sec-get-regexp.prototype.sticky - transitioning javascript builtin RegExpPrototypeStickyGetter( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - return FlagGetter( - receiver, Flag::kSticky, kRegExpPrototypeStickyGetter, - 'RegExp.prototype.sticky'); - } +// ES6 21.2.5.7. +// ES #sec-get-regexp.prototype.multiline +transitioning javascript builtin RegExpPrototypeMultilineGetter( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + return FlagGetter( + receiver, Flag::kMultiline, kRegExpPrototypeOldFlagGetter, + 'RegExp.prototype.multiline'); +} - // ES6 21.2.5.15. - // ES #sec-get-regexp.prototype.unicode - transitioning javascript builtin RegExpPrototypeUnicodeGetter( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - return FlagGetter( - receiver, Flag::kUnicode, kRegExpPrototypeUnicodeGetter, - 'RegExp.prototype.unicode'); - } +// ES #sec-get-regexp.prototype.dotAll +transitioning javascript builtin RegExpPrototypeDotAllGetter( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + const kNoCounter: constexpr int31 = -1; + return FlagGetter( + receiver, Flag::kDotAll, kNoCounter, 'RegExp.prototype.dotAll'); +} - extern transitioning macro - RegExpBuiltinsAssembler::FlagsGetter(implicit context: Context)( - Object, constexpr bool): String; +// ES6 21.2.5.12. +// ES #sec-get-regexp.prototype.sticky +transitioning javascript builtin RegExpPrototypeStickyGetter( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + return FlagGetter( + receiver, Flag::kSticky, kRegExpPrototypeStickyGetter, + 'RegExp.prototype.sticky'); +} - transitioning macro - FastFlagsGetter(implicit context: Context)(receiver: FastJSRegExp): String { - return FlagsGetter(receiver, true); - } +// ES6 21.2.5.15. +// ES #sec-get-regexp.prototype.unicode +transitioning javascript builtin RegExpPrototypeUnicodeGetter( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + return FlagGetter( + receiver, Flag::kUnicode, kRegExpPrototypeUnicodeGetter, + 'RegExp.prototype.unicode'); +} - transitioning macro SlowFlagsGetter(implicit context: - Context)(receiver: JSAny): String { - return FlagsGetter(receiver, false); - } +extern transitioning macro +RegExpBuiltinsAssembler::FlagsGetter(implicit context: Context)( + Object, constexpr bool): String; - // ES #sec-get-regexp.prototype.flags - // TFJ(RegExpPrototypeFlagsGetter, 0, kReceiver) \ - transitioning javascript builtin RegExpPrototypeFlagsGetter( - js-implicit context: NativeContext, receiver: JSAny)(): String { - ThrowIfNotJSReceiver( - receiver, MessageTemplate::kRegExpNonObject, 'RegExp.prototype.flags'); - - // The check is strict because the following code relies on individual flag - // getters on the regexp prototype (e.g.: global, sticky, ...). We don't - // bother to check these individually. - const fastRegexp = Cast(receiver) - otherwise return SlowFlagsGetter(receiver); - return FastFlagsGetter(fastRegexp); - } +transitioning macro +FastFlagsGetter(implicit context: Context)(receiver: FastJSRegExp): String { + return FlagsGetter(receiver, true); +} + +transitioning macro SlowFlagsGetter(implicit context: Context)(receiver: JSAny): + String { + return FlagsGetter(receiver, false); +} - extern transitioning macro RegExpBuiltinsAssembler::SlowLoadLastIndex( - implicit context: Context)(JSAny): JSAny; - extern transitioning macro RegExpBuiltinsAssembler::SlowStoreLastIndex( - implicit context: Context)(JSAny, JSAny): void; +// ES #sec-get-regexp.prototype.flags +// TFJ(RegExpPrototypeFlagsGetter, 0, kReceiver) \ +transitioning javascript builtin RegExpPrototypeFlagsGetter( + js-implicit context: NativeContext, receiver: JSAny)(): String { + ThrowIfNotJSReceiver( + receiver, MessageTemplate::kRegExpNonObject, 'RegExp.prototype.flags'); + + // The check is strict because the following code relies on individual flag + // getters on the regexp prototype (e.g.: global, sticky, ...). We don't + // bother to check these individually. + const fastRegexp = Cast(receiver) + otherwise return SlowFlagsGetter(receiver); + return FastFlagsGetter(fastRegexp); +} - extern macro RegExpBuiltinsAssembler::FastLoadLastIndex(JSRegExp): Smi; - extern macro RegExpBuiltinsAssembler::FastStoreLastIndex(JSRegExp, Smi): void; +extern transitioning macro RegExpBuiltinsAssembler::SlowLoadLastIndex( + implicit context: Context)(JSAny): JSAny; +extern transitioning macro RegExpBuiltinsAssembler::SlowStoreLastIndex( + implicit context: Context)(JSAny, JSAny): void; - @export - transitioning macro LoadLastIndex(implicit context: Context)( - regexp: JSAny, isFastPath: constexpr bool): JSAny { - return isFastPath ? FastLoadLastIndex(UnsafeCast(regexp)) : - SlowLoadLastIndex(regexp); - } +extern macro RegExpBuiltinsAssembler::FastLoadLastIndex(JSRegExp): Smi; +extern macro RegExpBuiltinsAssembler::FastStoreLastIndex(JSRegExp, Smi): void; - @export - transitioning macro LoadLastIndexAsLength(implicit context: Context)( - regexp: JSRegExp, isFastPath: constexpr bool): Number { - const lastIndex = LoadLastIndex(regexp, isFastPath); - if (isFastPath) { - // ToLength on a positive smi is a nop and can be skipped. - return UnsafeCast(lastIndex); - } else { - // Omit ToLength if last_index is a non-negative smi. - typeswitch (lastIndex) { - case (i: PositiveSmi): { - return i; - } - case (o: JSAny): { - return ToLength_Inline(o); - } +@export +transitioning macro LoadLastIndex(implicit context: Context)( + regexp: JSAny, isFastPath: constexpr bool): JSAny { + return isFastPath ? FastLoadLastIndex(UnsafeCast(regexp)) : + SlowLoadLastIndex(regexp); +} + +@export +transitioning macro LoadLastIndexAsLength(implicit context: Context)( + regexp: JSRegExp, isFastPath: constexpr bool): Number { + const lastIndex = LoadLastIndex(regexp, isFastPath); + if (isFastPath) { + // ToLength on a positive smi is a nop and can be skipped. + return UnsafeCast(lastIndex); + } else { + // Omit ToLength if last_index is a non-negative smi. + typeswitch (lastIndex) { + case (i: PositiveSmi): { + return i; + } + case (o: JSAny): { + return ToLength_Inline(o); } } } +} - @export - transitioning macro StoreLastIndex(implicit context: Context)( - regexp: JSAny, value: Number, isFastPath: constexpr bool): void { - if (isFastPath) { - FastStoreLastIndex(UnsafeCast(regexp), UnsafeCast(value)); - } else { - SlowStoreLastIndex(regexp, value); - } +@export +transitioning macro StoreLastIndex(implicit context: Context)( + regexp: JSAny, value: Number, isFastPath: constexpr bool): void { + if (isFastPath) { + FastStoreLastIndex(UnsafeCast(regexp), UnsafeCast(value)); + } else { + SlowStoreLastIndex(regexp, value); } +} - extern builtin - StringIndexOf(implicit context: Context)(String, String, Smi): Smi; - - extern macro RegExpBuiltinsAssembler::AdvanceStringIndex( - String, Number, bool, constexpr bool): Number; - extern macro - RegExpBuiltinsAssembler::AdvanceStringIndexFast(String, Smi, bool): Smi; - extern macro - RegExpBuiltinsAssembler::AdvanceStringIndexSlow(String, Number, bool): Smi; - - type UseCounterFeature extends int31 - constexpr 'v8::Isolate::UseCounterFeature'; - const kRegExpMatchIsTrueishOnNonJSRegExp: constexpr UseCounterFeature - generates 'v8::Isolate::kRegExpMatchIsTrueishOnNonJSRegExp'; - const kRegExpMatchIsFalseishOnJSRegExp: constexpr UseCounterFeature - generates 'v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp'; - const kRegExpPrototypeSourceGetter: constexpr UseCounterFeature - generates 'v8::Isolate::kRegExpPrototypeSourceGetter'; - const kRegExpExecCalledOnSlowRegExp: constexpr UseCounterFeature - generates 'v8::Isolate::kRegExpExecCalledOnSlowRegExp'; - - // ES#sec-isregexp IsRegExp ( argument ) - @export - transitioning macro IsRegExp(implicit context: Context)(obj: JSAny): bool { - const receiver = Cast(obj) otherwise return false; - - // Check @match. - const value = GetProperty(receiver, MatchSymbolConstant()); - if (value == Undefined) { - return Is(receiver); - } - - assert(value != Undefined); - // The common path. Symbol.match exists, equals the RegExpPrototypeMatch - // function (and is thus trueish), and the receiver is a JSRegExp. - if (ToBoolean(value)) { - if (!Is(receiver)) { - IncrementUseCounter( - context, SmiConstant(kRegExpMatchIsTrueishOnNonJSRegExp)); - } - return true; - } +extern builtin +StringIndexOf(implicit context: Context)(String, String, Smi): Smi; + +extern macro RegExpBuiltinsAssembler::AdvanceStringIndex( + String, Number, bool, constexpr bool): Number; +extern macro +RegExpBuiltinsAssembler::AdvanceStringIndexFast(String, Smi, bool): Smi; +extern macro +RegExpBuiltinsAssembler::AdvanceStringIndexSlow(String, Number, bool): Smi; + +type UseCounterFeature extends int31 +constexpr 'v8::Isolate::UseCounterFeature'; +const kRegExpMatchIsTrueishOnNonJSRegExp: constexpr UseCounterFeature + generates 'v8::Isolate::kRegExpMatchIsTrueishOnNonJSRegExp'; +const kRegExpMatchIsFalseishOnJSRegExp: constexpr UseCounterFeature + generates 'v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp'; +const kRegExpPrototypeSourceGetter: constexpr UseCounterFeature + generates 'v8::Isolate::kRegExpPrototypeSourceGetter'; +const kRegExpExecCalledOnSlowRegExp: constexpr UseCounterFeature + generates 'v8::Isolate::kRegExpExecCalledOnSlowRegExp'; + +// ES#sec-isregexp IsRegExp ( argument ) +@export +transitioning macro IsRegExp(implicit context: Context)(obj: JSAny): bool { + const receiver = Cast(obj) otherwise return false; + + // Check @match. + const value = GetProperty(receiver, MatchSymbolConstant()); + if (value == Undefined) { + return Is(receiver); + } - assert(!ToBoolean(value)); - if (Is(receiver)) { + assert(value != Undefined); + // The common path. Symbol.match exists, equals the RegExpPrototypeMatch + // function (and is thus trueish), and the receiver is a JSRegExp. + if (ToBoolean(value)) { + if (!Is(receiver)) { IncrementUseCounter( - context, SmiConstant(kRegExpMatchIsFalseishOnJSRegExp)); + context, SmiConstant(kRegExpMatchIsTrueishOnNonJSRegExp)); } - return false; + return true; } - extern runtime RegExpInitializeAndCompile(Context, JSRegExp, String, String): - JSAny; - - @export - transitioning macro RegExpCreate(implicit context: Context)( - nativeContext: NativeContext, maybeString: JSAny, flags: String): JSAny { - const regexpFun = LoadRegExpFunction(nativeContext); - const initialMap = UnsafeCast(regexpFun.prototype_or_initial_map); - return RegExpCreate(initialMap, maybeString, flags); + assert(!ToBoolean(value)); + if (Is(receiver)) { + IncrementUseCounter(context, SmiConstant(kRegExpMatchIsFalseishOnJSRegExp)); } + return false; +} - @export - transitioning macro RegExpCreate(implicit context: Context)( - initialMap: Map, maybeString: JSAny, flags: String): JSAny { - const pattern: String = - maybeString == Undefined ? kEmptyString : ToString_Inline(maybeString); - const regexp = - UnsafeCast(AllocateFastOrSlowJSObjectFromMap(initialMap)); - return RegExpInitializeAndCompile(context, regexp, pattern, flags); - } +extern runtime RegExpInitializeAndCompile( + Context, JSRegExp, String, String): JSAny; + +@export +transitioning macro RegExpCreate(implicit context: Context)( + nativeContext: NativeContext, maybeString: JSAny, flags: String): JSAny { + const regexpFun = LoadRegExpFunction(nativeContext); + const initialMap = UnsafeCast(regexpFun.prototype_or_initial_map); + return RegExpCreate(initialMap, maybeString, flags); +} + +@export +transitioning macro RegExpCreate(implicit context: Context)( + initialMap: Map, maybeString: JSAny, flags: String): JSAny { + const pattern: String = + maybeString == Undefined ? kEmptyString : ToString_Inline(maybeString); + const regexp = + UnsafeCast(AllocateFastOrSlowJSObjectFromMap(initialMap)); + return RegExpInitializeAndCompile(context, regexp, pattern, flags); +} } diff --git a/deps/v8/src/builtins/string-endswith.tq b/deps/v8/src/builtins/string-endswith.tq index 6941728b39aa87..b9615b114985fd 100644 --- a/deps/v8/src/builtins/string-endswith.tq +++ b/deps/v8/src/builtins/string-endswith.tq @@ -3,79 +3,78 @@ // found in the LICENSE file. namespace string { - macro TryFastStringCompareSequence( - string: String, searchStr: String, start: uintptr, - searchLength: uintptr): Boolean labels Slow { - const directString = Cast(string) otherwise Slow; - const directSearchStr = Cast(searchStr) otherwise Slow; +macro TryFastStringCompareSequence( + string: String, searchStr: String, start: uintptr, + searchLength: uintptr): Boolean labels Slow { + const directString = Cast(string) otherwise Slow; + const directSearchStr = Cast(searchStr) otherwise Slow; - let searchIndex: uintptr = 0; - let stringIndex: uintptr = start; + let searchIndex: uintptr = 0; + let stringIndex: uintptr = start; - while (searchIndex < searchLength) { - if (StringCharCodeAt(directSearchStr, searchIndex) != - StringCharCodeAt(directString, stringIndex)) { - return False; - } - - searchIndex++; - stringIndex++; + while (searchIndex < searchLength) { + if (StringCharCodeAt(directSearchStr, searchIndex) != + StringCharCodeAt(directString, stringIndex)) { + return False; } - return True; + + searchIndex++; + stringIndex++; } + return True; +} - // https://tc39.github.io/ecma262/#sec-string.prototype.endswith - transitioning javascript builtin StringPrototypeEndsWith( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): Boolean { - const searchString: JSAny = arguments[0]; - const endPosition: JSAny = arguments[1]; - const kBuiltinName: constexpr string = 'String.prototype.endsWith'; +// https://tc39.github.io/ecma262/#sec-string.prototype.endswith +transitioning javascript builtin StringPrototypeEndsWith( + js-implicit context: NativeContext, + receiver: JSAny)(...arguments): Boolean { + const searchString: JSAny = arguments[0]; + const endPosition: JSAny = arguments[1]; + const kBuiltinName: constexpr string = 'String.prototype.endsWith'; - // 1. Let O be ? RequireObjectCoercible(this value). - // 2. Let S be ? ToString(O). - const string: String = ToThisString(receiver, kBuiltinName); + // 1. Let O be ? RequireObjectCoercible(this value). + // 2. Let S be ? ToString(O). + const string: String = ToThisString(receiver, kBuiltinName); - // 3. Let isRegExp be ? IsRegExp(searchString). - // 4. If isRegExp is true, throw a TypeError exception. - if (regexp::IsRegExp(searchString)) { - ThrowTypeError(MessageTemplate::kFirstArgumentNotRegExp, kBuiltinName); - } + // 3. Let isRegExp be ? IsRegExp(searchString). + // 4. If isRegExp is true, throw a TypeError exception. + if (regexp::IsRegExp(searchString)) { + ThrowTypeError(MessageTemplate::kFirstArgumentNotRegExp, kBuiltinName); + } - // 5. Let searchStr be ? ToString(searchString). - const searchStr: String = ToString_Inline(searchString); + // 5. Let searchStr be ? ToString(searchString). + const searchStr: String = ToString_Inline(searchString); - // 6. Let len be the length of S. - const len: uintptr = string.length_uintptr; + // 6. Let len be the length of S. + const len: uintptr = string.length_uintptr; - // 7. If endPosition is undefined, let pos be len, - // else let pos be ? ToInteger(endPosition). - // 8. Let end be min(max(pos, 0), len). - const end: uintptr = - (endPosition != Undefined) ? ClampToIndexRange(endPosition, len) : len; + // 7. If endPosition is undefined, let pos be len, + // else let pos be ? ToInteger(endPosition). + // 8. Let end be min(max(pos, 0), len). + const end: uintptr = + (endPosition != Undefined) ? ClampToIndexRange(endPosition, len) : len; - // 9. Let searchLength be the length of searchStr. - const searchLength: uintptr = searchStr.length_uintptr; + // 9. Let searchLength be the length of searchStr. + const searchLength: uintptr = searchStr.length_uintptr; - // 10. Let start be end - searchLength. - const start: uintptr = end - searchLength; + // 10. Let start be end - searchLength. + const start: uintptr = end - searchLength; - // 11. If start is less than 0, return false. - if (Signed(start) < 0) return False; + // 11. If start is less than 0, return false. + if (Signed(start) < 0) return False; - // 12. If the sequence of code units of S starting at start of length - // searchLength is the same as the full code unit sequence of searchStr, - // return true. - // 13. Otherwise, return false. - try { - // Fast Path: If both strings are direct and relevant indices are Smis. - return TryFastStringCompareSequence( - string, searchStr, start, searchLength) otherwise Slow; - } - label Slow { - // Slow Path: If either of the string is indirect, bail into runtime. - return StringCompareSequence( - context, string, searchStr, Convert(start)); - } + // 12. If the sequence of code units of S starting at start of length + // searchLength is the same as the full code unit sequence of searchStr, + // return true. + // 13. Otherwise, return false. + try { + // Fast Path: If both strings are direct and relevant indices are Smis. + return TryFastStringCompareSequence(string, searchStr, start, searchLength) + otherwise Slow; + } label Slow { + // Slow Path: If either of the string is indirect, bail into runtime. + return StringCompareSequence( + context, string, searchStr, Convert(start)); } } +} diff --git a/deps/v8/src/builtins/string-html.tq b/deps/v8/src/builtins/string-html.tq index f12c2dd22f1e03..8b3e01342eaad1 100644 --- a/deps/v8/src/builtins/string-html.tq +++ b/deps/v8/src/builtins/string-html.tq @@ -3,127 +3,124 @@ // found in the LICENSE file. namespace string { - extern runtime StringEscapeQuotes(Context, String): String; - - // https://tc39.github.io/ecma262/#sec-createhtml - transitioning builtin CreateHTML(implicit context: Context)( - receiver: JSAny, methodName: String, tagName: String, attr: String, - attrValue: JSAny): String { - const tagContents: String = ToThisString(receiver, methodName); - let result = '<' + tagName; - if (attr != kEmptyString) { - const attrStringValue: String = - StringEscapeQuotes(context, ToString_Inline(attrValue)); - result = result + ' ' + attr + '=\"' + attrStringValue + '\"'; - } - - return result + '>' + tagContents + ''; +extern runtime StringEscapeQuotes(Context, String): String; + +// https://tc39.github.io/ecma262/#sec-createhtml +transitioning builtin CreateHTML(implicit context: Context)( + receiver: JSAny, methodName: String, tagName: String, attr: String, + attrValue: JSAny): String { + const tagContents: String = ToThisString(receiver, methodName); + let result = '<' + tagName; + if (attr != kEmptyString) { + const attrStringValue: String = + StringEscapeQuotes(context, ToString_Inline(attrValue)); + result = result + ' ' + attr + '=\"' + attrStringValue + '\"'; } - // https://tc39.github.io/ecma262/#sec-string.prototype.anchor - transitioning javascript builtin StringPrototypeAnchor( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): String { - return CreateHTML( - receiver, 'String.prototype.anchor', 'a', 'name', arguments[0]); - } + return result + '>' + tagContents + ''; +} - // https://tc39.github.io/ecma262/#sec-string.prototype.big - transitioning javascript builtin - StringPrototypeBig(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.big', 'big', kEmptyString, kEmptyString); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.anchor +transitioning javascript builtin StringPrototypeAnchor( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.anchor', 'a', 'name', arguments[0]); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.blink - transitioning javascript builtin - StringPrototypeBlink(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.blink', 'blink', kEmptyString, - kEmptyString); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.big +transitioning javascript builtin +StringPrototypeBig( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.big', 'big', kEmptyString, kEmptyString); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.bold - transitioning javascript builtin - StringPrototypeBold(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.bold', 'b', kEmptyString, kEmptyString); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.blink +transitioning javascript builtin +StringPrototypeBlink( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.blink', 'blink', kEmptyString, kEmptyString); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.fontcolor - transitioning javascript builtin - StringPrototypeFontcolor(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.fontcolor', 'font', 'color', arguments[0]); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.bold +transitioning javascript builtin +StringPrototypeBold( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.bold', 'b', kEmptyString, kEmptyString); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.fontsize - transitioning javascript builtin - StringPrototypeFontsize(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.fontsize', 'font', 'size', arguments[0]); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.fontcolor +transitioning javascript builtin +StringPrototypeFontcolor( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.fontcolor', 'font', 'color', arguments[0]); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.fixed - transitioning javascript builtin - StringPrototypeFixed(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.fixed', 'tt', kEmptyString, kEmptyString); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.fontsize +transitioning javascript builtin +StringPrototypeFontsize( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.fontsize', 'font', 'size', arguments[0]); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.italics - transitioning javascript builtin - StringPrototypeItalics(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.italics', 'i', kEmptyString, kEmptyString); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.fixed +transitioning javascript builtin +StringPrototypeFixed( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.fixed', 'tt', kEmptyString, kEmptyString); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.link - transitioning javascript builtin - StringPrototypeLink(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.link', 'a', 'href', arguments[0]); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.italics +transitioning javascript builtin +StringPrototypeItalics( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.italics', 'i', kEmptyString, kEmptyString); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.small - transitioning javascript builtin - StringPrototypeSmall(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.small', 'small', kEmptyString, - kEmptyString); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.link +transitioning javascript builtin +StringPrototypeLink( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.link', 'a', 'href', arguments[0]); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.strike - transitioning javascript builtin - StringPrototypeStrike(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.strike', 'strike', kEmptyString, - kEmptyString); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.small +transitioning javascript builtin +StringPrototypeSmall( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.small', 'small', kEmptyString, kEmptyString); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.sub - transitioning javascript builtin - StringPrototypeSub(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.sub', 'sub', kEmptyString, kEmptyString); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.strike +transitioning javascript builtin +StringPrototypeStrike( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.strike', 'strike', kEmptyString, + kEmptyString); +} - // https://tc39.github.io/ecma262/#sec-string.prototype.sup - transitioning javascript builtin - StringPrototypeSup(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - return CreateHTML( - receiver, 'String.prototype.sup', 'sup', kEmptyString, kEmptyString); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.sub +transitioning javascript builtin +StringPrototypeSub( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.sub', 'sub', kEmptyString, kEmptyString); +} + +// https://tc39.github.io/ecma262/#sec-string.prototype.sup +transitioning javascript builtin +StringPrototypeSup( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + return CreateHTML( + receiver, 'String.prototype.sup', 'sup', kEmptyString, kEmptyString); +} } diff --git a/deps/v8/src/builtins/string-iterator.tq b/deps/v8/src/builtins/string-iterator.tq index 79032e0e28074e..eea7a621f0f8ae 100644 --- a/deps/v8/src/builtins/string-iterator.tq +++ b/deps/v8/src/builtins/string-iterator.tq @@ -4,43 +4,43 @@ namespace string { - macro NewJSStringIterator(implicit context: Context)( - string: String, nextIndex: Smi): JSStringIterator { - return new JSStringIterator{ - map: GetInitialStringIteratorMap(), - properties_or_hash: kEmptyFixedArray, - elements: kEmptyFixedArray, - string: string, - index: nextIndex - }; - } +macro NewJSStringIterator(implicit context: Context)( + string: String, nextIndex: Smi): JSStringIterator { + return new JSStringIterator{ + map: GetInitialStringIteratorMap(), + properties_or_hash: kEmptyFixedArray, + elements: kEmptyFixedArray, + string: string, + index: nextIndex + }; +} - // ES6 #sec-string.prototype-@@iterator - transitioning javascript builtin StringPrototypeIterator( - js-implicit context: NativeContext, receiver: JSAny)(): JSStringIterator { - const name: String = - ToThisString(receiver, 'String.prototype[Symbol.iterator]'); - const index: Smi = 0; - return NewJSStringIterator(name, index); - } +// ES6 #sec-string.prototype-@@iterator +transitioning javascript builtin StringPrototypeIterator( + js-implicit context: NativeContext, receiver: JSAny)(): JSStringIterator { + const name: String = + ToThisString(receiver, 'String.prototype[Symbol.iterator]'); + const index: Smi = 0; + return NewJSStringIterator(name, index); +} - // ES6 #sec-%stringiteratorprototype%.next - transitioning javascript builtin StringIteratorPrototypeNext( - js-implicit context: NativeContext, receiver: JSAny)(): JSObject { - const iterator = Cast(receiver) otherwise ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, - 'String Iterator.prototype.next', receiver); - const string = iterator.string; - const position: intptr = SmiUntag(iterator.index); - const length: intptr = string.length_intptr; - if (position >= length) { - return AllocateJSIteratorResult(Undefined, True); - } - // Move to next codepoint. - const encoding = UnicodeEncoding::UTF16; - const ch = string::LoadSurrogatePairAt(string, length, position, encoding); - const value: String = string::StringFromSingleUTF16EncodedCodePoint(ch); - iterator.index = SmiTag(position + value.length_intptr); - return AllocateJSIteratorResult(value, False); +// ES6 #sec-%stringiteratorprototype%.next +transitioning javascript builtin StringIteratorPrototypeNext( + js-implicit context: NativeContext, receiver: JSAny)(): JSObject { + const iterator = Cast(receiver) otherwise ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, + 'String Iterator.prototype.next', receiver); + const string = iterator.string; + const position: intptr = SmiUntag(iterator.index); + const length: intptr = string.length_intptr; + if (position >= length) { + return AllocateJSIteratorResult(Undefined, True); } + // Move to next codepoint. + const encoding = UnicodeEncoding::UTF16; + const ch = string::LoadSurrogatePairAt(string, length, position, encoding); + const value: String = string::StringFromSingleUTF16EncodedCodePoint(ch); + iterator.index = SmiTag(position + value.length_intptr); + return AllocateJSIteratorResult(value, False); +} } diff --git a/deps/v8/src/builtins/string-pad.tq b/deps/v8/src/builtins/string-pad.tq index 4a4c3704065ae1..b95e68628a4497 100644 --- a/deps/v8/src/builtins/string-pad.tq +++ b/deps/v8/src/builtins/string-pad.tq @@ -6,106 +6,106 @@ namespace string { - extern transitioning builtin - StringSubstring(implicit context: Context)(String, intptr, intptr): String; +extern transitioning builtin +StringSubstring(implicit context: Context)(String, intptr, intptr): String; - const kStringPadStart: constexpr int31 = 0; - const kStringPadEnd: constexpr int31 = 1; +const kStringPadStart: constexpr int31 = 0; +const kStringPadEnd: constexpr int31 = 1; - transitioning macro StringPad(implicit context: Context)( - receiver: JSAny, arguments: Arguments, methodName: constexpr string, - variant: constexpr int31): String { - const receiverString: String = ToThisString(receiver, methodName); - const stringLength: Smi = receiverString.length_smi; +transitioning macro StringPad(implicit context: Context)( + receiver: JSAny, arguments: Arguments, methodName: constexpr string, + variant: constexpr int31): String { + const receiverString: String = ToThisString(receiver, methodName); + const stringLength: Smi = receiverString.length_smi; - if (arguments.length == 0) { - return receiverString; - } - const maxLength: Number = ToLength_Inline(arguments[0]); - assert(IsNumberNormalized(maxLength)); - - typeswitch (maxLength) { - case (smiMaxLength: Smi): { - if (smiMaxLength <= stringLength) { - return receiverString; - } - } - case (Number): { - } - } + if (arguments.length == 0) { + return receiverString; + } + const maxLength: Number = ToLength_Inline(arguments[0]); + assert(IsNumberNormalized(maxLength)); - let fillString: String = ' '; - let fillLength: intptr = 1; - - if (arguments.length != 1) { - const fill = arguments[1]; - if (fill != Undefined) { - fillString = ToString_Inline(fill); - fillLength = fillString.length_intptr; - if (fillLength == 0) { - return receiverString; - } + typeswitch (maxLength) { + case (smiMaxLength: Smi): { + if (smiMaxLength <= stringLength) { + return receiverString; } } - - // Pad. - assert(fillLength > 0); - // Throw if max_length is greater than String::kMaxLength. - if (!TaggedIsSmi(maxLength)) { - ThrowInvalidStringLength(context); + case (Number): { } + } - const smiMaxLength: Smi = UnsafeCast(maxLength); - if (smiMaxLength > SmiConstant(kStringMaxLength)) { - ThrowInvalidStringLength(context); - } - assert(smiMaxLength > stringLength); - const padLength: Smi = smiMaxLength - stringLength; - - let padding: String; - if (fillLength == 1) { - // Single char fill. - // Fast path for a single character fill. No need to calculate number of - // repetitions or remainder. - padding = StringRepeat(context, fillString, padLength); - } else { - // Multi char fill. - const fillLengthWord32: int32 = TruncateIntPtrToInt32(fillLength); - const padLengthWord32: int32 = Convert(padLength); - const repetitionsWord32: int32 = padLengthWord32 / fillLengthWord32; - const remainingWord32: int32 = padLengthWord32 % fillLengthWord32; - padding = - StringRepeat(context, fillString, Convert(repetitionsWord32)); - - if (remainingWord32 != 0) { - const remainderString = - StringSubstring(fillString, 0, Convert(remainingWord32)); - padding = padding + remainderString; + let fillString: String = ' '; + let fillLength: intptr = 1; + + if (arguments.length != 1) { + const fill = arguments[1]; + if (fill != Undefined) { + fillString = ToString_Inline(fill); + fillLength = fillString.length_intptr; + if (fillLength == 0) { + return receiverString; } } + } - // Return result. - assert(padLength == padding.length_smi); - if (variant == kStringPadStart) { - return padding + receiverString; - } - assert(variant == kStringPadEnd); - return receiverString + padding; + // Pad. + assert(fillLength > 0); + // Throw if max_length is greater than String::kMaxLength. + if (!TaggedIsSmi(maxLength)) { + ThrowInvalidStringLength(context); } - // ES6 #sec-string.prototype.padstart - transitioning javascript builtin - StringPrototypePadStart(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - const methodName: constexpr string = 'String.prototype.padStart'; - return StringPad(receiver, arguments, methodName, kStringPadStart); + const smiMaxLength: Smi = UnsafeCast(maxLength); + if (smiMaxLength > SmiConstant(kStringMaxLength)) { + ThrowInvalidStringLength(context); + } + assert(smiMaxLength > stringLength); + const padLength: Smi = smiMaxLength - stringLength; + + let padding: String; + if (fillLength == 1) { + // Single char fill. + // Fast path for a single character fill. No need to calculate number of + // repetitions or remainder. + padding = StringRepeat(context, fillString, padLength); + } else { + // Multi char fill. + const fillLengthWord32: int32 = TruncateIntPtrToInt32(fillLength); + const padLengthWord32: int32 = Convert(padLength); + const repetitionsWord32: int32 = padLengthWord32 / fillLengthWord32; + const remainingWord32: int32 = padLengthWord32 % fillLengthWord32; + padding = + StringRepeat(context, fillString, Convert(repetitionsWord32)); + + if (remainingWord32 != 0) { + const remainderString = + StringSubstring(fillString, 0, Convert(remainingWord32)); + padding = padding + remainderString; + } } - // ES6 #sec-string.prototype.padend - transitioning javascript builtin - StringPrototypePadEnd(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): String { - const methodName: constexpr string = 'String.prototype.padEnd'; - return StringPad(receiver, arguments, methodName, kStringPadEnd); + // Return result. + assert(padLength == padding.length_smi); + if (variant == kStringPadStart) { + return padding + receiverString; } + assert(variant == kStringPadEnd); + return receiverString + padding; +} + +// ES6 #sec-string.prototype.padstart +transitioning javascript builtin +StringPrototypePadStart( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + const methodName: constexpr string = 'String.prototype.padStart'; + return StringPad(receiver, arguments, methodName, kStringPadStart); +} + +// ES6 #sec-string.prototype.padend +transitioning javascript builtin +StringPrototypePadEnd( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + const methodName: constexpr string = 'String.prototype.padEnd'; + return StringPad(receiver, arguments, methodName, kStringPadEnd); +} } diff --git a/deps/v8/src/builtins/string-repeat.tq b/deps/v8/src/builtins/string-repeat.tq index e3e72ae7b5882a..e1e33eb53abe22 100644 --- a/deps/v8/src/builtins/string-repeat.tq +++ b/deps/v8/src/builtins/string-repeat.tq @@ -3,76 +3,72 @@ // found in the LICENSE file. namespace string { - const kBuiltinName: constexpr string = 'String.prototype.repeat'; +const kBuiltinName: constexpr string = 'String.prototype.repeat'; - builtin StringRepeat(implicit context: Context)(string: String, count: Smi): - String { - assert(count >= 0); - assert(string != kEmptyString); +builtin StringRepeat(implicit context: Context)( + string: String, count: Smi): String { + assert(count >= 0); + assert(string != kEmptyString); - let result: String = kEmptyString; - let powerOfTwoRepeats: String = string; - let n: intptr = Convert(count); + let result: String = kEmptyString; + let powerOfTwoRepeats: String = string; + let n: intptr = Convert(count); - while (true) { - if ((n & 1) == 1) result = result + powerOfTwoRepeats; + while (true) { + if ((n & 1) == 1) result = result + powerOfTwoRepeats; - n = n >> 1; - if (n == 0) break; + n = n >> 1; + if (n == 0) break; - powerOfTwoRepeats = powerOfTwoRepeats + powerOfTwoRepeats; - } - - return result; + powerOfTwoRepeats = powerOfTwoRepeats + powerOfTwoRepeats; } - // https://tc39.github.io/ecma262/#sec-string.prototype.repeat - transitioning javascript builtin StringPrototypeRepeat( - js-implicit context: NativeContext, - receiver: JSAny)(count: JSAny): String { - // 1. Let O be ? RequireObjectCoercible(this value). - // 2. Let S be ? ToString(O). - const s: String = ToThisString(receiver, kBuiltinName); + return result; +} - try { - // 3. Let n be ? ToInteger(count). - typeswitch (ToInteger_Inline(count)) { - case (n: Smi): { - // 4. If n < 0, throw a RangeError exception. - if (n < 0) goto InvalidCount; +// https://tc39.github.io/ecma262/#sec-string.prototype.repeat +transitioning javascript builtin StringPrototypeRepeat( + js-implicit context: NativeContext, receiver: JSAny)(count: JSAny): String { + // 1. Let O be ? RequireObjectCoercible(this value). + // 2. Let S be ? ToString(O). + const s: String = ToThisString(receiver, kBuiltinName); - // 6. If n is 0, return the empty String. - if (n == 0 || s.length_uint32 == 0) goto EmptyString; + try { + // 3. Let n be ? ToInteger(count). + typeswitch (ToInteger_Inline(count)) { + case (n: Smi): { + // 4. If n < 0, throw a RangeError exception. + if (n < 0) goto InvalidCount; - if (n > kStringMaxLength) goto InvalidStringLength; + // 6. If n is 0, return the empty String. + if (n == 0 || s.length_uint32 == 0) goto EmptyString; - // 7. Return the String value that is made from n copies of S appended - // together. - return StringRepeat(s, n); - } - case (heapNum: HeapNumber): deferred { - assert(IsNumberNormalized(heapNum)); - const n = LoadHeapNumberValue(heapNum); + if (n > kStringMaxLength) goto InvalidStringLength; + + // 7. Return the String value that is made from n copies of S appended + // together. + return StringRepeat(s, n); + } + case (heapNum: HeapNumber): deferred { + assert(IsNumberNormalized(heapNum)); + const n = LoadHeapNumberValue(heapNum); - // 4. If n < 0, throw a RangeError exception. - // 5. If n is +∞, throw a RangeError exception. - if (n == V8_INFINITY || n < 0.0) goto InvalidCount; + // 4. If n < 0, throw a RangeError exception. + // 5. If n is +∞, throw a RangeError exception. + if (n == V8_INFINITY || n < 0.0) goto InvalidCount; - // 6. If n is 0, return the empty String. - if (s.length_uint32 == 0) goto EmptyString; + // 6. If n is 0, return the empty String. + if (s.length_uint32 == 0) goto EmptyString; - goto InvalidStringLength; - } + goto InvalidStringLength; } } - label EmptyString { - return kEmptyString; - } - label InvalidCount deferred { - ThrowRangeError(MessageTemplate::kInvalidCountValue, count); - } - label InvalidStringLength deferred { - ThrowInvalidStringLength(context); - } + } label EmptyString { + return kEmptyString; + } label InvalidCount deferred { + ThrowRangeError(MessageTemplate::kInvalidCountValue, count); + } label InvalidStringLength deferred { + ThrowInvalidStringLength(context); } } +} diff --git a/deps/v8/src/builtins/string-replaceall.tq b/deps/v8/src/builtins/string-replaceall.tq index c7589f18a66bd4..9211304b345214 100644 --- a/deps/v8/src/builtins/string-replaceall.tq +++ b/deps/v8/src/builtins/string-replaceall.tq @@ -5,218 +5,216 @@ #include 'src/builtins/builtins-string-gen.h' namespace string { - extern macro ReplaceSymbolConstant(): Symbol; - - extern macro StringBuiltinsAssembler::GetSubstitution( - implicit context: Context)(String, Smi, Smi, String): String; - - extern builtin - StringIndexOf(implicit context: Context)(String, String, Smi): Smi; - - macro TryFastAbstractStringIndexOf(implicit context: Context)( - string: String, searchString: String, fromIndex: Smi): Smi labels Slow { - const stringLen = string.length_uintptr; - const searchLen = searchString.length_uintptr; - const directString = Cast(string) otherwise Slow; - const directSearchStr = Cast(searchString) otherwise Slow; - const fromIndexUint = Unsigned(SmiUntag(fromIndex)); - - for (let i: uintptr = fromIndexUint; i < stringLen; i++) { - let j = i; - let k: uintptr = 0; - while (j < stringLen && k < searchLen && - StringCharCodeAt(directString, j) == - StringCharCodeAt(directSearchStr, k)) { - j++; - k++; - } - if (k == searchLen) { - return SmiTag(Signed(i)); - } +extern macro ReplaceSymbolConstant(): Symbol; + +extern macro StringBuiltinsAssembler::GetSubstitution( + implicit context: Context)(String, Smi, Smi, String): String; + +extern builtin +StringIndexOf(implicit context: Context)(String, String, Smi): Smi; + +macro TryFastAbstractStringIndexOf(implicit context: Context)( + string: String, searchString: String, fromIndex: Smi): Smi labels Slow { + const stringLen = string.length_uintptr; + const searchLen = searchString.length_uintptr; + const directString = Cast(string) otherwise Slow; + const directSearchStr = Cast(searchString) otherwise Slow; + const fromIndexUint = Unsigned(SmiUntag(fromIndex)); + + for (let i: uintptr = fromIndexUint; i < stringLen; i++) { + let j = i; + let k: uintptr = 0; + while (j < stringLen && k < searchLen && + StringCharCodeAt(directString, j) == + StringCharCodeAt(directSearchStr, k)) { + j++; + k++; + } + if (k == searchLen) { + return SmiTag(Signed(i)); } - return -1; } + return -1; +} - macro AbstractStringIndexOf(implicit context: Context)( - string: String, searchString: String, fromIndex: Smi): Smi { - // Special case the empty string. - const searchStringLength = searchString.length_intptr; - const stringLength = string.length_intptr; - if (searchStringLength == 0 && SmiUntag(fromIndex) <= stringLength) { - return fromIndex; - } +macro AbstractStringIndexOf(implicit context: Context)( + string: String, searchString: String, fromIndex: Smi): Smi { + // Special case the empty string. + const searchStringLength = searchString.length_intptr; + const stringLength = string.length_intptr; + if (searchStringLength == 0 && SmiUntag(fromIndex) <= stringLength) { + return fromIndex; + } - // Don't bother to search if the searchString would go past the end - // of the string. This is actually necessary because of runtime - // checks. - if (SmiUntag(fromIndex) + searchStringLength > stringLength) { - return -1; - } + // Don't bother to search if the searchString would go past the end + // of the string. This is actually necessary because of runtime + // checks. + if (SmiUntag(fromIndex) + searchStringLength > stringLength) { + return -1; + } - try { - return TryFastAbstractStringIndexOf(string, searchString, fromIndex) - otherwise Slow; - } - label Slow { - for (let i: intptr = SmiUntag(fromIndex); - i + searchStringLength <= stringLength; i++) { - if (StringCompareSequence( - context, string, searchString, Convert(SmiTag(i))) == - True) { - return SmiTag(i); - } + try { + return TryFastAbstractStringIndexOf(string, searchString, fromIndex) + otherwise Slow; + } label Slow { + for (let i: intptr = SmiUntag(fromIndex); + i + searchStringLength <= stringLength; i++) { + if (StringCompareSequence( + context, string, searchString, Convert(SmiTag(i))) == + True) { + return SmiTag(i); } - return -1; } + return -1; } +} - transitioning macro - ThrowIfNotGlobal(implicit context: Context)(searchValue: JSAny): void { - let shouldThrow: bool; - typeswitch (searchValue) { - case (fastRegExp: FastJSRegExp): { - shouldThrow = !fastRegExp.global; - } - case (Object): { - const flags = GetProperty(searchValue, 'flags'); - RequireObjectCoercible(flags, 'String.prototype.replaceAll'); - shouldThrow = - StringIndexOf(ToString_Inline(flags), StringConstant('g'), 0) == -1; - } +transitioning macro +ThrowIfNotGlobal(implicit context: Context)(searchValue: JSAny): void { + let shouldThrow: bool; + typeswitch (searchValue) { + case (fastRegExp: FastJSRegExp): { + shouldThrow = !fastRegExp.global; } - if (shouldThrow) { - ThrowTypeError( - MessageTemplate::kRegExpGlobalInvokedOnNonGlobal, - 'String.prototype.replaceAll'); + case (Object): { + const flags = GetProperty(searchValue, 'flags'); + RequireObjectCoercible(flags, 'String.prototype.replaceAll'); + shouldThrow = + StringIndexOf(ToString_Inline(flags), StringConstant('g'), 0) == -1; } } + if (shouldThrow) { + ThrowTypeError( + MessageTemplate::kRegExpGlobalInvokedOnNonGlobal, + 'String.prototype.replaceAll'); + } +} - // https://tc39.es/ecma262/#sec-string.prototype.replaceall - transitioning javascript builtin StringPrototypeReplaceAll( - js-implicit context: NativeContext, - receiver: JSAny)(searchValue: JSAny, replaceValue: JSAny): JSAny { - // 1. Let O be ? RequireObjectCoercible(this value). - RequireObjectCoercible(receiver, 'String.prototype.replaceAll'); - - // 2. If searchValue is neither undefined nor null, then - if (searchValue != Undefined && searchValue != Null) { - // a. Let isRegExp be ? IsRegExp(searchString). - // b. If isRegExp is true, then - // i. Let flags be ? Get(searchValue, "flags"). - // ii. Perform ? RequireObjectCoercible(flags). - // iii. If ? ToString(flags) does not contain "g", throw a - // TypeError exception. - if (regexp::IsRegExp(searchValue)) { - ThrowIfNotGlobal(searchValue); - } - - // TODO(joshualitt): We could easily add fast paths for string - // searchValues and potential FastRegExps. - // c. Let replacer be ? GetMethod(searchValue, @@replace). - // d. If replacer is not undefined, then - // i. Return ? Call(replacer, searchValue, « O, replaceValue »). - try { - const replacer = GetMethod(searchValue, ReplaceSymbolConstant()) - otherwise ReplaceSymbolIsNullOrUndefined; - return Call(context, replacer, searchValue, receiver, replaceValue); - } - label ReplaceSymbolIsNullOrUndefined {} +// https://tc39.es/ecma262/#sec-string.prototype.replaceall +transitioning javascript builtin StringPrototypeReplaceAll( + js-implicit context: NativeContext, receiver: JSAny)( + searchValue: JSAny, replaceValue: JSAny): JSAny { + // 1. Let O be ? RequireObjectCoercible(this value). + RequireObjectCoercible(receiver, 'String.prototype.replaceAll'); + + // 2. If searchValue is neither undefined nor null, then + if (searchValue != Undefined && searchValue != Null) { + // a. Let isRegExp be ? IsRegExp(searchString). + // b. If isRegExp is true, then + // i. Let flags be ? Get(searchValue, "flags"). + // ii. Perform ? RequireObjectCoercible(flags). + // iii. If ? ToString(flags) does not contain "g", throw a + // TypeError exception. + if (regexp::IsRegExp(searchValue)) { + ThrowIfNotGlobal(searchValue); } - // 3. Let string be ? ToString(O). - const string = ToString_Inline(receiver); + // TODO(joshualitt): We could easily add fast paths for string + // searchValues and potential FastRegExps. + // c. Let replacer be ? GetMethod(searchValue, @@replace). + // d. If replacer is not undefined, then + // i. Return ? Call(replacer, searchValue, « O, replaceValue »). + try { + const replacer = GetMethod(searchValue, ReplaceSymbolConstant()) + otherwise ReplaceSymbolIsNullOrUndefined; + return Call(context, replacer, searchValue, receiver, replaceValue); + } label ReplaceSymbolIsNullOrUndefined {} + } - // 4. Let searchString be ? ToString(searchValue). - const searchString = ToString_Inline(searchValue); + // 3. Let string be ? ToString(O). + const string = ToString_Inline(receiver); - // 5. Let functionalReplace be IsCallable(replaceValue). - let replaceValueArg = replaceValue; - const functionalReplace = TaggedIsCallable(replaceValue); + // 4. Let searchString be ? ToString(searchValue). + const searchString = ToString_Inline(searchValue); - // 6. If functionalReplace is false, then - if (!functionalReplace) { - // a. Let replaceValue be ? ToString(replaceValue). - replaceValueArg = ToString_Inline(replaceValue); - } + // 5. Let functionalReplace be IsCallable(replaceValue). + let replaceValueArg = replaceValue; + const functionalReplace = Is(replaceValue); - // 7. Let searchLength be the length of searchString. - const searchLength = searchString.length_smi; - - // 8. Let advanceBy be max(1, searchLength). - const advanceBy = SmiMax(1, searchLength); - - // We combine the two loops from the spec into one to avoid - // needing a growable array. - // - // 9. Let matchPositions be a new empty List. - // 10. Let position be ! StringIndexOf(string, searchString, 0). - // 11. Repeat, while position is not -1 - // a. Append position to the end of matchPositions. - // b. Let position be ! StringIndexOf(string, searchString, - // position + advanceBy). - // 12. Let endOfLastMatch be 0. - // 13. Let result be the empty string value. - // 14. For each position in matchPositions, do - let endOfLastMatch: Smi = 0; - let result: String = kEmptyString; - let position = AbstractStringIndexOf(string, searchString, 0); - while (position != -1) { - // a. If functionalReplace is true, then - // b. Else, - let replacement: String; - if (functionalReplace) { - // i. Let replacement be ? ToString(? Call(replaceValue, undefined, - // « searchString, position, - // string »). - replacement = ToString_Inline(Call( - context, UnsafeCast(replaceValueArg), Undefined, - searchString, position, string)); - } else { - // i. Assert: Type(replaceValue) is String. - const replaceValueString = UnsafeCast(replaceValueArg); - - // ii. Let captures be a new empty List. - // iii. Let replacement be GetSubstitution(searchString, - // string, position, captures, - // undefined, replaceValue). - // Note: Instead we just call a simpler GetSubstitution primitive. - const matchEndPosition = position + searchLength; - replacement = GetSubstitution( - string, position, matchEndPosition, replaceValueString); - } + // 6. If functionalReplace is false, then + if (!functionalReplace) { + // a. Let replaceValue be ? ToString(replaceValue). + replaceValueArg = ToString_Inline(replaceValue); + } - // c. Let stringSlice be the substring of string consisting of the code - // units from endOfLastMatch (inclusive) up through position - // (exclusive). - const stringSlice = string::SubString( - string, Unsigned(SmiUntag(endOfLastMatch)), - Unsigned(SmiUntag(position))); + // 7. Let searchLength be the length of searchString. + const searchLength = searchString.length_smi; + + // 8. Let advanceBy be max(1, searchLength). + const advanceBy = SmiMax(1, searchLength); + + // We combine the two loops from the spec into one to avoid + // needing a growable array. + // + // 9. Let matchPositions be a new empty List. + // 10. Let position be ! StringIndexOf(string, searchString, 0). + // 11. Repeat, while position is not -1 + // a. Append position to the end of matchPositions. + // b. Let position be ! StringIndexOf(string, searchString, + // position + advanceBy). + // 12. Let endOfLastMatch be 0. + // 13. Let result be the empty string value. + // 14. For each position in matchPositions, do + let endOfLastMatch: Smi = 0; + let result: String = kEmptyString; + let position = AbstractStringIndexOf(string, searchString, 0); + while (position != -1) { + // a. If functionalReplace is true, then + // b. Else, + let replacement: String; + if (functionalReplace) { + // i. Let replacement be ? ToString(? Call(replaceValue, undefined, + // « searchString, position, + // string »). + replacement = ToString_Inline(Call( + context, UnsafeCast(replaceValueArg), Undefined, + searchString, position, string)); + } else { + // i. Assert: Type(replaceValue) is String. + const replaceValueString = UnsafeCast(replaceValueArg); + + // ii. Let captures be a new empty List. + // iii. Let replacement be GetSubstitution(searchString, + // string, position, captures, + // undefined, replaceValue). + // Note: Instead we just call a simpler GetSubstitution primitive. + const matchEndPosition = position + searchLength; + replacement = GetSubstitution( + string, position, matchEndPosition, replaceValueString); + } - // d. Let result be the string-concatenation of result, stringSlice, - // and replacement. - // TODO(joshualitt): This leaves a completely degenerate ConsString tree. - // We could be smarter here. - result = result + stringSlice + replacement; + // c. Let stringSlice be the substring of string consisting of the code + // units from endOfLastMatch (inclusive) up through position + // (exclusive). + const stringSlice = string::SubString( + string, Unsigned(SmiUntag(endOfLastMatch)), + Unsigned(SmiUntag(position))); - // e. Let endOfLastMatch be position + searchLength. - endOfLastMatch = position + searchLength; + // d. Let result be the string-concatenation of result, stringSlice, + // and replacement. + // TODO(joshualitt): This leaves a completely degenerate ConsString tree. + // We could be smarter here. + result = result + stringSlice + replacement; - position = - AbstractStringIndexOf(string, searchString, position + advanceBy); - } + // e. Let endOfLastMatch be position + searchLength. + endOfLastMatch = position + searchLength; - // 15. If endOfLastMatch < the length of string, then - if (endOfLastMatch < string.length_smi) { - // a. Let result be the string-concatenation of result and the substring - // of string consisting of the code units from endOfLastMatch - // (inclusive) up through the final code unit of string (inclusive). - result = result + - string::SubString( - string, Unsigned(SmiUntag(endOfLastMatch)), - Unsigned(string.length_intptr)); - } + position = + AbstractStringIndexOf(string, searchString, position + advanceBy); + } - // 16. Return result. - return result; + // 15. If endOfLastMatch < the length of string, then + if (endOfLastMatch < string.length_smi) { + // a. Let result be the string-concatenation of result and the substring + // of string consisting of the code units from endOfLastMatch + // (inclusive) up through the final code unit of string (inclusive). + result = result + + string::SubString( + string, Unsigned(SmiUntag(endOfLastMatch)), + Unsigned(string.length_intptr)); } + + // 16. Return result. + return result; +} } diff --git a/deps/v8/src/builtins/string-slice.tq b/deps/v8/src/builtins/string-slice.tq index ea95d44a82381a..71442a28faaf2a 100644 --- a/deps/v8/src/builtins/string-slice.tq +++ b/deps/v8/src/builtins/string-slice.tq @@ -3,33 +3,32 @@ // found in the LICENSE file. namespace string { - // ES6 #sec-string.prototype.slice ( start, end ) - // https://tc39.github.io/ecma262/#sec-string.prototype.slice - transitioning javascript builtin StringPrototypeSlice( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): String { - // 1. Let O be ? RequireObjectCoercible(this value). - // 2. Let S be ? ToString(O). - const string: String = ToThisString(receiver, 'String.prototype.slice'); +// ES6 #sec-string.prototype.slice ( start, end ) +// https://tc39.github.io/ecma262/#sec-string.prototype.slice +transitioning javascript builtin StringPrototypeSlice( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + // 1. Let O be ? RequireObjectCoercible(this value). + // 2. Let S be ? ToString(O). + const string: String = ToThisString(receiver, 'String.prototype.slice'); - // 3. Let len be the number of elements in S. - const length: uintptr = string.length_uintptr; + // 3. Let len be the number of elements in S. + const length: uintptr = string.length_uintptr; - // Convert {start} to a relative index. - const arg0 = arguments[0]; - const start: uintptr = - arg0 != Undefined ? ConvertToRelativeIndex(arg0, length) : 0; + // Convert {start} to a relative index. + const arg0 = arguments[0]; + const start: uintptr = + arg0 != Undefined ? ConvertToRelativeIndex(arg0, length) : 0; - // 5. If end is undefined, let intEnd be len; - // else Convert {end} to a relative index. - const arg1 = arguments[1]; - const end: uintptr = - arg1 != Undefined ? ConvertToRelativeIndex(arg1, length) : length; + // 5. If end is undefined, let intEnd be len; + // else Convert {end} to a relative index. + const arg1 = arguments[1]; + const end: uintptr = + arg1 != Undefined ? ConvertToRelativeIndex(arg1, length) : length; - if (end <= start) { - return kEmptyString; - } - - return SubString(string, start, end); + if (end <= start) { + return kEmptyString; } + + return SubString(string, start, end); +} } diff --git a/deps/v8/src/builtins/string-startswith.tq b/deps/v8/src/builtins/string-startswith.tq index 045722dd824daa..a1f99df17b70bc 100644 --- a/deps/v8/src/builtins/string-startswith.tq +++ b/deps/v8/src/builtins/string-startswith.tq @@ -5,57 +5,56 @@ #include 'src/builtins/builtins-regexp-gen.h' namespace string { - // https://tc39.github.io/ecma262/#sec-string.prototype.startswith - transitioning javascript builtin StringPrototypeStartsWith( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): Boolean { - const searchString: JSAny = arguments[0]; - const position: JSAny = arguments[1]; - const kBuiltinName: constexpr string = 'String.prototype.startsWith'; - - // 1. Let O be ? RequireObjectCoercible(this value). - // 2. Let S be ? ToString(O). - const string: String = ToThisString(receiver, kBuiltinName); - - // 3. Let isRegExp be ? IsRegExp(searchString). - // 4. If isRegExp is true, throw a TypeError exception. - if (regexp::IsRegExp(searchString)) { - ThrowTypeError(MessageTemplate::kFirstArgumentNotRegExp, kBuiltinName); - } - - // 5. Let searchStr be ? ToString(searchString). - const searchStr: String = ToString_Inline(searchString); - - // 8. Let len be the length of S. - const len: uintptr = string.length_uintptr; - - // 6. Let pos be ? ToInteger(position). - // 7. Assert: If position is undefined, then pos is 0. - // 9. Let start be min(max(pos, 0), len). - const start: uintptr = - (position != Undefined) ? ClampToIndexRange(position, len) : 0; - - // 10. Let searchLength be the length of searchStr. - const searchLength: uintptr = searchStr.length_uintptr; - - // 11. If searchLength + start is greater than len, return false. - // The comparison is rephrased to be overflow-friendly with unsigned - // indices. - if (searchLength > len - start) return False; - - // 12. If the sequence of code units of S starting at start of length - // searchLength is the same as the full code unit sequence of searchStr, - // return true. - // 13. Otherwise, return false. - try { - // Fast Path: If both strings are direct and relevant indices are Smis. - return TryFastStringCompareSequence( - string, searchStr, start, searchLength) otherwise Slow; - } - label Slow { - // Slow Path: If either of the string is indirect, bail into runtime. - return StringCompareSequence( - context, string, searchStr, Convert(start)); - } +// https://tc39.github.io/ecma262/#sec-string.prototype.startswith +transitioning javascript builtin StringPrototypeStartsWith( + js-implicit context: NativeContext, + receiver: JSAny)(...arguments): Boolean { + const searchString: JSAny = arguments[0]; + const position: JSAny = arguments[1]; + const kBuiltinName: constexpr string = 'String.prototype.startsWith'; + + // 1. Let O be ? RequireObjectCoercible(this value). + // 2. Let S be ? ToString(O). + const string: String = ToThisString(receiver, kBuiltinName); + + // 3. Let isRegExp be ? IsRegExp(searchString). + // 4. If isRegExp is true, throw a TypeError exception. + if (regexp::IsRegExp(searchString)) { + ThrowTypeError(MessageTemplate::kFirstArgumentNotRegExp, kBuiltinName); } + + // 5. Let searchStr be ? ToString(searchString). + const searchStr: String = ToString_Inline(searchString); + + // 8. Let len be the length of S. + const len: uintptr = string.length_uintptr; + + // 6. Let pos be ? ToInteger(position). + // 7. Assert: If position is undefined, then pos is 0. + // 9. Let start be min(max(pos, 0), len). + const start: uintptr = + (position != Undefined) ? ClampToIndexRange(position, len) : 0; + + // 10. Let searchLength be the length of searchStr. + const searchLength: uintptr = searchStr.length_uintptr; + + // 11. If searchLength + start is greater than len, return false. + // The comparison is rephrased to be overflow-friendly with unsigned + // indices. + if (searchLength > len - start) return False; + + // 12. If the sequence of code units of S starting at start of length + // searchLength is the same as the full code unit sequence of searchStr, + // return true. + // 13. Otherwise, return false. + try { + // Fast Path: If both strings are direct and relevant indices are Smis. + return TryFastStringCompareSequence(string, searchStr, start, searchLength) + otherwise Slow; + } label Slow { + // Slow Path: If either of the string is indirect, bail into runtime. + return StringCompareSequence( + context, string, searchStr, Convert(start)); + } +} } diff --git a/deps/v8/src/builtins/string-substr.tq b/deps/v8/src/builtins/string-substr.tq index 917bee691e0623..068c4437ca60dd 100644 --- a/deps/v8/src/builtins/string-substr.tq +++ b/deps/v8/src/builtins/string-substr.tq @@ -4,40 +4,39 @@ namespace string { - // String.prototype.substr ( start, length ) - // ES6 #sec-string.prototype.substr - transitioning javascript builtin StringPrototypeSubstr( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): String { - const methodName: constexpr string = 'String.prototype.substr'; - // 1. Let O be ? RequireObjectCoercible(this value). - // 2. Let S be ? ToString(O). - const string: String = ToThisString(receiver, methodName); +// String.prototype.substr ( start, length ) +// ES6 #sec-string.prototype.substr +transitioning javascript builtin StringPrototypeSubstr( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + const methodName: constexpr string = 'String.prototype.substr'; + // 1. Let O be ? RequireObjectCoercible(this value). + // 2. Let S be ? ToString(O). + const string: String = ToThisString(receiver, methodName); - // 5. Let size be the number of code units in S. - const size: uintptr = string.length_uintptr; + // 5. Let size be the number of code units in S. + const size: uintptr = string.length_uintptr; - // 3. Let intStart be ? ToInteger(start). - // 6. If intStart < 0, set intStart to max(size + intStart, 0). - const start = arguments[0]; - const initStart: uintptr = - start != Undefined ? ConvertToRelativeIndex(start, size) : 0; + // 3. Let intStart be ? ToInteger(start). + // 6. If intStart < 0, set intStart to max(size + intStart, 0). + const start = arguments[0]; + const initStart: uintptr = + start != Undefined ? ConvertToRelativeIndex(start, size) : 0; - // 4. If length is undefined, - // let end be +∞; otherwise let end be ? ToInteger(length). - // 7. Let resultLength be min(max(end, 0), size - intStart). - const length = arguments[1]; - const lengthLimit = size - initStart; - assert(lengthLimit <= size); - const resultLength: uintptr = length != Undefined ? - ClampToIndexRange(length, lengthLimit) : - lengthLimit; + // 4. If length is undefined, + // let end be +∞; otherwise let end be ? ToInteger(length). + // 7. Let resultLength be min(max(end, 0), size - intStart). + const length = arguments[1]; + const lengthLimit = size - initStart; + assert(lengthLimit <= size); + const resultLength: uintptr = length != Undefined ? + ClampToIndexRange(length, lengthLimit) : + lengthLimit; - // 8. If resultLength ≤ 0, return the empty String "". - if (resultLength == 0) return EmptyStringConstant(); + // 8. If resultLength ≤ 0, return the empty String "". + if (resultLength == 0) return EmptyStringConstant(); - // 9. Return the String value containing resultLength consecutive code units - // from S beginning with the code unit at index intStart. - return SubString(string, initStart, initStart + resultLength); - } + // 9. Return the String value containing resultLength consecutive code units + // from S beginning with the code unit at index intStart. + return SubString(string, initStart, initStart + resultLength); +} } diff --git a/deps/v8/src/builtins/string-substring.tq b/deps/v8/src/builtins/string-substring.tq index e4e7d700003721..099a28b5057c44 100644 --- a/deps/v8/src/builtins/string-substring.tq +++ b/deps/v8/src/builtins/string-substring.tq @@ -4,28 +4,26 @@ namespace string { - // ES6 #sec-string.prototype.substring - transitioning javascript builtin StringPrototypeSubstring( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): String { - // Check that {receiver} is coercible to Object and convert it to a String. - const string: String = ToThisString(receiver, 'String.prototype.substring'); - const length: uintptr = string.length_uintptr; +// ES6 #sec-string.prototype.substring +transitioning javascript builtin StringPrototypeSubstring( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { + // Check that {receiver} is coercible to Object and convert it to a String. + const string: String = ToThisString(receiver, 'String.prototype.substring'); + const length: uintptr = string.length_uintptr; - // Conversion and bounds-checks for {start}. - const arg0 = arguments[0]; - let start: uintptr = - arg0 != Undefined ? ClampToIndexRange(arg0, length) : 0; + // Conversion and bounds-checks for {start}. + const arg0 = arguments[0]; + let start: uintptr = arg0 != Undefined ? ClampToIndexRange(arg0, length) : 0; - // Conversion and bounds-checks for {end}. - const arg1 = arguments[1]; - let end: uintptr = - arg1 != Undefined ? ClampToIndexRange(arg1, length) : length; - if (end < start) { - const tmp: uintptr = end; - end = start; - start = tmp; - } - return SubString(string, start, end); + // Conversion and bounds-checks for {end}. + const arg1 = arguments[1]; + let end: uintptr = + arg1 != Undefined ? ClampToIndexRange(arg1, length) : length; + if (end < start) { + const tmp: uintptr = end; + end = start; + start = tmp; } + return SubString(string, start, end); +} } diff --git a/deps/v8/src/builtins/symbol.tq b/deps/v8/src/builtins/symbol.tq index cda344471fbc45..18bdebd380e62a 100644 --- a/deps/v8/src/builtins/symbol.tq +++ b/deps/v8/src/builtins/symbol.tq @@ -3,47 +3,45 @@ // found in the LICENSE file. namespace symbol { - extern runtime SymbolDescriptiveString(implicit context: Context)(Symbol): - String; +extern runtime SymbolDescriptiveString(implicit context: Context)(Symbol): + String; - transitioning macro ThisSymbolValue(implicit context: Context)( - receiver: JSAny, method: constexpr string): Symbol { - return UnsafeCast( - ToThisValue(receiver, PrimitiveType::kSymbol, method)); - } +transitioning macro ThisSymbolValue(implicit context: Context)( + receiver: JSAny, method: constexpr string): Symbol { + return UnsafeCast( + ToThisValue(receiver, PrimitiveType::kSymbol, method)); +} - // ES #sec-symbol.prototype.description - transitioning javascript builtin SymbolPrototypeDescriptionGetter( - js-implicit context: NativeContext, receiver: JSAny)(): String|Undefined { - // 1. Let s be the this value. - // 2. Let sym be ? thisSymbolValue(s). - const sym: Symbol = - ThisSymbolValue(receiver, 'Symbol.prototype.description'); - // 3. Return sym.[[Description]]. - return sym.description; - } +// ES #sec-symbol.prototype.description +transitioning javascript builtin SymbolPrototypeDescriptionGetter( + js-implicit context: NativeContext, receiver: JSAny)(): String|Undefined { + // 1. Let s be the this value. + // 2. Let sym be ? thisSymbolValue(s). + const sym: Symbol = ThisSymbolValue(receiver, 'Symbol.prototype.description'); + // 3. Return sym.[[Description]]. + return sym.description; +} - // ES6 #sec-symbol.prototype-@@toprimitive - transitioning javascript builtin SymbolPrototypeToPrimitive( - js-implicit context: NativeContext, - receiver: JSAny)(_hint: JSAny): JSAny { - // 1. Return ? thisSymbolValue(this value). - return ThisSymbolValue(receiver, 'Symbol.prototype [ @@toPrimitive ]'); - } +// ES6 #sec-symbol.prototype-@@toprimitive +transitioning javascript builtin SymbolPrototypeToPrimitive( + js-implicit context: NativeContext, receiver: JSAny)(_hint: JSAny): JSAny { + // 1. Return ? thisSymbolValue(this value). + return ThisSymbolValue(receiver, 'Symbol.prototype [ @@toPrimitive ]'); +} - // ES6 #sec-symbol.prototype.tostring - transitioning javascript builtin SymbolPrototypeToString( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - // 1. Let sym be ? thisSymbolValue(this value). - const sym: Symbol = ThisSymbolValue(receiver, 'Symbol.prototype.toString'); - // 2. Return SymbolDescriptiveString(sym). - return SymbolDescriptiveString(sym); - } +// ES6 #sec-symbol.prototype.tostring +transitioning javascript builtin SymbolPrototypeToString( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + // 1. Let sym be ? thisSymbolValue(this value). + const sym: Symbol = ThisSymbolValue(receiver, 'Symbol.prototype.toString'); + // 2. Return SymbolDescriptiveString(sym). + return SymbolDescriptiveString(sym); +} - // ES6 #sec-symbol.prototype.valueof - transitioning javascript builtin SymbolPrototypeValueOf( - js-implicit context: NativeContext, receiver: JSAny)(): JSAny { - // 1. Return ? thisSymbolValue(this value). - return ThisSymbolValue(receiver, 'Symbol.prototype.valueOf'); - } +// ES6 #sec-symbol.prototype.valueof +transitioning javascript builtin SymbolPrototypeValueOf( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + // 1. Return ? thisSymbolValue(this value). + return ThisSymbolValue(receiver, 'Symbol.prototype.valueOf'); +} } diff --git a/deps/v8/src/builtins/torque-internal.tq b/deps/v8/src/builtins/torque-internal.tq index 85c43342cf1b0e..d2b107f932dcad 100644 --- a/deps/v8/src/builtins/torque-internal.tq +++ b/deps/v8/src/builtins/torque-internal.tq @@ -3,188 +3,189 @@ // found in the LICENSE file. namespace torque_internal { - // Unsafe is a marker that we require to be passed when calling internal APIs - // that might lead to unsoundness when used incorrectly. Unsafe markers should - // therefore not be instantiated anywhere outside of this namespace. - struct Unsafe {} - - // Size of a type in memory (on the heap). For class types, this is the size - // of the pointer, not of the instance. - intrinsic %SizeOf(): constexpr int31; - - struct Reference { - const object: HeapObject; - const offset: intptr; - unsafeMarker: Unsafe; - } - type ConstReference extends Reference; - type MutableReference extends ConstReference; - - macro UnsafeNewReference(object: HeapObject, offset: intptr):&T { - return %RawDownCast<&T>( - Reference{object: object, offset: offset, unsafeMarker: Unsafe {}}); - } - - struct Slice { - macro TryAtIndex(index: intptr):&T labels OutOfBounds { - if (Convert(index) < Convert(this.length)) { - return UnsafeNewReference( - this.object, this.offset + index * %SizeOf()); - } else { - goto OutOfBounds; - } - } +// Unsafe is a marker that we require to be passed when calling internal APIs +// that might lead to unsoundness when used incorrectly. Unsafe markers should +// therefore not be instantiated anywhere outside of this namespace. +struct Unsafe {} + +// Size of a type in memory (on the heap). For class types, this is the size +// of the pointer, not of the instance. +intrinsic %SizeOf(): constexpr int31; + +struct Reference { + const object: HeapObject; + const offset: intptr; + unsafeMarker: Unsafe; +} +type ConstReference extends Reference; +type MutableReference extends ConstReference; - macro AtIndex(index: intptr):&T { - return this.TryAtIndex(index) otherwise unreachable; - } +namespace unsafe { +macro NewReference(object: HeapObject, offset: intptr):&T { + return %RawDownCast<&T>( + Reference{object: object, offset: offset, unsafeMarker: Unsafe {}}); +} +} // namespace unsafe - macro AtIndex(index: uintptr):&T { - return this.TryAtIndex(Convert(index)) otherwise unreachable; +struct Slice { + macro TryAtIndex(index: intptr):&T labels OutOfBounds { + if (Convert(index) < Convert(this.length)) { + return unsafe::NewReference( + this.object, this.offset + index * %SizeOf()); + } else { + goto OutOfBounds; } + } - macro AtIndex(index: constexpr int31):&T { - const i: intptr = Convert(index); - return this.TryAtIndex(i) otherwise unreachable; - } + macro AtIndex(index: intptr):&T { + return this.TryAtIndex(index) otherwise unreachable; + } - macro AtIndex(index: Smi):&T { - const i: intptr = Convert(index); - return this.TryAtIndex(i) otherwise unreachable; - } + macro AtIndex(index: uintptr):&T { + return this.TryAtIndex(Convert(index)) otherwise unreachable; + } - macro Iterator(): SliceIterator { - const end = this.offset + this.length * %SizeOf(); - return SliceIterator{ - object: this.object, - start: this.offset, - end: end, - unsafeMarker: Unsafe {} - }; - } - macro Iterator(startIndex: intptr, endIndex: intptr): SliceIterator { - check( - Convert(endIndex) <= Convert(this.length) && - Convert(startIndex) <= Convert(endIndex)); - const start = this.offset + startIndex * %SizeOf(); - const end = this.offset + endIndex * %SizeOf(); - return SliceIterator{ - object: this.object, - start, - end, - unsafeMarker: Unsafe {} - }; - } + macro AtIndex(index: constexpr int31):&T { + const i: intptr = Convert(index); + return this.TryAtIndex(i) otherwise unreachable; + } - const object: HeapObject; - const offset: intptr; - const length: intptr; - unsafeMarker: Unsafe; + macro AtIndex(index: Smi):&T { + const i: intptr = Convert(index); + return this.TryAtIndex(i) otherwise unreachable; } - macro UnsafeNewSlice( - object: HeapObject, offset: intptr, length: intptr): Slice { - return Slice{ - object: object, - offset: offset, - length: length, + macro Iterator(): SliceIterator { + const end = this.offset + this.length * %SizeOf(); + return SliceIterator{ + object: this.object, + start: this.offset, + end: end, + unsafeMarker: Unsafe {} + }; + } + macro Iterator(startIndex: intptr, endIndex: intptr): SliceIterator { + check( + Convert(endIndex) <= Convert(this.length) && + Convert(startIndex) <= Convert(endIndex)); + const start = this.offset + startIndex * %SizeOf(); + const end = this.offset + endIndex * %SizeOf(); + return SliceIterator{ + object: this.object, + start, + end, unsafeMarker: Unsafe {} }; } - struct SliceIterator { - macro Empty(): bool { - return this.start == this.end; - } - - macro Next(): T labels NoMore { - return * this.NextReference() otherwise NoMore; - } + const object: HeapObject; + const offset: intptr; + const length: intptr; + unsafeMarker: Unsafe; +} - macro NextReference():&T labels NoMore { - if (this.Empty()) { - goto NoMore; - } else { - const result = UnsafeNewReference(this.object, this.start); - this.start += %SizeOf(); - return result; - } - } +macro UnsafeNewSlice( + object: HeapObject, offset: intptr, length: intptr): Slice { + return Slice{ + object: object, + offset: offset, + length: length, + unsafeMarker: Unsafe {} + }; +} - object: HeapObject; - start: intptr; - end: intptr; - unsafeMarker: Unsafe; +struct SliceIterator { + macro Empty(): bool { + return this.start == this.end; } - macro AddIndexedFieldSizeToObjectSize( - baseSize: intptr, arrayLength: intptr, - fieldSize: constexpr int32): intptr { - const arrayLength = Convert(arrayLength); - const byteLength = TryInt32Mul(arrayLength, fieldSize) - otherwise unreachable; - return TryIntPtrAdd(baseSize, Convert(byteLength)) - otherwise unreachable; + macro Next(): T labels NoMore { + return * this.NextReference() otherwise NoMore; } - macro AlignTagged(x: intptr): intptr { - // Round up to a multiple of kTaggedSize. - return (x + kObjectAlignmentMask) & ~kObjectAlignmentMask; + macro NextReference():&T labels NoMore { + if (this.Empty()) { + goto NoMore; + } else { + const result = unsafe::NewReference(this.object, this.start); + this.start += %SizeOf(); + return result; + } } - macro IsTaggedAligned(x: intptr): bool { - return (x & kObjectAlignmentMask) == 0; - } + object: HeapObject; + start: intptr; + end: intptr; + unsafeMarker: Unsafe; +} - macro ValidAllocationSize(sizeInBytes: intptr, map: Map): bool { - if (sizeInBytes <= 0) return false; - if (!IsTaggedAligned(sizeInBytes)) return false; - const instanceSizeInWords = Convert(map.instance_size_in_words); - return instanceSizeInWords == kVariableSizeSentinel || - instanceSizeInWords * kTaggedSize == sizeInBytes; - } +macro AddIndexedFieldSizeToObjectSize( + baseSize: intptr, arrayLength: intptr, fieldSize: constexpr int32): intptr { + const arrayLength = Convert(arrayLength); + const byteLength = TryInt32Mul(arrayLength, fieldSize) + otherwise unreachable; + return TryIntPtrAdd(baseSize, Convert(byteLength)) + otherwise unreachable; +} - type UninitializedHeapObject extends HeapObject; +macro AlignTagged(x: intptr): intptr { + // Round up to a multiple of kTaggedSize. + return (x + kObjectAlignmentMask) & ~kObjectAlignmentMask; +} - extern macro AllocateAllowLOS(intptr): UninitializedHeapObject; - extern macro GetInstanceTypeMap(constexpr InstanceType): Map; +macro IsTaggedAligned(x: intptr): bool { + return (x & kObjectAlignmentMask) == 0; +} - macro Allocate(sizeInBytes: intptr, map: Map): UninitializedHeapObject { - assert(ValidAllocationSize(sizeInBytes, map)); - return AllocateAllowLOS(sizeInBytes); - } +macro ValidAllocationSize(sizeInBytes: intptr, map: Map): bool { + if (sizeInBytes <= 0) return false; + if (!IsTaggedAligned(sizeInBytes)) return false; + const instanceSizeInWords = Convert(map.instance_size_in_words); + return instanceSizeInWords == kVariableSizeSentinel || + instanceSizeInWords * kTaggedSize == sizeInBytes; +} - macro InitializeFieldsFromIterator( - target: Slice, originIterator: Iterator) { - let targetIterator = target.Iterator(); - let originIterator = originIterator; - while (true) { - const ref:&T = targetIterator.NextReference() otherwise break; - * ref = originIterator.Next() otherwise unreachable; - } - } - // Dummy implementations: do not initialize for UninitializedIterator. - InitializeFieldsFromIterator( - _target: Slice, _originIterator: UninitializedIterator) {} - InitializeFieldsFromIterator( - _target: Slice, _originIterator: UninitializedIterator) {} - - extern macro IsDoubleHole(HeapObject, intptr): bool; - extern macro StoreDoubleHole(HeapObject, intptr); - - macro LoadFloat64OrHole(r:&float64_or_hole): float64_or_hole { - return float64_or_hole{ - is_hole: IsDoubleHole(r.object, r.offset - kHeapObjectTag), - value: * UnsafeNewReference(r.object, r.offset) - }; +type UninitializedHeapObject extends HeapObject; + +extern macro AllocateAllowLOS(intptr): UninitializedHeapObject; +extern macro GetInstanceTypeMap(constexpr InstanceType): Map; + +macro Allocate(sizeInBytes: intptr, map: Map): UninitializedHeapObject { + assert(ValidAllocationSize(sizeInBytes, map)); + return AllocateAllowLOS(sizeInBytes); +} + +macro InitializeFieldsFromIterator( + target: Slice, originIterator: Iterator) { + let targetIterator = target.Iterator(); + let originIterator = originIterator; + while (true) { + const ref:&T = targetIterator.NextReference() otherwise break; + * ref = originIterator.Next() otherwise unreachable; } - macro StoreFloat64OrHole(r:&float64_or_hole, value: float64_or_hole) { - if (value.is_hole) { - StoreDoubleHole(r.object, r.offset - kHeapObjectTag); - } else { - * UnsafeNewReference(r.object, r.offset) = value.value; - } +} +// Dummy implementations: do not initialize for UninitializedIterator. +InitializeFieldsFromIterator( + _target: Slice, _originIterator: UninitializedIterator) {} +InitializeFieldsFromIterator( + _target: Slice, _originIterator: UninitializedIterator) {} + +extern macro IsDoubleHole(HeapObject, intptr): bool; +extern macro StoreDoubleHole(HeapObject, intptr); + +macro LoadFloat64OrHole(r:&float64_or_hole): float64_or_hole { + return float64_or_hole{ + is_hole: IsDoubleHole(r.object, r.offset - kHeapObjectTag), + value: * unsafe::NewReference(r.object, r.offset) + }; +} +macro StoreFloat64OrHole(r:&float64_or_hole, value: float64_or_hole) { + if (value.is_hole) { + StoreDoubleHole(r.object, r.offset - kHeapObjectTag); + } else { + * unsafe::NewReference(r.object, r.offset) = value.value; } +} } // namespace torque_internal // Indicates that an array-field should not be initialized. diff --git a/deps/v8/src/builtins/typed-array-createtypedarray.tq b/deps/v8/src/builtins/typed-array-createtypedarray.tq index e5398fc50ac08b..ec51efc00abfdd 100644 --- a/deps/v8/src/builtins/typed-array-createtypedarray.tq +++ b/deps/v8/src/builtins/typed-array-createtypedarray.tq @@ -5,452 +5,431 @@ #include 'src/builtins/builtins-constructor-gen.h' namespace typed_array { - extern builtin IterableToListMayPreserveHoles(Context, Object, Callable): - JSArray; - - extern macro TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer( - implicit context: Context)(uintptr): JSArrayBuffer; - extern macro CodeStubAssembler::AllocateByteArray(uintptr): ByteArray; - extern macro TypedArrayBuiltinsAssembler::GetDefaultConstructor( - implicit context: Context)(JSTypedArray): JSFunction; - extern macro TypedArrayBuiltinsAssembler::SetupTypedArrayEmbedderFields( - JSTypedArray): void; - - extern runtime ThrowInvalidTypedArrayAlignment(implicit context: Context)( - Map, String): never; - - transitioning macro AllocateTypedArray(implicit context: Context)( - isOnHeap: constexpr bool, map: Map, buffer: JSArrayBuffer, - byteOffset: uintptr, byteLength: uintptr, length: uintptr): JSTypedArray { - let elements: ByteArray; - if constexpr (isOnHeap) { - elements = AllocateByteArray(byteLength); - } else { - elements = kEmptyByteArray; - - // The max byteOffset is 8 * MaxSmi on the particular platform. 32 bit - // platforms are self-limiting, because we can't allocate an array bigger - // than our 32-bit arithmetic range anyway. 64 bit platforms could - // theoretically have an offset up to 2^35 - 1. - const backingStore: uintptr = Convert(buffer.backing_store); - - // Assert no overflow has occurred. Only assert if the mock array buffer - // allocator is NOT used. When the mock array buffer is used, impossibly - // large allocations are allowed that would erroneously cause an overflow - // and this assertion to fail. - assert( - IsMockArrayBufferAllocatorFlag() || - (backingStore + byteOffset) >= backingStore); - } - - // We can't just build the new object with "new JSTypedArray" here because - // Torque doesn't know its full size including embedder fields, so use CSA - // for the allocation step. - const typedArray = - UnsafeCast(AllocateFastOrSlowJSObjectFromMap(map)); - typedArray.elements = elements; - typedArray.buffer = buffer; - typedArray.byte_offset = byteOffset; - typedArray.byte_length = byteLength; - typedArray.length = length; - if constexpr (isOnHeap) { - typed_array::SetJSTypedArrayOnHeapDataPtr( - typedArray, elements, byteOffset); - } else { - typed_array::SetJSTypedArrayOffHeapDataPtr( - typedArray, buffer.backing_store, byteOffset); - assert( - typedArray.data_ptr == - (buffer.backing_store + Convert(byteOffset))); - } - SetupTypedArrayEmbedderFields(typedArray); - return typedArray; +extern builtin IterableToListMayPreserveHoles( + Context, Object, Callable): JSArray; + +extern macro TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer( + implicit context: Context)(uintptr): JSArrayBuffer; +extern macro CodeStubAssembler::AllocateByteArray(uintptr): ByteArray; +extern macro TypedArrayBuiltinsAssembler::GetDefaultConstructor( + implicit context: Context)(JSTypedArray): JSFunction; +extern macro TypedArrayBuiltinsAssembler::SetupTypedArrayEmbedderFields( + JSTypedArray): void; + +extern runtime ThrowInvalidTypedArrayAlignment(implicit context: Context)( + Map, String): never; + +transitioning macro AllocateTypedArray(implicit context: Context)( + isOnHeap: constexpr bool, map: Map, buffer: JSArrayBuffer, + byteOffset: uintptr, byteLength: uintptr, length: uintptr): JSTypedArray { + let elements: ByteArray; + if constexpr (isOnHeap) { + elements = AllocateByteArray(byteLength); + } else { + elements = kEmptyByteArray; + + // The max byteOffset is 8 * MaxSmi on the particular platform. 32 bit + // platforms are self-limiting, because we can't allocate an array bigger + // than our 32-bit arithmetic range anyway. 64 bit platforms could + // theoretically have an offset up to 2^35 - 1. + const backingStore: uintptr = Convert(buffer.backing_store_ptr); + + // Assert no overflow has occurred. Only assert if the mock array buffer + // allocator is NOT used. When the mock array buffer is used, impossibly + // large allocations are allowed that would erroneously cause an overflow + // and this assertion to fail. + assert( + IsMockArrayBufferAllocatorFlag() || + (backingStore + byteOffset) >= backingStore); } - transitioning macro TypedArrayInitialize(implicit context: Context)( - initialize: constexpr bool, map: Map, length: uintptr, - elementsInfo: typed_array::TypedArrayElementsInfo, - bufferConstructor: JSReceiver): JSTypedArray labels IfRangeError { - const byteLength = elementsInfo.CalculateByteLength(length) - otherwise IfRangeError; - const byteLengthNum = Convert(byteLength); - const defaultConstructor = GetArrayBufferFunction(); - const byteOffset: uintptr = 0; - - try { - if (bufferConstructor != defaultConstructor) { - goto AttachOffHeapBuffer(ConstructWithTarget( - defaultConstructor, bufferConstructor, byteLengthNum)); - } + // We can't just build the new object with "new JSTypedArray" here because + // Torque doesn't know its full size including embedder fields, so use CSA + // for the allocation step. + const typedArray = + UnsafeCast(AllocateFastOrSlowJSObjectFromMap(map)); + typedArray.elements = elements; + typedArray.buffer = buffer; + typedArray.byte_offset = byteOffset; + typedArray.byte_length = byteLength; + typedArray.length = length; + if constexpr (isOnHeap) { + typed_array::SetJSTypedArrayOnHeapDataPtr(typedArray, elements, byteOffset); + } else { + typed_array::SetJSTypedArrayOffHeapDataPtr( + typedArray, buffer.backing_store_ptr, byteOffset); + assert( + typedArray.data_ptr == + (buffer.backing_store_ptr + Convert(byteOffset))); + } + SetupTypedArrayEmbedderFields(typedArray); + return typedArray; +} - if (byteLength > kMaxTypedArrayInHeap) goto AllocateOffHeap; +transitioning macro TypedArrayInitialize(implicit context: Context)( + initialize: constexpr bool, map: Map, length: uintptr, + elementsInfo: typed_array::TypedArrayElementsInfo, + bufferConstructor: JSReceiver): JSTypedArray labels IfRangeError { + const byteLength = elementsInfo.CalculateByteLength(length) + otherwise IfRangeError; + const byteLengthNum = Convert(byteLength); + const defaultConstructor = GetArrayBufferFunction(); + const byteOffset: uintptr = 0; + + try { + if (bufferConstructor != defaultConstructor) { + goto AttachOffHeapBuffer(ConstructWithTarget( + defaultConstructor, bufferConstructor, byteLengthNum)); + } - const buffer = AllocateEmptyOnHeapBuffer(byteLength); + if (byteLength > kMaxTypedArrayInHeap) goto AllocateOffHeap; - const isOnHeap: constexpr bool = true; - const typedArray = AllocateTypedArray( - isOnHeap, map, buffer, byteOffset, byteLength, length); + const buffer = AllocateEmptyOnHeapBuffer(byteLength); - if constexpr (initialize) { - const backingStore = typedArray.data_ptr; - typed_array::CallCMemset(backingStore, 0, byteLength); - } + const isOnHeap: constexpr bool = true; + const typedArray = AllocateTypedArray( + isOnHeap, map, buffer, byteOffset, byteLength, length); - return typedArray; + if constexpr (initialize) { + const backingStore = typedArray.data_ptr; + typed_array::CallCMemset(backingStore, 0, byteLength); } - label AllocateOffHeap { - if constexpr (initialize) { - goto AttachOffHeapBuffer(Construct(defaultConstructor, byteLengthNum)); - } else { - goto AttachOffHeapBuffer(Call( - context, GetArrayBufferNoInitFunction(), Undefined, byteLengthNum)); - } - } - label AttachOffHeapBuffer(bufferObj: Object) { - const buffer = Cast(bufferObj) otherwise unreachable; - const isOnHeap: constexpr bool = false; - return AllocateTypedArray( - isOnHeap, map, buffer, byteOffset, byteLength, length); + + return typedArray; + } label AllocateOffHeap { + if constexpr (initialize) { + goto AttachOffHeapBuffer(Construct(defaultConstructor, byteLengthNum)); + } else { + goto AttachOffHeapBuffer(Call( + context, GetArrayBufferNoInitFunction(), Undefined, byteLengthNum)); } + } label AttachOffHeapBuffer(bufferObj: Object) { + const buffer = Cast(bufferObj) otherwise unreachable; + const isOnHeap: constexpr bool = false; + return AllocateTypedArray( + isOnHeap, map, buffer, byteOffset, byteLength, length); } +} - // 22.2.4.2 TypedArray ( length ) - // ES #sec-typedarray-length - transitioning macro ConstructByLength(implicit context: Context)( - map: Map, lengthObj: JSAny, - elementsInfo: typed_array::TypedArrayElementsInfo): JSTypedArray { - try { - const length: uintptr = ToIndex(lengthObj) otherwise RangeError; - const defaultConstructor: Constructor = GetArrayBufferFunction(); - const initialize: constexpr bool = true; - return TypedArrayInitialize( - initialize, map, length, elementsInfo, defaultConstructor) - otherwise RangeError; - } - label RangeError deferred { - ThrowRangeError(MessageTemplate::kInvalidTypedArrayLength, lengthObj); - } +// 22.2.4.2 TypedArray ( length ) +// ES #sec-typedarray-length +transitioning macro ConstructByLength(implicit context: Context)( + map: Map, lengthObj: JSAny, + elementsInfo: typed_array::TypedArrayElementsInfo): JSTypedArray { + try { + const length: uintptr = ToIndex(lengthObj) otherwise RangeError; + const defaultConstructor: Constructor = GetArrayBufferFunction(); + const initialize: constexpr bool = true; + return TypedArrayInitialize( + initialize, map, length, elementsInfo, defaultConstructor) + otherwise RangeError; + } label RangeError deferred { + ThrowRangeError(MessageTemplate::kInvalidTypedArrayLength, lengthObj); } +} + +// 22.2.4.4 TypedArray ( object ) +// ES #sec-typedarray-object +transitioning macro ConstructByArrayLike(implicit context: Context)( + map: Map, arrayLike: HeapObject, length: uintptr, + elementsInfo: typed_array::TypedArrayElementsInfo, + bufferConstructor: JSReceiver): JSTypedArray { + try { + const initialize: constexpr bool = false; + const typedArray = TypedArrayInitialize( + initialize, map, length, elementsInfo, bufferConstructor) + otherwise RangeError; - // 22.2.4.4 TypedArray ( object ) - // ES #sec-typedarray-object - transitioning macro ConstructByArrayLike(implicit context: Context)( - map: Map, arrayLike: HeapObject, length: uintptr, - elementsInfo: typed_array::TypedArrayElementsInfo, - bufferConstructor: JSReceiver): JSTypedArray { try { - const initialize: constexpr bool = false; - const typedArray = TypedArrayInitialize( - initialize, map, length, elementsInfo, bufferConstructor) - otherwise RangeError; - - try { - const src: JSTypedArray = - Cast(arrayLike) otherwise IfSlow; - - if (IsDetachedBuffer(src.buffer)) { - ThrowTypeError(MessageTemplate::kDetachedOperation, 'Construct'); - - } else if (src.elements_kind != elementsInfo.kind) { - goto IfSlow; - - } else if (length > 0) { - const byteLength = typedArray.byte_length; - assert(byteLength <= kArrayBufferMaxByteLength); - typed_array::CallCMemcpy( - typedArray.data_ptr, src.data_ptr, byteLength); - } + const src: JSTypedArray = Cast(arrayLike) otherwise IfSlow; + + if (IsDetachedBuffer(src.buffer)) { + ThrowTypeError(MessageTemplate::kDetachedOperation, 'Construct'); + + } else if (src.elements_kind != elementsInfo.kind) { + goto IfSlow; + + } else if (length > 0) { + const byteLength = typedArray.byte_length; + assert(byteLength <= kArrayBufferMaxByteLength); + typed_array::CallCMemcpy(typedArray.data_ptr, src.data_ptr, byteLength); } - label IfSlow deferred { - if (length > 0) { - TypedArrayCopyElements( - context, typedArray, arrayLike, Convert(length)); - } + } label IfSlow deferred { + if (length > 0) { + TypedArrayCopyElements( + context, typedArray, arrayLike, Convert(length)); } - return typedArray; - } - label RangeError deferred { - ThrowRangeError( - MessageTemplate::kInvalidTypedArrayLength, Convert(length)); } + return typedArray; + } label RangeError deferred { + ThrowRangeError( + MessageTemplate::kInvalidTypedArrayLength, Convert(length)); } +} - // 22.2.4.4 TypedArray ( object ) - // ES #sec-typedarray-object - transitioning macro ConstructByIterable(implicit context: Context)( - iterable: JSReceiver, iteratorFn: Callable): never - labels IfConstructByArrayLike(JSArray, uintptr, JSReceiver) { - const array: JSArray = - IterableToListMayPreserveHoles(context, iterable, iteratorFn); - // Max JSArray length is a valid JSTypedArray length so we just use it. - goto IfConstructByArrayLike( - array, array.length_uintptr, GetArrayBufferFunction()); - } +// 22.2.4.4 TypedArray ( object ) +// ES #sec-typedarray-object +transitioning macro ConstructByIterable(implicit context: Context)( + iterable: JSReceiver, iteratorFn: Callable): never + labels IfConstructByArrayLike(JSArray, uintptr, JSReceiver) { + const array: JSArray = + IterableToListMayPreserveHoles(context, iterable, iteratorFn); + // Max JSArray length is a valid JSTypedArray length so we just use it. + goto IfConstructByArrayLike( + array, array.length_uintptr, GetArrayBufferFunction()); +} - // 22.2.4.3 TypedArray ( typedArray ) - // ES #sec-typedarray-typedarray - transitioning macro ConstructByTypedArray(implicit context: Context)( - srcTypedArray: JSTypedArray): never - labels IfConstructByArrayLike(JSTypedArray, uintptr, JSReceiver) { - let bufferConstructor: JSReceiver = GetArrayBufferFunction(); - const srcBuffer: JSArrayBuffer = srcTypedArray.buffer; +// 22.2.4.3 TypedArray ( typedArray ) +// ES #sec-typedarray-typedarray +transitioning macro ConstructByTypedArray(implicit context: Context)( + srcTypedArray: JSTypedArray): never + labels IfConstructByArrayLike(JSTypedArray, uintptr, JSReceiver) { + let bufferConstructor: JSReceiver = GetArrayBufferFunction(); + const srcBuffer: JSArrayBuffer = srcTypedArray.buffer; + // TODO(petermarshall): Throw on detached typedArray. + let length: uintptr = IsDetachedBuffer(srcBuffer) ? 0 : srcTypedArray.length; + + // The spec requires that constructing a typed array using a SAB-backed + // typed array use the ArrayBuffer constructor, not the species constructor. + // See https://tc39.github.io/ecma262/#sec-typedarray-typedarray. + if (!IsSharedArrayBuffer(srcBuffer)) { + bufferConstructor = SpeciesConstructor(srcBuffer, bufferConstructor); // TODO(petermarshall): Throw on detached typedArray. - let length: uintptr = - IsDetachedBuffer(srcBuffer) ? 0 : srcTypedArray.length; - - // The spec requires that constructing a typed array using a SAB-backed - // typed array use the ArrayBuffer constructor, not the species constructor. - // See https://tc39.github.io/ecma262/#sec-typedarray-typedarray. - if (!IsSharedArrayBuffer(srcBuffer)) { - bufferConstructor = SpeciesConstructor(srcBuffer, bufferConstructor); - // TODO(petermarshall): Throw on detached typedArray. - if (IsDetachedBuffer(srcBuffer)) length = 0; - } - goto IfConstructByArrayLike(srcTypedArray, length, bufferConstructor); + if (IsDetachedBuffer(srcBuffer)) length = 0; } + goto IfConstructByArrayLike(srcTypedArray, length, bufferConstructor); +} - // 22.2.4.5 TypedArray ( buffer, byteOffset, length ) - // ES #sec-typedarray-buffer-byteoffset-length - transitioning macro ConstructByArrayBuffer(implicit context: Context)( - map: Map, buffer: JSArrayBuffer, byteOffset: JSAny, length: JSAny, - elementsInfo: typed_array::TypedArrayElementsInfo): JSTypedArray { - try { - // 6. Let offset be ? ToIndex(byteOffset). - const offset: uintptr = ToIndex(byteOffset) otherwise IfInvalidOffset; +// 22.2.4.5 TypedArray ( buffer, byteOffset, length ) +// ES #sec-typedarray-buffer-byteoffset-length +transitioning macro ConstructByArrayBuffer(implicit context: Context)( + map: Map, buffer: JSArrayBuffer, byteOffset: JSAny, length: JSAny, + elementsInfo: typed_array::TypedArrayElementsInfo): JSTypedArray { + try { + // 6. Let offset be ? ToIndex(byteOffset). + const offset: uintptr = ToIndex(byteOffset) otherwise IfInvalidOffset; + + // 7. If offset modulo elementSize ≠ 0, throw a RangeError exception. + if (elementsInfo.IsUnaligned(offset)) { + goto IfInvalidAlignment('start offset'); + } - // 7. If offset modulo elementSize ≠ 0, throw a RangeError exception. - if (elementsInfo.IsUnaligned(offset)) { - goto IfInvalidAlignment('start offset'); - } + // 8. If length is present and length is not undefined, then + // a. Let newLength be ? ToIndex(length). + let newLength: uintptr = ToIndex(length) otherwise IfInvalidLength; + let newByteLength: uintptr; - // 8. If length is present and length is not undefined, then - // a. Let newLength be ? ToIndex(length). - let newLength: uintptr = ToIndex(length) otherwise IfInvalidLength; - let newByteLength: uintptr; + // 9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. + if (IsDetachedBuffer(buffer)) { + ThrowTypeError(MessageTemplate::kDetachedOperation, 'Construct'); + } - // 9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. - if (IsDetachedBuffer(buffer)) { - ThrowTypeError(MessageTemplate::kDetachedOperation, 'Construct'); - } + // 10. Let bufferByteLength be buffer.[[ArrayBufferByteLength]]. + const bufferByteLength: uintptr = buffer.byte_length; - // 10. Let bufferByteLength be buffer.[[ArrayBufferByteLength]]. - const bufferByteLength: uintptr = buffer.byte_length; - - // 11. If length is either not present or undefined, then - if (length == Undefined) { - // a. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError - // exception. - if (elementsInfo.IsUnaligned(bufferByteLength)) { - goto IfInvalidAlignment('byte length'); - } - - // b. Let newByteLength be bufferByteLength - offset. - // c. If newByteLength < 0, throw a RangeError exception. - if (bufferByteLength < offset) goto IfInvalidOffset; - - // Spec step 16 length calculated here to avoid recalculating the length - // in the step 12 branch. - newByteLength = bufferByteLength - offset; - newLength = elementsInfo.CalculateLength(newByteLength) - otherwise IfInvalidOffset; - - // 12. Else, - } else { - // a. Let newByteLength be newLength × elementSize. - newByteLength = elementsInfo.CalculateByteLength(newLength) - otherwise IfInvalidLength; - - // b. If offset + newByteLength > bufferByteLength, throw a RangeError - // exception. - if ((bufferByteLength < newByteLength) || - (offset > bufferByteLength - newByteLength)) - goto IfInvalidLength; + // 11. If length is either not present or undefined, then + if (length == Undefined) { + // a. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError + // exception. + if (elementsInfo.IsUnaligned(bufferByteLength)) { + goto IfInvalidAlignment('byte length'); } - const isOnHeap: constexpr bool = false; - return AllocateTypedArray( - isOnHeap, map, buffer, offset, newByteLength, newLength); - } - label IfInvalidAlignment(problemString: String) deferred { - ThrowInvalidTypedArrayAlignment(map, problemString); - } - label IfInvalidLength deferred { - ThrowRangeError(MessageTemplate::kInvalidTypedArrayLength, length); - } - label IfInvalidOffset deferred { - ThrowRangeError(MessageTemplate::kInvalidOffset, byteOffset); - } - } + // b. Let newByteLength be bufferByteLength - offset. + // c. If newByteLength < 0, throw a RangeError exception. + if (bufferByteLength < offset) goto IfInvalidOffset; - // 22.2.4.6 TypedArrayCreate ( constructor, argumentList ) - // ES #typedarray-create - @export - transitioning macro TypedArrayCreateByLength(implicit context: Context)( - constructor: Constructor, length: Number, methodName: constexpr string): - JSTypedArray { - assert(IsSafeInteger(length)); + // Spec step 16 length calculated here to avoid recalculating the length + // in the step 12 branch. + newByteLength = bufferByteLength - offset; + newLength = elementsInfo.CalculateLength(newByteLength) + otherwise IfInvalidOffset; - // 1. Let newTypedArray be ? Construct(constructor, argumentList). - const newTypedArrayObj = Construct(constructor, length); + // 12. Else, + } else { + // a. Let newByteLength be newLength × elementSize. + newByteLength = elementsInfo.CalculateByteLength(newLength) + otherwise IfInvalidLength; + + // b. If offset + newByteLength > bufferByteLength, throw a RangeError + // exception. + if ((bufferByteLength < newByteLength) || + (offset > bufferByteLength - newByteLength)) + goto IfInvalidLength; + } - // 2. Perform ? ValidateTypedArray(newTypedArray). - // ValidateTypedArray currently returns the array, not the ViewBuffer. - const newTypedArray: JSTypedArray = - ValidateTypedArray(context, newTypedArrayObj, methodName); + const isOnHeap: constexpr bool = false; + return AllocateTypedArray( + isOnHeap, map, buffer, offset, newByteLength, newLength); + } label IfInvalidAlignment(problemString: String) deferred { + ThrowInvalidTypedArrayAlignment(map, problemString); + } label IfInvalidLength deferred { + ThrowRangeError(MessageTemplate::kInvalidTypedArrayLength, length); + } label IfInvalidOffset deferred { + ThrowRangeError(MessageTemplate::kInvalidOffset, byteOffset); + } +} - if (IsDetachedBuffer(newTypedArray.buffer)) deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, methodName); - } +// 22.2.4.6 TypedArrayCreate ( constructor, argumentList ) +// ES #typedarray-create +@export +transitioning macro TypedArrayCreateByLength(implicit context: Context)( + constructor: Constructor, length: Number, methodName: constexpr string): + JSTypedArray { + assert(IsSafeInteger(length)); - // 3. If argumentList is a List of a single Number, then - // a. If newTypedArray.[[ArrayLength]] < argumentList[0], throw a - // TypeError exception. - if (newTypedArray.length < Convert(length)) deferred { - ThrowTypeError(MessageTemplate::kTypedArrayTooShort); - } + // 1. Let newTypedArray be ? Construct(constructor, argumentList). + const newTypedArrayObj = Construct(constructor, length); - // 4. Return newTypedArray. - return newTypedArray; - } + // 2. Perform ? ValidateTypedArray(newTypedArray). + // ValidateTypedArray currently returns the array, not the ViewBuffer. + const newTypedArray: JSTypedArray = + ValidateTypedArray(context, newTypedArrayObj, methodName); - transitioning macro ConstructByJSReceiver(implicit context: - Context)(obj: JSReceiver): never - labels IfConstructByArrayLike(JSReceiver, uintptr, JSReceiver) { - try { - // TODO(v8:8906): Use iterator::GetIteratorMethod() once it supports - // labels. - const iteratorMethod = GetMethod(obj, IteratorSymbolConstant()) - otherwise IfIteratorUndefined, IfIteratorNotCallable; - ConstructByIterable(obj, iteratorMethod) - otherwise IfConstructByArrayLike; - } - label IfIteratorUndefined { - const lengthObj: JSAny = GetProperty(obj, kLengthString); - const lengthNumber: Number = ToLength_Inline(lengthObj); - // Throw RangeError here if the length does not fit in uintptr because - // such a length will not pass bounds checks in ConstructByArrayLike() - // anyway. - const length: uintptr = ChangeSafeIntegerNumberToUintPtr(lengthNumber) - otherwise goto IfInvalidLength(lengthNumber); - goto IfConstructByArrayLike(obj, length, GetArrayBufferFunction()); - } - label IfInvalidLength(length: Number) { - ThrowRangeError(MessageTemplate::kInvalidTypedArrayLength, length); + if (IsDetachedBuffer(newTypedArray.buffer)) deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, methodName); } - label IfIteratorNotCallable(_value: JSAny) deferred { - ThrowTypeError(MessageTemplate::kIteratorSymbolNonCallable); + + // 3. If argumentList is a List of a single Number, then + // a. If newTypedArray.[[ArrayLength]] < argumentList[0], throw a + // TypeError exception. + if (newTypedArray.length < Convert(length)) deferred { + ThrowTypeError(MessageTemplate::kTypedArrayTooShort); } - } - // 22.2.4 The TypedArray Constructors - // ES #sec-typedarray-constructors - transitioning builtin CreateTypedArray( - context: Context, target: JSFunction, newTarget: JSReceiver, arg1: JSAny, - arg2: JSAny, arg3: JSAny): JSTypedArray { - assert(IsConstructor(target)); - // 4. Let O be ? AllocateTypedArray(constructorName, NewTarget, - // "%TypedArrayPrototype%"). - const map = GetDerivedMap(target, newTarget); + // 4. Return newTypedArray. + return newTypedArray; +} - // 5. Let elementSize be the Number value of the Element Size value in Table - // 56 for constructorName. - const elementsInfo = GetTypedArrayElementsInfo(map); +transitioning macro ConstructByJSReceiver(implicit context: Context)( + obj: JSReceiver): never + labels IfConstructByArrayLike(JSReceiver, uintptr, JSReceiver) { + try { + // TODO(v8:8906): Use iterator::GetIteratorMethod() once it supports + // labels. + const iteratorMethod = GetMethod(obj, IteratorSymbolConstant()) + otherwise IfIteratorUndefined, IfIteratorNotCallable; + ConstructByIterable(obj, iteratorMethod) + otherwise IfConstructByArrayLike; + } label IfIteratorUndefined { + const lengthObj: JSAny = GetProperty(obj, kLengthString); + const lengthNumber: Number = ToLength_Inline(lengthObj); + // Throw RangeError here if the length does not fit in uintptr because + // such a length will not pass bounds checks in ConstructByArrayLike() + // anyway. + const length: uintptr = ChangeSafeIntegerNumberToUintPtr(lengthNumber) + otherwise goto IfInvalidLength(lengthNumber); + goto IfConstructByArrayLike(obj, length, GetArrayBufferFunction()); + } label IfInvalidLength(length: Number) { + ThrowRangeError(MessageTemplate::kInvalidTypedArrayLength, length); + } label IfIteratorNotCallable(_value: JSAny) deferred { + ThrowTypeError(MessageTemplate::kIteratorSymbolNonCallable); + } +} - try { - typeswitch (arg1) { - case (length: Smi): { - goto IfConstructByLength(length); - } - case (buffer: JSArrayBuffer): { - return ConstructByArrayBuffer(map, buffer, arg2, arg3, elementsInfo); - } - case (typedArray: JSTypedArray): { - ConstructByTypedArray(typedArray) otherwise IfConstructByArrayLike; - } - case (obj: JSReceiver): { - ConstructByJSReceiver(obj) otherwise IfConstructByArrayLike; - } - // The first argument was a number or fell through and is treated as - // a number. https://tc39.github.io/ecma262/#sec-typedarray-length - case (lengthObj: JSAny): { - goto IfConstructByLength(lengthObj); - } +// 22.2.4 The TypedArray Constructors +// ES #sec-typedarray-constructors +transitioning builtin CreateTypedArray( + context: Context, target: JSFunction, newTarget: JSReceiver, arg1: JSAny, + arg2: JSAny, arg3: JSAny): JSTypedArray { + assert(IsConstructor(target)); + // 4. Let O be ? AllocateTypedArray(constructorName, NewTarget, + // "%TypedArrayPrototype%"). + const map = GetDerivedMap(target, newTarget); + + // 5. Let elementSize be the Number value of the Element Size value in Table + // 56 for constructorName. + const elementsInfo = GetTypedArrayElementsInfo(map); + + try { + typeswitch (arg1) { + case (length: Smi): { + goto IfConstructByLength(length); + } + case (buffer: JSArrayBuffer): { + return ConstructByArrayBuffer(map, buffer, arg2, arg3, elementsInfo); + } + case (typedArray: JSTypedArray): { + ConstructByTypedArray(typedArray) otherwise IfConstructByArrayLike; + } + case (obj: JSReceiver): { + ConstructByJSReceiver(obj) otherwise IfConstructByArrayLike; + } + // The first argument was a number or fell through and is treated as + // a number. https://tc39.github.io/ecma262/#sec-typedarray-length + case (lengthObj: JSAny): { + goto IfConstructByLength(lengthObj); } } - label IfConstructByLength(length: JSAny) { - return ConstructByLength(map, length, elementsInfo); - } - label IfConstructByArrayLike( - arrayLike: JSReceiver, length: uintptr, bufferConstructor: JSReceiver) { - return ConstructByArrayLike( - map, arrayLike, length, elementsInfo, bufferConstructor); - } + } label IfConstructByLength(length: JSAny) { + return ConstructByLength(map, length, elementsInfo); + } label IfConstructByArrayLike( + arrayLike: JSReceiver, length: uintptr, bufferConstructor: JSReceiver) { + return ConstructByArrayLike( + map, arrayLike, length, elementsInfo, bufferConstructor); } +} - transitioning macro TypedArraySpeciesCreate(implicit context: Context)( - methodName: constexpr string, numArgs: constexpr int31, - exemplar: JSTypedArray, arg0: JSAny, arg1: JSAny, - arg2: JSAny): JSTypedArray { - const defaultConstructor = GetDefaultConstructor(exemplar); +transitioning macro TypedArraySpeciesCreate(implicit context: Context)( + methodName: constexpr string, numArgs: constexpr int31, + exemplar: JSTypedArray, arg0: JSAny, arg1: JSAny, + arg2: JSAny): JSTypedArray { + const defaultConstructor = GetDefaultConstructor(exemplar); - try { - if (!IsPrototypeTypedArrayPrototype(exemplar.map)) goto IfSlow; - if (IsTypedArraySpeciesProtectorCellInvalid()) goto IfSlow; + try { + if (!IsPrototypeTypedArrayPrototype(exemplar.map)) goto IfSlow; + if (IsTypedArraySpeciesProtectorCellInvalid()) goto IfSlow; - const typedArray = CreateTypedArray( - context, defaultConstructor, defaultConstructor, arg0, arg1, arg2); + const typedArray = CreateTypedArray( + context, defaultConstructor, defaultConstructor, arg0, arg1, arg2); - // It is assumed that the CreateTypedArray builtin does not produce a - // typed array that fails ValidateTypedArray - assert(!IsDetachedBuffer(typedArray.buffer)); + // It is assumed that the CreateTypedArray builtin does not produce a + // typed array that fails ValidateTypedArray + assert(!IsDetachedBuffer(typedArray.buffer)); - return typedArray; + return typedArray; + } label IfSlow deferred { + const constructor = + Cast(SpeciesConstructor(exemplar, defaultConstructor)) + otherwise unreachable; + + // TODO(pwong): Simplify and remove numArgs when varargs are supported in + // macros. + let newObj: JSAny = Undefined; + if constexpr (numArgs == 1) { + newObj = Construct(constructor, arg0); + } else { + assert(numArgs == 3); + newObj = Construct(constructor, arg0, arg1, arg2); } - label IfSlow deferred { - const constructor = - Cast(SpeciesConstructor(exemplar, defaultConstructor)) - otherwise unreachable; - - // TODO(pwong): Simplify and remove numArgs when varargs are supported in - // macros. - let newObj: JSAny = Undefined; - if constexpr (numArgs == 1) { - newObj = Construct(constructor, arg0); - } else { - assert(numArgs == 3); - newObj = Construct(constructor, arg0, arg1, arg2); - } - return ValidateTypedArray(context, newObj, methodName); - } + return ValidateTypedArray(context, newObj, methodName); } +} - @export - transitioning macro TypedArraySpeciesCreateByLength(implicit context: - Context)( - methodName: constexpr string, exemplar: JSTypedArray, length: uintptr): - JSTypedArray { - const numArgs: constexpr int31 = 1; - // TODO(v8:4153): pass length further as uintptr. - const typedArray: JSTypedArray = TypedArraySpeciesCreate( - methodName, numArgs, exemplar, Convert(length), Undefined, - Undefined); - if (typedArray.length < length) deferred { - ThrowTypeError(MessageTemplate::kTypedArrayTooShort); - } - return typedArray; - } +@export +transitioning macro TypedArraySpeciesCreateByLength(implicit context: Context)( + methodName: constexpr string, exemplar: JSTypedArray, length: uintptr): + JSTypedArray { + const numArgs: constexpr int31 = 1; + // TODO(v8:4153): pass length further as uintptr. + const typedArray: JSTypedArray = TypedArraySpeciesCreate( + methodName, numArgs, exemplar, Convert(length), Undefined, + Undefined); + if (typedArray.length < length) deferred { + ThrowTypeError(MessageTemplate::kTypedArrayTooShort); + } + return typedArray; +} - transitioning macro TypedArraySpeciesCreateByBuffer(implicit context: - Context)( - methodName: constexpr string, exemplar: JSTypedArray, - buffer: JSArrayBuffer, beginByteOffset: uintptr, - newLength: uintptr): JSTypedArray { - const numArgs: constexpr int31 = 3; - // TODO(v8:4153): pass length further as uintptr. - const typedArray: JSTypedArray = TypedArraySpeciesCreate( - methodName, numArgs, exemplar, buffer, Convert(beginByteOffset), - Convert(newLength)); - return typedArray; - } +transitioning macro TypedArraySpeciesCreateByBuffer(implicit context: Context)( + methodName: constexpr string, exemplar: JSTypedArray, buffer: JSArrayBuffer, + beginByteOffset: uintptr, newLength: uintptr): JSTypedArray { + const numArgs: constexpr int31 = 3; + // TODO(v8:4153): pass length further as uintptr. + const typedArray: JSTypedArray = TypedArraySpeciesCreate( + methodName, numArgs, exemplar, buffer, Convert(beginByteOffset), + Convert(newLength)); + return typedArray; +} } diff --git a/deps/v8/src/builtins/typed-array-every.tq b/deps/v8/src/builtins/typed-array-every.tq index cba688244b59ea..fdd4961dee64ab 100644 --- a/deps/v8/src/builtins/typed-array-every.tq +++ b/deps/v8/src/builtins/typed-array-every.tq @@ -5,52 +5,49 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameEvery: constexpr string = '%TypedArray%.prototype.every'; +const kBuiltinNameEvery: constexpr string = '%TypedArray%.prototype.every'; - transitioning macro EveryAllElements(implicit context: Context)( - array: typed_array::AttachedJSTypedArray, callbackfn: Callable, - thisArg: JSAny): Boolean { - let witness = typed_array::NewAttachedJSTypedArrayWitness(array); - const length: uintptr = witness.Get().length; - for (let k: uintptr = 0; k < length; k++) { - // BUG(4895): We should throw on detached buffers rather than simply exit. - witness.Recheck() otherwise break; - const value: JSAny = witness.Load(k); - // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi - // indices to optimize Convert(k) for the most common case. - const result = Call( - context, callbackfn, thisArg, value, Convert(k), - witness.GetStable()); - if (!ToBoolean(result)) { - return False; - } +transitioning macro EveryAllElements(implicit context: Context)( + array: typed_array::AttachedJSTypedArray, callbackfn: Callable, + thisArg: JSAny): Boolean { + let witness = typed_array::NewAttachedJSTypedArrayWitness(array); + const length: uintptr = witness.Get().length; + for (let k: uintptr = 0; k < length; k++) { + // BUG(4895): We should throw on detached buffers rather than simply exit. + witness.Recheck() otherwise break; + const value: JSAny = witness.Load(k); + // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi + // indices to optimize Convert(k) for the most common case. + const result = Call( + context, callbackfn, thisArg, value, Convert(k), + witness.GetStable()); + if (!ToBoolean(result)) { + return False; } - return True; } + return True; +} - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.every - transitioning javascript builtin - TypedArrayPrototypeEvery(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - // arguments[0] = callback - // arguments[1] = thisArg - try { - const array: JSTypedArray = Cast(receiver) - otherwise NotTypedArray; - const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.every +transitioning javascript builtin +TypedArrayPrototypeEvery( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // arguments[0] = callback + // arguments[1] = thisArg + try { + const array: JSTypedArray = Cast(receiver) + otherwise NotTypedArray; + const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; - const callbackfn = Cast(arguments[0]) otherwise NotCallable; - const thisArg = arguments[1]; - return EveryAllElements(uarray, callbackfn, thisArg); - } - label NotCallable deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); - } - label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameEvery); - } - label IsDetached deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameEvery); - } + const callbackfn = Cast(arguments[0]) otherwise NotCallable; + const thisArg = arguments[1]; + return EveryAllElements(uarray, callbackfn, thisArg); + } label NotCallable deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameEvery); + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameEvery); } } +} diff --git a/deps/v8/src/builtins/typed-array-filter.tq b/deps/v8/src/builtins/typed-array-filter.tq index dd3b4900dc70bf..15d40f92ebe53b 100644 --- a/deps/v8/src/builtins/typed-array-filter.tq +++ b/deps/v8/src/builtins/typed-array-filter.tq @@ -3,85 +3,81 @@ // found in the LICENSE file. namespace typed_array { - const kBuiltinNameFilter: constexpr string = '%TypedArray%.prototype.filter'; +const kBuiltinNameFilter: constexpr string = '%TypedArray%.prototype.filter'; - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.filter - transitioning javascript builtin TypedArrayPrototypeFilter( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - // arguments[0] = callback - // arguments[1] = thisArg - try { - // 1. Let O be the this value. - // 2. Perform ? ValidateTypedArray(O). - const array: JSTypedArray = Cast(receiver) - otherwise ThrowTypeError( - MessageTemplate::kNotTypedArray, kBuiltinNameFilter); - const src = typed_array::EnsureAttached(array) otherwise IsDetached; +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.filter +transitioning javascript builtin TypedArrayPrototypeFilter( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // arguments[0] = callback + // arguments[1] = thisArg + try { + // 1. Let O be the this value. + // 2. Perform ? ValidateTypedArray(O). + const array: JSTypedArray = Cast(receiver) + otherwise ThrowTypeError( + MessageTemplate::kNotTypedArray, kBuiltinNameFilter); + const src = typed_array::EnsureAttached(array) otherwise IsDetached; - // 3. Let len be O.[[ArrayLength]]. - const len: uintptr = src.length; + // 3. Let len be O.[[ArrayLength]]. + const len: uintptr = src.length; - // 4. If IsCallable(callbackfn) is false, throw a TypeError exception. - const callbackfn = Cast(arguments[0]) - otherwise ThrowTypeError( - MessageTemplate::kCalledNonCallable, arguments[0]); + // 4. If IsCallable(callbackfn) is false, throw a TypeError exception. + const callbackfn = Cast(arguments[0]) + otherwise ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); - // 5. If thisArg is present, let T be thisArg; else let T be undefined. - const thisArg: JSAny = arguments[1]; + // 5. If thisArg is present, let T be thisArg; else let T be undefined. + const thisArg: JSAny = arguments[1]; - // 6. Let kept be a new empty List. - // TODO(v8:4153): Support huge TypedArrays here. (growable fixed arrays - // can't be longer than kMaxSmiValue). - let kept = growable_fixed_array::NewGrowableFixedArray(); - let witness = typed_array::NewAttachedJSTypedArrayWitness(src); + // 6. Let kept be a new empty List. + // TODO(v8:4153): Support huge TypedArrays here. (growable fixed arrays + // can't be longer than kMaxSmiValue). + let kept = growable_fixed_array::NewGrowableFixedArray(); + let witness = typed_array::NewAttachedJSTypedArrayWitness(src); - // 7. Let k be 0. - // 8. Let captured be 0. - // 9. Repeat, while k < len - for (let k: uintptr = 0; k < len; k++) { - witness.Recheck() otherwise IsDetached; + // 7. Let k be 0. + // 8. Let captured be 0. + // 9. Repeat, while k < len + for (let k: uintptr = 0; k < len; k++) { + witness.Recheck() otherwise IsDetached; - // a. Let Pk be ! ToString(k). - // b. Let kValue be ? Get(O, Pk). - const value: JSAny = witness.Load(k); + // a. Let Pk be ! ToString(k). + // b. Let kValue be ? Get(O, Pk). + const value: JSAny = witness.Load(k); - // c. Let selected be ToBoolean(? Call(callbackfn, T, « kValue, k, O - // »)). - // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi - // indices to optimize Convert(k) for the most common case. - const selected: JSAny = Call( - context, callbackfn, thisArg, value, Convert(k), - witness.GetStable()); + // c. Let selected be ToBoolean(? Call(callbackfn, T, « kValue, k, O + // »)). + // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi + // indices to optimize Convert(k) for the most common case. + const selected: JSAny = Call( + context, callbackfn, thisArg, value, Convert(k), + witness.GetStable()); - // d. If selected is true, then - // i. Append kValue to the end of kept. - // ii. Increase captured by 1. - if (ToBoolean(selected)) kept.Push(value); + // d. If selected is true, then + // i. Append kValue to the end of kept. + // ii. Increase captured by 1. + if (ToBoolean(selected)) kept.Push(value); - // e.Increase k by 1. - } + // e.Increase k by 1. + } - // 10. Let A be ? TypedArraySpeciesCreate(O, captured). - const typedArray: JSTypedArray = TypedArraySpeciesCreateByLength( - kBuiltinNameFilter, array, Unsigned(kept.length)); + // 10. Let A be ? TypedArraySpeciesCreate(O, captured). + const typedArray: JSTypedArray = TypedArraySpeciesCreateByLength( + kBuiltinNameFilter, array, Unsigned(kept.length)); - // 11. Let n be 0. - // 12. For each element e of kept, do - // a. Perform ! Set(A, ! ToString(n), e, true). - // b. Increment n by 1. - // TODO(v8:4153): Consider passing growable typed array directly to - // TypedArrayCopyElements() to avoid JSArray materialization. Or collect - // indices instead of values the loop above. - const lengthNumber = Convert(Unsigned(kept.length)); - TypedArrayCopyElements( - context, typedArray, kept.ToJSArray(), lengthNumber); + // 11. Let n be 0. + // 12. For each element e of kept, do + // a. Perform ! Set(A, ! ToString(n), e, true). + // b. Increment n by 1. + // TODO(v8:4153): Consider passing growable typed array directly to + // TypedArrayCopyElements() to avoid JSArray materialization. Or collect + // indices instead of values the loop above. + const lengthNumber = Convert(Unsigned(kept.length)); + TypedArrayCopyElements(context, typedArray, kept.ToJSArray(), lengthNumber); - // 13. Return A. - return typedArray; - } - label IsDetached deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameFilter); - } + // 13. Return A. + return typedArray; + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameFilter); } } +} diff --git a/deps/v8/src/builtins/typed-array-find.tq b/deps/v8/src/builtins/typed-array-find.tq index ef4954274b2c63..24a13dbc23eea1 100644 --- a/deps/v8/src/builtins/typed-array-find.tq +++ b/deps/v8/src/builtins/typed-array-find.tq @@ -5,52 +5,49 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameFind: constexpr string = '%TypedArray%.prototype.find'; +const kBuiltinNameFind: constexpr string = '%TypedArray%.prototype.find'; - transitioning macro FindAllElements(implicit context: Context)( - array: typed_array::AttachedJSTypedArray, callbackfn: Callable, - thisArg: JSAny): JSAny { - let witness = typed_array::NewAttachedJSTypedArrayWitness(array); - const length: uintptr = witness.Get().length; - for (let k: uintptr = 0; k < length; k++) { - // BUG(4895): We should throw on detached buffers rather than simply exit. - witness.Recheck() otherwise break; - const value: JSAny = witness.Load(k); - // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi - // indices to optimize Convert(k) for the most common case. - const result = Call( - context, callbackfn, thisArg, value, Convert(k), - witness.GetStable()); - if (ToBoolean(result)) { - return value; - } +transitioning macro FindAllElements(implicit context: Context)( + array: typed_array::AttachedJSTypedArray, callbackfn: Callable, + thisArg: JSAny): JSAny { + let witness = typed_array::NewAttachedJSTypedArrayWitness(array); + const length: uintptr = witness.Get().length; + for (let k: uintptr = 0; k < length; k++) { + // BUG(4895): We should throw on detached buffers rather than simply exit. + witness.Recheck() otherwise break; + const value: JSAny = witness.Load(k); + // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi + // indices to optimize Convert(k) for the most common case. + const result = Call( + context, callbackfn, thisArg, value, Convert(k), + witness.GetStable()); + if (ToBoolean(result)) { + return value; } - return Undefined; } + return Undefined; +} - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.find - transitioning javascript builtin - TypedArrayPrototypeFind(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - // arguments[0] = callback - // arguments[1] = thisArg - try { - const array: JSTypedArray = Cast(receiver) - otherwise NotTypedArray; - const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.find +transitioning javascript builtin +TypedArrayPrototypeFind( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // arguments[0] = callback + // arguments[1] = thisArg + try { + const array: JSTypedArray = Cast(receiver) + otherwise NotTypedArray; + const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; - const callbackfn = Cast(arguments[0]) otherwise NotCallable; - const thisArg = arguments[1]; - return FindAllElements(uarray, callbackfn, thisArg); - } - label NotCallable deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); - } - label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameFind); - } - label IsDetached deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameFind); - } + const callbackfn = Cast(arguments[0]) otherwise NotCallable; + const thisArg = arguments[1]; + return FindAllElements(uarray, callbackfn, thisArg); + } label NotCallable deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameFind); + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameFind); } } +} diff --git a/deps/v8/src/builtins/typed-array-findindex.tq b/deps/v8/src/builtins/typed-array-findindex.tq index 5af9aede2968a1..7bb01151f351f2 100644 --- a/deps/v8/src/builtins/typed-array-findindex.tq +++ b/deps/v8/src/builtins/typed-array-findindex.tq @@ -5,56 +5,50 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameFindIndex: constexpr string = - '%TypedArray%.prototype.findIndex'; +const kBuiltinNameFindIndex: constexpr string = + '%TypedArray%.prototype.findIndex'; - transitioning macro FindIndexAllElements(implicit context: Context)( - array: typed_array::AttachedJSTypedArray, callbackfn: Callable, - thisArg: JSAny): Number { - let witness = typed_array::NewAttachedJSTypedArrayWitness(array); - const length: uintptr = witness.Get().length; - for (let k: uintptr = 0; k < length; k++) { - // BUG(4895): We should throw on detached buffers rather than simply exit. - witness.Recheck() otherwise break; - const value: JSAny = witness.Load(k); - // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi - // indices to optimize Convert(k) for the most common case. - const indexNumber: Number = Convert(k); - const result = Call( - context, callbackfn, thisArg, value, indexNumber, - witness.GetStable()); - if (ToBoolean(result)) { - return indexNumber; - } +transitioning macro FindIndexAllElements(implicit context: Context)( + array: typed_array::AttachedJSTypedArray, callbackfn: Callable, + thisArg: JSAny): Number { + let witness = typed_array::NewAttachedJSTypedArrayWitness(array); + const length: uintptr = witness.Get().length; + for (let k: uintptr = 0; k < length; k++) { + // BUG(4895): We should throw on detached buffers rather than simply exit. + witness.Recheck() otherwise break; + const value: JSAny = witness.Load(k); + // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi + // indices to optimize Convert(k) for the most common case. + const indexNumber: Number = Convert(k); + const result = Call( + context, callbackfn, thisArg, value, indexNumber, witness.GetStable()); + if (ToBoolean(result)) { + return indexNumber; } - return -1; } + return -1; +} - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.findIndex - transitioning javascript builtin - TypedArrayPrototypeFindIndex( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - // arguments[0] = callback - // arguments[1] = thisArg. - try { - const array: JSTypedArray = Cast(receiver) - otherwise NotTypedArray; - const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.findIndex +transitioning javascript builtin +TypedArrayPrototypeFindIndex( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // arguments[0] = callback + // arguments[1] = thisArg. + try { + const array: JSTypedArray = Cast(receiver) + otherwise NotTypedArray; + const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; - const callbackfn = Cast(arguments[0]) otherwise NotCallable; - const thisArg = arguments[1]; - return FindIndexAllElements(uarray, callbackfn, thisArg); - } - label NotCallable deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); - } - label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameFindIndex); - } - label IsDetached deferred { - ThrowTypeError( - MessageTemplate::kDetachedOperation, kBuiltinNameFindIndex); - } + const callbackfn = Cast(arguments[0]) otherwise NotCallable; + const thisArg = arguments[1]; + return FindIndexAllElements(uarray, callbackfn, thisArg); + } label NotCallable deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameFindIndex); + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameFindIndex); } } +} diff --git a/deps/v8/src/builtins/typed-array-foreach.tq b/deps/v8/src/builtins/typed-array-foreach.tq index dd134174568916..d696d9c8dd8447 100644 --- a/deps/v8/src/builtins/typed-array-foreach.tq +++ b/deps/v8/src/builtins/typed-array-foreach.tq @@ -5,52 +5,47 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameForEach: constexpr string = - '%TypedArray%.prototype.forEach'; +const kBuiltinNameForEach: constexpr string = '%TypedArray%.prototype.forEach'; - transitioning macro ForEachAllElements(implicit context: Context)( - array: typed_array::AttachedJSTypedArray, callbackfn: Callable, - thisArg: JSAny): Undefined { - let witness = typed_array::NewAttachedJSTypedArrayWitness(array); - const length: uintptr = witness.Get().length; - for (let k: uintptr = 0; k < length; k++) { - // BUG(4895): We should throw on detached buffers rather than simply exit. - witness.Recheck() otherwise break; - const value: JSAny = witness.Load(k); - // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi - // indices to optimize Convert(k) for the most common case. - Call( - context, callbackfn, thisArg, value, Convert(k), - witness.GetStable()); - } - return Undefined; +transitioning macro ForEachAllElements(implicit context: Context)( + array: typed_array::AttachedJSTypedArray, callbackfn: Callable, + thisArg: JSAny): Undefined { + let witness = typed_array::NewAttachedJSTypedArrayWitness(array); + const length: uintptr = witness.Get().length; + for (let k: uintptr = 0; k < length; k++) { + // BUG(4895): We should throw on detached buffers rather than simply exit. + witness.Recheck() otherwise break; + const value: JSAny = witness.Load(k); + // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi + // indices to optimize Convert(k) for the most common case. + Call( + context, callbackfn, thisArg, value, Convert(k), + witness.GetStable()); } + return Undefined; +} - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.every - transitioning javascript builtin - TypedArrayPrototypeForEach( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): Undefined { - // arguments[0] = callback - // arguments[1] = this_arg. +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.every +transitioning javascript builtin +TypedArrayPrototypeForEach(js-implicit context: NativeContext, receiver: JSAny)( + ...arguments): Undefined { + // arguments[0] = callback + // arguments[1] = this_arg. - try { - const array: JSTypedArray = Cast(receiver) - otherwise NotTypedArray; - const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; + try { + const array: JSTypedArray = Cast(receiver) + otherwise NotTypedArray; + const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; - const callbackfn = Cast(arguments[0]) otherwise NotCallable; - const thisArg = arguments[1]; - return ForEachAllElements(uarray, callbackfn, thisArg); - } - label NotCallable deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); - } - label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameForEach); - } - label IsDetached deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameForEach); - } + const callbackfn = Cast(arguments[0]) otherwise NotCallable; + const thisArg = arguments[1]; + return ForEachAllElements(uarray, callbackfn, thisArg); + } label NotCallable deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameForEach); + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameForEach); } } +} diff --git a/deps/v8/src/builtins/typed-array-from.tq b/deps/v8/src/builtins/typed-array-from.tq index a0c2fa72a86314..56d4d1d6cf75d3 100644 --- a/deps/v8/src/builtins/typed-array-from.tq +++ b/deps/v8/src/builtins/typed-array-from.tq @@ -5,190 +5,179 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameFrom: constexpr string = '%TypedArray%.from'; +const kBuiltinNameFrom: constexpr string = '%TypedArray%.from'; + +type BuiltinsName extends int31 constexpr 'Builtins::Name'; +const kTypedArrayPrototypeValues: constexpr BuiltinsName + generates 'Builtins::kTypedArrayPrototypeValues'; + +extern builtin IterableToList(implicit context: Context)(JSAny, JSAny): JSArray; + +// %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] ) +// https://tc39.github.io/ecma262/#sec-%typedarray%.from +transitioning javascript builtin +TypedArrayFrom(js-implicit context: NativeContext, receiver: JSAny)( + ...arguments): JSTypedArray { + try { + const source: JSAny = arguments[0]; + const mapfnObj: JSAny = arguments[1]; + const thisArg = arguments[2]; + + // 1. Let C be the this value. + // 2. If IsConstructor(C) is false, throw a TypeError exception. + const constructor = Cast(receiver) otherwise NotConstructor; + + // 3. If mapfn is undefined, then let mapping be false. + // 4. Else, + // a. If IsCallable(mapfn) is false, throw a TypeError exception. + // b. Let mapping be true. + const mapping: bool = mapfnObj != Undefined; + if (mapping && !Is(mapfnObj)) deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, mapfnObj); + } - type BuiltinsName extends int31 constexpr 'Builtins::Name'; - const kTypedArrayPrototypeValues: constexpr BuiltinsName - generates 'Builtins::kTypedArrayPrototypeValues'; + // We split up this builtin differently to the way it is written in the + // spec. We already have great code in the elements accessor for copying + // from a JSArray into a TypedArray, so we use that when possible. We only + // avoid calling into the elements accessor when we have a mapping + // function, because we can't handle that. Here, presence of a mapping + // function is the slow path. We also combine the two different loops in + // the specification (starting at 7.e and 13) because they are essentially + // identical. We also save on code-size this way. - extern builtin IterableToList(implicit context: Context)(JSAny, JSAny): - JSArray; + let finalLength: uintptr; + let finalSource: JSAny; - // %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] ) - // https://tc39.github.io/ecma262/#sec-%typedarray%.from - transitioning javascript builtin - TypedArrayFrom(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSTypedArray { try { - const source: JSAny = arguments[0]; - - // 1. Let C be the this value. - // 2. If IsConstructor(C) is false, throw a TypeError exception. - const constructor = Cast(receiver) otherwise NotConstructor; - - // 3. If mapfn is present and mapfn is not undefined, then - // a. If IsCallable(mapfn) is false, throw a TypeError exception. - // b. Let mapping be true. - // 4. Else, let mapping be false. - const mapping: bool = arguments.length > 1; - const mapfnObj: JSAny = mapping ? arguments[1] : Undefined; - if (mapping && !TaggedIsCallable(mapfnObj)) deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, mapfnObj); - } - - // 5. If thisArg is present, let T be thisArg; else let T be undefined. - const thisArg = arguments.length > 2 ? arguments[2] : Undefined; - - // We split up this builtin differently to the way it is written in the - // spec. We already have great code in the elements accessor for copying - // from a JSArray into a TypedArray, so we use that when possible. We only - // avoid calling into the elements accessor when we have a mapping - // function, because we can't handle that. Here, presence of a mapping - // function is the slow path. We also combine the two different loops in - // the specification (starting at 7.e and 13) because they are essentially - // identical. We also save on code-size this way. - - let finalLength: uintptr; - let finalSource: JSAny; + // 5. Let usingIterator be ? GetMethod(source, @@iterator). + // TODO(v8:8906): Use iterator::GetIteratorMethod() once it supports + // labels. + const usingIterator = GetMethod(source, IteratorSymbolConstant()) + otherwise IteratorIsUndefined, IteratorNotCallable; try { - // 6. Let usingIterator be ? GetMethod(source, @@iterator). - // TODO(v8:8906): Use iterator::GetIteratorMethod() once it supports - // labels. - const usingIterator = GetMethod(source, IteratorSymbolConstant()) - otherwise IteratorIsUndefined, IteratorNotCallable; - - try { - // TypedArrays have iterators, so normally we would go through the - // IterableToList case below, which would convert the TypedArray to a - // JSArray (boxing the values if they won't fit in a Smi). - // - // However, if we can guarantee that the source object has the - // built-in iterator and that the %ArrayIteratorPrototype%.next method - // has not been overridden, then we know the behavior of the iterator: - // returning the values in the TypedArray sequentially from index 0 to - // length-1. - // - // In this case, we can avoid creating the intermediate array and the - // associated HeapNumbers, and use the fast path in - // TypedArrayCopyElements which uses the same ordering as the default - // iterator. - // - // Drop through to the default check_iterator behavior if any of these - // checks fail. - const sourceTypedArray = - Cast(source) otherwise UseUserProvidedIterator; - const sourceBuffer = sourceTypedArray.buffer; - if (IsDetachedBuffer(sourceBuffer)) goto UseUserProvidedIterator; - - // Check that the iterator function is exactly - // Builtins::kTypedArrayPrototypeValues. - const iteratorFn = - Cast(usingIterator) otherwise UseUserProvidedIterator; - if (!TaggedEqual( - iteratorFn.shared_function_info.function_data, - SmiConstant(kTypedArrayPrototypeValues))) - goto UseUserProvidedIterator; - - // Check that the ArrayIterator prototype's "next" method hasn't been - // overridden. - if (IsArrayIteratorProtectorCellInvalid()) - goto UseUserProvidedIterator; - - // Source is a TypedArray with unmodified iterator behavior. Use the - // source object directly, taking advantage of the special-case code - // in TypedArrayCopyElements - finalLength = sourceTypedArray.length; - finalSource = source; - } - label UseUserProvidedIterator { - // 7. If usingIterator is not undefined, then - // a. Let values be ? IterableToList(source, usingIterator). - // b. Let len be the number of elements in values. - const values: JSArray = IterableToList(source, usingIterator); - - finalLength = Convert(values.length); - finalSource = values; - } - } - label IteratorIsUndefined { - // 8. NOTE: source is not an Iterable so assume it is already an - // array-like object. - - // 9. Let arrayLike be ! ToObject(source). - const arrayLike: JSReceiver = ToObject_Inline(context, source); - - // 10. Let len be ? ToLength(? Get(arrayLike, "length")). - const length = GetLengthProperty(arrayLike); - - try { - finalLength = ChangeSafeIntegerNumberToUintPtr(length) - otherwise IfInvalidLength; - finalSource = arrayLike; - } - label IfInvalidLength deferred { - ThrowRangeError(MessageTemplate::kInvalidTypedArrayLength, length); - } - } - label IteratorNotCallable(_value: JSAny) deferred { - ThrowTypeError(MessageTemplate::kIteratorSymbolNonCallable); + // TypedArrays have iterators, so normally we would go through the + // IterableToList case below, which would convert the TypedArray to a + // JSArray (boxing the values if they won't fit in a Smi). + // + // However, if we can guarantee that the source object has the + // built-in iterator and that the %ArrayIteratorPrototype%.next method + // has not been overridden, then we know the behavior of the iterator: + // returning the values in the TypedArray sequentially from index 0 to + // length-1. + // + // In this case, we can avoid creating the intermediate array and the + // associated HeapNumbers, and use the fast path in + // TypedArrayCopyElements which uses the same ordering as the default + // iterator. + // + // Drop through to the default check_iterator behavior if any of these + // checks fail. + const sourceTypedArray = + Cast(source) otherwise UseUserProvidedIterator; + const sourceBuffer = sourceTypedArray.buffer; + if (IsDetachedBuffer(sourceBuffer)) goto UseUserProvidedIterator; + + // Check that the iterator function is exactly + // Builtins::kTypedArrayPrototypeValues. + const iteratorFn = + Cast(usingIterator) otherwise UseUserProvidedIterator; + if (!TaggedEqual( + iteratorFn.shared_function_info.function_data, + SmiConstant(kTypedArrayPrototypeValues))) + goto UseUserProvidedIterator; + + // Check that the ArrayIterator prototype's "next" method hasn't been + // overridden. + if (IsArrayIteratorProtectorCellInvalid()) goto UseUserProvidedIterator; + + // Source is a TypedArray with unmodified iterator behavior. Use the + // source object directly, taking advantage of the special-case code + // in TypedArrayCopyElements + finalLength = sourceTypedArray.length; + finalSource = source; + } label UseUserProvidedIterator { + // 6. If usingIterator is not undefined, then + // a. Let values be ? IterableToList(source, usingIterator). + // b. Let len be the number of elements in values. + const values: JSArray = IterableToList(source, usingIterator); + + finalLength = Convert(values.length); + finalSource = values; } + } label IteratorIsUndefined { + // 7. NOTE: source is not an Iterable so assume it is already an + // array-like object. - const finalLengthNum = Convert(finalLength); + // 8. Let arrayLike be ! ToObject(source). + const arrayLike: JSReceiver = ToObject_Inline(context, source); - // 7c/11. Let targetObj be ? TypedArrayCreate(C, «len»). - const targetObj = TypedArrayCreateByLength( - constructor, finalLengthNum, kBuiltinNameFrom); + // 9. Let len be ? LengthOfArrayLike(arrayLike). + const length = GetLengthProperty(arrayLike); - if (!mapping) { - // Fast path. - if (finalLength != 0) { - // Call runtime. - TypedArrayCopyElements( - context, targetObj, finalSource, finalLengthNum); - } - return targetObj; + try { + finalLength = ChangeSafeIntegerNumberToUintPtr(length) + otherwise IfInvalidLength; + finalSource = arrayLike; + } label IfInvalidLength deferred { + ThrowRangeError(MessageTemplate::kInvalidTypedArrayLength, length); } - // Slow path. - - const mapfn: Callable = Cast(mapfnObj) otherwise unreachable; - const accessor: TypedArrayAccessor = - GetTypedArrayAccessor(targetObj.elements_kind); - - // 7d-7e and 12-13. - // 12. Let k be 0. - // 13. Repeat, while k < len - for (let k: uintptr = 0; k < finalLength; k++) { - // 13a. Let Pk be ! ToString(k). - const kNum = Convert(k); - - // 13b. Let kValue be ? Get(arrayLike, Pk). - const kValue: JSAny = GetProperty(finalSource, kNum); - - let mappedValue: JSAny; - // 13c. If mapping is true, then - if (mapping) { - // i. Let mappedValue be ? Call(mapfn, T, « kValue, k »). - mappedValue = Call(context, mapfn, thisArg, kValue, kNum); - } else { - // 13d. Else, let mappedValue be kValue. - mappedValue = kValue; - } - - // 13e. Perform ? Set(targetObj, Pk, mappedValue, true). - // Buffer may be detached during executing ToNumber/ToBigInt. - accessor.StoreJSAny(context, targetObj, k, mappedValue) - otherwise IfDetached; - - // 13f. Set k to k + 1. (done by the loop). + } label IteratorNotCallable(_value: JSAny) deferred { + ThrowTypeError(MessageTemplate::kIteratorSymbolNonCallable); + } + + const finalLengthNum = Convert(finalLength); + + // 6c/10. Let targetObj be ? TypedArrayCreate(C, «len»). + const targetObj = + TypedArrayCreateByLength(constructor, finalLengthNum, kBuiltinNameFrom); + + if (!mapping) { + // Fast path. + if (finalLength != 0) { + // Call runtime. + TypedArrayCopyElements(context, targetObj, finalSource, finalLengthNum); } return targetObj; } - label NotConstructor deferred { - ThrowTypeError(MessageTemplate::kNotConstructor, receiver); - } - label IfDetached deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameFrom); + // Slow path. + + const mapfn: Callable = Cast(mapfnObj) otherwise unreachable; + const accessor: TypedArrayAccessor = + GetTypedArrayAccessor(targetObj.elements_kind); + + // 6d-6e and 11-12. + // 11. Let k be 0. + // 12. Repeat, while k < len + for (let k: uintptr = 0; k < finalLength; k++) { + // 12a. Let Pk be ! ToString(k). + const kNum = Convert(k); + + // 12b. Let kValue be ? Get(arrayLike, Pk). + const kValue: JSAny = GetProperty(finalSource, kNum); + + let mappedValue: JSAny; + // 12c. If mapping is true, then + if (mapping) { + // i. Let mappedValue be ? Call(mapfn, T, « kValue, k »). + mappedValue = Call(context, mapfn, thisArg, kValue, kNum); + } else { + // 12d. Else, let mappedValue be kValue. + mappedValue = kValue; + } + + // 12e. Perform ? Set(targetObj, Pk, mappedValue, true). + // Buffer may be detached during executing ToNumber/ToBigInt. + accessor.StoreJSAny(context, targetObj, k, mappedValue) + otherwise IfDetached; + + // 12f. Set k to k + 1. (done by the loop). } + return targetObj; + } label NotConstructor deferred { + ThrowTypeError(MessageTemplate::kNotConstructor, receiver); + } label IfDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameFrom); } } +} diff --git a/deps/v8/src/builtins/typed-array-of.tq b/deps/v8/src/builtins/typed-array-of.tq index c65deeeb150aac..b5d42ef9a2f58e 100644 --- a/deps/v8/src/builtins/typed-array-of.tq +++ b/deps/v8/src/builtins/typed-array-of.tq @@ -5,52 +5,50 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameOf: constexpr string = '%TypedArray%.of'; - - // %TypedArray%.of ( ...items ) - // https://tc39.github.io/ecma262/#sec-%typedarray%.of - transitioning javascript builtin - TypedArrayOf(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSTypedArray { - try { - // 1. Let len be the actual number of arguments passed to this function. - const len: uintptr = Unsigned(arguments.length); - - // 2. Let items be the List of arguments passed to this function. - - // 3. Let C be the this value. - // 4. If IsConstructor(C) is false, throw a TypeError exception. - const constructor = Cast(receiver) otherwise NotConstructor; - - // 5. Let newObj be ? TypedArrayCreate(C, len). - const newObj = TypedArrayCreateByLength( - constructor, Convert(len), kBuiltinNameOf); - - const accessor: TypedArrayAccessor = - GetTypedArrayAccessor(newObj.elements_kind); - - // 6. Let k be 0. - // 7. Repeat, while k < len - for (let k: uintptr = 0; k < len; k++) { - // 7a. Let kValue be items[k]. - const kValue: JSAny = arguments[Signed(k)]; - - // 7b. Let Pk be ! ToString(k). - // 7c. Perform ? Set(newObj, Pk, kValue, true). - // Buffer may be detached during executing ToNumber/ToBigInt. - accessor.StoreJSAny(context, newObj, k, kValue) otherwise IfDetached; - - // 7d. Increase k by 1. (done by the loop). - } - - // 8. Return newObj. - return newObj; - } - label NotConstructor deferred { - ThrowTypeError(MessageTemplate::kNotConstructor, receiver); - } - label IfDetached deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameOf); +const kBuiltinNameOf: constexpr string = '%TypedArray%.of'; + +// %TypedArray%.of ( ...items ) +// https://tc39.github.io/ecma262/#sec-%typedarray%.of +transitioning javascript builtin +TypedArrayOf(js-implicit context: NativeContext, receiver: JSAny)(...arguments): + JSTypedArray { + try { + // 1. Let len be the actual number of arguments passed to this function. + const len: uintptr = Unsigned(arguments.length); + + // 2. Let items be the List of arguments passed to this function. + + // 3. Let C be the this value. + // 4. If IsConstructor(C) is false, throw a TypeError exception. + const constructor = Cast(receiver) otherwise NotConstructor; + + // 5. Let newObj be ? TypedArrayCreate(C, len). + const newObj = TypedArrayCreateByLength( + constructor, Convert(len), kBuiltinNameOf); + + const accessor: TypedArrayAccessor = + GetTypedArrayAccessor(newObj.elements_kind); + + // 6. Let k be 0. + // 7. Repeat, while k < len + for (let k: uintptr = 0; k < len; k++) { + // 7a. Let kValue be items[k]. + const kValue: JSAny = arguments[Signed(k)]; + + // 7b. Let Pk be ! ToString(k). + // 7c. Perform ? Set(newObj, Pk, kValue, true). + // Buffer may be detached during executing ToNumber/ToBigInt. + accessor.StoreJSAny(context, newObj, k, kValue) otherwise IfDetached; + + // 7d. Increase k by 1. (done by the loop). } + + // 8. Return newObj. + return newObj; + } label NotConstructor deferred { + ThrowTypeError(MessageTemplate::kNotConstructor, receiver); + } label IfDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameOf); } } +} diff --git a/deps/v8/src/builtins/typed-array-reduce.tq b/deps/v8/src/builtins/typed-array-reduce.tq index a2ff53f65c4f6c..a54ed1040e92f7 100644 --- a/deps/v8/src/builtins/typed-array-reduce.tq +++ b/deps/v8/src/builtins/typed-array-reduce.tq @@ -5,65 +5,61 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameReduce: constexpr string = '%TypedArray%.prototype.reduce'; +const kBuiltinNameReduce: constexpr string = '%TypedArray%.prototype.reduce'; - transitioning macro ReduceAllElements(implicit context: Context)( - array: typed_array::AttachedJSTypedArray, callbackfn: Callable, - initialValue: JSAny|TheHole): JSAny { - let witness = typed_array::NewAttachedJSTypedArrayWitness(array); - const length: uintptr = witness.Get().length; - let accumulator = initialValue; - for (let k: uintptr = 0; k < length; k++) { - // BUG(4895): We should throw on detached buffers rather than simply exit. - witness.Recheck() otherwise break; - const value: JSAny = witness.Load(k); - typeswitch (accumulator) { - case (TheHole): { - accumulator = value; - } - case (accumulatorNotHole: JSAny): { - // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi - // indices to optimize Convert(k) for the most common case. - accumulator = Call( - context, callbackfn, Undefined, accumulatorNotHole, value, - Convert(k), witness.GetStable()); - } - } - } +transitioning macro ReduceAllElements(implicit context: Context)( + array: typed_array::AttachedJSTypedArray, callbackfn: Callable, + initialValue: JSAny|TheHole): JSAny { + let witness = typed_array::NewAttachedJSTypedArrayWitness(array); + const length: uintptr = witness.Get().length; + let accumulator = initialValue; + for (let k: uintptr = 0; k < length; k++) { + // BUG(4895): We should throw on detached buffers rather than simply exit. + witness.Recheck() otherwise break; + const value: JSAny = witness.Load(k); typeswitch (accumulator) { case (TheHole): { - ThrowTypeError(MessageTemplate::kReduceNoInitial, kBuiltinNameReduce); + accumulator = value; } - case (accumulator: JSAny): { - return accumulator; + case (accumulatorNotHole: JSAny): { + // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi + // indices to optimize Convert(k) for the most common case. + accumulator = Call( + context, callbackfn, Undefined, accumulatorNotHole, value, + Convert(k), witness.GetStable()); } } } - - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduce - transitioning javascript builtin - TypedArrayPrototypeReduce( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - // arguments[0] = callback - // arguments[1] = initialValue. - try { - const array: JSTypedArray = Cast(receiver) - otherwise NotTypedArray; - const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; - - const callbackfn = Cast(arguments[0]) otherwise NotCallable; - const initialValue = arguments.length >= 2 ? arguments[1] : TheHole; - return ReduceAllElements(uarray, callbackfn, initialValue); - } - label NotCallable deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); - } - label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameReduce); + typeswitch (accumulator) { + case (TheHole): { + ThrowTypeError(MessageTemplate::kReduceNoInitial, kBuiltinNameReduce); } - label IsDetached deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameReduce); + case (accumulator: JSAny): { + return accumulator; } } } + +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduce +transitioning javascript builtin +TypedArrayPrototypeReduce( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // arguments[0] = callback + // arguments[1] = initialValue. + try { + const array: JSTypedArray = Cast(receiver) + otherwise NotTypedArray; + const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; + + const callbackfn = Cast(arguments[0]) otherwise NotCallable; + const initialValue = arguments.length >= 2 ? arguments[1] : TheHole; + return ReduceAllElements(uarray, callbackfn, initialValue); + } label NotCallable deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameReduce); + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameReduce); + } +} +} diff --git a/deps/v8/src/builtins/typed-array-reduceright.tq b/deps/v8/src/builtins/typed-array-reduceright.tq index ab334a1b8667e9..9ba2f70de4e886 100644 --- a/deps/v8/src/builtins/typed-array-reduceright.tq +++ b/deps/v8/src/builtins/typed-array-reduceright.tq @@ -5,69 +5,65 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameReduceRight: constexpr string = - '%TypedArray%.prototype.reduceRight'; +const kBuiltinNameReduceRight: constexpr string = + '%TypedArray%.prototype.reduceRight'; - transitioning macro ReduceRightAllElements(implicit context: Context)( - array: typed_array::AttachedJSTypedArray, callbackfn: Callable, - initialValue: JSAny|TheHole): JSAny { - let witness = typed_array::NewAttachedJSTypedArrayWitness(array); - const length: uintptr = witness.Get().length; - let accumulator = initialValue; - for (let k: uintptr = length; k-- > 0;) { - // BUG(4895): We should throw on detached buffers rather than simply exit. - witness.Recheck() otherwise break; - const value: JSAny = witness.Load(k); - typeswitch (accumulator) { - case (TheHole): { - accumulator = value; - } - case (accumulatorNotHole: JSAny): { - // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi - // indices to optimize Convert(k) for the most common case. - accumulator = Call( - context, callbackfn, Undefined, accumulatorNotHole, value, - Convert(k), witness.GetStable()); - } - } - } +transitioning macro ReduceRightAllElements(implicit context: Context)( + array: typed_array::AttachedJSTypedArray, callbackfn: Callable, + initialValue: JSAny|TheHole): JSAny { + let witness = typed_array::NewAttachedJSTypedArrayWitness(array); + const length: uintptr = witness.Get().length; + let accumulator = initialValue; + for (let k: uintptr = length; k-- > 0;) { + // BUG(4895): We should throw on detached buffers rather than simply exit. + witness.Recheck() otherwise break; + const value: JSAny = witness.Load(k); typeswitch (accumulator) { case (TheHole): { - ThrowTypeError( - MessageTemplate::kReduceNoInitial, kBuiltinNameReduceRight); + accumulator = value; } - case (accumulator: JSAny): { - return accumulator; + case (accumulatorNotHole: JSAny): { + // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi + // indices to optimize Convert(k) for the most common case. + accumulator = Call( + context, callbackfn, Undefined, accumulatorNotHole, value, + Convert(k), witness.GetStable()); } } } + typeswitch (accumulator) { + case (TheHole): { + ThrowTypeError( + MessageTemplate::kReduceNoInitial, kBuiltinNameReduceRight); + } + case (accumulator: JSAny): { + return accumulator; + } + } +} - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduceright - transitioning javascript builtin - TypedArrayPrototypeReduceRight( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - // arguments[0] = callback - // arguments[1] = initialValue. - try { - const array: JSTypedArray = Cast(receiver) - otherwise NotTypedArray; - const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduceright +transitioning javascript builtin +TypedArrayPrototypeReduceRight( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // arguments[0] = callback + // arguments[1] = initialValue. + try { + const array: JSTypedArray = Cast(receiver) + otherwise NotTypedArray; + const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; - const callbackfn = Cast(arguments[0]) otherwise NotCallable; - const initialValue = arguments.length >= 2 ? arguments[1] : TheHole; + const callbackfn = Cast(arguments[0]) otherwise NotCallable; + const initialValue = arguments.length >= 2 ? arguments[1] : TheHole; - return ReduceRightAllElements(uarray, callbackfn, initialValue); - } - label NotCallable deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); - } - label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameReduceRight); - } - label IsDetached deferred { - ThrowTypeError( - MessageTemplate::kDetachedOperation, kBuiltinNameReduceRight); - } + return ReduceRightAllElements(uarray, callbackfn, initialValue); + } label NotCallable deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameReduceRight); + } label IsDetached deferred { + ThrowTypeError( + MessageTemplate::kDetachedOperation, kBuiltinNameReduceRight); } } +} diff --git a/deps/v8/src/builtins/typed-array-set.tq b/deps/v8/src/builtins/typed-array-set.tq index bb70692e766b92..b5c9dcb261df65 100644 --- a/deps/v8/src/builtins/typed-array-set.tq +++ b/deps/v8/src/builtins/typed-array-set.tq @@ -5,315 +5,306 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameSet: constexpr string = '%TypedArray%.prototype.set'; - - extern runtime TypedArraySet(Context, JSTypedArray, Object, Number, Number): - void; - - extern macro - TypedArrayBuiltinsAssembler::CallCCopyFastNumberJSArrayElementsToTypedArray( - Context, - FastJSArray, // source - AttachedJSTypedArray, // dest - uintptr, // sourceLength - uintptr // destOffset - ): void; - - extern macro - TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsToTypedArray( - AttachedJSTypedArray, // source - AttachedJSTypedArray, // dest - uintptr, // sourceLength - uintptr // destOffset - ): void; - - // %TypedArray%.prototype.set ( overloaded [ , offset ] ) - // https://tc39.es/ecma262/#sec-%typedarray%.prototype.set-overloaded-offset - transitioning javascript builtin - TypedArrayPrototypeSet(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - // Steps 2-8 are the same for - // %TypedArray%.prototype.set ( array [ , offset ] ) and - // %TypedArray%.prototype.set ( typedArray [ , offset ] ) overloads. - - let target: JSTypedArray; - try { - // 2. Let target be the this value. - // 3. Perform ? RequireInternalSlot(target, [[TypedArrayName]]). - // 4. Assert: target has a [[ViewedArrayBuffer]] internal slot. - target = Cast(receiver) otherwise NotTypedArray; - } - label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameSet); - } - - try { - // 5. Let targetOffset be ? ToInteger(offset). - // 6. If targetOffset < 0, throw a RangeError exception. - let targetOffsetOverflowed: bool = false; - let targetOffset: uintptr = 0; - if (arguments.length > 1) { - const offsetArg = arguments[1]; - try { - targetOffset = ToUintPtr(offsetArg) - // On values less than zero throw RangeError immediately. - otherwise OffsetOutOfBounds, - // On UintPtr or SafeInteger range overflow throw RangeError after - // performing observable steps to follow the spec. - OffsetOverflow, OffsetOverflow; - } - label OffsetOverflow { - targetOffsetOverflowed = true; - } - } else { - // If the offset argument is not provided then the targetOffset is 0. - } - - // 7. Let targetBuffer be target.[[ViewedArrayBuffer]]. - // 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError - // exception. - const utarget = typed_array::EnsureAttached(target) otherwise IsDetached; +const kBuiltinNameSet: constexpr string = '%TypedArray%.prototype.set'; + +extern runtime TypedArraySet( + Context, JSTypedArray, Object, Number, Number): void; + +extern macro +TypedArrayBuiltinsAssembler::CallCCopyFastNumberJSArrayElementsToTypedArray( + Context, + FastJSArray, // source + AttachedJSTypedArray, // dest + uintptr, // sourceLength + uintptr // destOffset + ): void; + +extern macro +TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsToTypedArray( + AttachedJSTypedArray, // source + AttachedJSTypedArray, // dest + uintptr, // sourceLength + uintptr // destOffset + ): void; + +// %TypedArray%.prototype.set ( overloaded [ , offset ] ) +// https://tc39.es/ecma262/#sec-%typedarray%.prototype.set-overloaded-offset +transitioning javascript builtin +TypedArrayPrototypeSet( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // Steps 2-8 are the same for + // %TypedArray%.prototype.set ( array [ , offset ] ) and + // %TypedArray%.prototype.set ( typedArray [ , offset ] ) overloads. + + let target: JSTypedArray; + try { + // 2. Let target be the this value. + // 3. Perform ? RequireInternalSlot(target, [[TypedArrayName]]). + // 4. Assert: target has a [[ViewedArrayBuffer]] internal slot. + target = Cast(receiver) otherwise NotTypedArray; + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameSet); + } - const overloadedArg = arguments[0]; + try { + // 5. Let targetOffset be ? ToInteger(offset). + // 6. If targetOffset < 0, throw a RangeError exception. + let targetOffsetOverflowed: bool = false; + let targetOffset: uintptr = 0; + if (arguments.length > 1) { + const offsetArg = arguments[1]; try { - // 1. Choose 22.2.3.23.2 or 22.2.3.23.1 depending on whether the - // overloadedArg has a [[TypedArrayName]] internal slot. - // If it does, the definition in 22.2.3.23.2 applies. - // If it does not, the definition in 22.2.3.23.1 applies. - const typedArray = - Cast(overloadedArg) otherwise NotTypedArray; - - // Step 9 is not observable, do it later. - - // 10. Let srcBuffer be typedArray.[[ViewedArrayBuffer]]. - // 11. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError - // exception. - const utypedArray = - typed_array::EnsureAttached(typedArray) otherwise IsDetached; - - TypedArrayPrototypeSetTypedArray( - utarget, utypedArray, targetOffset, targetOffsetOverflowed) - otherwise OffsetOutOfBounds; - return Undefined; - } - label NotTypedArray deferred { - TypedArrayPrototypeSetArray( - utarget, overloadedArg, targetOffset, targetOffsetOverflowed) - otherwise OffsetOutOfBounds, IsDetached; - return Undefined; + targetOffset = ToUintPtr(offsetArg) + // On values less than zero throw RangeError immediately. + otherwise OffsetOutOfBounds, + // On UintPtr or SafeInteger range overflow throw RangeError after + // performing observable steps to follow the spec. + OffsetOverflow, OffsetOverflow; + } label OffsetOverflow { + targetOffsetOverflowed = true; } + } else { + // If the offset argument is not provided then the targetOffset is 0. } - label OffsetOutOfBounds deferred { - ThrowRangeError(MessageTemplate::kTypedArraySetOffsetOutOfBounds); - } - label IsDetached deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameSet); - } - } - // %TypedArray%.prototype.set ( array [ , offset ] ) - // https://tc39.es/ecma262/#sec-%typedarray%.prototype.set-array-offset - transitioning macro - TypedArrayPrototypeSetArray(implicit context: Context, receiver: JSAny)( - target: JSTypedArray, arrayArg: JSAny, targetOffset: uintptr, - targetOffsetOverflowed: bool): void labels IfOffsetOutOfBounds, - IfDetached { - // Steps 9-13 are not observable, do them later. - - // TODO(v8:8906): This ported behaviour is an observable spec violation and - // the comment below seems to be outdated. Consider removing this code. + // 7. Let targetBuffer be target.[[ViewedArrayBuffer]]. + // 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError + // exception. + const utarget = typed_array::EnsureAttached(target) otherwise IsDetached; + + const overloadedArg = arguments[0]; try { - const _arrayArgNum = Cast(arrayArg) otherwise NotNumber; - // For number as a first argument, throw TypeError instead of silently - // ignoring the call, so that users know they did something wrong. - // (Consistent with Firefox and Blink/WebKit) - ThrowTypeError(MessageTemplate::kInvalidArgument); - } - label NotNumber { - // Proceed to step 14. - } + // 1. Choose 22.2.3.23.2 or 22.2.3.23.1 depending on whether the + // overloadedArg has a [[TypedArrayName]] internal slot. + // If it does, the definition in 22.2.3.23.2 applies. + // If it does not, the definition in 22.2.3.23.1 applies. + const typedArray = + Cast(overloadedArg) otherwise NotTypedArray; - // 14. Let src be ? ToObject(array). - const src: JSReceiver = ToObject_Inline(context, arrayArg); + // Step 9 is not observable, do it later. - // 15. Let srcLength be ? LengthOfArrayLike(src). - const srcLengthNum: Number = GetLengthProperty(src); + // 10. Let srcBuffer be typedArray.[[ViewedArrayBuffer]]. + // 11. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError + // exception. + const utypedArray = + typed_array::EnsureAttached(typedArray) otherwise IsDetached; + + TypedArrayPrototypeSetTypedArray( + utarget, utypedArray, targetOffset, targetOffsetOverflowed) + otherwise OffsetOutOfBounds; + return Undefined; + } label NotTypedArray deferred { + TypedArrayPrototypeSetArray( + utarget, overloadedArg, targetOffset, targetOffsetOverflowed) + otherwise OffsetOutOfBounds, IsDetached; + return Undefined; + } + } label OffsetOutOfBounds deferred { + ThrowRangeError(MessageTemplate::kTypedArraySetOffsetOutOfBounds); + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameSet); + } +} - if (targetOffsetOverflowed) goto IfOffsetOutOfBounds; +// %TypedArray%.prototype.set ( array [ , offset ] ) +// https://tc39.es/ecma262/#sec-%typedarray%.prototype.set-array-offset +transitioning macro +TypedArrayPrototypeSetArray(implicit context: Context, receiver: JSAny)( + target: JSTypedArray, arrayArg: JSAny, targetOffset: uintptr, + targetOffsetOverflowed: bool): void labels IfOffsetOutOfBounds, + IfDetached { + // Steps 9-13 are not observable, do them later. + + // TODO(v8:8906): This ported behaviour is an observable spec violation and + // the comment below seems to be outdated. Consider removing this code. + try { + const _arrayArgNum = Cast(arrayArg) otherwise NotNumber; + // For number as a first argument, throw TypeError instead of silently + // ignoring the call, so that users know they did something wrong. + // (Consistent with Firefox and Blink/WebKit) + ThrowTypeError(MessageTemplate::kInvalidArgument); + } label NotNumber { + // Proceed to step 14. + } - // 9. Let targetLength be target.[[ArrayLength]]. - const targetLength = target.length; + // 14. Let src be ? ToObject(array). + const src: JSReceiver = ToObject_Inline(context, arrayArg); + + // 15. Let srcLength be ? LengthOfArrayLike(src). + const srcLengthNum: Number = GetLengthProperty(src); + + if (targetOffsetOverflowed) goto IfOffsetOutOfBounds; + + // 9. Let targetLength be target.[[ArrayLength]]. + const targetLength = target.length; + + // 16. If srcLength + targetOffset > targetLength, throw a RangeError + // exception. + const srcLength = ChangeSafeIntegerNumberToUintPtr(srcLengthNum) + otherwise IfOffsetOutOfBounds; + CheckIntegerIndexAdditionOverflow(srcLength, targetOffset, targetLength) + otherwise IfOffsetOutOfBounds; + + // All the obvervable side effects are executed, so there's nothing else + // to do with the empty source array. + if (srcLength == 0) return; + + // 10. Let targetName be the String value of target.[[TypedArrayName]]. + // 11. Let targetElementSize be the Element Size value specified in + // Table 62 for targetName. + // 12. Let targetType be the Element Type value in Table 62 for + // targetName. + + try { + // BigInt typed arrays are not handled by + // CopyFastNumberJSArrayElementsToTypedArray. + if (IsBigInt64ElementsKind(target.elements_kind)) goto IfSlow; + + const fastSrc: FastJSArray = Cast(src) otherwise goto IfSlow; + const srcKind: ElementsKind = fastSrc.map.elements_kind; + + // CopyFastNumberJSArrayElementsToTypedArray() can be used only with the + // following elements kinds: + // PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS, + // HOLEY_DOUBLE_ELEMENTS. + if (IsElementsKindInRange( + srcKind, ElementsKind::PACKED_SMI_ELEMENTS, + ElementsKind::HOLEY_SMI_ELEMENTS) || + IsElementsKindInRange( + srcKind, ElementsKind::PACKED_DOUBLE_ELEMENTS, + ElementsKind::HOLEY_DOUBLE_ELEMENTS)) { + const utarget = typed_array::EnsureAttached(target) otherwise IfDetached; + CallCCopyFastNumberJSArrayElementsToTypedArray( + context, fastSrc, utarget, srcLength, targetOffset); + + } else { + goto IfSlow; + } + } label IfSlow deferred { + TypedArraySet( + context, target, src, srcLengthNum, Convert(targetOffset)); + } +} - // 16. If srcLength + targetOffset > targetLength, throw a RangeError - // exception. - const srcLength = ChangeSafeIntegerNumberToUintPtr(srcLengthNum) - otherwise IfOffsetOutOfBounds; - CheckIntegerIndexAdditionOverflow(srcLength, targetOffset, targetLength) - otherwise IfOffsetOutOfBounds; +// %TypedArray%.prototype.set ( typedArray [ , offset ] ) +// https://tc39.es/ecma262/#sec-%typedarray%.prototype.set-typedarray-offset +transitioning macro +TypedArrayPrototypeSetTypedArray(implicit context: Context, receiver: JSAny)( + target: AttachedJSTypedArray, typedArray: AttachedJSTypedArray, + targetOffset: uintptr, + targetOffsetOverflowed: bool): void labels IfOffsetOutOfBounds { + // Steps 12-20 are not observable, so we can handle offset overflow + // at step 21 here. + if (targetOffsetOverflowed) goto IfOffsetOutOfBounds; + + // 9. Let targetLength be target.[[ArrayLength]]. + const targetLength = target.length; + + // 19. Let srcLength be typedArray.[[ArrayLength]]. + const srcLength: uintptr = typedArray.length; + + // Steps 12-20 are not observable, so we can do step 21 here. + + // 21. If srcLength + targetOffset > targetLength, throw a RangeError + // exception. + CheckIntegerIndexAdditionOverflow(srcLength, targetOffset, targetLength) + otherwise IfOffsetOutOfBounds; + + // 12. Let targetName be the String value of target.[[TypedArrayName]]. + // 13. Let targetType be the Element Type value in Table 62 for + // targetName. + // 14. Let targetElementSize be the Element Size value specified in + // Table 62 for targetName. + const targetElementsInfo = GetTypedArrayElementsInfo(target); + + // 16. Let srcName be the String value of typedArray.[[TypedArrayName]]. + // 17. Let srcType be the Element Type value in Table 62 for srcName. + // 18. Let srcElementSize be the Element Size value specified in + // Table 62 for srcName. + const srcKind: ElementsKind = typedArray.elements_kind; + // const srcElementsInfo = GetTypedArrayElementsInfo(typedArray); + + // We skip steps 23-25 because both memmove and + // CopyTypedArrayElementsToTypedArray() properly handle overlapping + // regions. + + // 23. If both IsSharedArrayBuffer(srcBuffer) and + // IsSharedArrayBuffer(targetBuffer) are true, then + // 23a. If srcBuffer.[[ArrayBufferData]] and + // targetBuffer.[[ArrayBufferData]] are the same Shared Data Block + // values, let same be true; else let same be false. + // 24. Else, let same be SameValue(srcBuffer, targetBuffer). + // 25. If same is true, then + // a. Let srcByteLength be typedArray.[[ByteLength]]. + // b. Set srcBuffer to ? CloneArrayBuffer(srcBuffer, srcByteOffset, + // srcByteLength, %ArrayBuffer%). + // c. NOTE: %ArrayBuffer% is used to clone srcBuffer because is it known + // to not have any observable side-effects. + // d. Let srcByteIndex be 0. + + try { + // Use memmove if possible. + if (srcKind != targetElementsInfo.kind) { + // Uint8/Uint8Clamped elements could still be copied with memmove. + if (!IsUint8ElementsKind(srcKind) || + !IsUint8ElementsKind(targetElementsInfo.kind)) { + goto IfSlow; + } + } // All the obvervable side effects are executed, so there's nothing else // to do with the empty source array. if (srcLength == 0) return; - // 10. Let targetName be the String value of target.[[TypedArrayName]]. - // 11. Let targetElementSize be the Element Size value specified in - // Table 62 for targetName. - // 12. Let targetType be the Element Type value in Table 62 for - // targetName. - - try { - // BigInt typed arrays are not handled by - // CopyFastNumberJSArrayElementsToTypedArray. - if (IsBigInt64ElementsKind(target.elements_kind)) goto IfSlow; - - const fastSrc: FastJSArray = Cast(src) otherwise goto IfSlow; - const srcKind: ElementsKind = fastSrc.map.elements_kind; - - // CopyFastNumberJSArrayElementsToTypedArray() can be used only with the - // following elements kinds: - // PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS, - // HOLEY_DOUBLE_ELEMENTS. - if (IsElementsKindInRange( - srcKind, ElementsKind::PACKED_SMI_ELEMENTS, - ElementsKind::HOLEY_SMI_ELEMENTS) || - IsElementsKindInRange( - srcKind, ElementsKind::PACKED_DOUBLE_ELEMENTS, - ElementsKind::HOLEY_DOUBLE_ELEMENTS)) { - const utarget = - typed_array::EnsureAttached(target) otherwise IfDetached; - CallCCopyFastNumberJSArrayElementsToTypedArray( - context, fastSrc, utarget, srcLength, targetOffset); - - } else { - goto IfSlow; + // Source and destination typed arrays have same elements kinds (modulo + // Uint8-Uint8Clamped difference) so we can use targetElementsInfo for + // calculations. + const countBytes: uintptr = + targetElementsInfo.CalculateByteLength(srcLength) + otherwise unreachable; + const startOffset: uintptr = + targetElementsInfo.CalculateByteLength(targetOffset) + otherwise unreachable; + const dstPtr: RawPtr = target.data_ptr + Convert(startOffset); + + assert(countBytes <= target.byte_length - startOffset); + assert(countBytes <= typedArray.byte_length); + + // 29. If srcType is the same as targetType, then + // a. NOTE: If srcType and targetType are the same, the transfer must + // be performed in a manner that preserves the bit-level encoding of + // the source data. + // b. Repeat, while targetByteIndex < limit + // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, Uint8, + // true, Unordered). + // ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, Uint8, + // value, true, Unordered). + // iii. Set srcByteIndex to srcByteIndex + 1. + // iv. Set targetByteIndex to targetByteIndex + 1. + CallCMemmove(dstPtr, typedArray.data_ptr, countBytes); + } label IfSlow deferred { + // 22. If target.[[ContentType]] is not equal to + // typedArray.[[ContentType]], throw a TypeError exception. + if (IsBigInt64ElementsKind(srcKind) != + IsBigInt64ElementsKind(targetElementsInfo.kind)) + deferred { + ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } - } - label IfSlow deferred { - TypedArraySet( - context, target, src, srcLengthNum, Convert(targetOffset)); - } - } - - // %TypedArray%.prototype.set ( typedArray [ , offset ] ) - // https://tc39.es/ecma262/#sec-%typedarray%.prototype.set-typedarray-offset - transitioning macro - TypedArrayPrototypeSetTypedArray(implicit context: Context, receiver: JSAny)( - target: AttachedJSTypedArray, typedArray: AttachedJSTypedArray, - targetOffset: uintptr, - targetOffsetOverflowed: bool): void labels IfOffsetOutOfBounds { - // Steps 12-20 are not observable, so we can handle offset overflow - // at step 21 here. - if (targetOffsetOverflowed) goto IfOffsetOutOfBounds; - - // 9. Let targetLength be target.[[ArrayLength]]. - const targetLength = target.length; - // 19. Let srcLength be typedArray.[[ArrayLength]]. - const srcLength: uintptr = typedArray.length; - - // Steps 12-20 are not observable, so we can do step 21 here. - - // 21. If srcLength + targetOffset > targetLength, throw a RangeError - // exception. - CheckIntegerIndexAdditionOverflow(srcLength, targetOffset, targetLength) - otherwise IfOffsetOutOfBounds; - - // 12. Let targetName be the String value of target.[[TypedArrayName]]. - // 13. Let targetType be the Element Type value in Table 62 for - // targetName. - // 14. Let targetElementSize be the Element Size value specified in - // Table 62 for targetName. - const targetElementsInfo = GetTypedArrayElementsInfo(target); - - // 16. Let srcName be the String value of typedArray.[[TypedArrayName]]. - // 17. Let srcType be the Element Type value in Table 62 for srcName. - // 18. Let srcElementSize be the Element Size value specified in - // Table 62 for srcName. - const srcKind: ElementsKind = typedArray.elements_kind; - // const srcElementsInfo = GetTypedArrayElementsInfo(typedArray); - - // We skip steps 23-25 because both memmove and - // CopyTypedArrayElementsToTypedArray() properly handle overlapping - // regions. - - // 23. If both IsSharedArrayBuffer(srcBuffer) and - // IsSharedArrayBuffer(targetBuffer) are true, then - // 23a. If srcBuffer.[[ArrayBufferData]] and - // targetBuffer.[[ArrayBufferData]] are the same Shared Data Block - // values, let same be true; else let same be false. - // 24. Else, let same be SameValue(srcBuffer, targetBuffer). - // 25. If same is true, then - // a. Let srcByteLength be typedArray.[[ByteLength]]. - // b. Set srcBuffer to ? CloneArrayBuffer(srcBuffer, srcByteOffset, - // srcByteLength, %ArrayBuffer%). - // c. NOTE: %ArrayBuffer% is used to clone srcBuffer because is it known - // to not have any observable side-effects. - // d. Let srcByteIndex be 0. - - try { - // Use memmove if possible. - if (srcKind != targetElementsInfo.kind) { - // Uint8/Uint8Clamped elements could still be copied with memmove. - if (!IsUint8ElementsKind(srcKind) || - !IsUint8ElementsKind(targetElementsInfo.kind)) { - goto IfSlow; - } - } + // All the obvervable side effects are executed, so there's nothing else + // to do with the empty source array. + if (srcLength == 0) return; - // All the obvervable side effects are executed, so there's nothing else - // to do with the empty source array. - if (srcLength == 0) return; - - // Source and destination typed arrays have same elements kinds (modulo - // Uint8-Uint8Clamped difference) so we can use targetElementsInfo for - // calculations. - const countBytes: uintptr = - targetElementsInfo.CalculateByteLength(srcLength) - otherwise unreachable; - const startOffset: uintptr = - targetElementsInfo.CalculateByteLength(targetOffset) - otherwise unreachable; - const dstPtr: RawPtr = target.data_ptr + Convert(startOffset); - - assert(countBytes <= target.byte_length - startOffset); - assert(countBytes <= typedArray.byte_length); - - // 29. If srcType is the same as targetType, then - // a. NOTE: If srcType and targetType are the same, the transfer must - // be performed in a manner that preserves the bit-level encoding of - // the source data. - // b. Repeat, while targetByteIndex < limit - // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, Uint8, - // true, Unordered). - // ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, Uint8, - // value, true, Unordered). - // iii. Set srcByteIndex to srcByteIndex + 1. - // iv. Set targetByteIndex to targetByteIndex + 1. - CallCMemmove(dstPtr, typedArray.data_ptr, countBytes); - } - label IfSlow deferred { - // 22. If target.[[ContentType]] is not equal to - // typedArray.[[ContentType]], throw a TypeError exception. - if (IsBigInt64ElementsKind(srcKind) != - IsBigInt64ElementsKind(targetElementsInfo.kind)) - deferred { - ThrowTypeError(MessageTemplate::kBigIntMixedTypes); - } - - // All the obvervable side effects are executed, so there's nothing else - // to do with the empty source array. - if (srcLength == 0) return; - - // 30. Else, - // a. Repeat, while targetByteIndex < limit - // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, - // srcType, true, Unordered). - // ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, - // targetType, value, true, Unordered). - // iii. Set srcByteIndex to srcByteIndex + srcElementSize. - // iv. Set targetByteIndex to targetByteIndex + targetElementSize. - CallCCopyTypedArrayElementsToTypedArray( - typedArray, target, srcLength, targetOffset); - } + // 30. Else, + // a. Repeat, while targetByteIndex < limit + // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, + // srcType, true, Unordered). + // ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, + // targetType, value, true, Unordered). + // iii. Set srcByteIndex to srcByteIndex + srcElementSize. + // iv. Set targetByteIndex to targetByteIndex + targetElementSize. + CallCCopyTypedArrayElementsToTypedArray( + typedArray, target, srcLength, targetOffset); } } +} diff --git a/deps/v8/src/builtins/typed-array-slice.tq b/deps/v8/src/builtins/typed-array-slice.tq index 578c2d017ada71..60604c548fc272 100644 --- a/deps/v8/src/builtins/typed-array-slice.tq +++ b/deps/v8/src/builtins/typed-array-slice.tq @@ -5,102 +5,99 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameSlice: constexpr string = '%TypedArray%.prototype.slice'; - - extern macro TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsSlice( - JSTypedArray, JSTypedArray, uintptr, uintptr): void; - - macro FastCopy( - src: typed_array::AttachedJSTypedArray, dest: JSTypedArray, k: uintptr, - count: uintptr) labels IfSlow { - if (IsForceSlowPath()) goto IfSlow; - - const srcKind: ElementsKind = src.elements_kind; - const destInfo = typed_array::GetTypedArrayElementsInfo(dest); - - // dest could be a different type from src or share the same buffer - // with the src because of custom species constructor. If the types - // of src and result array are the same and they are not sharing the - // same buffer, use memmove. - if (srcKind != destInfo.kind) goto IfSlow; - if (dest.buffer == src.buffer) { - goto IfSlow; - } +const kBuiltinNameSlice: constexpr string = '%TypedArray%.prototype.slice'; + +extern macro TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsSlice( + JSTypedArray, JSTypedArray, uintptr, uintptr): void; + +macro FastCopy( + src: typed_array::AttachedJSTypedArray, dest: JSTypedArray, k: uintptr, + count: uintptr) labels IfSlow { + if (IsForceSlowPath()) goto IfSlow; + + const srcKind: ElementsKind = src.elements_kind; + const destInfo = typed_array::GetTypedArrayElementsInfo(dest); + + // dest could be a different type from src or share the same buffer + // with the src because of custom species constructor. If the types + // of src and result array are the same and they are not sharing the + // same buffer, use memmove. + if (srcKind != destInfo.kind) goto IfSlow; + if (dest.buffer == src.buffer) { + goto IfSlow; + } - const countBytes: uintptr = destInfo.CalculateByteLength(count) - otherwise unreachable; - const startOffset: uintptr = destInfo.CalculateByteLength(k) - otherwise unreachable; - const srcPtr: RawPtr = src.data_ptr + Convert(startOffset); + const countBytes: uintptr = destInfo.CalculateByteLength(count) + otherwise unreachable; + const startOffset: uintptr = destInfo.CalculateByteLength(k) + otherwise unreachable; + const srcPtr: RawPtr = src.data_ptr + Convert(startOffset); - assert(countBytes <= dest.byte_length); - assert(countBytes <= src.byte_length - startOffset); + assert(countBytes <= dest.byte_length); + assert(countBytes <= src.byte_length - startOffset); - typed_array::CallCMemmove(dest.data_ptr, srcPtr, countBytes); - } + typed_array::CallCMemmove(dest.data_ptr, srcPtr, countBytes); +} - macro SlowCopy(implicit context: Context)( - src: JSTypedArray, dest: JSTypedArray, k: uintptr, final: uintptr) { - if (typed_array::IsBigInt64ElementsKind(src.elements_kind) != - typed_array::IsBigInt64ElementsKind(dest.elements_kind)) - deferred { - ThrowTypeError(MessageTemplate::kBigIntMixedTypes); - } +macro SlowCopy(implicit context: Context)( + src: JSTypedArray, dest: JSTypedArray, k: uintptr, final: uintptr) { + if (typed_array::IsBigInt64ElementsKind(src.elements_kind) != + typed_array::IsBigInt64ElementsKind(dest.elements_kind)) + deferred { + ThrowTypeError(MessageTemplate::kBigIntMixedTypes); + } - CallCCopyTypedArrayElementsSlice(src, dest, k, final); - } + CallCCopyTypedArrayElementsSlice(src, dest, k, final); +} - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.slice - transitioning javascript builtin TypedArrayPrototypeSlice( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSAny { - // arguments[0] = start - // arguments[1] = end - - // 1. Let O be the this value. - // 2. Perform ? ValidateTypedArray(O). - const src: JSTypedArray = - ValidateTypedArray(context, receiver, kBuiltinNameSlice); - - // 3. Let len be O.[[ArrayLength]]. - const len: uintptr = src.length; - - // 4. Let relativeStart be ? ToInteger(start). - // 5. If relativeStart < 0, let k be max((len + relativeStart), 0); - // else let k be min(relativeStart, len). - const start = arguments[0]; - const k: uintptr = - start != Undefined ? ConvertToRelativeIndex(start, len) : 0; - - // 6. If end is undefined, let relativeEnd be len; - // else let relativeEnd be ? ToInteger(end). - // 7. If relativeEnd < 0, let final be max((len + relativeEnd), 0); - // else let final be min(relativeEnd, len). - const end = arguments[1]; - const final: uintptr = - end != Undefined ? ConvertToRelativeIndex(end, len) : len; - - // 8. Let count be max(final - k, 0). - const count: uintptr = Unsigned(IntPtrMax(Signed(final - k), 0)); - - // 9. Let A be ? TypedArraySpeciesCreate(O, « count »). - const dest: JSTypedArray = - TypedArraySpeciesCreateByLength(kBuiltinNameSlice, src, count); - - if (count > 0) { - try { - const srcAttached = typed_array::EnsureAttached(src) - otherwise IfDetached; - FastCopy(srcAttached, dest, k, count) otherwise IfSlow; - } - label IfDetached deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameSlice); - } - label IfSlow deferred { - SlowCopy(src, dest, k, final); - } +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.slice +transitioning javascript builtin TypedArrayPrototypeSlice( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // arguments[0] = start + // arguments[1] = end + + // 1. Let O be the this value. + // 2. Perform ? ValidateTypedArray(O). + const src: JSTypedArray = + ValidateTypedArray(context, receiver, kBuiltinNameSlice); + + // 3. Let len be O.[[ArrayLength]]. + const len: uintptr = src.length; + + // 4. Let relativeStart be ? ToInteger(start). + // 5. If relativeStart < 0, let k be max((len + relativeStart), 0); + // else let k be min(relativeStart, len). + const start = arguments[0]; + const k: uintptr = + start != Undefined ? ConvertToRelativeIndex(start, len) : 0; + + // 6. If end is undefined, let relativeEnd be len; + // else let relativeEnd be ? ToInteger(end). + // 7. If relativeEnd < 0, let final be max((len + relativeEnd), 0); + // else let final be min(relativeEnd, len). + const end = arguments[1]; + const final: uintptr = + end != Undefined ? ConvertToRelativeIndex(end, len) : len; + + // 8. Let count be max(final - k, 0). + const count: uintptr = Unsigned(IntPtrMax(Signed(final - k), 0)); + + // 9. Let A be ? TypedArraySpeciesCreate(O, « count »). + const dest: JSTypedArray = + TypedArraySpeciesCreateByLength(kBuiltinNameSlice, src, count); + + if (count > 0) { + try { + const srcAttached = typed_array::EnsureAttached(src) + otherwise IfDetached; + FastCopy(srcAttached, dest, k, count) otherwise IfSlow; + } label IfDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameSlice); + } label IfSlow deferred { + SlowCopy(src, dest, k, final); } - - return dest; } + + return dest; +} } diff --git a/deps/v8/src/builtins/typed-array-some.tq b/deps/v8/src/builtins/typed-array-some.tq index a09ce964d58a0d..ecdfae1e8a58da 100644 --- a/deps/v8/src/builtins/typed-array-some.tq +++ b/deps/v8/src/builtins/typed-array-some.tq @@ -5,52 +5,49 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameSome: constexpr string = '%TypedArray%.prototype.some'; +const kBuiltinNameSome: constexpr string = '%TypedArray%.prototype.some'; - transitioning macro SomeAllElements(implicit context: Context)( - array: typed_array::AttachedJSTypedArray, callbackfn: Callable, - thisArg: JSAny): Boolean { - let witness = typed_array::NewAttachedJSTypedArrayWitness(array); - const length: uintptr = witness.Get().length; - for (let k: uintptr = 0; k < length; k++) { - // BUG(4895): We should throw on detached buffers rather than simply exit. - witness.Recheck() otherwise break; - const value: JSAny = witness.Load(k); - // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi - // indices to optimize Convert(k) for the most common case. - const result = Call( - context, callbackfn, thisArg, value, Convert(k), - witness.GetStable()); - if (ToBoolean(result)) { - return True; - } +transitioning macro SomeAllElements(implicit context: Context)( + array: typed_array::AttachedJSTypedArray, callbackfn: Callable, + thisArg: JSAny): Boolean { + let witness = typed_array::NewAttachedJSTypedArrayWitness(array); + const length: uintptr = witness.Get().length; + for (let k: uintptr = 0; k < length; k++) { + // BUG(4895): We should throw on detached buffers rather than simply exit. + witness.Recheck() otherwise break; + const value: JSAny = witness.Load(k); + // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi + // indices to optimize Convert(k) for the most common case. + const result = Call( + context, callbackfn, thisArg, value, Convert(k), + witness.GetStable()); + if (ToBoolean(result)) { + return True; } - return False; } + return False; +} - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.some - transitioning javascript builtin - TypedArrayPrototypeSome(js-implicit context: NativeContext, receiver: JSAny)( - ...arguments): JSAny { - // arguments[0] = callback - // arguments[1] = thisArg. - try { - const array: JSTypedArray = Cast(receiver) - otherwise NotTypedArray; - const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.some +transitioning javascript builtin +TypedArrayPrototypeSome( + js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { + // arguments[0] = callback + // arguments[1] = thisArg. + try { + const array: JSTypedArray = Cast(receiver) + otherwise NotTypedArray; + const uarray = typed_array::EnsureAttached(array) otherwise IsDetached; - const callbackfn = Cast(arguments[0]) otherwise NotCallable; - const thisArg = arguments[1]; - return SomeAllElements(uarray, callbackfn, thisArg); - } - label NotCallable deferred { - ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); - } - label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameSome); - } - label IsDetached deferred { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameSome); - } + const callbackfn = Cast(arguments[0]) otherwise NotCallable; + const thisArg = arguments[1]; + return SomeAllElements(uarray, callbackfn, thisArg); + } label NotCallable deferred { + ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameSome); + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameSome); } } +} diff --git a/deps/v8/src/builtins/typed-array-sort.tq b/deps/v8/src/builtins/typed-array-sort.tq index 171068761d6747..c32808038d0562 100644 --- a/deps/v8/src/builtins/typed-array-sort.tq +++ b/deps/v8/src/builtins/typed-array-sort.tq @@ -5,141 +5,140 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - const kBuiltinNameSort: constexpr string = '%TypedArray%.prototype.sort'; +const kBuiltinNameSort: constexpr string = '%TypedArray%.prototype.sort'; - extern runtime TypedArraySortFast(Context, JSAny): JSTypedArray; +extern runtime TypedArraySortFast(Context, JSAny): JSTypedArray; - transitioning macro CallCompare( - implicit context: Context, array: JSTypedArray, - comparefn: Callable)(a: JSAny, b: JSAny): Number { - // a. Let v be ? ToNumber(? Call(comparefn, undefined, x, y)). - const v: Number = - ToNumber_Inline(Call(context, comparefn, Undefined, a, b)); +transitioning macro CallCompare( + implicit context: Context, array: JSTypedArray, comparefn: Callable)( + a: JSAny, b: JSAny): Number { + // a. Let v be ? ToNumber(? Call(comparefn, undefined, x, y)). + const v: Number = ToNumber_Inline(Call(context, comparefn, Undefined, a, b)); - // b. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. - if (IsDetachedBuffer(array.buffer)) { - ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameSort); - } + // b. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. + if (IsDetachedBuffer(array.buffer)) { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameSort); + } - // c. If v is NaN, return +0. - if (NumberIsNaN(v)) return 0; + // c. If v is NaN, return +0. + if (NumberIsNaN(v)) return 0; - // d. return v. - return v; - } + // d. return v. + return v; +} - // Merges two sorted runs [from, middle) and [middle, to) - // from "source" into "target". - transitioning macro - TypedArrayMerge( - implicit context: Context, array: JSTypedArray, comparefn: Callable)( - source: FixedArray, from: uintptr, middle: uintptr, to: uintptr, - target: FixedArray) { - let left: uintptr = from; - let right: uintptr = middle; - - for (let targetIndex: uintptr = from; targetIndex < to; ++targetIndex) { - if (left < middle && right >= to) { - // If the left run has elements, but the right does not, we take - // from the left. - target.objects[targetIndex] = source.objects[left++]; - } else if (left < middle) { - // If both have elements, we need to compare. - const leftElement = UnsafeCast(source.objects[left]); - const rightElement = UnsafeCast(source.objects[right]); - if (CallCompare(leftElement, rightElement) <= 0) { - target.objects[targetIndex] = leftElement; - left++; - } else { - target.objects[targetIndex] = rightElement; - right++; - } +// Merges two sorted runs [from, middle) and [middle, to) +// from "source" into "target". +transitioning macro +TypedArrayMerge( + implicit context: Context, array: JSTypedArray, comparefn: Callable)( + source: FixedArray, from: uintptr, middle: uintptr, to: uintptr, + target: FixedArray) { + let left: uintptr = from; + let right: uintptr = middle; + + for (let targetIndex: uintptr = from; targetIndex < to; ++targetIndex) { + if (left < middle && right >= to) { + // If the left run has elements, but the right does not, we take + // from the left. + target.objects[targetIndex] = source.objects[left++]; + } else if (left < middle) { + // If both have elements, we need to compare. + const leftElement = UnsafeCast(source.objects[left]); + const rightElement = UnsafeCast(source.objects[right]); + if (CallCompare(leftElement, rightElement) <= 0) { + target.objects[targetIndex] = leftElement; + left++; } else { - // No elements on the left, but the right does, so we take - // from the right. - assert(left == middle); - target.objects[targetIndex] = source.objects[right++]; + target.objects[targetIndex] = rightElement; + right++; } + } else { + // No elements on the left, but the right does, so we take + // from the right. + assert(left == middle); + target.objects[targetIndex] = source.objects[right++]; } } +} - transitioning builtin - TypedArrayMergeSort(implicit context: Context)( - source: FixedArray, from: uintptr, to: uintptr, target: FixedArray, - array: JSTypedArray, comparefn: Callable): JSAny { - assert(to - from > 1); - const middle: uintptr = from + ((to - from) >>> 1); - - // On the next recursion step source becomes target and vice versa. - // This saves the copy of the relevant range from the original - // array into a work array on each recursion step. - if (middle - from > 1) { - TypedArrayMergeSort(target, from, middle, source, array, comparefn); - } - if (to - middle > 1) { - TypedArrayMergeSort(target, middle, to, source, array, comparefn); - } - - TypedArrayMerge(source, from, middle, to, target); - - return Undefined; +transitioning builtin +TypedArrayMergeSort(implicit context: Context)( + source: FixedArray, from: uintptr, to: uintptr, target: FixedArray, + array: JSTypedArray, comparefn: Callable): JSAny { + assert(to - from > 1); + const middle: uintptr = from + ((to - from) >>> 1); + + // On the next recursion step source becomes target and vice versa. + // This saves the copy of the relevant range from the original + // array into a work array on each recursion step. + if (middle - from > 1) { + TypedArrayMergeSort(target, from, middle, source, array, comparefn); + } + if (to - middle > 1) { + TypedArrayMergeSort(target, middle, to, source, array, comparefn); } - // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.sort - transitioning javascript builtin TypedArrayPrototypeSort( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSTypedArray { - // 1. If comparefn is not undefined and IsCallable(comparefn) is false, - // throw a TypeError exception. - const comparefnObj: JSAny = arguments.length > 0 ? arguments[0] : Undefined; - if (comparefnObj != Undefined && !TaggedIsCallable(comparefnObj)) { - ThrowTypeError(MessageTemplate::kBadSortComparisonFunction, comparefnObj); - } + TypedArrayMerge(source, from, middle, to, target); - // 2. Let obj be the this value. - const obj: JSAny = receiver; + return Undefined; +} - // 3. Let buffer be ? ValidateTypedArray(obj). - // ValidateTypedArray currently returns the array, not the ViewBuffer. - const array: JSTypedArray = - ValidateTypedArray(context, obj, kBuiltinNameSort); +// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.sort +transitioning javascript builtin TypedArrayPrototypeSort( + js-implicit context: NativeContext, + receiver: JSAny)(...arguments): JSTypedArray { + // 1. If comparefn is not undefined and IsCallable(comparefn) is false, + // throw a TypeError exception. + const comparefnObj: JSAny = arguments[0]; + if (comparefnObj != Undefined && !Is(comparefnObj)) { + ThrowTypeError(MessageTemplate::kBadSortComparisonFunction, comparefnObj); + } - // 4. Let len be obj.[[ArrayLength]]. - const len: uintptr = array.length; + // 2. Let obj be the this value. + const obj: JSAny = receiver; - // Arrays of length 1 or less are considered sorted. - if (len < 2) return array; + // 3. Let buffer be ? ValidateTypedArray(obj). + // ValidateTypedArray currently returns the array, not the ViewBuffer. + const array: JSTypedArray = + ValidateTypedArray(context, obj, kBuiltinNameSort); - // Default sorting is done in C++ using std::sort - if (comparefnObj == Undefined) { - return TypedArraySortFast(context, obj); - } + // 4. Let len be obj.[[ArrayLength]]. + const len: uintptr = array.length; - const comparefn: Callable = - Cast(comparefnObj) otherwise unreachable; - const accessor: TypedArrayAccessor = - GetTypedArrayAccessor(array.elements_kind); - - // Prepare the two work arrays. All numbers are converted to tagged - // objects first, and merge sorted between the two FixedArrays. - // The result is then written back into the JSTypedArray. - const work1: FixedArray = AllocateZeroedFixedArray(Convert(len)); - const work2: FixedArray = AllocateZeroedFixedArray(Convert(len)); - - for (let i: uintptr = 0; i < len; ++i) { - const element: Numeric = accessor.LoadNumeric(context, array, i); - work1.objects[i] = element; - work2.objects[i] = element; - } + // Arrays of length 1 or less are considered sorted. + if (len < 2) return array; + + // Default sorting is done in C++ using std::sort + if (comparefnObj == Undefined) { + return TypedArraySortFast(context, obj); + } - TypedArrayMergeSort(work2, 0, len, work1, array, comparefn); + const comparefn: Callable = + Cast(comparefnObj) otherwise unreachable; + const accessor: TypedArrayAccessor = + GetTypedArrayAccessor(array.elements_kind); + + // Prepare the two work arrays. All numbers are converted to tagged + // objects first, and merge sorted between the two FixedArrays. + // The result is then written back into the JSTypedArray. + const work1: FixedArray = AllocateZeroedFixedArray(Convert(len)); + const work2: FixedArray = AllocateZeroedFixedArray(Convert(len)); + + for (let i: uintptr = 0; i < len; ++i) { + const element: Numeric = accessor.LoadNumeric(array, i); + work1.objects[i] = element; + work2.objects[i] = element; + } - // work1 contains the sorted numbers. Write them back. - for (let i: uintptr = 0; i < len; ++i) { - accessor.StoreNumeric( - context, array, i, UnsafeCast(work1.objects[i])); - } + TypedArrayMergeSort(work2, 0, len, work1, array, comparefn); - return array; + // work1 contains the sorted numbers. Write them back. + for (let i: uintptr = 0; i < len; ++i) { + accessor.StoreNumeric( + context, array, i, UnsafeCast(work1.objects[i])); } + + return array; +} } diff --git a/deps/v8/src/builtins/typed-array-subarray.tq b/deps/v8/src/builtins/typed-array-subarray.tq index c0adc5f19e3959..73d9e80c619500 100644 --- a/deps/v8/src/builtins/typed-array-subarray.tq +++ b/deps/v8/src/builtins/typed-array-subarray.tq @@ -3,60 +3,60 @@ // found in the LICENSE file. namespace typed_array { - // ES %TypedArray%.prototype.subarray - transitioning javascript builtin TypedArrayPrototypeSubArray( - js-implicit context: NativeContext, - receiver: JSAny)(...arguments): JSTypedArray { - const methodName: constexpr string = '%TypedArray%.prototype.subarray'; - - // 1. Let O be the this value. - // 3. If O does not have a [[TypedArrayName]] internal slot, throw a - // TypeError exception. - const source = Cast(receiver) - otherwise ThrowTypeError( - MessageTemplate::kIncompatibleMethodReceiver, methodName); - - // 5. Let buffer be O.[[ViewedArrayBuffer]]. - const buffer = typed_array::GetBuffer(source); - - // 6. Let srcLength be O.[[ArrayLength]]. - const srcLength: uintptr = source.length; - - // 7. Let relativeBegin be ? ToInteger(begin). - // 8. If relativeBegin < 0, let beginIndex be max((srcLength + - // relativeBegin), 0); else let beginIndex be min(relativeBegin, - // srcLength). - const arg0 = arguments[0]; - const begin: uintptr = - arg0 != Undefined ? ConvertToRelativeIndex(arg0, srcLength) : 0; - - // 9. If end is undefined, let relativeEnd be srcLength; - // else, let relativeEnd be ? ToInteger(end). - // 10. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), - // 0); else let endIndex be min(relativeEnd, srcLength). - const arg1 = arguments[1]; - const end: uintptr = - arg1 != Undefined ? ConvertToRelativeIndex(arg1, srcLength) : srcLength; - - // 11. Let newLength be max(endIndex - beginIndex, 0). - const newLength: uintptr = Unsigned(IntPtrMax(Signed(end - begin), 0)); - - // 12. Let constructorName be the String value of O.[[TypedArrayName]]. - // 13. Let elementSize be the Number value of the Element Size value - // specified in Table 52 for constructorName. - const elementsInfo = typed_array::GetTypedArrayElementsInfo(source); - - // 14. Let srcByteOffset be O.[[ByteOffset]]. - const srcByteOffset: uintptr = source.byte_offset; - - // 15. Let beginByteOffset be srcByteOffset + beginIndex × elementSize. - const beginByteOffset = - srcByteOffset + elementsInfo.CalculateByteLength(begin) - otherwise ThrowRangeError(MessageTemplate::kInvalidArrayBufferLength); - - // 16. Let argumentsList be « buffer, beginByteOffset, newLength ». - // 17. Return ? TypedArraySpeciesCreate(O, argumentsList). - return TypedArraySpeciesCreateByBuffer( - methodName, source, buffer, beginByteOffset, newLength); - } +// ES %TypedArray%.prototype.subarray +transitioning javascript builtin TypedArrayPrototypeSubArray( + js-implicit context: NativeContext, + receiver: JSAny)(...arguments): JSTypedArray { + const methodName: constexpr string = '%TypedArray%.prototype.subarray'; + + // 1. Let O be the this value. + // 3. If O does not have a [[TypedArrayName]] internal slot, throw a + // TypeError exception. + const source = Cast(receiver) + otherwise ThrowTypeError( + MessageTemplate::kIncompatibleMethodReceiver, methodName); + + // 5. Let buffer be O.[[ViewedArrayBuffer]]. + const buffer = typed_array::GetBuffer(source); + + // 6. Let srcLength be O.[[ArrayLength]]. + const srcLength: uintptr = source.length; + + // 7. Let relativeBegin be ? ToInteger(begin). + // 8. If relativeBegin < 0, let beginIndex be max((srcLength + + // relativeBegin), 0); else let beginIndex be min(relativeBegin, + // srcLength). + const arg0 = arguments[0]; + const begin: uintptr = + arg0 != Undefined ? ConvertToRelativeIndex(arg0, srcLength) : 0; + + // 9. If end is undefined, let relativeEnd be srcLength; + // else, let relativeEnd be ? ToInteger(end). + // 10. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), + // 0); else let endIndex be min(relativeEnd, srcLength). + const arg1 = arguments[1]; + const end: uintptr = + arg1 != Undefined ? ConvertToRelativeIndex(arg1, srcLength) : srcLength; + + // 11. Let newLength be max(endIndex - beginIndex, 0). + const newLength: uintptr = Unsigned(IntPtrMax(Signed(end - begin), 0)); + + // 12. Let constructorName be the String value of O.[[TypedArrayName]]. + // 13. Let elementSize be the Number value of the Element Size value + // specified in Table 52 for constructorName. + const elementsInfo = typed_array::GetTypedArrayElementsInfo(source); + + // 14. Let srcByteOffset be O.[[ByteOffset]]. + const srcByteOffset: uintptr = source.byte_offset; + + // 15. Let beginByteOffset be srcByteOffset + beginIndex × elementSize. + const beginByteOffset = + srcByteOffset + elementsInfo.CalculateByteLength(begin) + otherwise ThrowRangeError(MessageTemplate::kInvalidArrayBufferLength); + + // 16. Let argumentsList be « buffer, beginByteOffset, newLength ». + // 17. Return ? TypedArraySpeciesCreate(O, argumentsList). + return TypedArraySpeciesCreateByBuffer( + methodName, source, buffer, beginByteOffset, newLength); +} } diff --git a/deps/v8/src/builtins/typed-array.tq b/deps/v8/src/builtins/typed-array.tq index 1b23d3f57297d1..033de32a1d0314 100644 --- a/deps/v8/src/builtins/typed-array.tq +++ b/deps/v8/src/builtins/typed-array.tq @@ -5,271 +5,267 @@ #include 'src/builtins/builtins-typed-array-gen.h' namespace typed_array { - // Naming convention from elements.cc. We have a similar intent but implement - // fastpaths using generics instead of using a class hierarchy for elements - // kinds specific implementations. - type Uint8Elements extends ElementsKind; - type Int8Elements extends ElementsKind; - type Uint16Elements extends ElementsKind; - type Int16Elements extends ElementsKind; - type Uint32Elements extends ElementsKind; - type Int32Elements extends ElementsKind; - type Float32Elements extends ElementsKind; - type Float64Elements extends ElementsKind; - type Uint8ClampedElements extends ElementsKind; - type BigUint64Elements extends ElementsKind; - type BigInt64Elements extends ElementsKind; +// Naming convention from elements.cc. We have a similar intent but implement +// fastpaths using generics instead of using a class hierarchy for elements +// kinds specific implementations. +type Uint8Elements extends ElementsKind; +type Int8Elements extends ElementsKind; +type Uint16Elements extends ElementsKind; +type Int16Elements extends ElementsKind; +type Uint32Elements extends ElementsKind; +type Int32Elements extends ElementsKind; +type Float32Elements extends ElementsKind; +type Float64Elements extends ElementsKind; +type Uint8ClampedElements extends ElementsKind; +type BigUint64Elements extends ElementsKind; +type BigInt64Elements extends ElementsKind; - @export - struct TypedArrayElementsInfo { - // Calculates the number of bytes required for specified number of elements. - macro CalculateByteLength(length: uintptr): uintptr labels IfInvalid { - if (length > kTypedArrayMaxLength) goto IfInvalid; - const maxArrayLength = kArrayBufferMaxByteLength >>> this.sizeLog2; - if (length > maxArrayLength) goto IfInvalid; - const byteLength = length << this.sizeLog2; - return byteLength; - } - - // Calculates the maximum number of elements supported by a specified number - // of bytes. - macro CalculateLength(byteLength: uintptr): uintptr labels IfInvalid { - const length = byteLength >>> this.sizeLog2; - if (length > kTypedArrayMaxLength) goto IfInvalid; - return length; - } - - // Determines if `bytes` (byte offset or length) cannot be evenly divided by - // element size. - macro IsUnaligned(bytes: uintptr): bool { - // Exploits the fact the element size is a power of 2. Determining whether - // there is remainder (not aligned) can be achieved efficiently with bit - // masking. Shift is safe as sizeLog2 can be 3 at most (see - // ElementsKindToShiftSize). - return (bytes & ((1 << this.sizeLog2) - 1)) != 0; - } - - sizeLog2: uintptr; - kind: ElementsKind; +@export +struct TypedArrayElementsInfo { + // Calculates the number of bytes required for specified number of elements. + macro CalculateByteLength(length: uintptr): uintptr labels IfInvalid { + if (length > kTypedArrayMaxLength) goto IfInvalid; + const maxArrayLength = kArrayBufferMaxByteLength >>> this.sizeLog2; + if (length > maxArrayLength) goto IfInvalid; + const byteLength = length << this.sizeLog2; + return byteLength; } - extern runtime TypedArrayCopyElements(Context, JSTypedArray, Object, Number): - void; - extern macro TypedArrayBuiltinsAssembler::ValidateTypedArray( - Context, JSAny, constexpr string): JSTypedArray; - extern macro TypedArrayBuiltinsAssembler::CallCMemcpy( - RawPtr, RawPtr, uintptr): void; - extern macro TypedArrayBuiltinsAssembler::CallCMemmove( - RawPtr, RawPtr, uintptr): void; - extern macro TypedArrayBuiltinsAssembler::CallCMemset( - RawPtr, intptr, uintptr): void; - extern macro TypedArrayBuiltinsAssembler::GetBuffer( - implicit context: Context)(JSTypedArray): JSArrayBuffer; - extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo( - JSTypedArray): TypedArrayElementsInfo; - extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map): - TypedArrayElementsInfo; - extern macro TypedArrayBuiltinsAssembler::IsUint8ElementsKind(ElementsKind): - bool; - extern macro TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind( - ElementsKind): bool; - extern macro LoadFixedTypedArrayElementAsTagged( - RawPtr, uintptr, constexpr ElementsKind): Numeric; - extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric( - Context, JSTypedArray, uintptr, Numeric, constexpr ElementsKind); - extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged( - Context, JSTypedArray, uintptr, JSAny, - constexpr ElementsKind) labels IfDetached; + // Calculates the maximum number of elements supported by a specified number + // of bytes. + macro CalculateLength(byteLength: uintptr): uintptr labels IfInvalid { + const length = byteLength >>> this.sizeLog2; + if (length > kTypedArrayMaxLength) goto IfInvalid; + return length; + } - type LoadNumericFn = builtin(Context, JSTypedArray, uintptr) => Numeric; - type StoreNumericFn = builtin(Context, JSTypedArray, uintptr, Numeric) => Smi; - type StoreJSAnyFn = builtin(Context, JSTypedArray, uintptr, JSAny) => Smi; + // Determines if `bytes` (byte offset or length) cannot be evenly divided by + // element size. + macro IsUnaligned(bytes: uintptr): bool { + // Exploits the fact the element size is a power of 2. Determining whether + // there is remainder (not aligned) can be achieved efficiently with bit + // masking. Shift is safe as sizeLog2 can be 3 at most (see + // ElementsKindToShiftSize). + return (bytes & ((1 << this.sizeLog2) - 1)) != 0; + } - // The result codes returned by StoreNumericFn and StoreJSAnyFn builtins. - const kStoreSucceded: Smi = 0; - const kStoreFailureArrayDetached: Smi = 1; + sizeLog2: uintptr; + kind: ElementsKind; +} +extern runtime TypedArrayCopyElements( + Context, JSTypedArray, Object, Number): void; +extern macro TypedArrayBuiltinsAssembler::ValidateTypedArray( + Context, JSAny, constexpr string): JSTypedArray; - struct TypedArrayAccessor { - macro LoadNumeric( - context: Context, array: JSTypedArray, index: uintptr): Numeric { - const loadfn: LoadNumericFn = this.loadNumericFn; - return loadfn(context, array, index); - } +extern macro TypedArrayBuiltinsAssembler::CallCMemcpy( + RawPtr, RawPtr, uintptr): void; +extern macro TypedArrayBuiltinsAssembler::CallCMemmove( + RawPtr, RawPtr, uintptr): void; +extern macro TypedArrayBuiltinsAssembler::CallCMemset( + RawPtr, intptr, uintptr): void; +extern macro TypedArrayBuiltinsAssembler::GetBuffer(implicit context: Context)( + JSTypedArray): JSArrayBuffer; +extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo( + JSTypedArray): TypedArrayElementsInfo; +extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map): + TypedArrayElementsInfo; +extern macro TypedArrayBuiltinsAssembler::IsUint8ElementsKind(ElementsKind): + bool; +extern macro TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(ElementsKind): + bool; +extern macro LoadFixedTypedArrayElementAsTagged( + RawPtr, uintptr, constexpr ElementsKind): Numeric; +extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric( + Context, JSTypedArray, uintptr, Numeric, constexpr ElementsKind); +extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged( + Context, JSTypedArray, uintptr, JSAny, constexpr ElementsKind) + labels IfDetached; - macro StoreNumeric( - context: Context, array: JSTypedArray, index: uintptr, value: Numeric) { - const storefn: StoreNumericFn = this.storeNumericFn; - const result = storefn(context, array, index, value); - assert(result == kStoreSucceded); - } +type LoadNumericFn = builtin(JSTypedArray, uintptr) => Numeric; +type StoreNumericFn = builtin(Context, JSTypedArray, uintptr, Numeric) => Smi; +type StoreJSAnyFn = builtin(Context, JSTypedArray, uintptr, JSAny) => Smi; - macro StoreJSAny( - context: Context, array: JSTypedArray, index: uintptr, value: JSAny) - labels IfDetached { - const storefn: StoreJSAnyFn = this.storeJSAnyFn; - const result = storefn(context, array, index, value); - if (result == kStoreFailureArrayDetached) { - goto IfDetached; - } - assert(result == kStoreSucceded); - } +// The result codes returned by StoreNumericFn and StoreJSAnyFn builtins. +const kStoreSucceded: Smi = 0; +const kStoreFailureArrayDetached: Smi = 1; - loadNumericFn: LoadNumericFn; - storeNumericFn: StoreNumericFn; - storeJSAnyFn: StoreJSAnyFn; +struct TypedArrayAccessor { + macro LoadNumeric(array: JSTypedArray, index: uintptr): Numeric { + const loadfn: LoadNumericFn = this.loadNumericFn; + return loadfn(array, index); } - macro GetTypedArrayAccessor(): - TypedArrayAccessor { - const loadNumericFn = LoadTypedElement; - const storeNumericFn = StoreTypedElementNumeric; - const storeJSAnyFn = StoreTypedElementJSAny; - return TypedArrayAccessor{loadNumericFn, storeNumericFn, storeJSAnyFn}; + macro StoreNumeric( + context: Context, array: JSTypedArray, index: uintptr, value: Numeric) { + const storefn: StoreNumericFn = this.storeNumericFn; + const result = storefn(context, array, index, value); + assert(result == kStoreSucceded); } - macro GetTypedArrayAccessor(elementsKind: ElementsKind): TypedArrayAccessor { - if (IsElementsKindGreaterThan( - elementsKind, ElementsKind::UINT32_ELEMENTS)) { - if (elementsKind == ElementsKind::INT32_ELEMENTS) { - return GetTypedArrayAccessor(); - } else if (elementsKind == ElementsKind::FLOAT32_ELEMENTS) { - return GetTypedArrayAccessor(); - } else if (elementsKind == ElementsKind::FLOAT64_ELEMENTS) { - return GetTypedArrayAccessor(); - } else if (elementsKind == ElementsKind::UINT8_CLAMPED_ELEMENTS) { - return GetTypedArrayAccessor(); - } else if (elementsKind == ElementsKind::BIGUINT64_ELEMENTS) { - return GetTypedArrayAccessor(); - } else if (elementsKind == ElementsKind::BIGINT64_ELEMENTS) { - return GetTypedArrayAccessor(); - } - } else { - if (elementsKind == ElementsKind::UINT8_ELEMENTS) { - return GetTypedArrayAccessor(); - } else if (elementsKind == ElementsKind::INT8_ELEMENTS) { - return GetTypedArrayAccessor(); - } else if (elementsKind == ElementsKind::UINT16_ELEMENTS) { - return GetTypedArrayAccessor(); - } else if (elementsKind == ElementsKind::INT16_ELEMENTS) { - return GetTypedArrayAccessor(); - } else if (elementsKind == ElementsKind::UINT32_ELEMENTS) { - return GetTypedArrayAccessor(); - } + macro StoreJSAny( + context: Context, array: JSTypedArray, index: uintptr, value: JSAny) + labels IfDetached { + const storefn: StoreJSAnyFn = this.storeJSAnyFn; + const result = storefn(context, array, index, value); + if (result == kStoreFailureArrayDetached) { + goto IfDetached; } - unreachable; + assert(result == kStoreSucceded); } - extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr( - JSTypedArray, ByteArray, uintptr): void; - extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr( - JSTypedArray, RawPtr, uintptr): void; - - // AttachedJSTypedArray guards that the array's buffer is not detached. - transient type AttachedJSTypedArray extends JSTypedArray; + loadNumericFn: LoadNumericFn; + storeNumericFn: StoreNumericFn; + storeJSAnyFn: StoreJSAnyFn; +} - macro EnsureAttached(array: JSTypedArray): AttachedJSTypedArray - labels Detached { - if (IsDetachedBuffer(array.buffer)) goto Detached; - return %RawDownCast(array); - } +macro GetTypedArrayAccessor(): + TypedArrayAccessor { + const loadNumericFn = LoadTypedElement; + const storeNumericFn = StoreTypedElementNumeric; + const storeJSAnyFn = StoreTypedElementJSAny; + return TypedArrayAccessor{loadNumericFn, storeNumericFn, storeJSAnyFn}; +} - struct AttachedJSTypedArrayWitness { - macro Get(): AttachedJSTypedArray { - return this.unstable; +macro GetTypedArrayAccessor(elementsKind: ElementsKind): TypedArrayAccessor { + if (IsElementsKindGreaterThan(elementsKind, ElementsKind::UINT32_ELEMENTS)) { + if (elementsKind == ElementsKind::INT32_ELEMENTS) { + return GetTypedArrayAccessor(); + } else if (elementsKind == ElementsKind::FLOAT32_ELEMENTS) { + return GetTypedArrayAccessor(); + } else if (elementsKind == ElementsKind::FLOAT64_ELEMENTS) { + return GetTypedArrayAccessor(); + } else if (elementsKind == ElementsKind::UINT8_CLAMPED_ELEMENTS) { + return GetTypedArrayAccessor(); + } else if (elementsKind == ElementsKind::BIGUINT64_ELEMENTS) { + return GetTypedArrayAccessor(); + } else if (elementsKind == ElementsKind::BIGINT64_ELEMENTS) { + return GetTypedArrayAccessor(); } - - macro GetStable(): JSTypedArray { - return this.stable; + } else { + if (elementsKind == ElementsKind::UINT8_ELEMENTS) { + return GetTypedArrayAccessor(); + } else if (elementsKind == ElementsKind::INT8_ELEMENTS) { + return GetTypedArrayAccessor(); + } else if (elementsKind == ElementsKind::UINT16_ELEMENTS) { + return GetTypedArrayAccessor(); + } else if (elementsKind == ElementsKind::INT16_ELEMENTS) { + return GetTypedArrayAccessor(); + } else if (elementsKind == ElementsKind::UINT32_ELEMENTS) { + return GetTypedArrayAccessor(); } + } + unreachable; +} - macro Recheck() labels Detached { - if (IsDetachedBuffer(this.stable.buffer)) goto Detached; - this.unstable = %RawDownCast(this.stable); - } +extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr( + JSTypedArray, ByteArray, uintptr): void; +extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr( + JSTypedArray, RawPtr, uintptr): void; - macro Load(implicit context: Context)(k: uintptr): JSAny { - const lf: LoadNumericFn = this.loadfn; - return lf(context, this.unstable, k); - } +// AttachedJSTypedArray guards that the array's buffer is not detached. +transient type AttachedJSTypedArray extends JSTypedArray; - stable: JSTypedArray; - unstable: AttachedJSTypedArray; - loadfn: LoadNumericFn; - } +macro EnsureAttached(array: JSTypedArray): AttachedJSTypedArray + labels Detached { + if (IsDetachedBuffer(array.buffer)) goto Detached; + return %RawDownCast(array); +} - macro NewAttachedJSTypedArrayWitness(array: AttachedJSTypedArray): - AttachedJSTypedArrayWitness { - const kind = array.elements_kind; - const accessor: TypedArrayAccessor = GetTypedArrayAccessor(kind); - return AttachedJSTypedArrayWitness{ - stable: array, - unstable: array, - loadfn: accessor.loadNumericFn - }; +struct AttachedJSTypedArrayWitness { + macro Get(): AttachedJSTypedArray { + return this.unstable; } - macro KindForArrayType(): - constexpr ElementsKind; - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::UINT8_ELEMENTS; - } - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::INT8_ELEMENTS; - } - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::UINT16_ELEMENTS; - } - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::INT16_ELEMENTS; - } - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::UINT32_ELEMENTS; - } - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::INT32_ELEMENTS; - } - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::FLOAT32_ELEMENTS; - } - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::FLOAT64_ELEMENTS; - } - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::UINT8_CLAMPED_ELEMENTS; - } - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::BIGUINT64_ELEMENTS; - } - KindForArrayType(): constexpr ElementsKind { - return ElementsKind::BIGINT64_ELEMENTS; + macro GetStable(): JSTypedArray { + return this.stable; } - builtin LoadTypedElement( - _context: Context, array: JSTypedArray, index: uintptr): Numeric { - return LoadFixedTypedArrayElementAsTagged( - array.data_ptr, index, KindForArrayType()); + macro Recheck() labels Detached { + if (IsDetachedBuffer(this.stable.buffer)) goto Detached; + this.unstable = %RawDownCast(this.stable); } - builtin StoreTypedElementNumeric( - context: Context, typedArray: JSTypedArray, index: uintptr, - value: Numeric): Smi { - StoreJSTypedArrayElementFromNumeric( - context, typedArray, index, value, KindForArrayType()); - return kStoreSucceded; + macro Load(implicit context: Context)(k: uintptr): JSAny { + const lf: LoadNumericFn = this.loadfn; + return lf(this.unstable, k); } - // Returns True on sucess or False if the typedArrays was detached. - builtin StoreTypedElementJSAny( - context: Context, typedArray: JSTypedArray, index: uintptr, - value: JSAny): Smi { - try { - StoreJSTypedArrayElementFromTagged( - context, typedArray, index, value, KindForArrayType()) - otherwise IfDetached; - } - label IfDetached { - return kStoreFailureArrayDetached; - } - return kStoreSucceded; + stable: JSTypedArray; + unstable: AttachedJSTypedArray; + loadfn: LoadNumericFn; +} + +macro NewAttachedJSTypedArrayWitness(array: AttachedJSTypedArray): + AttachedJSTypedArrayWitness { + const kind = array.elements_kind; + const accessor: TypedArrayAccessor = GetTypedArrayAccessor(kind); + return AttachedJSTypedArrayWitness{ + stable: array, + unstable: array, + loadfn: accessor.loadNumericFn + }; +} + +macro KindForArrayType(): constexpr ElementsKind; +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::UINT8_ELEMENTS; +} +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::INT8_ELEMENTS; +} +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::UINT16_ELEMENTS; +} +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::INT16_ELEMENTS; +} +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::UINT32_ELEMENTS; +} +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::INT32_ELEMENTS; +} +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::FLOAT32_ELEMENTS; +} +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::FLOAT64_ELEMENTS; +} +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::UINT8_CLAMPED_ELEMENTS; +} +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::BIGUINT64_ELEMENTS; +} +KindForArrayType(): constexpr ElementsKind { + return ElementsKind::BIGINT64_ELEMENTS; +} + +builtin LoadTypedElement( + array: JSTypedArray, index: uintptr): Numeric { + return LoadFixedTypedArrayElementAsTagged( + array.data_ptr, index, KindForArrayType()); +} + +builtin StoreTypedElementNumeric( + context: Context, typedArray: JSTypedArray, index: uintptr, + value: Numeric): Smi { + StoreJSTypedArrayElementFromNumeric( + context, typedArray, index, value, KindForArrayType()); + return kStoreSucceded; +} + +// Returns True on sucess or False if the typedArrays was detached. +builtin StoreTypedElementJSAny( + context: Context, typedArray: JSTypedArray, index: uintptr, + value: JSAny): Smi { + try { + StoreJSTypedArrayElementFromTagged( + context, typedArray, index, value, KindForArrayType()) + otherwise IfDetached; + } label IfDetached { + return kStoreFailureArrayDetached; } + return kStoreSucceded; +} } diff --git a/deps/v8/src/builtins/wasm.tq b/deps/v8/src/builtins/wasm.tq new file mode 100644 index 00000000000000..097e39d430e7d3 --- /dev/null +++ b/deps/v8/src/builtins/wasm.tq @@ -0,0 +1,273 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include 'src/builtins/builtins-wasm-gen.h' + +namespace runtime { +extern runtime WasmMemoryGrow(Context, WasmInstanceObject, Smi): Smi; +extern runtime WasmRefFunc(Context, WasmInstanceObject, Smi): JSAny; +extern runtime WasmFunctionTableGet( + Context, WasmInstanceObject, Smi, Smi): JSAny; +extern runtime WasmFunctionTableSet( + Context, WasmInstanceObject, Smi, Smi, Object): JSAny; +extern runtime ThrowWasmError(Context, Smi): JSAny; +extern runtime Throw(Context, Object): JSAny; +extern runtime ReThrow(Context, Object): JSAny; +extern runtime WasmStackGuard(Context): JSAny; +extern runtime ThrowWasmStackOverflow(Context): JSAny; +extern runtime WasmTraceMemory(Context, Smi): JSAny; +} + +namespace wasm { +const kFuncTableType: + constexpr int31 generates 'wasm::ValueType::Kind::kFuncRef'; + +extern macro WasmBuiltinsAssembler::LoadInstanceFromFrame(): WasmInstanceObject; + +// WasmInstanceObject has a field layout that Torque can't handle yet. +// TODO(bbudge) Eliminate these functions when Torque is ready. +extern macro WasmBuiltinsAssembler::LoadContextFromInstance(WasmInstanceObject): + NativeContext; +extern macro WasmBuiltinsAssembler::LoadTablesFromInstance(WasmInstanceObject): + FixedArray; +extern macro WasmBuiltinsAssembler::LoadExternalFunctionsFromInstance( + WasmInstanceObject): FixedArray; + +macro LoadContextFromFrame(): NativeContext { + return LoadContextFromInstance(LoadInstanceFromFrame()); +} + +builtin WasmInt32ToHeapNumber(val: int32): HeapNumber { + return AllocateHeapNumberWithValue(Convert(val)); +} + +builtin WasmTaggedNonSmiToInt32(implicit context: Context)(val: JSAnyNotSmi): + int32 { + return ChangeTaggedNonSmiToInt32(val); +} + +builtin WasmTaggedToFloat64(implicit context: Context)(val: JSAny): float64 { + return ChangeTaggedToFloat64(val); +} + +builtin WasmMemoryGrow(numPages: int32): int32 { + if (!IsValidPositiveSmi(ChangeInt32ToIntPtr(numPages))) + return Int32Constant(-1); + const instance: WasmInstanceObject = LoadInstanceFromFrame(); + const context: NativeContext = LoadContextFromInstance(instance); + const result: Smi = + runtime::WasmMemoryGrow(context, instance, SmiFromInt32(numPages)); + return SmiToInt32(result); +} + +builtin WasmTableGet(tableIndex: intptr, index: int32): Object { + const instance: WasmInstanceObject = LoadInstanceFromFrame(); + const entryIndex: intptr = ChangeInt32ToIntPtr(index); + try { + assert(IsValidPositiveSmi(tableIndex)); + if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange; + + const tables: FixedArray = LoadTablesFromInstance(instance); + const table: WasmTableObject = %RawDownCast( + LoadFixedArrayElement(tables, tableIndex)); + const entriesCount: intptr = Convert(table.current_length); + if (entryIndex >= entriesCount) goto IndexOutOfRange; + + const entries: FixedArray = table.entries; + const entry: Object = LoadFixedArrayElement(entries, entryIndex); + + try { + const entryObject: HeapObject = + TaggedToHeapObject(entry) otherwise ReturnEntry; + if (IsTuple2Map(entryObject.map)) goto CallRuntime; + goto ReturnEntry; + } label ReturnEntry { + return entry; + } + } label CallRuntime deferred { + tail runtime::WasmFunctionTableGet( + LoadContextFromInstance(instance), instance, SmiFromIntPtr(tableIndex), + SmiFromIntPtr(entryIndex)); + } label IndexOutOfRange deferred { + tail ThrowWasmTrapTableOutOfBounds(); + } +} + +builtin WasmTableSet(tableIndex: intptr, index: int32, value: Object): Object { + const instance: WasmInstanceObject = LoadInstanceFromFrame(); + const entryIndex: intptr = ChangeInt32ToIntPtr(index); + try { + assert(IsValidPositiveSmi(tableIndex)); + if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange; + + const tables: FixedArray = LoadTablesFromInstance(instance); + const table: WasmTableObject = %RawDownCast( + LoadFixedArrayElement(tables, tableIndex)); + + // Fall back to the runtime to set funcrefs, since we have to update + // function dispatch tables. + const tableType: Smi = table.raw_type; + if (tableType == SmiConstant(kFuncTableType)) goto CallRuntime; + + const entriesCount: intptr = Convert(table.current_length); + if (entryIndex >= entriesCount) goto IndexOutOfRange; + + const entries: FixedArray = table.entries; + StoreFixedArrayElement(entries, entryIndex, value); + return Undefined; + } label CallRuntime deferred { + tail runtime::WasmFunctionTableSet( + LoadContextFromInstance(instance), instance, SmiFromIntPtr(tableIndex), + SmiFromIntPtr(entryIndex), value); + } label IndexOutOfRange deferred { + tail ThrowWasmTrapTableOutOfBounds(); + } +} + +builtin WasmRefFunc(index: uint32): Object { + const instance: WasmInstanceObject = LoadInstanceFromFrame(); + try { + const table: FixedArray = LoadExternalFunctionsFromInstance(instance); + if (table == Undefined) goto CallRuntime; + const functionIndex: intptr = Signed(ChangeUint32ToWord(index)); + const result: Object = LoadFixedArrayElement(table, functionIndex); + if (result == Undefined) goto CallRuntime; + return result; + } label CallRuntime deferred { + tail runtime::WasmRefFunc( + LoadContextFromInstance(instance), instance, SmiFromUint32(index)); + } +} + +builtin WasmThrow(exception: Object): JSAny { + tail runtime::Throw(LoadContextFromFrame(), exception); +} + +builtin WasmRethrow(exception: Object): JSAny { + if (exception == Null) tail ThrowWasmTrapRethrowNullRef(); + tail runtime::ReThrow(LoadContextFromFrame(), exception); +} + +builtin WasmStackGuard(): JSAny { + tail runtime::WasmStackGuard(LoadContextFromFrame()); +} + +builtin WasmStackOverflow(): JSAny { + tail runtime::ThrowWasmStackOverflow(LoadContextFromFrame()); +} + +builtin WasmTraceMemory(info: Smi): JSAny { + tail runtime::WasmTraceMemory(LoadContextFromFrame(), info); +} + +builtin WasmAllocateJSArray(implicit context: Context)(size: Smi): JSArray { + const map: Map = GetFastPackedElementsJSArrayMap(); + return AllocateJSArray(ElementsKind::PACKED_ELEMENTS, map, size, size); +} + +extern macro TryHasOwnProperty(HeapObject, Map, InstanceType, Name): never + labels Found, NotFound, Bailout; +type OnNonExistent constexpr 'OnNonExistent'; +const kReturnUndefined: constexpr OnNonExistent + generates 'OnNonExistent::kReturnUndefined'; +extern macro SmiConstant(constexpr OnNonExistent): Smi; +extern transitioning builtin GetPropertyWithReceiver(implicit context: Context)( + JSAny, Name, JSAny, Smi): JSAny; + +transitioning builtin WasmGetOwnProperty(implicit context: Context)( + object: Object, uniqueName: Name): JSAny { + try { + const heapObject: HeapObject = + TaggedToHeapObject(object) otherwise NotFound; + const receiver: JSReceiver = + Cast(heapObject) otherwise NotFound; + try { + TryHasOwnProperty( + receiver, receiver.map, receiver.instanceType, uniqueName) + otherwise Found, NotFound, Bailout; + } label Found { + tail GetPropertyWithReceiver( + receiver, uniqueName, receiver, SmiConstant(kReturnUndefined)); + } + } label NotFound deferred { + return Undefined; + } label Bailout deferred { + unreachable; + } +} + +// Trap builtins. + +builtin WasmTrap(error: Smi): JSAny { + tail runtime::ThrowWasmError(LoadContextFromFrame(), error); +} + +builtin ThrowWasmTrapUnreachable(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnreachable)); +} + +builtin ThrowWasmTrapMemOutOfBounds(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapMemOutOfBounds)); +} + +builtin ThrowWasmTrapUnalignedAccess(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnalignedAccess)); +} + +builtin ThrowWasmTrapDivByZero(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDivByZero)); +} + +builtin ThrowWasmTrapDivUnrepresentable(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDivUnrepresentable)); +} + +builtin ThrowWasmTrapRemByZero(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRemByZero)); +} + +builtin ThrowWasmTrapFloatUnrepresentable(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFloatUnrepresentable)); +} + +builtin ThrowWasmTrapFuncInvalid(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFuncInvalid)); +} + +builtin ThrowWasmTrapFuncSigMismatch(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFuncSigMismatch)); +} + +builtin ThrowWasmTrapDataSegmentDropped(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDataSegmentDropped)); +} + +builtin ThrowWasmTrapElemSegmentDropped(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapElemSegmentDropped)); +} + +builtin ThrowWasmTrapTableOutOfBounds(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapTableOutOfBounds)); +} + +builtin ThrowWasmTrapBrOnExnNullRef(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapBrOnExnNullRef)); +} + +builtin ThrowWasmTrapRethrowNullRef(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRethrowNullRef)); +} + +builtin ThrowWasmTrapNullDereference(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapNullDereference)); +} + +builtin ThrowWasmTrapIllegalCast(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapIllegalCast)); +} + +builtin ThrowWasmTrapArrayOutOfBounds(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapArrayOutOfBounds)); +} +} diff --git a/deps/v8/src/builtins/x64/builtins-x64.cc b/deps/v8/src/builtins/x64/builtins-x64.cc index 8d028c88f0086e..bfabe26292b8d3 100644 --- a/deps/v8/src/builtins/x64/builtins-x64.cc +++ b/deps/v8/src/builtins/x64/builtins-x64.cc @@ -1769,7 +1769,6 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { } // static -// TODO(victor): merge steps 1, 2 and 3 when V8_REVERSE_JSARGS is set. void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { // Stack Layout: // rsp[0] : Return address @@ -1781,19 +1780,40 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { // NOTE: The order of args are reversed if V8_REVERSE_JSARGS // rax contains the number of arguments, n, not counting the receiver. - // 1. Make sure we have at least one argument. +#ifdef V8_REVERSE_JSARGS + // 1. Get the callable to call (passed as receiver) from the stack. + { + StackArgumentsAccessor args(rax); + __ movq(rdi, args.GetReceiverOperand()); + } + + // 2. Save the return address and drop the callable. + __ PopReturnAddressTo(rbx); + __ Pop(kScratchRegister); + + // 3. Make sure we have at least one argument. { Label done; __ testq(rax, rax); __ j(not_zero, &done, Label::kNear); - __ PopReturnAddressTo(rbx); -#ifdef V8_REVERSE_JSARGS - __ Pop(kScratchRegister); // Pop the receiver. __ PushRoot(RootIndex::kUndefinedValue); - __ Push(kScratchRegister); + __ incq(rax); + __ bind(&done); + } + + // 4. Push back the return address one slot down on the stack (overwriting the + // original callable), making the original first argument the new receiver. + __ PushReturnAddressFrom(rbx); + __ decq(rax); // One fewer argument (first argument is new receiver). + #else + // 1. Make sure we have at least one argument. + { + Label done; + __ testq(rax, rax); + __ j(not_zero, &done, Label::kNear); + __ PopReturnAddressTo(rbx); __ PushRoot(RootIndex::kUndefinedValue); -#endif __ PushReturnAddressFrom(rbx); __ incq(rax); __ bind(&done); @@ -1805,14 +1825,6 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { __ movq(rdi, args.GetReceiverOperand()); } -#ifdef V8_REVERSE_JSARGS - // 3. Shift return address one slot down on the stack (overwriting the - // original receiver), making the original first argument the new receiver. - { - __ DropUnderReturnAddress(1, rbx); // Drop one slot under return address. - __ decq(rax); // One fewer argument (first argument is new receiver). - } -#else // 3. Shift arguments and return address one slot down on the stack // (overwriting the original receiver). Adjust argument count to make // the original first argument the new receiver. @@ -2205,10 +2217,8 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, Label copy, check; Register src = r8, dest = rsp, num = r9, current = r11; __ movq(src, rsp); - __ movq(kScratchRegister, rcx); - __ negq(kScratchRegister); - __ leaq(rsp, Operand(rsp, kScratchRegister, times_system_pointer_size, - 0)); // Update stack pointer. + __ leaq(kScratchRegister, Operand(rcx, times_system_pointer_size, 0)); + __ AllocateStackSpace(kScratchRegister); __ leaq(num, Operand(rax, 2)); // Number of words to copy. // +2 for receiver and return address. __ Set(current, 0); @@ -3500,8 +3510,9 @@ void Builtins::Generate_CallApiGetter(MacroAssembler* masm) { DCHECK(api_function_address != name_arg); __ LoadTaggedPointerField( scratch, FieldOperand(callback, AccessorInfo::kJsGetterOffset)); - __ movq(api_function_address, - FieldOperand(scratch, Foreign::kForeignAddressOffset)); + __ LoadExternalPointerField( + api_function_address, + FieldOperand(scratch, Foreign::kForeignAddressOffset)); // +3 is to skip prolog, return address and name handle. Operand return_value_operand( diff --git a/deps/v8/src/codegen/arm/constants-arm.h b/deps/v8/src/codegen/arm/constants-arm.h index 171de9e1d7d135..a7726a8f25e361 100644 --- a/deps/v8/src/codegen/arm/constants-arm.h +++ b/deps/v8/src/codegen/arm/constants-arm.h @@ -459,23 +459,6 @@ class Instruction { return InstructionBits() & (((2 << (hi - lo)) - 1) << lo); } - // Static support. - - // Extract a single bit from the instruction bits and return it as bit 0 in - // the result. - static inline int Bit(Instr instr, int nr) { return (instr >> nr) & 1; } - - // Extract a bit field from the instruction bits and return it in the - // least-significant bits of the result. - static inline int Bits(Instr instr, int hi, int lo) { - return (instr >> lo) & ((2 << (hi - lo)) - 1); - } - - // Read a bit field , leaving its position unchanged in the result. - static inline int BitField(Instr instr, int hi, int lo) { - return instr & (((2 << (hi - lo)) - 1) << lo); - } - // Accessors for the different named fields used in the ARM encoding. // The naming of these accessor corresponds to figure A3-1. // diff --git a/deps/v8/src/codegen/arm/cpu-arm.cc b/deps/v8/src/codegen/arm/cpu-arm.cc index 9113de705d2052..47fe4bdb7404ce 100644 --- a/deps/v8/src/codegen/arm/cpu-arm.cc +++ b/deps/v8/src/codegen/arm/cpu-arm.cc @@ -37,18 +37,6 @@ V8_NOINLINE void CpuFeatures::FlushICache(void* start, size_t size) { register uint32_t end asm("r1") = beg + size; register uint32_t flg asm("r2") = 0; -#ifdef __clang__ - // This variant of the asm avoids a constant pool entry, which can be - // problematic when LTO'ing. It is also slightly shorter. - register uint32_t scno asm("r7") = __ARM_NR_cacheflush; - - asm volatile("svc 0\n" - : - : "r"(beg), "r"(end), "r"(flg), "r"(scno) - : "memory"); -#else - // Use a different variant of the asm with GCC because some versions doesn't - // support r7 as an asm input. asm volatile( // This assembly works for both ARM and Thumb targets. @@ -66,7 +54,6 @@ V8_NOINLINE void CpuFeatures::FlushICache(void* start, size_t size) { : "r"(beg), "r"(end), "r"(flg), [scno] "i"(__ARM_NR_cacheflush) : "memory"); #endif -#endif #endif // !USE_SIMULATOR } diff --git a/deps/v8/src/codegen/arm/interface-descriptors-arm.cc b/deps/v8/src/codegen/arm/interface-descriptors-arm.cc index 575fd2780572b4..5a4e08dc77c0bd 100644 --- a/deps/v8/src/codegen/arm/interface-descriptors-arm.cc +++ b/deps/v8/src/codegen/arm/interface-descriptors-arm.cc @@ -283,6 +283,30 @@ void RunMicrotasksEntryDescriptor::InitializePlatformSpecific( data->InitializePlatformSpecific(arraysize(registers), registers); } +void BinaryOp_WithFeedbackDescriptor::InitializePlatformSpecific( + CallInterfaceDescriptorData* data) { + // TODO(v8:8888): Implement on this platform. + DefaultInitializePlatformSpecific(data, 4); +} + +void CallTrampoline_WithFeedbackDescriptor::InitializePlatformSpecific( + CallInterfaceDescriptorData* data) { + // TODO(v8:8888): Implement on this platform. + DefaultInitializePlatformSpecific(data, 4); +} + +void Compare_WithFeedbackDescriptor::InitializePlatformSpecific( + CallInterfaceDescriptorData* data) { + // TODO(v8:8888): Implement on this platform. + DefaultInitializePlatformSpecific(data, 4); +} + +void UnaryOp_WithFeedbackDescriptor::InitializePlatformSpecific( + CallInterfaceDescriptorData* data) { + // TODO(v8:8888): Implement on this platform. + DefaultInitializePlatformSpecific(data, 3); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/codegen/arm/macro-assembler-arm.cc b/deps/v8/src/codegen/arm/macro-assembler-arm.cc index 349c8dc29e7e97..7e5fa8cef1c1c2 100644 --- a/deps/v8/src/codegen/arm/macro-assembler-arm.cc +++ b/deps/v8/src/codegen/arm/macro-assembler-arm.cc @@ -17,7 +17,7 @@ #include "src/codegen/register-configuration.h" #include "src/debug/debug.h" #include "src/execution/frames-inl.h" -#include "src/heap/heap-inl.h" // For MemoryChunk. +#include "src/heap/memory-chunk.h" #include "src/init/bootstrapper.h" #include "src/logging/counters.h" #include "src/numbers/double.h" @@ -427,6 +427,35 @@ void TurboAssembler::Push(Smi smi) { push(scratch); } +void TurboAssembler::PushArray(Register array, Register size, Register scratch, + PushArrayOrder order) { + UseScratchRegisterScope temps(this); + Register counter = scratch; + Register tmp = temps.Acquire(); + DCHECK(!AreAliased(array, size, counter, tmp)); + Label loop, entry; + if (order == PushArrayOrder::kReverse) { + mov(counter, Operand(0)); + b(&entry); + bind(&loop); + ldr(tmp, MemOperand(array, counter, LSL, kSystemPointerSizeLog2)); + push(tmp); + add(counter, counter, Operand(1)); + bind(&entry); + cmp(counter, size); + b(lt, &loop); + } else { + mov(counter, size); + b(&entry); + bind(&loop); + ldr(tmp, MemOperand(array, counter, LSL, kSystemPointerSizeLog2)); + push(tmp); + bind(&entry); + sub(counter, counter, Operand(1), SetCC); + b(ge, &loop); + } +} + void TurboAssembler::Move(Register dst, Smi smi) { mov(dst, Operand(smi)); } void TurboAssembler::Move(Register dst, Handle value) { @@ -1556,7 +1585,7 @@ void MacroAssembler::CallDebugOnFunctionCall(Register fun, Register new_target, Register expected_parameter_count, Register actual_parameter_count) { // Load receiver to pass it later to DebugOnFunctionCall hook. - ldr(r4, MemOperand(sp, actual_parameter_count, LSL, kPointerSizeLog2)); + ldr(r4, ReceiverOperand(actual_parameter_count)); FrameScope frame(this, has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); SmiTag(expected_parameter_count); diff --git a/deps/v8/src/codegen/arm/macro-assembler-arm.h b/deps/v8/src/codegen/arm/macro-assembler-arm.h index 9ec1bafb5803aa..a7dc5498b8b8ec 100644 --- a/deps/v8/src/codegen/arm/macro-assembler-arm.h +++ b/deps/v8/src/codegen/arm/macro-assembler-arm.h @@ -156,6 +156,12 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { } } + enum class PushArrayOrder { kNormal, kReverse }; + // `array` points to the first element (the lowest address). + // `array` and `size` are not modified. + void PushArray(Register array, Register size, Register scratch, + PushArrayOrder order = PushArrayOrder::kNormal); + void Pop(Register dst) { pop(dst); } // Pop two registers. Pops rightmost register first (from lower address). @@ -720,6 +726,18 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { void JumpIfIsInRange(Register value, unsigned lower_limit, unsigned higher_limit, Label* on_in_range); + // It assumes that the arguments are located below the stack pointer. + // argc is the number of arguments not including the receiver. + // TODO(victorgomes): Remove this function once we stick with the reversed + // arguments order. + MemOperand ReceiverOperand(Register argc) { +#ifdef V8_REVERSE_JSARGS + return MemOperand(sp, 0); +#else + return MemOperand(sp, argc, LSL, kSystemPointerSizeLog2); +#endif + } + // --------------------------------------------------------------------------- // Runtime calls diff --git a/deps/v8/src/codegen/arm/register-arm.h b/deps/v8/src/codegen/arm/register-arm.h index 0d453ec03ed81b..77ae14f98cc834 100644 --- a/deps/v8/src/codegen/arm/register-arm.h +++ b/deps/v8/src/codegen/arm/register-arm.h @@ -351,6 +351,8 @@ constexpr Register kWasmCompileLazyFuncIndexRegister = r4; constexpr Register cp = r7; // JavaScript context pointer. constexpr Register kRootRegister = r10; // Roots array pointer. +constexpr DoubleRegister kFPReturnRegister0 = d0; + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/codegen/arm64/assembler-arm64-inl.h b/deps/v8/src/codegen/arm64/assembler-arm64-inl.h index f3c3e559753c10..c47f8f1aa54baf 100644 --- a/deps/v8/src/codegen/arm64/assembler-arm64-inl.h +++ b/deps/v8/src/codegen/arm64/assembler-arm64-inl.h @@ -660,6 +660,7 @@ Address RelocInfo::constant_pool_entry_address() { HeapObject RelocInfo::target_object() { DCHECK(IsCodeTarget(rmode_) || IsEmbeddedObjectMode(rmode_)); if (IsCompressedEmbeddedObject(rmode_)) { + CHECK(!host_.is_null()); return HeapObject::cast(Object(DecompressTaggedAny( host_.address(), Assembler::target_compressed_address_at(pc_, constant_pool_)))); diff --git a/deps/v8/src/codegen/arm64/assembler-arm64.cc b/deps/v8/src/codegen/arm64/assembler-arm64.cc index d5a0295934d8eb..97a57d6f3c6d5a 100644 --- a/deps/v8/src/codegen/arm64/assembler-arm64.cc +++ b/deps/v8/src/codegen/arm64/assembler-arm64.cc @@ -140,7 +140,9 @@ bool RelocInfo::IsCodedSpecially() { bool RelocInfo::IsInConstantPool() { Instruction* instr = reinterpret_cast(pc_); - return instr->IsLdrLiteralX(); + DCHECK_IMPLIES(instr->IsLdrLiteralW(), COMPRESS_POINTERS_BOOL); + return instr->IsLdrLiteralX() || + (COMPRESS_POINTERS_BOOL && instr->IsLdrLiteralW()); } uint32_t RelocInfo::wasm_call_tag() const { diff --git a/deps/v8/src/codegen/arm64/instructions-arm64.cc b/deps/v8/src/codegen/arm64/instructions-arm64.cc index c2224ffe34aa0e..7d986f286d92de 100644 --- a/deps/v8/src/codegen/arm64/instructions-arm64.cc +++ b/deps/v8/src/codegen/arm64/instructions-arm64.cc @@ -343,6 +343,10 @@ void NEONFormatDecoder::SetFormatMaps(const NEONFormatMap* format0, formats_[0] = format0; formats_[1] = (format1 == nullptr) ? formats_[0] : format1; formats_[2] = (format2 == nullptr) ? formats_[1] : format2; + // Support four parameters form (e.i. ld4r) + // to avoid using positional arguments in DisassemblingDecoder. + // See: https://crbug.com/v8/10365 + formats_[3] = formats_[2]; } void NEONFormatDecoder::SetFormatMap(unsigned index, @@ -353,15 +357,18 @@ void NEONFormatDecoder::SetFormatMap(unsigned index, } const char* NEONFormatDecoder::SubstitutePlaceholders(const char* string) { - return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder); + return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder, + kPlaceholder); } const char* NEONFormatDecoder::Substitute(const char* string, SubstitutionMode mode0, SubstitutionMode mode1, - SubstitutionMode mode2) { + SubstitutionMode mode2, + SubstitutionMode mode3) { snprintf(form_buffer_, sizeof(form_buffer_), string, GetSubstitute(0, mode0), - GetSubstitute(1, mode1), GetSubstitute(2, mode2)); + GetSubstitute(1, mode1), GetSubstitute(2, mode2), + GetSubstitute(3, mode3)); return form_buffer_; } diff --git a/deps/v8/src/codegen/arm64/instructions-arm64.h b/deps/v8/src/codegen/arm64/instructions-arm64.h index d2341b972fbcb7..c115fb692469f2 100644 --- a/deps/v8/src/codegen/arm64/instructions-arm64.h +++ b/deps/v8/src/codegen/arm64/instructions-arm64.h @@ -619,7 +619,8 @@ class NEONFormatDecoder { // substitution mode. const char* Substitute(const char* string, SubstitutionMode mode0 = kFormat, SubstitutionMode mode1 = kFormat, - SubstitutionMode mode2 = kFormat); + SubstitutionMode mode2 = kFormat, + SubstitutionMode mode3 = kFormat); // Append a "2" to a mnemonic string based of the state of the Q bit. const char* Mnemonic(const char* mnemonic); @@ -738,7 +739,7 @@ class NEONFormatDecoder { uint8_t PickBits(const uint8_t bits[]); Instr instrbits_; - const NEONFormatMap* formats_[3]; + const NEONFormatMap* formats_[4]; char form_buffer_[64]; char mne_buffer_[16]; }; diff --git a/deps/v8/src/codegen/arm64/interface-descriptors-arm64.cc b/deps/v8/src/codegen/arm64/interface-descriptors-arm64.cc index 2d86ace4bc28c0..9f0592244491be 100644 --- a/deps/v8/src/codegen/arm64/interface-descriptors-arm64.cc +++ b/deps/v8/src/codegen/arm64/interface-descriptors-arm64.cc @@ -287,6 +287,30 @@ void RunMicrotasksEntryDescriptor::InitializePlatformSpecific( data->InitializePlatformSpecific(arraysize(registers), registers); } +void BinaryOp_WithFeedbackDescriptor::InitializePlatformSpecific( + CallInterfaceDescriptorData* data) { + // TODO(v8:8888): Implement on this platform. + DefaultInitializePlatformSpecific(data, 4); +} + +void CallTrampoline_WithFeedbackDescriptor::InitializePlatformSpecific( + CallInterfaceDescriptorData* data) { + // TODO(v8:8888): Implement on this platform. + DefaultInitializePlatformSpecific(data, 4); +} + +void Compare_WithFeedbackDescriptor::InitializePlatformSpecific( + CallInterfaceDescriptorData* data) { + // TODO(v8:8888): Implement on this platform. + DefaultInitializePlatformSpecific(data, 4); +} + +void UnaryOp_WithFeedbackDescriptor::InitializePlatformSpecific( + CallInterfaceDescriptorData* data) { + // TODO(v8:8888): Implement on this platform. + DefaultInitializePlatformSpecific(data, 3); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/codegen/arm64/macro-assembler-arm64-inl.h b/deps/v8/src/codegen/arm64/macro-assembler-arm64-inl.h index 809838bcf9d247..93b8136d9a997a 100644 --- a/deps/v8/src/codegen/arm64/macro-assembler-arm64-inl.h +++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64-inl.h @@ -713,7 +713,7 @@ void TurboAssembler::Fmov(VRegister vd, float imm) { } else { UseScratchRegisterScope temps(this); Register tmp = temps.AcquireW(); - Mov(tmp, bit_cast(imm)); + Mov(tmp, bits); Fmov(vd, tmp); } } else { diff --git a/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc b/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc index 1273904c9c2bd0..c157df29966975 100644 --- a/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc +++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc @@ -16,7 +16,7 @@ #include "src/deoptimizer/deoptimizer.h" #include "src/execution/frame-constants.h" #include "src/execution/frames-inl.h" -#include "src/heap/heap-inl.h" // For MemoryChunk. +#include "src/heap/memory-chunk.h" #include "src/init/bootstrapper.h" #include "src/logging/counters.h" #include "src/runtime/runtime.h" @@ -1306,7 +1306,14 @@ void TurboAssembler::CopyDoubleWords(Register dst, Register src, Register count, static_assert(kSystemPointerSize == kDRegSize, "pointers must be the same size as doubles"); - int direction = (mode == kDstLessThanSrc) ? 1 : -1; + if (mode == kDstLessThanSrcAndReverse) { + Add(src, src, Operand(count, LSL, kSystemPointerSizeLog2)); + Sub(src, src, kSystemPointerSize); + } + + int src_direction = (mode == kDstLessThanSrc) ? 1 : -1; + int dst_direction = (mode == kSrcLessThanDst) ? -1 : 1; + UseScratchRegisterScope scope(this); VRegister temp0 = scope.AcquireD(); VRegister temp1 = scope.AcquireD(); @@ -1314,23 +1321,30 @@ void TurboAssembler::CopyDoubleWords(Register dst, Register src, Register count, Label pairs, loop, done; Tbz(count, 0, &pairs); - Ldr(temp0, MemOperand(src, direction * kSystemPointerSize, PostIndex)); + Ldr(temp0, MemOperand(src, src_direction * kSystemPointerSize, PostIndex)); Sub(count, count, 1); - Str(temp0, MemOperand(dst, direction * kSystemPointerSize, PostIndex)); + Str(temp0, MemOperand(dst, dst_direction * kSystemPointerSize, PostIndex)); Bind(&pairs); if (mode == kSrcLessThanDst) { // Adjust pointers for post-index ldp/stp with negative offset: Sub(dst, dst, kSystemPointerSize); Sub(src, src, kSystemPointerSize); + } else if (mode == kDstLessThanSrcAndReverse) { + Sub(src, src, kSystemPointerSize); } Bind(&loop); Cbz(count, &done); Ldp(temp0, temp1, - MemOperand(src, 2 * direction * kSystemPointerSize, PostIndex)); + MemOperand(src, 2 * src_direction * kSystemPointerSize, PostIndex)); Sub(count, count, 2); - Stp(temp0, temp1, - MemOperand(dst, 2 * direction * kSystemPointerSize, PostIndex)); + if (mode == kDstLessThanSrcAndReverse) { + Stp(temp1, temp0, + MemOperand(dst, 2 * dst_direction * kSystemPointerSize, PostIndex)); + } else { + Stp(temp0, temp1, + MemOperand(dst, 2 * dst_direction * kSystemPointerSize, PostIndex)); + } B(&loop); // TODO(all): large copies may benefit from using temporary Q registers @@ -2093,7 +2107,7 @@ void MacroAssembler::CallDebugOnFunctionCall(Register fun, Register new_target, Register expected_parameter_count, Register actual_parameter_count) { // Load receiver to pass it later to DebugOnFunctionCall hook. - Ldr(x4, MemOperand(sp, actual_parameter_count, LSL, kSystemPointerSizeLog2)); + Peek(x4, ReceiverOperand(actual_parameter_count)); FrameScope frame(this, has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); if (!new_target.is_valid()) new_target = padreg; @@ -2165,6 +2179,14 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, Bind(&done); } +Operand MacroAssembler::ReceiverOperand(Register arg_count) { +#ifdef V8_REVERSE_JSARGS + return Operand(0); +#else + return Operand(arg_count, LSL, kXRegSizeLog2); +#endif +} + void MacroAssembler::InvokeFunctionWithNewTarget( Register function, Register new_target, Register actual_parameter_count, InvokeFlag flag) { @@ -2297,7 +2319,7 @@ void TurboAssembler::EnterFrame(StackFrame::Type type) { // sp[2] : fp // sp[1] : type // sp[0] : for alignment - } else if (type == StackFrame::WASM_COMPILED || + } else if (type == StackFrame::WASM || type == StackFrame::WASM_COMPILE_LAZY || type == StackFrame::WASM_EXIT) { Register type_reg = temps.AcquireX(); @@ -2966,7 +2988,9 @@ void TurboAssembler::PrintfNoPreserve(const char* format, // Copies of the printf vararg registers that we can pop from. CPURegList pcs_varargs = kPCSVarargs; +#ifndef V8_OS_WIN CPURegList pcs_varargs_fp = kPCSVarargsFP; +#endif // Place the arguments. There are lots of clever tricks and optimizations we // could use here, but Printf is a debug tool so instead we just try to keep @@ -2981,7 +3005,14 @@ void TurboAssembler::PrintfNoPreserve(const char* format, if (args[i].Is32Bits()) pcs[i] = pcs[i].W(); } else if (args[i].IsVRegister()) { // In C, floats are always cast to doubles for varargs calls. +#ifdef V8_OS_WIN + // In case of variadic functions SIMD and Floating-point registers + // aren't used. The general x0-x7 should be used instead. + // https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions + pcs[i] = pcs_varargs.PopLowestIndex().X(); +#else pcs[i] = pcs_varargs_fp.PopLowestIndex().D(); +#endif } else { DCHECK(args[i].IsNone()); arg_count = i; @@ -3012,6 +3043,22 @@ void TurboAssembler::PrintfNoPreserve(const char* format, // Do a second pass to move values into their final positions and perform any // conversions that may be required. for (int i = 0; i < arg_count; i++) { +#ifdef V8_OS_WIN + if (args[i].IsVRegister()) { + if (pcs[i].SizeInBytes() != args[i].SizeInBytes()) { + // If the argument is half- or single-precision + // converts to double-precision before that is + // moved into the one of X scratch register. + VRegister temp0 = temps.AcquireD(); + Fcvt(temp0.VReg(), args[i].VReg()); + Fmov(pcs[i].Reg(), temp0); + } else { + Fmov(pcs[i].Reg(), args[i].VReg()); + } + } else { + Mov(pcs[i].Reg(), args[i].Reg(), kDiscardForSameWReg); + } +#else DCHECK(pcs[i].type() == args[i].type()); if (pcs[i].IsRegister()) { Mov(pcs[i].Reg(), args[i].Reg(), kDiscardForSameWReg); @@ -3023,6 +3070,7 @@ void TurboAssembler::PrintfNoPreserve(const char* format, Fcvt(pcs[i].VReg(), args[i].VReg()); } } +#endif } // Load the format string into x0, as per the procedure-call standard. diff --git a/deps/v8/src/codegen/arm64/macro-assembler-arm64.h b/deps/v8/src/codegen/arm64/macro-assembler-arm64.h index 7b1fb69e954231..109e73c3c229d4 100644 --- a/deps/v8/src/codegen/arm64/macro-assembler-arm64.h +++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64.h @@ -703,7 +703,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { void CopySlots(Register dst, Register src, Register slot_count); // Copy count double words from the address in register src to the address - // in register dst. There are two modes for this function: + // in register dst. There are three modes for this function: // 1) Address dst must be less than src, or the gap between them must be // greater than or equal to count double words, otherwise the result is // unpredictable. This is the default mode. @@ -711,10 +711,15 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { // greater than or equal to count double words, otherwise the result is // undpredictable. In this mode, src and dst specify the last (highest) // address of the regions to copy from and to. + // 3) The same as mode 1, but the words are copied in the reversed order. // The case where src == dst is not supported. // The function may corrupt its register arguments. The registers must not // alias each other. - enum CopyDoubleWordsMode { kDstLessThanSrc, kSrcLessThanDst }; + enum CopyDoubleWordsMode { + kDstLessThanSrc, + kSrcLessThanDst, + kDstLessThanSrcAndReverse + }; void CopyDoubleWords(Register dst, Register src, Register count, CopyDoubleWordsMode mode = kDstLessThanSrc); @@ -1762,6 +1767,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { DecodeField(reg, reg); } + // TODO(victorgomes): inline this function once we remove V8_REVERSE_JSARGS + // flag. + Operand ReceiverOperand(const Register arg_count); + // ---- SMI and Number Utilities ---- inline void SmiTag(Register dst, Register src); diff --git a/deps/v8/src/codegen/arm64/register-arm64.h b/deps/v8/src/codegen/arm64/register-arm64.h index 9571aa5ab57155..c98b0f6162f9a2 100644 --- a/deps/v8/src/codegen/arm64/register-arm64.h +++ b/deps/v8/src/codegen/arm64/register-arm64.h @@ -470,8 +470,9 @@ ALIAS_REGISTER(Register, padreg, x31); // Keeps the 0 double value. ALIAS_REGISTER(VRegister, fp_zero, d15); // MacroAssembler fixed V Registers. -ALIAS_REGISTER(VRegister, fp_fixed1, d28); -ALIAS_REGISTER(VRegister, fp_fixed2, d29); +// d29 is not part of ALLOCATABLE_DOUBLE_REGISTERS, so use 27 and 28. +ALIAS_REGISTER(VRegister, fp_fixed1, d27); +ALIAS_REGISTER(VRegister, fp_fixed2, d28); // MacroAssembler scratch V registers. ALIAS_REGISTER(VRegister, fp_scratch, d30); @@ -522,8 +523,6 @@ using Simd128Register = VRegister; // Lists of registers. class V8_EXPORT_PRIVATE CPURegList { public: - CPURegList() = default; - template explicit CPURegList(CPURegister reg0, CPURegisters... regs) : list_(CPURegister::ListOf(reg0, regs...)), @@ -696,6 +695,8 @@ constexpr Register kRuntimeCallArgvRegister = x11; constexpr Register kWasmInstanceRegister = x7; constexpr Register kWasmCompileLazyFuncIndexRegister = x8; +constexpr DoubleRegister kFPReturnRegister0 = d0; + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/codegen/assembler.cc b/deps/v8/src/codegen/assembler.cc index 4bda1260a90e1d..3b27bf5db9eb52 100644 --- a/deps/v8/src/codegen/assembler.cc +++ b/deps/v8/src/codegen/assembler.cc @@ -41,7 +41,6 @@ #include "src/execution/isolate.h" #include "src/heap/heap-inl.h" // For MemoryAllocator. TODO(jkummerow): Drop. #include "src/snapshot/embedded/embedded-data.h" -#include "src/snapshot/serializer-common.h" #include "src/snapshot/snapshot.h" #include "src/utils/ostreams.h" #include "src/utils/vector.h" diff --git a/deps/v8/src/codegen/code-stub-assembler.cc b/deps/v8/src/codegen/code-stub-assembler.cc index 0464faea3b7da9..901ce0c7b49410 100644 --- a/deps/v8/src/codegen/code-stub-assembler.cc +++ b/deps/v8/src/codegen/code-stub-assembler.cc @@ -12,13 +12,15 @@ #include "src/execution/frames-inl.h" #include "src/execution/frames.h" #include "src/execution/protectors.h" -#include "src/heap/heap-inl.h" // For Page/MemoryChunk. TODO(jkummerow): Drop. +#include "src/heap/heap-inl.h" // For MemoryChunk. TODO(jkummerow): Drop. +#include "src/heap/memory-chunk.h" #include "src/logging/counters.h" #include "src/objects/api-callbacks.h" #include "src/objects/cell.h" #include "src/objects/descriptor-array.h" #include "src/objects/function-kind.h" #include "src/objects/heap-number.h" +#include "src/objects/js-aggregate-error.h" #include "src/objects/js-generator.h" #include "src/objects/oddball.h" #include "src/objects/ordered-hash-table-inl.h" @@ -144,164 +146,6 @@ TNode CodeStubAssembler::IntPtrToParameter( return value; } -void CodeStubAssembler::CollectCallableFeedback( - TNode maybe_target, TNode context, - TNode feedback_vector, TNode slot_id, - CallableFeedbackMode mode) { - Label extra_checks(this, Label::kDeferred), done(this); - - // Check if we have monomorphic {target} feedback already. - TNode feedback = - LoadFeedbackVectorSlot(feedback_vector, slot_id); - Comment("check if monomorphic"); - TNode is_monomorphic = IsWeakReferenceToObject(feedback, maybe_target); - GotoIf(is_monomorphic, &done); - - // Check if it is a megamorphic {target}. - Comment("check if megamorphic"); - TNode is_megamorphic = TaggedEqual( - feedback, HeapConstant(FeedbackVector::MegamorphicSentinel(isolate()))); - Branch(is_megamorphic, &done, &extra_checks); - - BIND(&extra_checks); - { - Label initialize(this), mark_megamorphic(this); - - Comment("check if weak reference"); - TNode is_uninitialized = TaggedEqual( - feedback, - HeapConstant(FeedbackVector::UninitializedSentinel(isolate()))); - GotoIf(is_uninitialized, &initialize); - CSA_ASSERT(this, IsWeakOrCleared(feedback)); - - // If the weak reference is cleared, we have a new chance to become - // monomorphic. - Comment("check if weak reference is cleared"); - GotoIf(IsCleared(feedback), &initialize); - GotoIf(TaggedIsSmi(maybe_target), &mark_megamorphic); - - if (mode == CallableFeedbackMode::kDontCollectFeedbackCell) { - Goto(&mark_megamorphic); - } else { - Label try_transition_to_feedback_cell(this); - - // Check if {target} is a JSFunction. - Comment("check if target is a JSFunction"); - TNode target = CAST(maybe_target); - GotoIfNot(IsJSFunction(target), &mark_megamorphic); - - // Check if {target}s feedback vector cell matches the {feedback_value}. - TNode feedback_value = GetHeapObjectAssumeWeak(feedback); - TNode target_feedback_cell = - LoadObjectField(target, JSFunction::kFeedbackCellOffset); - Branch(TaggedEqual(feedback_value, target_feedback_cell), &done, - &try_transition_to_feedback_cell); - - BIND(&try_transition_to_feedback_cell); - { - // Check if {target} and {feedback_value} are both JSFunctions with - // the same feedback vector cell, and that those functions were - // actually compiled already. - GotoIfNot(IsJSFunction(feedback_value), &mark_megamorphic); - TNode feedback_cell = CAST( - LoadObjectField(feedback_value, JSFunction::kFeedbackCellOffset)); - GotoIfNot(TaggedEqual(feedback_cell, target_feedback_cell), - &mark_megamorphic); - GotoIfNot(IsFeedbackCell(feedback_cell), &mark_megamorphic); - - // Record the feedback vector cell. - Comment("transition to polymorphic"); - StoreWeakReferenceInFeedbackVector(feedback_vector, slot_id, - feedback_cell); - ReportFeedbackUpdate(feedback_vector, slot_id, - "Call:FeedbackVectorCell"); - Goto(&done); - } - } - - BIND(&initialize); - { - Comment("check if function in same native context"); - GotoIf(TaggedIsSmi(maybe_target), &mark_megamorphic); - TNode target = CAST(maybe_target); - // Check if the {target} is a JSFunction or JSBoundFunction - // in the current native context. - TVARIABLE(HeapObject, var_current, target); - Label loop(this, &var_current), done_loop(this); - Goto(&loop); - BIND(&loop); - { - Label if_boundfunction(this), if_function(this); - TNode current = var_current.value(); - TNode current_instance_type = LoadInstanceType(current); - GotoIf(InstanceTypeEqual(current_instance_type, JS_BOUND_FUNCTION_TYPE), - &if_boundfunction); - Branch(InstanceTypeEqual(current_instance_type, JS_FUNCTION_TYPE), - &if_function, &mark_megamorphic); - - BIND(&if_function); - { - // Check that the JSFunction {current} is in the current native - // context. - TNode current_context = - CAST(LoadObjectField(current, JSFunction::kContextOffset)); - TNode current_native_context = - LoadNativeContext(current_context); - Branch( - TaggedEqual(LoadNativeContext(context), current_native_context), - &done_loop, &mark_megamorphic); - } - BIND(&if_boundfunction); - { - // Continue with the [[BoundTargetFunction]] of {target}. - var_current = LoadObjectField( - current, JSBoundFunction::kBoundTargetFunctionOffset); - Goto(&loop); - } - } - BIND(&done_loop); - StoreWeakReferenceInFeedbackVector(feedback_vector, slot_id, target); - ReportFeedbackUpdate(feedback_vector, slot_id, "Call:Initialize"); - Goto(&done); - } - - BIND(&mark_megamorphic); - { - // MegamorphicSentinel is an immortal immovable object so - // write-barrier is not needed. - Comment("transition to megamorphic"); - DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kmegamorphic_symbol)); - StoreFeedbackVectorSlot( - feedback_vector, slot_id, - HeapConstant(FeedbackVector::MegamorphicSentinel(isolate())), - SKIP_WRITE_BARRIER); - ReportFeedbackUpdate(feedback_vector, slot_id, - "Call:TransitionMegamorphic"); - Goto(&done); - } - } - - BIND(&done); -} - -void CodeStubAssembler::CollectCallFeedback( - TNode maybe_target, TNode context, - TNode maybe_feedback_vector, TNode slot_id) { - Label feedback_done(this); - // If feedback_vector is not valid, then nothing to do. - GotoIf(IsUndefined(maybe_feedback_vector), &feedback_done); - - // Increment the call count. - TNode feedback_vector = CAST(maybe_feedback_vector); - IncrementCallCount(feedback_vector, slot_id); - - // Collect the callable {target} feedback. - CollectCallableFeedback(maybe_target, context, feedback_vector, slot_id, - CallableFeedbackMode::kCollectFeedbackCell); - Goto(&feedback_done); - - BIND(&feedback_done); -} void CodeStubAssembler::IncrementCallCount( TNode feedback_vector, TNode slot_id) { @@ -373,7 +217,7 @@ TNode CodeStubAssembler::SelectSmiConstant(SloppyTNode condition, SmiConstant(false_value)); } -TNode CodeStubAssembler::NoContextConstant() { +TNode CodeStubAssembler::NoContextConstant() { return SmiConstant(Context::kNoContext); } @@ -762,8 +606,8 @@ TNode CodeStubAssembler::IsValidSmiIndex(TNode smi) { TNode CodeStubAssembler::TaggedIndexToIntPtr( TNode value) { - return Signed(WordSar(BitcastTaggedToWordForTagAndSmiBits(value), - IntPtrConstant(kSmiTagSize))); + return Signed(WordSarShiftOutZeros(BitcastTaggedToWordForTagAndSmiBits(value), + IntPtrConstant(kSmiTagSize))); } TNode CodeStubAssembler::IntPtrToTaggedIndex( @@ -858,16 +702,17 @@ TNode CodeStubAssembler::SmiUntag(SloppyTNode value) { if (ToIntPtrConstant(value, &constant_value)) { return IntPtrConstant(constant_value >> (kSmiShiftSize + kSmiTagSize)); } + TNode raw_bits = BitcastTaggedToWordForTagAndSmiBits(value); if (COMPRESS_POINTERS_BOOL) { - return ChangeInt32ToIntPtr(SmiToInt32(value)); + // Clear the upper half using sign-extension. + raw_bits = ChangeInt32ToIntPtr(TruncateIntPtrToInt32(raw_bits)); } - return Signed(WordSar(BitcastTaggedToWordForTagAndSmiBits(value), - SmiShiftBitsConstant())); + return Signed(WordSarShiftOutZeros(raw_bits, SmiShiftBitsConstant())); } TNode CodeStubAssembler::SmiToInt32(SloppyTNode value) { if (COMPRESS_POINTERS_BOOL) { - return Signed(Word32Sar( + return Signed(Word32SarShiftOutZeros( TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(value)), SmiShiftBitsConstant32())); } @@ -2226,9 +2071,10 @@ TNode CodeStubAssembler::LoadPropertyArrayLength( TNode CodeStubAssembler::LoadJSTypedArrayDataPtr( TNode typed_array) { - // Data pointer = external_pointer + static_cast(base_pointer). - TNode external_pointer = LoadObjectField( - typed_array, JSTypedArray::kExternalPointerOffset); + // Data pointer = DecodeExternalPointer(external_pointer) + + // static_cast(base_pointer). + TNode external_pointer = + DecodeExternalPointer(LoadJSTypedArrayExternalPointer(typed_array)); TNode base_pointer; if (COMPRESS_POINTERS_BOOL) { @@ -3687,6 +3533,17 @@ void CodeStubAssembler::StoreFieldsNoWriteBarrier(TNode start_address, kTaggedSize, IndexAdvanceMode::kPost); } +void CodeStubAssembler::MakeFixedArrayCOW(TNode array) { + CSA_ASSERT(this, IsFixedArrayMap(LoadMap(array))); + Label done(this); + // The empty fixed array is not modifiable anyway. And we shouldn't change its + // Map. + GotoIf(TaggedEqual(array, EmptyFixedArrayConstant()), &done); + StoreMap(array, FixedCOWArrayMapConstant()); + Goto(&done); + BIND(&done); +} + TNode CodeStubAssembler::IsValidFastJSArrayCapacity( TNode capacity) { return UintPtrLessThanOrEqual(capacity, @@ -4900,6 +4757,12 @@ void CodeStubAssembler::CopyFixedArrayElements( Comment("] CopyFixedArrayElements"); } +TNode CodeStubAssembler::HeapObjectToJSAggregateError( + TNode heap_object, Label* fail) { + GotoIfNot(IsJSAggregateError(heap_object), fail); + return UncheckedCast(heap_object); +} + TNode CodeStubAssembler::HeapObjectToFixedArray( TNode base, Label* cast_fail) { Label fixed_array(this); @@ -5235,6 +5098,22 @@ void CodeStubAssembler::TaggedToWord32OrBigIntImpl( } } +TNode CodeStubAssembler::TruncateNumberToWord32(TNode number) { + TVARIABLE(Int32T, var_result); + Label done(this), if_heapnumber(this); + GotoIfNot(TaggedIsSmi(number), &if_heapnumber); + var_result = SmiToInt32(CAST(number)); + Goto(&done); + + BIND(&if_heapnumber); + TNode value = LoadHeapNumberValue(CAST(number)); + var_result = Signed(TruncateFloat64ToWord32(value)); + Goto(&done); + + BIND(&done); + return var_result.value(); +} + TNode CodeStubAssembler::TruncateHeapNumberValueToWord32( TNode object) { TNode value = LoadHeapNumberValue(object); @@ -5248,6 +5127,38 @@ void CodeStubAssembler::TryHeapNumberToSmi(TNode number, TryFloat64ToSmi(value, var_result_smi, if_smi); } +void CodeStubAssembler::TryFloat32ToSmi(TNode value, + TVariable* var_result_smi, + Label* if_smi) { + TNode ivalue = TruncateFloat32ToInt32(value); + TNode fvalue = RoundInt32ToFloat32(ivalue); + + Label if_int32(this), if_heap_number(this); + + GotoIfNot(Float32Equal(value, fvalue), &if_heap_number); + GotoIfNot(Word32Equal(ivalue, Int32Constant(0)), &if_int32); + Branch(Int32LessThan(UncheckedCast(BitcastFloat32ToInt32(value)), + Int32Constant(0)), + &if_heap_number, &if_int32); + + TVARIABLE(Number, var_result); + BIND(&if_int32); + { + if (SmiValuesAre32Bits()) { + *var_result_smi = SmiTag(ChangeInt32ToIntPtr(ivalue)); + } else { + DCHECK(SmiValuesAre31Bits()); + TNode> pair = Int32AddWithOverflow(ivalue, ivalue); + TNode overflow = Projection<1>(pair); + GotoIf(overflow, &if_heap_number); + *var_result_smi = + BitcastWordToTaggedSigned(ChangeInt32ToIntPtr(Projection<0>(pair))); + } + Goto(if_smi); + } + BIND(&if_heap_number); +} + void CodeStubAssembler::TryFloat64ToSmi(TNode value, TVariable* var_result_smi, Label* if_smi) { @@ -5280,6 +5191,24 @@ void CodeStubAssembler::TryFloat64ToSmi(TNode value, BIND(&if_heap_number); } +TNode CodeStubAssembler::ChangeFloat32ToTagged(TNode value) { + Label if_smi(this), done(this); + TVARIABLE(Smi, var_smi_result); + TVARIABLE(Number, var_result); + TryFloat32ToSmi(value, &var_smi_result, &if_smi); + + var_result = AllocateHeapNumberWithValue(ChangeFloat32ToFloat64(value)); + Goto(&done); + + BIND(&if_smi); + { + var_result = var_smi_result.value(); + Goto(&done); + } + BIND(&done); + return var_result.value(); +} + TNode CodeStubAssembler::ChangeFloat64ToTagged( SloppyTNode value) { Label if_smi(this), done(this); @@ -5464,6 +5393,42 @@ TNode CodeStubAssembler::ChangeNumberToFloat64(TNode value) { return result.value(); } +TNode CodeStubAssembler::ChangeTaggedNonSmiToInt32( + TNode context, TNode input) { + return Select( + IsHeapNumber(input), + [=] { + return Signed(TruncateFloat64ToWord32(LoadHeapNumberValue(input))); + }, + [=] { + return TruncateNumberToWord32( + CAST(CallBuiltin(Builtins::kNonNumberToNumber, context, input))); + }); +} + +TNode CodeStubAssembler::ChangeTaggedToFloat64(TNode context, + TNode input) { + TVARIABLE(Float64T, var_result); + Label end(this), not_smi(this); + + GotoIfNot(TaggedIsSmi(input), ¬_smi); + var_result = SmiToFloat64(CAST(input)); + Goto(&end); + + BIND(¬_smi); + var_result = Select( + IsHeapNumber(CAST(input)), + [=] { return LoadHeapNumberValue(CAST(input)); }, + [=] { + return ChangeNumberToFloat64( + CAST(CallBuiltin(Builtins::kNonNumberToNumber, context, input))); + }); + Goto(&end); + + BIND(&end); + return var_result.value(); +} + TNode CodeStubAssembler::TimesSystemPointerSize( SloppyTNode value) { return WordShl(value, kSystemPointerSizeLog2); @@ -5759,12 +5724,10 @@ TNode CodeStubAssembler::IsTypedArraySpeciesProtectorCellInvalid() { return TaggedEqual(cell_value, invalid); } -TNode CodeStubAssembler::IsRegExpSpeciesProtectorCellInvalid( - TNode native_context) { - TNode cell = CAST(LoadContextElement( - native_context, Context::REGEXP_SPECIES_PROTECTOR_INDEX)); - TNode cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); +TNode CodeStubAssembler::IsRegExpSpeciesProtectorCellInvalid() { TNode invalid = SmiConstant(Protectors::kProtectorInvalid); + TNode cell = RegExpSpeciesProtectorConstant(); + TNode cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); return TaggedEqual(cell_value, invalid); } @@ -5988,6 +5951,16 @@ TNode CodeStubAssembler::IsJSObject(SloppyTNode object) { return IsJSObjectMap(LoadMap(object)); } +TNode CodeStubAssembler::IsJSFinalizationRegistryMap(TNode map) { + return InstanceTypeEqual(LoadMapInstanceType(map), + JS_FINALIZATION_REGISTRY_TYPE); +} + +TNode CodeStubAssembler::IsJSFinalizationRegistry( + TNode object) { + return IsJSFinalizationRegistryMap(LoadMap(object)); +} + TNode CodeStubAssembler::IsJSPromiseMap(SloppyTNode map) { CSA_ASSERT(this, IsMap(map)); return InstanceTypeEqual(LoadMapInstanceType(map), JS_PROMISE_TYPE); @@ -6029,6 +6002,10 @@ TNode CodeStubAssembler::IsJSPrimitiveWrapperMap(SloppyTNode map) { return IsJSPrimitiveWrapperInstanceType(LoadMapInstanceType(map)); } +TNode CodeStubAssembler::IsJSAggregateError(TNode object) { + return HasInstanceType(object, JS_AGGREGATE_ERROR_TYPE); +} + TNode CodeStubAssembler::IsJSArrayInstanceType( SloppyTNode instance_type) { return InstanceTypeEqual(instance_type, JS_ARRAY_TYPE); @@ -6746,12 +6723,13 @@ TNode ToDirectStringAssembler::TryToSequential( { STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); - TNode result = BitcastTaggedToWord(var_string_.value()); + TNode result = + ReinterpretCast(BitcastTaggedToWord(var_string_.value())); if (ptr_kind == PTR_TO_DATA) { - result = IntPtrAdd(result, IntPtrConstant(SeqOneByteString::kHeaderSize - + result = RawPtrAdd(result, IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); } - var_result = ReinterpretCast(result); + var_result = result; Goto(&out); } @@ -6761,13 +6739,13 @@ TNode ToDirectStringAssembler::TryToSequential( if_bailout); TNode string = var_string_.value(); - TNode result = - LoadObjectField(string, ExternalString::kResourceDataOffset); + TNode result = + DecodeExternalPointer(LoadExternalStringResourceData(CAST(string))); if (ptr_kind == PTR_TO_STRING) { - result = IntPtrSub(result, IntPtrConstant(SeqOneByteString::kHeaderSize - + result = RawPtrSub(result, IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); } - var_result = ReinterpretCast(result); + var_result = result; Goto(&out); } @@ -6889,8 +6867,8 @@ TNode CodeStubAssembler::NumberToString(TNode input) { BIND(&runtime); { // No cache entry, go to the runtime. - result = - CAST(CallRuntime(Runtime::kNumberToString, NoContextConstant(), input)); + result = CAST( + CallRuntime(Runtime::kNumberToStringSlow, NoContextConstant(), input)); Goto(&done); } BIND(&done); @@ -7327,7 +7305,7 @@ TNode CodeStubAssembler::DecodeWord32(SloppyTNode word32, } TNode CodeStubAssembler::DecodeWord(SloppyTNode word, - uint32_t shift, uint32_t mask) { + uint32_t shift, uintptr_t mask) { DCHECK_EQ((mask >> shift) << shift, mask); return Unsigned(WordAnd(WordShr(word, static_cast(shift)), IntPtrConstant(mask >> shift))); @@ -7335,25 +7313,39 @@ TNode CodeStubAssembler::DecodeWord(SloppyTNode word, TNode CodeStubAssembler::UpdateWord32(TNode word, TNode value, - uint32_t shift, uint32_t mask) { + uint32_t shift, uint32_t mask, + bool starts_as_zero) { DCHECK_EQ((mask >> shift) << shift, mask); // Ensure the {value} fits fully in the mask. CSA_ASSERT(this, Uint32LessThanOrEqual(value, Uint32Constant(mask >> shift))); TNode encoded_value = Word32Shl(value, Int32Constant(shift)); - TNode inverted_mask = Int32Constant(~mask); - return Word32Or(Word32And(word, inverted_mask), encoded_value); + TNode masked_word; + if (starts_as_zero) { + CSA_ASSERT(this, Word32Equal(Word32And(word, Int32Constant(~mask)), word)); + masked_word = word; + } else { + masked_word = Word32And(word, Int32Constant(~mask)); + } + return Word32Or(masked_word, encoded_value); } TNode CodeStubAssembler::UpdateWord(TNode word, TNode value, - uint32_t shift, uint32_t mask) { + uint32_t shift, uintptr_t mask, + bool starts_as_zero) { DCHECK_EQ((mask >> shift) << shift, mask); // Ensure the {value} fits fully in the mask. CSA_ASSERT(this, UintPtrLessThanOrEqual(value, UintPtrConstant(mask >> shift))); TNode encoded_value = WordShl(value, static_cast(shift)); - TNode inverted_mask = IntPtrConstant(~static_cast(mask)); - return WordOr(WordAnd(word, inverted_mask), encoded_value); + TNode masked_word; + if (starts_as_zero) { + CSA_ASSERT(this, WordEqual(WordAnd(word, UintPtrConstant(~mask)), word)); + masked_word = word; + } else { + masked_word = WordAnd(word, UintPtrConstant(~mask)); + } + return WordOr(masked_word, encoded_value); } void CodeStubAssembler::SetCounter(StatsCounter* counter, int value) { @@ -12487,15 +12479,9 @@ void CodeStubAssembler::ThrowIfArrayBufferViewBufferIsDetached( ThrowIfArrayBufferIsDetached(context, buffer, method_name); } -TNode CodeStubAssembler::LoadJSArrayBufferBitField( +TNode CodeStubAssembler::LoadJSArrayBufferBackingStorePtr( TNode array_buffer) { - return LoadObjectField(array_buffer, JSArrayBuffer::kBitFieldOffset); -} - -TNode CodeStubAssembler::LoadJSArrayBufferBackingStore( - TNode array_buffer) { - return LoadObjectField(array_buffer, - JSArrayBuffer::kBackingStoreOffset); + return DecodeExternalPointer(LoadJSArrayBufferBackingStore(array_buffer)); } TNode CodeStubAssembler::LoadJSArrayBufferViewBuffer( @@ -12672,6 +12658,18 @@ TNode CodeStubAssembler::IsFastElementsKind( Int32Constant(LAST_FAST_ELEMENTS_KIND)); } +TNode CodeStubAssembler::IsFastOrNonExtensibleOrSealedElementsKind( + TNode elements_kind) { + STATIC_ASSERT(FIRST_ELEMENTS_KIND == FIRST_FAST_ELEMENTS_KIND); + STATIC_ASSERT(LAST_FAST_ELEMENTS_KIND + 1 == PACKED_NONEXTENSIBLE_ELEMENTS); + STATIC_ASSERT(PACKED_NONEXTENSIBLE_ELEMENTS + 1 == + HOLEY_NONEXTENSIBLE_ELEMENTS); + STATIC_ASSERT(HOLEY_NONEXTENSIBLE_ELEMENTS + 1 == PACKED_SEALED_ELEMENTS); + STATIC_ASSERT(PACKED_SEALED_ELEMENTS + 1 == HOLEY_SEALED_ELEMENTS); + return Uint32LessThanOrEqual(elements_kind, + Int32Constant(HOLEY_SEALED_ELEMENTS)); +} + TNode CodeStubAssembler::IsDoubleElementsKind( TNode elements_kind) { STATIC_ASSERT(FIRST_ELEMENTS_KIND == FIRST_FAST_ELEMENTS_KIND); @@ -13240,6 +13238,21 @@ TNode CodeStubAssembler::TaggedToDirectString(TNode value, return CAST(value); } +void CodeStubAssembler::RemoveFinalizationRegistryCellFromUnregisterTokenMap( + TNode finalization_registry, + TNode weak_cell) { + const TNode remove_cell = ExternalConstant( + ExternalReference:: + js_finalization_registry_remove_cell_from_unregister_token_map()); + const TNode isolate_ptr = + ExternalConstant(ExternalReference::isolate_address(isolate())); + + CallCFunction(remove_cell, MachineType::Pointer(), + std::make_pair(MachineType::Pointer(), isolate_ptr), + std::make_pair(MachineType::AnyTagged(), finalization_registry), + std::make_pair(MachineType::AnyTagged(), weak_cell)); +} + PrototypeCheckAssembler::PrototypeCheckAssembler( compiler::CodeAssemblerState* state, Flags flags, TNode native_context, TNode initial_prototype_map, diff --git a/deps/v8/src/codegen/code-stub-assembler.h b/deps/v8/src/codegen/code-stub-assembler.h index 618481ff47a4eb..b01729c73db8d4 100644 --- a/deps/v8/src/codegen/code-stub-assembler.h +++ b/deps/v8/src/codegen/code-stub-assembler.h @@ -9,6 +9,7 @@ #include "src/base/macros.h" #include "src/codegen/bailout-reason.h" +#include "src/common/external-pointer.h" #include "src/common/globals.h" #include "src/common/message-template.h" #include "src/compiler/code-assembler.h" @@ -20,7 +21,6 @@ #include "src/objects/smi.h" #include "src/objects/tagged-index.h" #include "src/roots/roots.h" - #include "torque-generated/exported-macros-assembler-tq.h" namespace v8 { @@ -34,28 +34,79 @@ class StubCache; enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol }; -#define HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V) \ - V(ArrayIteratorProtector, array_iterator_protector, ArrayIteratorProtector) \ - V(ArraySpeciesProtector, array_species_protector, ArraySpeciesProtector) \ - V(MapIteratorProtector, map_iterator_protector, MapIteratorProtector) \ - V(NoElementsProtector, no_elements_protector, NoElementsProtector) \ - V(NumberStringCache, number_string_cache, NumberStringCache) \ - V(PromiseResolveProtector, promise_resolve_protector, \ - PromiseResolveProtector) \ - V(PromiseSpeciesProtector, promise_species_protector, \ - PromiseSpeciesProtector) \ - V(PromiseThenProtector, promise_then_protector, PromiseThenProtector) \ - V(SetIteratorProtector, set_iterator_protector, SetIteratorProtector) \ - V(SingleCharacterStringCache, single_character_string_cache, \ - SingleCharacterStringCache) \ - V(StringIteratorProtector, string_iterator_protector, \ - StringIteratorProtector) \ - V(TypedArraySpeciesProtector, typed_array_species_protector, \ +#define HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V) \ + V(ArrayIteratorProtector, array_iterator_protector, ArrayIteratorProtector) \ + V(ArraySpeciesProtector, array_species_protector, ArraySpeciesProtector) \ + V(AsyncFunctionAwaitRejectSharedFun, async_function_await_reject_shared_fun, \ + AsyncFunctionAwaitRejectSharedFun) \ + V(AsyncFunctionAwaitResolveSharedFun, \ + async_function_await_resolve_shared_fun, \ + AsyncFunctionAwaitResolveSharedFun) \ + V(AsyncGeneratorAwaitRejectSharedFun, \ + async_generator_await_reject_shared_fun, \ + AsyncGeneratorAwaitRejectSharedFun) \ + V(AsyncGeneratorAwaitResolveSharedFun, \ + async_generator_await_resolve_shared_fun, \ + AsyncGeneratorAwaitResolveSharedFun) \ + V(AsyncGeneratorReturnClosedRejectSharedFun, \ + async_generator_return_closed_reject_shared_fun, \ + AsyncGeneratorReturnClosedRejectSharedFun) \ + V(AsyncGeneratorReturnClosedResolveSharedFun, \ + async_generator_return_closed_resolve_shared_fun, \ + AsyncGeneratorReturnClosedResolveSharedFun) \ + V(AsyncGeneratorReturnResolveSharedFun, \ + async_generator_return_resolve_shared_fun, \ + AsyncGeneratorReturnResolveSharedFun) \ + V(AsyncGeneratorYieldResolveSharedFun, \ + async_generator_yield_resolve_shared_fun, \ + AsyncGeneratorYieldResolveSharedFun) \ + V(AsyncIteratorValueUnwrapSharedFun, async_iterator_value_unwrap_shared_fun, \ + AsyncIteratorValueUnwrapSharedFun) \ + V(MapIteratorProtector, map_iterator_protector, MapIteratorProtector) \ + V(NoElementsProtector, no_elements_protector, NoElementsProtector) \ + V(NumberStringCache, number_string_cache, NumberStringCache) \ + V(PromiseAllResolveElementSharedFun, promise_all_resolve_element_shared_fun, \ + PromiseAllResolveElementSharedFun) \ + V(PromiseAllSettledRejectElementSharedFun, \ + promise_all_settled_reject_element_shared_fun, \ + PromiseAllSettledRejectElementSharedFun) \ + V(PromiseAllSettledResolveElementSharedFun, \ + promise_all_settled_resolve_element_shared_fun, \ + PromiseAllSettledResolveElementSharedFun) \ + V(PromiseAnyRejectElementSharedFun, promise_any_reject_element_shared_fun, \ + PromiseAnyRejectElementSharedFun) \ + V(PromiseCapabilityDefaultRejectSharedFun, \ + promise_capability_default_reject_shared_fun, \ + PromiseCapabilityDefaultRejectSharedFun) \ + V(PromiseCapabilityDefaultResolveSharedFun, \ + promise_capability_default_resolve_shared_fun, \ + PromiseCapabilityDefaultResolveSharedFun) \ + V(PromiseCatchFinallySharedFun, promise_catch_finally_shared_fun, \ + PromiseCatchFinallySharedFun) \ + V(PromiseGetCapabilitiesExecutorSharedFun, \ + promise_get_capabilities_executor_shared_fun, \ + PromiseGetCapabilitiesExecutorSharedFun) \ + V(PromiseResolveProtector, promise_resolve_protector, \ + PromiseResolveProtector) \ + V(PromiseSpeciesProtector, promise_species_protector, \ + PromiseSpeciesProtector) \ + V(PromiseThenFinallySharedFun, promise_then_finally_shared_fun, \ + PromiseThenFinallySharedFun) \ + V(PromiseThenProtector, promise_then_protector, PromiseThenProtector) \ + V(PromiseThrowerFinallySharedFun, promise_thrower_finally_shared_fun, \ + PromiseThrowerFinallySharedFun) \ + V(PromiseValueThunkFinallySharedFun, promise_value_thunk_finally_shared_fun, \ + PromiseValueThunkFinallySharedFun) \ + V(ProxyRevokeSharedFun, proxy_revoke_shared_fun, ProxyRevokeSharedFun) \ + V(RegExpSpeciesProtector, regexp_species_protector, RegExpSpeciesProtector) \ + V(SetIteratorProtector, set_iterator_protector, SetIteratorProtector) \ + V(SingleCharacterStringCache, single_character_string_cache, \ + SingleCharacterStringCache) \ + V(StringIteratorProtector, string_iterator_protector, \ + StringIteratorProtector) \ + V(TypedArraySpeciesProtector, typed_array_species_protector, \ TypedArraySpeciesProtector) -#define TORQUE_INTERNAL_CLASS_LIST_CSA_ADAPTER(V, NAME, Name, name) \ - V(Name##Map, name##_map, Name##Map) - #define HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(V) \ V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \ V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \ @@ -106,6 +157,7 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol }; V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \ V(match_symbol, match_symbol, MatchSymbol) \ V(megamorphic_symbol, megamorphic_symbol, MegamorphicSymbol) \ + V(message_string, message_string, MessageString) \ V(MetaMap, meta_map, MetaMap) \ V(minus_Infinity_string, minus_Infinity_string, MinusInfinityString) \ V(MinusZeroValue, minus_zero_value, MinusZero) \ @@ -178,8 +230,7 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol }; V(uninitialized_symbol, uninitialized_symbol, UninitializedSymbol) \ V(WeakFixedArrayMap, weak_fixed_array_map, WeakFixedArrayMap) \ V(zero_string, zero_string, ZeroString) \ - TORQUE_INTERNAL_CLASS_LIST_GENERATOR(TORQUE_INTERNAL_CLASS_LIST_CSA_ADAPTER, \ - V) + TORQUE_INTERNAL_MAP_CSA_LIST(V) #define HEAP_IMMOVABLE_OBJECT_LIST(V) \ HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V) \ @@ -430,6 +481,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler return UncheckedCast(value); } + TNode HeapObjectToJSAggregateError( + TNode heap_object, Label* fail); + TNode HeapObjectToJSArray(TNode heap_object, Label* fail) { GotoIfNot(IsJSArray(heap_object), fail); @@ -576,7 +630,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler return Word32BinaryNot(TaggedEqual(a, b)); } - TNode NoContextConstant(); + TNode NoContextConstant(); #define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \ TNode DecodeExternalPointer( + TNode encoded_pointer) { + STATIC_ASSERT(kExternalPointerSize == kSystemPointerSize); + TNode value = ReinterpretCast(encoded_pointer); + if (V8_HEAP_SANDBOX_BOOL) { + value = UncheckedCast( + WordXor(value, UintPtrConstant(kExternalPointerSalt))); + } + return value; + } + + // Convert external pointer value to on-V8-heap representation. + // This should eventually become a call to a non-allocating runtime function. + TNode EncodeExternalPointer(TNode pointer) { + STATIC_ASSERT(kExternalPointerSize == kSystemPointerSize); + TNode encoded_pointer = pointer; + if (V8_HEAP_SANDBOX_BOOL) { + encoded_pointer = UncheckedCast( + WordXor(encoded_pointer, UintPtrConstant(kExternalPointerSalt))); + } + return ReinterpretCast(encoded_pointer); + } + // Load value from current parent frame by given offset in bytes. TNode LoadFromParentFrame(int offset); @@ -1781,6 +1860,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode end_address, TNode value); + // Marks the FixedArray copy-on-write without moving it. + void MakeFixedArrayCOW(TNode array); + TNode AllocateCellWithValue( TNode value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); TNode AllocateSmiCell(int value = 0) { @@ -2047,35 +2129,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler enum class DestroySource { kNo, kYes }; - // Collect the callable |maybe_target| feedback for either a CALL_IC or - // an INSTANCEOF_IC in the |feedback_vector| at |slot_id|. There are - // two modes for feedback collection: - // - // kCollectFeedbackCell - collect JSFunctions, but devolve to the - // FeedbackCell as long as all JSFunctions - // seen share the same one. - // kDontCollectFeedbackCell - collect JSFunctions without devolving - // to the FeedbackCell in case a - // different JSFunction appears. Go directly - // to the Megamorphic sentinel value in this - // case. - enum class CallableFeedbackMode { - kCollectFeedbackCell, - kDontCollectFeedbackCell - }; - void CollectCallableFeedback(TNode maybe_target, - TNode context, - TNode feedback_vector, - TNode slot_id, - CallableFeedbackMode mode); - - // Collect CALL_IC feedback for |maybe_target| function in the - // |feedback_vector| at |slot_id|, and the call counts in - // the |feedback_vector| at |slot_id+1|. - void CollectCallFeedback(TNode maybe_target, TNode context, - TNode maybe_feedback_vector, - TNode slot_id); - // Increment the call count for a CALL_IC or construct call. // The call count is located at feedback_vector[slot_id + 1]. void IncrementCallCount(TNode feedback_vector, @@ -2415,14 +2468,18 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TVariable* var_maybe_bigint, TVariable* var_feedback); + TNode TruncateNumberToWord32(TNode value); // Truncate the floating point value of a HeapNumber to an Int32. TNode TruncateHeapNumberValueToWord32(TNode object); // Conversions. void TryHeapNumberToSmi(TNode number, TVariable* output, Label* if_smi); + void TryFloat32ToSmi(TNode number, TVariable* output, + Label* if_smi); void TryFloat64ToSmi(TNode number, TVariable* output, Label* if_smi); + TNode ChangeFloat32ToTagged(TNode value); TNode ChangeFloat64ToTagged(SloppyTNode value); TNode ChangeInt32ToTagged(SloppyTNode value); TNode ChangeUint32ToTagged(SloppyTNode value); @@ -2430,6 +2487,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode ChangeNumberToUint32(TNode value); TNode ChangeNumberToFloat64(TNode value); + TNode ChangeTaggedNonSmiToInt32(TNode context, + TNode input); + TNode ChangeTaggedToFloat64(TNode context, + TNode input); + void TaggedToNumeric(TNode context, TNode value, TVariable* var_numeric); void TaggedToNumericWithFeedback(TNode context, TNode value, @@ -2546,6 +2608,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode IsOddball(SloppyTNode object); TNode IsOddballInstanceType(SloppyTNode instance_type); TNode IsIndirectStringInstanceType(SloppyTNode instance_type); + TNode IsJSAggregateError(TNode object); TNode IsJSArrayBuffer(SloppyTNode object); TNode IsJSDataView(TNode object); TNode IsJSArrayInstanceType(SloppyTNode instance_type); @@ -2565,6 +2628,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode IsJSObjectInstanceType(SloppyTNode instance_type); TNode IsJSObjectMap(SloppyTNode map); TNode IsJSObject(SloppyTNode object); + TNode IsJSFinalizationRegistryMap(TNode map); + TNode IsJSFinalizationRegistry(TNode object); TNode IsJSPromiseMap(SloppyTNode map); TNode IsJSPromise(SloppyTNode object); TNode IsJSProxy(SloppyTNode object); @@ -2643,8 +2708,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode IsPromiseThenProtectorCellInvalid(); TNode IsArraySpeciesProtectorCellInvalid(); TNode IsTypedArraySpeciesProtectorCellInvalid(); - TNode IsRegExpSpeciesProtectorCellInvalid( - TNode native_context); + TNode IsRegExpSpeciesProtectorCellInvalid(); TNode IsPromiseSpeciesProtectorCellInvalid(); TNode IsMockArrayBufferAllocatorFlag() { @@ -2698,6 +2762,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler bool IsFastElementsKind(ElementsKind kind) { return v8::internal::IsFastElementsKind(kind); } + TNode IsFastOrNonExtensibleOrSealedElementsKind( + TNode elements_kind); + TNode IsDictionaryElementsKind(TNode elements_kind) { return ElementsKindEqual(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)); } @@ -2812,43 +2879,52 @@ class V8_EXPORT_PRIVATE CodeStubAssembler // Decodes an unsigned (!) value from |word| to a word-size node. TNode DecodeWord(SloppyTNode word, uint32_t shift, - uint32_t mask); + uintptr_t mask); // Returns a node that contains the updated values of a |BitField|. template - TNode UpdateWord32(TNode word, TNode value) { - return UpdateWord32(word, value, BitField::kShift, BitField::kMask); + TNode UpdateWord32(TNode word, TNode value, + bool starts_as_zero = false) { + return UpdateWord32(word, value, BitField::kShift, BitField::kMask, + starts_as_zero); } // Returns a node that contains the updated values of a |BitField|. template - TNode UpdateWord(TNode word, TNode value) { - return UpdateWord(word, value, BitField::kShift, BitField::kMask); + TNode UpdateWord(TNode word, TNode value, + bool starts_as_zero = false) { + return UpdateWord(word, value, BitField::kShift, BitField::kMask, + starts_as_zero); } // Returns a node that contains the updated values of a |BitField|. template - TNode UpdateWordInWord32(TNode word, - TNode value) { - return UncheckedCast(TruncateIntPtrToInt32( - Signed(UpdateWord(ChangeUint32ToWord(word), value)))); + TNode UpdateWordInWord32(TNode word, TNode value, + bool starts_as_zero = false) { + return UncheckedCast( + TruncateIntPtrToInt32(Signed(UpdateWord( + ChangeUint32ToWord(word), value, starts_as_zero)))); } // Returns a node that contains the updated values of a |BitField|. template - TNode UpdateWord32InWord(TNode word, TNode value) { - return UpdateWord(word, ChangeUint32ToWord(value)); + TNode UpdateWord32InWord(TNode word, TNode value, + bool starts_as_zero = false) { + return UpdateWord(word, ChangeUint32ToWord(value), + starts_as_zero); } // Returns a node that contains the updated {value} inside {word} starting // at {shift} and fitting in {mask}. TNode UpdateWord32(TNode word, TNode value, - uint32_t shift, uint32_t mask); + uint32_t shift, uint32_t mask, + bool starts_as_zero = false); // Returns a node that contains the updated {value} inside {word} starting // at {shift} and fitting in {mask}. TNode UpdateWord(TNode word, TNode value, - uint32_t shift, uint32_t mask); + uint32_t shift, uintptr_t mask, + bool starts_as_zero = false); // Returns true if any of the |T|'s bits in given |word32| are set. template @@ -3593,8 +3669,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode IsDebugActive(); // JSArrayBuffer helpers - TNode LoadJSArrayBufferBitField(TNode array_buffer); - TNode LoadJSArrayBufferBackingStore( + TNode LoadJSArrayBufferBackingStorePtr( TNode array_buffer); void ThrowIfArrayBufferIsDetached(SloppyTNode context, TNode array_buffer, @@ -3671,10 +3746,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode MakeTypeError(MessageTemplate message, TNode context, TArgs... args) { STATIC_ASSERT(sizeof...(TArgs) <= 3); - const TNode make_type_error = LoadContextElement( - LoadNativeContext(context), Context::MAKE_TYPE_ERROR_INDEX); - return CAST(Call(context, make_type_error, UndefinedConstant(), - SmiConstant(message), args...)); + return CAST(CallRuntime(Runtime::kNewTypeError, context, + SmiConstant(message), args...)); } void Abort(AbortReason reason) { @@ -3844,6 +3917,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode RefillMathRandom(TNode native_context); + void RemoveFinalizationRegistryCellFromUnregisterTokenMap( + TNode finalization_registry, + TNode weak_cell); + private: friend class CodeStubArguments; diff --git a/deps/v8/src/codegen/compiler.cc b/deps/v8/src/codegen/compiler.cc index 595e59f55148c4..c436c57407cdca 100644 --- a/deps/v8/src/codegen/compiler.cc +++ b/deps/v8/src/codegen/compiler.cc @@ -30,6 +30,7 @@ #include "src/execution/frames-inl.h" #include "src/execution/isolate-inl.h" #include "src/execution/isolate.h" +#include "src/execution/off-thread-isolate.h" #include "src/execution/runtime-profiler.h" #include "src/execution/vm-state-inl.h" #include "src/handles/maybe-handles.h" @@ -42,10 +43,11 @@ #include "src/objects/map.h" #include "src/objects/object-list-macros.h" #include "src/objects/shared-function-info.h" +#include "src/objects/string.h" #include "src/parsing/parse-info.h" #include "src/parsing/parser.h" #include "src/parsing/parsing.h" -#include "src/parsing/rewriter.h" +#include "src/parsing/pending-compilation-error-handler.h" #include "src/parsing/scanner-character-streams.h" #include "src/snapshot/code-serializer.h" #include "src/utils/ostreams.h" @@ -179,13 +181,15 @@ CompilationJob::Status UnoptimizedCompilationJob::FinalizeJob( return UpdateState(FinalizeJobImpl(shared_info, isolate), State::kSucceeded); } -void UnoptimizedCompilationJob::RecordCompilationStats(Isolate* isolate) const { +namespace { + +void RecordUnoptimizedCompilationStats(Isolate* isolate, + Handle shared_info) { int code_size; - if (compilation_info()->has_bytecode_array()) { - code_size = compilation_info()->bytecode_array()->SizeIncludingMetadata(); + if (shared_info->HasBytecodeArray()) { + code_size = shared_info->GetBytecodeArray().SizeIncludingMetadata(); } else { - DCHECK(compilation_info()->has_asm_wasm_data()); - code_size = compilation_info()->asm_wasm_data()->Size(); + code_size = shared_info->asm_wasm_data().Size(); } Counters* counters = isolate->counters(); @@ -197,27 +201,30 @@ void UnoptimizedCompilationJob::RecordCompilationStats(Isolate* isolate) const { // Also add total time (there's now already timer_ on the base class). } -void UnoptimizedCompilationJob::RecordFunctionCompilation( - CodeEventListener::LogEventsAndTags tag, Handle shared, - Isolate* isolate) const { +void RecordUnoptimizedFunctionCompilation( + Isolate* isolate, CodeEventListener::LogEventsAndTags tag, + Handle shared, base::TimeDelta time_taken_to_execute, + base::TimeDelta time_taken_to_finalize) { Handle abstract_code; - if (compilation_info()->has_bytecode_array()) { + if (shared->HasBytecodeArray()) { abstract_code = - Handle::cast(compilation_info()->bytecode_array()); + handle(AbstractCode::cast(shared->GetBytecodeArray()), isolate); } else { - DCHECK(compilation_info()->has_asm_wasm_data()); + DCHECK(shared->HasAsmWasmData()); abstract_code = Handle::cast(BUILTIN_CODE(isolate, InstantiateAsmJs)); } - double time_taken_ms = time_taken_to_execute_.InMillisecondsF() + - time_taken_to_finalize_.InMillisecondsF(); + double time_taken_ms = time_taken_to_execute.InMillisecondsF() + + time_taken_to_finalize.InMillisecondsF(); Handle