Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make local.tee's type its local's type #2511

Merged
merged 13 commits into from Dec 13, 2019

Conversation

aheejin
Copy link
Member

@aheejin aheejin commented Dec 6, 2019

According to the current spec, local.tee's return type should be the
same as its local's type. (Discussions on whether we should change this
rule is going on in WebAssembly/reference-types#55, but here I will
assume this spec does not change. If this changes, we should change many
parts of Binaryen transformation anyway...)

But currently in Binaryen local.tee's type is computed from its
value's type. This didn't make any difference in the MVP, but after we
have subtype relationship in #2451, this can become a problem. For
example:

(func $test (result funcref) (local $0 anyref)
  (local.tee $0
    (ref.func $test)
  )
)

This shouldn't validate in the spec, but this will pass Binaryen
validation with the current local.tee implementation.

This makes local.tee's type computed from the local's type, and makes
LocalSet::makeTee get a type parameter, to which we should pass the
its corresponding local's type. We don't embed the local type in the
class LocalSet because it may increase memory size.

This also fixes the type of local.get to be the local type where
local.get and local.set pair is created from local.tee.

According to the current spec, `local.tee`'s return type should be the
same as its local's type. (Discussions on whether we should change this
rule is going on in WebAssembly/reference-types#55, but here I will
assume this spec does not change. If this changes, we should change many
parts of Binaryen transformation anyway...)

But currently in Binaryen `local.tee`'s type is computed from its
value's type. This didn't make any difference in the MVP, but after we
have subtype relationship in WebAssembly#2451, this can become a problem. For
example:
```
(func $test (result funcref) (local $0 anyref)
  (local.tee $0
    (ref.func $test)
  )
)
```
This shouldn't validate in the spec, but this will pass Binaryen
validation with the current `local.tee` implementation.

This makes `local.tee`'s type computed from the local's type, and makes
`LocalSet::makeTee` get a type parameter, to which we should pass the
its corresponding local's type. We don't embed the local type in the
class `LocalSet` because it may increase memory size.

This also fixes the type of `local.get` to be the local type where
`local.get` and `local.set` pair is created from `local.tee`.
src/wasm/wasm-validator.cpp Outdated Show resolved Hide resolved
src/wasm-builder.h Outdated Show resolved Hide resolved
@kripken
Copy link
Member

kripken commented Dec 6, 2019

I'm a little worried about changes in the spec, though, let's discuss that before landing this.

'tee': function(index, value) {
return Module['_BinaryenLocalTee'](module, index, value);
'tee': function(index, value, type) {
return Module['_BinaryenLocalTee'](module, index, value, type);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make it so that if type is not specified, the type of value is used - to make this backwards compatible?

Copy link
Member Author

Choose a reason for hiding this comment

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

That would only work in non-reference types. The purpose of this change is to prevent to use the value type for local.tee's type in the first place because of subtypes... Wouldn't that be easy to be used incorrectly?

Copy link
Contributor

@dcodeIO dcodeIO Dec 8, 2019

Choose a reason for hiding this comment

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

Mostly thinking in terms of existing projects that don't use reference types yet, where having to change every single local.tee might be quite some work for no immediate benefit. Perhaps only make if backwards compatible for i32, i64, f32, f64?

Copy link
Member Author

@aheejin aheejin Dec 10, 2019

Choose a reason for hiding this comment

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

I am still inclined to change the signature to be consistent; making the old signature only work for old number types seems a little unnatural and also adds checking overhead to every local.tee call. I don't know how high the cost of changing existing code will be, but doesn't all existing code have to undergo significant changes after #2510 lands anyway..? WDYT? cc @kripken

Copy link
Member

Choose a reason for hiding this comment

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

I would like to make the change as less confusing as possible for people with existing code. It seems like they would not provide the parameter, so it would be coerced from undefined to 0, which is none. Then they'd get a validation error later, which might not be that obvious?

Automatically converting the 0 to the proper type is one option, silently - IIUC @dcodeIO that's what you suggest?

Another option is to give an immediate error, if (type === undefined) throw Error('tee() must receive the type as a fourth parameter (this was an API change));` perhaps? A benefit to doing it that way is people will know to update their code, so it won't keep using the old API forever.

Copy link
Member Author

@aheejin aheejin Dec 10, 2019

Choose a reason for hiding this comment

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

What do you mean by

Automatically converting the 0 to the proper type is one option

?

Copy link
Member

Choose a reason for hiding this comment

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

I meant what @dcodeIO said, at least as I understood it:

Can we make it so that if type is not specified, the type of value is used - to make this backwards compatible?

If type is not provided, use the type of the value instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

What do you think @dcodeIO? I like the idea of requiring type parameter in all local.tee, and explicitly error out if type is undefined. Allowing untyped API only for the number types doesn't seem to be very consistent. Can we land this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, go ahead :). Should be fine with other breaking changes already landed.

Co-Authored-By: Thomas Lively <7121787+tlively@users.noreply.github.com>
@aheejin
Copy link
Member Author

aheejin commented Dec 8, 2019

I'm a little worried about changes in the spec, though, let's discuss that before landing this.

Which part of the spec do you mean? The local.tee spec? (I don't think it has changed in any way yet) Or binaryen.js API?

'tee': function(index, value) {
return Module['_BinaryenLocalTee'](module, index, value);
'tee': function(index, value, type) {
return Module['_BinaryenLocalTee'](module, index, 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.

I would like to make the change as less confusing as possible for people with existing code. It seems like they would not provide the parameter, so it would be coerced from undefined to 0, which is none. Then they'd get a validation error later, which might not be that obvious?

Automatically converting the 0 to the proper type is one option, silently - IIUC @dcodeIO that's what you suggest?

Another option is to give an immediate error, if (type === undefined) throw Error('tee() must receive the type as a fourth parameter (this was an API change));` perhaps? A benefit to doing it that way is people will know to update their code, so it won't keep using the old API forever.

@aheejin aheejin merged commit 89d1cf9 into WebAssembly:master Dec 13, 2019
@aheejin aheejin deleted the local_tee_type branch December 13, 2019 02:36
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.

None yet

4 participants