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

Implement operations on typed values #293

Merged
merged 2 commits into from
May 7, 2018
Merged

Conversation

philipc
Copy link
Collaborator

@philipc philipc commented Apr 25, 2018

A couple of things of note:

  • parsing the DIEs and maintaining a hash of base types is the user's responsibility, but we may want to add more to help with this.
  • the evaluation requests base types from the user via EvaluationResult::RequiresBaseType. Even though this probably isn't something that will need a Future, I chose this because it avoids adding a type parameter to Evaluation for a closure or trait.

I used @tromey's work as a starting point, but the implementation has significantly changed. I'm now using an enum for the value, instead of a struct with type and value members. The reason for this is I think it makes it easier to get the operations correct in some cases. For example, I think that division for unsigned base types should be an unsigned division (I think the requirement for signed division in the standard only applies to the generic type). One drawback of this approach is that the reinterpret operation is ugly, and I'm open to ideas on how to simplify that. @tromey Can you please take a quick look at this approach and let me know if you see any design problems with it?

@coveralls
Copy link

coveralls commented Apr 25, 2018

Coverage Status

Coverage increased (+0.2%) to 92.63% when pulling 56aa5b4 on philipc:op-types into f177b94 on gimli-rs:master.

@tromey
Copy link
Member

tromey commented Apr 25, 2018

This seems reasonable to me.

@philipc philipc force-pushed the op-types branch 2 times, most recently from 43a7b83 to 2dabeb0 Compare April 28, 2018 07:26
@philipc philipc changed the title [WIP] Implement operations on typed values Implement operations on typed values Apr 28, 2018
@philipc
Copy link
Collaborator Author

philipc commented Apr 28, 2018

This is ready for review now.

@philipc philipc requested a review from fitzgen May 5, 2018 04:55
Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

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

I think this is a really nice clean up! I have a few thoughts inline below, but its mostly just speculation.

Thanks for this nice PR @philipc :)

src/value.rs Outdated
pub enum ValueType {
/// The generic type, which is address-sized and of unspecified sign.
/// This type is also used to represent address base types.
Generic,
Copy link
Member

Choose a reason for hiding this comment

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

Maybe point to 2.5.1. in dwarf5 here as well?

///
/// The `ValueType` of `self` must be integral.
/// Values are sign extended if the source value is signed.
pub fn to_u64(self, addr_mask: u64) -> Result<u64> {
Copy link
Member

Choose a reason for hiding this comment

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

We should file a follow up issue to implement TryFrom<Value> for u64 in a month and a half, when it hits stable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think that allows the addr_mask parameter.

/// The `value_type` may be integral or floating point.
/// The result is truncated if the `u64` value does
/// not fit the bounds of the `value_type`.
pub fn from_u64(value_type: ValueType, value: u64) -> Result<Value> {
Copy link
Member

Choose a reason for hiding this comment

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

And also TryFrom<u64> for Value

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

And here we also need the value_type parameter. I guess you could implement TryFrom<(ValueType, u64)>, but I think the function call is clearer.

/// The `value_type` may be integral or floating point.
/// The result is not defined if the `f64` value does
/// not fit the bounds of the `value_type`.
fn from_f64(value_type: ValueType, value: f64) -> Result<Value> {
Copy link
Member

Choose a reason for hiding this comment

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

And I guess all of these variants.

(Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_add(v2)),
(Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_add(v2)),
(Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_add(v2)),
(Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_add(v2)),
Copy link
Member

Choose a reason for hiding this comment

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

I feel like all these operation implementations could use a macro or something to reduce boilerplate.

Copy link
Collaborator 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 of this: philipc@d0b80cf?

Copy link
Member

Choose a reason for hiding this comment

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

Looks nice!

(Value::I64(v1), Value::I64(v2)) => v1 >= v2,
(Value::U64(v1), Value::U64(v2)) => v1 >= v2,
(Value::F32(v1), Value::F32(v2)) => v1 >= v2,
(Value::F64(v1), Value::F64(v2)) => v1 >= v2,
Copy link
Member

Choose a reason for hiding this comment

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

Thinking about it a little more, something like this could be useful:

enum SameTypeValues {
    Generic(u64, u64),
    I8(i8, i8),
    U8(u8, u8),
    I16(i16, i16),
    U16(u16, u16),
    I32(i32, i32),
    U32(u32, u32),
    I64(i64, i64),
    U64(u64, u64),
    F32(f32, f32),
    F64(f64, f64),
}

impl SameTypeValues {
    fn try_from(a: Value, b: Value) -> Result<SameTypeValues> {
        match (a, b) {
            (Generic(x), Generic(y)) => Ok(SameTypeValues::Generic(x, y)),
            (I8(x), I8(y)) => Ok(SameTypeValues::I8(x, y)),
            (U8(x), U8(y)) => Ok(SameTypeValues::U8(x, y)),
            (I16(x), I16(y)) => Ok(SameTypeValues::I16(x, y)),
            (U16(x), U16(y)) => Ok(SameTypeValues::U16(x, y)),
            (I32(x), I32(y)) => Ok(SameTypeValues::I32(x, y)),
            (U32(x), U32(y)) => Ok(SameTypeValues::U32(x, y)),
            (I64(x), I64(y)) => Ok(SameTypeValues::I64(x, y)),
            (U64(x), U64(y)) => Ok(SameTypeValues::U64(x, y)),
            (F32(x), F32(y)) => Ok(SameTypeValues::F32(x, y)),
            (F64(x), F64(y)) => Ok(SameTypeValues::F64(x, y)),
            _ => Err(Error::UnsupportedTypeOperation),
        }
    }
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The users of SameTypeValues would still have to match on just as many cases though?

@philipc philipc merged commit 54dd5a3 into gimli-rs:master May 7, 2018
@philipc philipc deleted the op-types branch May 7, 2018 08:25
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.

4 participants