Skip to content

Commit

Permalink
Cherry-pick 50c7aae. rdar://problem/110417987
Browse files Browse the repository at this point in the history
    Fixup air pointer args if they are not valid in BBQ
    https://bugs.webkit.org/show_bug.cgi?id=251890
    rdar://105079565

    Reviewed by Mark Lam and Yusuke Suzuki.

    We are not fixing up air args if their offsets don't fit into the instruction
    in a few cases.

    Here are some examples:

    MoveDouble 28480(%sp), %q16 ; too big
    MoveVector 248(%sp), %q16 ; not 16-byte aligned

    Let's fix up these arguments. We also fix a missing validation check
    when parsing exception tags exposed by this test.

    * Source/JavaScriptCore/wasm/WasmAirIRGenerator64.cpp:
    (JSC::Wasm::AirIRGenerator64::addReturn):
    * Source/JavaScriptCore/wasm/WasmAirIRGeneratorBase.h:
    (JSC::Wasm::AirIRGeneratorBase::emitPatchpoint):

    oops

    Canonical link: https://commits.webkit.org/260038@main

Canonical link: https://commits.webkit.org/245886.878@safari-7613.4.1.0-branch
  • Loading branch information
rjepstein committed Jun 7, 2023
1 parent 09d0da3 commit aff18ba
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 3 deletions.
55 changes: 55 additions & 0 deletions JSTests/wasm/stress/big-try-simd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//@ requireOptions("--useWebAssemblySIMD=1")
//@ skip if $architecture != "arm64" && $architecture != "x86_64"
import { instantiate } from "../wabt-wrapper.js"
import * as assert from "../assert.js"

const N = 10

let wat = `
(module
(tag $t0 (param `

for (let i = 0; i < N; ++i)
wat += `v128 `

wat += `))
(func $f0 `
for (let i = 0; i < 50; ++i)
wat += `(local v128) `
for (let i = 0; i < N; ++i)
wat += `(local $l${i} v128) `

for (let i = 0; i < N; ++i)
wat += `(local.set $l${i} (v128.const i64x2 0 ${i + 5})) `


for (let i = 0; i < N; ++i)
wat += `(local.get $l${i}) `

wat += `
(throw $t0)
)
(func $f1 (export "test")
(try
(do
(call $f0))
(catch $t0
(return)
)
)
(unreachable)
(return))
)
`

async function test() {
const instance = await instantiate(wat, {}, { simd: true, exceptions: true })
const { test } = instance.exports

for (let i = 0; i < 10000; ++i) {
assert.throws(() => test(42), TypeError, "an exported wasm function cannot contain a v128 parameter or return value")
}
}

assert.asyncTest(test())
61 changes: 61 additions & 0 deletions JSTests/wasm/stress/big-try.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//@ requireOptions("--useWebAssemblySIMD=1")
//@ skip if $architecture != "arm64" && $architecture != "x86_64"
import { instantiate } from "../wabt-wrapper.js"
import * as assert from "../assert.js"

const N = 1000

let wat = `
(module
(tag $t0 (param `

for (let i = 0; i < N; ++i)
wat += `f64 `

wat += `))
(func $f0 `
for (let i = 0; i < 5000; ++i)
wat += `(local f64) `
for (let i = 0; i < N; ++i)
wat += `(local $l${i} f64) `

for (let i = 0; i < N; ++i)
wat += `(local.set $l${i} (f64.const ${i + 5})) `


for (let i = 0; i < N; ++i)
wat += `(local.get $l${i}) `

wat += `
(throw $t0)
)
(func $f1 (export "test") (result f64)
(try
(do
(call $f0))
(catch $t0
`
for (let i = 0; i < N - 2; ++i)
wat += `(drop) `

wat += `
(f64.add)
(return)
)
)
(unreachable)
(return))
)
`

async function test() {
const instance = await instantiate(wat, {}, { simd: true, exceptions: true })
const { test } = instance.exports

for (let i = 0; i < 10000; ++i) {
assert.eq(test(42), 2*5 + 0 + 1)
}
}

assert.asyncTest(test())
38 changes: 38 additions & 0 deletions JSTests/wasm/stress/big-tuple-args.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//@ requireOptions("--useWebAssemblySIMD=1")
//@ skip if $architecture != "arm64" && $architecture != "x86_64"
import { instantiate } from "../wabt-wrapper.js"
import * as assert from "../assert.js"

const N = 4095 + 32

let wat = `
(module
(func $f0 (result `

for (let i = 0; i < N; ++i)
wat += `f64 `

wat += `) (local $l0 f64) `

for (let i = 0; i < N; ++i)
wat += `(local.get $l0) `

wat += `
)
(func $f1 (export "test")
(call $f0)
(f64.add)
(return))
)
`

async function test() {
const instance = await instantiate(wat, {}, { simd: true })
const { test } = instance.exports

for (let i = 0; i < 10000; ++i) {
assert.eq(test(42), undefined)
}
}

assert.asyncTest(test())
37 changes: 37 additions & 0 deletions JSTests/wasm/stress/big-tuple.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//@ requireOptions("--useWebAssemblySIMD=1")
//@ skip if $architecture != "arm64" && $architecture != "x86_64"
import { instantiate } from "../wabt-wrapper.js"
import * as assert from "../assert.js"

const N = 4095 + 32

let wat = `
(module
(func $f0 (result `

for (let i = 0; i < N; ++i)
wat += `f64 `

wat += `) (local $l0 f64) `

for (let i = 0; i < N; ++i)
wat += `(local.get $l0) `

wat += `
)
(func $f1 (export "test")
(call $f0)
(return))
)
`

async function test() {
const instance = await instantiate(wat, {}, { simd: true })
const { test } = instance.exports

for (let i = 0; i < 10000; ++i) {
assert.eq(test(42), undefined)
}
}

assert.asyncTest(test())
49 changes: 49 additions & 0 deletions JSTests/wasm/stress/simd-big-tuple.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//@ requireOptions("--useWebAssemblySIMD=1")
//@ skip if $architecture != "arm64" && $architecture != "x86_64"
import { instantiate } from "../wabt-wrapper.js"
import * as assert from "../assert.js"

let wat = `
(module
(func $f0 (result v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128)
(local $l0 v128)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
(local.get $l0)
)
(func $f1 (export "test")
(call $f0)
(return))
)
`

async function test() {
const instance = await instantiate(wat, {}, { simd: true })
const { test } = instance.exports

for (let i = 0; i < 10000; ++i) {
assert.eq(test(42), undefined)
}
}

assert.asyncTest(test())
16 changes: 16 additions & 0 deletions JSTests/wasm/stress/tag-return.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ requireOptions("--useWebAssemblySIMD=1")
//@ skip if $architecture != "arm64" && $architecture != "x86_64"
import { instantiate } from "../wabt-wrapper.js"
import * as assert from "../assert.js"

const N = 15

let wat = `
(module
(tag $t0 (result f32)))`

async function test() {
await assert.throwsAsync(instantiate(wat, {}, { exceptions: true }), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 20: 0th Exception type cannot have a non-void return type 0 (evaluating 'new WebAssembly.Module(binaryResult.buffer)')")
}

assert.asyncTest(test())
27 changes: 24 additions & 3 deletions Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,8 +601,18 @@ class AirIRGenerator {
switch (patch->resultConstraints[i].kind()) {
case B3::ValueRep::StackArgument: {
Arg arg = Arg::callArg(patch->resultConstraints[i].offsetFromSP());
B3::Air::Opcode opcode = moveForType(m_proc.typeAtOffset(patch->type(), i));
Width width = widthForBytes(sizeofType(m_proc.typeAtOffset(patch->type(), i)));
if (arg.isValidForm(opcode, width))
resultMovs.append(Inst(opcode, nullptr, arg, toTmp(results[i])));
else {
auto immTmp = self().gPtr();
auto newPtr = self().gPtr();
resultMovs.append(Inst(Move, nullptr, Arg::bigImm(arg.offset()), immTmp));
resultMovs.append(Inst(Derived::AddPtr, nullptr, Tmp(MacroAssembler::stackPointerRegister), immTmp, newPtr));
resultMovs.append(Inst(opcode, nullptr, Arg::addr(newPtr), toTmp(results[i])));
}
inst.args.append(arg);
resultMovs.append(Inst(B3::Air::moveForType(m_proc.typeAtOffset(patch->type(), i)), nullptr, arg, toTmp(results[i])));
break;
}
case B3::ValueRep::Register: {
Expand Down Expand Up @@ -3367,14 +3377,25 @@ auto AirIRGenerator::addReturn(const ControlData& data, const Stack& returnValue
TypedTmp tmp = returnValues[offset + i];

if (rep.isStack()) {
append(moveForType(toB3Type(tmp.type())), tmp, Arg::addr(Tmp(GPRInfo::callFrameRegister), rep.offsetFromFP()));
Arg arg = Arg::addr(Tmp(GPRInfo::callFrameRegister), rep.offsetFromFP());
B3::Air::Opcode opcode = moveForType(toB3Type(tmp.type()));
Width width = tmp.type().width();
if (arg.isValidForm(opcode, width))
append(opcode, tmp, arg);
else {
auto immTmp = self().gPtr();
auto newPtr = self().gPtr();
append(Move, Arg::bigImm(arg.offset()), immTmp);
append(AddPtr, Tmp(GPRInfo::callFrameRegister), immTmp, newPtr);
append(opcode, tmp, Arg::addr(newPtr));
}
continue;
}

ASSERT(rep.isReg());
if (data.signature()->returnType(i).isI32())
append(Move32, tmp, tmp);
returnConstraints.append(ConstrainedTmp(tmp, wasmCallInfo.results[i]));
returnConstraints.append(ConstrainedTmp(tmp, rep));
}

emitPatchpoint(m_currentBlock, patch, ResultList { }, WTFMove(returnConstraints));
Expand Down
2 changes: 2 additions & 0 deletions Source/JavaScriptCore/wasm/WasmSectionParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,8 @@ auto SectionParser::parseException() -> PartialResult
WASM_PARSER_FAIL_IF(!parseVarUInt32(typeNumber), "can't get ", exceptionNumber, "th Exception's type number");
WASM_PARSER_FAIL_IF(typeNumber >= m_info->usedSignatures.size(), exceptionNumber, "th Exception type number is invalid ", typeNumber);
SignatureIndex signatureIndex = SignatureInformation::get(m_info->usedSignatures[typeNumber]);
auto signature = TypeInformation::getFunctionSignature(signatureIndex);
WASM_PARSER_FAIL_IF(!signature.returnsVoid(), exceptionNumber, "th Exception type cannot have a non-void return type ", typeNumber);
m_info->internalExceptionSignatureIndices.uncheckedAppend(signatureIndex);
}

Expand Down

0 comments on commit aff18ba

Please sign in to comment.