diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /js/src/wasm/WasmTypes.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | uxp-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz |
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/wasm/WasmTypes.cpp')
-rw-r--r-- | js/src/wasm/WasmTypes.cpp | 727 |
1 files changed, 727 insertions, 0 deletions
diff --git a/js/src/wasm/WasmTypes.cpp b/js/src/wasm/WasmTypes.cpp new file mode 100644 index 0000000000..5add17d06e --- /dev/null +++ b/js/src/wasm/WasmTypes.cpp @@ -0,0 +1,727 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * + * Copyright 2015 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wasm/WasmTypes.h" + +#include "mozilla/MathAlgorithms.h" + +#include "fdlibm.h" + +#include "jslibmath.h" +#include "jsmath.h" + +#include "jit/MacroAssembler.h" +#include "js/Conversions.h" +#include "vm/Interpreter.h" +#include "wasm/WasmInstance.h" +#include "wasm/WasmSerialize.h" +#include "wasm/WasmSignalHandlers.h" + +#include "vm/Stack-inl.h" + +using namespace js; +using namespace js::jit; +using namespace js::wasm; + +using mozilla::IsNaN; +using mozilla::IsPowerOfTwo; + +void +Val::writePayload(uint8_t* dst) const +{ + switch (type_) { + case ValType::I32: + case ValType::F32: + memcpy(dst, &u.i32_, sizeof(u.i32_)); + return; + case ValType::I64: + case ValType::F64: + memcpy(dst, &u.i64_, sizeof(u.i64_)); + return; + case ValType::I8x16: + case ValType::I16x8: + case ValType::I32x4: + case ValType::F32x4: + case ValType::B8x16: + case ValType::B16x8: + case ValType::B32x4: + memcpy(dst, &u, jit::Simd128DataSize); + return; + } +} + +#if defined(JS_CODEGEN_ARM) +extern "C" { + +extern MOZ_EXPORT int64_t +__aeabi_idivmod(int, int); + +extern MOZ_EXPORT int64_t +__aeabi_uidivmod(int, int); + +} +#endif + +static void +WasmReportOverRecursed() +{ + ReportOverRecursed(JSRuntime::innermostWasmActivation()->cx()); +} + +static bool +WasmHandleExecutionInterrupt() +{ + WasmActivation* activation = JSRuntime::innermostWasmActivation(); + bool success = CheckForInterrupt(activation->cx()); + + // Preserve the invariant that having a non-null resumePC means that we are + // handling an interrupt. Note that resumePC has already been copied onto + // the stack by the interrupt stub, so we can clear it before returning + // to the stub. + activation->setResumePC(nullptr); + + return success; +} + +static void +WasmReportTrap(int32_t trapIndex) +{ + JSContext* cx = JSRuntime::innermostWasmActivation()->cx(); + + MOZ_ASSERT(trapIndex < int32_t(Trap::Limit) && trapIndex >= 0); + Trap trap = Trap(trapIndex); + + unsigned errorNumber; + switch (trap) { + case Trap::Unreachable: + errorNumber = JSMSG_WASM_UNREACHABLE; + break; + case Trap::IntegerOverflow: + errorNumber = JSMSG_WASM_INTEGER_OVERFLOW; + break; + case Trap::InvalidConversionToInteger: + errorNumber = JSMSG_WASM_INVALID_CONVERSION; + break; + case Trap::IntegerDivideByZero: + errorNumber = JSMSG_WASM_INT_DIVIDE_BY_ZERO; + break; + case Trap::IndirectCallToNull: + errorNumber = JSMSG_WASM_IND_CALL_TO_NULL; + break; + case Trap::IndirectCallBadSig: + errorNumber = JSMSG_WASM_IND_CALL_BAD_SIG; + break; + case Trap::ImpreciseSimdConversion: + errorNumber = JSMSG_SIMD_FAILED_CONVERSION; + break; + case Trap::OutOfBounds: + errorNumber = JSMSG_WASM_OUT_OF_BOUNDS; + break; + case Trap::StackOverflow: + errorNumber = JSMSG_OVER_RECURSED; + break; + default: + MOZ_CRASH("unexpected trap"); + } + + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNumber); +} + +static void +WasmReportOutOfBounds() +{ + JSContext* cx = JSRuntime::innermostWasmActivation()->cx(); + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_OUT_OF_BOUNDS); +} + +static void +WasmReportUnalignedAccess() +{ + JSContext* cx = JSRuntime::innermostWasmActivation()->cx(); + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_UNALIGNED_ACCESS); +} + +static int32_t +CoerceInPlace_ToInt32(MutableHandleValue val) +{ + JSContext* cx = JSRuntime::innermostWasmActivation()->cx(); + + int32_t i32; + if (!ToInt32(cx, val, &i32)) + return false; + val.set(Int32Value(i32)); + + return true; +} + +static int32_t +CoerceInPlace_ToNumber(MutableHandleValue val) +{ + JSContext* cx = JSRuntime::innermostWasmActivation()->cx(); + + double dbl; + if (!ToNumber(cx, val, &dbl)) + return false; + val.set(DoubleValue(dbl)); + + return true; +} + +static int64_t +DivI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo) +{ + int64_t x = ((uint64_t)x_hi << 32) + x_lo; + int64_t y = ((uint64_t)y_hi << 32) + y_lo; + MOZ_ASSERT(x != INT64_MIN || y != -1); + MOZ_ASSERT(y != 0); + return x / y; +} + +static int64_t +UDivI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo) +{ + uint64_t x = ((uint64_t)x_hi << 32) + x_lo; + uint64_t y = ((uint64_t)y_hi << 32) + y_lo; + MOZ_ASSERT(y != 0); + return x / y; +} + +static int64_t +ModI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo) +{ + int64_t x = ((uint64_t)x_hi << 32) + x_lo; + int64_t y = ((uint64_t)y_hi << 32) + y_lo; + MOZ_ASSERT(x != INT64_MIN || y != -1); + MOZ_ASSERT(y != 0); + return x % y; +} + +static int64_t +UModI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo) +{ + uint64_t x = ((uint64_t)x_hi << 32) + x_lo; + uint64_t y = ((uint64_t)y_hi << 32) + y_lo; + MOZ_ASSERT(y != 0); + return x % y; +} + +static int64_t +TruncateDoubleToInt64(double input) +{ + // Note: INT64_MAX is not representable in double. It is actually + // INT64_MAX + 1. Therefore also sending the failure value. + if (input >= double(INT64_MAX) || input < double(INT64_MIN) || IsNaN(input)) + return 0x8000000000000000; + return int64_t(input); +} + +static uint64_t +TruncateDoubleToUint64(double input) +{ + // Note: UINT64_MAX is not representable in double. It is actually UINT64_MAX + 1. + // Therefore also sending the failure value. + if (input >= double(UINT64_MAX) || input <= -1.0 || IsNaN(input)) + return 0x8000000000000000; + return uint64_t(input); +} + +static double +Int64ToFloatingPoint(int32_t x_hi, uint32_t x_lo) +{ + int64_t x = int64_t((uint64_t(x_hi) << 32)) + int64_t(x_lo); + return double(x); +} + +static double +Uint64ToFloatingPoint(int32_t x_hi, uint32_t x_lo) +{ + uint64_t x = (uint64_t(x_hi) << 32) + uint64_t(x_lo); + return double(x); +} + +template <class F> +static inline void* +FuncCast(F* pf, ABIFunctionType type) +{ + void *pv = JS_FUNC_TO_DATA_PTR(void*, pf); +#ifdef JS_SIMULATOR + pv = Simulator::RedirectNativeFunction(pv, type); +#endif + return pv; +} + +void* +wasm::AddressOf(SymbolicAddress imm, ExclusiveContext* cx) +{ + switch (imm) { + case SymbolicAddress::Context: + return cx->contextAddressForJit(); + case SymbolicAddress::InterruptUint32: + return cx->runtimeAddressOfInterruptUint32(); + case SymbolicAddress::ReportOverRecursed: + return FuncCast(WasmReportOverRecursed, Args_General0); + case SymbolicAddress::HandleExecutionInterrupt: + return FuncCast(WasmHandleExecutionInterrupt, Args_General0); + case SymbolicAddress::ReportTrap: + return FuncCast(WasmReportTrap, Args_General1); + case SymbolicAddress::ReportOutOfBounds: + return FuncCast(WasmReportOutOfBounds, Args_General0); + case SymbolicAddress::ReportUnalignedAccess: + return FuncCast(WasmReportUnalignedAccess, Args_General0); + case SymbolicAddress::CallImport_Void: + return FuncCast(Instance::callImport_void, Args_General4); + case SymbolicAddress::CallImport_I32: + return FuncCast(Instance::callImport_i32, Args_General4); + case SymbolicAddress::CallImport_I64: + return FuncCast(Instance::callImport_i64, Args_General4); + case SymbolicAddress::CallImport_F64: + return FuncCast(Instance::callImport_f64, Args_General4); + case SymbolicAddress::CoerceInPlace_ToInt32: + return FuncCast(CoerceInPlace_ToInt32, Args_General1); + case SymbolicAddress::CoerceInPlace_ToNumber: + return FuncCast(CoerceInPlace_ToNumber, Args_General1); + case SymbolicAddress::ToInt32: + return FuncCast<int32_t (double)>(JS::ToInt32, Args_Int_Double); + case SymbolicAddress::DivI64: + return FuncCast(DivI64, Args_General4); + case SymbolicAddress::UDivI64: + return FuncCast(UDivI64, Args_General4); + case SymbolicAddress::ModI64: + return FuncCast(ModI64, Args_General4); + case SymbolicAddress::UModI64: + return FuncCast(UModI64, Args_General4); + case SymbolicAddress::TruncateDoubleToUint64: + return FuncCast(TruncateDoubleToUint64, Args_Int64_Double); + case SymbolicAddress::TruncateDoubleToInt64: + return FuncCast(TruncateDoubleToInt64, Args_Int64_Double); + case SymbolicAddress::Uint64ToFloatingPoint: + return FuncCast(Uint64ToFloatingPoint, Args_Double_IntInt); + case SymbolicAddress::Int64ToFloatingPoint: + return FuncCast(Int64ToFloatingPoint, Args_Double_IntInt); +#if defined(JS_CODEGEN_ARM) + case SymbolicAddress::aeabi_idivmod: + return FuncCast(__aeabi_idivmod, Args_General2); + case SymbolicAddress::aeabi_uidivmod: + return FuncCast(__aeabi_uidivmod, Args_General2); + case SymbolicAddress::AtomicCmpXchg: + return FuncCast(atomics_cmpxchg_asm_callout, Args_General5); + case SymbolicAddress::AtomicXchg: + return FuncCast(atomics_xchg_asm_callout, Args_General4); + case SymbolicAddress::AtomicFetchAdd: + return FuncCast(atomics_add_asm_callout, Args_General4); + case SymbolicAddress::AtomicFetchSub: + return FuncCast(atomics_sub_asm_callout, Args_General4); + case SymbolicAddress::AtomicFetchAnd: + return FuncCast(atomics_and_asm_callout, Args_General4); + case SymbolicAddress::AtomicFetchOr: + return FuncCast(atomics_or_asm_callout, Args_General4); + case SymbolicAddress::AtomicFetchXor: + return FuncCast(atomics_xor_asm_callout, Args_General4); +#endif + case SymbolicAddress::ModD: + return FuncCast(NumberMod, Args_Double_DoubleDouble); + case SymbolicAddress::SinD: + return FuncCast<double (double)>(sin, Args_Double_Double); + case SymbolicAddress::CosD: + return FuncCast<double (double)>(cos, Args_Double_Double); + case SymbolicAddress::TanD: + return FuncCast<double (double)>(tan, Args_Double_Double); + case SymbolicAddress::ASinD: + return FuncCast<double (double)>(fdlibm::asin, Args_Double_Double); + case SymbolicAddress::ACosD: + return FuncCast<double (double)>(fdlibm::acos, Args_Double_Double); + case SymbolicAddress::ATanD: + return FuncCast<double (double)>(fdlibm::atan, Args_Double_Double); + case SymbolicAddress::CeilD: + return FuncCast<double (double)>(fdlibm::ceil, Args_Double_Double); + case SymbolicAddress::CeilF: + return FuncCast<float (float)>(fdlibm::ceilf, Args_Float32_Float32); + case SymbolicAddress::FloorD: + return FuncCast<double (double)>(fdlibm::floor, Args_Double_Double); + case SymbolicAddress::FloorF: + return FuncCast<float (float)>(fdlibm::floorf, Args_Float32_Float32); + case SymbolicAddress::TruncD: + return FuncCast<double (double)>(fdlibm::trunc, Args_Double_Double); + case SymbolicAddress::TruncF: + return FuncCast<float (float)>(fdlibm::truncf, Args_Float32_Float32); + case SymbolicAddress::NearbyIntD: + return FuncCast<double (double)>(fdlibm::nearbyint, Args_Double_Double); + case SymbolicAddress::NearbyIntF: + return FuncCast<float (float)>(fdlibm::nearbyintf, Args_Float32_Float32); + case SymbolicAddress::ExpD: + return FuncCast<double (double)>(fdlibm::exp, Args_Double_Double); + case SymbolicAddress::LogD: + return FuncCast<double (double)>(fdlibm::log, Args_Double_Double); + case SymbolicAddress::PowD: + return FuncCast(ecmaPow, Args_Double_DoubleDouble); + case SymbolicAddress::ATan2D: + return FuncCast(ecmaAtan2, Args_Double_DoubleDouble); + case SymbolicAddress::GrowMemory: + return FuncCast<uint32_t (Instance*, uint32_t)>(Instance::growMemory_i32, Args_General2); + case SymbolicAddress::CurrentMemory: + return FuncCast<uint32_t (Instance*)>(Instance::currentMemory_i32, Args_General1); + case SymbolicAddress::Limit: + break; + } + + MOZ_CRASH("Bad SymbolicAddress"); +} + +static uint32_t +GetCPUID() +{ + enum Arch { + X86 = 0x1, + X64 = 0x2, + ARM = 0x3, + MIPS = 0x4, + MIPS64 = 0x5, + ARCH_BITS = 3 + }; + +#if defined(JS_CODEGEN_X86) + MOZ_ASSERT(uint32_t(jit::CPUInfo::GetSSEVersion()) <= (UINT32_MAX >> ARCH_BITS)); + return X86 | (uint32_t(jit::CPUInfo::GetSSEVersion()) << ARCH_BITS); +#elif defined(JS_CODEGEN_X64) + MOZ_ASSERT(uint32_t(jit::CPUInfo::GetSSEVersion()) <= (UINT32_MAX >> ARCH_BITS)); + return X64 | (uint32_t(jit::CPUInfo::GetSSEVersion()) << ARCH_BITS); +#elif defined(JS_CODEGEN_ARM) + MOZ_ASSERT(jit::GetARMFlags() <= (UINT32_MAX >> ARCH_BITS)); + return ARM | (jit::GetARMFlags() << ARCH_BITS); +#elif defined(JS_CODEGEN_ARM64) + MOZ_CRASH("not enabled"); +#elif defined(JS_CODEGEN_MIPS32) + MOZ_ASSERT(jit::GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS)); + return MIPS | (jit::GetMIPSFlags() << ARCH_BITS); +#elif defined(JS_CODEGEN_MIPS64) + MOZ_ASSERT(jit::GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS)); + return MIPS64 | (jit::GetMIPSFlags() << ARCH_BITS); +#elif defined(JS_CODEGEN_NONE) + return 0; +#else +# error "unknown architecture" +#endif +} + +size_t +Sig::serializedSize() const +{ + return sizeof(ret_) + + SerializedPodVectorSize(args_); +} + +uint8_t* +Sig::serialize(uint8_t* cursor) const +{ + cursor = WriteScalar<ExprType>(cursor, ret_); + cursor = SerializePodVector(cursor, args_); + return cursor; +} + +const uint8_t* +Sig::deserialize(const uint8_t* cursor) +{ + (cursor = ReadScalar<ExprType>(cursor, &ret_)) && + (cursor = DeserializePodVector(cursor, &args_)); + return cursor; +} + +size_t +Sig::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const +{ + return args_.sizeOfExcludingThis(mallocSizeOf); +} + +typedef uint32_t ImmediateType; // for 32/64 consistency +static const unsigned sTotalBits = sizeof(ImmediateType) * 8; +static const unsigned sTagBits = 1; +static const unsigned sReturnBit = 1; +static const unsigned sLengthBits = 4; +static const unsigned sTypeBits = 2; +static const unsigned sMaxTypes = (sTotalBits - sTagBits - sReturnBit - sLengthBits) / sTypeBits; + +static bool +IsImmediateType(ValType vt) +{ + switch (vt) { + case ValType::I32: + case ValType::I64: + case ValType::F32: + case ValType::F64: + return true; + case ValType::I8x16: + case ValType::I16x8: + case ValType::I32x4: + case ValType::F32x4: + case ValType::B8x16: + case ValType::B16x8: + case ValType::B32x4: + return false; + } + MOZ_CRASH("bad ValType"); +} + +static unsigned +EncodeImmediateType(ValType vt) +{ + static_assert(3 < (1 << sTypeBits), "fits"); + switch (vt) { + case ValType::I32: + return 0; + case ValType::I64: + return 1; + case ValType::F32: + return 2; + case ValType::F64: + return 3; + case ValType::I8x16: + case ValType::I16x8: + case ValType::I32x4: + case ValType::F32x4: + case ValType::B8x16: + case ValType::B16x8: + case ValType::B32x4: + break; + } + MOZ_CRASH("bad ValType"); +} + +/* static */ bool +SigIdDesc::isGlobal(const Sig& sig) +{ + unsigned numTypes = (sig.ret() == ExprType::Void ? 0 : 1) + + (sig.args().length()); + if (numTypes > sMaxTypes) + return true; + + if (sig.ret() != ExprType::Void && !IsImmediateType(NonVoidToValType(sig.ret()))) + return true; + + for (ValType v : sig.args()) { + if (!IsImmediateType(v)) + return true; + } + + return false; +} + +/* static */ SigIdDesc +SigIdDesc::global(const Sig& sig, uint32_t globalDataOffset) +{ + MOZ_ASSERT(isGlobal(sig)); + return SigIdDesc(Kind::Global, globalDataOffset); +} + +static ImmediateType +LengthToBits(uint32_t length) +{ + static_assert(sMaxTypes <= ((1 << sLengthBits) - 1), "fits"); + MOZ_ASSERT(length <= sMaxTypes); + return length; +} + +/* static */ SigIdDesc +SigIdDesc::immediate(const Sig& sig) +{ + ImmediateType immediate = ImmediateBit; + uint32_t shift = sTagBits; + + if (sig.ret() != ExprType::Void) { + immediate |= (1 << shift); + shift += sReturnBit; + + immediate |= EncodeImmediateType(NonVoidToValType(sig.ret())) << shift; + shift += sTypeBits; + } else { + shift += sReturnBit; + } + + immediate |= LengthToBits(sig.args().length()) << shift; + shift += sLengthBits; + + for (ValType argType : sig.args()) { + immediate |= EncodeImmediateType(argType) << shift; + shift += sTypeBits; + } + + MOZ_ASSERT(shift <= sTotalBits); + return SigIdDesc(Kind::Immediate, immediate); +} + +size_t +SigWithId::serializedSize() const +{ + return Sig::serializedSize() + + sizeof(id); +} + +uint8_t* +SigWithId::serialize(uint8_t* cursor) const +{ + cursor = Sig::serialize(cursor); + cursor = WriteBytes(cursor, &id, sizeof(id)); + return cursor; +} + +const uint8_t* +SigWithId::deserialize(const uint8_t* cursor) +{ + (cursor = Sig::deserialize(cursor)) && + (cursor = ReadBytes(cursor, &id, sizeof(id))); + return cursor; +} + +size_t +SigWithId::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const +{ + return Sig::sizeOfExcludingThis(mallocSizeOf); +} + +Assumptions::Assumptions(JS::BuildIdCharVector&& buildId) + : cpuId(GetCPUID()), + buildId(Move(buildId)) +{} + +Assumptions::Assumptions() + : cpuId(GetCPUID()), + buildId() +{} + +bool +Assumptions::initBuildIdFromContext(ExclusiveContext* cx) +{ + if (!cx->buildIdOp() || !cx->buildIdOp()(&buildId)) { + ReportOutOfMemory(cx); + return false; + } + return true; +} + +bool +Assumptions::clone(const Assumptions& other) +{ + cpuId = other.cpuId; + return buildId.appendAll(other.buildId); +} + +bool +Assumptions::operator==(const Assumptions& rhs) const +{ + return cpuId == rhs.cpuId && + buildId.length() == rhs.buildId.length() && + PodEqual(buildId.begin(), rhs.buildId.begin(), buildId.length()); +} + +size_t +Assumptions::serializedSize() const +{ + return sizeof(uint32_t) + + SerializedPodVectorSize(buildId); +} + +uint8_t* +Assumptions::serialize(uint8_t* cursor) const +{ + // The format of serialized Assumptions must never change in a way that + // would cause old cache files written with by an old build-id to match the + // assumptions of a different build-id. + + cursor = WriteScalar<uint32_t>(cursor, cpuId); + cursor = SerializePodVector(cursor, buildId); + return cursor; +} + +const uint8_t* +Assumptions::deserialize(const uint8_t* cursor, size_t remain) +{ + (cursor = ReadScalarChecked<uint32_t>(cursor, &remain, &cpuId)) && + (cursor = DeserializePodVectorChecked(cursor, &remain, &buildId)); + return cursor; +} + +size_t +Assumptions::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const +{ + return buildId.sizeOfExcludingThis(mallocSizeOf); +} + +// Heap length on ARM should fit in an ARM immediate. We approximate the set +// of valid ARM immediates with the predicate: +// 2^n for n in [16, 24) +// or +// 2^24 * n for n >= 1. +bool +wasm::IsValidARMImmediate(uint32_t i) +{ + bool valid = (IsPowerOfTwo(i) || + (i & 0x00ffffff) == 0); + + MOZ_ASSERT_IF(valid, i % PageSize == 0); + + return valid; +} + +uint32_t +wasm::RoundUpToNextValidARMImmediate(uint32_t i) +{ + MOZ_ASSERT(i <= 0xff000000); + + if (i <= 16 * 1024 * 1024) + i = i ? mozilla::RoundUpPow2(i) : 0; + else + i = (i + 0x00ffffff) & ~0x00ffffff; + + MOZ_ASSERT(IsValidARMImmediate(i)); + + return i; +} + +#ifndef WASM_HUGE_MEMORY + +bool +wasm::IsValidBoundsCheckImmediate(uint32_t i) +{ +#ifdef JS_CODEGEN_ARM + return IsValidARMImmediate(i); +#else + return true; +#endif +} + +size_t +wasm::ComputeMappedSize(uint32_t maxSize) +{ + MOZ_ASSERT(maxSize % PageSize == 0); + + // It is the bounds-check limit, not the mapped size, that gets baked into + // code. Thus round up the maxSize to the next valid immediate value + // *before* adding in the guard page. + +# ifdef JS_CODEGEN_ARM + uint32_t boundsCheckLimit = RoundUpToNextValidARMImmediate(maxSize); +# else + uint32_t boundsCheckLimit = maxSize; +# endif + MOZ_ASSERT(IsValidBoundsCheckImmediate(boundsCheckLimit)); + + MOZ_ASSERT(boundsCheckLimit % gc::SystemPageSize() == 0); + MOZ_ASSERT(GuardSize % gc::SystemPageSize() == 0); + return boundsCheckLimit + GuardSize; +} + +#endif // WASM_HUGE_MEMORY |