diff --git a/libraries/wasm-jit/Include/Inline/DenseStaticIntSet.h b/libraries/wasm-jit/Include/Inline/DenseStaticIntSet.h index 28bb1143a33..48317e5479a 100644 --- a/libraries/wasm-jit/Include/Inline/DenseStaticIntSet.h +++ b/libraries/wasm-jit/Include/Inline/DenseStaticIntSet.h @@ -28,7 +28,7 @@ struct DenseStaticIntSet inline bool contains(Index index) const { assert((Uptr)index < maxIndexPlusOne); - return (elements[index / indicesPerElement] & (1ull << (index % indicesPerElement))) != 0; + return (elements[index / indicesPerElement] & (Element(1) << (index % indicesPerElement))) != 0; } bool isEmpty() const { @@ -60,7 +60,7 @@ struct DenseStaticIntSet inline void add(Index index) { assert((Uptr)index < maxIndexPlusOne); - elements[index / indicesPerElement] |= 1ull << (index % indicesPerElement); + elements[index / indicesPerElement] |= Element(1) << (index % indicesPerElement); } inline void addRange(Index rangeMin,Index rangeMax) { @@ -73,7 +73,7 @@ struct DenseStaticIntSet } inline bool remove(Index index) { - const Element elementMask = 1ull << (index % indicesPerElement); + const Element elementMask = Element(1) << (index % indicesPerElement); const bool hadIndex = (elements[index / indicesPerElement] & elementMask) != 0; elements[index / indicesPerElement] &= ~elementMask; return hadIndex; @@ -134,8 +134,8 @@ struct DenseStaticIntSet } private: - typedef U64 Element; + typedef Uptr Element; enum { indicesPerElement = sizeof(Element) * 8 }; enum { numElements = (maxIndexPlusOne + indicesPerElement - 1) / indicesPerElement }; - U64 elements[numElements]; + Element elements[numElements]; }; diff --git a/libraries/wasm-jit/Include/Platform/Platform.h b/libraries/wasm-jit/Include/Platform/Platform.h index adc8067d4bb..7935301d62f 100644 --- a/libraries/wasm-jit/Include/Platform/Platform.h +++ b/libraries/wasm-jit/Include/Platform/Platform.h @@ -33,10 +33,16 @@ namespace Platform // countLeadingZeroes/countTrailingZeroes returns the number of leading/trailing zeroes, or the bit width of the input if no bits are set. #ifdef _WIN32 // BitScanReverse/BitScanForward return 0 if the input is 0. - inline U64 countLeadingZeroes(U64 value) { unsigned long result; return _BitScanReverse64(&result,value) ? (63 - result) : 64; } inline U32 countLeadingZeroes(U32 value) { unsigned long result; return _BitScanReverse(&result,value) ? (31 - result) : 32; } - inline U64 countTrailingZeroes(U64 value) { unsigned long result; return _BitScanForward64(&result,value) ? result : 64; } inline U32 countTrailingZeroes(U32 value) { unsigned long result; return _BitScanForward(&result,value) ? result : 32; } + + #ifdef _WIN64 + inline U64 countLeadingZeroes(U64 value) { unsigned long result; return _BitScanReverse64(&result,value) ? (63 - result) : 64; } + inline U64 countTrailingZeroes(U64 value) { unsigned long result; return _BitScanForward64(&result,value) ? result : 64; } + #else + inline U64 countLeadingZeroes(U64 value) { throw; } + inline U64 countTrailingZeroes(U64 value) { throw; } + #endif #else // __builtin_clz/__builtin_ctz are undefined if the input is 0. inline U64 countLeadingZeroes(U64 value) { return value == 0 ? 64 : __builtin_clzll(value); } @@ -108,7 +114,7 @@ namespace Platform // Describes an instruction pointer. PLATFORM_API bool describeInstructionPointer(Uptr ip,std::string& outDescription); - #ifdef _WIN32 + #ifdef _WIN64 // Registers/deregisters the data used by Windows SEH to unwind stack frames. PLATFORM_API void registerSEHUnwindInfo(Uptr imageLoadAddress,Uptr pdataAddress,Uptr pdataNumBytes); PLATFORM_API void deregisterSEHUnwindInfo(Uptr pdataAddress); diff --git a/libraries/wasm-jit/Source/IR/Validate.cpp b/libraries/wasm-jit/Source/IR/Validate.cpp index 7fc5062526c..d83593bef85 100644 --- a/libraries/wasm-jit/Source/IR/Validate.cpp +++ b/libraries/wasm-jit/Source/IR/Validate.cpp @@ -45,7 +45,7 @@ namespace IR void validate(SizeConstraints size,Uptr maxMax) { - Uptr max = size.max == UINT64_MAX ? maxMax : size.max; + U64 max = size.max == UINT64_MAX ? maxMax : size.max; VALIDATE_UNLESS("disjoint size bounds: ",size.min>max); VALIDATE_UNLESS("maximum size exceeds limit: ",max>maxMax); } diff --git a/libraries/wasm-jit/Source/Platform/Windows.cpp b/libraries/wasm-jit/Source/Platform/Windows.cpp index d2592b04ee9..bc3c30fc46a 100644 --- a/libraries/wasm-jit/Source/Platform/Windows.cpp +++ b/libraries/wasm-jit/Source/Platform/Windows.cpp @@ -131,22 +131,24 @@ namespace Platform } } - void registerSEHUnwindInfo(Uptr imageLoadAddress,Uptr pdataAddress,Uptr pdataNumBytes) - { - const U32 numFunctions = (U32)(pdataNumBytes / sizeof(RUNTIME_FUNCTION)); + #if defined(_WIN32) && defined(_AMD64_) + void registerSEHUnwindInfo(Uptr imageLoadAddress,Uptr pdataAddress,Uptr pdataNumBytes) + { + const U32 numFunctions = (U32)(pdataNumBytes / sizeof(RUNTIME_FUNCTION)); - // Register our manually fixed up copy of the function table. - if(!RtlAddFunctionTable(reinterpret_cast(pdataAddress),numFunctions,imageLoadAddress)) + // Register our manually fixed up copy of the function table. + if(!RtlAddFunctionTable(reinterpret_cast(pdataAddress),numFunctions,imageLoadAddress)) + { + Errors::fatal("RtlAddFunctionTable failed"); + } + } + void deregisterSEHUnwindInfo(Uptr pdataAddress) { - Errors::fatal("RtlAddFunctionTable failed"); + auto functionTable = reinterpret_cast(pdataAddress); + RtlDeleteFunctionTable(functionTable); + delete [] functionTable; } - } - void deregisterSEHUnwindInfo(Uptr pdataAddress) - { - auto functionTable = reinterpret_cast(pdataAddress); - RtlDeleteFunctionTable(functionTable); - delete [] functionTable; - } + #endif CallStack unwindStack(const CONTEXT& immutableContext) { @@ -156,6 +158,7 @@ namespace Platform // Unwind the stack until there isn't a valid instruction pointer, which signals we've reached the base. CallStack callStack; + #ifdef _WIN64 while(context.Rip) { callStack.stackFrames.push_back({context.Rip}); @@ -186,6 +189,7 @@ namespace Platform ); } } + #endif return callStack; } diff --git a/libraries/wasm-jit/Source/Programs/Test.cpp b/libraries/wasm-jit/Source/Programs/Test.cpp index 6796bcd3d4b..d6c4f49ac8f 100644 --- a/libraries/wasm-jit/Source/Programs/Test.cpp +++ b/libraries/wasm-jit/Source/Programs/Test.cpp @@ -148,15 +148,15 @@ bool processAction(TestScriptState& state,Action* action,Result& outResult) ModuleInstance* moduleInstance = getModuleContextByInternalName(state,invokeAction->locus,"invoke",invokeAction->internalModuleName); // A null module instance at this point indicates a module that failed to link or instantiate, so don't produce further errors. - if(moduleInstance) - { - // Find the named export in the module instance. - auto functionInstance = asFunctionNullable(getInstanceExport(moduleInstance,invokeAction->exportName)); - if(!functionInstance) { testErrorf(state,invokeAction->locus,"couldn't find exported function with name: %s",invokeAction->exportName.c_str()); return false; } + if(!moduleInstance) { return false; } + + // Find the named export in the module instance. + auto functionInstance = asFunctionNullable(getInstanceExport(moduleInstance,invokeAction->exportName)); + if(!functionInstance) { testErrorf(state,invokeAction->locus,"couldn't find exported function with name: %s",invokeAction->exportName.c_str()); return false; } + + // Execute the invoke + outResult = invokeFunction(functionInstance,invokeAction->arguments); - // Execute the invoke - outResult = invokeFunction(functionInstance,invokeAction->arguments); - } return true; } case ActionType::get: diff --git a/libraries/wasm-jit/Source/Runtime/LLVMEmitIR.cpp b/libraries/wasm-jit/Source/Runtime/LLVMEmitIR.cpp index 9cf0c1575e9..f505c8222bc 100644 --- a/libraries/wasm-jit/Source/Runtime/LLVMEmitIR.cpp +++ b/libraries/wasm-jit/Source/Runtime/LLVMEmitIR.cpp @@ -25,7 +25,7 @@ namespace LLVMJIT llvm::Constant* defaultTablePointer; llvm::Constant* defaultTableEndOffset; llvm::Constant* defaultMemoryBase; - llvm::Constant* defaultMemoryAddressMask; + llvm::Constant* defaultMemoryEndOffset; llvm::DIBuilder diBuilder; llvm::DICompileUnit* diCompileUnit; @@ -217,23 +217,56 @@ namespace LLVMJIT // Bounds checks and converts a memory operation I32 address operand to a LLVM pointer. llvm::Value* coerceByteIndexToPointer(llvm::Value* byteIndex,U32 offset,llvm::Type* memoryType) { - // On a 64 bit runtime, if the address is 32-bits, zext it to 64-bits. - // This is crucial for security, as LLVM will otherwise implicitly sign extend it to 64-bits in the GEP below, - // interpreting it as a signed offset and allowing access to memory outside the sandboxed memory range. - // There are no 'far addresses' in a 32 bit runtime. - llvm::Value* nativeByteIndex = sizeof(Uptr) == 4 ? byteIndex : irBuilder.CreateZExt(byteIndex,llvmI64Type); - llvm::Value* offsetByteIndex = nativeByteIndex; - if(offset) + if(HAS_64BIT_ADDRESS_SPACE) { - auto nativeOffset = sizeof(Uptr) == 4 ? emitLiteral((U32)offset) : irBuilder.CreateZExt(emitLiteral((U32)offset),llvmI64Type); - offsetByteIndex = irBuilder.CreateAdd(nativeByteIndex,nativeOffset); + // On a 64 bit runtime, if the address is 32-bits, zext it to 64-bits. + // This is crucial for security, as LLVM will otherwise implicitly sign extend it to 64-bits in the GEP below, + // interpreting it as a signed offset and allowing access to memory outside the sandboxed memory range. + // There are no 'far addresses' in a 32 bit runtime. + if(sizeof(Uptr) != 4) { byteIndex = irBuilder.CreateZExt(byteIndex,llvmI64Type); } + + // Add the offset to the byte index. + if(offset) + { + byteIndex = irBuilder.CreateAdd(byteIndex,irBuilder.CreateZExt(emitLiteral(offset),llvmI64Type)); + } + + // If HAS_64BIT_ADDRESS_SPACE, the memory has enough virtual address space allocated to + // ensure that any 32-bit byte index + 32-bit offset will fall within the virtual address sandbox, + // so no explicit bounds check is necessary. } + else + { + // Add the offset to the byte index using a LLVM intrinsic that returns a carry bit if the add overflowed. + llvm::Value* overflowed = emitLiteral(false); + if(offset) + { + auto offsetByteIndexWithOverflow = irBuilder.CreateCall( + getLLVMIntrinsic({llvmI32Type},llvm::Intrinsic::uadd_with_overflow), + {byteIndex,emitLiteral(U32(offset))} + ); + byteIndex = irBuilder.CreateExtractValue(offsetByteIndexWithOverflow,{0}); + overflowed = irBuilder.CreateExtractValue(offsetByteIndexWithOverflow,{1}); + } - // Mask the index to the address-space size. - auto maskedByteIndex = irBuilder.CreateAnd(offsetByteIndex,moduleContext.defaultMemoryAddressMask); + // Check that the offset didn't overflow, and that the final byte index is within the virtual address space + // allocated for the memory. + emitConditionalTrapIntrinsic( + irBuilder.CreateOr( + overflowed, + irBuilder.CreateICmpUGT( + byteIndex, + irBuilder.CreateSub( + moduleContext.defaultMemoryEndOffset, + emitLiteral(Uptr(memoryType->getPrimitiveSizeInBits() / 8) - 1) + ) + ) + ), + "wavmIntrinsics.accessViolationTrap",FunctionType::get(),{}); + } // Cast the pointer to the appropriate type. - auto bytePointer = irBuilder.CreateInBoundsGEP(moduleContext.defaultMemoryBase,maskedByteIndex); + auto bytePointer = irBuilder.CreateInBoundsGEP(moduleContext.defaultMemoryBase,byteIndex); return irBuilder.CreatePointerCast(bytePointer,memoryType->getPointerTo()); } @@ -242,7 +275,21 @@ namespace LLVMJIT { emitConditionalTrapIntrinsic( irBuilder.CreateICmpEQ(divisor,typedZeroConstants[(Uptr)type]), - "wavmIntrinsics.divideByZeroTrap",FunctionType::get(),{}); + "wavmIntrinsics.divideByZeroOrIntegerOverflowTrap",FunctionType::get(),{}); + } + + // Traps on (x / 0) or (INT_MIN / -1). + void trapDivideByZeroOrIntegerOverflow(ValueType type,llvm::Value* left,llvm::Value* right) + { + emitConditionalTrapIntrinsic( + irBuilder.CreateOr( + irBuilder.CreateAnd( + irBuilder.CreateICmpEQ(left,type == ValueType::i32 ? emitLiteral((U32)INT32_MIN) : emitLiteral((U64)INT64_MIN)), + irBuilder.CreateICmpEQ(right,type == ValueType::i32 ? emitLiteral((U32)-1) : emitLiteral((U64)-1)) + ), + irBuilder.CreateICmpEQ(right,typedZeroConstants[(Uptr)type]) + ), + "wavmIntrinsics.divideByZeroOrIntegerOverflowTrap",FunctionType::get(),{}); } llvm::Value* getLLVMIntrinsic(const std::initializer_list& argTypes,llvm::Intrinsic::ID id) @@ -867,10 +914,10 @@ namespace LLVMJIT EMIT_INT_BINARY_OP(rotl,emitRotl(type,left,right)) // Divides use trapDivideByZero to avoid the undefined behavior in LLVM's division instructions. - EMIT_INT_BINARY_OP(div_s, (trapDivideByZero(type,right), irBuilder.CreateSDiv(left,right)) ) + EMIT_INT_BINARY_OP(div_s, (trapDivideByZeroOrIntegerOverflow(type,left,right), irBuilder.CreateSDiv(left,right)) ) + EMIT_INT_BINARY_OP(rem_s, emitSRem(type,left,right) ) EMIT_INT_BINARY_OP(div_u, (trapDivideByZero(type,right), irBuilder.CreateUDiv(left,right)) ) EMIT_INT_BINARY_OP(rem_u, (trapDivideByZero(type,right), irBuilder.CreateURem(left,right)) ) - EMIT_INT_BINARY_OP(rem_s,emitSRem(type,left,right)) // Explicitly mask the shift amount operand to the word size to avoid LLVM's undefined behavior. EMIT_INT_BINARY_OP(shl,irBuilder.CreateShl(left,emitShiftCountMask(type,right))) @@ -983,10 +1030,6 @@ namespace LLVMJIT EMIT_SIMD_SPLAT(i64x2,scalar,2) EMIT_SIMD_SPLAT(f32x4,scalar,4) EMIT_SIMD_SPLAT(f64x2,scalar,2) - EMIT_SIMD_SPLAT(b8x16,coerceI32ToBool(scalar),16) - EMIT_SIMD_SPLAT(b16x8,coerceI32ToBool(scalar),8) - EMIT_SIMD_SPLAT(b32x4,coerceI32ToBool(scalar),4) - EMIT_SIMD_SPLAT(b64x2,coerceI32ToBool(scalar),2) EMIT_STORE_OP(v128,store,value->getType(),4,identityConversion) EMIT_LOAD_OP(v128,load,llvmI64x2Type,4,identityConversion) @@ -1130,11 +1173,6 @@ namespace LLVMJIT EMIT_SIMD_EXTRACT_LANE_OP(f32x4_extract_lane,llvmF32x4Type,4,scalar) EMIT_SIMD_EXTRACT_LANE_OP(f64x2_extract_lane,llvmF64x2Type,2,scalar) - - EMIT_SIMD_EXTRACT_LANE_OP(b8x16_extract_lane,llvmB8x16Type,16,coerceBoolToI32(scalar)) - EMIT_SIMD_EXTRACT_LANE_OP(b16x8_extract_lane,llvmB16x8Type,8,coerceBoolToI32(scalar)) - EMIT_SIMD_EXTRACT_LANE_OP(b32x4_extract_lane,llvmB32x4Type,4,coerceBoolToI32(scalar)) - EMIT_SIMD_EXTRACT_LANE_OP(b64x2_extract_lane,llvmB64x2Type,2,coerceBoolToI32(scalar)) #define EMIT_SIMD_REPLACE_LANE_OP(typePrefix,llvmType,numLanes,coerceScalar) \ void typePrefix##_replace_lane(LaneIndexImm imm) \ @@ -1152,11 +1190,6 @@ namespace LLVMJIT EMIT_SIMD_REPLACE_LANE_OP(f32x4,llvmF32x4Type,4,scalar) EMIT_SIMD_REPLACE_LANE_OP(f64x2,llvmF64x2Type,2,scalar) - EMIT_SIMD_REPLACE_LANE_OP(b8x16,llvmB8x16Type,16,coerceI32ToBool(scalar)) - EMIT_SIMD_REPLACE_LANE_OP(b16x8,llvmB16x8Type,8,coerceI32ToBool(scalar)) - EMIT_SIMD_REPLACE_LANE_OP(b32x4,llvmB32x4Type,4,coerceI32ToBool(scalar)) - EMIT_SIMD_REPLACE_LANE_OP(b64x2,llvmB64x2Type,2,coerceI32ToBool(scalar)) - void v8x16_shuffle(ShuffleImm<16> imm) { auto right = irBuilder.CreateBitCast(pop(),llvmI8x16Type); @@ -1327,7 +1360,8 @@ namespace LLVMJIT llvm::AtomicOrdering::SequentiallyConsistent, \ llvm::AtomicOrdering::SequentiallyConsistent); \ atomicCmpXchg->setVolatile(true); \ - push(memoryToValueConversion(atomicCmpXchg,asLLVMType(ValueType::valueTypeId))); \ + auto previousValue = irBuilder.CreateExtractValue(atomicCmpXchg,{0}); \ + push(memoryToValueConversion(previousValue,asLLVMType(ValueType::valueTypeId))); \ } EMIT_ATOMIC_CMPXCHG(i32,atomic_rmw8_u_cmpxchg,llvmI8Type,0,irBuilder.CreateZExt,irBuilder.CreateTrunc) @@ -1361,7 +1395,7 @@ namespace LLVMJIT EMIT_ATOMIC_RMW(i64,atomic_rmw8_u_xchg,Xchg,llvmI8Type,0,irBuilder.CreateZExt,irBuilder.CreateTrunc) EMIT_ATOMIC_RMW(i64,atomic_rmw16_u_xchg,Xchg,llvmI16Type,1,irBuilder.CreateZExt,irBuilder.CreateTrunc) - EMIT_ATOMIC_RMW(i64,atomic_rmw32_u_xchg,Xchg,llvmI16Type,2,irBuilder.CreateZExt,irBuilder.CreateTrunc) + EMIT_ATOMIC_RMW(i64,atomic_rmw32_u_xchg,Xchg,llvmI32Type,2,irBuilder.CreateZExt,irBuilder.CreateTrunc) EMIT_ATOMIC_RMW(i64,atomic_rmw_xchg,Xchg,llvmI64Type,3,identityConversion,identityConversion) EMIT_ATOMIC_RMW(i32,atomic_rmw8_u_add,Add,llvmI8Type,0,irBuilder.CreateZExt,irBuilder.CreateTrunc) @@ -1545,10 +1579,10 @@ namespace LLVMJIT if(moduleInstance->defaultMemory) { defaultMemoryBase = emitLiteralPointer(moduleInstance->defaultMemory->baseAddress,llvmI8PtrType); - const Uptr defaultMemoryAddressMaskValue = Uptr(moduleInstance->defaultMemory->endOffset) - 1; - defaultMemoryAddressMask = emitLiteral(defaultMemoryAddressMaskValue); + const Uptr defaultMemoryEndOffsetValue = Uptr(moduleInstance->defaultMemory->endOffset); + defaultMemoryEndOffset = emitLiteral(defaultMemoryEndOffsetValue); } - else { defaultMemoryBase = defaultMemoryAddressMask = nullptr; } + else { defaultMemoryBase = defaultMemoryEndOffset = nullptr; } // Set up the LLVM values used to access the global table. if(moduleInstance->defaultTable) diff --git a/libraries/wasm-jit/Source/Runtime/LLVMJIT.cpp b/libraries/wasm-jit/Source/Runtime/LLVMJIT.cpp index d2328efeb01..ba0052d7905 100644 --- a/libraries/wasm-jit/Source/Runtime/LLVMJIT.cpp +++ b/libraries/wasm-jit/Source/Runtime/LLVMJIT.cpp @@ -11,11 +11,17 @@ #define DUMP_UNOPTIMIZED_MODULE 1 #define VERIFY_MODULE 1 #define DUMP_OPTIMIZED_MODULE 1 + #define PRINT_DISASSEMBLY 0 #else #define USE_WRITEABLE_JIT_CODE_PAGES 0 #define DUMP_UNOPTIMIZED_MODULE 0 #define VERIFY_MODULE 0 #define DUMP_OPTIMIZED_MODULE 0 + #define PRINT_DISASSEMBLY 0 +#endif + +#if PRINT_DISASSEMBLY +#include "llvm-c/Disassembler.h" #endif namespace LLVMJIT @@ -41,10 +47,6 @@ namespace LLVMJIT llvm::Type* llvmI64x2Type; llvm::Type* llvmF32x4Type; llvm::Type* llvmF64x2Type; - llvm::Type* llvmB8x16Type; - llvm::Type* llvmB16x8Type; - llvm::Type* llvmB32x4Type; - llvm::Type* llvmB64x2Type; #endif llvm::Constant* typedZeroConstants[(Uptr)ValueType::num]; @@ -225,7 +227,7 @@ namespace LLVMJIT ~JITUnit() { compileLayer->removeModuleSet(handle); - #ifdef _WIN32 + #ifdef _WIN64 if(pdataCopy) { Platform::deregisterSEHUnwindInfo(reinterpret_cast(pdataCopy)); } #endif } @@ -328,7 +330,11 @@ namespace LLVMJIT void notifySymbolLoaded(const char* name,Uptr baseAddress,Uptr numBytes,std::map&& offsetToOpIndexMap) override { - assert(!strcmp(name,"invokeThunk")); + #if defined(_WIN32) && !defined(_WIN64) + assert(!strcmp(name,"_invokeThunk")); + #else + assert(!strcmp(name,"invokeThunk")); + #endif symbol = new JITSymbol(functionType,baseAddress,numBytes,std::move(offsetToOpIndexMap)); } }; @@ -341,18 +347,43 @@ namespace LLVMJIT virtual llvm::JITSymbol findSymbolInLogicalDylib(const std::string& name) override; }; + static std::map runtimeSymbolMap = + { + #ifdef _WIN32 + // the LLVM X86 code generator calls __chkstk when allocating more than 4KB of stack space + {"__chkstk","__chkstk"}, + #ifndef _WIN64 + {"__aullrem","_aullrem"}, + {"__allrem","_allrem"}, + {"__aulldiv","_aulldiv"}, + {"__alldiv","_alldiv"}, + #endif + #endif + #ifdef __arm__ + {"__aeabi_uidiv","__aeabi_uidiv"}, + {"__aeabi_idiv","__aeabi_idiv"}, + {"__aeabi_idivmod","__aeabi_idivmod"}, + {"__aeabi_uldiv","__aeabi_uldiv"}, + {"__aeabi_uldivmod","__aeabi_uldivmod"}, + {"__aeabi_unwind_cpp_pr0","__aeabi_unwind_cpp_pr0"}, + {"__aeabi_unwind_cpp_pr1","__aeabi_unwind_cpp_pr1"}, + #endif + }; + NullResolver NullResolver::singleton; llvm::JITSymbol NullResolver::findSymbol(const std::string& name) { - // Allow __chkstk through: the LLVM X86 code generator adds calls to it when allocating more than 4KB of stack space. - if(name == "__chkstk") - { - void *addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(name); - if (addr) { return llvm::JITSymbol(reinterpret_cast(addr),llvm::JITSymbolFlags::None); } + // Allow some intrinsics used by LLVM + auto runtimeSymbolNameIt = runtimeSymbolMap.find(name); + if(runtimeSymbolNameIt != runtimeSymbolMap.end()) + { + const char* lookupName = runtimeSymbolNameIt->second; + void *addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(lookupName); + if(!addr) { Errors::fatalf("LLVM generated code references undefined external symbol: %s\n",lookupName); } + return llvm::JITSymbol(reinterpret_cast(addr),llvm::JITSymbolFlags::None); } - Log::printf(Log::Category::error,"LLVM generated code referenced external symbol: %s\n",name.c_str()); - Errors::unreachable(); + Errors::fatalf("LLVM generated code references disallowed external symbol: %s\n",name.c_str()); } llvm::JITSymbol NullResolver::findSymbolInLogicalDylib(const std::string& name) { return llvm::JITSymbol(nullptr); } @@ -371,7 +402,7 @@ namespace LLVMJIT // Make a copy of the loaded object info for use by the finalizer. jitUnit->loadedObjects.push_back({object,loadedObject}); - #ifdef _WIN32 + #ifdef _WIN64 // On Windows, look for .pdata and .xdata sections containing information about how to unwind the stack. // This needs to be done before the below emitAndFinalize call, which will incorrectly apply relocations to the unwind info. @@ -423,6 +454,36 @@ namespace LLVMJIT } + #if PRINT_DISASSEMBLY + void disassembleFunction(U8* bytes,Uptr numBytes) + { + LLVMDisasmContextRef disasmRef = LLVMCreateDisasm(llvm::sys::getProcessTriple().c_str(),nullptr,0,nullptr,nullptr); + + U8* nextByte = bytes; + Uptr numBytesRemaining = numBytes; + while(numBytesRemaining) + { + char instructionBuffer[256]; + const Uptr numInstructionBytes = LLVMDisasmInstruction( + disasmRef, + nextByte, + numBytesRemaining, + reinterpret_cast(nextByte), + instructionBuffer, + sizeof(instructionBuffer) + ); + assert(numInstructionBytes > 0); + assert(numInstructionBytes <= numBytesRemaining); + numBytesRemaining -= numInstructionBytes; + nextByte += numInstructionBytes; + + Log::printf(Log::Category::debug,"\t\t%s\n",instructionBuffer); + }; + + LLVMDisasmDispose(disasmRef); + } + #endif + void JITUnit::NotifyFinalizedFunctor::operator()(const llvm::orc::ObjectLinkingLayerBase::ObjSetHandleT& objectSetHandle) { for(Uptr objectIndex = 0;objectIndex < jitUnit->loadedObjects.size();++objectIndex) @@ -444,7 +505,8 @@ namespace LLVMJIT && address) { // Compute the address the functions was loaded at. - Uptr loadedAddress = *address; + assert(*address <= UINTPTR_MAX); + Uptr loadedAddress = Uptr(*address); auto symbolSection = symbol.getSection(); if(symbolSection) { @@ -455,9 +517,19 @@ namespace LLVMJIT llvm::DILineInfoTable lineInfoTable = dwarfContext->getLineInfoForAddressRange(loadedAddress,symbolSizePair.second); std::map offsetToOpIndexMap; for(auto lineInfo : lineInfoTable) { offsetToOpIndexMap.emplace(U32(lineInfo.first - loadedAddress),lineInfo.second.Line); } + + #if PRINT_DISASSEMBLY + Log::printf(Log::Category::error,"Disassembly for function %s\n",name.get().data()); + disassembleFunction(reinterpret_cast(loadedAddress),Uptr(symbolSizePair.second)); + #endif // Notify the JIT unit that the symbol was loaded. - jitUnit->notifySymbolLoaded(name->data(),loadedAddress,symbolSizePair.second,std::move(offsetToOpIndexMap)); + assert(symbolSizePair.second <= UINTPTR_MAX); + jitUnit->notifySymbolLoaded( + name->data(),loadedAddress, + Uptr(symbolSizePair.second), + std::move(offsetToOpIndexMap) + ); } } } @@ -525,7 +597,7 @@ namespace LLVMJIT { Timing::logRatePerSecond("Generated machine code",machineCodeTimer,(F64)llvmModule->size(),"functions"); } - + delete llvmModule; } @@ -551,10 +623,18 @@ namespace LLVMJIT bool getFunctionIndexFromExternalName(const char* externalName,Uptr& outFunctionDefIndex) { - if(!strncmp(externalName,"wasmFunc",8)) + #if defined(_WIN32) && !defined(_WIN64) + const char wasmFuncPrefix[] = "_wasmFunc"; + #else + const char wasmFuncPrefix[] = "wasmFunc"; + #endif + const Uptr numPrefixChars = sizeof(wasmFuncPrefix) - 1; + if(!strncmp(externalName,wasmFuncPrefix,numPrefixChars)) { char* numberEnd = nullptr; - outFunctionDefIndex = std::strtoull(externalName + 8,&numberEnd,10); + U64 functionDefIndex64 = std::strtoull(externalName + numPrefixChars,&numberEnd,10); + if(functionDefIndex64 > UINTPTR_MAX) { return false; } + outFunctionDefIndex = Uptr(functionDefIndex64); return true; } else { return false; } @@ -663,6 +743,7 @@ namespace LLVMJIT llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); llvm::InitializeNativeTargetAsmParser(); + llvm::InitializeNativeTargetDisassembler(); llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); auto targetTriple = llvm::sys::getProcessTriple(); @@ -671,7 +752,15 @@ namespace LLVMJIT // our symbols can't be found in the JITed object file. targetTriple += "-elf"; #endif - targetMachine = llvm::EngineBuilder().selectTarget(llvm::Triple(targetTriple),"","",llvm::SmallVector()); + targetMachine = llvm::EngineBuilder().selectTarget( + llvm::Triple(targetTriple),"","", + #if defined(_WIN32) && !defined(_WIN64) + // Use SSE2 instead of the FPU on x86 for more control over how intermediate results are rounded. + llvm::SmallVector({"+sse2"}) + #else + llvm::SmallVector() + #endif + ); llvmI8Type = llvm::Type::getInt8Ty(context); llvmI16Type = llvm::Type::getInt16Ty(context); @@ -690,10 +779,6 @@ namespace LLVMJIT llvmI64x2Type = llvm::VectorType::get(llvmI64Type,2); llvmF32x4Type = llvm::VectorType::get(llvmF32Type,4); llvmF64x2Type = llvm::VectorType::get(llvmF64Type,2); - llvmB8x16Type = llvm::VectorType::get(llvmBoolType,16); - llvmB16x8Type = llvm::VectorType::get(llvmBoolType,8); - llvmB32x4Type = llvm::VectorType::get(llvmBoolType,4); - llvmB64x2Type = llvm::VectorType::get(llvmBoolType,2); #endif llvmResultTypes[(Uptr)ResultType::none] = llvm::Type::getVoidTy(context); diff --git a/libraries/wasm-jit/Source/Runtime/LLVMJIT.h b/libraries/wasm-jit/Source/Runtime/LLVMJIT.h index 3d22067d025..afadb6053e4 100644 --- a/libraries/wasm-jit/Source/Runtime/LLVMJIT.h +++ b/libraries/wasm-jit/Source/Runtime/LLVMJIT.h @@ -86,10 +86,6 @@ namespace LLVMJIT extern llvm::Type* llvmI64x2Type; extern llvm::Type* llvmF32x4Type; extern llvm::Type* llvmF64x2Type; - extern llvm::Type* llvmB8x16Type; - extern llvm::Type* llvmB16x8Type; - extern llvm::Type* llvmB32x4Type; - extern llvm::Type* llvmB64x2Type; #endif // Zero constants of each type. diff --git a/libraries/wasm-jit/Source/Runtime/Memory.cpp b/libraries/wasm-jit/Source/Runtime/Memory.cpp index 87cae5bd04d..63cbe0d0957 100644 --- a/libraries/wasm-jit/Source/Runtime/Memory.cpp +++ b/libraries/wasm-jit/Source/Runtime/Memory.cpp @@ -20,7 +20,7 @@ namespace Runtime const Uptr alignmentPages = alignmentBytes >> Platform::getPageSizeLog2(); outUnalignedNumPlatformPages = numAllocatedVirtualPages + alignmentPages; outUnalignedBaseAddress = Platform::allocateVirtualPages(outUnalignedNumPlatformPages); - if(!outUnalignedBaseAddress) { return nullptr; } + if(!outUnalignedBaseAddress) { outUnalignedNumPlatformPages = 0; return nullptr; } else { return (U8*)((Uptr)(outUnalignedBaseAddress + alignmentBytes - 1) & ~(alignmentBytes - 1)); } } @@ -30,19 +30,20 @@ namespace Runtime // On a 64-bit runtime, allocate 8GB of address space for the memory. // This allows eliding bounds checks on memory accesses, since a 32-bit index + 32-bit offset will always be within the reserved address-space. - // On a 32-bit runtime, allocate 1GB. - const Uptr memoryMaxBytes = HAS_64BIT_ADDRESS_SPACE ? 8ull*1024*1024*1024 : 0x40000000; + // On a 32-bit runtime, allocate 256MB. + const Uptr memoryMaxBytes = HAS_64BIT_ADDRESS_SPACE ? Uptr(8ull*1024*1024*1024) : 0x10000000; // On a 64 bit runtime, align the instance memory base to a 4GB boundary, so the lower 32-bits will all be zero. Maybe it will allow better code generation? // Note that this reserves a full extra 4GB, but only uses (4GB-1 page) for alignment, so there will always be a guard page at the end to // protect against unaligned loads/stores that straddle the end of the address-space. - const Uptr alignmentBytes = HAS_64BIT_ADDRESS_SPACE ? 4ull*1024*1024*1024 : ((Uptr)1 << Platform::getPageSizeLog2()); + const Uptr alignmentBytes = HAS_64BIT_ADDRESS_SPACE ? Uptr(4ull*1024*1024*1024) : ((Uptr)1 << Platform::getPageSizeLog2()); memory->baseAddress = allocateVirtualPagesAligned(memoryMaxBytes,alignmentBytes,memory->reservedBaseAddress,memory->reservedNumPlatformPages); memory->endOffset = memoryMaxBytes; if(!memory->baseAddress) { delete memory; return nullptr; } // Grow the memory to the type's minimum size. - if(growMemory(memory,type.size.min) == -1) { delete memory; return nullptr; } + assert(type.size.min <= UINTPTR_MAX); + if(growMemory(memory,Uptr(type.size.min)) == -1) { delete memory; return nullptr; } // Add the memory to the global array. memories.push_back(memory); @@ -79,7 +80,11 @@ namespace Runtime } Uptr getMemoryNumPages(MemoryInstance* memory) { return memory->numPages; } - Uptr getMemoryMaxPages(MemoryInstance* memory) { return memory->type.size.max; } + Uptr getMemoryMaxPages(MemoryInstance* memory) + { + assert(memory->type.size.max <= UINTPTR_MAX); + return Uptr(memory->type.size.max); + } Iptr growMemory(MemoryInstance* memory,Uptr numNewPages) { diff --git a/libraries/wasm-jit/Source/Runtime/ModuleInstance.cpp b/libraries/wasm-jit/Source/Runtime/ModuleInstance.cpp index bfc0002c95c..1ae704b3495 100644 --- a/libraries/wasm-jit/Source/Runtime/ModuleInstance.cpp +++ b/libraries/wasm-jit/Source/Runtime/ModuleInstance.cpp @@ -96,7 +96,8 @@ namespace Runtime const Value baseOffsetValue = evaluateInitializer(moduleInstance,tableSegment.baseOffset); errorUnless(baseOffsetValue.type == ValueType::i32); const U32 baseOffset = baseOffsetValue.i32; - if(baseOffset + tableSegment.indices.size() > table->elements.size()) + if(baseOffset > table->elements.size() + || table->elements.size() - baseOffset < tableSegment.indices.size()) { causeException(Exception::Cause::invalidSegmentOffset); } } for(auto& dataSegment : module.dataSegments) @@ -106,7 +107,9 @@ namespace Runtime const Value baseOffsetValue = evaluateInitializer(moduleInstance,dataSegment.baseOffset); errorUnless(baseOffsetValue.type == ValueType::i32); const U32 baseOffset = baseOffsetValue.i32; - if(baseOffset + dataSegment.data.size() > (memory->numPages << IR::numBytesPerPageLog2)) + const Uptr numMemoryBytes = (memory->numPages << IR::numBytesPerPageLog2); + if(baseOffset > numMemoryBytes + || numMemoryBytes - baseOffset < dataSegment.data.size()) { causeException(Exception::Cause::invalidSegmentOffset); } } diff --git a/libraries/wasm-jit/Source/Runtime/Table.cpp b/libraries/wasm-jit/Source/Runtime/Table.cpp index 03761122d78..0cc4bf858bc 100644 --- a/libraries/wasm-jit/Source/Runtime/Table.cpp +++ b/libraries/wasm-jit/Source/Runtime/Table.cpp @@ -18,18 +18,19 @@ namespace Runtime TableInstance* table = new TableInstance(type); // In 64-bit, allocate enough address-space to safely access 32-bit table indices without bounds checking, or 16MB (4M elements) if the host is 32-bit. - const Uptr tableMaxBytes = HAS_64BIT_ADDRESS_SPACE ? (sizeof(TableInstance::FunctionElement) << 32) : 16*1024*1024; + const Uptr tableMaxBytes = HAS_64BIT_ADDRESS_SPACE ? Uptr(U64(sizeof(TableInstance::FunctionElement)) << 32) : 16*1024*1024; // On a 64 bit runtime, align the table base to a 4GB boundary, so the lower 32-bits will all be zero. Maybe it will allow better code generation? // Note that this reserves a full extra 4GB, but only uses (4GB-1 page) for alignment, so there will always be a guard page at the end to // protect against unaligned loads/stores that straddle the end of the address-space. - const Uptr alignmentBytes = HAS_64BIT_ADDRESS_SPACE ? 4ull*1024*1024*1024 : (Uptr(1) << Platform::getPageSizeLog2()); + const Uptr alignmentBytes = HAS_64BIT_ADDRESS_SPACE ? Uptr(4ull*1024*1024*1024) : (Uptr(1) << Platform::getPageSizeLog2()); table->baseAddress = (TableInstance::FunctionElement*)allocateVirtualPagesAligned(tableMaxBytes,alignmentBytes,table->reservedBaseAddress,table->reservedNumPlatformPages); table->endOffset = tableMaxBytes; if(!table->baseAddress) { delete table; return nullptr; } // Grow the table to the type's minimum size. - if(growTable(table,type.size.min) == -1) { delete table; return nullptr; } + assert(type.size.min <= UINTPTR_MAX); + if(growTable(table,Uptr(type.size.min)) == -1) { delete table; return nullptr; } // Add the table to the global array. tables.push_back(table); diff --git a/libraries/wasm-jit/Source/Runtime/Threads.cpp b/libraries/wasm-jit/Source/Runtime/Threads.cpp index ac98b417bdb..22a74d8a9f3 100644 --- a/libraries/wasm-jit/Source/Runtime/Threads.cpp +++ b/libraries/wasm-jit/Source/Runtime/Threads.cpp @@ -194,7 +194,7 @@ static U32 wakeAddress(Uptr address,U32 numToWake) } // Remove the events from the wait list. - waitList->wakeEvents.erase(waitList->wakeEvents.begin(),waitList->wakeEvents.begin() + numToWake); + waitList->wakeEvents.erase(waitList->wakeEvents.begin(),waitList->wakeEvents.begin() + actualNumToWake); } closeWaitList(address,waitList); diff --git a/libraries/wasm-jit/Source/Runtime/WAVMIntrinsics.cpp b/libraries/wasm-jit/Source/Runtime/WAVMIntrinsics.cpp index 47fe8002ab1..bf14805a620 100644 --- a/libraries/wasm-jit/Source/Runtime/WAVMIntrinsics.cpp +++ b/libraries/wasm-jit/Source/Runtime/WAVMIntrinsics.cpp @@ -123,7 +123,7 @@ namespace Runtime DEFINE_INTRINSIC_FUNCTION1(wavmIntrinsics,floatToUnsignedInt,floatToUnsignedInt,i64,f32,source) { return floatToInt(source,-1.0f,-2.0f * INT64_MIN); } DEFINE_INTRINSIC_FUNCTION1(wavmIntrinsics,floatToUnsignedInt,floatToUnsignedInt,i64,f64,source) { return floatToInt(source,-1.0,-2.0 * INT64_MIN); } - DEFINE_INTRINSIC_FUNCTION0(wavmIntrinsics,divideByZeroTrap,divideByZeroTrap,none) + DEFINE_INTRINSIC_FUNCTION0(wavmIntrinsics,divideByZeroOrIntegerOverflowTrap,divideByZeroOrIntegerOverflowTrap,none) { causeException(Exception::Cause::integerDivideByZeroOrIntegerOverflow); } @@ -132,6 +132,11 @@ namespace Runtime { causeException(Exception::Cause::reachedUnreachable); } + + DEFINE_INTRINSIC_FUNCTION0(wavmIntrinsics,accessViolationTrap,accessViolationTrap,none) + { + causeException(Exception::Cause::accessViolation); + } DEFINE_INTRINSIC_FUNCTION3(wavmIntrinsics,indirectCallSignatureMismatch,indirectCallSignatureMismatch,none,i32,index,i64,expectedSignatureBits,i64,tableBits) { diff --git a/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp b/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp index 4953550be10..cf5feac18f3 100644 --- a/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp +++ b/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp @@ -74,30 +74,30 @@ namespace IR serialize(stream,tableType.elementType); Uptr flags = 0; - if(!Stream::isInput && tableType.size.max != UINT64_MAX) { flags |= 1; } + if(!Stream::isInput && tableType.size.max != UINT64_MAX) { flags |= 0x01; } #if ENABLE_THREADING_PROTOTYPE - if(!Stream::isInput && tableType.isShared) { flags |= 2; } + if(!Stream::isInput && tableType.isShared) { flags |= 0x10; } serializeVarUInt32(stream,flags); - if(Stream::isInput) { tableType.isShared = (flags & 2) != 0; } + if(Stream::isInput) { tableType.isShared = (flags & 0x10) != 0; } #else serializeVarUInt32(stream,flags); #endif - serialize(stream,tableType.size,flags & 1); + serialize(stream,tableType.size,flags & 0x01); } template void serialize(Stream& stream,MemoryType& memoryType) { Uptr flags = 0; - if(!Stream::isInput && memoryType.size.max != UINT64_MAX) { flags |= 1; } + if(!Stream::isInput && memoryType.size.max != UINT64_MAX) { flags |= 0x01; } #if ENABLE_THREADING_PROTOTYPE - if(!Stream::isInput && memoryType.isShared) { flags |= 2; } + if(!Stream::isInput && memoryType.isShared) { flags |= 0x10; } serializeVarUInt32(stream,flags); - if(Stream::isInput) { memoryType.isShared = (flags & 2) != 0; } + if(Stream::isInput) { memoryType.isShared = (flags & 0x10) != 0; } #else serializeVarUInt32(stream,flags); #endif - serialize(stream,memoryType.size,flags & 1); + serialize(stream,memoryType.size,flags & 0x01); } template diff --git a/libraries/wasm-jit/Source/WAST/Lexer.cpp b/libraries/wasm-jit/Source/WAST/Lexer.cpp index fbf42b9ce5b..9673eaca5e8 100644 --- a/libraries/wasm-jit/Source/WAST/Lexer.cpp +++ b/libraries/wasm-jit/Source/WAST/Lexer.cpp @@ -66,16 +66,16 @@ namespace WAST { static const std::pair regexpTokenPairs[] = { - {t_decimalInt,"[+\\-]?\\d+"}, - {t_decimalFloat,"[+\\-]?\\d+\\.\\d*([eE][+\\-]?\\d+)?"}, - {t_decimalFloat,"[+\\-]?\\d+[eE][+\\-]?\\d+"}, + {t_decimalInt,"[+\\-]?\\d+(_\\d+)*"}, + {t_decimalFloat,"[+\\-]?\\d+(_\\d+)*\\.(\\d+(_\\d+)*)*([eE][+\\-]?\\d+(_\\d+)*)?"}, + {t_decimalFloat,"[+\\-]?\\d+(_\\d+)*[eE][+\\-]?\\d+(_\\d+)*"}, - {t_hexInt,"[+\\-]?0[xX][\\da-fA-F]+"}, - {t_hexFloat,"[+\\-]?0[xX][\\da-fA-F]+\\.[\\da-fA-F]*([pP][+\\-]?\\d+)?"}, - {t_hexFloat,"[+\\-]?0[xX][\\da-fA-F]+[pP][+\\-]?\\d+"}, + {t_hexInt,"[+\\-]?0[xX][\\da-fA-F]+(_[\\da-fA-F]+)*"}, + {t_hexFloat,"[+\\-]?0[xX][\\da-fA-F]+(_[\\da-fA-F]+)*\\.([\\da-fA-F]+(_[\\da-fA-F]+)*)*([pP][+\\-]?\\d+(_\\d+)*)?"}, + {t_hexFloat,"[+\\-]?0[xX][\\da-fA-F]+(_[\\da-fA-F]+)*[pP][+\\-]?\\d+(_\\d+)*"}, - {t_floatNaN,"[+\\-]?nan(:0[xX][\\da-fA-F]+)?"}, - {t_floatInf,"[+\\-]?inf(inity)?"}, + {t_floatNaN,"[+\\-]?nan(:0[xX][\\da-fA-F]+(_[\\da-fA-F]+)*)?"}, + {t_floatInf,"[+\\-]?inf"}, {t_string,"\"([^\"\n\\\\]*(\\\\([^0-9a-fA-Fu]|[0-9a-fA-F][0-9a-fA-F]|u\\{[0-9a-fA-F]+})))*\""}, diff --git a/libraries/wasm-jit/Source/WAST/Parse.cpp b/libraries/wasm-jit/Source/WAST/Parse.cpp index 313185230b1..c1835511353 100644 --- a/libraries/wasm-jit/Source/WAST/Parse.cpp +++ b/libraries/wasm-jit/Source/WAST/Parse.cpp @@ -146,54 +146,81 @@ namespace WAST } })); - // Parse an optional result type. - tryParseParenthesizedTagged(state,t_result,[&] + // Parse <= 1 result type: (result *)* + while(state.nextToken[0].type == t_leftParenthesis + && state.nextToken[1].type == t_result) { - tryParseResultType(state,ret); - }); + parseParenthesized(state,[&] + { + require(state,t_result); + + ResultType resultElementType; + const Token* elementToken = state.nextToken; + while(tryParseResultType(state,resultElementType)) + { + if(ret != ResultType::none) { parseErrorf(state,elementToken,"function type cannot have more than 1 result element"); } + ret = resultElementType; + }; + }); + }; return FunctionType::get(ret,parameters); } - IndexedFunctionType parseFunctionTypeRef(ModuleParseState& state,NameToIndexMap& outLocalNameToIndexMap,std::vector& outLocalDisassemblyNames) + UnresolvedFunctionType parseFunctionTypeRefAndOrDecl(ModuleParseState& state,NameToIndexMap& outLocalNameToIndexMap,std::vector& outLocalDisassemblyNames) { // Parse an optional function type reference. - const Token* typeReferenceToken = state.nextToken; - IndexedFunctionType referencedFunctionType = {UINT32_MAX}; + Reference functionTypeRef; if(state.nextToken[0].type == t_leftParenthesis && state.nextToken[1].type == t_type) { - // Parse a reference by name or index to some type in the module's type table. parseParenthesized(state,[&] { require(state,t_type); - referencedFunctionType.index = parseAndResolveNameOrIndexRef(state,state.typeNameToIndexMap,state.module.types.size(),"type"); + if(!tryParseNameOrIndexRef(state,functionTypeRef)) + { + parseErrorf(state,state.nextToken,"expected type name or index"); + throw RecoverParseException(); + } }); } // Parse the explicit function parameters and result type. - const FunctionType* directFunctionType = parseFunctionType(state,outLocalNameToIndexMap,outLocalDisassemblyNames); - const bool hasNoDirectType = directFunctionType == FunctionType::get(); + const FunctionType* explicitFunctionType = parseFunctionType(state,outLocalNameToIndexMap,outLocalDisassemblyNames); - // Validate that if the function definition has both a type reference, and explicit parameter/result type declarations, that they match. - IndexedFunctionType functionType; - if(referencedFunctionType.index != UINT32_MAX && hasNoDirectType) + UnresolvedFunctionType result; + result.reference = functionTypeRef; + result.explicitType = explicitFunctionType; + return result; + } + + IndexedFunctionType resolveFunctionType(ModuleParseState& state,const UnresolvedFunctionType& unresolvedType) + { + if(!unresolvedType.reference) { - functionType = referencedFunctionType; + return getUniqueFunctionTypeIndex(state,unresolvedType.explicitType); } else { - functionType = getUniqueFunctionTypeIndex(state,directFunctionType); - if(referencedFunctionType.index != UINT32_MAX && state.module.types[referencedFunctionType.index] != directFunctionType) + // Resolve the referenced type. + const U32 referencedFunctionTypeIndex = resolveRef(state,state.typeNameToIndexMap,state.module.types.size(),unresolvedType.reference); + + // Validate that if the function definition has both a type reference and explicit parameter/result type declarations, they match. + const bool hasExplicitParametersOrResultType = unresolvedType.explicitType != FunctionType::get(); + if(hasExplicitParametersOrResultType) { - parseErrorf(state,typeReferenceToken,"referenced function type (%s) does not match declared parameters and results (%s)", - asString(state.module.types[referencedFunctionType.index]).c_str(), - asString(directFunctionType).c_str() - ); + if(referencedFunctionTypeIndex != UINT32_MAX + && state.module.types[referencedFunctionTypeIndex] != unresolvedType.explicitType) + { + parseErrorf(state,unresolvedType.reference.token,"referenced function type (%s) does not match declared parameters and results (%s)", + asString(state.module.types[referencedFunctionTypeIndex]).c_str(), + asString(unresolvedType.explicitType).c_str() + ); + } } - } - return functionType; + return {referencedFunctionTypeIndex}; + } } IndexedFunctionType getUniqueFunctionTypeIndex(ModuleParseState& state,const FunctionType* functionType) @@ -249,10 +276,10 @@ namespace WAST } }; - assert(nextChar - state.string > state.nextToken->begin + 1); + assert(U32(nextChar - state.string) > state.nextToken->begin + 1); ++state.nextToken; - assert(nextChar - state.string <= state.nextToken->begin); - assert(nextChar - firstChar <= UINT32_MAX); + assert(U32(nextChar - state.string) <= state.nextToken->begin); + assert(U32(nextChar - firstChar) <= UINT32_MAX); outName = Name(firstChar,U32(nextChar - firstChar)); return true; } diff --git a/libraries/wasm-jit/Source/WAST/Parse.h b/libraries/wasm-jit/Source/WAST/Parse.h index 450650f25a8..2a2623dae88 100644 --- a/libraries/wasm-jit/Source/WAST/Parse.h +++ b/libraries/wasm-jit/Source/WAST/Parse.h @@ -104,6 +104,13 @@ namespace WAST operator bool() const { return type != Type::invalid; } }; + // Represents a function type, either as an unresolved name/index, or as an explicit type, or both. + struct UnresolvedFunctionType + { + Reference reference; + const IR::FunctionType* explicitType; + }; + // State associated with parsing a module. struct ModuleParseState : ParseState { @@ -119,6 +126,9 @@ namespace WAST IR::DisassemblyNames disassemblyNames; + // Thunks that are called after parsing all types. + std::vector> postTypeCallbacks; + // Thunks that are called after parsing all declarations. std::vector> postDeclarationCallbacks; @@ -141,7 +151,8 @@ namespace WAST IR::ValueType parseValueType(ParseState& state); const IR::FunctionType* parseFunctionType(ModuleParseState& state,NameToIndexMap& outLocalNameToIndexMap,std::vector& outLocalDisassemblyNames); - IR::IndexedFunctionType parseFunctionTypeRef(ModuleParseState& state,NameToIndexMap& outLocalNameToIndexMap,std::vector& outLocalDisassemblyNames); + UnresolvedFunctionType parseFunctionTypeRefAndOrDecl(ModuleParseState& state,NameToIndexMap& outLocalNameToIndexMap,std::vector& outLocalDisassemblyNames); + IR::IndexedFunctionType resolveFunctionType(ModuleParseState& state,const UnresolvedFunctionType& unresolvedType); IR::IndexedFunctionType getUniqueFunctionTypeIndex(ModuleParseState& state,const IR::FunctionType* functionType); // Literal parsing. diff --git a/libraries/wasm-jit/Source/WAST/ParseFunction.cpp b/libraries/wasm-jit/Source/WAST/ParseFunction.cpp index 0e7e6e4b0ea..96f22782bdc 100644 --- a/libraries/wasm-jit/Source/WAST/ParseFunction.cpp +++ b/libraries/wasm-jit/Source/WAST/ParseFunction.cpp @@ -14,8 +14,6 @@ using namespace IR; namespace { - struct Local {}; - // State associated with parsing a function. struct FunctionParseState : ParseState { @@ -546,90 +544,79 @@ namespace WAST std::vector* localDisassemblyNames = new std::vector; NameToIndexMap* localNameToIndexMap = new NameToIndexMap(); - // Parse an optional function type reference. - const Token* typeReferenceToken = state.nextToken; - IndexedFunctionType referencedFunctionType = {UINT32_MAX}; - if(state.nextToken[0].type == t_leftParenthesis - && state.nextToken[1].type == t_type) - { - referencedFunctionType = parseFunctionTypeRef(state,*localNameToIndexMap,*localDisassemblyNames); - } - - // Parse the explicit function parameters and result type. - const FunctionType* directFunctionType = parseFunctionType(state,*localNameToIndexMap,*localDisassemblyNames); - const bool hasNoDirectType = directFunctionType == FunctionType::get(); - - // Validate that if the function definition has both a type reference, and explicit parameter/result type declarations, that they match. - IndexedFunctionType functionType; - if(referencedFunctionType.index != UINT32_MAX && hasNoDirectType) - { - functionType = referencedFunctionType; - } - else - { - functionType = getUniqueFunctionTypeIndex(state,directFunctionType); - if(referencedFunctionType.index != UINT32_MAX && state.module.types[referencedFunctionType.index] != directFunctionType) - { - parseErrorf(state,typeReferenceToken,"referenced function type (%s) does not match declared parameters and results (%s)", - asString(state.module.types[referencedFunctionType.index]).c_str(), - asString(directFunctionType).c_str() - ); - } - } - - // Parse the function's local variables. - std::vector nonParameterLocalTypes; - while(tryParseParenthesizedTagged(state,t_local,[&] - { - Name localName; - if(tryParseName(state,localName)) - { - bindName(state,*localNameToIndexMap,localName,directFunctionType->parameters.size() + nonParameterLocalTypes.size()); - localDisassemblyNames->push_back(localName.getString()); - nonParameterLocalTypes.push_back(parseValueType(state)); - } - else - { - while(state.nextToken->type != t_rightParenthesis) - { - localDisassemblyNames->push_back(std::string()); - nonParameterLocalTypes.push_back(parseValueType(state)); - }; - } - })); - - // Defer parsing the body of the function until after all declarations have been parsed. + // Parse the function type, as a reference or explicit declaration. + const UnresolvedFunctionType unresolvedFunctionType = parseFunctionTypeRefAndOrDecl(state,*localNameToIndexMap,*localDisassemblyNames); + + // Defer resolving the function type until all type declarations have been parsed. const Uptr functionIndex = state.module.functions.size(); const Uptr functionDefIndex = state.module.functions.defs.size(); const Token* firstBodyToken = state.nextToken; - state.postDeclarationCallbacks.push_back([functionIndex,functionDefIndex,firstBodyToken,localNameToIndexMap,localDisassemblyNames](ModuleParseState& state) + state.postTypeCallbacks.push_back( + [functionIndex,functionDefIndex,firstBodyToken,localNameToIndexMap,localDisassemblyNames,unresolvedFunctionType] + (ModuleParseState& state) { - FunctionParseState functionState(state,localNameToIndexMap,firstBodyToken,state.module.functions.defs[functionDefIndex]); - try + // Resolve the function type and set it on the FunctionDef. + const IndexedFunctionType functionTypeIndex = resolveFunctionType(state,unresolvedFunctionType); + state.module.functions.defs[functionDefIndex].type = functionTypeIndex; + + // Defer parsing the body of the function until all function types have been resolved. + state.postDeclarationCallbacks.push_back( + [functionIndex,functionDefIndex,firstBodyToken,localNameToIndexMap,localDisassemblyNames,functionTypeIndex] + (ModuleParseState& state) { - parseInstrSequence(functionState); - if(!functionState.errors.size()) + FunctionDef& functionDef = state.module.functions.defs[functionDefIndex]; + const FunctionType* functionType = functionTypeIndex.index == UINT32_MAX + ? FunctionType::get() + : state.module.types[functionTypeIndex.index]; + + // Parse the function's local variables. + ParseState localParseState(state.string,state.lineInfo,state.errors,firstBodyToken); + while(tryParseParenthesizedTagged(localParseState,t_local,[&] { - functionState.validatingCodeStream.end(); - functionState.validatingCodeStream.finishValidation(); - } - } - catch(ValidationException exception) - { - parseErrorf(state,firstBodyToken,"%s",exception.message.c_str()); - } - catch(RecoverParseException) {} - catch(FatalParseException) {} + Name localName; + if(tryParseName(localParseState,localName)) + { + bindName(localParseState,*localNameToIndexMap,localName,functionType->parameters.size() + functionDef.nonParameterLocalTypes.size()); + localDisassemblyNames->push_back(localName.getString()); + functionDef.nonParameterLocalTypes.push_back(parseValueType(localParseState)); + } + else + { + while(localParseState.nextToken->type != t_rightParenthesis) + { + localDisassemblyNames->push_back(std::string()); + functionDef.nonParameterLocalTypes.push_back(parseValueType(localParseState)); + }; + } + })); + state.disassemblyNames.functions[functionIndex].locals = std::move(*localDisassemblyNames); + delete localDisassemblyNames; - state.module.functions.defs[functionDefIndex].code = std::move(functionState.codeByteStream.getBytes()); - state.disassemblyNames.functions[functionIndex].locals = std::move(*localDisassemblyNames); - delete localDisassemblyNames; + // Parse the function's code. + FunctionParseState functionState(state,localNameToIndexMap,localParseState.nextToken,functionDef); + try + { + parseInstrSequence(functionState); + if(!functionState.errors.size()) + { + functionState.validatingCodeStream.end(); + functionState.validatingCodeStream.finishValidation(); + } + } + catch(ValidationException exception) + { + parseErrorf(state,firstBodyToken,"%s",exception.message.c_str()); + } + catch(RecoverParseException) {} + catch(FatalParseException) {} + functionDef.code = std::move(functionState.codeByteStream.getBytes()); + }); }); // Continue parsing after the closing parenthesis. findClosingParenthesis(state,funcToken-1); --state.nextToken; - return {functionType,std::move(nonParameterLocalTypes),{}}; + return {{UINT32_MAX},{},{}}; } } \ No newline at end of file diff --git a/libraries/wasm-jit/Source/WAST/ParseModule.cpp b/libraries/wasm-jit/Source/WAST/ParseModule.cpp index aa03cdd7cb2..13bdfe3d109 100644 --- a/libraries/wasm-jit/Source/WAST/ParseModule.cpp +++ b/libraries/wasm-jit/Source/WAST/ParseModule.cpp @@ -111,14 +111,16 @@ static void errorIfFollowsDefinitions(ModuleParseState& state) } template -static void createImport( +static Uptr createImport( ParseState& state,Name name,std::string&& moduleName,std::string&& exportName, NameToIndexMap& nameToIndexMap,IndexSpace& indexSpace,std::vector& disassemblyNameArray, Type type) { + const Uptr importIndex = indexSpace.imports.size(); bindName(state,nameToIndexMap,name,indexSpace.size()); disassemblyNameArray.push_back({name.getString()}); indexSpace.imports.push_back({type,std::move(moduleName),std::move(exportName)}); + return importIndex; } static bool parseOptionalSharedDeclaration(ModuleParseState& state) @@ -164,11 +166,17 @@ static void parseImport(ModuleParseState& state) { NameToIndexMap localNameToIndexMap; std::vector localDissassemblyNames; - const IndexedFunctionType functionType = parseFunctionTypeRef(state,localNameToIndexMap,localDissassemblyNames); - createImport(state,name,std::move(moduleName),std::move(exportName), + const UnresolvedFunctionType unresolvedFunctionType = parseFunctionTypeRefAndOrDecl(state,localNameToIndexMap,localDissassemblyNames); + const Uptr importIndex = createImport(state,name,std::move(moduleName),std::move(exportName), state.functionNameToIndexMap,state.module.functions,state.disassemblyNames.functions, - functionType); + {UINT32_MAX}); state.disassemblyNames.functions.back().locals = localDissassemblyNames; + + // Resolve the function import type after all type declarations have been parsed. + state.postTypeCallbacks.push_back([unresolvedFunctionType,importIndex](ModuleParseState& state) + { + state.module.functions.imports[importIndex].type = resolveFunctionType(state,unresolvedFunctionType); + }); break; } case t_table: @@ -373,7 +381,6 @@ static void parseElem(ModuleParseState& state) parseElemSegmentBody(state,tableRef,baseIndex,elemToken); } - template static void parseObjectDefOrImport( ModuleParseState& state, @@ -432,9 +439,18 @@ static void parseFunc(ModuleParseState& state) parseObjectDefOrImport(state,state.functionNameToIndexMap,state.module.functions,state.disassemblyNames.functions,t_func,ObjectKind::function, [&](ModuleParseState& state) { + // Parse the imported function's type. NameToIndexMap localNameToIndexMap; std::vector localDisassemblyNames; - return parseFunctionTypeRef(state,localNameToIndexMap,localDisassemblyNames); + const UnresolvedFunctionType unresolvedFunctionType = parseFunctionTypeRefAndOrDecl(state,localNameToIndexMap,localDisassemblyNames); + + // Resolve the function import type after all type declarations have been parsed. + const Uptr importIndex = state.module.functions.imports.size(); + state.postTypeCallbacks.push_back([unresolvedFunctionType,importIndex](ModuleParseState& state) + { + state.module.functions.imports[importIndex].type = resolveFunctionType(state,unresolvedFunctionType); + }); + return IndexedFunctionType {UINT32_MAX}; }, parseFunctionDef); } @@ -580,6 +596,15 @@ namespace WAST parseDeclaration(state); }; + // Process the callbacks requested after all type declarations have been parsed. + if(!state.errors.size()) + { + for(const auto& callback : state.postTypeCallbacks) + { + callback(state); + } + } + // Process the callbacks requested after all declarations have been parsed. if(!state.errors.size()) { diff --git a/libraries/wasm-jit/Source/WAST/ParseNumbers.cpp b/libraries/wasm-jit/Source/WAST/ParseNumbers.cpp index 23a9c50fc54..0f4a490c7ec 100644 --- a/libraries/wasm-jit/Source/WAST/ParseNumbers.cpp +++ b/libraries/wasm-jit/Source/WAST/ParseNumbers.cpp @@ -14,14 +14,13 @@ #include #define IEEE_8087 -#define NO_HEX_FP #define NO_INFNAN_CHECK -#define strtod parseDecimalF64 -#define dtoa printDecimalF64 +#define strtod parseNonSpecialF64 +#define dtoa printNonSpecialF64 #ifdef _MSC_VER #pragma warning(push) - #pragma warning(disable : 4244 4083 4706 4701 4703) + #pragma warning(disable : 4244 4083 4706 4701 4703 4018) #elif defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" @@ -43,7 +42,6 @@ #endif #undef IEEE_8087 -#undef NO_HEX_FP #undef NO_STRTOD_BIGCOMP #undef NO_INFNAN_CHECK #undef strtod @@ -70,8 +68,10 @@ static U64 parseHexUnsignedInt(const char*& nextChar,ParseState& state,U64 maxVa U64 result = 0; U8 hexit = 0; - while(tryParseHexit(nextChar,hexit)) + while(true) { + if(*nextChar == '_') { ++nextChar; continue; } + if(!tryParseHexit(nextChar,hexit)) { break; } if(result > (maxValue - hexit) / 16) { parseErrorf(state,firstHexit,"integer literal is too large"); @@ -91,8 +91,11 @@ static U64 parseDecimalUnsignedInt(const char*& nextChar,ParseState& state,U64 m { U64 result = 0; const char* firstDigit = nextChar; - while(*nextChar >= '0' && *nextChar <= '9') + while(true) { + if(*nextChar == '_') { ++nextChar; continue; } + if(*nextChar < '0' || *nextChar > '9') { break; } + const U8 digit = *nextChar - '0'; ++nextChar; @@ -100,7 +103,7 @@ static U64 parseDecimalUnsignedInt(const char*& nextChar,ParseState& state,U64 m { parseErrorf(state,firstDigit,"%s is too large",context); result = maxValue; - while(*nextChar >= '0' && *nextChar <= '9') { ++nextChar; }; + while((*nextChar >= '0' && *nextChar <= '9') || *nextChar == '_') { ++nextChar; }; break; } assert(result * 10 + digit >= result); @@ -158,121 +161,58 @@ Float parseInfinity(const char* nextChar) // Parses a decimal floating point literal, advancing nextChar past the parsed characters. // Assumes it will only be called for input that's already been accepted by the lexer as a decimal float literal. template -Float parseDecimalFloat(const char*& nextChar,ParseState& state) +Float parseFloat(const char*& nextChar,ParseState& state) { - // Use David Gay's strtod to parse a floating point number. + // Scan the token's characters for underscores, and make a copy of it without the underscores for strtod. const char* firstChar = nextChar; - F64 f64 = parseDecimalF64(nextChar,const_cast(&nextChar)); - if(nextChar == firstChar) - { - ++nextChar; - Errors::fatalf("strtod failed to parse number accepted by lexer"); - } - if(f64 < std::numeric_limits::lowest() || f64 > std::numeric_limits::max()) - { - parseErrorf(state,firstChar,"float literal is too large"); - } - - return (Float)f64; -} - -// Parses a hexadecimal floating point literal, advancing nextChar past the parsed characters. -// Assumes it will only be called for input that's already been accepted by the lexer as a hexadecimal float literal. -template -Float parseHexFloat(const char*& nextChar,ParseState& state) -{ - typedef typename Floats::FloatComponents FloatComponents; - typedef typename FloatComponents::Bits FloatBits; - FloatComponents resultComponents; - - resultComponents.bits.sign = parseSign(nextChar) ? 1 : 0; - - assert(nextChar[0] == '0' && (nextChar[1] == 'x' || nextChar[1] == 'X')); - nextChar += 2; - - // Parse hexits into a 64-bit fixed point number, keeping track of where the point is in exponent. - U64 fixedPoI64 = 0; - bool hasSeenPoint = false; - I64 exponent = 0; + std::string noUnderscoreString; + bool hasUnderscores = false; while(true) { - U8 hexit = 0; - if(tryParseHexit(nextChar,hexit)) + // Determine whether the next character is still part of the number. + bool isNumericChar = false; + switch(*nextChar) + { + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case '+': case '-': case 'x': case 'X': case '.': case 'p': case 'P': case '_': + isNumericChar = true; + break; + }; + if(!isNumericChar) { break; } + + if(*nextChar == '_' && !hasUnderscores) { - // Once there are too many hexits to accumulate in the 64-bit fixed point number, ignore - // the hexits, but continue to update exponent so we get an accurate but imprecise number. - if(fixedPoI64 <= (UINT64_MAX - 15) / 16) - { - assert(fixedPoI64 * 16 + hexit >= fixedPoI64); - fixedPoI64 = fixedPoI64 * 16 + hexit; - exponent -= hasSeenPoint ? 4 : 0; - } - else - { - exponent += hasSeenPoint ? 0 : 4; - } + // If this is the first underscore encountered, copy the preceding characters of the number to a std::string. + noUnderscoreString = std::string(firstChar,nextChar); + hasUnderscores = true; } - else if(*nextChar == '.') + else if(*nextChar != '_' && hasUnderscores) { - assert(!hasSeenPoint); - hasSeenPoint = true; - ++nextChar; + // If an underscore has previously been encountered, copy non-underscore characters to that string. + noUnderscoreString += *nextChar; } - else { break; } - } - // Parse an optional exponent. - if(*nextChar == 'p' || *nextChar == 'P') - { ++nextChar; - const bool isExponentNegative = parseSign(nextChar); - const U64 userExponent = parseDecimalUnsignedInt(nextChar,state,U64(-INT32_MIN),"float literal exponent"); - exponent = isExponentNegative ? exponent - userExponent : exponent + userExponent; - } + }; - if(!fixedPoI64) + // Pass the underscore-free string to parseNonSpecialF64 instead of the original input string. + if(hasUnderscores) { firstChar = noUnderscoreString.c_str(); } + + // Use David Gay's strtod to parse a floating point number. + char* endChar = nullptr; + F64 f64 = parseNonSpecialF64(firstChar,&endChar); + if(endChar == firstChar) { - // If both the integer and fractional part are zero, just return zero. - resultComponents.bits.exponent = 0; - resultComponents.bits.significand = 0; + Errors::fatalf("strtod failed to parse number accepted by lexer"); } - else + if(Float(f64) < std::numeric_limits::lowest() || Float(f64) > std::numeric_limits::max()) { - // Shift the fixed point number's most significant set bit into the MSB. - const Uptr leadingZeroes = Platform::countLeadingZeroes(fixedPoI64); - fixedPoI64 <<= leadingZeroes; - exponent += 64; - exponent -= leadingZeroes; - - const I64 exponentWithImplicitLeadingOne = exponent - 1; - if(exponentWithImplicitLeadingOne > FloatComponents::maxNormalExponent) - { - // If the number is out of range, produce an error and return infinity. - resultComponents.bits.exponent = FloatComponents::maxExponentBits; - resultComponents.bits.significand = FloatComponents::maxSignificand; - parseErrorf(state,state.nextToken,"hexadecimal float literal is out of range"); - } - else if(exponentWithImplicitLeadingOne < FloatComponents::minNormalExponent) - { - // Denormals are encoded as if their exponent is minNormalExponent, but - // with the significand shifted down to include the leading 1 that is implicit for - // normal numbers, and with the encoded exponent = 0. - const Uptr denormalShift = FloatComponents::minNormalExponent - exponent; - fixedPoI64 = denormalShift >= 64 ? 0 : (fixedPoI64 >> denormalShift); - resultComponents.bits.exponent = 0; - resultComponents.bits.significand = FloatBits(fixedPoI64 >> (64 - FloatComponents::numSignificandBits)); - } - else - { - // Encode a normal floating point value. - assert(exponentWithImplicitLeadingOne >= FloatComponents::minNormalExponent); - assert(exponentWithImplicitLeadingOne <= FloatComponents::maxNormalExponent); - resultComponents.bits.exponent = FloatBits(exponentWithImplicitLeadingOne + FloatComponents::exponentBias); - resultComponents.bits.significand = FloatBits(fixedPoI64 >> (63 - FloatComponents::numSignificandBits)); - } + parseErrorf(state,firstChar,"float literal is too large"); } - return resultComponents.value; + return (Float)f64; } // Tries to parse an numeric literal token as an integer, advancing state.nextToken. @@ -315,9 +255,9 @@ bool tryParseFloat(ParseState& state,Float& outFloat) switch(state.nextToken->type) { case t_decimalInt: - case t_decimalFloat: outFloat = parseDecimalFloat(nextChar,state); break; + case t_decimalFloat: outFloat = parseFloat(nextChar,state); break; case t_hexInt: - case t_hexFloat: outFloat = parseHexFloat(nextChar,state); break; + case t_hexFloat: outFloat = parseFloat(nextChar,state); break; case t_floatNaN: outFloat = parseNaN(nextChar,state); break; case t_floatInf: outFloat = parseInfinity(nextChar); break; default: diff --git a/libraries/wasm-jit/Source/WAST/ParseTests.cpp b/libraries/wasm-jit/Source/WAST/ParseTests.cpp index e62d94a9fc3..013e6449404 100644 --- a/libraries/wasm-jit/Source/WAST/ParseTests.cpp +++ b/libraries/wasm-jit/Source/WAST/ParseTests.cpp @@ -179,6 +179,12 @@ static Action* parseAction(ParseState& state) return result; } +template +static bool stringStartsWith(const char* string,const char (&prefix)[numPrefixChars]) +{ + return !strncmp(string,prefix,numPrefixChars - 1); +} + static Command* parseCommand(ParseState& state) { Command* result = nullptr; @@ -250,14 +256,11 @@ static Command* parseCommand(ParseState& state) else if(!strcmp(expectedErrorMessage.c_str(),"integer overflow")) { expectedCause = Runtime::Exception::Cause::integerDivideByZeroOrIntegerOverflow; } else if(!strcmp(expectedErrorMessage.c_str(),"integer divide by zero")) { expectedCause = Runtime::Exception::Cause::integerDivideByZeroOrIntegerOverflow; } else if(!strcmp(expectedErrorMessage.c_str(),"invalid conversion to integer")) { expectedCause = Runtime::Exception::Cause::invalidFloatOperation; } - else if(!strcmp(expectedErrorMessage.c_str(),"unreachable executed")) { expectedCause = Runtime::Exception::Cause::reachedUnreachable; } - else if(!strcmp(expectedErrorMessage.c_str(),"unreachable")) { expectedCause = Runtime::Exception::Cause::reachedUnreachable; } - else if(!strcmp(expectedErrorMessage.c_str(),"indirect call signature mismatch")) { expectedCause = Runtime::Exception::Cause::indirectCallSignatureMismatch; } - else if(!strcmp(expectedErrorMessage.c_str(),"indirect call")) { expectedCause = Runtime::Exception::Cause::indirectCallSignatureMismatch; } - else if(!strcmp(expectedErrorMessage.c_str(),"undefined element")) { expectedCause = Runtime::Exception::Cause::undefinedTableElement; } - else if(!strcmp(expectedErrorMessage.c_str(),"undefined")) { expectedCause = Runtime::Exception::Cause::undefinedTableElement; } - else if(!strcmp(expectedErrorMessage.c_str(),"uninitialized")) { expectedCause = Runtime::Exception::Cause::undefinedTableElement; } - else if(!strcmp(expectedErrorMessage.c_str(),"uninitialized element")) { expectedCause = Runtime::Exception::Cause::undefinedTableElement; } + else if(!strcmp(expectedErrorMessage.c_str(),"unaligned atomic")) { expectedCause = Runtime::Exception::Cause::misalignedAtomicMemoryAccess; } + else if(stringStartsWith(expectedErrorMessage.c_str(),"unreachable")) { expectedCause = Runtime::Exception::Cause::reachedUnreachable; } + else if(stringStartsWith(expectedErrorMessage.c_str(),"indirect call")) { expectedCause = Runtime::Exception::Cause::indirectCallSignatureMismatch; } + else if(stringStartsWith(expectedErrorMessage.c_str(),"undefined")) { expectedCause = Runtime::Exception::Cause::undefinedTableElement; } + else if(stringStartsWith(expectedErrorMessage.c_str(),"uninitialized")) { expectedCause = Runtime::Exception::Cause::undefinedTableElement; } result = new AssertTrapCommand(std::move(locus),action,expectedCause); break; diff --git a/libraries/wasm-jit/Test/spec/CMakeLists.txt b/libraries/wasm-jit/Test/spec/CMakeLists.txt index de768398db0..e08b6e3ed2b 100644 --- a/libraries/wasm-jit/Test/spec/CMakeLists.txt +++ b/libraries/wasm-jit/Test/spec/CMakeLists.txt @@ -7,6 +7,7 @@ add_test(WAVM_known_failures ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/WAVM_known_fa add_test(address ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/address.wast) add_test(align ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/align.wast) +add_test(atomic ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/atomic.wast) add_test(binary ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/binary.wast) add_test(block ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/block.wast) add_test(br ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/br.wast) @@ -19,6 +20,7 @@ add_test(comments ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/comments.wast) add_test(const ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/const.wast) add_test(conversions ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/conversions.wast) add_test(custom_section ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/custom_section.wast) +add_test(elem ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/elem.wast) add_test(endianness ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/endianness.wast) add_test(exports ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/exports.wast) add_test(f32 ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/f32.wast) @@ -64,10 +66,12 @@ add_test(switch ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/switch.wast) add_test(tee_local ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/tee_local.wast) add_test(token ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/token.wast) add_test(traps ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/traps.wast) +add_test(type ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/type.wast) add_test(typecheck ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/typecheck.wast) add_test(unreachable ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/unreachable.wast) add_test(unreached-invalid ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/unreached-invalid.wast) add_test(unwind ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/unwind.wast) +add_test(utf8-invalid-encoding ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/utf8-invalid-encoding.wast) add_test(utf8-custom-section-id ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/utf8-custom-section-id.wast) add_test(utf8-import-field ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/utf8-import-field.wast) add_test(utf8-import-module ${TEST_BIN} ${CMAKE_CURRENT_LIST_DIR}/utf8-import-module.wast) diff --git a/libraries/wasm-jit/Test/spec/WAVM_known_failures.wast b/libraries/wasm-jit/Test/spec/WAVM_known_failures.wast index 19dbcbec924..cc88951a5e3 100644 --- a/libraries/wasm-jit/Test/spec/WAVM_known_failures.wast +++ b/libraries/wasm-jit/Test/spec/WAVM_known_failures.wast @@ -194,21 +194,3 @@ (assert_return (invoke "f64.no_fold_div_one" (i64.const 0x7ff4000000000000)) (i64.const 0x7ff0000000000000)) (assert_return (invoke "f64.no_fold_div_neg1" (i64.const 0x7ff4000000000000)) (i64.const 0x7ff0000000000000)) (assert_return (invoke "no_fold_promote_demote" (i32.const 0x7fa00000)) (i32.const 0x7f800000)) - -;; -;; from int_exprs.wast -;; - -(module - (func (export "i32.no_fold_div_neg1") (param $x i32) (result i32) - (i32.div_s (get_local $x) (i32.const -1))) - - (func (export "i64.no_fold_div_neg1") (param $x i64) (result i64) - (i64.div_s (get_local $x) (i64.const -1))) -) - -(assert_return (invoke "i32.no_fold_div_neg1" (i32.const 0x80000000)) (i32.const 0x80000000)) -(assert_return (invoke "i64.no_fold_div_neg1" (i64.const 0x8000000000000000)) (i64.const 0x8000000000000000)) -;; should be: -;;(assert_trap (invoke "i32.no_fold_div_neg1" (i32.const 0x80000000)) "integer overflow") -;;(assert_trap (invoke "i64.no_fold_div_neg1" (i64.const 0x8000000000000000)) "integer overflow") \ No newline at end of file diff --git a/libraries/wasm-jit/Test/spec/address.wast b/libraries/wasm-jit/Test/spec/address.wast index 47bd21bad80..ee2a6bb3910 100644 --- a/libraries/wasm-jit/Test/spec/address.wast +++ b/libraries/wasm-jit/Test/spec/address.wast @@ -1,25 +1,47 @@ (module - (import "spectest" "print" (func $print (param i32))) - (memory 1) (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz") - (func (export "good") (param $i i32) - (call $print (i32.load8_u offset=0 (get_local $i))) ;; 97 'a' - (call $print (i32.load8_u offset=1 (get_local $i))) ;; 98 'b' - (call $print (i32.load8_u offset=2 (get_local $i))) ;; 99 'c' - (call $print (i32.load8_u offset=25 (get_local $i))) ;; 122 'z' + (func (export "good1") (param $i i32) (result i32) + (i32.load8_u offset=0 (get_local $i)) ;; 97 'a' + ) + (func (export "good2") (param $i i32) (result i32) + (i32.load8_u offset=1 (get_local $i)) ;; 98 'b' + ) + (func (export "good3") (param $i i32) (result i32) + (i32.load8_u offset=2 (get_local $i)) ;; 99 'c' + ) + (func (export "good4") (param $i i32) (result i32) + (i32.load8_u offset=25 (get_local $i)) ;; 122 'z' + ) - (call $print (i32.load16_u offset=0 (get_local $i))) ;; 25185 'ab' - (call $print (i32.load16_u align=1 (get_local $i))) ;; 25185 'ab' - (call $print (i32.load16_u offset=1 align=1 (get_local $i))) ;; 25442 'bc' - (call $print (i32.load16_u offset=2 (get_local $i))) ;; 25699 'cd' - (call $print (i32.load16_u offset=25 align=1 (get_local $i))) ;; 122 'z\0' + (func (export "good5") (param $i i32) (result i32) + (i32.load16_u offset=0 (get_local $i)) ;; 25185 'ab' + ) + (func (export "good6") (param $i i32) (result i32) + (i32.load16_u align=1 (get_local $i)) ;; 25185 'ab' + ) + (func (export "good7") (param $i i32) (result i32) + (i32.load16_u offset=1 align=1 (get_local $i)) ;; 25442 'bc' + ) + (func (export "good8") (param $i i32) (result i32) + (i32.load16_u offset=2 (get_local $i)) ;; 25699 'cd' + ) + (func (export "good9") (param $i i32) (result i32) + (i32.load16_u offset=25 align=1 (get_local $i)) ;; 122 'z\0' + ) - (call $print (i32.load offset=0 (get_local $i))) ;; 1684234849 'abcd' - (call $print (i32.load offset=1 align=1 (get_local $i))) ;; 1701077858 'bcde' - (call $print (i32.load offset=2 align=2 (get_local $i))) ;; 1717920867 'cdef' - (call $print (i32.load offset=25 align=1 (get_local $i))) ;; 122 'z\0\0\0' + (func (export "good10") (param $i i32) (result i32) + (i32.load offset=0 (get_local $i)) ;; 1684234849 'abcd' + ) + (func (export "good11") (param $i i32) (result i32) + (i32.load offset=1 align=1 (get_local $i)) ;; 1701077858 'bcde' + ) + (func (export "good12") (param $i i32) (result i32) + (i32.load offset=2 align=2 (get_local $i)) ;; 1717920867 'cdef' + ) + (func (export "good13") (param $i i32) (result i32) + (i32.load offset=25 align=1 (get_local $i)) ;; 122 'z\0\0\0' ) (func (export "bad") (param $i i32) @@ -27,9 +49,48 @@ ) ) -(invoke "good" (i32.const 0)) -(invoke "good" (i32.const 65507)) -(assert_trap (invoke "good" (i32.const 65508)) "out of bounds memory access") +(assert_return (invoke "good1" (i32.const 0)) (i32.const 97)) +(assert_return (invoke "good2" (i32.const 0)) (i32.const 98)) +(assert_return (invoke "good3" (i32.const 0)) (i32.const 99)) +(assert_return (invoke "good4" (i32.const 0)) (i32.const 122)) +(assert_return (invoke "good5" (i32.const 0)) (i32.const 25185)) +(assert_return (invoke "good6" (i32.const 0)) (i32.const 25185)) +(assert_return (invoke "good7" (i32.const 0)) (i32.const 25442)) +(assert_return (invoke "good8" (i32.const 0)) (i32.const 25699)) +(assert_return (invoke "good9" (i32.const 0)) (i32.const 122)) +(assert_return (invoke "good10" (i32.const 0)) (i32.const 1684234849)) +(assert_return (invoke "good11" (i32.const 0)) (i32.const 1701077858)) +(assert_return (invoke "good12" (i32.const 0)) (i32.const 1717920867)) +(assert_return (invoke "good13" (i32.const 0)) (i32.const 122)) + +(assert_return (invoke "good1" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good2" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good3" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good4" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good5" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good6" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good7" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good8" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good9" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good10" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good11" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good12" (i32.const 65507)) (i32.const 0)) +(assert_return (invoke "good13" (i32.const 65507)) (i32.const 0)) + +(assert_return (invoke "good1" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good2" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good3" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good4" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good5" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good6" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good7" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good8" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good9" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good10" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good11" (i32.const 65508)) (i32.const 0)) +(assert_return (invoke "good12" (i32.const 65508)) (i32.const 0)) +(assert_trap (invoke "good13" (i32.const 65508)) "out of bounds memory access") + (assert_trap (invoke "bad" (i32.const 0)) "out of bounds memory access") (assert_trap (invoke "bad" (i32.const 1)) "out of bounds memory access") diff --git a/libraries/wasm-jit/Test/spec/atomic.wast b/libraries/wasm-jit/Test/spec/atomic.wast new file mode 100644 index 00000000000..84c5847681f --- /dev/null +++ b/libraries/wasm-jit/Test/spec/atomic.wast @@ -0,0 +1,418 @@ +;; atomic operations + +(module + (memory 1 1) + + (func (export "init") (param $value i64) (i64.store (i32.const 0) (get_local $value))) + + (func (export "i32.atomic.load") (param $addr i32) (result i32) (i32.atomic.load (get_local $addr))) + (func (export "i64.atomic.load") (param $addr i32) (result i64) (i64.atomic.load (get_local $addr))) + (func (export "i32.atomic.load8_u") (param $addr i32) (result i32) (i32.atomic.load8_u (get_local $addr))) + (func (export "i32.atomic.load16_u") (param $addr i32) (result i32) (i32.atomic.load16_u (get_local $addr))) + (func (export "i64.atomic.load8_u") (param $addr i32) (result i64) (i64.atomic.load8_u (get_local $addr))) + (func (export "i64.atomic.load16_u") (param $addr i32) (result i64) (i64.atomic.load16_u (get_local $addr))) + (func (export "i64.atomic.load32_u") (param $addr i32) (result i64) (i64.atomic.load32_u (get_local $addr))) + + (func (export "i32.atomic.store") (param $addr i32) (param $value i32) (i32.atomic.store (get_local $addr) (get_local $value))) + (func (export "i64.atomic.store") (param $addr i32) (param $value i64) (i64.atomic.store (get_local $addr) (get_local $value))) + (func (export "i32.atomic.store8") (param $addr i32) (param $value i32) (i32.atomic.store8 (get_local $addr) (get_local $value))) + (func (export "i32.atomic.store16") (param $addr i32) (param $value i32) (i32.atomic.store16 (get_local $addr) (get_local $value))) + (func (export "i64.atomic.store8") (param $addr i32) (param $value i64) (i64.atomic.store8 (get_local $addr) (get_local $value))) + (func (export "i64.atomic.store16") (param $addr i32) (param $value i64) (i64.atomic.store16 (get_local $addr) (get_local $value))) + (func (export "i64.atomic.store32") (param $addr i32) (param $value i64) (i64.atomic.store32 (get_local $addr) (get_local $value))) + + (func (export "i32.atomic.rmw.add") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.add (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw.add") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.add (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw8_u.add") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw8_u.add (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw16_u.add") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16_u.add (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw8_u.add") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw8_u.add (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw16_u.add") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16_u.add (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw32_u.add") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32_u.add (get_local $addr) (get_local $value))) + + (func (export "i32.atomic.rmw.sub") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.sub (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw.sub") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.sub (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw8_u.sub") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw8_u.sub (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw16_u.sub") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16_u.sub (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw8_u.sub") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw8_u.sub (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw16_u.sub") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16_u.sub (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw32_u.sub") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32_u.sub (get_local $addr) (get_local $value))) + + (func (export "i32.atomic.rmw.and") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.and (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw.and") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.and (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw8_u.and") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw8_u.and (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw16_u.and") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16_u.and (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw8_u.and") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw8_u.and (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw16_u.and") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16_u.and (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw32_u.and") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32_u.and (get_local $addr) (get_local $value))) + + (func (export "i32.atomic.rmw.or") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.or (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw.or") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.or (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw8_u.or") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw8_u.or (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw16_u.or") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16_u.or (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw8_u.or") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw8_u.or (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw16_u.or") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16_u.or (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw32_u.or") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32_u.or (get_local $addr) (get_local $value))) + + (func (export "i32.atomic.rmw.xor") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.xor (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw.xor") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.xor (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw8_u.xor") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw8_u.xor (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw16_u.xor") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16_u.xor (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw8_u.xor") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw8_u.xor (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw16_u.xor") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16_u.xor (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw32_u.xor") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32_u.xor (get_local $addr) (get_local $value))) + + (func (export "i32.atomic.rmw.xchg") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.xchg (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw.xchg") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.xchg (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw8_u.xchg") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw8_u.xchg (get_local $addr) (get_local $value))) + (func (export "i32.atomic.rmw16_u.xchg") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16_u.xchg (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw8_u.xchg") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw8_u.xchg (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw16_u.xchg") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16_u.xchg (get_local $addr) (get_local $value))) + (func (export "i64.atomic.rmw32_u.xchg") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32_u.xchg (get_local $addr) (get_local $value))) + + (func (export "i32.atomic.rmw.cmpxchg") (param $addr i32) (param $expected i32) (param $value i32) (result i32) (i32.atomic.rmw.cmpxchg (get_local $addr) (get_local $expected) (get_local $value))) + (func (export "i64.atomic.rmw.cmpxchg") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw.cmpxchg (get_local $addr) (get_local $expected) (get_local $value))) + (func (export "i32.atomic.rmw8_u.cmpxchg") (param $addr i32) (param $expected i32) (param $value i32) (result i32) (i32.atomic.rmw8_u.cmpxchg (get_local $addr) (get_local $expected) (get_local $value))) + (func (export "i32.atomic.rmw16_u.cmpxchg") (param $addr i32) (param $expected i32) (param $value i32) (result i32) (i32.atomic.rmw16_u.cmpxchg (get_local $addr) (get_local $expected) (get_local $value))) + (func (export "i64.atomic.rmw8_u.cmpxchg") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw8_u.cmpxchg (get_local $addr) (get_local $expected) (get_local $value))) + (func (export "i64.atomic.rmw16_u.cmpxchg") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw16_u.cmpxchg (get_local $addr) (get_local $expected) (get_local $value))) + (func (export "i64.atomic.rmw32_u.cmpxchg") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw32_u.cmpxchg (get_local $addr) (get_local $expected) (get_local $value))) + +) + +;; *.atomic.load* + +(invoke "init" (i64.const 0x0706050403020100)) + +(assert_return (invoke "i32.atomic.load" (i32.const 0)) (i32.const 0x03020100)) +(assert_return (invoke "i32.atomic.load" (i32.const 4)) (i32.const 0x07060504)) + +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x0706050403020100)) + +(assert_return (invoke "i32.atomic.load8_u" (i32.const 0)) (i32.const 0x00)) +(assert_return (invoke "i32.atomic.load8_u" (i32.const 5)) (i32.const 0x05)) + +(assert_return (invoke "i32.atomic.load16_u" (i32.const 0)) (i32.const 0x0100)) +(assert_return (invoke "i32.atomic.load16_u" (i32.const 6)) (i32.const 0x0706)) + +(assert_return (invoke "i64.atomic.load8_u" (i32.const 0)) (i64.const 0x00)) +(assert_return (invoke "i64.atomic.load8_u" (i32.const 5)) (i64.const 0x05)) + +(assert_return (invoke "i64.atomic.load16_u" (i32.const 0)) (i64.const 0x0100)) +(assert_return (invoke "i64.atomic.load16_u" (i32.const 6)) (i64.const 0x0706)) + +(assert_return (invoke "i64.atomic.load32_u" (i32.const 0)) (i64.const 0x03020100)) +(assert_return (invoke "i64.atomic.load32_u" (i32.const 4)) (i64.const 0x07060504)) + +;; *.atomic.store* + +(invoke "init" (i64.const 0x0000000000000000)) + +(assert_return (invoke "i32.atomic.store" (i32.const 0) (i32.const 0xffeeddcc))) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x00000000ffeeddcc)) + +(assert_return (invoke "i64.atomic.store" (i32.const 0) (i64.const 0x0123456789abcdef))) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x0123456789abcdef)) + +(assert_return (invoke "i32.atomic.store8" (i32.const 1) (i32.const 0x42))) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x0123456789ab42ef)) + +(assert_return (invoke "i32.atomic.store16" (i32.const 4) (i32.const 0x8844))) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x0123884489ab42ef)) + +(assert_return (invoke "i64.atomic.store8" (i32.const 1) (i64.const 0x99))) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x0123884489ab99ef)) + +(assert_return (invoke "i64.atomic.store16" (i32.const 4) (i64.const 0xcafe))) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x0123cafe89ab99ef)) + +(assert_return (invoke "i64.atomic.store32" (i32.const 4) (i64.const 0xdeadbeef))) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0xdeadbeef89ab99ef)) + +;; *.atomic.rmw*.add + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw.add" (i32.const 0) (i32.const 0x12345678)) (i32.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111123456789)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw.add" (i32.const 0) (i64.const 0x0101010102020202)) (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1212121213131313)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw8_u.add" (i32.const 0) (i32.const 0xcdcdcdcd)) (i32.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111111111de)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw16_u.add" (i32.const 0) (i32.const 0xcafecafe)) (i32.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x111111111111dc0f)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw8_u.add" (i32.const 0) (i64.const 0x4242424242424242)) (i64.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111153)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw16_u.add" (i32.const 0) (i64.const 0xbeefbeefbeefbeef)) (i64.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x111111111111d000)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw32_u.add" (i32.const 0) (i64.const 0xcabba6e5cabba6e5)) (i64.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111dbccb7f6)) + +;; *.atomic.rmw*.sub + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw.sub" (i32.const 0) (i32.const 0x12345678)) (i32.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111fedcba99)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw.sub" (i32.const 0) (i64.const 0x0101010102020202)) (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x101010100f0f0f0f)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw8_u.sub" (i32.const 0) (i32.const 0xcdcdcdcd)) (i32.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111144)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw16_u.sub" (i32.const 0) (i32.const 0xcafecafe)) (i32.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111114613)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw8_u.sub" (i32.const 0) (i64.const 0x4242424242424242)) (i64.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111111111cf)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw16_u.sub" (i32.const 0) (i64.const 0xbeefbeefbeefbeef)) (i64.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111115222)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw32_u.sub" (i32.const 0) (i64.const 0xcabba6e5cabba6e5)) (i64.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111146556a2c)) + +;; *.atomic.rmw*.and + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw.and" (i32.const 0) (i32.const 0x12345678)) (i32.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111110101010)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw.and" (i32.const 0) (i64.const 0x0101010102020202)) (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x0101010100000000)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw8_u.and" (i32.const 0) (i32.const 0xcdcdcdcd)) (i32.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111101)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw16_u.and" (i32.const 0) (i32.const 0xcafecafe)) (i32.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111110010)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw8_u.and" (i32.const 0) (i64.const 0x4242424242424242)) (i64.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111100)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw16_u.and" (i32.const 0) (i64.const 0xbeefbeefbeefbeef)) (i64.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111001)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw32_u.and" (i32.const 0) (i64.const 0xcabba6e5cabba6e5)) (i64.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111100110001)) + +;; *.atomic.rmw*.or + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw.or" (i32.const 0) (i32.const 0x12345678)) (i32.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111113355779)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw.or" (i32.const 0) (i64.const 0x0101010102020202)) (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111113131313)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw8_u.or" (i32.const 0) (i32.const 0xcdcdcdcd)) (i32.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111111111dd)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw16_u.or" (i32.const 0) (i32.const 0xcafecafe)) (i32.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x111111111111dbff)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw8_u.or" (i32.const 0) (i64.const 0x4242424242424242)) (i64.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111153)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw16_u.or" (i32.const 0) (i64.const 0xbeefbeefbeefbeef)) (i64.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x111111111111bfff)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw32_u.or" (i32.const 0) (i64.const 0xcabba6e5cabba6e5)) (i64.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111dbbbb7f5)) + +;; *.atomic.rmw*.xor + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw.xor" (i32.const 0) (i32.const 0x12345678)) (i32.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111103254769)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw.xor" (i32.const 0) (i64.const 0x0101010102020202)) (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1010101013131313)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw8_u.xor" (i32.const 0) (i32.const 0xcdcdcdcd)) (i32.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111111111dc)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw16_u.xor" (i32.const 0) (i32.const 0xcafecafe)) (i32.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x111111111111dbef)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw8_u.xor" (i32.const 0) (i64.const 0x4242424242424242)) (i64.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111153)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw16_u.xor" (i32.const 0) (i64.const 0xbeefbeefbeefbeef)) (i64.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x111111111111affe)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw32_u.xor" (i32.const 0) (i64.const 0xcabba6e5cabba6e5)) (i64.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111dbaab7f4)) + +;; *.atomic.rmw*.xchg + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw.xchg" (i32.const 0) (i32.const 0x12345678)) (i32.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111112345678)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw.xchg" (i32.const 0) (i64.const 0x0101010102020202)) (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x0101010102020202)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw8_u.xchg" (i32.const 0) (i32.const 0xcdcdcdcd)) (i32.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111111111cd)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw16_u.xchg" (i32.const 0) (i32.const 0xcafecafe)) (i32.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x111111111111cafe)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw8_u.xchg" (i32.const 0) (i64.const 0x4242424242424242)) (i64.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111142)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw16_u.xchg" (i32.const 0) (i64.const 0xbeefbeefbeefbeef)) (i64.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x111111111111beef)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw32_u.xchg" (i32.const 0) (i64.const 0xcabba6e5cabba6e5)) (i64.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111cabba6e5)) + +;; *.atomic.rmw*.cmpxchg (compare false) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw.cmpxchg" (i32.const 0) (i32.const 0) (i32.const 0x12345678)) (i32.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111111)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw.cmpxchg" (i32.const 0) (i64.const 0) (i64.const 0x0101010102020202)) (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111111)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw8_u.cmpxchg" (i32.const 0) (i32.const 0) (i32.const 0xcdcdcdcd)) (i32.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111111)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw16_u.cmpxchg" (i32.const 0) (i32.const 0) (i32.const 0xcafecafe)) (i32.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111111)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw8_u.cmpxchg" (i32.const 0) (i64.const 0) (i64.const 0x4242424242424242)) (i64.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111111)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw16_u.cmpxchg" (i32.const 0) (i64.const 0) (i64.const 0xbeefbeefbeefbeef)) (i64.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111111)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw32_u.cmpxchg" (i32.const 0) (i64.const 0) (i64.const 0xcabba6e5cabba6e5)) (i64.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111111)) + +;; *.atomic.rmw*.cmpxchg (compare true) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw.cmpxchg" (i32.const 0) (i32.const 0x11111111) (i32.const 0x12345678)) (i32.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111112345678)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw.cmpxchg" (i32.const 0) (i64.const 0x1111111111111111) (i64.const 0x0101010102020202)) (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x0101010102020202)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw8_u.cmpxchg" (i32.const 0) (i32.const 0x11) (i32.const 0xcdcdcdcd)) (i32.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111111111cd)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i32.atomic.rmw16_u.cmpxchg" (i32.const 0) (i32.const 0x1111) (i32.const 0xcafecafe)) (i32.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x111111111111cafe)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw8_u.cmpxchg" (i32.const 0) (i64.const 0x11) (i64.const 0x4242424242424242)) (i64.const 0x11)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x1111111111111142)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw16_u.cmpxchg" (i32.const 0) (i64.const 0x1111) (i64.const 0xbeefbeefbeefbeef)) (i64.const 0x1111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x111111111111beef)) + +(invoke "init" (i64.const 0x1111111111111111)) +(assert_return (invoke "i64.atomic.rmw32_u.cmpxchg" (i32.const 0) (i64.const 0x11111111) (i64.const 0xcabba6e5cabba6e5)) (i64.const 0x11111111)) +(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0x11111111cabba6e5)) + + +;; unaligned accesses + +(assert_trap (invoke "i32.atomic.load" (i32.const 1)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.load" (i32.const 1)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.load16_u" (i32.const 1)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.load16_u" (i32.const 1)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.load32_u" (i32.const 1)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.store" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.store" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.store16" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.store16" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.store32" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw.add" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw.add" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw16_u.add" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw16_u.add" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw32_u.add" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw.sub" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw.sub" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw16_u.sub" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw16_u.sub" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw32_u.sub" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw.and" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw.and" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw16_u.and" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw16_u.and" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw32_u.and" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw.or" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw.or" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw16_u.or" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw16_u.or" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw32_u.or" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw.xor" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw.xor" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw16_u.xor" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw16_u.xor" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw32_u.xor" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw.xchg" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw.xchg" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw16_u.xchg" (i32.const 1) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw16_u.xchg" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw32_u.xchg" (i32.const 1) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw.cmpxchg" (i32.const 1) (i32.const 0) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw.cmpxchg" (i32.const 1) (i64.const 0) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i32.atomic.rmw16_u.cmpxchg" (i32.const 1) (i32.const 0) (i32.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw16_u.cmpxchg" (i32.const 1) (i64.const 0) (i64.const 0)) "unaligned atomic") +(assert_trap (invoke "i64.atomic.rmw32_u.cmpxchg" (i32.const 1) (i64.const 0) (i64.const 0)) "unaligned atomic") diff --git a/libraries/wasm-jit/Test/spec/call_indirect.wast b/libraries/wasm-jit/Test/spec/call_indirect.wast index 3c27c53c69e..b9b152e8225 100644 --- a/libraries/wasm-jit/Test/spec/call_indirect.wast +++ b/libraries/wasm-jit/Test/spec/call_indirect.wast @@ -376,33 +376,3 @@ (module (table anyfunc (elem 0 0))) "unknown function 0" ) - - -;; Invalid bounds for elements - -(assert_unlinkable - (module - (table 10 anyfunc) - (elem (i32.const 10) $f) - (func $f) - ) - "elements segment does not fit" -) - -(assert_unlinkable - (module - (table 10 anyfunc) - (elem (i32.const -1) $f) - (func $f) - ) - "elements segment does not fit" -) - -(assert_unlinkable - (module - (table 10 anyfunc) - (elem (i32.const -10) $f) - (func $f) - ) - "elements segment does not fit" -) diff --git a/libraries/wasm-jit/Test/spec/const.wast b/libraries/wasm-jit/Test/spec/const.wast index 9eb591a45e0..5929646c3e7 100644 --- a/libraries/wasm-jit/Test/spec/const.wast +++ b/libraries/wasm-jit/Test/spec/const.wast @@ -45,3 +45,93 @@ (module quote "(func (i64.const -9223372036854775809) drop)") "constant out of range" ) + +(module (func (f32.const 0x1p127) drop)) +(module (func (f32.const -0x1p127) drop)) +(module (func (f32.const 0x1.fffffep127) drop)) +(module (func (f32.const -0x1.fffffep127) drop)) +(module (func (f32.const 0x1.fffffe7p127) drop)) +(module (func (f32.const -0x1.fffffe7p127) drop)) +(assert_malformed + (module quote "(func (f32.const 0x1p128) drop)") + "constant out of range" +) +(assert_malformed + (module quote "(func (f32.const -0x1p128) drop)") + "constant out of range" +) +(assert_malformed + (module quote "(func (f32.const 0x1.ffffffp127) drop)") + "constant out of range" +) +(assert_malformed + (module quote "(func (f32.const -0x1.ffffffp127) drop)") + "constant out of range" +) + +(module (func (f32.const 1e38) drop)) +(module (func (f32.const -1e38) drop)) +(assert_malformed + (module quote "(func (f32.const 1e39) drop)") + "constant out of range" +) +(assert_malformed + (module quote "(func (f32.const -1e39) drop)") + "constant out of range" +) + +(module (func (f32.const 340282356779733623858607532500980858880) drop)) +(module (func (f32.const -340282356779733623858607532500980858880) drop)) +(assert_malformed + (module quote "(func (f32.const 340282356779733661637539395458142568448) drop)") + "constant out of range" +) +(assert_malformed + (module quote "(func (f32.const -340282356779733661637539395458142568448) drop)") + "constant out of range" +) + +(module (func (f64.const 0x1p1023) drop)) +(module (func (f64.const -0x1p1023) drop)) +(module (func (f64.const 0x1.fffffffffffffp1023) drop)) +(module (func (f64.const -0x1.fffffffffffffp1023) drop)) +(module (func (f64.const 0x1.fffffffffffff7p1023) drop)) +(module (func (f64.const -0x1.fffffffffffff7p1023) drop)) +(assert_malformed + (module quote "(func (f64.const 0x1p1024) drop)") + "constant out of range" +) +(assert_malformed + (module quote "(func (f64.const -0x1p1024) drop)") + "constant out of range" +) +(assert_malformed + (module quote "(func (f64.const 0x1.fffffffffffff8p1023) drop)") + "constant out of range" +) +(assert_malformed + (module quote "(func (f64.const -0x1.fffffffffffff8p1023) drop)") + "constant out of range" +) + +(module (func (f64.const 1e308) drop)) +(module (func (f64.const -1e308) drop)) +(assert_malformed + (module quote "(func (f64.const 1e309) drop)") + "constant out of range" +) +(assert_malformed + (module quote "(func (f64.const -1e309) drop)") + "constant out of range" +) + +(module (func (f64.const 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368) drop)) +(module (func (f64.const -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368) drop)) +(assert_malformed + (module quote "(func (f64.const 269653970229347356221791135597556535197105851288767494898376215204735891170042808140884337949150317257310688430271573696351481990334196274152701320055306275479074865864826923114368235135583993416113802762682700913456874855354834422248712838998185022412196739306217084753107265771378949821875606039276187287552) drop)") + "constant out of range" +) +(assert_malformed + (module quote "(func (f64.const -269653970229347356221791135597556535197105851288767494898376215204735891170042808140884337949150317257310688430271573696351481990334196274152701320055306275479074865864826923114368235135583993416113802762682700913456874855354834422248712838998185022412196739306217084753107265771378949821875606039276187287552) drop)") + "constant out of range" +) diff --git a/libraries/wasm-jit/Test/spec/elem.wast b/libraries/wasm-jit/Test/spec/elem.wast new file mode 100644 index 00000000000..c75e07b23e3 --- /dev/null +++ b/libraries/wasm-jit/Test/spec/elem.wast @@ -0,0 +1,215 @@ +;; Test the element section + +(module + (table 10 anyfunc) + (elem (i32.const 0) $f) + (func $f) +) + +(module + (table 10 anyfunc) + (elem (i32.const 9) $f) + (func $f) +) + +(module + (type $out-i32 (func (result i32))) + (table 10 anyfunc) + (elem (i32.const 7) $const-i32-a) + (elem (i32.const 9) $const-i32-b) + (func $const-i32-a (type $out-i32) (i32.const 65)) + (func $const-i32-b (type $out-i32) (i32.const 66)) + (func (export "call-7") (type $out-i32) + (call_indirect $out-i32 (i32.const 7)) + ) + (func (export "call-9") (type $out-i32) + (call_indirect $out-i32 (i32.const 9)) + ) +) + +(assert_return (invoke "call-7") (i32.const 65)) +(assert_return (invoke "call-9") (i32.const 66)) + +;; Two elements target the same slot + +(module + (type $out-i32 (func (result i32))) + (table 10 anyfunc) + (elem (i32.const 9) $const-i32-a) + (elem (i32.const 9) $const-i32-b) + (func $const-i32-a (type $out-i32) (i32.const 65)) + (func $const-i32-b (type $out-i32) (i32.const 66)) + (func (export "call-overwritten-element") (type $out-i32) + (call_indirect $out-i32 (i32.const 9)) + ) +) + +(assert_return (invoke "call-overwritten-element") (i32.const 66)) + +;; Invalid bounds for elements + +(assert_unlinkable + (module + (table 10 anyfunc) + (elem (i32.const 10) $f) + (func $f) + ) + "elements segment does not fit" +) + +(assert_unlinkable + (module + (table 10 20 anyfunc) + (elem (i32.const 10) $f) + (func $f) + ) + "elements segment does not fit" +) + +(assert_unlinkable + (module + (table 10 anyfunc) + (elem (i32.const -1) $f) + (func $f) + ) + "elements segment does not fit" +) + +(assert_unlinkable + (module + (table 10 anyfunc) + (elem (i32.const -10) $f) + (func $f) + ) + "elements segment does not fit" +) + +;; Tests with an imported table + +(module + (import "spectest" "table" (table 10 anyfunc)) + (elem (i32.const 0) $f) + (func $f) +) + +(module + (import "spectest" "table" (table 10 anyfunc)) + (elem (i32.const 9) $f) + (func $f) +) + +;; Two elements target the same slot + +(module + (type $out-i32 (func (result i32))) + (import "spectest" "table" (table 10 anyfunc)) + (elem (i32.const 9) $const-i32-a) + (elem (i32.const 9) $const-i32-b) + (func $const-i32-a (type $out-i32) (i32.const 65)) + (func $const-i32-b (type $out-i32) (i32.const 66)) + (func (export "call-overwritten-element") (type $out-i32) + (call_indirect $out-i32 (i32.const 9)) + ) +) + +(assert_return (invoke "call-overwritten-element") (i32.const 66)) + +;; Invalid bounds for elements + +(assert_unlinkable + (module + (import "spectest" "table" (table 10 anyfunc)) + (elem (i32.const 10) $f) + (func $f) + ) + "elements segment does not fit" +) + +(assert_unlinkable + (module + (import "spectest" "table" (table 10 20 anyfunc)) + (elem (i32.const 10) $f) + (func $f) + ) + "elements segment does not fit" +) + +(assert_unlinkable + (module + (import "spectest" "table" (table 10 anyfunc)) + (elem (i32.const -1) $f) + (func $f) + ) + "elements segment does not fit" +) + +(assert_unlinkable + (module + (import "spectest" "table" (table 10 anyfunc)) + (elem (i32.const -10) $f) + (func $f) + ) + "elements segment does not fit" +) + +;; Element without table + +(assert_invalid + (module + (elem (i32.const 0) $f) + (func $f) + ) + "unknown table 0" +) + +;; Test element sections across multiple modules change the same table + +(module $module1 + (type $out-i32 (func (result i32))) + (table (export "shared-table") 10 anyfunc) + (elem (i32.const 8) $const-i32-a) + (elem (i32.const 9) $const-i32-b) + (func $const-i32-a (type $out-i32) (i32.const 65)) + (func $const-i32-b (type $out-i32) (i32.const 66)) + (func (export "call-7") (type $out-i32) + (call_indirect $out-i32 (i32.const 7)) + ) + (func (export "call-8") (type $out-i32) + (call_indirect $out-i32 (i32.const 8)) + ) + (func (export "call-9") (type $out-i32) + (call_indirect $out-i32 (i32.const 9)) + ) +) + +(register "module1" $module1) + +(assert_trap (invoke $module1 "call-7") "uninitialized element 7") +(assert_return (invoke $module1 "call-8") (i32.const 65)) +(assert_return (invoke $module1 "call-9") (i32.const 66)) + +(module $module2 + (type $out-i32 (func (result i32))) + (import "module1" "shared-table" (table 10 anyfunc)) + (elem (i32.const 7) $const-i32-c) + (elem (i32.const 8) $const-i32-d) + (func $const-i32-c (type $out-i32) (i32.const 67)) + (func $const-i32-d (type $out-i32) (i32.const 68)) +) + +(assert_return (invoke $module1 "call-7") (i32.const 67)) +(assert_return (invoke $module1 "call-8") (i32.const 68)) +(assert_return (invoke $module1 "call-9") (i32.const 66)) + +(module $module3 + (type $out-i32 (func (result i32))) + (import "module1" "shared-table" (table 10 anyfunc)) + (elem (i32.const 8) $const-i32-e) + (elem (i32.const 9) $const-i32-f) + (func $const-i32-e (type $out-i32) (i32.const 69)) + (func $const-i32-f (type $out-i32) (i32.const 70)) +) + +(assert_return (invoke $module1 "call-7") (i32.const 67)) +(assert_return (invoke $module1 "call-8") (i32.const 69)) +(assert_return (invoke $module1 "call-9") (i32.const 70)) diff --git a/libraries/wasm-jit/Test/spec/float_literals.wast b/libraries/wasm-jit/Test/spec/float_literals.wast index 1ab14f1a016..ed5969b8898 100644 --- a/libraries/wasm-jit/Test/spec/float_literals.wast +++ b/libraries/wasm-jit/Test/spec/float_literals.wast @@ -72,6 +72,28 @@ (func (export "f64_dec.max_subnormal") (result i64) (i64.reinterpret/f64 (f64.const 2.2250738585072011e-308))) (func (export "f64_dec.max_finite") (result i64) (i64.reinterpret/f64 (f64.const 1.7976931348623157e+308))) (func (export "f64_dec.trailing_dot") (result i64) (i64.reinterpret/f64 (f64.const 1.e100))) + + (func (export "f32-dec-sep1") (result f32) (f32.const 1_000_000)) + (func (export "f32-dec-sep2") (result f32) (f32.const 1_0_0_0)) + (func (export "f32-dec-sep3") (result f32) (f32.const 100_3.141_592)) + (func (export "f32-dec-sep4") (result f32) (f32.const 99e+1_3)) + (func (export "f32-dec-sep5") (result f32) (f32.const 122_000.11_3_54E0_2_3)) + (func (export "f32-hex-sep1") (result f32) (f32.const 0xa_0f_00_99)) + (func (export "f32-hex-sep2") (result f32) (f32.const 0x1_a_A_0_f)) + (func (export "f32-hex-sep3") (result f32) (f32.const 0xa0_ff.f141_a59a)) + (func (export "f32-hex-sep4") (result f32) (f32.const 0xf0P+1_3)) + (func (export "f32-hex-sep5") (result f32) (f32.const 0x2a_f00a.1f_3_eep2_3)) + + (func (export "f64-dec-sep1") (result f64) (f64.const 1_000_000)) + (func (export "f64-dec-sep2") (result f64) (f64.const 1_0_0_0)) + (func (export "f64-dec-sep3") (result f64) (f64.const 100_3.141_592)) + (func (export "f64-dec-sep4") (result f64) (f64.const 99e-1_23)) + (func (export "f64-dec-sep5") (result f64) (f64.const 122_000.11_3_54e0_2_3)) + (func (export "f64-hex-sep1") (result f64) (f64.const 0xa_f00f_0000_9999)) + (func (export "f64-hex-sep2") (result f64) (f64.const 0x1_a_A_0_f)) + (func (export "f64-hex-sep3") (result f64) (f64.const 0xa0_ff.f141_a59a)) + (func (export "f64-hex-sep4") (result f64) (f64.const 0xf0P+1_3)) + (func (export "f64-hex-sep5") (result f64) (f64.const 0x2a_f00a.1f_3_eep2_3)) ) (assert_return (invoke "f32.nan") (i32.const 0x7fc00000)) @@ -135,3 +157,343 @@ (assert_return (invoke "f64_dec.max_subnormal") (i64.const 0xfffffffffffff)) (assert_return (invoke "f64_dec.max_finite") (i64.const 0x7fefffffffffffff)) (assert_return (invoke "f64_dec.trailing_dot") (i64.const 0x54b249ad2594c37d)) + +(assert_return (invoke "f32-dec-sep1") (f32.const 1000000)) +(assert_return (invoke "f32-dec-sep2") (f32.const 1000)) +(assert_return (invoke "f32-dec-sep3") (f32.const 1003.141592)) +(assert_return (invoke "f32-dec-sep4") (f32.const 99e+13)) +(assert_return (invoke "f32-dec-sep5") (f32.const 122000.11354e23)) +(assert_return (invoke "f32-hex-sep1") (f32.const 0xa0f0099)) +(assert_return (invoke "f32-hex-sep2") (f32.const 0x1aa0f)) +(assert_return (invoke "f32-hex-sep3") (f32.const 0xa0ff.f141a59a)) +(assert_return (invoke "f32-hex-sep4") (f32.const 0xf0P+13)) +(assert_return (invoke "f32-hex-sep5") (f32.const 0x2af00a.1f3eep23)) + +(assert_return (invoke "f64-dec-sep1") (f64.const 1000000)) +(assert_return (invoke "f64-dec-sep2") (f64.const 1000)) +(assert_return (invoke "f64-dec-sep3") (f64.const 1003.141592)) +(assert_return (invoke "f64-dec-sep4") (f64.const 99e-123)) +(assert_return (invoke "f64-dec-sep5") (f64.const 122000.11354e23)) +(assert_return (invoke "f64-hex-sep1") (f64.const 0xaf00f00009999)) +(assert_return (invoke "f64-hex-sep2") (f64.const 0x1aa0f)) +(assert_return (invoke "f64-hex-sep3") (f64.const 0xa0ff.f141a59a)) +(assert_return (invoke "f64-hex-sep4") (f64.const 0xf0P+13)) +(assert_return (invoke "f64-hex-sep5") (f64.const 0x2af00a.1f3eep23)) + +;; Test parsing a float from binary +(module binary + ;; (func (export "4294967249") (result f64) (f64.const 4294967249)) + "\00\61\73\6d\01\00\00\00\01\85\80\80\80\00\01\60" + "\00\01\7c\03\82\80\80\80\00\01\00\07\8e\80\80\80" + "\00\01\0a\34\32\39\34\39\36\37\32\34\39\00\00\0a" + "\91\80\80\80\00\01\8b\80\80\80\00\00\44\00\00\20" + "\fa\ff\ff\ef\41\0b" +) + +(assert_return (invoke "4294967249") (f64.const 4294967249)) + +(assert_malformed + (module quote "(global f32 (f32.const _100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const +_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const -_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 99_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1__000))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const _1.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1_.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1._0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const _1e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1e1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1_e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1e_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const _1.0e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0e1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0_e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0e_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0e+_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 1.0e_+1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const _0x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0_x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x00_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0xff__ffff))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x_1.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1_.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1._0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x_1p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1p1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1_p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1p_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x_1.0p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0p1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0_p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0p_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0p+_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f32 (f32.const 0x1.0p_+1))") + "unknown operator" +) + +(assert_malformed + (module quote "(global f64 (f64.const _100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const +_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const -_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 99_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1__000))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const _1.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1_.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1._0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const _1e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1e1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1_e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1e_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const _1.0e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0e1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0_e1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0e_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0e+_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 1.0e_+1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const _0x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0_x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x00_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0xff__ffff))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x_1.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1_.0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1._0))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x_1p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1p1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1_p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1p_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x_1.0p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0p1_))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0_p1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0p_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0p+_1))") + "unknown operator" +) +(assert_malformed + (module quote "(global f64 (f64.const 0x1.0p_+1))") + "unknown operator" +) diff --git a/libraries/wasm-jit/Test/spec/func.wast b/libraries/wasm-jit/Test/spec/func.wast index 41c2e65bae7..c60782f0e10 100644 --- a/libraries/wasm-jit/Test/spec/func.wast +++ b/libraries/wasm-jit/Test/spec/func.wast @@ -30,11 +30,27 @@ (func (result i32) (unreachable)) + (type $sig-1 (func)) + (type $sig-2 (func (result i32))) + (type $sig-3 (func (param $x i32))) + (type $sig-4 (func (param i32 f64 i32) (result i32))) + + (func (export "type-use-1") (type $sig-1)) + (func (export "type-use-2") (type $sig-2) (i32.const 0)) + (func (export "type-use-3") (type $sig-3)) + (func (export "type-use-4") (type $sig-4) (i32.const 0)) + (func (export "type-use-5") (type $sig-2) (result i32) (i32.const 0)) + (func (export "type-use-6") (type $sig-3) (param i32)) + (func (export "type-use-7") + (type $sig-4) (param i32) (param f64 i32) (result i32) (i32.const 0) + ) + (func (type $sig)) + (func (type $forward)) ;; forward reference (func $complex (param i32 f32) (param $x i64) (param) (param i32) - (result i32) + (result) (result i32) (result) (local f32) (local $y i32) (local i64 i32) (local) (local f64 i32) (unreachable) (unreachable) ) @@ -44,6 +60,7 @@ (unreachable) (unreachable) ) + (type $forward (func)) ;; Typing of locals @@ -149,59 +166,20 @@ (func (export "init-local-i64") (result i64) (local i64) (get_local 0)) (func (export "init-local-f32") (result f32) (local f32) (get_local 0)) (func (export "init-local-f64") (result f64) (local f64) (get_local 0)) +) - - ;; Desugaring of implicit type signature - (func $empty-sig-1) ;; should be assigned type $sig - (func $complex-sig-1 (param f64 i64 f64 i64 f64 i64 f32 i32)) - (func $empty-sig-2) ;; should be assigned type $sig - (func $complex-sig-2 (param f64 i64 f64 i64 f64 i64 f32 i32)) - (func $complex-sig-3 (param f64 i64 f64 i64 f64 i64 f32 i32)) - - (type $empty-sig-duplicate (func)) - (type $complex-sig-duplicate (func (param f64 i64 f64 i64 f64 i64 f32 i32))) - (table anyfunc - (elem - $complex-sig-3 $empty-sig-2 $complex-sig-1 $complex-sig-3 $empty-sig-1 - ) - ) - - (func (export "signature-explicit-reused") - (call_indirect $sig (i32.const 1)) - (call_indirect $sig (i32.const 4)) - ) - - (func (export "signature-implicit-reused") - ;; The implicit index 16 in this test depends on the function and - ;; type definitions, and may need adapting if they change. - (call_indirect 16 - (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0) - (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0) - (i32.const 0) - ) - (call_indirect 16 - (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0) - (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0) - (i32.const 2) - ) - (call_indirect 16 - (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0) - (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0) - (i32.const 3) - ) - ) - - (func (export "signature-explicit-duplicate") - (call_indirect $empty-sig-duplicate (i32.const 1)) - ) - - (func (export "signature-implicit-duplicate") - (call_indirect $complex-sig-duplicate - (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0) - (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0) - (i32.const 0) - ) - ) +(assert_return (invoke "type-use-1")) +(assert_return (invoke "type-use-2") (i32.const 0)) +(assert_return (invoke "type-use-3" (i32.const 1))) +(assert_return + (invoke "type-use-4" (i32.const 1) (f64.const 1) (i32.const 1)) + (i32.const 0) +) +(assert_return (invoke "type-use-5") (i32.const 0)) +(assert_return (invoke "type-use-6" (i32.const 1))) +(assert_return + (invoke "type-use-7" (i32.const 1) (f64.const 1) (i32.const 1)) + (i32.const 0) ) (assert_return (invoke "local-first-i32") (i32.const 0)) @@ -305,12 +283,178 @@ (assert_return (invoke "init-local-f32") (f32.const 0)) (assert_return (invoke "init-local-f64") (f64.const 0)) + +;; Expansion of inline function types + +(module + (func $f (result f64) (f64.const 0)) ;; adds implicit type definition + (func $g (param i32)) ;; reuses explicit type definition + (type $t (func (param i32))) + + (func $i32->void (type 0)) ;; (param i32) + (func $void->f64 (type 1) (f64.const 0)) ;; (result f64) + (func $check + (call $i32->void (i32.const 0)) + (drop (call $void->f64)) + ) +) + +(assert_invalid + (module + (func $f (result f64) (f64.const 0)) ;; adds implicit type definition + (func $g (param i32)) ;; reuses explicit type definition + (func $h (result f64) (f64.const 1)) ;; reuses implicit type definition + (type $t (func (param i32))) + + (func (type 2)) ;; does not exist + ) + "unknown type" +) + + +(module + (type $sig (func)) + + (func $empty-sig-1) ;; should be assigned type $sig + (func $complex-sig-1 (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $empty-sig-2) ;; should be assigned type $sig + (func $complex-sig-2 (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-3 (param f64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-4 (param i64 i64 f64 i64 f64 i64 f32 i32)) + (func $complex-sig-5 (param i64 i64 f64 i64 f64 i64 f32 i32)) + + (type $empty-sig-duplicate (func)) + (type $complex-sig-duplicate (func (param i64 i64 f64 i64 f64 i64 f32 i32))) + (table anyfunc + (elem + $complex-sig-3 $empty-sig-2 $complex-sig-1 $complex-sig-3 $empty-sig-1 + $complex-sig-4 $complex-sig-5 + ) + ) + + (func (export "signature-explicit-reused") + (call_indirect $sig (i32.const 1)) + (call_indirect $sig (i32.const 4)) + ) + + (func (export "signature-implicit-reused") + ;; The implicit index 3 in this test depends on the function and + ;; type definitions, and may need adapting if they change. + (call_indirect 3 + (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0) + (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0) + (i32.const 0) + ) + (call_indirect 3 + (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0) + (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0) + (i32.const 2) + ) + (call_indirect 3 + (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0) + (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0) + (i32.const 3) + ) + ) + + (func (export "signature-explicit-duplicate") + (call_indirect $empty-sig-duplicate (i32.const 1)) + ) + + (func (export "signature-implicit-duplicate") + (call_indirect $complex-sig-duplicate + (i64.const 0) (i64.const 0) (f64.const 0) (i64.const 0) + (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0) + (i32.const 5) + ) + (call_indirect $complex-sig-duplicate + (i64.const 0) (i64.const 0) (f64.const 0) (i64.const 0) + (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0) + (i32.const 6) + ) + ) +) + (assert_return (invoke "signature-explicit-reused")) (assert_return (invoke "signature-implicit-reused")) (assert_return (invoke "signature-explicit-duplicate")) (assert_return (invoke "signature-implicit-duplicate")) +;; Malformed type use + +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (type $sig) (result i32) (param i32) (i32.const 0))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (param i32) (type $sig) (result i32) (i32.const 0))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (param i32) (result i32) (type $sig) (i32.const 0))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (result i32) (type $sig) (param i32) (i32.const 0))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (result i32) (param i32) (type $sig) (i32.const 0))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(func (result i32) (param i32) (i32.const 0))" + ) + "unexpected token" +) + +(assert_malformed + (module quote + "(type $sig (func))" + "(func (type $sig) (result i32) (i32.const 0))" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (type $sig) (result i32) (i32.const 0))" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (type $sig) (param i32) (i32.const 0))" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32 i32) (result i32)))" + "(func (type $sig) (param i32) (result i32) (unreachable))" + ) + "inline function type" +) + + ;; Invalid typing of locals (assert_invalid diff --git a/libraries/wasm-jit/Test/spec/func_ptrs.wast b/libraries/wasm-jit/Test/spec/func_ptrs.wast index f7edd9f4481..ef54c5da0b4 100644 --- a/libraries/wasm-jit/Test/spec/func_ptrs.wast +++ b/libraries/wasm-jit/Test/spec/func_ptrs.wast @@ -23,6 +23,7 @@ (func (export "four") (type $U) (call $print (get_local 0))) ) + (assert_return (invoke "one") (i32.const 13)) (assert_return (invoke "two" (i32.const 13)) (i32.const 14)) (assert_return (invoke "three" (i32.const 13)) (i32.const 11)) diff --git a/libraries/wasm-jit/Test/spec/imports.wast b/libraries/wasm-jit/Test/spec/imports.wast index 69ccd0b5d79..e9a28dcdcc2 100644 --- a/libraries/wasm-jit/Test/spec/imports.wast +++ b/libraries/wasm-jit/Test/spec/imports.wast @@ -47,6 +47,10 @@ (func (export "p5") (import "spectest" "print") (type 0)) (func (export "p6") (import "spectest" "print") (type 0) (param i32) (result)) + (import "spectest" "print" (func (type $forward))) + (func (import "spectest" "print") (type $forward)) + (type $forward (func (param i32))) + (table anyfunc (elem $print_i32 $print_f64)) (func (export "print32") (param $i i32) @@ -102,92 +106,92 @@ (assert_unlinkable (module (import "test" "func" (func (param i32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func" (func (result i32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func" (func (param i32) (result i32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func-i32" (func))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func-i32" (func (result i32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func-i32" (func (param f32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func-i32" (func (param i64)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func-i32" (func (param i32) (result i32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func->i32" (func))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func->i32" (func (param i32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func->i32" (func (result f32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func->i32" (func (result i64)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func->i32" (func (param i32) (result i32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func-i32->i32" (func))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func-i32->i32" (func (param i32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func-i32->i32" (func (result i32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "global-i32" (func (result i32)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "table-10-inf" (func))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "memory-2-inf" (func))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "global" (func))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "table" (func))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "memory" (func))) - "type mismatch" + "incompatible import type" ) @@ -230,27 +234,27 @@ (assert_unlinkable (module (import "test" "func" (global i32))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "table-10-inf" (global i32))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "memory-2-inf" (global i32))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "print" (global i32))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "table" (global i32))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "memory" (global i32))) - "type mismatch" + "incompatible import type" ) @@ -326,36 +330,36 @@ (assert_unlinkable (module (import "test" "table-10-inf" (table 12 anyfunc))) - "actual size smaller than declared" + "incompatible import type" ) (assert_unlinkable (module (import "test" "table-10-inf" (table 10 20 anyfunc))) - "maximum size larger than declared" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "table" (table 12 anyfunc))) - "actual size smaller than declared" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "table" (table 10 15 anyfunc))) - "maximum size larger than declared" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func" (table 10 anyfunc))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "global-i32" (table 10 anyfunc))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "memory-2-inf" (table 10 anyfunc))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "print" (table 10 anyfunc))) - "type mismatch" + "incompatible import type" ) @@ -419,53 +423,53 @@ (assert_unlinkable (module (import "test" "memory-2-inf" (memory 3))) - "actual size smaller than declared" + "incompatible import type" ) (assert_unlinkable (module (import "test" "memory-2-inf" (memory 2 3))) - "maximum size larger than declared" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "memory" (memory 2))) - "actual size smaller than declared" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "memory" (memory 1 1))) - "maximum size larger than declared" + "incompatible import type" ) (assert_unlinkable (module (import "test" "func-i32" (memory 1))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "global-i32" (memory 1))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "test" "table-10-inf" (memory 1))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "print" (memory 1))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "global" (memory 1))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "table" (memory 1))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "memory" (memory 2))) - "actual size smaller than declared" + "incompatible import type" ) (assert_unlinkable (module (import "spectest" "memory" (memory 1 1))) - "maximum size larger than declared" + "incompatible import type" ) (module diff --git a/libraries/wasm-jit/Test/spec/int_exprs.wast b/libraries/wasm-jit/Test/spec/int_exprs.wast index de6a645cfcb..99396a8b032 100644 --- a/libraries/wasm-jit/Test/spec/int_exprs.wast +++ b/libraries/wasm-jit/Test/spec/int_exprs.wast @@ -346,5 +346,5 @@ (i64.div_s (get_local $x) (i64.const -1))) ) -;;(assert_trap (invoke "i32.no_fold_div_neg1" (i32.const 0x80000000)) "integer overflow") -;;(assert_trap (invoke "i64.no_fold_div_neg1" (i64.const 0x8000000000000000)) "integer overflow") +(assert_trap (invoke "i32.no_fold_div_neg1" (i32.const 0x80000000)) "integer overflow") +(assert_trap (invoke "i64.no_fold_div_neg1" (i64.const 0x8000000000000000)) "integer overflow") diff --git a/libraries/wasm-jit/Test/spec/int_literals.wast b/libraries/wasm-jit/Test/spec/int_literals.wast index f0ec0417854..73b37cc5a9b 100644 --- a/libraries/wasm-jit/Test/spec/int_literals.wast +++ b/libraries/wasm-jit/Test/spec/int_literals.wast @@ -22,6 +22,16 @@ (func (export "i64.not_octal") (result i64) (return (i64.const 010))) (func (export "i64.unsigned_decimal") (result i64) (return (i64.const 18446744073709551615))) (func (export "i64.plus_sign") (result i64) (return (i64.const +42))) + + (func (export "i32-dec-sep1") (result i32) (i32.const 1_000_000)) + (func (export "i32-dec-sep2") (result i32) (i32.const 1_0_0_0)) + (func (export "i32-hex-sep1") (result i32) (i32.const 0xa_0f_00_99)) + (func (export "i32-hex-sep2") (result i32) (i32.const 0x1_a_A_0_f)) + + (func (export "i64-dec-sep1") (result i64) (i64.const 1_000_000)) + (func (export "i64-dec-sep2") (result i64) (i64.const 1_0_0_0)) + (func (export "i64-hex-sep1") (result i64) (i64.const 0xa_f00f_0000_9999)) + (func (export "i64-hex-sep2") (result i64) (i64.const 0x1_a_A_0_f)) ) (assert_return (invoke "i32.test") (i32.const 195940365)) @@ -47,3 +57,95 @@ (assert_return (invoke "i64.not_octal") (i64.const 10)) (assert_return (invoke "i64.unsigned_decimal") (i64.const -1)) (assert_return (invoke "i64.plus_sign") (i64.const 42)) + +(assert_return (invoke "i32-dec-sep1") (i32.const 1000000)) +(assert_return (invoke "i32-dec-sep2") (i32.const 1000)) +(assert_return (invoke "i32-hex-sep1") (i32.const 0xa0f0099)) +(assert_return (invoke "i32-hex-sep2") (i32.const 0x1aa0f)) + +(assert_return (invoke "i64-dec-sep1") (i64.const 1000000)) +(assert_return (invoke "i64-dec-sep2") (i64.const 1000)) +(assert_return (invoke "i64-hex-sep1") (i64.const 0xaf00f00009999)) +(assert_return (invoke "i64-hex-sep2") (i64.const 0x1aa0f)) + +(assert_malformed + (module quote "(global i32 (i32.const _100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const +_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const -_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 99_))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 1__000))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const _0x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 0_x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 0x_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 0x00_))") + "unknown operator" +) +(assert_malformed + (module quote "(global i32 (i32.const 0xff__ffff))") + "unknown operator" +) + +(assert_malformed + (module quote "(global i64 (i64.const _100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const +_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const -_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 99_))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 1__000))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const _0x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 0_x100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 0x_100))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 0x00_))") + "unknown operator" +) +(assert_malformed + (module quote "(global i64 (i64.const 0xff__ffff))") + "unknown operator" +) diff --git a/libraries/wasm-jit/Test/spec/linking.wast b/libraries/wasm-jit/Test/spec/linking.wast index 6a7dc36530b..b2f0dd3db1f 100644 --- a/libraries/wasm-jit/Test/spec/linking.wast +++ b/libraries/wasm-jit/Test/spec/linking.wast @@ -26,11 +26,11 @@ (register "reexport_f") (assert_unlinkable (module (import "reexport_f" "print" (func (param i64)))) - "type mismatch" + "incompatible import type" ) (assert_unlinkable (module (import "reexport_f" "print" (func (param i32) (result i32)))) - "type mismatch" + "incompatible import type" ) @@ -162,6 +162,14 @@ (func $f) ) +(module $G1 (global (export "g") i32 (i32.const 5))) +(register "G1" $G1) +(module $G2 + (global (import "G1" "g") i32) + (global (export "g") i32 (get_global 0)) +) +(assert_return (get $G2 "g") (i32.const 5)) + (assert_unlinkable (module (table (import "Mt" "tab") 0 anyfunc) diff --git a/libraries/wasm-jit/Test/spec/memory.wast b/libraries/wasm-jit/Test/spec/memory.wast index 346d8f8fb86..b49ac4b2be8 100644 --- a/libraries/wasm-jit/Test/spec/memory.wast +++ b/libraries/wasm-jit/Test/spec/memory.wast @@ -129,7 +129,7 @@ (assert_invalid (module (memory 1 0)) - "memory size minimum must not be greater than maximum" + "size minimum must not be greater than maximum" ) (assert_invalid (module (memory 65537)) diff --git a/libraries/wasm-jit/Test/spec/names.wast b/libraries/wasm-jit/Test/spec/names.wast index b749b23298d..b58e4d4c663 100644 --- a/libraries/wasm-jit/Test/spec/names.wast +++ b/libraries/wasm-jit/Test/spec/names.wast @@ -1084,4 +1084,4 @@ (export "print32" (func 2)) ) -(invoke "print32" (i32.const 42) (i32.const 123)) +(assert_return (invoke "print32" (i32.const 42) (i32.const 123))) diff --git a/libraries/wasm-jit/Test/spec/traps.wast b/libraries/wasm-jit/Test/spec/traps.wast index 32072b9844c..a9401408e3f 100644 --- a/libraries/wasm-jit/Test/spec/traps.wast +++ b/libraries/wasm-jit/Test/spec/traps.wast @@ -17,6 +17,8 @@ (assert_trap (invoke "no_dce.i32.div_u" (i32.const 1) (i32.const 0)) "integer divide by zero") (assert_trap (invoke "no_dce.i64.div_s" (i64.const 1) (i64.const 0)) "integer divide by zero") (assert_trap (invoke "no_dce.i64.div_u" (i64.const 1) (i64.const 0)) "integer divide by zero") +(assert_trap (invoke "no_dce.i32.div_s" (i32.const 0x80000000) (i32.const -1)) "integer overflow") +(assert_trap (invoke "no_dce.i64.div_s" (i64.const 0x8000000000000000) (i64.const -1)) "integer overflow") (module (func (export "no_dce.i32.rem_s") (param $x i32) (param $y i32) diff --git a/libraries/wasm-jit/Test/spec/type.wast b/libraries/wasm-jit/Test/spec/type.wast new file mode 100644 index 00000000000..5ceeeb26977 --- /dev/null +++ b/libraries/wasm-jit/Test/spec/type.wast @@ -0,0 +1,59 @@ +;; Test type definitions + +(module + (type (func)) + (type $t (func)) + + (type (func (param i32))) + (type (func (param $x i32))) + (type (func (result i32))) + (type (func (param i32) (result i32))) + (type (func (param $x i32) (result i32))) + + (type (func (param f32 f64))) + ;; (type (func (result i64 f32))) + ;; (type (func (param i32 i64) (result f32 f64))) + + (type (func (param f32) (param f64))) + (type (func (param $x f32) (param f64))) + (type (func (param f32) (param $y f64))) + (type (func (param $x f32) (param $y f64))) + ;; (type (func (result i64) (result f32))) + ;; (type (func (param i32) (param i64) (result f32) (result f64))) + ;; (type (func (param $x i32) (param $y i64) (result f32) (result f64))) + + (type (func (param f32 f64) (param $x i32) (param f64 i32 i32))) + ;; (type (func (result i64 i64 f32) (result f32 i32))) + ;; (type + ;; (func (param i32 i32) (param i64 i32) (result f32 f64) (result f64 i32)) + ;; ) + + (type (func (param) (param $x f32) (param) (param) (param f64 i32) (param))) + ;; (type + ;; (func (result) (result) (result i64 i64) (result) (result f32) (result)) + ;; ) + ;; (type + ;; (func + ;; (param i32 i32) (param i64 i32) (param) (param $x i32) (param) + ;; (result) (result f32 f64) (result f64 i32) (result) + ;; ) + ;; ) +) + +(assert_malformed + (module quote "(type (func (result i32) (param i32)))") + "result before parameter" +) +(assert_malformed + (module quote "(type (func (result $x i32)))") + "unexpected token" +) + +(assert_invalid + (module (type (func (result i32 i32)))) + "invalid result arity" +) +(assert_invalid + (module (type (func (result i32) (result i32)))) + "invalid result arity" +) diff --git a/libraries/wasm-jit/Test/spec/unreached-invalid.wast b/libraries/wasm-jit/Test/spec/unreached-invalid.wast index 8c73deb9c84..e22b8b4c91f 100644 --- a/libraries/wasm-jit/Test/spec/unreached-invalid.wast +++ b/libraries/wasm-jit/Test/spec/unreached-invalid.wast @@ -195,6 +195,18 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-unary-num-vs-void-in-loop-after-unreachable + (unreachable) (loop (drop (i32.eqz (nop)))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-unary-num-vs-void-in-i32-loop-after-unreachable + (unreachable) (loop (result i32) (i32.eqz (nop))) + )) + "type mismatch" +) (assert_invalid (module (func $type-unary-num-vs-num-after-unreachable (unreachable) (drop (i32.eqz (f32.const 1))) @@ -249,6 +261,24 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-unary-num-vs-void-in-if-after-unreachable + (unreachable) (if (i32.const 0) (then (drop (i32.eqz (nop))))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-unary-num-vs-void-in-else-after-unreachable + (unreachable) (if (i32.const 0) (then (nop)) (else (drop (i32.eqz (nop))))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-unary-num-vs-void-in-else-after-unreachable-if + (if (i32.const 0) (then (unreachable)) (else (drop (i32.eqz (nop))))) + )) + "type mismatch" +) (assert_invalid (module (func $type-unary-num-vs-void-after-nested-unreachable @@ -456,6 +486,31 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-br_if-num-vs-void-after-unreachable (result i32) + (block (result i32) + (block (unreachable) (br_if 1 (i32.const 0) (i32.const 0))) + ) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-br_if-num-vs-num-after-unreachable (result i32) + (block (result i32) + (block (result f32) (unreachable) (br_if 1 (i32.const 0) (i32.const 0))) + (drop) (i32.const 0) + ) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-br_if-num2-vs-num-after-unreachable (result i32) + (block (result i32) + (unreachable) (br_if 0 (i32.const 0) (i32.const 0)) (i32.const 0) + ) + )) + "type mismatch" +) (assert_invalid (module (func $type-br_table-num-vs-num-after-unreachable (block (br_table 0 (unreachable) (f32.const 1))) @@ -623,3 +678,22 @@ )) "type mismatch" ) + +(assert_invalid + (module (func $tee-local-unreachable-value + (local i32) + (tee_local 0 (unreachable)) + )) + "type mismatch" +) +(assert_invalid + (module (func $br_if-unreachable (result i32) + (block (result i32) + (block + (br_if 1 (unreachable) (i32.const 0)) + ) + (i32.const 0) + ) + )) + "type mismatch" +) diff --git a/libraries/wasm-jit/Test/spec/utf8-invalid-encoding.wast b/libraries/wasm-jit/Test/spec/utf8-invalid-encoding.wast new file mode 100644 index 00000000000..3b35730989c --- /dev/null +++ b/libraries/wasm-jit/Test/spec/utf8-invalid-encoding.wast @@ -0,0 +1,176 @@ +(assert_malformed (module quote "(func (export \"\\00\\00\\fe\\ff\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\8f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\9f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\a0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\bf\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c0\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c0\\bf\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c1\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c1\\bf\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c2\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c2\\2e\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c2\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c2\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c2\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c2\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\c2\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\df\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\df\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\df\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\df\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\00\\a0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\7f\\a0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\80\\a0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\9f\\a0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\9f\\bf\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\a0\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\a0\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\a0\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\a0\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\c0\\a0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e0\\fd\\a0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\00\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\2e\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\7f\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\80\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\80\\2e\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\80\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\80\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\80\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\c0\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\e1\\fd\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ec\\00\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ec\\7f\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ec\\80\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ec\\80\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ec\\80\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ec\\80\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ec\\c0\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ec\\fd\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\00\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\7f\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\80\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\80\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\80\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\80\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\a0\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\a0\\bf\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\bf\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\bf\\bf\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\c0\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ed\\fd\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ee\\00\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ee\\7f\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ee\\80\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ee\\80\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ee\\80\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ee\\80\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ee\\c0\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ee\\fd\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ef\\00\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ef\\7f\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ef\\80\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ef\\80\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ef\\80\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ef\\80\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ef\\c0\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ef\\fd\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\00\\90\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\7f\\90\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\80\\90\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\8f\\90\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\8f\\bf\\bf\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\90\\00\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\90\\7f\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\90\\90\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\90\\90\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\90\\90\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\90\\90\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\90\\c0\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\90\\fd\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\c0\\90\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f0\\fd\\90\\90\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\00\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\7f\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\00\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\7f\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\c0\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\80\\fd\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\c0\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f1\\fd\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\00\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\7f\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\80\\00\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\80\\7f\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\80\\80\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\80\\80\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\80\\80\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\80\\80\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\80\\c0\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\80\\fd\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\c0\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f3\\fd\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\00\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\7f\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\80\\00\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\80\\7f\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\80\\80\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\80\\80\\7f\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\80\\80\\c0\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\80\\80\\fd\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\80\\c0\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\80\\fd\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\90\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\bf\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\c0\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f4\\fd\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f5\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f7\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f7\\bf\\bf\\bf\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f8\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f8\\80\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f8\\80\\80\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f8\\80\\80\\80\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f8\\80\\80\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f8\\80\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f8\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f8\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f8\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\f8\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fb\\bf\\bf\\bf\\bf\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\80\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\\80\\23\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\80\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\\80\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fc\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fd\\bf\\bf\\bf\\bf\\bf\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fe\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\fe\\ff\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ff\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ff\\fe\\00\\00\"))") "invalid UTF-8 encoding") +(assert_malformed (module quote "(func (export \"\\ff\\fe\"))") "invalid UTF-8 encoding")