forked from WebKit/WebKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Wasm-GC] Add extern.internalize/externalize
https://bugs.webkit.org/show_bug.cgi?id=251039 Reviewed by Justin Michaud. Adds extern conversion instructions to convert between anyref (internal references) and externref. The any to extern direction is currently a no-op. The extern to any direction requires checking for Numbers in the i31 range and converting them to i31ref representation. The any to extern is a no-op because JSC's value representation allows i31s to just be JSC 32-bit exact integers, and structs and arrays are represented as objects. This would need to change if the representation were to change, so that, e.g., structs and arrays have an optimized non-object wasm representation and a wrapper object is used to interop with JS. The addition of internalize means non-Wasm values (JS objects, strings, etc) can be converted into an internal reference as "host references" that are opaque to Wasm. These need to be distinguishable from true Wasm values, including in JIT code, which requires adding a WasmGCObjectType JSType. * JSTests/wasm/gc/extern.js: Added. (testInternalize): (testRoundtrip): (testTable): * JSTests/wasm/wasm.json: * Source/JavaScriptCore/bytecode/BytecodeList.rb: * Source/JavaScriptCore/llint/WebAssembly32_64.asm: * Source/JavaScriptCore/llint/WebAssembly64.asm: * Source/JavaScriptCore/runtime/JSType.cpp: (WTF::printInternal): * Source/JavaScriptCore/runtime/JSType.h: * Source/JavaScriptCore/wasm/WasmAirIRGeneratorBase.h: (JSC::Wasm::ExpressionType>::emitRefTestOrCast): (JSC::Wasm::ExpressionType>::makeBranchNotWasmGCObject): (JSC::Wasm::ExpressionType>::addExternInternalize): (JSC::Wasm::ExpressionType>::addExternExternalize): * Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp: (JSC::Wasm::B3IRGenerator::emitRefTestOrCast): (JSC::Wasm::B3IRGenerator::addExternInternalize): (JSC::Wasm::B3IRGenerator::addExternExternalize): * Source/JavaScriptCore/wasm/WasmBBQJIT.cpp: (JSC::Wasm::BBQJIT::addExternInternalize): (JSC::Wasm::BBQJIT::addExternExternalize): * Source/JavaScriptCore/wasm/WasmFormat.h: (JSC::Wasm::externrefType): (JSC::Wasm::anyrefType): * Source/JavaScriptCore/wasm/WasmFunctionParser.h: (JSC::Wasm::FunctionParser<Context>::parseExpression): * Source/JavaScriptCore/wasm/WasmLLIntBuiltin.h: * Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp: (JSC::Wasm::LLIntGenerator::addExternInternalize): (JSC::Wasm::LLIntGenerator::addExternExternalize): * Source/JavaScriptCore/wasm/WasmOperations.cpp: (JSC::Wasm::JSC_DEFINE_JIT_OPERATION): * Source/JavaScriptCore/wasm/WasmOperations.h: * Source/JavaScriptCore/wasm/WasmOperationsInlines.h: (JSC::Wasm::refCast): (JSC::Wasm::externInternalize): * Source/JavaScriptCore/wasm/WasmSlowPaths.cpp: (JSC::LLInt::WASM_SLOW_PATH_DECL): * Source/JavaScriptCore/wasm/WasmTypeDefinition.cpp: (JSC::Wasm::TypeInformation::signatureForLLIntBuiltin): (JSC::Wasm::TypeInformation::TypeInformation): * Source/JavaScriptCore/wasm/WasmTypeDefinition.h: * Source/JavaScriptCore/wasm/js/JSWebAssemblyArray.h: * Source/JavaScriptCore/wasm/js/JSWebAssemblyStruct.h: * Source/JavaScriptCore/wasm/wasm.json: Canonical link: https://commits.webkit.org/262282@main
- Loading branch information
Showing
23 changed files
with
425 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
//@ runWebAssemblySuite("--useWebAssemblyTypedFunctionReferences=true", "--useWebAssemblyGC=true") | ||
|
||
import * as assert from "../assert.js"; | ||
import { compile, instantiate } from "./wast-wrapper.js"; | ||
|
||
function testInternalize() { | ||
{ | ||
let m = instantiate(` | ||
(module | ||
(func (export "f") (param externref) (result i32) | ||
(i31.get_s (ref.cast i31 (extern.internalize (local.get 0))))) | ||
) | ||
`); | ||
assert.eq(m.exports.f(0), 0); | ||
assert.eq(m.exports.f(5), 5); | ||
assert.eq(m.exports.f(5.0), 5); | ||
assert.eq(m.exports.f(2 ** 30 - 1), 2 ** 30 - 1); | ||
assert.eq(m.exports.f(-(2 ** 30)), -(2 ** 30)); | ||
assert.throws( | ||
() => m.exports.f(2 ** 30), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
assert.throws( | ||
() => m.exports.f(2 ** 32), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
assert.throws( | ||
() => m.exports.f(-(2 ** 30) - 1), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
assert.throws( | ||
() => m.exports.f(5.3), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
assert.throws( | ||
() => m.exports.f("foo"), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
assert.throws( | ||
() => m.exports.f(Symbol()), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
} | ||
|
||
// With internalize available, it's possible to create hostref values that | ||
// need to be distinguished from eqref values. | ||
{ | ||
let m = instantiate(` | ||
(module | ||
(func (export "f") (param externref) | ||
(ref.cast eq (extern.internalize (local.get 0))) | ||
drop) | ||
) | ||
`); | ||
m.exports.f(0); | ||
assert.throws( | ||
() => m.exports.f("foo"), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
assert.throws( | ||
() => m.exports.f(2 ** 32), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
assert.throws( | ||
() => m.exports.f(Symbol()), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
} | ||
|
||
{ | ||
let m = instantiate(` | ||
(module | ||
(func (export "f") (param externref) | ||
(ref.cast array (extern.internalize (local.get 0))) | ||
drop) | ||
) | ||
`); | ||
assert.throws( | ||
() => m.exports.f("foo"), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
assert.throws( | ||
() => m.exports.f(2 ** 32), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
assert.throws( | ||
() => m.exports.f(Symbol()), | ||
WebAssembly.RuntimeError, | ||
"ref.cast failed to cast reference to target heap type" | ||
); | ||
} | ||
} | ||
|
||
function testExternalize() { | ||
{ | ||
let m = instantiate(` | ||
(module | ||
(func (export "f") (param i32) (result externref) | ||
(extern.externalize (i31.new (local.get 0)))) | ||
) | ||
`); | ||
assert.eq(m.exports.f(0), 0); | ||
assert.eq(m.exports.f(5), 5); | ||
} | ||
|
||
{ | ||
let m = instantiate(` | ||
(module | ||
(type (array i32)) | ||
(func (export "f") (result externref) | ||
(extern.externalize (array.new_canon 0 (i32.const 42) (i32.const 5)))) | ||
) | ||
`); | ||
assert.eq(typeof m.exports.f(), "object"); | ||
} | ||
} | ||
|
||
function testRoundtrip() { | ||
{ | ||
let m = instantiate(` | ||
(module | ||
(func (param anyref) (result anyref) | ||
(extern.internalize (extern.externalize (local.get 0)))) | ||
(func (export "f") (param i32) (result i32) | ||
(i31.get_s (ref.cast i31 (call 0 (i31.new (local.get 0)))))) | ||
) | ||
`); | ||
assert.eq(m.exports.f(0), 0); | ||
assert.eq(m.exports.f(5), 5); | ||
assert.eq(m.exports.f(2**30 - 1), 2**30 - 1); | ||
} | ||
|
||
{ | ||
let m = instantiate(` | ||
(module | ||
(type (array i32)) | ||
(func (param anyref) (result anyref) | ||
(extern.internalize (extern.externalize (local.get 0)))) | ||
(func (export "f") (result i32) | ||
(array.get 0 | ||
(ref.cast 0 (call 0 (array.new_canon 0 (i32.const 42) (i32.const 5)))) | ||
(i32.const 0))) | ||
) | ||
`); | ||
assert.eq(m.exports.f(), 42); | ||
} | ||
} | ||
|
||
function testTable() { | ||
{ | ||
let m = instantiate(` | ||
(module | ||
(type (struct)) | ||
(table (export "t") 10 externref) | ||
(func (table.set (i32.const 0) (extern.externalize (struct.new_canon 0)))) | ||
(func (export "isStruct") (result i32) | ||
(ref.test 0 (extern.internalize (table.get (i32.const 1))))) | ||
(start 0) | ||
) | ||
`); | ||
assert.eq(m.exports.t.get(0) !== null, true); | ||
assert.eq(m.exports.t.get(1), null); | ||
m.exports.t.set(1, m.exports.t.get(0)); | ||
assert.eq(m.exports.t.get(1) !== null, true); | ||
assert.eq(m.exports.isStruct(), 1); | ||
} | ||
} | ||
|
||
testInternalize(); | ||
testExternalize(); | ||
testRoundtrip(); | ||
testTable(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.