Help Trying to understand the bytecode generated for equals$extension

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Help Trying to understand the bytecode generated for equals$extension

Nuno Seco
Hello. Quite new to Scala (couple of days).

I am going through Martin Odersky's book trying to learn the basics in order to start using it professionally.

In trying to understand the difference between AnyRef and AnyVal I started looking at the code generated when an Int is wrapped in a subclass of each.

For the AnyVal example I have:
class TestAnyVal(val e: Int) extends AnyVal {
}

The code generated for equals method in the companion object of my class generated the following:

public final boolean equals$extension(int, java.lang.Object);
    descriptor: (ILjava/lang/Object;)Z
    flags: ACC_PUBLIC, ACC_FINAL
    Code:
      stack=2, locals=6, args_size=3
         0: aload_2
         1: astore_3
         2: aload_3
         3: instanceof    #31                 // class Chapter11/TestAnyVal
         6: ifeq          15
         9: iconst_1
        10: istore        4
        12: goto          18
        15: iconst_0
        16: istore        4
        18: iload         4
        20: ifeq          50
        23: aload_2
        24: checkcast     #31                 // class Chapter11/TestAnyVal
        27: invokevirtual #34                 // Method Chapter11/TestAnyVal.e:()I
        30: istore        5
        32: iload_1
        33: iload         5
        35: if_icmpne     42
        38: iconst_1
        39: goto          43
        42: iconst_0
        43: ifeq          50
        46: iconst_1
        47: goto          51
        50: iconst_0
        51: ireturn
         (....)



My question:
Aren't lines 0,1,2 in the above bytecode redundant? In other words if lines 1,2 were omitted wouldn't the result be the same? 

--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Help Trying to understand the bytecode generated for equals$extension

Lukas Rytz-2
Hi

This is an artefact of how code generation for pattern matching is implemented. For example

class C {
  def e(a: Any) = a match {
    case c: C => this eq c
  }
}

also generates bytecode that uses redundant local variables. This is mostly a cosmetic issue, the JVM is good at optimizing this kind of redundancies. But yes, ideally Scala would not unnecessarily use locals.

In 2.12, you can use `-opt:l:method` to improve the bytecode, it implements copy propagation.




On Tue, Nov 29, 2016 at 7:40 PM, Nuno Seco <[hidden email]> wrote:
Hello. Quite new to Scala (couple of days).

I am going through Martin Odersky's book trying to learn the basics in order to start using it professionally.

In trying to understand the difference between AnyRef and AnyVal I started looking at the code generated when an Int is wrapped in a subclass of each.

For the AnyVal example I have:
class TestAnyVal(val e: Int) extends AnyVal {
}

The code generated for equals method in the companion object of my class generated the following:

public final boolean equals$extension(int, java.lang.Object);
    descriptor: (ILjava/lang/Object;)Z
    flags: ACC_PUBLIC, ACC_FINAL
    Code:
      stack=2, locals=6, args_size=3
         0: aload_2
         1: astore_3
         2: aload_3
         3: instanceof    #31                 // class Chapter11/TestAnyVal
         6: ifeq          15
         9: iconst_1
        10: istore        4
        12: goto          18
        15: iconst_0
        16: istore        4
        18: iload         4
        20: ifeq          50
        23: aload_2
        24: checkcast     #31                 // class Chapter11/TestAnyVal
        27: invokevirtual #34                 // Method Chapter11/TestAnyVal.e:()I
        30: istore        5
        32: iload_1
        33: iload         5
        35: if_icmpne     42
        38: iconst_1
        39: goto          43
        42: iconst_0
        43: ifeq          50
        46: iconst_1
        47: goto          51
        50: iconst_0
        51: ireturn
         (....)



My question:
Aren't lines 0,1,2 in the above bytecode redundant? In other words if lines 1,2 were omitted wouldn't the result be the same? 

--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Help Trying to understand the bytecode generated for equals$extension

Iulian Dragos

Lukas’ answer is of course correct. Note that you can still get that optimization with 2.11 (or 2.10 for that matter), using -optimize:

public final boolean equals$extension(int, java.lang.Object);
    Code:
       0: aload_2
       1: instanceof    #31                 // class TestAnyVal
       4: ifeq          12
       7: iconst_1
       8: istore_3
       9: goto          14
      12: iconst_0
      13: istore_3
      14: iload_3
      15: ifeq          45
      18: aload_2
      19: checkcast     #31                 // class TestAnyVal
      22: invokevirtual #34                 // Method TestAnyVal.e:()I
      25: istore        4
      27: iload_1
      28: iload         4
      30: if_icmpne     37
      33: iconst_1
      34: goto          38
      37: iconst_0
      38: ifeq          45
      41: iconst_1
      42: goto          46
      45: iconst_0
      46: ireturn

On Tue, Nov 29, 2016 at 11:52 PM, Lukas Rytz <[hidden email]> wrote:
Hi

This is an artefact of how code generation for pattern matching is implemented. For example

class C {
  def e(a: Any) = a match {
    case c: C => this eq c
  }
}

also generates bytecode that uses redundant local variables. This is mostly a cosmetic issue, the JVM is good at optimizing this kind of redundancies. But yes, ideally Scala would not unnecessarily use locals.

In 2.12, you can use `-opt:l:method` to improve the bytecode, it implements copy propagation.




On Tue, Nov 29, 2016 at 7:40 PM, Nuno Seco <[hidden email]> wrote:
Hello. Quite new to Scala (couple of days).

I am going through Martin Odersky's book trying to learn the basics in order to start using it professionally.

In trying to understand the difference between AnyRef and AnyVal I started looking at the code generated when an Int is wrapped in a subclass of each.

For the AnyVal example I have:
class TestAnyVal(val e: Int) extends AnyVal {
}

The code generated for equals method in the companion object of my class generated the following:

public final boolean equals$extension(int, java.lang.Object);
    descriptor: (ILjava/lang/Object;)Z
    flags: ACC_PUBLIC, ACC_FINAL
    Code:
      stack=2, locals=6, args_size=3
         0: aload_2
         1: astore_3
         2: aload_3
         3: instanceof    #31                 // class Chapter11/TestAnyVal
         6: ifeq          15
         9: iconst_1
        10: istore        4
        12: goto          18
        15: iconst_0
        16: istore        4
        18: iload         4
        20: ifeq          50
        23: aload_2
        24: checkcast     #31                 // class Chapter11/TestAnyVal
        27: invokevirtual #34                 // Method Chapter11/TestAnyVal.e:()I
        30: istore        5
        32: iload_1
        33: iload         5
        35: if_icmpne     42
        38: iconst_1
        39: goto          43
        42: iconst_0
        43: ifeq          50
        46: iconst_1
        47: goto          51
        50: iconst_0
        51: ireturn
         (....)



My question:
Aren't lines 0,1,2 in the above bytecode redundant? In other words if lines 1,2 were omitted wouldn't the result be the same? 

--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--
« Je déteste la montagne, ça cache le paysage »
Alphonse Allais

--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.