summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp2
-rw-r--r--src/literal.h17
-rw-r--r--src/wasm-interpreter.h10
-rw-r--r--src/wasm/literal.cpp60
4 files changed, 66 insertions, 23 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 6beb2b97c..4fbd4cfa0 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -81,8 +81,8 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
case HeapType::i31:
WASM_UNREACHABLE("TODO: i31");
case HeapType::ext:
- case HeapType::any:
WASM_UNREACHABLE("TODO: extern literals");
+ case HeapType::any:
case HeapType::eq:
case HeapType::func:
case HeapType::struct_:
diff --git a/src/literal.h b/src/literal.h
index 9d7ac2222..b484fc3b8 100644
--- a/src/literal.h
+++ b/src/literal.h
@@ -45,17 +45,17 @@ class Literal {
uint8_t v128[16];
// funcref function name. `isNull()` indicates a `null` value.
Name func;
- // A reference to GC data, either a Struct or an Array. For both of those
- // we store the referred data as a Literals object (which is natural for an
+ // A reference to GC data, either a Struct or an Array. For both of those we
+ // store the referred data as a Literals object (which is natural for an
// Array, and for a Struct, is just the fields in order). The type is used
// to indicate whether this is a Struct or an Array, and of what type. We
// also use this to store String data, as it is similarly stored on the
- // heap.
+ // heap. For externrefs, the gcData is the same as for the corresponding
+ // internal references and the values are only differentiated by the type.
+ // Externalized i31 references have a gcData containing the internal i31
+ // reference as its sole value even though internal i31 references do not
+ // have a gcData.
std::shared_ptr<GCData> gcData;
- // TODO: Literals of type `anyref` can only be `null` currently but we
- // will need to represent external values eventually, to
- // 1) run the spec tests and fuzzer with reference types enabled and
- // 2) avoid bailing out when seeing a reference typed value in precompute
};
public:
@@ -665,6 +665,9 @@ public:
Literal relaxedFmaF64x2(const Literal& left, const Literal& right) const;
Literal relaxedFmsF64x2(const Literal& left, const Literal& right) const;
+ Literal externalize() const;
+ Literal internalize() const;
+
private:
Literal addSatSI8(const Literal& other) const;
Literal addSatUI8(const Literal& other) const;
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index afc193f71..75f2a8338 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1785,16 +1785,16 @@ public:
}
const auto& value = flow.getSingleValue();
NOTE_EVAL1(value);
- if (value.isNull()) {
- trap("null ref");
- }
switch (curr->op) {
case RefAsNonNull:
- // We've already checked for a null.
+ if (value.isNull()) {
+ trap("null ref");
+ }
return value;
case ExternInternalize:
+ return value.internalize();
case ExternExternalize:
- WASM_UNREACHABLE("unimplemented extern conversion");
+ return value.externalize();
}
WASM_UNREACHABLE("unimplemented ref.as_*");
}
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index 2a7dd1bcf..230eeae66 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -70,10 +70,11 @@ Literal::Literal(const uint8_t init[16]) : type(Type::v128) {
}
Literal::Literal(std::shared_ptr<GCData> gcData, HeapType type)
- : gcData(gcData), type(type, NonNullable) {
+ : gcData(gcData), type(type, gcData ? NonNullable : Nullable) {
// The type must be a proper type for GC data: either a struct, array, or
- // string; or a null.
- assert((isData() && gcData) || (type.isBottom() && !gcData));
+ // string; or an externalized version of the same; or a null.
+ assert((isData() && gcData) || (type == HeapType::ext && gcData) ||
+ (type.isBottom() && !gcData));
}
Literal::Literal(std::string string)
@@ -110,7 +111,7 @@ Literal::Literal(const Literal& other) : type(other.type) {
new (&gcData) std::shared_ptr<GCData>();
return;
}
- if (other.isData()) {
+ if (other.isData() || other.type.getHeapType() == HeapType::ext) {
new (&gcData) std::shared_ptr<GCData>(other.gcData);
return;
}
@@ -126,14 +127,14 @@ Literal::Literal(const Literal& other) : type(other.type) {
case HeapType::i31:
i32 = other.i32;
return;
+ case HeapType::ext:
+ gcData = other.gcData;
+ return;
case HeapType::none:
case HeapType::noext:
case HeapType::nofunc:
- // Null
- return;
- case HeapType::ext:
+ WASM_UNREACHABLE("null literals should already have been handled");
case HeapType::any:
- WASM_UNREACHABLE("TODO: extern literals");
case HeapType::eq:
case HeapType::func:
case HeapType::struct_:
@@ -154,7 +155,7 @@ Literal::~Literal() {
if (type.isBasic()) {
return;
}
- if (isNull() || isData()) {
+ if (isNull() || isData() || type.getHeapType() == HeapType::ext) {
gcData.~shared_ptr();
}
}
@@ -584,8 +585,9 @@ std::ostream& operator<<(std::ostream& o, Literal literal) {
o << "nullfuncref";
break;
case HeapType::ext:
+ o << "externref";
+ break;
case HeapType::any:
- WASM_UNREACHABLE("TODO: extern literals");
case HeapType::eq:
case HeapType::func:
case HeapType::struct_:
@@ -2590,4 +2592,42 @@ Literal Literal::relaxedFmsF64x2(const Literal& left,
return ternary<2, &Literal::getLanesF64x2, &Literal::fms>(*this, left, right);
}
+Literal Literal::externalize() const {
+ assert(Type::isSubType(type, Type(HeapType::any, Nullable)) &&
+ "can only externalize internal references");
+ if (isNull()) {
+ return Literal(std::shared_ptr<GCData>{}, HeapType::noext);
+ }
+ auto heapType = type.getHeapType();
+ if (heapType.isBasic()) {
+ switch (heapType.getBasic()) {
+ case HeapType::i31: {
+ return Literal(std::make_shared<GCData>(HeapType::i31, Literals{*this}),
+ HeapType::ext);
+ }
+ case HeapType::string:
+ case HeapType::stringview_wtf8:
+ case HeapType::stringview_wtf16:
+ case HeapType::stringview_iter:
+ WASM_UNREACHABLE("TODO: string literals");
+ default:
+ WASM_UNREACHABLE("unexpected type");
+ }
+ }
+ return Literal(gcData, HeapType::ext);
+}
+
+Literal Literal::internalize() const {
+ assert(Type::isSubType(type, Type(HeapType::ext, Nullable)) &&
+ "can only internalize external references");
+ if (isNull()) {
+ return Literal(std::shared_ptr<GCData>{}, HeapType::none);
+ }
+ if (gcData->type == HeapType::i31) {
+ assert(gcData->values[0].type.getHeapType() == HeapType::i31);
+ return gcData->values[0];
+ }
+ return Literal(gcData, gcData->type);
+}
+
} // namespace wasm