(rawFn, signature)
| 199 | // reads the return value back only after, so nested/reentrant calls into |
| 200 | // the same function are safe. |
| 201 | function wrapWithSharedBuffer(rawFn, signature) { |
| 202 | if (rawFn == null) return rawFn; |
| 203 | const buffer = rawFn[kSbSharedBuffer]; |
| 204 | if (buffer === undefined) return rawFn; |
| 205 | |
| 206 | // Callers without explicit signature info (the `functions` accessor |
| 207 | // patch below) rely on the `kSbArguments` / `kSbReturn` metadata attached |
| 208 | // by the native `CreateFunction`. |
| 209 | let argumentTypes, returnType; |
| 210 | if (signature === undefined) { |
| 211 | argumentTypes = rawFn[kSbArguments]; |
| 212 | returnType = rawFn[kSbReturn]; |
| 213 | |
| 214 | // `CreateFunction` always attaches these for SB-eligible functions. |
| 215 | // Missing here means the native side and this wrapper are out of sync. |
| 216 | assert(argumentTypes !== undefined && returnType !== undefined, |
| 217 | 'FFI: shared-buffer raw function is missing kSbArguments or kSbReturn'); |
| 218 | } else { |
| 219 | argumentTypes = signature.arguments ?? []; |
| 220 | returnType = signature.return ?? 'void'; |
| 221 | } |
| 222 | |
| 223 | const slowInvoke = rawFn[kSbInvokeSlow]; |
| 224 | const view = new DataView(buffer); |
| 225 | let retGetter = null; |
| 226 | if (returnType !== 'void') { |
| 227 | const retInfo = sbTypeInfo[returnType]; |
| 228 | assert(retInfo !== undefined, |
| 229 | `FFI: shared-buffer type table missing entry for return type "${returnType}"`); |
| 230 | retGetter = retInfo.get; |
| 231 | } |
| 232 | |
| 233 | const nargs = argumentTypes.length; |
| 234 | const argInfos = []; |
| 235 | const argOffsets = []; |
| 236 | let anyPointer = false; |
| 237 | for (let i = 0; i < nargs; i++) { |
| 238 | const info = sbTypeInfo[argumentTypes[i]]; |
| 239 | assert(info !== undefined, |
| 240 | `FFI: shared-buffer type table missing entry for argument type "${argumentTypes[i]}"`); |
| 241 | // Push the `sbTypeInfo` entry directly (entries with the same `kind` |
| 242 | // share a shape, keeping `writeNumericArg`'s call sites |
| 243 | // low-polymorphism) and store offsets in a parallel array to avoid |
| 244 | // per-arg object cloning. |
| 245 | argInfos.push(info); |
| 246 | argOffsets.push(8 * (i + 1)); |
| 247 | if (info.kind === 'pointer') anyPointer = true; |
| 248 | } |
| 249 | |
| 250 | let wrapper; |
| 251 | if (anyPointer) { |
| 252 | // Pointer signatures need a per-arg runtime type check and fall back |
| 253 | // to the native slow-path invoker for non-BigInt pointer arguments, |
| 254 | // so arity specialization wouldn't buy much here. |
| 255 | assert(slowInvoke !== undefined, |
| 256 | 'FFI: shared-buffer raw function with pointer arguments is missing kSbInvokeSlow'); |
| 257 | wrapper = function(...args) { |
| 258 | if (args.length !== nargs) { |
no test coverage detected
searching dependent graphs…