Title: [289417] trunk
Revision
289417
Author
ca...@igalia.com
Date
2022-02-08 12:42:04 -0800 (Tue, 08 Feb 2022)

Log Message

[JSC] move function wrapping logic to a new Function type
https://bugs.webkit.org/show_bug.cgi?id=235382

Reviewed by Yusuke Suzuki.

JSTests:

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.

Source/_javascript_Core:

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:

Modified Paths

Added Paths

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();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to