Diff
Modified: trunk/JSTests/ChangeLog (289416 => 289417)
--- trunk/JSTests/ChangeLog 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/JSTests/ChangeLog 2022-02-08 20:42:04 UTC (rev 289417)
@@ -1,3 +1,16 @@
+2022-02-08 Caitlin Potter <ca...@igalia.com>
+
+ [JSC] move function wrapping logic to a new Function type
+ https://bugs.webkit.org/show_bug.cgi?id=235382
+
+ Reviewed by Yusuke Suzuki.
+
+ Adds a new file testing CopyNameAndLength stuff in the ShadowRealm proposal,
+ and fix up assertions about this in shadow-realm-evaluate.js
+
+ * stress/shadow-realm-evaluate.js:
+ * stress/shadow-realm-remote-function-copy-length-and-name.js: Added.
+
2022-02-06 Yusuke Suzuki <ysuz...@apple.com>
[Wasm] ref.null check should be done first in B3 call_ref
Modified: trunk/JSTests/stress/shadow-realm-evaluate.js (289416 => 289417)
--- trunk/JSTests/stress/shadow-realm-evaluate.js 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/JSTests/stress/shadow-realm-evaluate.js 2022-02-08 20:42:04 UTC (rev 289417)
@@ -80,9 +80,18 @@
shouldBe(Object.getPrototypeOf(wrappedInvokeAndAdd), Function.prototype);
// name and length properties from wrapped function are absent
- shouldBe(Object.getOwnPropertyDescriptor(wrappedInvokeAndAdd, "length"), undefined);
- shouldBe(Object.getOwnPropertyDescriptor(wrappedInvokeAndAdd, "name"), undefined);
+ let lengthDesc = Object.getOwnPropertyDescriptor(wrappedInvokeAndAdd, "length");
+ shouldBe(lengthDesc.value, 2);
+ shouldBe(lengthDesc.writable, false);
+ shouldBe(lengthDesc.enumerable, false);
+ shouldBe(lengthDesc.configurable, true);
+ let nameDesc = Object.getOwnPropertyDescriptor(wrappedInvokeAndAdd, "name");
+ shouldBe(nameDesc.value, "invokeAndAdd");
+ shouldBe(nameDesc.writable, false);
+ shouldBe(nameDesc.enumerable, false);
+ shouldBe(nameDesc.configurable, true);
+
// can't pass objects into a shadow realm-wrapped function
let numberObj = { valueOf() { return -1 } };
shouldThrow(
Added: trunk/JSTests/stress/shadow-realm-remote-function-copy-length-and-name.js (0 => 289417)
--- trunk/JSTests/stress/shadow-realm-remote-function-copy-length-and-name.js (rev 0)
+++ trunk/JSTests/stress/shadow-realm-remote-function-copy-length-and-name.js 2022-02-08 20:42:04 UTC (rev 289417)
@@ -0,0 +1,414 @@
+//@ requireOptions("--useShadowRealm=1")
+
+function summarizeElement(element) {
+ if (typeof element === "object") {
+ if (element === null)
+ return "null";
+ if (Array.isArray(element))
+ return summarizeArray(element, 0);
+ }
+ let result = JSON.stringify(element);
+ if (result.length > 20) {
+ let c = result[0];
+ if (c === "{")
+ c = "}";
+ result = `${result.substr(0, 15)}...${c}`;
+ }
+ return result;
+}
+
+function summarizeArray(array, index, showIndex) {
+
+ let prefix = index === 0 ? "" : `...${summarizeElement(array[index - 1])}, `;
+ let suffix = index + 1 < array.length ? `, ${summarizeElement(array[index + 1])}...` : "";
+
+ if (prefix.length > 20)
+ prefix = prefix.substr(prefix.length - 20);
+ if (suffix.length > 20)
+ suffix = suffix.substr(0, 20);
+ ender = showIndex ? ` (at index ${index})` : "";
+ return `[${prefix}${JSON.stringify(array[index])}${suffix}]${ender}`;
+}
+function shouldBeArrayEqual(actual, expected) {
+ if ((Array.isArray(expected) && !Array.isArray(actual)))
+ throw new Error(`Expected ${JSON.stringify} but found ${JSON.stringify(actual)}`);
+
+ var i;
+ for (var i = 0; i < expected.length; ++i) {
+ let e = expected[i];
+ let a = actual[i];
+ if (e === a)
+ continue;
+ if (Array.isArray(e))
+ shouldBeArrayEqual(a, e);
+ throw new Error(`Expected ${summarizeArray(expected, i, true)} but found ${summarizeArray(actual, i)}`)
+ }
+}
+
+function shouldBe(actual, expected) {
+ if (Array.isArray(actual) || Array.isArray(expected))
+ return shouldBeArrayEqual(actual, expected);
+ if (actual !== expected)
+ throw new Error(`expected ${expected} but got ${actual}`);
+}
+
+function shouldHaveDescriptor(object, propertyName, descriptor) {
+ let actual = Object.getOwnPropertyDescriptor(object, propertyName);
+ let order = Object.keys(descriptor).sort();
+ for (let key of order) {
+ let value = descriptor[key];
+ if (["undefined", "boolean", "number", "string", "symbol", "bigint"].includes(typeof value) || value === null) {
+ if (actual[key] !== value)
+ throw new Error(`Expected ${summarizeElement(actual)}'s '${key}' to be ${summarizeElement(value)}, but found ${summarizeElement(actual[key])}`);
+ } else if (typeof value === "function") {
+ if (actual[key] !== value && String(value) !== String(actual[key]))
+ throw new Error(`Expected ${summarizeElement(actual)}'s '${key}' to be ${summarizeElement(value)}, but found ${summarizeElement(actual[key])}`);
+ }
+ }
+}
+
+function shouldThrow(op, errorConstructor, desc) {
+ try {
+ op();
+ } catch (e) {
+ if (!(e instanceof errorConstructor)) {
+ throw new Error(`threw ${e}, but should have thrown ${errorConstructor.name}`);
+ }
+ return;
+ }
+ throw new Error(`Expected ${desc || 'operation'} to throw ${errorConstructor.name}, but no exception thrown`);
+}
+
+let realm = new ShadowRealm;
+
+let f = realm.evaluate(`(() => {
+ let test1 = function(a, b, c) {
+ };
+ return test1;
+})()`);
+
+shouldHaveDescriptor(f, "length", {
+ value: 3,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+shouldHaveDescriptor(f, "name", {
+ value: "test1",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+f = realm.evaluate(`(() => {
+ function test2(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {
+ }
+ return test2;
+})()`);
+
+shouldHaveDescriptor(f, "length", {
+ value: 16,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+shouldHaveDescriptor(f, "name", {
+ value: "test2",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+f = realm.evaluate(`(() => {
+ let f = function() {
+ }
+ Object.defineProperty(f, "length", {
+ value: -Infinity,
+ writable: true,
+ configurable: true,
+ enumerable: true
+ });
+ Object.defineProperty(f, "name", {
+ value: "27",
+ writable: true,
+ configurable: true,
+ enumerable: true
+ });
+ return f;
+})()`);
+
+shouldHaveDescriptor(f, "length", {
+ value: 0,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+shouldHaveDescriptor(f, "name", {
+ value: "27",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+f = realm.evaluate(`(() => {
+ let f = function() {
+ }
+ Object.defineProperty(f, "length", {
+ value: -9.74,
+ writable: true,
+ configurable: true,
+ enumerable: true
+ });
+ Object.defineProperty(f, "name", {
+ value: 57,
+ writable: true,
+ configurable: true,
+ enumerable: true
+ });
+ return f;
+})()`);
+
+shouldHaveDescriptor(f, "length", {
+ value: 0,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+shouldHaveDescriptor(f, "name", {
+ value: "",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+let innerLog = realm.evaluate(`(() => {
+ globalThis._log = [];
+ globalThis.log = function log(item) {
+ globalThis._log.push(item);
+ };
+
+ return function log() {
+ let log = globalThis._log;
+ globalThis._log = [];
+ return JSON.stringify(log);
+ };
+})()`);
+
+function log() {
+ let result = JSON.parse(innerLog());
+ shouldBe(Array.isArray(result), true);
+ return result;
+}
+
+f = realm.evaluate(`(() => {
+ let target = (function() {
+ log(\`called\`);
+ });
+ let p = new Proxy(target, {
+ getOwnPropertyDescriptor(t, p) {
+ log(\`getOwnPropertyDescriptor \${p}\`);
+ return Reflect.getOwnProperty(...arguments);
+ },
+ get(t, p) {
+ log(\`get \${p}\`);
+ return Reflect.get(...arguments);
+ },
+ defineProperty(t, p, o) {
+ log(\`defineProperty \${p}\`);
+ return Reflect.defineProperty(...arguments);
+ },
+ getPrototypeOf(t) {
+ log(\`getPrototypeOf\`);
+ return Reflect.getPrototypeOf(...arguments);
+ },
+ setPrototypeOf(t, v) {
+ log(\`setPrototypeOf\`);
+ return Reflect.setPrototypeOf(...arguments);
+ },
+ isExtensible(t) {
+ log(\`isExtensible\`);
+ return Reflect.isExtensible(...arguments);
+ },
+ preventExtensions(t) {
+ log(\`preventExtensions\`);
+ return Reflect.preventExtensions(...arguments);
+ },
+ has(t, p) {
+ log(\`has \${p}\`);
+ return Reflect.has(...arguments);
+ },
+ set(t, p, v) {
+ log(\`set \${p}\`);
+ return Reflect.set(...arguments);
+ },
+ delete(t, p) {
+ log(\`delete \${p}\`);
+ return Reflect.delete(...arguments);
+ },
+ ownKeys(t) {
+ log(\`ownKeys\`);
+ return Reflect.ownKeys(...arguments);
+ },
+ apply() {
+ log(\`apply\`);
+ return Reflect.apply(...arguments);
+ },
+ construct() {
+ log(\`construct\`);
+ return Reflect.argumentList(...arguments);
+ },
+ });
+ Object.defineProperty(target, "length", {
+ get() {
+ log("length getter");
+ return Infinity;
+ },
+ set() {
+ log("length setter");
+ return false;
+ },
+ configurable: true,
+ enumerable: true
+ });
+ Object.defineProperty(target, "name", {
+ get() {
+ log("name getter");
+ return Infinity;
+ },
+ set() {
+ log("name setter");
+ return false;
+ },
+ configurable: true,
+ enumerable: true
+ });
+ return p;
+})()`);
+
+f();
+shouldHaveDescriptor(f, "length", {
+ value: Infinity,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+shouldHaveDescriptor(f, "name", {
+ value: "",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+shouldBe(log(), [
+ "get length",
+ "length getter",
+ "get name",
+ "name getter",
+ "apply",
+ "called"
+]);
+f();
+shouldBe(log(), ["apply", "called"]);
+
+f = realm.evaluate(`(() => {
+ let target = (function() {
+ log(\`called 2\`);
+ });
+ let p = new Proxy(target, {
+ getOwnPropertyDescriptor(t, p) {
+ log(\`getOwnPropertyDescriptor \${p}\`);
+ return Reflect.getOwnProperty(...arguments);
+ },
+ get(t, p) {
+ log(\`get \${p}\`);
+ return Reflect.get(...arguments);
+ },
+ defineProperty(t, p, o) {
+ log(\`defineProperty \${p}\`);
+ return Reflect.defineProperty(...arguments);
+ },
+ getPrototypeOf(t) {
+ log(\`getPrototypeOf\`);
+ return Reflect.getPrototypeOf(...arguments);
+ },
+ setPrototypeOf(t, v) {
+ log(\`setPrototypeOf\`);
+ return Reflect.setPrototypeOf(...arguments);
+ },
+ isExtensible(t) {
+ log(\`isExtensible\`);
+ return Reflect.isExtensible(...arguments);
+ },
+ preventExtensions(t) {
+ log(\`preventExtensions\`);
+ return Reflect.preventExtensions(...arguments);
+ },
+ has(t, p) {
+ log(\`has \${p}\`);
+ return Reflect.has(...arguments);
+ },
+ set(t, p, v) {
+ log(\`set \${p}\`);
+ return Reflect.set(...arguments);
+ },
+ delete(t, p) {
+ log(\`delete \${p}\`);
+ return Reflect.delete(...arguments);
+ },
+ ownKeys(t) {
+ log(\`ownKeys\`);
+ return Reflect.ownKeys(...arguments);
+ },
+ apply() {
+ log(\`apply\`);
+ return Reflect.apply(...arguments);
+ },
+ construct() {
+ log(\`construct\`);
+ return Reflect.argumentList(...arguments);
+ },
+ });
+ Object.defineProperty(target, "length", {
+ get() { return },
+ configurable: true,
+ enumerable: true
+ });
+ Object.defineProperty(target, "name", {
+ value: 57,
+ configurable: true,
+ enumerable: true
+ });
+ return p;
+})()`);
+
+f();
+shouldHaveDescriptor(f, "length", {
+ value: 0,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+shouldHaveDescriptor(f, "name", {
+ value: "",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+shouldBe(log(), [
+ "get length",
+ "get name",
+ "apply",
+ "called 2"
+]);
+f();
+shouldBe(log(), ["apply", "called 2"]);
+
+shouldHaveDescriptor(f, "length", {
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+shouldHaveDescriptor(f, "name", {
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
Modified: trunk/Source/_javascript_Core/CMakeLists.txt (289416 => 289417)
--- trunk/Source/_javascript_Core/CMakeLists.txt 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/CMakeLists.txt 2022-02-08 20:42:04 UTC (rev 289417)
@@ -1083,6 +1083,7 @@
runtime/JSPromiseConstructor.h
runtime/JSPropertyNameEnumerator.h
runtime/JSProxy.h
+ runtime/JSRemoteFunction.h
runtime/JSRunLoopTimer.h
runtime/JSScope.h
runtime/JSScriptFetchParameters.h
Modified: trunk/Source/_javascript_Core/ChangeLog (289416 => 289417)
--- trunk/Source/_javascript_Core/ChangeLog 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/ChangeLog 2022-02-08 20:42:04 UTC (rev 289417)
@@ -1,3 +1,58 @@
+2022-02-08 Caitlin Potter <ca...@igalia.com>
+
+ [JSC] move function wrapping logic to a new Function type
+ https://bugs.webkit.org/show_bug.cgi?id=235382
+
+ Reviewed by Yusuke Suzuki.
+
+ In this initial patch, there is still a lot of JS-builtin machinery,
+ including some duplicated functionality. Additionally, JIT support
+ has not been incorporated yet.
+
+ Broadly, the idea is that there are custom hooks for calling a
+ JSRemoteFunction, which perform the wrapping functionality. This avoids
+ the need for allocating closures which contain the wrapping logic.
+
+ TODO:
+ - JIT/DFG/FTL support
+ - structure caching (unnecessary since these are not constructors?)
+ - improved baseline perf
+
+ * CMakeLists.txt:
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * Sources.txt:
+ * assembler/LinkBuffer.h:
+ * builtins/BuiltinNames.h:
+ * builtins/ShadowRealmPrototype.js:
+ * bytecode/LinkTimeConstant.h:
+ * dfg/DFGSpeculativeJIT.cpp:
+ * ftl/FTLLowerDFGToB3.cpp:
+ * heap/Heap.cpp:
+ * heap/Heap.h:
+ * inspector/JSInjectedScriptHost.cpp:
+ * interpreter/Interpreter.cpp:
+ * jit/AssemblyHelpers.h:
+ * jit/JITOperations.cpp:
+ * jit/JITOperations.h:
+ * jit/ThunkGenerators.cpp:
+ * jit/ThunkGenerators.h:
+ * jsc.cpp:
+ * runtime/ErrorInstance.cpp:
+ * runtime/FunctionPrototype.cpp:
+ * runtime/InternalFunction.cpp:
+ * runtime/Intrinsic.cpp:
+ * runtime/Intrinsic.h:
+ * runtime/JSCast.h:
+ * runtime/JSFunction.cpp:
+ * runtime/JSFunction.h:
+ * runtime/JSFunctionInlines.h:
+ * runtime/JSGlobalObject.cpp:
+ * runtime/JSGlobalObject.h:
+ * runtime/JSRemoteFunction.cpp: Added.
+ * runtime/JSRemoteFunction.h: Added.
+ * runtime/VM.cpp:
+ * runtime/VM.h:
+
2022-02-08 Razvan Caliman <rcali...@apple.com>
Web Inspector: [Flexbox] Add support for showing/hiding flex container overlays and basic overlay drawing
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (289416 => 289417)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2022-02-08 20:42:04 UTC (rev 289417)
@@ -1133,6 +1133,7 @@
53F6BF6D1C3F060A00F41E5D /* InternalFunctionAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F6BF6C1C3F060A00F41E5D /* InternalFunctionAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
53FA2AE11CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FA2AE01CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
53FD04D41D7AB291003287D3 /* WasmCallingConvention.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 5B4032802798D20600F37939 /* JSRemoteFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B40327E2798D1FD00F37939 /* JSRemoteFunction.h */; settings = {ATTRIBUTES = (Private, ); }; };
5B70CFDE1DB69E6600EC23F9 /* JSAsyncFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */; };
5B70CFE01DB69E6600EC23F9 /* AsyncFunctionPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFDA1DB69E5C00EC23F9 /* AsyncFunctionPrototype.h */; };
5B70CFE21DB69E6600EC23F9 /* AsyncFunctionConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFDC1DB69E5C00EC23F9 /* AsyncFunctionConstructor.h */; };
@@ -4084,6 +4085,8 @@
53FA2AE21CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp; sourceTree = "<group>"; };
53FD04D11D7AB187003287D3 /* WasmCallingConvention.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmCallingConvention.cpp; sourceTree = "<group>"; };
53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmCallingConvention.h; sourceTree = "<group>"; };
+ 5B40327E2798D1FD00F37939 /* JSRemoteFunction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSRemoteFunction.h; sourceTree = "<group>"; };
+ 5B40327F2798D1FD00F37939 /* JSRemoteFunction.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSRemoteFunction.cpp; sourceTree = "<group>"; };
5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAsyncFunction.h; sourceTree = "<group>"; };
5B70CFD91DB69E5C00EC23F9 /* JSAsyncFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAsyncFunction.cpp; sourceTree = "<group>"; };
5B70CFDA1DB69E5C00EC23F9 /* AsyncFunctionPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncFunctionPrototype.h; sourceTree = "<group>"; };
@@ -7971,6 +7974,8 @@
2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */,
862553CE16136AA5009F17D0 /* JSProxy.cpp */,
862553CF16136AA5009F17D0 /* JSProxy.h */,
+ 5B40327F2798D1FD00F37939 /* JSRemoteFunction.cpp */,
+ 5B40327E2798D1FD00F37939 /* JSRemoteFunction.h */,
534638721E70D01500F12AC1 /* JSRunLoopTimer.cpp */,
534638701E70CF3D00F12AC1 /* JSRunLoopTimer.h */,
14874AE115EBDE4A002E3587 /* JSScope.cpp */,
@@ -10675,6 +10680,7 @@
996B731F1BDA08EF00331B84 /* JSPromisePrototype.lut.h in Headers */,
2A05ABD61961DF2400341750 /* JSPropertyNameEnumerator.h in Headers */,
862553D216136E1A009F17D0 /* JSProxy.h in Headers */,
+ 5B4032802798D20600F37939 /* JSRemoteFunction.h in Headers */,
A552C3801ADDB8FE00139726 /* JSRemoteInspector.h in Headers */,
BC18C4260E16F5CD00B34460 /* JSRetainPtr.h in Headers */,
534638711E70CF3D00F12AC1 /* JSRunLoopTimer.h in Headers */,
Modified: trunk/Source/_javascript_Core/Sources.txt (289416 => 289417)
--- trunk/Source/_javascript_Core/Sources.txt 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/Sources.txt 2022-02-08 20:42:04 UTC (rev 289417)
@@ -902,6 +902,7 @@
runtime/JSPromisePrototype.cpp
runtime/JSPropertyNameEnumerator.cpp
runtime/JSProxy.cpp
+runtime/JSRemoteFunction.cpp
runtime/JSRunLoopTimer.cpp
runtime/JSScope.cpp
runtime/JSScriptFetcher.cpp
Modified: trunk/Source/_javascript_Core/assembler/LinkBuffer.h (289416 => 289417)
--- trunk/Source/_javascript_Core/assembler/LinkBuffer.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/assembler/LinkBuffer.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -92,6 +92,7 @@
v(DFGThunk) \
v(FTLThunk) \
v(BoundFunctionThunk) \
+ v(RemoteFunctionThunk) \
v(SpecializedThunk) \
v(VirtualThunk) \
v(WasmThunk) \
Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.h (289416 => 289417)
--- trunk/Source/_javascript_Core/builtins/BuiltinNames.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -189,6 +189,8 @@
macro(outOfLineReactionCounts) \
macro(emptyPropertyNameEnumerator) \
macro(sentinelString) \
+ macro(createRemoteFunction) \
+ macro(isRemoteFunction) \
namespace Symbols {
Modified: trunk/Source/_javascript_Core/builtins/ShadowRealmPrototype.js (289416 => 289417)
--- trunk/Source/_javascript_Core/builtins/ShadowRealmPrototype.js 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/builtins/ShadowRealmPrototype.js 2022-02-08 20:42:04 UTC (rev 289417)
@@ -32,39 +32,7 @@
"use strict";
if (@isCallable(target)) {
- var wrapped = function(/* args... */) {
- var length = arguments.length;
- var wrappedArgs = @newArrayWithSize(length);
- for (var index = 0; index < length; ++index)
- // Note that for arguments, we flip `fromShadowRealm` since to
- // wrap a function from realm A to work in realm B, we need to
- // wrap the arguments (from realm B) to work in realm A before
- // calling the wrapped function
- @putByValDirect(wrappedArgs, index, @wrap(!fromShadowRealm, shadowRealm, arguments[index]));
-
- try {
- var result = target.@apply(@undefined, wrappedArgs);
- } catch (e) {
- const msg = "wrapped function threw: " + e.toString();
- if (fromShadowRealm)
- @throwTypeError(msg);
- else {
- const mkTypeError = @evalInRealm(shadowRealm, "(msg) => new TypeError(msg)");
- const err = mkTypeError.@apply(msg);
- throw err;
- }
- }
- return @wrap(fromShadowRealm, shadowRealm, result);
- };
- delete wrapped['name'];
- delete wrapped['length'];
-
- // Because this function (wrap) will run with the incubating realm
- // active, we only need to fix the prototype on `wrapped` if we are
- // moving the function from the incubating realm to the shadow realm
- if (!fromShadowRealm)
- @moveFunctionToRealm(wrapped, shadowRealm);
- return wrapped;
+ return @createRemoteFunction(target, fromShadowRealm ? null : shadowRealm);
} else if (@isObject(target)) {
@throwTypeError("value passing between realms must be callable or primitive");
}
Modified: trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h (289416 => 289417)
--- trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -117,6 +117,8 @@
v(createPrivateSymbol, nullptr) \
v(emptyPropertyNameEnumerator, nullptr) \
v(sentinelString, nullptr) \
+ v(createRemoteFunction, nullptr) \
+ v(isRemoteFunction, nullptr) \
#define DECLARE_LINK_TIME_CONSTANT(name, code) name,
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -11257,6 +11257,9 @@
static_assert(std::is_final_v<JSBoundFunction>, "We don't handle subclasses when comparing classInfo below");
slowCases.append(m_jit.branchPtr(CCallHelpers::Equal, result.gpr(), TrustedImmPtr(JSBoundFunction::info())));
+ static_assert(std::is_final_v<JSRemoteFunction>, "We don't handle subclasses when comparing classInfo below");
+ slowCases.append(m_jit.branchPtr(CCallHelpers::Equal, result.gpr(), TrustedImmPtr(JSRemoteFunction::info())));
+
getExecutable(m_jit, function.gpr(), executable.gpr());
JITCompiler::Jump isNativeExecutable = m_jit.branch8(JITCompiler::Equal, JITCompiler::Address(executable.gpr(), JSCell::typeInfoTypeOffset()), TrustedImm32(NativeExecutableType));
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -8613,6 +8613,7 @@
JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
LBasicBlock notBoundFunctionCase = m_out.newBlock();
+ LBasicBlock notBoundOrRemoteFunctionCase = m_out.newBlock();
LBasicBlock functionExecutableCase = m_out.newBlock();
LBasicBlock nativeExecutableCase = m_out.newBlock();
LBasicBlock testPtr = m_out.newBlock();
@@ -8628,7 +8629,11 @@
static_assert(std::is_final_v<JSBoundFunction>, "We don't handle subclasses when comparing classInfo below");
m_out.branch(m_out.equal(classInfo, m_out.constIntPtr(JSBoundFunction::info())), unsure(slowCase), unsure(notBoundFunctionCase));
- LBasicBlock lastNext = m_out.appendTo(notBoundFunctionCase, nativeExecutableCase);
+ static_assert(std::is_final_v<JSRemoteFunction>, "We don't handle subclasses when comparing classInfo below");
+ m_out.appendTo(notBoundFunctionCase, notBoundOrRemoteFunctionCase);
+ m_out.branch(m_out.equal(classInfo, m_out.constIntPtr(JSRemoteFunction::info())), unsure(slowCase), unsure(notBoundOrRemoteFunctionCase));
+
+ LBasicBlock lastNext = m_out.appendTo(notBoundOrRemoteFunctionCase, nativeExecutableCase);
LValue executable = getExecutable(function);
m_out.branch(isType(executable, NativeExecutableType), unsure(nativeExecutableCase), unsure(functionExecutableCase));
Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/heap/Heap.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -51,6 +51,7 @@
#include "JITStubRoutineSet.h"
#include "JITWorklistInlines.h"
#include "JSFinalizationRegistry.h"
+#include "JSRemoteFunction.h"
#include "JSVirtualMachineInternal.h"
#include "JSWeakMap.h"
#include "JSWeakObjectRef.h"
@@ -3219,6 +3220,7 @@
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(nativeStdFunctionSpace, nativeStdFunctionHeapCellType, JSNativeStdFunction) // Hash:0x70ed61e4
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(proxyObjectSpace, cellHeapCellType, ProxyObject)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(proxyRevokeSpace, cellHeapCellType, ProxyRevoke) // Hash:0xb506a939
+DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(remoteFunctionSpace, cellHeapCellType, JSRemoteFunction)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(scopedArgumentsTableSpace, destructibleCellHeapCellType, ScopedArgumentsTable)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(scriptFetchParametersSpace, destructibleCellHeapCellType, JSScriptFetchParameters)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(scriptFetcherSpace, destructibleCellHeapCellType, JSScriptFetcher)
Modified: trunk/Source/_javascript_Core/heap/Heap.h (289416 => 289417)
--- trunk/Source/_javascript_Core/heap/Heap.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/heap/Heap.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -926,6 +926,7 @@
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(nativeStdFunctionSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(proxyObjectSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(proxyRevokeSpace)
+ DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(remoteFunctionSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(scopedArgumentsTableSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(scriptFetchParametersSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(scriptFetcherSpace)
Modified: trunk/Source/_javascript_Core/inspector/JSInjectedScriptHost.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/inspector/JSInjectedScriptHost.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/inspector/JSInjectedScriptHost.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -347,7 +347,16 @@
}
return array;
}
+ if (JSRemoteFunction* remoteFunction = jsDynamicCast<JSRemoteFunction*>(vm, value)) {
+ unsigned index = 0;
+ JSArray* array = constructEmptyArray(globalObject, nullptr, 1);
+ RETURN_IF_EXCEPTION(scope, JSValue());
+ array->putDirectIndex(globalObject, index++, constructInternalProperty(globalObject, "targetFunction"_s, remoteFunction->targetFunction()));
+ RETURN_IF_EXCEPTION(scope, JSValue());
+ return array;
+ }
+
if (ProxyObject* proxy = jsDynamicCast<ProxyObject*>(vm, value)) {
unsigned index = 0;
JSArray* array = constructEmptyArray(globalObject, nullptr, 2);
Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -51,6 +51,7 @@
#include "JSLexicalEnvironment.h"
#include "JSModuleEnvironment.h"
#include "JSModuleRecord.h"
+#include "JSRemoteFunction.h"
#include "JSString.h"
#include "JSWebAssemblyException.h"
#include "LLIntThunks.h"
@@ -555,12 +556,13 @@
class UnwindFunctor {
public:
- UnwindFunctor(VM& vm, CallFrame*& callFrame, bool isTermination, JSValue thrownValue, CodeBlock*& codeBlock, CatchInfo& handler)
+ UnwindFunctor(VM& vm, CallFrame*& callFrame, bool isTermination, JSValue thrownValue, CodeBlock*& codeBlock, CatchInfo& handler, bool& seenRemoteFucnction)
: m_vm(vm)
, m_callFrame(callFrame)
, m_isTermination(isTermination)
, m_codeBlock(codeBlock)
, m_handler(handler)
+ , m_seenRemoteFunction(seenRemoteFucnction)
{
#if ENABLE(WEBASSEMBLY)
if (!m_isTermination) {
@@ -609,6 +611,13 @@
}
#endif
+ if (!m_callFrame->isWasmFrame() && JSC::isRemoteFunction(m_vm, m_callFrame->jsCallee()) && !m_isTermination) {
+ // Continue searching for a handler, but mark that a marshalling function was on the stack so that we can
+ // translate the exception before jumping to the handler.
+ const_cast<UnwindFunctor*>(this)->m_seenRemoteFunction = true;
+ return StackVisitor::Continue;
+ }
+
notifyDebuggerOfUnwinding(m_vm, m_callFrame);
copyCalleeSavesToEntryFrameCalleeSavesBuffer(visitor);
@@ -657,8 +666,39 @@
const Wasm::Tag* m_wasmTag { nullptr };
bool m_catchableFromWasm { false };
#endif
+
+ bool& m_seenRemoteFunction;
};
+// Replace an exception which passes across a marshalling boundary with a TypeError for its handler's global object.
+static void sanitizeRemoteFunctionException(VM& vm, CallFrame* handlerCallFrame, Exception* exception)
+{
+ DeferTermination deferScope(vm);
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ ASSERT(exception);
+ ASSERT(!vm.isTerminationException(exception));
+
+ JSGlobalObject* globalObject = handlerCallFrame->jsCallee()->globalObject();
+ JSValue exceptionValue = exception->value();
+ scope.clearException();
+
+ // Avoid user-observable ToString()
+ String exceptionString;
+ if (exceptionValue.isPrimitive())
+ exceptionString = exceptionValue.toWTFString(globalObject);
+ else if (exceptionValue.asCell()->inherits<ErrorInstance>(vm))
+ exceptionString = static_cast<ErrorInstance*>(exceptionValue.asCell())->sanitizedMessageString(globalObject);
+
+ ASSERT(!scope.exception()); // We must not have entered JS at this point
+
+ if (exceptionString.length()) {
+ throwVMTypeError(globalObject, scope, exceptionString);
+ return;
+ }
+
+ throwVMTypeError(globalObject, scope);
+}
+
NEVER_INLINE CatchInfo Interpreter::unwind(VM& vm, CallFrame*& callFrame, Exception* exception)
{
auto scope = DECLARE_CATCH_SCOPE(vm);
@@ -678,8 +718,15 @@
// Calculate an exception handler vPC, unwinding call frames as necessary.
CatchInfo catchInfo;
- UnwindFunctor functor(vm, callFrame, vm.isTerminationException(exception), exceptionValue, codeBlock, catchInfo);
+ bool seenRemoteFunction = false;
+ UnwindFunctor functor(vm, callFrame, vm.isTerminationException(exception), exceptionValue, codeBlock, catchInfo, seenRemoteFunction);
StackVisitor::visit<StackVisitor::TerminateIfTopEntryFrameIsEmpty>(callFrame, vm, functor);
+
+ if (seenRemoteFunction) {
+ sanitizeRemoteFunctionException(vm, callFrame, exception);
+ exception = scope.exception(); // clear m_needExceptionCheck
+ }
+
if (vm.hasCheckpointOSRSideState())
vm.popAllCheckpointOSRSideStateUntil(callFrame);
Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (289416 => 289417)
--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -1345,6 +1345,7 @@
void jitAssertIsNull(GPRReg);
void jitAssertTagsInPlace();
void jitAssertArgumentCountSane();
+ inline void jitAssertNoException(VM& vm) { jitReleaseAssertNoException(vm); }
#else
void jitAssertIsInt32(GPRReg) { }
void jitAssertIsJSInt32(GPRReg) { }
@@ -1355,6 +1356,7 @@
void jitAssertIsNull(GPRReg) { }
void jitAssertTagsInPlace() { }
void jitAssertArgumentCountSane() { }
+ void jitAssertNoException(VM&) { }
#endif
void jitReleaseAssertNoException(VM&);
Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/jit/JITOperations.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -55,6 +55,7 @@
#include "JSGlobalObjectFunctions.h"
#include "JSInternalPromise.h"
#include "JSLexicalEnvironment.h"
+#include "JSRemoteFunction.h"
#include "JSWithScope.h"
#include "LLIntEntrypoint.h"
#include "ObjectConstructor.h"
@@ -115,6 +116,87 @@
ASSERT(vm.targetMachinePCForThrow);
}
+static JSValue getWrappedValue(JSGlobalObject* globalObject, JSGlobalObject* targetGlobalObject, JSValue value)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (!value.isObject())
+ RELEASE_AND_RETURN(scope, value);
+
+ if (value.isCallable(vm))
+ RELEASE_AND_RETURN(scope, JSRemoteFunction::create(vm, targetGlobalObject, static_cast<JSObject*>(value.asCell())));
+
+ throwTypeError(globalObject, scope, "value passing between realms must be callable or primitive");
+ return jsUndefined();
+}
+
+JSC_DEFINE_JIT_OPERATION(operationGetWrappedValueForTarget, EncodedJSValue, (JSRemoteFunction* callee, EncodedJSValue encodedValue))
+{
+ JSGlobalObject* globalObject = callee->globalObject();
+ VM& vm = globalObject->vm();
+
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+ ASSERT(isRemoteFunction(vm, callee));
+
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSGlobalObject* targetGlobalObject = callee->targetFunction()->globalObject();
+ RELEASE_AND_RETURN(scope, JSValue::encode(getWrappedValue(globalObject, targetGlobalObject, JSValue::decode(encodedValue))));
+}
+
+JSC_DEFINE_JIT_OPERATION(operationGetWrappedValueForCaller, EncodedJSValue, (JSRemoteFunction* callee, EncodedJSValue encodedValue))
+{
+ JSGlobalObject* globalObject = callee->globalObject();
+ VM& vm = globalObject->vm();
+
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+ ASSERT(isRemoteFunction(vm, callee));
+
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(getWrappedValue(globalObject, globalObject, JSValue::decode(encodedValue))));
+}
+
+JSC_DEFINE_JIT_OPERATION(operationThrowRemoteFunctionException, EncodedJSValue, (JSRemoteFunction* callee))
+{
+ JSGlobalObject* globalObject = callee->globalObject();
+ VM& vm = globalObject->vm();
+
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+ ASSERT(isRemoteFunction(vm, callee));
+
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ Exception* exception = scope.exception();
+
+ // We should only be here when "rethrowing" an exception
+ RELEASE_ASSERT(exception);
+
+ if (UNLIKELY(vm.isTerminationException(exception))) {
+ scope.release();
+ return { };
+ }
+
+ JSValue exceptionValue = exception->value();
+ scope.clearException();
+
+ String exceptionString = exceptionValue.toWTFString(globalObject);
+ Exception* toStringException = scope.exception();
+ if (UNLIKELY(toStringException && vm.isTerminationException(toStringException))) {
+ scope.release();
+ return { };
+ }
+ scope.clearException();
+
+ if (exceptionString.length())
+ return throwVMTypeError(globalObject, scope, exceptionString);
+
+ return throwVMTypeError(globalObject, scope);
+}
+
JSC_DEFINE_JIT_OPERATION(operationThrowIteratorResultIsNotObject, void, (JSGlobalObject* globalObject))
{
VM& vm = globalObject->vm();
Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (289416 => 289417)
--- trunk/Source/_javascript_Core/jit/JITOperations.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -52,6 +52,7 @@
class JSGlobalObject;
class JSLexicalEnvironment;
class JSObject;
+class JSRemoteFunction;
class JSScope;
class JSString;
class JSValue;
@@ -155,6 +156,9 @@
JSC_DECLARE_JIT_OPERATION(operationVMHandleException, void, (VM*));
JSC_DECLARE_JIT_OPERATION(operationThrowStackOverflowErrorFromThunk, void, (JSGlobalObject*));
JSC_DECLARE_JIT_OPERATION(operationThrowIteratorResultIsNotObject, void, (JSGlobalObject*));
+JSC_DECLARE_JIT_OPERATION(operationGetWrappedValueForCaller, EncodedJSValue, (JSRemoteFunction*, EncodedJSValue));
+JSC_DECLARE_JIT_OPERATION(operationGetWrappedValueForTarget, EncodedJSValue, (JSRemoteFunction*, EncodedJSValue));
+JSC_DECLARE_JIT_OPERATION(operationThrowRemoteFunctionException, EncodedJSValue, (JSRemoteFunction*));
JSC_DECLARE_JIT_OPERATION(operationThrowStackOverflowError, void, (CodeBlock*));
JSC_DECLARE_JIT_OPERATION(operationCallArityCheck, int32_t, (JSGlobalObject*));
Modified: trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -29,6 +29,7 @@
#include "JITOperations.h"
#include "JITThunks.h"
#include "JSBoundFunction.h"
+#include "JSRemoteFunction.h"
#include "LLIntThunks.h"
#include "MaxFrameExtentForSlowPathCall.h"
#include "SpecializedThunkJIT.h"
@@ -1421,6 +1422,192 @@
linkBuffer, JITThunkPtrTag, "Specialized thunk for bound function calls with no arguments");
}
+MacroAssemblerCodeRef<JITThunkPtrTag> remoteFunctionCallGenerator(VM& vm)
+{
+ CCallHelpers jit;
+ jit.emitFunctionPrologue();
+
+ // Set up our call frame.
+ jit.storePtr(CCallHelpers::TrustedImmPtr(nullptr), CCallHelpers::addressFor(CallFrameSlot::codeBlock));
+ jit.store32(CCallHelpers::TrustedImm32(0), CCallHelpers::tagFor(CallFrameSlot::argumentCountIncludingThis));
+
+ unsigned extraStackNeeded = 0;
+ if (unsigned stackMisalignment = sizeof(CallerFrameAndPC) % stackAlignmentBytes())
+ extraStackNeeded = stackAlignmentBytes() - stackMisalignment;
+
+ // We need to forward all of the arguments that we were passed. We aren't allowed to do a tail
+ // call here as far as I can tell. At least not so long as the generic path doesn't do a tail
+ // call, since that would be way too weird.
+
+ // The formula for the number of stack bytes needed given some number of parameters (including
+ // this) is:
+ //
+ // stackAlign((numParams + numFrameLocals + CallFrameHeaderSize) * sizeof(Register) - sizeof(CallerFrameAndPC))
+ //
+ // Probably we want to write this as:
+ //
+ // stackAlign((numParams + numFrameLocals + (CallFrameHeaderSize - CallerFrameAndPCSize)) * sizeof(Register))
+ static constexpr int numFrameLocals = 1;
+ VirtualRegister loopIndex = virtualRegisterForLocal(0);
+
+ jit.loadCell(CCallHelpers::addressFor(CallFrameSlot::callee), GPRInfo::regT0);
+ jit.load32(CCallHelpers::payloadFor(CallFrameSlot::argumentCountIncludingThis), GPRInfo::regT1);
+
+ jit.add32(CCallHelpers::TrustedImm32(CallFrame::headerSizeInRegisters - CallerFrameAndPC::sizeInRegisters + numFrameLocals), GPRInfo::regT1, GPRInfo::regT2);
+ jit.lshift32(CCallHelpers::TrustedImm32(3), GPRInfo::regT2);
+ jit.add32(CCallHelpers::TrustedImm32(stackAlignmentBytes() - 1), GPRInfo::regT2);
+ jit.and32(CCallHelpers::TrustedImm32(-stackAlignmentBytes()), GPRInfo::regT2);
+
+ if (extraStackNeeded)
+ jit.add32(CCallHelpers::TrustedImm32(extraStackNeeded), GPRInfo::regT2);
+
+ // At this point regT1 has the actual argument count, and regT2 has the amount of stack we will need.
+ // Check to see if we have enough stack space.
+
+ jit.negPtr(GPRInfo::regT2);
+ jit.addPtr(CCallHelpers::stackPointerRegister, GPRInfo::regT2);
+ CCallHelpers::Jump haveStackSpace = jit.branchPtr(CCallHelpers::BelowOrEqual, CCallHelpers::AbsoluteAddress(vm.addressOfSoftStackLimit()), GPRInfo::regT2);
+
+ // Throw Stack Overflow exception
+ jit.copyCalleeSavesToEntryFrameCalleeSavesBuffer(vm.topEntryFrame);
+ jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, JSBoundFunction::offsetOfScopeChain()), GPRInfo::regT3);
+ jit.setupArguments<decltype(operationThrowStackOverflowErrorFromThunk)>(GPRInfo::regT3);
+ jit.prepareCallOperation(vm);
+ jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationThrowStackOverflowErrorFromThunk)), GPRInfo::nonArgGPR0);
+ emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
+ jit.call(GPRInfo::nonArgGPR0, OperationPtrTag);
+ jit.jumpToExceptionHandler(vm);
+
+ haveStackSpace.link(&jit);
+ jit.move(GPRInfo::regT2, CCallHelpers::stackPointerRegister);
+
+ // Set `this` to undefined
+ // NOTE: needs concensus in TC39 (https://github.com/tc39/proposal-shadowrealm/issues/328)
+ jit.store32(GPRInfo::regT1, CCallHelpers::calleeFramePayloadSlot(CallFrameSlot::argumentCountIncludingThis));
+ jit.storeTrustedValue(jsUndefined(), CCallHelpers::calleeArgumentSlot(0));
+
+ JSValueRegs valueRegs = JSValueRegs::withTwoAvailableRegs(GPRInfo::regT4, GPRInfo::regT2);
+
+ // Before processing the arguments loop, check that we have generated JIT code for calling
+ // to avoid processing the loop twice in the slow case.
+ CCallHelpers::Jump noCode;
+ {
+ jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, JSRemoteFunction::offsetOfTargetFunction()), GPRInfo::regT2);
+ jit.loadPtr(CCallHelpers::Address(GPRInfo::regT2, JSFunction::offsetOfExecutableOrRareData()), GPRInfo::regT2);
+ auto hasExecutable = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT2, CCallHelpers::TrustedImm32(JSFunction::rareDataTag));
+ jit.loadPtr(CCallHelpers::Address(GPRInfo::regT2, FunctionRareData::offsetOfExecutable() - JSFunction::rareDataTag), GPRInfo::regT2);
+ hasExecutable.link(&jit);
+
+ jit.loadPtr(
+ CCallHelpers::Address(
+ GPRInfo::regT2, ExecutableBase::offsetOfJITCodeWithArityCheckFor(CodeForCall)),
+ GPRInfo::regT2);
+ noCode = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT2);
+ }
+
+ CCallHelpers::JumpList exceptionChecks;
+
+ // Argument processing loop:
+ // For each argument (order should not be observable):
+ // if the value is a Primitive, copy it into the new call frame arguments, otherwise
+ // perform wrapping logic. If the wrapping logic results in a new JSRemoteFunction,
+ // copy it into the new call frame's arguments, otherwise it must have thrown a TypeError.
+ CCallHelpers::Jump done = jit.branchSub32(CCallHelpers::Zero, CCallHelpers::TrustedImm32(1), GPRInfo::regT1);
+ {
+ CCallHelpers::Label loop = jit.label();
+ jit.loadValue(CCallHelpers::addressFor(virtualRegisterForArgumentIncludingThis(0)).indexedBy(GPRInfo::regT1, CCallHelpers::TimesEight), valueRegs);
+
+ CCallHelpers::JumpList valueIsPrimitive;
+ valueIsPrimitive.append(jit.branchIfNotCell(valueRegs));
+ valueIsPrimitive.append(jit.branchIfNotObject(valueRegs.payloadGPR()));
+
+ jit.storePtr(GPRInfo::regT1, jit.addressFor(loopIndex));
+
+ jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationGetWrappedValueForTarget)), GPRInfo::nonArgGPR0);
+ emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
+
+ jit.setupArguments<decltype(operationGetWrappedValueForTarget)>(GPRInfo::regT0, valueRegs);
+ jit.prepareCallOperation(vm);
+ jit.call(GPRInfo::nonArgGPR0, OperationPtrTag);
+ exceptionChecks.append(jit.emitJumpIfException(vm));
+
+ jit.setupResults(valueRegs);
+ jit.loadCell(CCallHelpers::addressFor(CallFrameSlot::callee), GPRInfo::regT0);
+
+ jit.loadPtr(jit.addressFor(loopIndex), GPRInfo::regT1);
+
+ valueIsPrimitive.link(&jit);
+ jit.storeValue(valueRegs, CCallHelpers::calleeArgumentSlot(0).indexedBy(GPRInfo::regT1, CCallHelpers::TimesEight));
+ jit.branchSub32(CCallHelpers::NonZero, CCallHelpers::TrustedImm32(1), GPRInfo::regT1).linkTo(loop, &jit);
+
+ done.link(&jit);
+ }
+
+ jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, JSRemoteFunction::offsetOfTargetFunction()), GPRInfo::regT2);
+ jit.storeCell(GPRInfo::regT2, CCallHelpers::calleeFrameSlot(CallFrameSlot::callee));
+
+ jit.loadPtr(CCallHelpers::Address(GPRInfo::regT2, JSFunction::offsetOfExecutableOrRareData()), GPRInfo::regT0);
+ auto hasExecutable = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT0, CCallHelpers::TrustedImm32(JSFunction::rareDataTag));
+ jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, FunctionRareData::offsetOfExecutable() - JSFunction::rareDataTag), GPRInfo::regT0);
+ hasExecutable.link(&jit);
+
+ jit.loadPtr(
+ CCallHelpers::Address(
+ GPRInfo::regT0, ExecutableBase::offsetOfJITCodeWithArityCheckFor(CodeForCall)),
+ GPRInfo::regT0);
+
+ // Based on the check above, we should be good with this. On ARM64, emitPointerValidation will do this.
+#if ASSERT_ENABLED && !CPU(ARM64E)
+ {
+ CCallHelpers::Jump checkNotNull = jit.branchTestPtr(CCallHelpers::NonZero, GPRInfo::regT0);
+ jit.abortWithReason(TGInvalidPointer);
+ checkNotNull.link(&jit);
+ }
+#endif
+
+ emitPointerValidation(jit, GPRInfo::regT0, JSEntryPtrTag);
+ jit.call(GPRInfo::regT0, JSEntryPtrTag);
+
+ // Wrap return value
+#if USE(JSVALUE64)
+ JSValueRegs resultRegs(GPRInfo::returnValueGPR);
+#else
+ JSValueRegs resultRegs(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
+#endif
+
+ CCallHelpers::JumpList resultIsPrimitive;
+ resultIsPrimitive.append(jit.branchIfNotCell(resultRegs));
+ resultIsPrimitive.append(jit.branchIfNotObject(resultRegs.payloadGPR()));
+
+ jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationGetWrappedValueForCaller)), GPRInfo::nonArgGPR0);
+ emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
+
+ jit.loadCell(CCallHelpers::addressFor(CallFrameSlot::callee), GPRInfo::regT2);
+ jit.setupArguments<decltype(operationGetWrappedValueForCaller)>(GPRInfo::regT2, resultRegs);
+ jit.prepareCallOperation(vm);
+ jit.call(GPRInfo::nonArgGPR0, OperationPtrTag);
+ exceptionChecks.append(jit.emitJumpIfException(vm));
+
+ resultIsPrimitive.link(&jit);
+ jit.emitFunctionEpilogue();
+ jit.ret();
+
+ exceptionChecks.link(&jit);
+ jit.copyCalleeSavesToEntryFrameCalleeSavesBuffer(vm.topEntryFrame);
+ jit.setupArguments<decltype(operationLookupExceptionHandler)>(CCallHelpers::TrustedImmPtr(&vm));
+ jit.prepareCallOperation(vm);
+ jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationLookupExceptionHandler)), GPRInfo::nonArgGPR0);
+ emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
+ jit.call(GPRInfo::nonArgGPR0, OperationPtrTag);
+
+ jit.jumpToExceptionHandler(vm);
+
+ LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID, LinkBuffer::Profile::RemoteFunctionThunk);
+ linkBuffer.link(noCode, CodeLocationLabel<JITThunkPtrTag>(vm.jitStubs->ctiNativeTailCallWithoutSavedTags(vm)));
+ return FINALIZE_CODE(
+ linkBuffer, JITThunkPtrTag, "Specialized thunk for remote function calls");
+}
+
} // namespace JSC
#endif // ENABLE(JIT)
Modified: trunk/Source/_javascript_Core/jit/ThunkGenerators.h (289416 => 289417)
--- trunk/Source/_javascript_Core/jit/ThunkGenerators.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/jit/ThunkGenerators.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -82,6 +82,8 @@
MacroAssemblerCodeRef<JITThunkPtrTag> boundFunctionCallGenerator(VM&);
+MacroAssemblerCodeRef<JITThunkPtrTag> remoteFunctionCallGenerator(VM&);
+
#if ENABLE(EXTRA_CTI_THUNKS)
MacroAssemblerCodeRef<JITThunkPtrTag> checkExceptionGenerator(VM&);
#endif
Modified: trunk/Source/_javascript_Core/jsc.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/jsc.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/jsc.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -49,6 +49,7 @@
#include "JSBigInt.h"
#include "JSFinalizationRegistry.h"
#include "JSFunction.h"
+#include "JSFunctionInlines.h"
#include "JSInternalPromise.h"
#include "JSLock.h"
#include "JSNativeStdFunction.h"
@@ -366,6 +367,7 @@
static JSC_DECLARE_HOST_FUNCTION(functionDollarGC);
static JSC_DECLARE_HOST_FUNCTION(functionDollarClearKeptObjects);
static JSC_DECLARE_HOST_FUNCTION(functionDollarGlobalObjectFor);
+static JSC_DECLARE_HOST_FUNCTION(functionDollarIsRemoteFunction);
static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentStart);
static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentReceiveBroadcast);
static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentReport);
@@ -649,6 +651,7 @@
addFunction(vm, dollar, "gc", functionDollarGC, 0, static_cast<unsigned>(PropertyAttribute::None));
addFunction(vm, dollar, "clearKeptObjects", functionDollarClearKeptObjects, 0, static_cast<unsigned>(PropertyAttribute::None));
addFunction(vm, dollar, "globalObjectFor", functionDollarGlobalObjectFor, 1, static_cast<unsigned>(PropertyAttribute::None));
+ addFunction(vm, dollar, "isRemoteFunction", functionDollarIsRemoteFunction, 1, static_cast<unsigned>(PropertyAttribute::None));
dollar->putDirect(vm, Identifier::fromString(vm, "global"), globalThis());
dollar->putDirectCustomAccessor(vm, Identifier::fromString(vm, "IsHTMLDDA"),
@@ -2084,6 +2087,18 @@
return JSValue::encode(jsUndefined());
}
+JSC_DEFINE_HOST_FUNCTION(functionDollarIsRemoteFunction, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (callFrame->argumentCount() < 1)
+ return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Not enough arguments"_s)));
+
+ JSValue arg = callFrame->argument(0);
+ return JSValue::encode(jsBoolean(isRemoteFunction(vm, arg)));
+}
+
JSC_DEFINE_HOST_FUNCTION(functionDollarAgentStart, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
VM& vm = globalObject->vm();
Modified: trunk/Source/_javascript_Core/runtime/ErrorInstance.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/ErrorInstance.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/ErrorInstance.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -163,8 +163,9 @@
messageValue = messageSlot.getValue(globalObject, messagePropertName);
RETURN_IF_EXCEPTION(scope, { });
- if (!messageValue)
+ if (!messageValue || !messageValue.isPrimitive())
return { };
+
RELEASE_AND_RETURN(scope, messageValue.toWTFString(globalObject));
}
@@ -194,7 +195,7 @@
}
RETURN_IF_EXCEPTION(scope, { });
- if (!nameValue)
+ if (!nameValue || !nameValue.isPrimitive())
return "Error"_s;
RELEASE_AND_RETURN(scope, nameValue.toWTFString(globalObject));
}
Modified: trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -181,7 +181,7 @@
JSCell* callee = visitor->callee().asCell();
- if (callee && (callee->inherits<JSBoundFunction>(callee->vm()) || callee->type() == ProxyObjectType))
+ if (callee && (callee->inherits<JSBoundFunction>(callee->vm()) || callee->inherits<JSRemoteFunction>(callee->vm()) || callee->type() == ProxyObjectType))
return StackVisitor::Continue;
if (!m_hasFoundFrame && callee != m_targetCallee)
Modified: trunk/Source/_javascript_Core/runtime/InternalFunction.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/InternalFunction.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/InternalFunction.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -189,6 +189,10 @@
object = jsCast<JSBoundFunction*>(object)->targetFunction();
continue;
}
+ if (object->inherits<JSRemoteFunction>(vm)) {
+ object = jsCast<JSRemoteFunction*>(object)->targetFunction();
+ continue;
+ }
if (object->type() == ProxyObjectType) {
auto* proxy = jsCast<ProxyObject*>(object);
Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/Intrinsic.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -205,6 +205,8 @@
return "IsTypedArrayViewIntrinsic";
case BoundFunctionCallIntrinsic:
return "BoundFunctionCallIntrinsic";
+ case RemoteFunctionCallIntrinsic:
+ return "RemoteFunctionCallIntrinsic";
case JSMapGetIntrinsic:
return "JSMapGetIntrinsic";
case JSMapHasIntrinsic:
Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/Intrinsic.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -118,6 +118,7 @@
TypedArrayEntriesIntrinsic,
IsTypedArrayViewIntrinsic,
BoundFunctionCallIntrinsic,
+ RemoteFunctionCallIntrinsic,
JSMapGetIntrinsic,
JSMapHasIntrinsic,
JSMapSetIntrinsic,
Modified: trunk/Source/_javascript_Core/runtime/JSCast.h (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/JSCast.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/JSCast.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -99,6 +99,7 @@
macro(JSSymbolTableObject, JSType::GlobalObjectType, JSType::ModuleEnvironmentType) \
macro(JSScope, JSType::GlobalObjectType, JSType::WithScopeType) \
macro(StringObject, JSType::StringObjectType, JSType::DerivedStringObjectType) \
+ macro(ShadowRealmObject, JSType::ShadowRealmType, JSType::ShadowRealmType) \
// Forward declare the classes because they may not already exist.
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -35,6 +35,7 @@
#include "JSBoundFunction.h"
#include "JSCInlines.h"
#include "JSGlobalObject.h"
+#include "JSRemoteFunction.h"
#include "JSToWasmICCallee.h"
#include "ObjectConstructor.h"
#include "ObjectPrototype.h"
@@ -123,8 +124,8 @@
ASSERT(methodTable(vm)->getConstructData == &JSFunction::getConstructData);
ASSERT(methodTable(vm)->getCallData == &JSFunction::getCallData);
- // JSBoundFunction instances use finishCreation(VM&) overload and lazily allocate their name string / length.
- ASSERT(!this->inherits<JSBoundFunction>(vm));
+ // JSBoundFunction/JSRemoteFunction instances use finishCreation(VM&) overload and lazily allocate their name string / length.
+ ASSERT(!this->inherits<JSBoundFunction>(vm) && !this->inherits<JSRemoteFunction>(vm));
putDirect(vm, vm.propertyNames->length, jsNumber(length), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
if (!name.isNull())
@@ -252,6 +253,12 @@
JSValue string = jsMakeNontrivialString(globalObject, "function ", function->nameString(), "() {\n [native code]\n}");
RETURN_IF_EXCEPTION(scope, nullptr);
return asString(string);
+ } else if (inherits<JSRemoteFunction>(vm)) {
+ JSRemoteFunction* function = jsCast<JSRemoteFunction*>(this);
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ JSValue string = jsMakeNontrivialString(globalObject, "function ", function->nameString(), "() {\n [native code]\n}");
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ return asString(string);
}
if (isHostFunction())
@@ -571,6 +578,8 @@
double length = 0;
if (this->inherits<JSBoundFunction>(vm))
length = jsCast<JSBoundFunction*>(this)->length(vm);
+ else if (this->inherits<JSRemoteFunction>(vm))
+ length = jsCast<JSRemoteFunction*>(this)->length(vm);
else {
ASSERT(!isHostFunction());
length = jsExecutable()->parameterCount();
@@ -624,7 +633,7 @@
JSFunction::PropertyStatus JSFunction::reifyLazyPropertyIfNeeded(VM& vm, JSGlobalObject* globalObject, PropertyName propertyName)
{
- if (isHostOrBuiltinFunction() && !this->inherits<JSBoundFunction>(vm))
+ if (isHostOrBuiltinFunction() && !this->inherits<JSBoundFunction>(vm) && !this->inherits<JSRemoteFunction>(vm))
return PropertyStatus::Eager;
PropertyStatus lazyLength = reifyLazyLengthIfNeeded(vm, globalObject, propertyName);
if (isLazy(lazyLength))
@@ -638,7 +647,7 @@
JSFunction::PropertyStatus JSFunction::reifyLazyPropertyForHostOrBuiltinIfNeeded(VM& vm, JSGlobalObject* globalObject, PropertyName propertyName)
{
ASSERT(isHostOrBuiltinFunction());
- if (isBuiltinFunction() || this->inherits<JSBoundFunction>(vm)) {
+ if (isBuiltinFunction() || this->inherits<JSBoundFunction>(vm) || this->inherits<JSRemoteFunction>(vm)) {
PropertyStatus lazyLength = reifyLazyLengthIfNeeded(vm, globalObject, propertyName);
if (isLazy(lazyLength))
return lazyLength;
@@ -695,6 +704,14 @@
unsigned initialAttributes = PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly;
rareData->setHasReifiedName();
putDirect(vm, nameIdent, string, initialAttributes);
+ } else if (this->inherits<JSRemoteFunction>(vm)) {
+ FunctionRareData* rareData = this->ensureRareData(vm);
+ JSString* name = jsCast<JSRemoteFunction*>(this)->nameMayBeNull();
+ if (!name)
+ name = jsEmptyString(vm);
+ unsigned initialAttributes = PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly;
+ rareData->setHasReifiedName();
+ putDirect(vm, nameIdent, name, initialAttributes);
}
return PropertyStatus::Reified;
}
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.h (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/JSFunction.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -150,6 +150,7 @@
bool isBuiltinFunction() const;
JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const;
bool isClassConstructorFunction() const;
+ bool isRemoteFunction(VM&) const;
void setFunctionName(JSGlobalObject*, JSValue name);
Modified: trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -28,6 +28,7 @@
#include "FunctionExecutable.h"
#include "JSBoundFunction.h"
#include "JSFunction.h"
+#include "JSRemoteFunction.h"
#include "NativeExecutable.h"
namespace JSC {
@@ -78,6 +79,11 @@
return !isHostFunction() && jsExecutable()->isClassConstructorFunction();
}
+inline bool JSFunction::isRemoteFunction(VM& vm) const
+{
+ return inherits<JSRemoteFunction>(vm);
+}
+
inline TaggedNativeFunction JSFunction::nativeFunction()
{
ASSERT(isHostFunctionNonInline());
@@ -98,6 +104,11 @@
return function->nativeFunction() == nativeFunction;
}
+inline bool isRemoteFunction(VM& vm, JSValue value)
+{
+ return value.inherits<JSRemoteFunction>(vm);
+}
+
inline bool JSFunction::hasReifiedLength() const
{
if (FunctionRareData* rareData = this->rareData())
@@ -114,6 +125,8 @@
inline bool JSFunction::canAssumeNameAndLengthAreOriginal(VM&)
{
+ // JSRemoteFunction never has a 'name' field, return true
+ // to avoid allocating a FunctionRareData.
if (isHostFunction())
return false;
FunctionRareData* rareData = this->rareData();
@@ -159,7 +172,7 @@
inline JSString* JSFunction::asStringConcurrently(VM& vm) const
{
- if (inherits<JSBoundFunction>(vm))
+ if (inherits<JSBoundFunction>(vm) || inherits<JSRemoteFunction>(vm))
return nullptr;
if (isHostFunction())
return static_cast<NativeExecutable*>(executable())->asStringConcurrently();
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -140,6 +140,7 @@
#include "JSPromise.h"
#include "JSPromiseConstructor.h"
#include "JSPromisePrototype.h"
+#include "JSRemoteFunction.h"
#include "JSSet.h"
#include "JSSetIterator.h"
#include "JSStringIterator.h"
@@ -770,6 +771,10 @@
[] (const Initializer<Structure>& init) {
init.set(JSNativeStdFunction::createStructure(init.vm, init.owner, init.owner->m_functionPrototype.get()));
});
+ m_remoteFunctionStructure.initLater(
+ [] (const Initializer<Structure>& init) {
+ init.set(JSRemoteFunction::createStructure(init.vm, init.owner, init.owner->m_functionPrototype.get()));
+ });
JSFunction* callFunction = nullptr;
JSFunction* applyFunction = nullptr;
JSFunction* hasInstanceSymbolFunction = nullptr;
@@ -1531,6 +1536,14 @@
init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 0, String(), createPrivateSymbol));
});
+ // ShadowRealms
+ m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::createRemoteFunction)].initLater([] (const Initializer<JSCell>& init) {
+ init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 0, String(), createRemoteFunction));
+ });
+ m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::isRemoteFunction)].initLater([] (const Initializer<JSCell>& init) {
+ init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 0, String(), isRemoteFunction));
+ });
+
#if ENABLE(WEBASSEMBLY)
// WebAssembly Streaming API
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::webAssemblyCompileStreamingInternal)].initLater([] (const Initializer<JSCell>& init) {
@@ -2259,6 +2272,7 @@
thisObject->m_customSetterFunctionStructure.visit(visitor);
thisObject->m_boundFunctionStructure.visit(visitor);
thisObject->m_nativeStdFunctionStructure.visit(visitor);
+ thisObject->m_remoteFunctionStructure.visit(visitor);
visitor.append(thisObject->m_shadowRealmObjectStructure);
visitor.append(thisObject->m_regExpStructure);
visitor.append(thisObject->m_generatorFunctionStructure);
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -421,6 +421,7 @@
PropertyOffset m_functionNameOffset;
WriteBarrierStructureID m_shadowRealmObjectStructure;
WriteBarrierStructureID m_regExpStructure;
+
WriteBarrierStructureID m_asyncFunctionStructure;
WriteBarrierStructureID m_asyncGeneratorFunctionStructure;
WriteBarrierStructureID m_generatorFunctionStructure;
@@ -437,6 +438,7 @@
LazyProperty<JSGlobalObject, Structure> m_customGetterFunctionStructure;
LazyProperty<JSGlobalObject, Structure> m_customSetterFunctionStructure;
LazyProperty<JSGlobalObject, Structure> m_nativeStdFunctionStructure;
+ LazyProperty<JSGlobalObject, Structure> m_remoteFunctionStructure;
WriteBarrier<AsyncFunctionPrototype> m_asyncFunctionPrototype;
WriteBarrier<AsyncGeneratorFunctionPrototype> m_asyncGeneratorFunctionPrototype;
LazyProperty<JSGlobalObject, Structure> m_iteratorResultObjectStructure;
@@ -872,6 +874,7 @@
Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); }
Structure* regExpMatchesArrayWithIndicesStructure() const { return m_regExpMatchesArrayWithIndicesStructure.get(); }
Structure* regExpMatchesIndicesArrayStructure() const { return m_regExpMatchesIndicesArrayStructure.get(); }
+ Structure* remoteFunctionStructure() const { return m_remoteFunctionStructure.get(this); }
Structure* moduleRecordStructure() const { return m_moduleRecordStructure.get(this); }
Structure* moduleNamespaceObjectStructure() const { return m_moduleNamespaceObjectStructure.get(this); }
Structure* proxyObjectStructure() const { return m_proxyObjectStructure.get(this); }
Added: trunk/Source/_javascript_Core/runtime/JSRemoteFunction.cpp (0 => 289417)
--- trunk/Source/_javascript_Core/runtime/JSRemoteFunction.cpp (rev 0)
+++ trunk/Source/_javascript_Core/runtime/JSRemoteFunction.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2021 Igalia S.L.
+ * Author: Caitlin Potter <ca...@igalia.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSRemoteFunction.h"
+
+#include "ExecutableBaseInlines.h"
+#include "JSCInlines.h"
+#include "ShadowRealmObject.h"
+
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+const ClassInfo JSRemoteFunction::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRemoteFunction) };
+
+JSRemoteFunction::JSRemoteFunction(VM& vm, NativeExecutable* executable, JSGlobalObject* globalObject, Structure* structure, JSObject* targetFunction)
+ : Base(vm, executable, globalObject, structure)
+ , m_targetFunction(vm, this, targetFunction)
+ , m_length(0.0)
+{
+}
+
+static JSValue wrapValue(JSGlobalObject* globalObject, JSGlobalObject* targetGlobalObject, JSValue value)
+{
+ VM& vm = globalObject->vm();
+
+ if (value.isPrimitive())
+ return value;
+
+ if (value.isCallable(vm)) {
+ JSObject* targetFunction = static_cast<JSObject*>(value.asCell());
+ return JSRemoteFunction::create(vm, targetGlobalObject, targetFunction);
+ }
+
+ return JSValue();
+}
+
+static inline JSValue wrapArgument(JSGlobalObject* globalObject, JSGlobalObject* targetGlobalObject, JSValue value)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ JSValue result = wrapValue(globalObject, targetGlobalObject, value);
+ RETURN_IF_EXCEPTION(scope, { });
+ if (!result)
+ throwTypeError(globalObject, scope, "value passing between realms must be callable or primitive");
+ RELEASE_AND_RETURN(scope, result);
+}
+
+static inline JSValue wrapReturnValue(JSGlobalObject* globalObject, JSGlobalObject* targetGlobalObject, JSValue value)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ JSValue result = wrapValue(globalObject, targetGlobalObject, value);
+ RETURN_IF_EXCEPTION(scope, { });
+ if (!result)
+ throwTypeError(globalObject, scope, "value passing between realms must be callable or primitive");
+ RELEASE_AND_RETURN(scope, result);
+}
+
+JSC_DEFINE_HOST_FUNCTION(remoteFunctionCallForJSFunction, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ JSRemoteFunction* remoteFunction = jsCast<JSRemoteFunction*>(callFrame->jsCallee());
+ ASSERT(remoteFunction->isRemoteFunction(vm));
+ JSFunction* targetFunction = jsCast<JSFunction*>(remoteFunction->targetFunction());
+ JSGlobalObject* targetGlobalObject = targetFunction->globalObject();
+
+ MarkedArgumentBuffer args;
+ for (unsigned i = 0; i < callFrame->argumentCount(); ++i) {
+ JSValue wrappedValue = wrapArgument(globalObject, targetGlobalObject, callFrame->uncheckedArgument(i));
+ RETURN_IF_EXCEPTION(scope, { });
+ args.append(wrappedValue);
+ }
+ if (UNLIKELY(args.hasOverflowed())) {
+ throwOutOfMemoryError(globalObject, scope);
+ return { };
+ }
+ ExecutableBase* executable = targetFunction->executable();
+ if (executable->hasJITCodeForCall()) {
+ // Force the executable to cache its arity entrypoint.
+ executable->entrypointFor(CodeForCall, MustCheckArity);
+ }
+
+ auto callData = getCallData(vm, targetFunction);
+ ASSERT(callData.type != CallData::Type::None);
+ auto result = call(targetGlobalObject, targetFunction, callData, jsUndefined(), args);
+ RETURN_IF_EXCEPTION(scope, { });
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(wrapReturnValue(globalObject, globalObject, result)));
+}
+
+JSC_DEFINE_HOST_FUNCTION(remoteFunctionCallGeneric, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ JSRemoteFunction* remoteFunction = jsCast<JSRemoteFunction*>(callFrame->jsCallee());
+ ASSERT(remoteFunction->isRemoteFunction(vm));
+ JSObject* targetFunction = remoteFunction->targetFunction();
+ JSGlobalObject* targetGlobalObject = targetFunction->globalObject();
+
+ MarkedArgumentBuffer args;
+ for (unsigned i = 0; i < callFrame->argumentCount(); ++i) {
+ JSValue wrappedValue = wrapArgument(globalObject, targetGlobalObject, callFrame->uncheckedArgument(i));
+ args.append(wrappedValue);
+ }
+ if (UNLIKELY(args.hasOverflowed())) {
+ throwOutOfMemoryError(globalObject, scope);
+ return { };
+ }
+
+ auto callData = getCallData(vm, targetFunction);
+ ASSERT(callData.type != CallData::Type::None);
+ auto result = call(targetGlobalObject, targetFunction, callData, jsUndefined(), args);
+ RETURN_IF_EXCEPTION(scope, { });
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(wrapReturnValue(globalObject, targetGlobalObject, result)));
+}
+
+JSC_DEFINE_HOST_FUNCTION(isRemoteFunction, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+ ASSERT(callFrame->argumentCount() == 1);
+ JSValue value = callFrame->uncheckedArgument(0);
+ return JSValue::encode(jsBoolean(JSC::isRemoteFunction(globalObject->vm(), value)));
+}
+
+JSC_DEFINE_HOST_FUNCTION(createRemoteFunction, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ ASSERT(callFrame->argumentCount() == 2);
+ JSValue targetFunction = callFrame->uncheckedArgument(0);
+ ASSERT(targetFunction.isCallable(vm));
+
+ JSObject* targetCallable = jsCast<JSObject*>(targetFunction.asCell());
+ JSGlobalObject* destinationGlobalObject = globalObject;
+ if (!callFrame->uncheckedArgument(1).isUndefinedOrNull()) {
+ if (auto shadowRealm = jsDynamicCast<ShadowRealmObject*>(vm, callFrame->uncheckedArgument(1)))
+ destinationGlobalObject = shadowRealm->globalObject();
+ else
+ destinationGlobalObject = jsCast<JSGlobalObject*>(callFrame->uncheckedArgument(1));
+ }
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(JSRemoteFunction::create(vm, destinationGlobalObject, targetCallable)));
+}
+
+inline Structure* getRemoteFunctionStructure(JSGlobalObject* globalObject)
+{
+ // FIXME: implement globalObject-aware structure caching
+ return globalObject->remoteFunctionStructure();
+}
+
+JSRemoteFunction* JSRemoteFunction::create(VM& vm, JSGlobalObject* globalObject, JSObject* targetCallable)
+{
+ ASSERT(targetCallable && targetCallable->isCallable(vm));
+ if (auto remote = jsDynamicCast<JSRemoteFunction*>(vm, targetCallable)) {
+ targetCallable = remote->targetFunction();
+ ASSERT(!JSC::isRemoteFunction(vm, targetCallable));
+ }
+
+ bool isJSFunction = getJSFunction(targetCallable);
+ NativeExecutable* executable = vm.getRemoteFunction(isJSFunction);
+ Structure* structure = getRemoteFunctionStructure(globalObject);
+ JSRemoteFunction* function = new (NotNull, allocateCell<JSRemoteFunction>(vm)) JSRemoteFunction(vm, executable, globalObject, structure, targetCallable);
+
+ function->finishCreation(vm);
+ return function;
+}
+
+void JSRemoteFunction::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(vm, info()));
+
+ // 3.1.2: CopyNameAndLength
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ JSGlobalObject* globalObject = this->globalObject();
+
+ PropertySlot slot(m_targetFunction.get(), PropertySlot::InternalMethodType::Get);
+ bool targetHasLength = m_targetFunction->getOwnPropertySlotInline(globalObject, vm.propertyNames->length, slot);
+ RETURN_IF_EXCEPTION(scope, void());
+
+ if (targetHasLength) {
+ JSValue targetLength = slot.getValue(globalObject, vm.propertyNames->length);
+ RETURN_IF_EXCEPTION(scope, void());
+ double targetLengthAsInt = targetLength.toIntegerOrInfinity(globalObject);
+ RETURN_IF_EXCEPTION(scope, void());
+ m_length = std::max(targetLengthAsInt, 0.0);
+ }
+
+ JSValue targetName = JSValue(m_targetFunction.get()).get(globalObject, vm.propertyNames->name);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (targetName.isString())
+ m_nameMayBeNull.set(vm, this, asString(targetName));
+
+ scope.release();
+}
+
+template<typename Visitor>
+void JSRemoteFunction::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ JSRemoteFunction* thisObject = jsCast<JSRemoteFunction*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(thisObject->m_targetFunction);
+ visitor.append(thisObject->m_nameMayBeNull);
+}
+
+DEFINE_VISIT_CHILDREN(JSRemoteFunction);
+
+} // namespace JSC
Added: trunk/Source/_javascript_Core/runtime/JSRemoteFunction.h (0 => 289417)
--- trunk/Source/_javascript_Core/runtime/JSRemoteFunction.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/JSRemoteFunction.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 Igalia S.L.
+ * Author: Caitlin Potter <ca...@igalia.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "AuxiliaryBarrier.h"
+#include "JSObject.h"
+#include <wtf/TaggedArrayStoragePtr.h>
+
+namespace JSC {
+
+JSC_DECLARE_HOST_FUNCTION(remoteFunctionCallForJSFunction);
+JSC_DECLARE_HOST_FUNCTION(remoteFunctionCallGeneric);
+JSC_DECLARE_HOST_FUNCTION(isRemoteFunction);
+JSC_DECLARE_HOST_FUNCTION(createRemoteFunction);
+
+// JSRemoteFunction creates a bridge between its native Realm and a remote one.
+// When invoked, arguments are wrapped to prevent leaking information across the realm boundary.
+// The return value and any abrupt completions are also filtered.
+class JSRemoteFunction final : public JSFunction {
+public:
+ using Base = JSFunction;
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+
+ template<typename CellType, SubspaceAccess mode>
+ static IsoSubspace* subspaceFor(VM& vm)
+ {
+ return vm.remoteFunctionSpace<mode>();
+ }
+
+ JS_EXPORT_PRIVATE static JSRemoteFunction* create(VM&, JSGlobalObject*, JSObject* targetCallable);
+
+ JSObject* targetFunction() { return m_targetFunction.get(); }
+ JSGlobalObject* targetGlobalObject() { return targetFunction()->globalObject(); }
+ JSString* nameMayBeNull() const { return m_nameMayBeNull.get(); }
+ const String& nameString()
+ {
+ if (!m_nameMayBeNull)
+ return emptyString();
+ ASSERT(!m_nameMayBeNull->isRope());
+ bool allocationAllowed = false;
+ return m_nameMayBeNull->tryGetValue(allocationAllowed);
+ }
+
+ double length(VM&) const { return m_length; }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ ASSERT(globalObject);
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
+ }
+
+ static ptrdiff_t offsetOfTargetFunction() { return OBJECT_OFFSETOF(JSRemoteFunction, m_targetFunction); }
+
+ DECLARE_EXPORT_INFO;
+
+private:
+ JSRemoteFunction(VM&, NativeExecutable*, JSGlobalObject*, Structure*, JSObject* targetCallable);
+
+ void finishCreation(VM&);
+ DECLARE_VISIT_CHILDREN;
+
+ WriteBarrier<JSObject> m_targetFunction;
+ WriteBarrier<JSString> m_nameMayBeNull;
+ double m_length;
+};
+
+}
Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/VM.cpp 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp 2022-02-08 20:42:04 UTC (rev 289417)
@@ -632,6 +632,8 @@
return randomThunkGenerator;
case BoundFunctionCallIntrinsic:
return boundFunctionCallGenerator;
+ case RemoteFunctionCallIntrinsic:
+ return remoteFunctionCallGenerator;
default:
return nullptr;
}
@@ -709,6 +711,25 @@
return getOrCreate(m_fastBoundExecutable);
}
+NativeExecutable* VM::getRemoteFunction(bool isJSFunction)
+{
+ bool slowCase = !isJSFunction;
+ auto getOrCreate = [&] (Weak<NativeExecutable>& slot) -> NativeExecutable* {
+ if (auto* cached = slot.get())
+ return cached;
+ NativeExecutable* result = getHostFunction(
+ slowCase ? remoteFunctionCallGeneric : remoteFunctionCallForJSFunction,
+ slowCase ? NoIntrinsic : RemoteFunctionCallIntrinsic,
+ callHostFunctionAsConstructor, nullptr, String());
+ slot = Weak<NativeExecutable>(result);
+ return result;
+ };
+
+ if (slowCase)
+ return getOrCreate(m_slowRemoteFunctionExecutable);
+ return getOrCreate(m_fastRemoteFunctionExecutable);
+}
+
MacroAssemblerCodePtr<JSEntryPtrTag> VM::getCTIInternalFunctionTrampolineFor(CodeSpecializationKind kind)
{
#if ENABLE(JIT)
Modified: trunk/Source/_javascript_Core/runtime/VM.h (289416 => 289417)
--- trunk/Source/_javascript_Core/runtime/VM.h 2022-02-08 20:25:39 UTC (rev 289416)
+++ trunk/Source/_javascript_Core/runtime/VM.h 2022-02-08 20:42:04 UTC (rev 289417)
@@ -432,6 +432,7 @@
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(nativeStdFunctionSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(proxyObjectSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(proxyRevokeSpace)
+ DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(remoteFunctionSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(scopedArgumentsTableSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(scriptFetchParametersSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(scriptFetcherSpace)
@@ -572,6 +573,9 @@
Weak<NativeExecutable> m_slowBoundExecutable;
Weak<NativeExecutable> m_slowCanConstructBoundExecutable;
+ Weak<NativeExecutable> m_fastRemoteFunctionExecutable;
+ Weak<NativeExecutable> m_slowRemoteFunctionExecutable;
+
Ref<DeferredWorkTimer> deferredWorkTimer;
JSCell* currentlyDestructingCallbackObject;
@@ -686,6 +690,7 @@
NativeExecutable* getHostFunction(NativeFunction, Intrinsic, NativeFunction constructor, const DOMJIT::Signature*, const String& name);
NativeExecutable* getBoundFunction(bool isJSFunction, bool canConstruct);
+ NativeExecutable* getRemoteFunction(bool isJSFunction);
MacroAssemblerCodePtr<JSEntryPtrTag> getCTIInternalFunctionTrampolineFor(CodeSpecializationKind);
MacroAssemblerCodeRef<JSEntryPtrTag> getCTILinkCall();