Skip to content

Commit

Permalink
Bug 1790626 - wasm: Use pointer to TypeDef instead of type index in P…
Browse files Browse the repository at this point in the history
…ackedType. r=yury

This commit switches the representation of PackedType (and therefore ValType/FieldType)
to use a *TypeDef instead of type index.

There are several changes here:
  1. PackedTypeCode is always 64-bits now to pack the pointer. This penalizes 32-bit
     platforms, but we likely don't care about them enough to try to optimize this.
  2. RefType::TypeIndex is RefType::TypeRef
  3. RefType::typeIndex() is RefType::typeDef()
  4. TypeContext now stores a map from *TypeDef to original type index for printing errors
  5. Decoding a RefType now stores a *TypeDef instead of type index
  6. We now just transfer the SharedTypeContext from ModuleEnvironment to Metadata instead
     of copying definitions. This is needed for sharing the indexOf map.
  7. We now manually serialize/deserialize TypeContext
  8. TypeContext now stores SharedTypeDef in vector instead of TypeDef, this is needed so
     that *TypeDef is not invalidated across resizing the vector (asm.js does this)
  9. The initialization of TypeContext is refactored to keep the indexOf map in-sync
     with adding new types (asm.js needs this)
  10. We now manually serialize/deserialize PackedTypeCode using a new SerializedTypeCode
  11. Serialization now needs a TypeContext in order to get the index of type definitions
  12. Deserialization now constructs a TypeContext, and uses that when deserializing
      ValType/RefType/FieldType

Differential Revision: https://phabricator.services.mozilla.com/D157387
  • Loading branch information
eqrion committed Oct 18, 2022
1 parent 17d7998 commit f4d3b34
Show file tree
Hide file tree
Showing 28 changed files with 600 additions and 646 deletions.
4 changes: 2 additions & 2 deletions js/src/jit/CodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17313,7 +17313,7 @@ void CodeGenerator::emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir) {
break;
case wasm::RefType::Func:
case wasm::RefType::Eq:
case wasm::RefType::TypeIndex:
case wasm::RefType::TypeRef:
MOZ_CRASH("unexpected argument type when calling from ion to wasm");
}
break;
Expand Down Expand Up @@ -17390,7 +17390,7 @@ void CodeGenerator::emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir) {
// API to do so.
MOZ_ASSERT(lir->mir()->type() == MIRType::Value);
break;
case wasm::RefType::TypeIndex:
case wasm::RefType::TypeRef:
MOZ_CRASH("unexpected return type when calling from ion to wasm");
}
break;
Expand Down
27 changes: 17 additions & 10 deletions js/src/wasm/AsmJS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1941,13 +1941,18 @@ class MOZ_STACK_CLASS ModuleValidator : public ModuleValidatorShared {
}

*sigIndex = moduleEnv_.types->length();
return moduleEnv_.types->append(std::move(sig));
MutableTypeDef typeDef = moduleEnv_.types->addType();
if (!typeDef) {
return false;
}
*typeDef = std::move(sig);
return true;
}
bool declareSig(FuncType&& sig, uint32_t* sigIndex) {
SigSet::AddPtr p = sigSet_.lookupForAdd(sig);
if (p) {
*sigIndex = p->sigIndex();
MOZ_ASSERT(moduleEnv_.types->funcType(*sigIndex) == sig);
MOZ_ASSERT(moduleEnv_.types->type(*sigIndex).funcType() == sig);
return true;
}

Expand Down Expand Up @@ -2128,15 +2133,15 @@ class MOZ_STACK_CLASS ModuleValidator : public ModuleValidatorShared {
uint32_t funcIndex = r.front().value();
uint32_t funcTypeIndex = r.front().key().sigIndex();
MOZ_ASSERT(!moduleEnv_.funcs[funcIndex].type);
moduleEnv_.funcs[funcIndex] =
FuncDesc(&moduleEnv_.types->funcType(funcTypeIndex), funcTypeIndex);
moduleEnv_.funcs[funcIndex] = FuncDesc(
&moduleEnv_.types->type(funcTypeIndex).funcType(), funcTypeIndex);
}
for (const Func& func : funcDefs_) {
uint32_t funcIndex = funcImportMap_.count() + func.funcDefIndex();
uint32_t funcTypeIndex = func.sigIndex();
MOZ_ASSERT(!moduleEnv_.funcs[funcIndex].type);
moduleEnv_.funcs[funcIndex] =
FuncDesc(&moduleEnv_.types->funcType(funcTypeIndex), funcTypeIndex);
moduleEnv_.funcs[funcIndex] = FuncDesc(
&moduleEnv_.types->type(funcTypeIndex).funcType(), funcTypeIndex);
}
for (const Export& exp : moduleEnv_.exports) {
if (exp.kind() != DefinitionKind::Function) {
Expand Down Expand Up @@ -4036,7 +4041,8 @@ static bool CheckFunctionSignature(ModuleValidator<Unit>& m, ParseNode* usepn,
return m.addFuncDef(name, usepn->pn_pos.begin, std::move(sig), func);
}

const FuncType& existingSig = m.env().types->funcType(existing->sigIndex());
const FuncType& existingSig =
m.env().types->type(existing->sigIndex()).funcType();

if (!CheckSignatureAgainstExisting(m, usepn, sig, existingSig)) {
return false;
Expand Down Expand Up @@ -4110,7 +4116,7 @@ static bool CheckFuncPtrTableAgainstExisting(ModuleValidator<Unit>& m,
}

if (!CheckSignatureAgainstExisting(
m, usepn, sig, m.env().types->funcType(table.sigIndex()))) {
m, usepn, sig, m.env().types->type(table.sigIndex()).funcType())) {
return false;
}

Expand Down Expand Up @@ -5948,7 +5954,8 @@ static bool CheckReturnType(FunctionValidatorShared& f, ParseNode* usepn,

if (f.returnedType() != type) {
return f.failf(usepn, "%s incompatible with previous return of type %s",
ToString(type).get(), ToString(f.returnedType()).get());
ToString(type, nullptr).get(),
ToString(f.returnedType(), nullptr).get());
}

return true;
Expand Down Expand Up @@ -6274,7 +6281,7 @@ static bool CheckFuncPtrTable(ModuleValidator<Unit>& m, ParseNode* decl) {
elem, "function-pointer table's elements must be names of functions");
}

const FuncType& funcSig = m.env().types->funcType(func->sigIndex());
const FuncType& funcSig = m.env().types->type(func->sigIndex()).funcType();
if (sig) {
if (*sig != funcSig) {
return m.fail(elem, "all functions in table must have same signature");
Expand Down
109 changes: 15 additions & 94 deletions js/src/wasm/WasmBinary.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,9 @@ class Encoder {
[[nodiscard]] bool writeVarS64(int64_t i) { return writeVarS<int64_t>(i); }
[[nodiscard]] bool writeValType(ValType type) {
static_assert(size_t(TypeCode::Limit) <= UINT8_MAX, "fits");
if (type.isTypeIndex()) {
return writeFixedU8(uint8_t(TypeCode::NullableRef)) &&
writeVarU32(type.refType().typeIndex());
}
// writeValType is only used by asm.js, which doesn't use type
// references
MOZ_RELEASE_ASSERT(!type.isTypeRef(), "NYI");
TypeCode tc = type.packed().typeCode();
MOZ_ASSERT(size_t(tc) < size_t(TypeCode::Limit));
return writeFixedU8(uint8_t(tc));
Expand Down Expand Up @@ -492,39 +491,25 @@ class Decoder {

// Value and reference types

[[nodiscard]] ValType uncheckedReadValType();
template <class T>
[[nodiscard]] bool readPackedType(uint32_t numTypes,
const FeatureArgs& features, T* type);
[[nodiscard]] ValType uncheckedReadValType(const TypeContext& types);

template <class T>
[[nodiscard]] bool readPackedType(const TypeContext& types,
const FeatureArgs& features, T* type);

[[nodiscard]] bool readValType(uint32_t numTypes, const FeatureArgs& features,
ValType* type);
[[nodiscard]] bool readValType(const TypeContext& types,
const FeatureArgs& features, ValType* type);

[[nodiscard]] bool readFieldType(uint32_t numTypes,
const FeatureArgs& features,
FieldType* type);
[[nodiscard]] bool readFieldType(const TypeContext& types,
const FeatureArgs& features,
FieldType* type);

[[nodiscard]] bool readHeapType(uint32_t numTypes,
const FeatureArgs& features, bool nullable,
RefType* type);
[[nodiscard]] bool readHeapType(const TypeContext& types,
const FeatureArgs& features, bool nullable,
RefType* type);
[[nodiscard]] bool readRefType(uint32_t numTypes, const FeatureArgs& features,
RefType* type);

[[nodiscard]] bool readRefType(const TypeContext& types,
const FeatureArgs& features, RefType* type);
[[nodiscard]] bool validateTypeIndex(const TypeContext& types,
const FeatureArgs& features,
RefType type);

// Instruction opcode

Expand All @@ -545,7 +530,6 @@ class Decoder {
#endif
[[nodiscard]] bool readRefNull(const TypeContext& types,
const FeatureArgs& features, RefType* type);
[[nodiscard]] bool readRefNull(const FeatureArgs& features, RefType* type);

// See writeBytes comment.

Expand Down Expand Up @@ -647,7 +631,7 @@ class Decoder {

// Value and reference types

inline ValType Decoder::uncheckedReadValType() {
inline ValType Decoder::uncheckedReadValType(const TypeContext& types) {
uint8_t code = uncheckedReadFixedU8();
switch (code) {
case uint8_t(TypeCode::FuncRef):
Expand All @@ -666,15 +650,16 @@ inline ValType Decoder::uncheckedReadValType() {
}

int32_t x = uncheckedReadVarS32();
return RefType::fromTypeIndex(x, nullable);
const TypeDef* typeDef = &types.type(x);
return RefType::fromTypeDef(typeDef, nullable);
}
default:
return ValType::fromNonRefTypeCode(TypeCode(code));
}
}

template <class T>
inline bool Decoder::readPackedType(uint32_t numTypes,
inline bool Decoder::readPackedType(const TypeContext& types,
const FeatureArgs& features, T* type) {
static_assert(uint8_t(TypeCode::Limit) <= UINT8_MAX, "fits");
uint8_t code;
Expand Down Expand Up @@ -706,7 +691,7 @@ inline bool Decoder::readPackedType(uint32_t numTypes,
}
bool nullable = code == uint8_t(TypeCode::NullableRef);
RefType refType;
if (!readHeapType(numTypes, features, nullable, &refType)) {
if (!readHeapType(types, features, nullable, &refType)) {
return false;
}
*type = refType;
Expand Down Expand Up @@ -736,40 +721,19 @@ inline bool Decoder::readPackedType(uint32_t numTypes,
}
return fail("bad type");
}
template <class T>
inline bool Decoder::readPackedType(const TypeContext& types,
const FeatureArgs& features, T* type) {
if (!readPackedType(types.length(), features, type)) {
return false;
}
if (type->isTypeIndex() &&
!validateTypeIndex(types, features, type->refType())) {
return false;
}
return true;
}

inline bool Decoder::readValType(uint32_t numTypes, const FeatureArgs& features,
ValType* type) {
return readPackedType<ValType>(numTypes, features, type);
}
inline bool Decoder::readValType(const TypeContext& types,
const FeatureArgs& features, ValType* type) {
return readPackedType<ValType>(types, features, type);
}

inline bool Decoder::readFieldType(uint32_t numTypes,
const FeatureArgs& features,
FieldType* type) {
return readPackedType<FieldType>(numTypes, features, type);
}
inline bool Decoder::readFieldType(const TypeContext& types,
const FeatureArgs& features,
FieldType* type) {
return readPackedType<FieldType>(types, features, type);
}

inline bool Decoder::readHeapType(uint32_t numTypes,
inline bool Decoder::readHeapType(const TypeContext& types,
const FeatureArgs& features, bool nullable,
RefType* type) {
uint8_t nextByte;
Expand Down Expand Up @@ -804,40 +768,18 @@ inline bool Decoder::readHeapType(uint32_t numTypes,
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
if (features.functionReferences) {
int32_t x;
if (!readVarS32(&x) || x < 0 || uint32_t(x) >= numTypes ||
if (!readVarS32(&x) || x < 0 || uint32_t(x) >= types.length() ||
uint32_t(x) >= MaxTypeIndex) {
return fail("invalid heap type index");
}
*type = RefType::fromTypeIndex(x, nullable);
const TypeDef* typeDef = &types.type(x);
*type = RefType::fromTypeDef(typeDef, nullable);
return true;
}
#endif
return fail("invalid heap type");
}
inline bool Decoder::readHeapType(const TypeContext& types,
const FeatureArgs& features, bool nullable,
RefType* type) {
if (!readHeapType(types.length(), features, nullable, type)) {
return false;
}

if (type->isTypeIndex() && !validateTypeIndex(types, features, *type)) {
return false;
}
return true;
}
inline bool Decoder::readRefType(uint32_t numTypes, const FeatureArgs& features,
RefType* type) {
ValType valType;
if (!readValType(numTypes, features, &valType)) {
return false;
}
if (!valType.isRefType()) {
return fail("bad type");
}
*type = valType.refType();
return true;
}
inline bool Decoder::readRefType(const TypeContext& types,
const FeatureArgs& features, RefType* type) {
ValType valType;
Expand All @@ -850,23 +792,6 @@ inline bool Decoder::readRefType(const TypeContext& types,
*type = valType.refType();
return true;
}
inline bool Decoder::validateTypeIndex(const TypeContext& types,
const FeatureArgs& features,
RefType type) {
MOZ_ASSERT(type.isTypeIndex());

if (features.gc && (types[type.typeIndex()].isStructType() ||
types[type.typeIndex()].isArrayType())) {
return true;
}
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
if (features.functionReferences && types[type.typeIndex()].isFuncType()) {
return true;
}
#endif

return fail("type index references an invalid type");
}

// Instruction opcode

Expand Down Expand Up @@ -948,10 +873,6 @@ inline bool Decoder::readRefNull(const TypeContext& types,
return readHeapType(types, features, true, type);
}

inline bool Decoder::readRefNull(const FeatureArgs& features, RefType* type) {
return readHeapType(MaxTypes, features, true, type);
}

} // namespace wasm
} // namespace js

Expand Down
2 changes: 1 addition & 1 deletion js/src/wasm/WasmBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ static int32_t CoerceInPlace_JitEntry(int funcExportIndex, Instance* instance,
break;
case RefType::Func:
case RefType::Eq:
case RefType::TypeIndex:
case RefType::TypeRef:
// Guarded against by temporarilyUnsupportedReftypeForEntry()
MOZ_CRASH("unexpected input argument in CoerceInPlace_JitEntry");
}
Expand Down
2 changes: 1 addition & 1 deletion js/src/wasm/WasmCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ void LazyStubTier::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code,
}

size_t Metadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const {
return SizeOfVectorExcludingThis(types, mallocSizeOf) +
return types->sizeOfExcludingThis(mallocSizeOf) +
globals.sizeOfExcludingThis(mallocSizeOf) +
tables.sizeOfExcludingThis(mallocSizeOf) +
tags.sizeOfExcludingThis(mallocSizeOf) +
Expand Down
8 changes: 4 additions & 4 deletions js/src/wasm/WasmCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ WASM_DECLARE_CACHEABLE_POD(MetadataCacheablePod)
using ModuleHash = uint8_t[8];

struct Metadata : public ShareableBase<Metadata>, public MetadataCacheablePod {
TypeDefVector types;
SharedTypeContext types;
uint32_t typeIdsOffsetStart;
GlobalDescVector globals;
TableDescVector tables;
Expand Down Expand Up @@ -407,16 +407,16 @@ struct Metadata : public ShareableBase<Metadata>, public MetadataCacheablePod {
}

const FuncType& getFuncImportType(const FuncImport& funcImport) const {
return types[funcImport.typeIndex()].funcType();
return types->type(funcImport.typeIndex()).funcType();
}
const FuncType& getFuncExportType(const FuncExport& funcExport) const {
return types[funcExport.typeIndex()].funcType();
return types->type(funcExport.typeIndex()).funcType();
}

size_t debugNumFuncs() const { return debugFuncTypeIndices.length(); }
const FuncType& debugFuncType(uint32_t funcIndex) const {
MOZ_ASSERT(debugEnabled);
return types[debugFuncTypeIndices[funcIndex]].funcType();
return types->type(debugFuncTypeIndices[funcIndex]).funcType();
}

// AsmJSMetadata derives Metadata iff isAsmJS(). Mostly this distinction is
Expand Down
4 changes: 2 additions & 2 deletions js/src/wasm/WasmConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ static constexpr TypeCode LowestPrimitiveTypeCode = TypeCode::I16;

static constexpr TypeCode AbstractReferenceTypeCode = TypeCode::ExternRef;

// A type code used to represent (ref null? typeindex) whether or not the type
// A type code used to represent (ref null? T) whether or not the type
// is encoded with 'Ref' or 'NullableRef'.

static constexpr TypeCode AbstractReferenceTypeIndexCode = TypeCode::Ref;
static constexpr TypeCode AbstractTypeRefCode = TypeCode::Ref;

// A wasm::Trap represents a wasm-defined trap that can occur during execution
// which triggers a WebAssembly.RuntimeError. Generated code may jump to a Trap
Expand Down
3 changes: 2 additions & 1 deletion js/src/wasm/WasmDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ void DebugState::ensureEnterFrameTrapsState(JSContext* cx, Instance* instance,
bool DebugState::debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals,
size_t* argsLength,
StackResults* stackResults) {
const TypeContext& types = *metadata().types;
const FuncType& funcType = metadata().debugFuncType(funcIndex);
const ValTypeVector& args = funcType.args();
const ValTypeVector& results = funcType.results();
Expand All @@ -392,7 +393,7 @@ bool DebugState::debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals,
Decoder d(bytecode().begin() + offsetInModule, bytecode().end(),
offsetInModule,
/* error = */ nullptr);
return DecodeValidatedLocalEntries(d, locals);
return DecodeValidatedLocalEntries(types, d, locals);
}

bool DebugState::getGlobal(Instance& instance, uint32_t globalIndex,
Expand Down
Loading

0 comments on commit f4d3b34

Please sign in to comment.