summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-01-14 08:49:19 -0800
committerGitHub <noreply@github.com>2022-01-14 08:49:19 -0800
commit6cb41eca43b8a6045b0138545c6b4fcdfcf4448a (patch)
treef2d3c76265912347a933039056b1ba39c7077954 /src/wasm
parent993ea84f82c2baf6cd4f7d397b5270715d8e0d6c (diff)
downloadbinaryen-6cb41eca43b8a6045b0138545c6b4fcdfcf4448a.tar.gz
binaryen-6cb41eca43b8a6045b0138545c6b4fcdfcf4448a.tar.bz2
binaryen-6cb41eca43b8a6045b0138545c6b4fcdfcf4448a.zip
Optimize Literal constructors and destructor (#4456)
Handle the isBasic() case first - that inlined function is very fast to call, and it is the common case. Also, do not do unnecessary work there: just write out what we need, instead of always doing a memcpy of 16 bytes. This makes us over 2x faster on the benchmark in #4452
Diffstat (limited to 'src/wasm')
-rw-r--r--src/wasm/literal.cpp110
1 files changed, 63 insertions, 47 deletions
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index e761206bc..ea398acd3 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -30,19 +30,41 @@ namespace wasm {
template<int N> using LaneArray = std::array<Literal, N>;
Literal::Literal(Type type) : type(type) {
- if (type == Type::i31ref) {
- // i31ref is special in that it is non-nullable, so we construct with zero
- i32 = 0;
- } else {
- assert(type != Type::unreachable && !type.isNonNullable());
- if (isData()) {
- new (&gcData) std::shared_ptr<GCData>();
- } else if (type.isRtt()) {
- new (this) Literal(Literal::makeCanonicalRtt(type.getHeapType()));
- } else {
- memset(&v128, 0, 16);
+ if (type.isBasic()) {
+ switch (type.getBasic()) {
+ case Type::i32:
+ case Type::f32:
+ i32 = 0;
+ return;
+ case Type::i64:
+ case Type::f64:
+ i64 = 0;
+ return;
+ case Type::v128:
+ memset(&v128, 0, 16);
+ return;
+ case Type::none:
+ return;
+ case Type::unreachable:
+ case Type::funcref:
+ case Type::externref:
+ case Type::anyref:
+ case Type::eqref:
+ case Type::i31ref:
+ case Type::dataref:
+ break;
}
}
+
+ if (isData()) {
+ assert(!type.isNonNullable());
+ new (&gcData) std::shared_ptr<GCData>();
+ } else if (type.isRtt()) {
+ new (this) Literal(Literal::makeCanonicalRtt(type.getHeapType()));
+ } else {
+ // For anything else, zero out all the union data.
+ memset(&v128, 0, 16);
+ }
}
Literal::Literal(const uint8_t init[16]) : type(Type::v128) {
@@ -63,6 +85,31 @@ Literal::Literal(std::unique_ptr<RttSupers>&& rttSupers, Type type)
}
Literal::Literal(const Literal& other) : type(other.type) {
+ if (type.isBasic()) {
+ switch (type.getBasic()) {
+ case Type::i32:
+ case Type::f32:
+ i32 = other.i32;
+ return;
+ case Type::i64:
+ case Type::f64:
+ i64 = other.i64;
+ return;
+ case Type::v128:
+ memcpy(&v128, other.v128, 16);
+ return;
+ case Type::none:
+ return;
+ case Type::unreachable:
+ case Type::funcref:
+ case Type::externref:
+ case Type::anyref:
+ case Type::eqref:
+ case Type::i31ref:
+ case Type::dataref:
+ break;
+ }
+ }
if (other.isData()) {
new (&gcData) std::shared_ptr<GCData>(other.gcData);
return;
@@ -93,49 +140,18 @@ Literal::Literal(const Literal& other) : type(other.type) {
}
}
}
- TODO_SINGLE_COMPOUND(type);
- switch (type.getBasic()) {
- case Type::i32:
- case Type::f32:
- i32 = other.i32;
- break;
- case Type::i64:
- case Type::f64:
- i64 = other.i64;
- break;
- case Type::v128:
- memcpy(&v128, other.v128, 16);
- break;
- case Type::none:
- break;
- case Type::unreachable:
- case Type::funcref:
- case Type::externref:
- case Type::anyref:
- case Type::eqref:
- case Type::i31ref:
- case Type::dataref:
- WASM_UNREACHABLE("invalid type");
- }
}
Literal::~Literal() {
+ // Early exit for the common case; basic types need no special handling.
+ if (type.isBasic()) {
+ return;
+ }
+
if (isData()) {
gcData.~shared_ptr();
} else if (type.isRtt()) {
rttSupers.~unique_ptr();
- } else if (type.isFunction() || type.isRef()) {
- // Nothing special to do for a function or a non-GC reference (GC data was
- // handled earlier). For references, this handles the case of (ref ? i31)
- // for example, which may or may not be basic.
- } else {
- // Basic types need no special handling.
- // TODO: change this to an assert after we figure out the underlying issue
- // on the release builder
- // https://github.com/WebAssembly/binaryen/issues/3459
- if (!type.isBasic()) {
- Fatal() << "~Literal on unhandled type: " << type << '\n';
- }
}
}