Bug 1229399: Implement write/readVarU32 and use it for locals/globals; r=luke

This commit is contained in:
Benjamin Bouvier 2016-01-18 17:40:03 +01:00
parent c848138c5a
commit 5746c4ca9e
4 changed files with 90 additions and 35 deletions

View File

@ -2696,20 +2696,24 @@ class MOZ_STACK_CLASS FunctionValidator
}
MOZ_WARN_UNUSED_RESULT
bool writeU8(uint8_t u) {
return encoder().writeU8(u);
bool writeU8(uint8_t u8) {
return encoder().writeU8(u8);
}
MOZ_WARN_UNUSED_RESULT
bool writeU32(uint32_t u) {
return encoder().writeU32(u);
bool writeVarU32(uint32_t u32) {
return encoder().writeVarU32(u32);
}
MOZ_WARN_UNUSED_RESULT
bool writeI32(int32_t u) {
return encoder().writeI32(u);
bool writeU32(uint32_t u32) {
return encoder().writeU32(u32);
}
MOZ_WARN_UNUSED_RESULT
bool writeInt32Lit(int32_t i) {
return writeOp(Expr::I32Literal) && encoder().writeI32(i);
bool writeI32(int32_t i32) {
return encoder().writeI32(i32);
}
MOZ_WARN_UNUSED_RESULT
bool writeInt32Lit(int32_t i32) {
return writeOp(Expr::I32Literal) && encoder().writeI32(i32);
}
MOZ_WARN_UNUSED_RESULT
@ -3406,7 +3410,7 @@ SetLocal(FunctionValidator& f, Expr exprStmt, NumLit lit)
{
return f.writeOp(exprStmt) &&
f.writeOp(Expr::SetLocal) &&
f.writeU32(f.numLocals()) &&
f.writeVarU32(f.numLocals()) &&
f.writeLit(lit);
}
@ -3509,7 +3513,7 @@ CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type)
if (!f.writeOp(Expr::GetLocal))
return false;
MOZ_ASSERT(local->type != ValType::I64, "no int64 in asm.js");
if (!f.writeU32(local->slot))
if (!f.writeVarU32(local->slot))
return false;
*type = Type::var(local->type);
return true;
@ -3524,7 +3528,7 @@ CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type)
case ModuleValidator::Global::Variable: {
*type = global->varOrConstType();
return f.writeOp(Expr::LoadGlobal) &&
f.writeU32(global->varOrConstGlobalDataOffset()) &&
f.writeVarU32(global->varOrConstGlobalDataOffset()) &&
f.writeU8(uint8_t(global->isConst()));
}
case ModuleValidator::Global::Function:
@ -3815,25 +3819,19 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type
{
RootedPropertyName name(f.cx(), lhs->name());
size_t opcodeAt;
size_t indexAt;
if (!f.tempOp(&opcodeAt) || !f.temp32(&indexAt))
return false;
Type rhsType;
if (!CheckExpr(f, rhs, &rhsType))
return false;
if (const FunctionValidator::Local* lhsVar = f.lookupLocal(name)) {
if (!f.writeOp(Expr::SetLocal) || !f.writeVarU32(lhsVar->slot))
return false;
Type rhsType;
if (!CheckExpr(f, rhs, &rhsType))
return false;
if (!(rhsType <= lhsVar->type)) {
return f.failf(lhs, "%s is not a subtype of %s",
rhsType.toChars(), Type::var(lhsVar->type).toChars());
}
MOZ_ASSERT(lhsVar->type != ValType::I64, "no int64 in asm.js");
f.patchOp(opcodeAt, Expr::SetLocal);
f.patch32(indexAt, lhsVar->slot);
*type = rhsType;
return true;
}
@ -3842,13 +3840,16 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type
if (global->which() != ModuleValidator::Global::Variable)
return f.failName(lhs, "'%s' is not a mutable variable", name);
if (!(rhsType <= global->varOrConstType())) {
return f.failf(lhs, "%s is not a subtype of %s",
rhsType.toChars(), global->varOrConstType().toChars());
}
if (!f.writeOp(Expr::StoreGlobal) || !f.writeVarU32(global->varOrConstGlobalDataOffset()))
return false;
f.patchOp(opcodeAt, Expr::StoreGlobal);
f.patch32(indexAt, global->varOrConstGlobalDataOffset());
Type rhsType;
if (!CheckExpr(f, rhs, &rhsType))
return false;
Type globType = global->varOrConstType();
if (!(rhsType <= globType))
return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(), globType.toChars());
*type = rhsType;
return true;
}

View File

@ -398,7 +398,7 @@ class Encoder
done_(false)
{}
bool init(UniqueBytecode bytecode) {
bool init(UniqueBytecode bytecode = UniqueBytecode()) {
if (bytecode) {
bytecode_ = mozilla::Move(bytecode);
bytecode_->clear();
@ -417,6 +417,19 @@ class Encoder
return mozilla::Move(bytecode_);
}
MOZ_WARN_UNUSED_RESULT bool
writeVarU32(uint32_t i) {
do {
uint8_t byte = i & 0x7F;
i >>= 7;
if (i != 0)
byte |= 0x80;
if (!writeU8(byte))
return false;
} while(i != 0);
return true;
}
MOZ_WARN_UNUSED_RESULT bool
writeU8(uint8_t i, size_t* offset = nullptr) { return write<uint8_t>(i, offset); }
MOZ_WARN_UNUSED_RESULT bool
@ -546,6 +559,26 @@ class Decoder
return true;
}
MOZ_WARN_UNUSED_RESULT bool readVarU32(uint32_t* decoded) {
*decoded = 0;
uint8_t byte;
uint32_t shift = 0;
do {
if (!readU8(&byte))
return false;
if (!(byte & 0x80)) {
*decoded |= uint32_t(byte & 0x7F) << shift;
return true;
}
*decoded |= uint32_t(byte & 0x7F) << shift;
shift += 7;
} while (shift != 28);
if (!readU8(&byte) || (byte & 0xF0))
return false;
*decoded |= uint32_t(byte) << 28;
return true;
}
// The infallible unpacking API should be used when we are sure that the
// bytecode is well-formed.
uint8_t uncheckedReadU8 () { return uncheckedRead<uint8_t>(); }
@ -567,6 +600,25 @@ class Decoder
v[i] = uncheckedReadF32();
return jit::SimdConstant::CreateX4(v[0], v[1], v[2], v[3]);
}
uint32_t uncheckedReadVarU32() {
uint32_t decoded = 0;
uint32_t shift = 0;
uint8_t byte;
do {
byte = uncheckedReadU8();
if (!(byte & 0x80)) {
decoded |= uint32_t(byte & 0x7F) << shift;
return decoded;
}
decoded |= uint32_t(byte & 0x7F) << shift;
shift += 7;
} while (shift != 28);
byte = uncheckedReadU8();
MOZ_ASSERT(!(byte & 0xF0));
decoded |= uint32_t(byte) << 28;
return decoded;
}
};
// Source coordinates for a call site. As they're read sequentially, we

View File

@ -1170,6 +1170,7 @@ class FunctionCompiler
uint8_t readU8() { return decoder_.uncheckedReadU8(); }
uint32_t readU32() { return decoder_.uncheckedReadU32(); }
uint32_t readVarU32() { return decoder_.uncheckedReadVarU32(); }
int32_t readI32() { return decoder_.uncheckedReadI32(); }
float readF32() { return decoder_.uncheckedReadF32(); }
double readF64() { return decoder_.uncheckedReadF64(); }
@ -1330,7 +1331,7 @@ EmitLiteral(FunctionCompiler& f, ValType type, MDefinition**def)
static bool
EmitGetLocal(FunctionCompiler& f, const DebugOnly<MIRType>& type, MDefinition** def)
{
uint32_t slot = f.readU32();
uint32_t slot = f.readVarU32();
*def = f.getLocalDef(slot);
MOZ_ASSERT_IF(*def, (*def)->type() == type);
return true;
@ -1339,7 +1340,7 @@ EmitGetLocal(FunctionCompiler& f, const DebugOnly<MIRType>& type, MDefinition**
static bool
EmitLoadGlobal(FunctionCompiler& f, MIRType type, MDefinition** def)
{
uint32_t globalDataOffset = f.readU32();
uint32_t globalDataOffset = f.readVarU32();
bool isConst = bool(f.readU8());
*def = f.loadGlobalVar(globalDataOffset, isConst, type);
return true;
@ -1429,7 +1430,7 @@ EmitStoreWithCoercion(FunctionCompiler& f, Scalar::Type rhsType, Scalar::Type vi
static bool
EmitSetLocal(FunctionCompiler& f, ValType type, MDefinition** def)
{
uint32_t slot = f.readU32();
uint32_t slot = f.readVarU32();
MDefinition* expr;
if (!EmitExpr(f, type, &expr))
return false;
@ -1441,7 +1442,7 @@ EmitSetLocal(FunctionCompiler& f, ValType type, MDefinition** def)
static bool
EmitStoreGlobal(FunctionCompiler& f, ValType type, MDefinition**def)
{
uint32_t globalDataOffset = f.readU32();
uint32_t globalDataOffset = f.readVarU32();
MDefinition* expr;
if (!EmitExpr(f, type, &expr))
return false;

View File

@ -86,6 +86,7 @@ UNIFIED_SOURCES += [
'testUbiNode.cpp',
'testUncaughtError.cpp',
'testUTF8.cpp',
'testWasmLEB128.cpp',
'testWeakMap.cpp',
'testXDR.cpp',
]