Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/clusterfuzz/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
'--disable-strings',
'--disable-stack-switching',
'--disable-relaxed-atomics',
'--disable-multibyte',
]


Expand Down
3 changes: 3 additions & 0 deletions src/binaryen-c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,9 @@ BinaryenFeatures BinaryenFeatureCallIndirectOverlong(void) {
BinaryenFeatures BinaryenFeatureRelaxedAtomics(void) {
return static_cast<BinaryenFeatures>(FeatureSet::RelaxedAtomics);
}
BinaryenFeatures BinaryenFeatureMultibyte(void) {
return static_cast<BinaryenFeatures>(FeatureSet::Multibyte);
}
BinaryenFeatures BinaryenFeatureCustomPageSizes(void) {
return static_cast<BinaryenFeatures>(FeatureSet::CustomPageSizes);
}
Expand Down
1 change: 1 addition & 0 deletions src/binaryen-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ BINARYEN_API BinaryenFeatures BinaryenFeatureFP16(void);
BINARYEN_API BinaryenFeatures BinaryenFeatureBulkMemoryOpt(void);
BINARYEN_API BinaryenFeatures BinaryenFeatureCallIndirectOverlong(void);
BINARYEN_API BinaryenFeatures BinaryenFeatureRelaxedAtomics(void);
BINARYEN_API BinaryenFeatures BinaryenFeatureMultibyte(void);
BINARYEN_API BinaryenFeatures BinaryenFeatureCustomPageSizes(void);
BINARYEN_API BinaryenFeatures BinaryenFeatureAll(void);

Expand Down
1 change: 1 addition & 0 deletions src/interpreter/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ struct ExpressionInterpreter : OverriddenVisitor<ExpressionInterpreter, Flow> {
Flow visitArrayNewFixed(ArrayNewFixed* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayGet(ArrayGet* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArraySet(ArraySet* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayStore(ArrayStore* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayLen(ArrayLen* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayCopy(ArrayCopy* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayFill(ArrayFill* curr) { WASM_UNREACHABLE("TODO"); }
Expand Down
1 change: 1 addition & 0 deletions src/ir/ReFinalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ void ReFinalize::visitArrayNewElem(ArrayNewElem* curr) { curr->finalize(); }
void ReFinalize::visitArrayNewFixed(ArrayNewFixed* curr) { curr->finalize(); }
void ReFinalize::visitArrayGet(ArrayGet* curr) { curr->finalize(); }
void ReFinalize::visitArraySet(ArraySet* curr) { curr->finalize(); }
void ReFinalize::visitArrayStore(ArrayStore* curr) { curr->finalize(); }
void ReFinalize::visitArrayLen(ArrayLen* curr) { curr->finalize(); }
void ReFinalize::visitArrayCopy(ArrayCopy* curr) { curr->finalize(); }
void ReFinalize::visitArrayFill(ArrayFill* curr) { curr->finalize(); }
Expand Down
15 changes: 15 additions & 0 deletions src/ir/child-typer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,21 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
note(&curr->value, type);
}

void visitArrayStore(ArrayStore* curr,
std::optional<HeapType> ht = std::nullopt,
std::optional<Type> valueType = std::nullopt) {
if (!ht) {
if (!curr->ref->type.isRef()) {
self().noteUnknown();
return;
}
ht = curr->ref->type.getHeapType();
}
note(&curr->ref, Type(*ht, Nullable));
note(&curr->index, Type::i32);
note(&curr->value, valueType ? *valueType : curr->value->type);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should self().noteUnknown() if curr->value->type == Type::unreachable.

}

void visitArrayLen(ArrayLen* curr) {
note(&curr->ref, Type(HeapType::array, Nullable));
}
Expand Down
4 changes: 4 additions & 0 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
return 2 + nullCheckCost(curr->ref) + visit(curr->ref) +
visit(curr->index) + visit(curr->value);
}
CostType visitArrayStore(ArrayStore* curr) {
return 2 + nullCheckCost(curr->ref) + visit(curr->ref) +
visit(curr->index) + visit(curr->value);
}
CostType visitArrayLen(ArrayLen* curr) {
return 1 + nullCheckCost(curr->ref) + visit(curr->ref);
}
Expand Down
9 changes: 9 additions & 0 deletions src/ir/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,15 @@ class EffectAnalyzer {
parent.isAtomic |=
curr->isAtomic() && curr->ref->type.getHeapType().isShared();
}
void visitArrayStore(ArrayStore* curr) {
if (curr->ref->type.isNull()) {
parent.trap = true;
return;
}
parent.writesArray = true;
// traps when the arg is null or the index out of bounds
parent.implicitTrap = true;
}
void visitArrayLen(ArrayLen* curr) {
if (curr->ref->type.isNull()) {
parent.trap = true;
Expand Down
8 changes: 8 additions & 0 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,13 @@ struct InfoCollector
addChildParentLink(curr->ref, curr);
addChildParentLink(curr->value, curr);
}
void visitArrayStore(ArrayStore* curr) {
if (curr->ref->type == Type::unreachable) {
return;
}
addChildParentLink(curr->ref, curr);
addChildParentLink(curr->value, curr);
}

void visitArrayLen(ArrayLen* curr) {
// TODO: optimize when possible (perhaps we can infer a Literal for the
Expand Down Expand Up @@ -1742,6 +1749,7 @@ void TNHOracle::scan(Function* func,
}
void visitArrayGet(ArrayGet* curr) { notePossibleTrap(curr->ref); }
void visitArraySet(ArraySet* curr) { notePossibleTrap(curr->ref); }
void visitArrayStore(ArrayStore* curr) { notePossibleTrap(curr->ref); }
void visitArrayLen(ArrayLen* curr) { notePossibleTrap(curr->ref); }
void visitArrayCopy(ArrayCopy* curr) {
notePossibleTrap(curr->srcRef);
Expand Down
1 change: 1 addition & 0 deletions src/ir/subtype-exprs.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
auto array = curr->ref->type.getHeapType().getArray();
self()->noteSubtype(curr->value, array.element.type);
}
void visitArrayStore(ArrayStore* curr) {}
void visitArrayLen(ArrayLen* curr) {}
void visitArrayCopy(ArrayCopy* curr) {
if (!curr->srcRef->type.isArray() || !curr->destRef->type.isArray()) {
Expand Down
13 changes: 13 additions & 0 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,11 @@ struct NullInstrParserCtx {
MemoryOrder) {
return Ok{};
}
template<typename HeapTypeT>
Result<>
makeArrayStore(Index, const std::vector<Annotation>&, Type, int, HeapTypeT) {
return Ok{};
}
Result<> makeAtomicRMW(Index,
const std::vector<Annotation>&,
AtomicRMWOp,
Expand Down Expand Up @@ -2326,6 +2331,14 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx>, AnnotationParserCtx {
pos, irBuilder.makeStore(bytes, memarg.offset, memarg.align, type, *m));
}

Result<> makeArrayStore(Index pos,
const std::vector<Annotation>& annotations,
Type type,
int bytes,
HeapTypeT arrayType) {
return withLoc(pos, irBuilder.makeArrayStore(arrayType, bytes, type));
}

Result<> makeAtomicRMW(Index pos,
const std::vector<Annotation>& annotations,
AtomicRMWOp op,
Expand Down
10 changes: 10 additions & 0 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -1818,6 +1818,16 @@ Result<> makeStore(Ctx& ctx,
Type type,
int bytes,
bool isAtomic) {
if (ctx.in.takeSExprStart("type"sv)) {
auto arrayType = typeidx(ctx);
CHECK_ERR(arrayType);

if (!ctx.in.takeRParen()) {
return ctx.in.err("expected end of type use");
}

return ctx.makeArrayStore(pos, annotations, type, bytes, *arrayType);
}
auto mem = maybeMemidx(ctx);
CHECK_ERR(mem);

Expand Down
47 changes: 32 additions & 15 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,25 @@ struct PrintExpressionContents
return parent.printBlockType(sig);
}

std::ostream& printStorePostfix(uint8_t bytes, Type valueType) {
if (bytes < 4 || (valueType == Type::i64 && bytes < 8)) {
if (bytes == 1) {
o << '8';
} else if (bytes == 2) {
if (valueType == Type::f32) {
o << "_f16";
} else {
o << "16";
}
} else if (bytes == 4) {
o << "32";
} else {
abort();
}
}
return o;
}

void visitBlock(Block* curr) {
printMedium(o, "block");
if (curr->name.is()) {
Expand Down Expand Up @@ -589,21 +608,7 @@ struct PrintExpressionContents
o << ".atomic";
}
o << ".store";
if (curr->bytes < 4 || (curr->valueType == Type::i64 && curr->bytes < 8)) {
if (curr->bytes == 1) {
o << '8';
} else if (curr->bytes == 2) {
if (curr->valueType == Type::f32) {
o << "_f16";
} else {
o << "16";
}
} else if (curr->bytes == 4) {
o << "32";
} else {
abort();
}
}
printStorePostfix(curr->bytes, curr->valueType);
restoreNormalColor(o);
printMemoryName(curr->memory, o, wasm);
printMemoryOrder(curr->order);
Expand Down Expand Up @@ -2477,6 +2482,18 @@ struct PrintExpressionContents
o << ' ';
printHeapTypeName(curr->ref->type.getHeapType());
}
void visitArrayStore(ArrayStore* curr) {
prepareColor(o) << forceConcrete(curr->value->type);
o << ".store";
printStorePostfix(curr->bytes, curr->value->type);
o << " ";
restoreNormalColor(o);

o << '(';
printMinor(o, "type ");
printHeapTypeName(curr->ref->type.getHeapType());
o << ')';
}
void visitArrayLen(ArrayLen* curr) { printMedium(o, "array.len"); }
void visitArrayCopy(ArrayCopy* curr) {
printMedium(o, "array.copy ");
Expand Down
2 changes: 2 additions & 0 deletions src/passes/TypeGeneralizing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,8 @@ struct TransferFn : OverriddenVisitor<TransferFn> {
}
}

void visitArrayStore(ArrayStore* curr) { WASM_UNREACHABLE("TODO"); }

void visitArrayLen(ArrayLen* curr) {
// The input must be an array.
push(Type(HeapType::array, Nullable));
Expand Down
1 change: 1 addition & 0 deletions src/tools/tool-options.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ struct ToolOptions : public Options {
.addFeature(FeatureSet::FP16, "float 16 operations")
.addFeature(FeatureSet::CustomDescriptors,
"custom descriptors (RTTs) and exact references")
.addFeature(FeatureSet::Multibyte, "multibyte array loads and stores")
.addFeature(FeatureSet::RelaxedAtomics,
"acquire/release atomic memory operations")
.addFeature(FeatureSet::CustomPageSizes, "custom page sizes")
Expand Down
13 changes: 11 additions & 2 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ enum {
MaxLEB32Bytes = 5,
};

enum class BackingType {
Memory,
Array,
};

template<typename T, typename MiniT> struct LEB {
static_assert(sizeof(MiniT) == 1, "MiniT must be a byte");

Expand Down Expand Up @@ -359,6 +364,7 @@ enum BrOnCastFlag {

constexpr uint32_t ExactImport = 1 << 5;

constexpr uint32_t HasBackingArrayMask = 1 << 4;
constexpr uint32_t HasMemoryOrderMask = 1 << 5;
constexpr uint32_t HasMemoryIndexMask = 1 << 6;

Expand Down Expand Up @@ -463,6 +469,7 @@ extern const char* BulkMemoryOptFeature;
extern const char* CallIndirectOverlongFeature;
extern const char* CustomDescriptorsFeature;
extern const char* RelaxedAtomicsFeature;
extern const char* MultibyteFeature;
extern const char* CustomPageSizesFeature;

enum Subsection {
Expand Down Expand Up @@ -1709,6 +1716,8 @@ class WasmBinaryReader {

void readExports();

Result<> readStore(unsigned bytes, Type type);

// The strings in the strings section (which are referred to by StringConst).
std::vector<Name> strings;
void readStrings();
Expand Down Expand Up @@ -1756,11 +1765,11 @@ class WasmBinaryReader {
void readJSCalledHints(size_t payloadLen);
void readIdempotentHints(size_t payloadLen);

std::tuple<Address, Address, Index, MemoryOrder>
std::tuple<Address, Address, Index, MemoryOrder, BackingType>
readMemoryAccess(bool isAtomic, bool isRMW);
std::tuple<Name, Address, Address, MemoryOrder> getAtomicMemarg();
std::tuple<Name, Address, Address, MemoryOrder> getRMWMemarg();
std::tuple<Name, Address, Address> getMemarg();
std::tuple<Name, Address, Address, BackingType> getMemarg();
MemoryOrder getMemoryOrder(bool isRMW = false);

[[noreturn]] void throwError(std::string text) {
Expand Down
12 changes: 12 additions & 0 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,18 @@ class Builder {
ret->finalize();
return ret;
}
ArrayStore* makeArrayStore(unsigned bytes,
Expression* ref,
Expression* index,
Expression* value) {
auto* ret = wasm.allocator.alloc<ArrayStore>();
ret->bytes = bytes;
ret->ref = ref;
ret->index = index;
ret->value = value;
ret->finalize();
return ret;
}
ArrayLen* makeArrayLen(Expression* ref) {
auto* ret = wasm.allocator.alloc<ArrayLen>();
ret->ref = ref;
Expand Down
7 changes: 7 additions & 0 deletions src/wasm-delegations-fields.def
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,13 @@ DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(ArraySet, ref)
DELEGATE_FIELD_INT(ArraySet, order)
DELEGATE_FIELD_CASE_END(ArraySet)

DELEGATE_FIELD_CASE_START(ArrayStore)
DELEGATE_FIELD_CHILD(ArrayStore, value)
DELEGATE_FIELD_CHILD(ArrayStore, index)
DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(ArrayStore, ref)
DELEGATE_FIELD_INT(ArrayStore, bytes)
DELEGATE_FIELD_CASE_END(ArrayStore)

DELEGATE_FIELD_CASE_START(ArrayLen)
DELEGATE_FIELD_CHILD(ArrayLen, ref)
DELEGATE_FIELD_CASE_END(ArrayLen)
Expand Down
1 change: 1 addition & 0 deletions src/wasm-delegations.def
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ DELEGATE(ArrayNewElem);
DELEGATE(ArrayNewFixed);
DELEGATE(ArrayGet);
DELEGATE(ArraySet);
DELEGATE(ArrayStore);
DELEGATE(ArrayLen);
DELEGATE(ArrayCopy);
DELEGATE(ArrayFill);
Expand Down
7 changes: 6 additions & 1 deletion src/wasm-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ struct FeatureSet {
CustomDescriptors = 1 << 21,
RelaxedAtomics = 1 << 22,
CustomPageSizes = 1 << 23,
Multibyte = 1 << 24,
MVP = None,
// Keep in sync with llvm default features:
// https://github.com/llvm/llvm-project/blob/c7576cb89d6c95f03968076e902d3adfd1996577/clang/lib/Basic/Targets/WebAssembly.cpp#L150-L153
Default = SignExt | MutableGlobals,
All = (1 << 24) - 1,
All = (1 << 25) - 1,
};

static std::string toString(Feature f) {
Expand Down Expand Up @@ -114,6 +115,8 @@ struct FeatureSet {
return "relaxed-atomics";
case CustomPageSizes:
return "custom-page-sizes";
case Multibyte:
return "multibyte";
case MVP:
case Default:
case All:
Expand Down Expand Up @@ -176,6 +179,7 @@ struct FeatureSet {
}
bool hasRelaxedAtomics() const { return (features & RelaxedAtomics) != 0; }
bool hasCustomPageSizes() const { return (features & CustomPageSizes) != 0; }
bool hasMultibyte() const { return (features & Multibyte) != 0; }
bool hasAll() const { return (features & All) != 0; }

void set(FeatureSet f, bool v = true) {
Expand Down Expand Up @@ -203,6 +207,7 @@ struct FeatureSet {
void setBulkMemoryOpt(bool v = true) { set(BulkMemoryOpt, v); }
void setCustomDescriptors(bool v = true) { set(CustomDescriptors, v); }
void setRelaxedAtomics(bool v = true) { set(RelaxedAtomics, v); }
void setMultibyte(bool v = true) { set(Multibyte, v); }
void setMVP() { features = MVP; }
void setAll() { features = All; }

Expand Down
Loading
Loading