-
Notifications
You must be signed in to change notification settings - Fork 21
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
Specialization is broken for class inheriting from specialized traits with separate compilation #6035
Comments
Imported From: https://issues.scala-lang.org/browse/SI-6035?orig=1 |
@gkossakowski said: |
@magarciaEPFL said: However, in that case and also here, a "correct" implementation for that method must be inherited, right? (Otherwise the bytecode verifier would complain). Including the javap of |
@axel22 said (edited on Jul 6, 2012 11:13:44 AM UTC): Paul, since you optimized the specialized flag in pickling previously, can you comment if that is ok, or do you feel that the flag itself should be pickled? |
@gkossakowski said: Compiled from "check.scala"
public abstract class Inter extends java.lang.Object implements Foo$mcI$sp
public int foo$mcI$sp(int);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: iload_1
2: invokestatic #11; //Method Foo$class.foo$mcI$sp:(LFoo;I)I
5: ireturn
Compiled from "check.scala"
public abstract class Foo$class extends java.lang.Object
public static int foo$mcI$sp(Foo, int);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: iload_1
2: invokestatic #12; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
5: invokeinterface #18, 2; //InterfaceMethod Foo.foo:(Ljava/lang/Object;)Ljava/lang/Object;
10: invokestatic #22; //Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
13: ireturn Compiled from "check2.scala"
public class Baz extends Inter
public int foo$mcI$sp(int);
Code:
Stack=2, Locals=2, Args_size=2
0: iload_1
1: iconst_1
2: iadd
3: ireturn as you can see Inter just forward to Foo$class that in turns forwards to abstract, specialized method and takes care of boxing and unboxing. The Baz class overrides specialized implementation and thus avoids boxing. I think this is really what we need. |
@axel22 said: trait Foo[@specialized(AnyRef, Int) A, @specialized(Boolean) B] {
def apply(x: A): B
}
abstract class Inter extends Foo[String, Boolean]
class Baz extends Inter {
def apply(x: String) = false
} The Here's the relevant commit: |
@paulp said:
Right, that's why I wasn't too concerned about putting it in uncurry, which I agree is arbitrary. The phase called "superaccessors" which already is less than completely descriptively named should maybe be renamed - it's the only waystation between typer and pickler, and pickler should stick to pickling. |
@paulp said: private def rawPickledCorrespondence = Array(
(IMPLICIT, IMPLICIT_PKL),
(FINAL, FINAL_PKL),
(PRIVATE, PRIVATE_PKL),
(PROTECTED, PROTECTED_PKL),
(SEALED, SEALED_PKL),
(OVERRIDE, OVERRIDE_PKL),
(CASE, CASE_PKL),
(ABSTRACT, ABSTRACT_PKL),
(DEFERRED, DEFERRED_PKL),
(METHOD, METHOD_PKL),
(MODULE, MODULE_PKL),
(INTERFACE, INTERFACE_PKL)
) |
@paulp said: private final val PKL_MASK = 0x00000FFF |
@paulp said: case EXISTENTIALtpe =>
val restpe = readTypeRef()
// @PP: Where is the flag setting supposed to happen? I infer
// from the lack of flag setting in the rest of the unpickler
// that it isn't right here. See #4757 for the immediate
// motivation to fix it.
val tparams = until(end, readSymbolRef) map (_ setFlag EXISTENTIAL)
newExistentialType(tparams, restpe) |
@paulp said: |
@adriaanm said: |
@gkossakowski said: I'll try to do that. |
@paulp said: |
@gkossakowski said: |
@adriaanm said: |
Let's say we compile code like this:
and we'll inspect methods in
Baz
:Now let's compile the same code in two steps:
using
./bin/scalac -d classes/ check.scala
and then:
using
./bin/scalac -cp classes/ -d classes/ check2.scala
if we then inspect byte of
Baz
we'll see:Notice the difference that there's no public int
foo$mcI$sp(int)
; generated this time. The reason for that is that we do not pickleSPECIALIZED
flag that is set on type parameter symbols. Thus, if we read bytecode for Inter and Foo we'll not haveSPECIALIZED
flag set for parameter A and this will cause specialization to not kick in.Now, the reason why we do not pickle
SPECIALIZED
flag is twofold:SPECIALIZED
flag is set uncurry (see: https://github.com/scala/scala/blob/master/src/compiler/scala/tools/nsc/transform/UnCurry.scala#L569). This is rather questionable place for that kind of code as it mutates flags and pickle will never see those changes.only 32 lowest bits are pickled (see https://github.com/scala/scala/blob/master/src/reflect/scala/reflect/internal/Flags.scala#L310) and
SPECIALIZED
has index 40 (https://github.com/scala/scala/blob/master/src/reflect/scala/reflect/internal/Flags.scala#L160).The first problem has been introduced in 7bddd73 (scala/scala@7bddd73) but I don't think reverting this change makes sense for efficiency reasons. Therefore we have two choices:
SPECIALIZED
flag so it gets pickled and set it before pickling happens (probably right before, it means in pickler).I like the first solution much better. We don't want to slow down unpickling.
The text was updated successfully, but these errors were encountered: