mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 22:55:23 +00:00
Bug 1242804 - Baldr: check enum limits (r=bbouvier)
--HG-- extra : commitid : 84UukXxvZNS extra : rebase_source : f0fa0b4951c6db31da4d82562f54c459c8ead874
This commit is contained in:
parent
61673d713d
commit
a0e0319958
@ -1099,6 +1099,7 @@ class Type
|
||||
case ValType::I32x4: return Int32x4;
|
||||
case ValType::F32x4: return Float32x4;
|
||||
case ValType::B32x4: return Bool32x4;
|
||||
case ValType::Limit: break;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type");
|
||||
}
|
||||
@ -1113,6 +1114,7 @@ class Type
|
||||
case ExprType::I32x4: return Int32x4;
|
||||
case ExprType::F32x4: return Float32x4;
|
||||
case ExprType::B32x4: return Bool32x4;
|
||||
case ExprType::Limit: break;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type");
|
||||
}
|
||||
@ -1161,6 +1163,7 @@ class Type
|
||||
case ValType::I32x4: return isInt32x4();
|
||||
case ValType::F32x4: return isFloat32x4();
|
||||
case ValType::B32x4: return isBool32x4();
|
||||
case ValType::Limit: break;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected rhs type");
|
||||
}
|
||||
@ -4639,6 +4642,7 @@ CheckCoercionArg(FunctionValidator& f, ParseNode* arg, ValType expected, Type* t
|
||||
break;
|
||||
case ValType::I32:
|
||||
case ValType::F64:
|
||||
case ValType::Limit:
|
||||
MOZ_CRASH("not call coercions");
|
||||
}
|
||||
|
||||
@ -5457,6 +5461,8 @@ CoerceResult(FunctionValidator& f, ParseNode* expr, ExprType expected, Type actu
|
||||
return f.failf(expr, "%s is not a subtype of bool32x4", actual.toChars());
|
||||
f.patchOp(patchAt, Expr::Id);
|
||||
break;
|
||||
case ExprType::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
}
|
||||
|
||||
*type = Type::ret(expected);
|
||||
@ -7079,6 +7085,8 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, uint8_t* global
|
||||
case ValType::F32x4:
|
||||
memcpy(datum, v.f32x4(), Simd128DataSize);
|
||||
break;
|
||||
case ValType::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -7129,6 +7137,8 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, uint8_t* global
|
||||
memcpy(datum, simdConstant.asInt32x4(), Simd128DataSize);
|
||||
break;
|
||||
}
|
||||
case ValType::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -269,7 +269,9 @@ enum class Expr : uint16_t
|
||||
F64FromS32,
|
||||
F64FromU32,
|
||||
|
||||
F64StoreMemF32
|
||||
F64StoreMemF32,
|
||||
|
||||
Limit
|
||||
};
|
||||
|
||||
enum NeedsBoundsCheck : uint8_t
|
||||
@ -296,7 +298,7 @@ class Encoder
|
||||
return bytecode_.append(reinterpret_cast<uint8_t*>(&v), sizeof(T));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class IntT, class T>
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool writeEnum(T v, size_t* offset) {
|
||||
// For now, just write a u16 instead of a variable-length integer.
|
||||
@ -304,16 +306,17 @@ class Encoder
|
||||
// pre-order encoding and back-patching; let's see if we switch to
|
||||
// post-order first.
|
||||
static_assert(mozilla::IsEnum<T>::value, "is an enum");
|
||||
MOZ_ASSERT(uint64_t(v) < UINT16_MAX);
|
||||
return write<uint16_t>(uint16_t(v), offset);
|
||||
MOZ_ASSERT(uint64_t(v) < IntT(-1));
|
||||
MOZ_ASSERT(v != T::Limit);
|
||||
return write<IntT>(IntT(v), offset);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class IntT, class T>
|
||||
void patchEnum(size_t pc, T v) {
|
||||
// See writeEnum comment.
|
||||
static_assert(mozilla::IsEnum<T>::value, "is an enum");
|
||||
MOZ_ASSERT(uint64_t(v) < UINT16_MAX);
|
||||
memcpy(&bytecode_[pc], &v, sizeof(uint16_t));
|
||||
memcpy(&bytecode_[pc], &v, sizeof(IntT));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -349,11 +352,11 @@ class Encoder
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
writeExpr(Expr expr, size_t* offset = nullptr) { return writeEnum(expr, offset); }
|
||||
writeExpr(Expr expr, size_t* offset = nullptr) { return writeEnum<uint16_t>(expr, offset); }
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
writeValType(ValType type, size_t* offset = nullptr) { return writeEnum(type, offset); }
|
||||
writeValType(ValType type, size_t* offset = nullptr) { return writeEnum<uint8_t>(type, offset); }
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
writeExprType(ExprType type, size_t* offset = nullptr) { return writeEnum(type, offset); }
|
||||
writeExprType(ExprType type, size_t* offset = nullptr) { return writeEnum<uint8_t>(type, offset); }
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
writeU8(uint8_t i, size_t* offset = nullptr) { return write<uint8_t>(i, offset); }
|
||||
@ -421,7 +424,7 @@ class Encoder
|
||||
void patchExpr(size_t pc, Expr expr) {
|
||||
// See comment in writeEnum
|
||||
MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint16_t)));
|
||||
patchEnum(pc, expr);
|
||||
patchEnum<uint16_t>(pc, expr);
|
||||
}
|
||||
template<class T>
|
||||
void patch32(size_t pc, T i) {
|
||||
@ -449,16 +452,16 @@ class Decoder
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class IntT, class T>
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
readEnum(T* out) {
|
||||
static_assert(mozilla::IsEnum<T>::value, "is an enum");
|
||||
// See Encoder::writeEnum.
|
||||
uint16_t u16;
|
||||
if (!read(&u16))
|
||||
IntT i;
|
||||
if (!read(&i) || i >= IntT(T::Limit))
|
||||
return false;
|
||||
if (out)
|
||||
*out = T(u16);
|
||||
*out = T(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -470,11 +473,11 @@ class Decoder
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class IntT, class T>
|
||||
T uncheckedPeekEnum() const {
|
||||
// See Encoder::writeEnum.
|
||||
static_assert(mozilla::IsEnum<T>::value, "is an enum");
|
||||
return (T)uncheckedPeek<uint16_t>();
|
||||
return (T)uncheckedPeek<IntT>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -484,11 +487,11 @@ class Decoder
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class IntT, class T>
|
||||
T uncheckedReadEnum() {
|
||||
// See Encoder::writeEnum.
|
||||
static_assert(mozilla::IsEnum<T>::value, "is an enum");
|
||||
return (T)uncheckedRead<uint16_t>();
|
||||
return (T)uncheckedRead<IntT>();
|
||||
}
|
||||
|
||||
public:
|
||||
@ -571,13 +574,13 @@ class Decoder
|
||||
return true;
|
||||
}
|
||||
MOZ_WARN_UNUSED_RESULT bool readExpr(Expr* expr = nullptr) {
|
||||
return readEnum(expr);
|
||||
return readEnum<uint16_t>(expr);
|
||||
}
|
||||
MOZ_WARN_UNUSED_RESULT bool readValType(ValType* type = nullptr) {
|
||||
return readEnum(type);
|
||||
return readEnum<uint8_t>(type);
|
||||
}
|
||||
MOZ_WARN_UNUSED_RESULT bool readExprType(ExprType* type = nullptr) {
|
||||
return readEnum(type);
|
||||
return readEnum<uint8_t>(type);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT bool readCString(const char** cstr = nullptr) {
|
||||
@ -666,10 +669,10 @@ class Decoder
|
||||
return decoded;
|
||||
}
|
||||
Expr uncheckedReadExpr() {
|
||||
return uncheckedReadEnum<Expr>();
|
||||
return uncheckedReadEnum<uint16_t, Expr>();
|
||||
}
|
||||
Expr uncheckedPeekExpr() const {
|
||||
return uncheckedPeekEnum<Expr>();
|
||||
return uncheckedPeekEnum<uint16_t, Expr>();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -238,19 +238,22 @@ ModuleGenerator::allocateGlobalVar(ValType type, bool isConst, uint32_t* index)
|
||||
MOZ_ASSERT(!startedFuncDefs());
|
||||
unsigned width = 0;
|
||||
switch (type) {
|
||||
case wasm::ValType::I32:
|
||||
case wasm::ValType::F32:
|
||||
case ValType::I32:
|
||||
case ValType::F32:
|
||||
width = 4;
|
||||
break;
|
||||
case wasm::ValType::I64:
|
||||
case wasm::ValType::F64:
|
||||
case ValType::I64:
|
||||
case ValType::F64:
|
||||
width = 8;
|
||||
break;
|
||||
case wasm::ValType::I32x4:
|
||||
case wasm::ValType::F32x4:
|
||||
case wasm::ValType::B32x4:
|
||||
case ValType::I32x4:
|
||||
case ValType::F32x4:
|
||||
case ValType::B32x4:
|
||||
width = 16;
|
||||
break;
|
||||
case ValType::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t offset;
|
||||
|
@ -135,6 +135,8 @@ class FunctionCompiler
|
||||
// Bool32x4 uses the same data layout as Int32x4.
|
||||
ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType_Bool32x4);
|
||||
break;
|
||||
case ValType::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
}
|
||||
|
||||
curBlock_->add(ins);
|
||||
@ -1292,24 +1294,6 @@ class FunctionCompiler
|
||||
}
|
||||
};
|
||||
|
||||
// A Type or Undefined, implicitly constructed from an ExprType and usabled as
|
||||
// an ExprType. Has two functions:
|
||||
// - in debug, will ensure that the expected type and the actual type of some
|
||||
// expressions match.
|
||||
// - provides a way to mean "no type" in the context of expression statements,
|
||||
// and will provoke assertions if we're trying to use an expected type when we
|
||||
// don't have one.
|
||||
class MaybeType
|
||||
{
|
||||
Maybe<ExprType> maybe_;
|
||||
MaybeType() {}
|
||||
public:
|
||||
MOZ_IMPLICIT MaybeType(ExprType t) : maybe_() { maybe_.emplace(t); }
|
||||
static MaybeType Undefined() { return MaybeType(); }
|
||||
explicit operator bool() { return maybe_.isSome(); }
|
||||
MOZ_IMPLICIT operator ExprType() { return maybe_.value(); }
|
||||
};
|
||||
|
||||
static bool
|
||||
EmitLiteral(FunctionCompiler& f, ExprType type, MDefinition** def)
|
||||
{
|
||||
@ -1348,7 +1332,8 @@ EmitLiteral(FunctionCompiler& f, ExprType type, MDefinition** def)
|
||||
*def = f.constant(lit, MIRType_Bool32x4);
|
||||
return true;
|
||||
}
|
||||
case ExprType::Void: {
|
||||
case ExprType::Void:
|
||||
case ExprType::Limit: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1356,25 +1341,25 @@ EmitLiteral(FunctionCompiler& f, ExprType type, MDefinition** def)
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitGetLocal(FunctionCompiler& f, MaybeType type, MDefinition** def)
|
||||
EmitGetLocal(FunctionCompiler& f, ExprType type, MDefinition** def)
|
||||
{
|
||||
uint32_t slot = f.readVarU32();
|
||||
*def = f.getLocalDef(slot);
|
||||
MOZ_ASSERT_IF(type, f.localType(slot) == type);
|
||||
MOZ_ASSERT_IF(type != ExprType::Limit, f.localType(slot) == type);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitLoadGlobal(FunctionCompiler& f, MaybeType type, MDefinition** def)
|
||||
EmitLoadGlobal(FunctionCompiler& f, ExprType type, MDefinition** def)
|
||||
{
|
||||
uint32_t index = f.readVarU32();
|
||||
const AsmJSGlobalVariable& global = f.mg().globalVar(index);
|
||||
*def = f.loadGlobalVar(global.globalDataOffset, global.isConst, ToMIRType(global.type));
|
||||
MOZ_ASSERT_IF(type, global.type == type);
|
||||
MOZ_ASSERT_IF(type != ExprType::Limit, global.type == type);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool EmitExpr(FunctionCompiler&, MaybeType, MDefinition**, LabelVector* = nullptr);
|
||||
static bool EmitExpr(FunctionCompiler&, ExprType, MDefinition**, LabelVector* = nullptr);
|
||||
static bool EmitExprStmt(FunctionCompiler&, MDefinition**, LabelVector* = nullptr);
|
||||
|
||||
static bool
|
||||
@ -1450,12 +1435,12 @@ EmitStoreWithCoercion(FunctionCompiler& f, Scalar::Type rhsType, Scalar::Type vi
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitSetLocal(FunctionCompiler& f, MaybeType expected, MDefinition** def)
|
||||
EmitSetLocal(FunctionCompiler& f, ExprType expected, MDefinition** def)
|
||||
{
|
||||
uint32_t slot = f.readVarU32();
|
||||
MDefinition* expr;
|
||||
ExprType actual = f.localType(slot);
|
||||
MOZ_ASSERT_IF(expected, actual == expected);
|
||||
MOZ_ASSERT_IF(expected != ExprType::Limit, actual == expected);
|
||||
if (!EmitExpr(f, actual, &expr))
|
||||
return false;
|
||||
f.assign(slot, expr);
|
||||
@ -1464,11 +1449,11 @@ EmitSetLocal(FunctionCompiler& f, MaybeType expected, MDefinition** def)
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitStoreGlobal(FunctionCompiler& f, MaybeType type, MDefinition**def)
|
||||
EmitStoreGlobal(FunctionCompiler& f, ExprType type, MDefinition**def)
|
||||
{
|
||||
uint32_t index = f.readVarU32();
|
||||
const AsmJSGlobalVariable& global = f.mg().globalVar(index);
|
||||
MOZ_ASSERT_IF(type, global.type == type);
|
||||
MOZ_ASSERT_IF(type != ExprType::Limit, global.type == type);
|
||||
MDefinition* expr;
|
||||
if (!EmitExpr(f, global.type, &expr))
|
||||
return false;
|
||||
@ -1589,6 +1574,7 @@ EmitCallArgs(FunctionCompiler& f, const Sig& sig, FunctionCompiler::Call* call)
|
||||
case ValType::I32x4: if (!EmitExpr(f, ExprType::I32x4, &arg)) return false; break;
|
||||
case ValType::F32x4: if (!EmitExpr(f, ExprType::F32x4, &arg)) return false; break;
|
||||
case ValType::B32x4: if (!EmitExpr(f, ExprType::B32x4, &arg)) return false; break;
|
||||
case ValType::Limit: MOZ_CRASH("Limit");
|
||||
}
|
||||
if (!f.passArg(arg, sig.arg(i), call))
|
||||
return false;
|
||||
@ -1598,12 +1584,12 @@ EmitCallArgs(FunctionCompiler& f, const Sig& sig, FunctionCompiler::Call* call)
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitInternalCall(FunctionCompiler& f, MaybeType ret, MDefinition** def)
|
||||
EmitInternalCall(FunctionCompiler& f, ExprType ret, MDefinition** def)
|
||||
{
|
||||
uint32_t funcIndex = f.readU32();
|
||||
|
||||
const Sig& sig = f.mg().funcSig(funcIndex);
|
||||
MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret, sig.ret() == ret);
|
||||
MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret != ExprType::Limit, sig.ret() == ret);
|
||||
|
||||
uint32_t lineno, column;
|
||||
f.readCallLineCol(&lineno, &column);
|
||||
@ -1616,14 +1602,14 @@ EmitInternalCall(FunctionCompiler& f, MaybeType ret, MDefinition** def)
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitFuncPtrCall(FunctionCompiler& f, MaybeType ret, MDefinition** def)
|
||||
EmitFuncPtrCall(FunctionCompiler& f, ExprType ret, MDefinition** def)
|
||||
{
|
||||
uint32_t mask = f.readU32();
|
||||
uint32_t globalDataOffset = f.readU32();
|
||||
uint32_t sigIndex = f.readU32();
|
||||
|
||||
const Sig& sig = f.mg().sig(sigIndex);
|
||||
MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret, sig.ret() == ret);
|
||||
MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret != ExprType::Limit, sig.ret() == ret);
|
||||
|
||||
uint32_t lineno, column;
|
||||
f.readCallLineCol(&lineno, &column);
|
||||
@ -1640,7 +1626,7 @@ EmitFuncPtrCall(FunctionCompiler& f, MaybeType ret, MDefinition** def)
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitFFICall(FunctionCompiler& f, MaybeType ret, MDefinition** def)
|
||||
EmitFFICall(FunctionCompiler& f, ExprType ret, MDefinition** def)
|
||||
{
|
||||
uint32_t importIndex = f.readU32();
|
||||
|
||||
@ -1649,7 +1635,7 @@ EmitFFICall(FunctionCompiler& f, MaybeType ret, MDefinition** def)
|
||||
|
||||
const ModuleImportGeneratorData& import = f.mg().import(importIndex);
|
||||
const Sig& sig = *import.sig;
|
||||
MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret, sig.ret() == ret);
|
||||
MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret != ExprType::Limit, sig.ret() == ret);
|
||||
|
||||
FunctionCompiler::Call call(f, lineno, column);
|
||||
if (!EmitCallArgs(f, sig, &call))
|
||||
@ -1805,7 +1791,8 @@ SimdToLaneType(ExprType type)
|
||||
case ExprType::I64:
|
||||
case ExprType::F32:
|
||||
case ExprType::F64:
|
||||
case ExprType::Void:;
|
||||
case ExprType::Void:
|
||||
case ExprType::Limit:;
|
||||
}
|
||||
MOZ_CRASH("bad simd type");
|
||||
}
|
||||
@ -2065,6 +2052,7 @@ EmitSimdCtor(FunctionCompiler& f, ExprType type, MDefinition** def)
|
||||
case ExprType::F32:
|
||||
case ExprType::F64:
|
||||
case ExprType::Void:
|
||||
case ExprType::Limit:
|
||||
break;
|
||||
}
|
||||
MOZ_CRASH("unexpected SIMD type");
|
||||
@ -2093,7 +2081,7 @@ EmitUnaryMir(FunctionCompiler& f, ExprType type, MDefinition** def)
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitTernary(FunctionCompiler& f, MaybeType type, MDefinition** def)
|
||||
EmitTernary(FunctionCompiler& f, ExprType type, MDefinition** def)
|
||||
{
|
||||
MDefinition* cond;
|
||||
if (!EmitExpr(f, ExprType::I32, &cond))
|
||||
@ -2645,7 +2633,7 @@ EmitRet(FunctionCompiler& f)
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitBlock(FunctionCompiler& f, MaybeType type, MDefinition** def)
|
||||
EmitBlock(FunctionCompiler& f, ExprType type, MDefinition** def)
|
||||
{
|
||||
size_t numStmt = f.readU32();
|
||||
for (size_t i = 1; i < numStmt; i++) {
|
||||
@ -2680,7 +2668,7 @@ EmitBreak(FunctionCompiler& f, bool hasLabel)
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* maybeLabels)
|
||||
EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* maybeLabels)
|
||||
{
|
||||
if (!f.mirGen().ensureBallast())
|
||||
return false;
|
||||
@ -2982,6 +2970,8 @@ EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* ma
|
||||
case Expr::DebugCheckPoint:
|
||||
case Expr::Unreachable:
|
||||
break;
|
||||
case Expr::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
}
|
||||
|
||||
MOZ_CRASH("unexpected wasm opcode");
|
||||
@ -2990,7 +2980,7 @@ EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* ma
|
||||
static bool
|
||||
EmitExprStmt(FunctionCompiler& f, MDefinition** def, LabelVector* maybeLabels)
|
||||
{
|
||||
return EmitExpr(f, MaybeType::Undefined(), def, maybeLabels);
|
||||
return EmitExpr(f, ExprType::Limit, def, maybeLabels);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1287,6 +1287,8 @@ Module::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
|
||||
memcpy(&coercedArgs[i], simd.asInt32x4(), Simd128DataSize);
|
||||
break;
|
||||
}
|
||||
case ValType::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1349,6 +1351,8 @@ Module::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
|
||||
return false;
|
||||
args.rval().set(ObjectValue(*simdObj));
|
||||
break;
|
||||
case ExprType::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1412,6 +1416,7 @@ Module::callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const Val
|
||||
case ValType::I32x4: MOZ_CRASH("NYI");
|
||||
case ValType::F32x4: MOZ_CRASH("NYI");
|
||||
case ValType::B32x4: MOZ_CRASH("NYI");
|
||||
case ValType::Limit: MOZ_CRASH("Limit");
|
||||
}
|
||||
if (!TypeScript::ArgTypes(script, i)->hasType(type))
|
||||
return true;
|
||||
|
@ -272,6 +272,8 @@ GenerateEntry(ModuleGenerator& mg, unsigned exportIndex, bool usesHeap)
|
||||
// We don't have control on argv alignment, do an unaligned access.
|
||||
masm.storeUnalignedFloat32x4(ReturnSimd128Reg, Address(argv, 0));
|
||||
break;
|
||||
case ExprType::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
}
|
||||
|
||||
// Restore clobbered non-volatile registers of the caller.
|
||||
@ -416,6 +418,8 @@ GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, Label* throwLa
|
||||
case ExprType::F32x4:
|
||||
case ExprType::B32x4:
|
||||
MOZ_CRASH("SIMD types shouldn't be returned from a FFI");
|
||||
case ExprType::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
}
|
||||
|
||||
GenerateExitEpilogue(masm, framePushed, ExitReason::ImportInterp, offsets);
|
||||
@ -663,6 +667,8 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, bool usesHeap,
|
||||
case ExprType::F32x4:
|
||||
case ExprType::B32x4:
|
||||
MOZ_CRASH("SIMD types shouldn't be returned from an import");
|
||||
case ExprType::Limit:
|
||||
MOZ_CRASH("Limit");
|
||||
}
|
||||
|
||||
Label done;
|
||||
|
@ -54,7 +54,9 @@ enum class ValType
|
||||
F64,
|
||||
I32x4,
|
||||
F32x4,
|
||||
B32x4
|
||||
B32x4,
|
||||
|
||||
Limit
|
||||
};
|
||||
|
||||
typedef Vector<ValType, 8, SystemAllocPolicy> ValTypeVector;
|
||||
@ -76,6 +78,7 @@ ToMIRType(ValType vt)
|
||||
case ValType::I32x4: return jit::MIRType_Int32x4;
|
||||
case ValType::F32x4: return jit::MIRType_Float32x4;
|
||||
case ValType::B32x4: return jit::MIRType_Bool32x4;
|
||||
case ValType::Limit: break;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type");
|
||||
}
|
||||
@ -147,7 +150,9 @@ enum class ExprType : uint16_t
|
||||
I32x4 = uint8_t(ValType::I32x4),
|
||||
F32x4 = uint8_t(ValType::F32x4),
|
||||
B32x4 = uint8_t(ValType::B32x4),
|
||||
Void
|
||||
Void,
|
||||
|
||||
Limit
|
||||
};
|
||||
|
||||
static inline bool
|
||||
|
@ -4,30 +4,107 @@ if (!this.wasmEval)
|
||||
quit();
|
||||
|
||||
// MagicNumber = 0x4d534100
|
||||
var magic0 = 0;
|
||||
var magic1 = 97; // 'a'
|
||||
var magic2 = 115; // 's'
|
||||
var magic3 = 109; // 'm'
|
||||
const magic0 = 0;
|
||||
const magic1 = 97; // 'a'
|
||||
const magic2 = 115; // 's'
|
||||
const magic3 = 109; // 'm'
|
||||
|
||||
// EncodingVersion = -1
|
||||
var ver0 = 0xff;
|
||||
var ver1 = 0xff;
|
||||
var ver2 = 0xff;
|
||||
var ver3 = 0xff;
|
||||
// EncodingVersion = -1 (to be changed to 1 at some point in the future)
|
||||
const ver0 = 0xff;
|
||||
const ver1 = 0xff;
|
||||
const ver2 = 0xff;
|
||||
const ver3 = 0xff;
|
||||
|
||||
var magicError = /failed to match magic number/;
|
||||
var versionError = /failed to match binary version/;
|
||||
var extraError = /failed to consume all bytes of module/;
|
||||
// Section names
|
||||
const sigSectionStr = "sig";
|
||||
const declSectionStr = "decl";
|
||||
const exportSectionStr = "export";
|
||||
const codeSectionStr = "code";
|
||||
|
||||
assertErrorMessage(() => wasmEval(Uint8Array.of().buffer), Error, magicError);
|
||||
assertErrorMessage(() => wasmEval(Uint8Array.of(42).buffer), Error, magicError);
|
||||
assertErrorMessage(() => wasmEval(Uint8Array.of(magic0, magic1, magic2).buffer), Error, magicError);
|
||||
assertErrorMessage(() => wasmEval(Uint8Array.of(1,2,3,4).buffer), Error, magicError);
|
||||
assertErrorMessage(() => wasmEval(Uint8Array.of(magic0, magic1, magic2, magic3).buffer), Error, versionError);
|
||||
assertErrorMessage(() => wasmEval(Uint8Array.of(magic0, magic1, magic2, magic3, 1).buffer), Error, versionError);
|
||||
assertErrorMessage(() => wasmEval(Uint8Array.of(magic0, magic1, magic2, magic3, ver0).buffer), Error, versionError);
|
||||
assertErrorMessage(() => wasmEval(Uint8Array.of(magic0, magic1, magic2, magic3, ver0, ver1, ver2).buffer), Error, versionError);
|
||||
assertErrorMessage(() => wasmEval(Uint8Array.of(magic0, magic1, magic2, magic3, ver0, ver1, ver2, ver3, 0, 1).buffer), Error, extraError);
|
||||
const magicError = /failed to match magic number/;
|
||||
const versionError = /failed to match binary version/;
|
||||
const extraError = /failed to consume all bytes of module/;
|
||||
const sectionError = /failed to read section name/;
|
||||
|
||||
var o = wasmEval(Uint8Array.of(magic0, magic1, magic2, magic3, ver0, ver1, ver2, ver3, 0).buffer);
|
||||
const I32Code = 0;
|
||||
const I64Code = 1;
|
||||
const F32Code = 2;
|
||||
const F64Code = 3;
|
||||
const I32x4Code = 4;
|
||||
const F32x4Code = 5;
|
||||
const B32x4Code = 6;
|
||||
const VoidCode = 7;
|
||||
|
||||
function toBuf(array) {
|
||||
for (var b of array)
|
||||
assertEq(b < 256, true);
|
||||
return Uint8Array.from(array).buffer;
|
||||
}
|
||||
|
||||
function varU32(u32) {
|
||||
// TODO
|
||||
assertEq(u32 < 128, true);
|
||||
return [u32];
|
||||
}
|
||||
|
||||
function moduleHeaderThen(...rest) {
|
||||
return [magic0, magic1, magic2, magic3, ver0, ver1, ver2, ver3, ...rest];
|
||||
}
|
||||
|
||||
assertErrorMessage(() => wasmEval(toBuf([])), Error, magicError);
|
||||
assertErrorMessage(() => wasmEval(toBuf([42])), Error, magicError);
|
||||
assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2])), Error, magicError);
|
||||
assertErrorMessage(() => wasmEval(toBuf([1,2,3,4])), Error, magicError);
|
||||
assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3])), Error, versionError);
|
||||
assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3, 1])), Error, versionError);
|
||||
assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3, ver0])), Error, versionError);
|
||||
assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3, ver0, ver1, ver2])), Error, versionError);
|
||||
|
||||
var o = wasmEval(toBuf(moduleHeaderThen(0)));
|
||||
assertEq(Object.getOwnPropertyNames(o).length, 0);
|
||||
|
||||
assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(1))), Error, sectionError);
|
||||
assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(0, 1))), Error, extraError);
|
||||
|
||||
function sectionName(name) {
|
||||
return (name + '\0').split('').map(c => c.charCodeAt(0));
|
||||
}
|
||||
|
||||
function sectionLength(length) {
|
||||
var i32 = new Uint32Array(1);
|
||||
i32[0] = length;
|
||||
return new Uint8Array(i32.buffer);
|
||||
}
|
||||
|
||||
function moduleWithSections(sectionArray) {
|
||||
var bytes = moduleHeaderThen();
|
||||
for (section of sectionArray) {
|
||||
bytes.push(...sectionName(section.name));
|
||||
bytes.push(...sectionLength(section.body.length));
|
||||
bytes.push(...section.body);
|
||||
}
|
||||
bytes.push(0);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function sigSection(sigs) {
|
||||
var body = [];
|
||||
body.push(...varU32(sigs.length));
|
||||
for (var sig of sigs) {
|
||||
body.push(...varU32(sig.args.length));
|
||||
body.push(...varU32(sig.ret));
|
||||
for (var arg of sig.args)
|
||||
body.push(...varU32(arg));
|
||||
}
|
||||
return { name: sigSectionStr, body };
|
||||
}
|
||||
|
||||
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([{name: sigSectionStr, body: [1]}]))), Error);
|
||||
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([{name: sigSectionStr, body: [1, 1, 0]}]))), Error);
|
||||
|
||||
wasmEval(toBuf(moduleWithSections([sigSection([])])));
|
||||
wasmEval(toBuf(moduleWithSections([sigSection([{args:[], ret:VoidCode}])])));
|
||||
wasmEval(toBuf(moduleWithSections([sigSection([{args:[I32Code], ret:VoidCode}])])));
|
||||
|
||||
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([{args:[], ret:100}])]))), Error, /bad result type/);
|
||||
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([{args:[100], ret:VoidCode}])]))), Error, /bad arg type/);
|
||||
|
Loading…
Reference in New Issue
Block a user