From 5f013e537495e94e67ae59c60d2b0f0ff7fe00b2 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Sun, 28 Aug 2022 05:48:19 +0430 Subject: [PATCH] Meta: Generate bigint values for v128 constants in Wasm tests --- Meta/generate-libwasm-spec-test.py | 87 +++++++++++++++++++++++++++++- Tests/LibWasm/test-wasm.cpp | 9 +++- 2 files changed, 93 insertions(+), 3 deletions(-) diff --git a/Meta/generate-libwasm-spec-test.py b/Meta/generate-libwasm-spec-test.py index 431d7c18d9a..117ceba6b06 100644 --- a/Meta/generate-libwasm-spec-test.py +++ b/Meta/generate-libwasm-spec-test.py @@ -8,6 +8,7 @@ import math from tempfile import NamedTemporaryFile from subprocess import call import json +import array atom_end = set('()"' + whitespace) @@ -61,8 +62,89 @@ def parse_typed_value(ast): 'i64.const': 'i64', 'f32.const': 'float', 'f64.const': 'double', + 'v128.const': 'bigint', } - if len(ast) == 2 and ast[0][0] in types: + + v128_sizes = { + 'i8x16': 1, + 'i16x8': 2, + 'i32x4': 4, + 'i64x2': 8, + 'f32x4': 4, + 'f64x2': 8, + } + v128_format_names = { + 'i8x16': 'b', + 'i16x8': 'h', + 'i32x4': 'i', + 'i64x2': 'q', + 'f32x4': 'f', + 'f64x2': 'd', + } + v128_format_names_unsigned = { + 'i8x16': 'B', + 'i16x8': 'H', + 'i32x4': 'I', + 'i64x2': 'Q', + } + + def parse_v128_chunk(num, type) -> array: + negative = 1 + if num.startswith('-'): + negative = -1 + num = num[1:] + elif num.startswith('+'): + num = num[1:] + + # wtf spec test, split your wast tests already + while num.startswith('0') and not num.startswith('0x'): + num = num[1:] + + if num == '': + num = '0' + + if type.startswith('f'): + def generate(): + if num == 'nan:canonical': + return float.fromhex('0x7fc00000') + if num == 'nan:arithmetic': + return float.fromhex('0x7ff00000') + if num == 'nan:signaling': + return float.fromhex('0x7ff80000') + if num.startswith('nan:'): + # FIXME: I have no idea if this is actually correct :P + rest = num[4:] + return float.fromhex('0x7ff80000') + int(rest, base=16) + if num.lower() == 'infinity': + return float.fromhex('0x7ff00000') * negative + try: + return float(num) * negative + except ValueError: + return float.fromhex(num) * negative + + value = generate() + return struct.pack(f'={v128_format_names[type]}', value) + value = negative * int(num.replace('_', ''), base=0) + try: + return struct.pack(f'={v128_format_names[type]}', value) + except struct.error: + # The test format uses signed and unsigned values interchangeably, this is probably an unsigned value. + return struct.pack(f'={v128_format_names_unsigned[type]}', value) + + if len(ast) >= 2 and ast[0][0] in types: + if ast[0][0] == 'v128.const': + value = array.array('b') + for i, num in enumerate(ast[2:]): + size = v128_sizes[ast[1][0]] + s = len(value) + value.frombytes(parse_v128_chunk(num[0], ast[1][0])) + assert len(value) - s == size, f'Expected {size} bytes, got {len(value) - s} bytes' + + return { + 'type': types[ast[0][0]], + 'value': value.tobytes().hex() + } + return {"type": types[ast[0][0]], "value": ast[1][0]} return {"type": "error"} @@ -285,6 +367,9 @@ def genarg(spec): def gen(): x = spec['value'] + if spec['type'] == 'bigint': + return f"0x{x}n" + if spec['type'] in ('i32', 'i64'): if x.startswith('0x'): if spec['type'] == 'i32': diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index fc18fc1227b..b1e5d17cf66 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -235,7 +235,9 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke) } u128 bits; - (void)argument.as_bigint().big_integer().export_data({ bit_cast(&bits), sizeof(bits) }); + (void)argument.as_bigint().big_integer().unsigned_value().export_data({ bit_cast(&bits), sizeof(bits) }); + VERIFY(!argument.as_bigint().big_integer().is_negative()); + arguments.append(Wasm::Value(bits)); break; } @@ -269,7 +271,10 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke) [](auto const& value) { return JS::Value(static_cast(value)); }, [](i32 value) { return JS::Value(static_cast(value)); }, [&](i64 value) { return JS::Value(JS::BigInt::create(vm, Crypto::SignedBigInteger { value })); }, - [&](u128 value) { return JS::Value(JS::BigInt::create(vm, Crypto::SignedBigInteger::import_data(bit_cast(&value), sizeof(value)))); }, + [&](u128 value) { + auto unsigned_bigint_value = Crypto::UnsignedBigInteger::import_data(bit_cast(&value), sizeof(value)); + return JS::Value(JS::BigInt::create(vm, Crypto::SignedBigInteger(move(unsigned_bigint_value), false))); + }, [](Wasm::Reference const& reference) { return reference.ref().visit( [](const Wasm::Reference::Null&) { return JS::js_null(); },