Skip to content

[GC] Fix parsing/printing of ref types using i31#3469

Merged
kripken merged 31 commits intomasterfrom
i31etc
Jan 7, 2021
Merged

[GC] Fix parsing/printing of ref types using i31#3469
kripken merged 31 commits intomasterfrom
i31etc

Conversation

@kripken
Copy link
Member

@kripken kripken commented Jan 7, 2021

This lets us parse (ref null i31) and (ref i31) and not just i31ref.

It also fixes the parsing of i31ref, making it nullable for now, which we
need to do until we support non-nullability.

Fix some internal handling of i31 where we had just i31ref (which meant we
just handled the non-nullable type).

After fixing a bug in printing (where we didn't print out (ref null i31)
properly), I found some a simplification, to remove TypeName.

@kripken kripken requested review from aheejin and tlively January 7, 2021 00:55
@kripken kripken changed the title Fix parsing/printing of ref types using i31 [GC] Fix parsing/printing of ref types using i31 Jan 7, 2021
Comment on lines +1419 to +1420
// FIXME: for now, force all inputs to be nullable
return Type(HeapType::BasicHeapType::i31, Nullable);
Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't it be simple to just assume Type::i31ref is nullable and return Type::i31ref here, and later fix Type::i31ref itself? This way it looks internally Type::i31ref is still non-nullable but when we parse i31ref we treat it as something other than i31ref which is nullable.

The same for the similar usages in wasm-s-parser.cpp and wasm-validator.cpp.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure this would be any simpler because all the other code needs to be prepared to deal with either (ref null i31) or (ref i31). Which version is considered "Basic" because it has the Type::i31ref shorthand should really only matter for printing, unless I'm missing something.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it is slightly simpler in the current approach, since this is more consistent with our other behavior, which is to turn all inputs immediately into nullable types. It's true that it looks a little more awkward here, since it's no longer "basic", but it is still applying that simple rule.

default:
WASM_UNREACHABLE("unknown basic type");
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Is there any case in which t.isRef() and we don't enable FeatureSet::ReferenceTypes? If it is always enabled for any reference types, can we enable it by default for t.isRef() and only additionally handle GC related stuff?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, good point. I pushed a commit with that simplification now.


static std::ostream& operator<<(std::ostream& o, const SExprType& localType) {
Type type = localType.type;
static std::ostream& operator<<(std::ostream& o, const SExprType& sType) {
Copy link
Member

Choose a reason for hiding this comment

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

I'm not very sure what is this method exactly for anymore.. It seems it was added in #2675 to support multivalue printing for local types without commas, like (i32 i64), but it has since grown and its name also changed from LocalType to SExprType... Can you help me on when we just use printType and when we use this method?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry, yes, it is a little confusing. I've added comments in this PR which might help. But probably we should rename things too.

  • printTypeName prints a "serialized" name, as a list of characters. It has no spaces, in particular. We use this to emit a name for any type, no matter what it contains. Say an array contains (ref eq) then we'd print some serialization of that into [ref_eq] or such.
  • SExprType prints out a type in normal s-format. For (ref eq) it would be exactly that (with spaces etc.). But that can recursively call printTypeName for the sub-types that it is declared from, when it needs their "serialized" name.

Copy link
Member

Choose a reason for hiding this comment

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

It would be good to standardize on either using printXXX functions or using wrapper structs with bespoke operator<< implementations, but I don't think that needs to happen here. (I prefer the latter fwiw.)

Comment on lines +603 to +605
auto leftHeap = left.getHeapType();
if ((leftHeap == HeapType::i31 || leftHeap.isArray() ||
leftHeap.isStruct()) &&
Copy link
Member

Choose a reason for hiding this comment

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

I assume eqref is short for (ref null eq) and that there is also a (ref eq). In that case this code probably should compare with rightHeap == HeapType::eq rather than with right == Type::eqref. It will have to handle differing nullability between left and right as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, yes. Pushed a fix now.

Comment on lines +603 to +604
rightHeap == HeapType::eq &&
(!left.isNullable() || right.isNullable())) {
Copy link
Member

Choose a reason for hiding this comment

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

Just noticed that the right == Type::funcref check below should probably be changed in the same way.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch, fixed.

@kripken kripken merged commit 6a35e33 into master Jan 7, 2021
@kripken kripken deleted the i31etc branch January 7, 2021 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants