scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

Val type doesn't seem to be specialized properly #5490

Open scabug opened 12 years ago

scabug commented 12 years ago

This issue was noticed in #5005. Basically, the problem here is that the typer runs before specialize, so the type of a val is never a specific specialized subclass. This means that all method calls on a specialized instance stored in a val end up using the unspecialized code instead. Here's an example that Vlad cooked up which shows the issue:

class C[@specialized(Int) A](val a:A) {
  @inline final def get:A = a
}

class B {
  // needs to be final, otherwise the most you can infer for c is C[Int]
  //(someone else might override it and not return C$mcI$sp)
  final val c = new C(13) 

  // not getting inlined, inter-procedural TFA necessary
  def runIndirect: Int = c.get

  // not getting inlined, but TFA should infer C$mcI@sp for the stack slot
  def runLocal: Int = {
    val cc = new C(13)
    cc.get
  }

  // getting inlined
  def runDirect:Int = new C(13).get
}

Looking at the bytecode, you'll notice that runDirect correctly calls (and inlines) C$mcI$sp.get$mcI$sp call, whereas runIndirect and runLocal both call C.get$mcI$sp, which cannot be final and thus is not inlined. Furthermore, even though the "c" val is defined as being a C[Int], the generated accessor method returns a C, not a C$mcI$sp.

Vlad thinks that type-flow analysis (TFA) might able to "fix" this in the case of local vals (or final vals which can't be overridden).

scabug commented 12 years ago

Imported From: https://issues.scala-lang.org/browse/SI-5490?orig=1 Reporter: @non See #5005

scabug commented 12 years ago

@magarciaEPFL said (edited on Jul 11, 2012 4:47:56 PM UTC): See if the fix for #6035 ( https://github.com/scala/scala/pull/872 ) helps with this bug.

scabug commented 12 years ago

@non said (edited on Jul 11, 2012 6:32:12 PM UTC): I merged Aleksandar's commit but unfortunately it doesn't fix either of these cases:

runDirect() is correctly getting inlining:


   0:   new     #28; //class C$mcI$sp
   3:   dup
   4:   bipush  13
   6:   invokespecial   #32; //Method C$mcI$sp."<init>":(I)V
   9:   invokevirtual   #37; //Method C$mcI$sp.a:()I
   12:  ireturn

But runLocal() still is not:


   0:   new     #28; //class C$mcI$sp
   3:   dup
   4:   bipush  13
   6:   invokespecial   #32; //Method C$mcI$sp."<init>":(I)V
   9:   astore_1
   10:  aload_1
   11:  invokevirtual   #25; //Method C.get$mcI$sp:()I
   14:  ireturn

Neither is runIndirect(); also, c's accessor and field are not being specialized:


   0:   aload_0
   1:   invokevirtual   #20; //Method c:()LC;
   4:   invokevirtual   #25; //Method C.get$mcI$sp:()I
   7:   ireturn
scabug commented 12 years ago

@magarciaEPFL said: Another suggestion (but this one might work) is trying the fixes in https://github.com/scala/scala/pull/887

scabug commented 12 years ago

@non said: I just tried the 2.10.x branch (which has pull request 887 merged) and still see the issue.