8000 [WASM-Function-References] Add ref.as_non_null instruction · WebKit/WebKit@cdfc2fb · GitHub
[go: up one dir, main page]

Skip to content

Commit cdfc2fb

Browse files
committed
[WASM-Function-References] Add ref.as_non_null instruction
https://bugs.webkit.org/show_bug.cgi?id=251037 Reviewed by Justin Michaud. Adds the ref.as_non_null instruction, which checks for non-null (and traps if null) and returns a non-null reference. * JSTests/wasm.yaml: * JSTests/wasm/function-references-spec-tests/ref_as_non_null.wast.js: Added. * JSTests/wasm/function-references/ref_as_non_null.js: Added. (module): (async ref_as_non_null): * JSTests/wasm/wasm.json: * Source/JavaScriptCore/bytecode/BytecodeList.rb: * Source/JavaScriptCore/llint/WebAssembly32_64.asm: * Source/JavaScriptCore/llint/WebAssembly64.asm: * Source/JavaScriptCore/wasm/WasmAirIRGeneratorBase.h: (JSC::Wasm::ExpressionType>::addRefAsNonNull): * Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp: (JSC::Wasm::B3IRGenerator::addRefAsNonNull): * Source/JavaScriptCore/wasm/WasmExceptionType.h: (JSC::Wasm::isTypeErrorExceptionType): * Source/JavaScriptCore/wasm/WasmFunctionParser.h: (JSC::Wasm::FunctionParser<Context>::parseExpression): (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression): * Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp: (JSC::Wasm::LLIntGenerator::addRefAsNonNull): * Source/JavaScriptCore/wasm/wasm.json: Canonical link: https://commits.webkit.org/259420@main
1 parent 537d68a commit cdfc2fb

File tree

13 files changed

+145
-1
lines changed

13 files changed

+145
-1
lines changed

JSTests/wasm.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565

6666
- path: wasm/function-references-spec-tests/call_ref.wast.js
6767
cmd: runWebAssemblyFunctionReferenceSpecTest :normal
68+
- path: wasm/function-references-spec-tests/ref_as_non_null.wast.js
69+
cmd: runWebAssemblyFunctionReferenceSpecTest :normal
6870
- path: wasm/function-references-spec-tests/ref_null.wast.js
6971
cmd: runWebAssemblyFunctionReferenceSpecTest :normal
7072
- path: wasm/function-references-spec-tests/call-null-ref.wast.js
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// ref_as_non_null.wast:1
2+
let $1 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x91\x80\x80\x80\x00\x03\x60\x00\x01\x7f\x60\x01\x6b\x00\x01\x7f\x60\x01\x6c\x00\x01\x7f\x03\x88\x80\x80\x80\x00\x07\x01\x02\x00\x00\x00\x00\x00\x07\xbc\x80\x80\x80\x00\x04\x0d\x6e\x75\x6c\x6c\x61\x62\x6c\x65\x2d\x6e\x75\x6c\x6c\x00\x03\x0d\x6e\x6f\x6e\x6e\x75\x6c\x6c\x61\x62\x6c\x65\x2d\x66\x00\x04\x0a\x6e\x75\x6c\x6c\x61\x62\x6c\x65\x2d\x66\x00\x05\x0b\x75\x6e\x72\x65\x61\x63\x68\x61\x62\x6c\x65\x00\x06\x09\x85\x80\x80\x80\x00\x01\x01\x00\x01\x02\x0a\xce\x80\x80\x80\x00\x07\x87\x80\x80\x80\x00\x00\x20\x00\xd3\x14\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\xd3\x14\x00\x0b\x84\x80\x80\x80\x00\x00\x41\x07\x0b\x86\x80\x80\x80\x00\x00\xd0\x00\x10\x01\x0b\x86\x80\x80\x80\x00\x00\xd2\x02\x10\x00\x0b\x86\x80\x80\x80\x00\x00\xd2\x02\x10\x01\x0b\x86\x80\x80\x80\x00\x00\x00\xd3\x10\x00\x0b");
3+
4+
// ref_as_non_null.wast:25
5+
assert_trap(() => call($1, "unreachable", []));
6+
7+
// ref_as_non_null.wast:27
8+
assert_trap(() => call($1, "nullable-null", []));
9+
10+
// ref_as_non_null.wast:28
11+
assert_return(() => call($1, "nonnullable-f", []), 7);
12+
13+
// ref_as_non_null.wast:29
14+
assert_return(() => call($1, "nullable-f", []), 7);
15+
16+
// ref_as_non_null.wast:31
17+
assert_invalid("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8d\x80\x80\x80\x00\x03\x60\x00\x01\x7f\x60\x01\x6b\x00\x00\x60\x00\x00\x03\x83\x80\x80\x80\x00\x02\x01\x02\x0a\x97\x80\x80\x80\x00\x02\x86\x80\x80\x80\x00\x00\x20\x00\xd3\x1a\x0b\x86\x80\x80\x80\x00\x00\xd0\x00\x10\x00\x0b");
18+
19+
// ref_as_non_null.wast:41
20+
let $2 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x93\x80\x80\x80\x00\x04\x60\x00\x00\x60\x01\x6b\x00\x00\x60\x01\x6b\x70\x00\x60\x01\x6b\x6f\x00\x03\x84\x80\x80\x80\x00\x03\x01\x02\x03\x0a\xa2\x80\x80\x80\x00\x03\x86\x80\x80\x80\x00\x00\x20\x00\xd3\x1a\x0b\x86\x80\x80\x80\x00\x00\x20\x00\xd3\x1a\x0b\x86\x80\x80\x80\x00\x00\x20\x00\xd3\x1a\x0b");
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//@ runWebAssemblySuite("--useWebAssemblyTypedFunctionReferences=true")
2+
import * as assert from '../assert.js';
3+
import { instantiate } from "../wabt-wrapper.js";
4+
5+
function module(bytes, valid = true) {
6+
let buffer = new ArrayBuffer(bytes.length);
7+
let view = new Uint8Array(buffer);
8+
for (let i = 0; i < bytes.length; ++i) {
9+
view[i] = bytes.charCodeAt(i);
10+
}
11+
return new WebAssembly.Module(buffer);
12+
}
13+
14+
async function ref_as_non_null() {
15+
/*
16+
(module
17+
(type $t (func))
18+
(elem declare funcref (ref.func $foo))
19+
(func $foo)
20+
(func $f (result (ref null $t)) (ref.func $foo))
21+
(func (export "main") (result (ref $t))
22+
(ref.as_non_null (call $f)))
23+
)
24+
*/
25+
let instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8e\x80\x80\x80\x00\x03\x60\x00\x00\x60\x00\x01\x6c\x00\x60\x00\x01\x6b\x00\x03\x84\x80\x80\x80\x00\x03\x00\x01\x02\x07\x88\x80\x80\x80\x00\x01\x04\x6d\x61\x69\x6e\x00\x02\x09\x87\x80\x80\x80\x00\x01\x07\x70\x01\xd2\x00\x0b\x0a\x9b\x80\x80\x80\x00\x03\x82\x80\x80\x80\x00\x00\x0b\x84\x80\x80\x80\x00\x00\xd2\x00\x0b\x85\x80\x80\x80\x00\x00\x10\x01\xd3\x0b"));
26+
instance.exports.main();
27+
28+
/*
29+
(module
30+
(type $t (func))
31+
(elem declare funcref (ref.func $foo))
32+
(func $foo)
33+
(func $f (result (ref null $t)) (ref.null $t))
34+
(func (export "main") (result (ref $t))
35+
(ref.as_non_null (call $f)))
36+
)
37+
*/
38+
assert.throws(
39+
() => new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8e\x80\x80\x80\x00\x03\x60\x00\x00\x60\x00\x01\x6c\x00\x60\x00\x01\x6b\x00\x03\x84\x80\x80\x80\x00\x03\x00\x01\x02\x07\x88\x80\x80\x80\x00\x01\x04\x6d\x61\x69\x6e\x00\x02\x09\x87\x80\x80\x80\x00\x01\x07\x70\x01\xd2\x00\x0b\x0a\x9b\x80\x80\x80\x00\x03\x82\x80\x80\x80\x00\x00\x0b\x84\x80\x80\x80\x00\x00\xd0\x00\x0b\x85\x80\x80\x80\x00\x00\x10\x01\xd3\x0b")).exports.main(),
40+
WebAssembly.RuntimeError,
41+
"ref.as_non_null to a null reference (evaluating 'func(...args)')"
42+
)
43+
}
44+
45+
assert.asyncTest(ref_as_non_null());

JSTests/wasm/wasm.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
"ref.null": { "category": "special", "value": 208, "return": ["externref", "funcref"], "parameter": [], "immediate": [{"name": "reftype", "type": "ref_type"}], "description": "a constant null reference" },
8989
"ref.is_null": { "category": "special", "value": 209, "return": ["i32"], "parameter": ["externref"], "immediate": [], "description": "determine if a reference is null" },
9090
"ref.func": { "category": "special", "value": 210, "return": ["funcref"], "parameter": [], "immediate": [{"name": "function_index", "type": "varuint32"}], "description": "return a reference to the function at the given index" },
91+
"ref.as_non_null": { "category": "special", "value": 211, "return": ["any"], "parameter": ["any"], "immediate": [], "description": "return the reference with non-null type or trap if null" },
9192
"get_local": { "category": "special", "value": 32, "return": ["any"], "parameter": [], "immediate": [{"name": "local_index", "type": "varuint32"}], "description": "read a local variable or parameter" },
9293
"set_local": { "category": "special", "value": 33, "return": [], "parameter": ["any"], "immediate": [{"name": "local_index", "type": "varuint32"}], "description": "write a local variable or parameter" },
9394
"tee_local": { "category": "special", "value": 34, "return": ["any"], "parameter": ["any"], "immediate": [{"name": "local_index", "type": "varuint32"}], "description": "write a local variable or parameter and return the same value" },

Source/JavaScriptCore/bytecode/BytecodeList.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,12 @@
15881588
functionIndex: unsigned,
15891589
}
15901590

1591+
op :ref_as_non_null,
1592+
args: {
1593+
dst: VirtualRegister,
1594+
ref: VirtualRegister,
1595+
}
1596+
15911597
op :get_global,
15921598
args: {
15931599
dst: VirtualRegister,

Source/JavaScriptCore/llint/WebAssembly32_64.asm

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,15 @@ wasmOp(ref_is_null, WasmRefIsNull, macro(ctx)
156156
returni(ctx, t0)
157157
end)
158158

159+
wasmOp(ref_as_non_null, WasmRefAsNonNull, macro(ctx)
160+
mload2i(ctx, m_ref, t1, t0)
161+
bieq t1, NullTag, .nullRef
162+
returni(ctx, t0)
163+
164+
.nullRef:
165+
throwException(NullRefAsNonNull)
166+
end)
167+
159168
wasmOp(get_global, WasmGetGlobal, macro(ctx)
160169
loadp Wasm::Instance::m_globals[wasmInstance], t0
161170
wgetu(ctx, m_globalIndex, t1)

Source/JavaScriptCore/llint/WebAssembly64.asm

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ wasmOp(ref_is_null, WasmRefIsNull, macro(ctx)
104104
returni(ctx, t0)
105105
end)
106106

107+
wasmOp(ref_as_non_null, WasmRefAsNonNull, macro(ctx)
108+
mloadp(ctx, m_ref, t0)
109+
bqeq t0, ValueNull, .nullRef
110+
returnq(ctx, t0)
111+
112+
.nullRef:
113+
throwException(NullRefAsNonNull)
114+
end)
115+
107116
wasmOp(get_global, WasmGetGlobal, macro(ctx)
108117
loadp Wasm::Instance::m_globals[wasmInstance], t0
109118
wgetu(ctx, m_globalIndex, t1)

Source/JavaScriptCore/wasm/WasmAirIRGeneratorBase.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ struct AirIRGeneratorBase {
362362
// References
363363
// addRefIsNull (in derived classes)
364364
PartialResult WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
365+
PartialResult WARN_UNUSED_RETURN addRefAsNonNull(ExpressionType, ExpressionType&);
365366

366367
// Tables
367368
PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType index, ExpressionType& result);
@@ -1245,6 +1246,15 @@ auto AirIRGeneratorBase<Derived, ExpressionType>::addRefFunc(uint32_t index, Exp
12451246
return { };
12461247
}
12471248

1249+
template <typename Derived, typename ExpressionType>
1250+
auto AirIRGeneratorBase<Derived, ExpressionType>::addRefAsNonNull(ExpressionType reference, ExpressionType& result) -> PartialResult
1251+
{
1252+
emitThrowOnNullReference(reference, ExceptionType::NullRefAsNonNull);
1253+
result = self().tmpForType(Type { TypeKind::Ref, reference.type().index });
1254+
append(Move, reference, result);
1255+
return { };
1256+
}
1257+
12481258
template <typename Derived, typename ExpressionType>
12491259
auto AirIRGeneratorBase<Derived, ExpressionType>::addTableGet(unsigned tableIndex, ExpressionType index, ExpressionType& result) -> PartialResult
12501260
{

Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ class B3IRGenerator {
529529
// References
530530
PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType value, ExpressionType& result);
531531
PartialResult WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
532+
PartialResult WARN_UNUSED_RETURN addRefAsNonNull(ExpressionType, ExpressionType&);
532533

533534
// Tables
534535
PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType index, ExpressionType& result);
@@ -1295,6 +1296,19 @@ auto B3IRGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> Partia
12951296
return { };
12961297
}
12971298

1299+
auto B3IRGenerator::addRefAsNonNull(ExpressionType reference, ExpressionType& result) -> PartialResult
1300+
{
1301+
result = push(get(reference));
1302+
{
1303+
CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
1304+
m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), get(reference), m_currentBlock->appendNew<Const64Value>(m_proc, origin(), JSValue::encode(jsNull()))));
1305+
check->setGenerator([=, this] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
1306+
this->emitExceptionCheck(jit, ExceptionType::NullRefAsNonNull);
1307+
});
1308+
}
1309+
return { };
1310+
}
1311+
12981312
auto B3IRGenerator::addTableInit(unsigned elementIndex, unsigned tableIndex, ExpressionType dstOffset, ExpressionType srcOffset, ExpressionType length) -> PartialResult
12991313
{
13001314
Value* resultValue = callWasmOperation(m_currentBlock, toB3Type(Types::I32), operationWasmTableInit,

Source/JavaScriptCore/wasm/WasmExceptionType.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ namespace Wasm {
5353
macro(NullArrayGet, "array.get to a null reference"_s) \
5454
macro(NullArraySet, "array.set to a null reference"_s) \
5555
macro(NullArrayLen, "array.len to a null reference"_s) \
56-
macro(TypeErrorInvalidV128Use, "an exported wasm function cannot contain a v128 parameter or return value"_s)
56+
macro(TypeErrorInvalidV128Use, "an exported wasm function cannot contain a v128 parameter or return value"_s) \
57+
macro(NullRefAsNonNull, "ref.as_non_null to a null reference"_s)
5758

5859
enum class ExceptionType : uint32_t {
5960
#define MAKE_ENUM(enumName, error) enumName,
@@ -94,6 +95,7 @@ ALWAYS_INLINE bool isTypeErrorExceptionType(ExceptionType type)
9495
case ExceptionType::NullArrayGet:
9596
case ExceptionType::NullArraySet:
9697
case ExceptionType::NullArrayLen:
98+
case ExceptionType::NullRefAsNonNull:
97< 436E /code>99
return false;
98100
case ExceptionType::FuncrefNotWasm:
99101
case ExceptionType::InvalidGCTypeUse:

0 commit comments

Comments
 (0)
0