Skip to content

Commit

Permalink
Bug 1754260 - Move wasm intrinsic operations from 0xFA prefix. r=rhunt
Browse files Browse the repository at this point in the history
  • Loading branch information
yurydelendik committed Feb 23, 2022
1 parent be058f2 commit 4241043
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 75 deletions.
4 changes: 2 additions & 2 deletions js/src/builtin/TestingFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2031,9 +2031,9 @@ static bool WasmIntrinsicI8VecMul(JSContext* cx, unsigned argc, Value* vp) {

CallArgs args = CallArgsFromVp(argc, vp);

wasm::IntrinsicOp ops[] = {wasm::IntrinsicOp::I8VecMul};
wasm::IntrinsicId ids[] = {wasm::IntrinsicId::I8VecMul};
RootedWasmModuleObject module(cx);
if (!wasm::CompileIntrinsicModule(cx, ops, wasm::Shareable::False, &module)) {
if (!wasm::CompileIntrinsicModule(cx, ids, wasm::Shareable::False, &module)) {
return false;
}
args.rval().set(ObjectValue(*module.get()));
Expand Down
2 changes: 1 addition & 1 deletion js/src/wasm/WasmBCClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -1579,7 +1579,7 @@ struct BaseCompiler final {
# endif
#endif

[[nodiscard]] bool emitIntrinsic(IntrinsicOp op);
[[nodiscard]] bool emitIntrinsic();
};

} // namespace wasm
Expand Down
21 changes: 9 additions & 12 deletions js/src/wasm/WasmBaselineCompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7789,12 +7789,12 @@ bool BaseCompiler::emitVectorLaneSelect() {
//
// "Intrinsics" - magically imported functions for internal use.

bool BaseCompiler::emitIntrinsic(IntrinsicOp op) {
bool BaseCompiler::emitIntrinsic() {
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
const Intrinsic& intrinsic = Intrinsic::getFromOp(op);
const Intrinsic* intrinsic;

BaseNothingVector params;
if (!iter_.readIntrinsic(intrinsic, &params)) {
if (!iter_.readIntrinsic(&intrinsic, &params)) {
return false;
}

Expand All @@ -7806,7 +7806,7 @@ bool BaseCompiler::emitIntrinsic(IntrinsicOp op) {
pushHeapBase();

// Call the intrinsic
return emitInstanceCall(lineOrBytecode, intrinsic.signature);
return emitInstanceCall(lineOrBytecode, intrinsic->signature);
}

//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -9554,16 +9554,13 @@ bool BaseCompiler::emitBody() {
}

// asm.js and other private operations
case uint16_t(Op::MozPrefix):
return iter_.unrecognizedOpcode(&op);

// private intrinsic operations
case uint16_t(Op::IntrinsicPrefix): {
if (!moduleEnv_.intrinsicsEnabled() ||
op.b1 >= uint32_t(IntrinsicOp::Limit)) {
case uint16_t(Op::MozPrefix): {
if (op.b1 != uint32_t(MozOp::Intrinsic) ||
!moduleEnv_.intrinsicsEnabled()) {
return iter_.unrecognizedOpcode(&op);
}
CHECK_NEXT(emitIntrinsic(IntrinsicOp(op.b1)));
// private intrinsic operations
CHECK_NEXT(emitIntrinsic());
}

default:
Expand Down
5 changes: 0 additions & 5 deletions js/src/wasm/WasmBinary.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,6 @@ class Opcode {
static_assert(size_t(SimdOp::Limit) <= 0xFFFFFF, "fits");
MOZ_ASSERT(size_t(op) < size_t(SimdOp::Limit));
}
MOZ_IMPLICIT Opcode(IntrinsicOp op)
: bits_((uint32_t(op) << 8) | uint32_t(Op::IntrinsicPrefix)) {
static_assert(size_t(IntrinsicOp::Limit) <= 0xFFFFFF, "fits");
MOZ_ASSERT(size_t(op) < size_t(IntrinsicOp::Limit));
}

bool isOp() const { return bits_ < uint32_t(Op::FirstPrefix); }
bool isMisc() const { return (bits_ & 255) == uint32_t(Op::MiscPrefix); }
Expand Down
14 changes: 9 additions & 5 deletions js/src/wasm/WasmConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,6 @@ enum class Op {
RefEq = 0xd5,

FirstPrefix = 0xfa,
IntrinsicPrefix = 0xfa,
GcPrefix = 0xfb,
MiscPrefix = 0xfc,
SimdPrefix = 0xfd,
Expand Down Expand Up @@ -940,11 +939,12 @@ enum class ThreadOp {
Limit
};

enum class IntrinsicOp {
enum class IntrinsicId {
// ------------------------------------------------------------------------
// These operators are emitted internally when compiling intrinsic modules
// and are rejected by wasm validation. They are prefixed by
// IntrinsicPrefix. See wasm/WasmIntrinsic.yaml for the list.
// These are part/suffix of the MozOp::Intrinsic operators that are emitted
// internally when compiling intrinsic modules and are rejected by wasm
// validation.
// See wasm/WasmIntrinsic.yaml for the list.
#define DECL_INTRINSIC_OP(op, export, sa_name, abitype, entry, idx) \
op = idx, // NOLINT
FOR_EACH_INTRINSIC(DECL_INTRINSIC_OP)
Expand Down Expand Up @@ -994,6 +994,10 @@ enum class MozOp {
OldCallDirect,
OldCallIndirect,

// Intrinsic modules operations. The operator has argument leb u32 to specify
// particular operation id. See IntrinsicId above.
Intrinsic,

Limit
};

Expand Down
39 changes: 21 additions & 18 deletions js/src/wasm/WasmIntrinsic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ bool Intrinsic::funcType(FuncType* type) const {
}

/* static */
const Intrinsic& Intrinsic::getFromOp(IntrinsicOp op) {
switch (op) {
const Intrinsic& Intrinsic::getFromId(IntrinsicId id) {
switch (id) {
#define OP(op, export, sa_name, abitype, entry, idx) \
case IntrinsicOp::op: \
case IntrinsicId::op: \
return Intrinsic##op;
FOR_EACH_INTRINSIC(OP)
#undef OP
Expand All @@ -66,7 +66,7 @@ const Intrinsic& Intrinsic::getFromOp(IntrinsicOp op) {
}
}

bool EncodeIntrinsicBody(const Intrinsic& intrinsic, IntrinsicOp op,
bool EncodeIntrinsicBody(const Intrinsic& intrinsic, IntrinsicId id,
Bytes* body) {
Encoder encoder(*body);
if (!EncodeLocalEntries(encoder, ValTypeVector())) {
Expand All @@ -77,7 +77,10 @@ bool EncodeIntrinsicBody(const Intrinsic& intrinsic, IntrinsicOp op,
return false;
}
}
if (!encoder.writeOp(op)) {
if (!encoder.writeOp(MozOp::Intrinsic)) {
return false;
}
if (!encoder.writeVarU32(uint32_t(id))) {
return false;
}
if (!encoder.writeOp(Op::End)) {
Expand All @@ -87,7 +90,7 @@ bool EncodeIntrinsicBody(const Intrinsic& intrinsic, IntrinsicOp op,
}

bool wasm::CompileIntrinsicModule(JSContext* cx,
const mozilla::Span<IntrinsicOp> ops,
const mozilla::Span<IntrinsicId> ids,
Shareable sharedMemory,
MutableHandleWasmModuleObject result) {
// Create the options manually, enabling intrinsics
Expand Down Expand Up @@ -121,15 +124,15 @@ bool wasm::CompileIntrinsicModule(JSContext* cx,
moduleEnv.memory = Some(MemoryDesc(Limits(0, Nothing(), sharedMemory)));

// Initialize the type section
if (!moduleEnv.initTypes(ops.size())) {
if (!moduleEnv.initTypes(ids.size())) {
return false;
}

// Add (type (func (params ...))) for each intrinsic. The function types will
// be deduplicated by the runtime
for (uint32_t funcIndex = 0; funcIndex < ops.size(); funcIndex++) {
const IntrinsicOp& op = ops[funcIndex];
const Intrinsic& intrinsic = Intrinsic::getFromOp(op);
for (uint32_t funcIndex = 0; funcIndex < ids.size(); funcIndex++) {
const IntrinsicId& id = ids[funcIndex];
const Intrinsic& intrinsic = Intrinsic::getFromId(id);

FuncType type;
if (!intrinsic.funcType(&type)) {
Expand All @@ -142,7 +145,7 @@ bool wasm::CompileIntrinsicModule(JSContext* cx,
// Add (func (type $i)) declarations. Do this after all types have been added
// as the function declaration metadata uses pointers into the type vectors
// that must be stable.
for (uint32_t funcIndex = 0; funcIndex < ops.size(); funcIndex++) {
for (uint32_t funcIndex = 0; funcIndex < ids.size(); funcIndex++) {
FuncDesc decl(&(*moduleEnv.types)[funcIndex].funcType(),
&moduleEnv.typeIds[funcIndex], funcIndex);
if (!moduleEnv.funcs.append(decl)) {
Expand All @@ -153,8 +156,8 @@ bool wasm::CompileIntrinsicModule(JSContext* cx,
}

// Add (export "$name" (func $i)) declarations.
for (uint32_t funcIndex = 0; funcIndex < ops.size(); funcIndex++) {
const Intrinsic& intrinsic = Intrinsic::getFromOp(ops[funcIndex]);
for (uint32_t funcIndex = 0; funcIndex < ids.size(); funcIndex++) {
const Intrinsic& intrinsic = Intrinsic::getFromId(ids[funcIndex]);

UniqueChars exportString = DuplicateString(intrinsic.exportName);
if (!exportString ||
Expand All @@ -176,13 +179,13 @@ bool wasm::CompileIntrinsicModule(JSContext* cx,

// Prepare and compile function bodies
Vector<Bytes, 1, SystemAllocPolicy> bodies;
if (!bodies.reserve(ops.size())) {
if (!bodies.reserve(ids.size())) {
ReportOutOfMemory(cx);
return false;
}
for (uint32_t funcIndex = 0; funcIndex < ops.size(); funcIndex++) {
IntrinsicOp op = ops[funcIndex];
const Intrinsic& intrinsic = Intrinsic::getFromOp(ops[funcIndex]);
for (uint32_t funcIndex = 0; funcIndex < ids.size(); funcIndex++) {
IntrinsicId id = ids[funcIndex];
const Intrinsic& intrinsic = Intrinsic::getFromId(ids[funcIndex]);

// Compilation may be done using other threads, ModuleGenerator requires
// that function bodies live until after finishFuncDefs().
Expand All @@ -191,7 +194,7 @@ bool wasm::CompileIntrinsicModule(JSContext* cx,

// Encode function body that will call the intrinsic using our builtin
// opcode, and launch a compile task
if (!EncodeIntrinsicBody(intrinsic, op, &bytecode) ||
if (!EncodeIntrinsicBody(intrinsic, id, &bytecode) ||
!mg.compileFuncDef(funcIndex, 0, bytecode.begin(),
bytecode.begin() + bytecode.length())) {
// This must be an OOM and will be reported by the caller
Expand Down
8 changes: 4 additions & 4 deletions js/src/wasm/WasmIntrinsic.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ struct Intrinsic {
// Allocate a FuncType for this intrinsic, returning false for OOM
bool funcType(FuncType* type) const;

// Get the Intrinsic for an IntrinsicOp. IntrinsicOp must be validated.
static const Intrinsic& getFromOp(IntrinsicOp op);
// Get the Intrinsic for an IntrinsicId. IntrinsicId must be validated.
static const Intrinsic& getFromId(IntrinsicId id);
};

// Compile and return the intrinsic module for a given set of intrinsic ops.
bool CompileIntrinsicModule(JSContext* cx, const mozilla::Span<IntrinsicOp> ops,
// Compile and return the intrinsic module for a given set of operations.
bool CompileIntrinsicModule(JSContext* cx, const mozilla::Span<IntrinsicId> ids,
Shareable sharedMemory,
MutableHandleWasmModuleObject result);

Expand Down
27 changes: 13 additions & 14 deletions js/src/wasm/WasmIonCompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5857,23 +5857,23 @@ static bool EmitStoreLaneSimd128(FunctionCompiler& f, uint32_t laneSize) {

#endif

static bool EmitIntrinsic(FunctionCompiler& f, IntrinsicOp op) {
const Intrinsic& intrinsic = Intrinsic::getFromOp(op);
static bool EmitIntrinsic(FunctionCompiler& f) {
const Intrinsic* intrinsic;

DefVector params;
if (!f.iter().readIntrinsic(intrinsic, &params)) {
if (!f.iter().readIntrinsic(&intrinsic, &params)) {
return false;
}

uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
const SymbolicAddressSignature& callee = intrinsic.signature;
const SymbolicAddressSignature& callee = intrinsic->signature;

CallCompileState args;
if (!f.passInstance(callee.argTypes[0], &args)) {
return false;
}

if (!f.passArgs(params, intrinsic.params, &args)) {
if (!f.passArgs(params, intrinsic->params, &args)) {
return false;
}

Expand Down Expand Up @@ -6385,15 +6385,7 @@ static bool EmitBodyExprs(FunctionCompiler& f) {
case uint16_t(Op::I64Extend32S):
CHECK(EmitSignExtend(f, 4, 8));

case uint16_t(Op::IntrinsicPrefix): {
if (!f.moduleEnv().intrinsicsEnabled() ||
op.b1 >= uint32_t(IntrinsicOp::Limit)) {
return f.iter().unrecognizedOpcode(&op);
}
CHECK(EmitIntrinsic(f, IntrinsicOp(op.b1)));
}

// Gc operations
// Gc operations
#ifdef ENABLE_WASM_GC
case uint16_t(Op::GcPrefix): {
return f.iter().unrecognizedOpcode(&op);
Expand Down Expand Up @@ -6975,6 +6967,13 @@ static bool EmitBodyExprs(FunctionCompiler& f) {

// asm.js-specific operators
case uint16_t(Op::MozPrefix): {
if (op.b1 == uint32_t(MozOp::Intrinsic)) {
if (!f.moduleEnv().intrinsicsEnabled()) {
return f.iter().unrecognizedOpcode(&op);
}
CHECK(EmitIntrinsic(f));
}

if (!f.moduleEnv().isAsmJS()) {
return f.iter().unrecognizedOpcode(&op);
}
Expand Down
18 changes: 9 additions & 9 deletions js/src/wasm/WasmJS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5327,15 +5327,15 @@ static bool WebAssembly_mozIntGemm(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);

RootedWasmModuleObject module(cx);
wasm::IntrinsicOp ops[] = {
wasm::IntrinsicOp::I8PrepareB,
wasm::IntrinsicOp::I8PrepareBFromTransposed,
wasm::IntrinsicOp::I8PrepareBFromQuantizedTransposed,
wasm::IntrinsicOp::I8PrepareA,
wasm::IntrinsicOp::I8PrepareBias,
wasm::IntrinsicOp::I8MultiplyAndAddBias,
wasm::IntrinsicOp::I8SelectColumnsOfB};
if (!wasm::CompileIntrinsicModule(cx, ops, Shareable::False, &module)) {
wasm::IntrinsicId ids[] = {
wasm::IntrinsicId::I8PrepareB,
wasm::IntrinsicId::I8PrepareBFromTransposed,
wasm::IntrinsicId::I8PrepareBFromQuantizedTransposed,
wasm::IntrinsicId::I8PrepareA,
wasm::IntrinsicId::I8PrepareBias,
wasm::IntrinsicId::I8MultiplyAndAddBias,
wasm::IntrinsicId::I8SelectColumnsOfB};
if (!wasm::CompileIntrinsicModule(cx, ids, Shareable::False, &module)) {
ReportOutOfMemory(cx);
return false;
}
Expand Down
6 changes: 4 additions & 2 deletions js/src/wasm/WasmOpIter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,6 @@ OpKind wasm::Classify(OpBytes op) {
WASM_FUNCTION_REFERENCES_OP(OpKind::BrOnNull);
case Op::RefEq:
WASM_GC_OP(OpKind::Comparison);
case Op::IntrinsicPrefix:
return OpKind::Intrinsic;
case Op::GcPrefix: {
switch (GcOp(op.b1)) {
case GcOp::Limit:
Expand Down Expand Up @@ -780,9 +778,13 @@ OpKind wasm::Classify(OpBytes op) {
return OpKind::OldCallDirect;
case MozOp::OldCallIndirect:
return OpKind::OldCallIndirect;
case MozOp::Intrinsic:
return OpKind::Intrinsic;
}
break;
}
case Op::FirstPrefix:
break;
}
MOZ_CRASH("unimplemented opcode");
}
Expand Down
18 changes: 15 additions & 3 deletions js/src/wasm/WasmOpIter.h
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ class MOZ_STACK_CLASS OpIter : private Policy {
uint32_t* laneIndex, Value* input);
#endif

[[nodiscard]] bool readIntrinsic(const Intrinsic& intrinsic,
[[nodiscard]] bool readIntrinsic(const Intrinsic** intrinsic,
ValueVector* params);

// At a location where readOp is allowed, peek at the next opcode
Expand Down Expand Up @@ -3471,13 +3471,25 @@ inline bool OpIter<Policy>::readStoreLane(uint32_t byteSize,
#endif // ENABLE_WASM_SIMD

template <typename Policy>
inline bool OpIter<Policy>::readIntrinsic(const Intrinsic& intrinsic,
inline bool OpIter<Policy>::readIntrinsic(const Intrinsic** intrinsic,
ValueVector* params) {
MOZ_ASSERT(Classify(op_) == OpKind::Intrinsic);

uint32_t id;
if (!d_.readVarU32(&id)) {
return false;
}

if (id >= uint32_t(IntrinsicId::Limit)) {
return fail("intrinsic index out of range");
}

*intrinsic = &Intrinsic::getFromId(IntrinsicId(id));

if (!env_.usesMemory()) {
return fail("can't touch memory without memory");
}
return popWithTypes(intrinsic.params, params);
return popWithTypes((*intrinsic)->params, params);
}

} // namespace wasm
Expand Down

0 comments on commit 4241043

Please sign in to comment.