On 9/28/2012 5:33 PM, Vitaly Davidovich wrote:

Yeah, the CLR does something similar - there's a type, ValueType, which is the base class for all structs implicitly. It's just a moniker though since you can't extend it explicitly (languages like C# then provide keywords to declare them) and it provides just a handful of basic methods inherited from object which you can override if need be. They can implement interfaces, but not extend (or be extended by) classes. Assignment just does bitwise copying, as well as passing them as args (unless ref/out is used) or returning them. Assigning or referring to them via any interface that they implement boxes it.

The really nice thing about them is you can implement (and BCL does) some lightweight abstractions like enumerators. You can also do RAII-like things with them; C# actually generates code that refers to them as-is (not IDisposable) when desugaring using{} blocks. It's very nice basically :)


my own VM does something vaguely similar as well, but it differs somewhat from the strategy described (in that value-types are indicated via a modifier flag and don't require any special treatment at the bytecode level), and they are not quite as efficient as they could be.

value-classes also exist, and can do RAII-like stuff via copy-constructors and destructors.


partly this is handled internally with them being objects as before, except:
normal objects have a copyValue method which simply returns the same object;
value-types create a new object which holds a copy of the object (for value-classes, creates a new instance of the object, calling the copy-constructor with the old object).

and, similarly:
the dropValue method for normal reference-objects is essentially no-op;
however, for value-types, it will destroy the object (for value-classes, calling the destructor and then freeing the memory).

note (for my VM, not JVM based): many VM objects are not class instances... and these methods are VM-internal, and exist separately from the actual methods declared in a class. some are just weird, such as toString, which calls a VM internal method, which may in-turn call the class method if the object is an instance of a class. technically, the vtable for these internal methods is linked to (indirectly) via the GC's object header.


I'm wondering why the JVM can't do something like that apart from having to modify the language spec and thus have VM vendors needing to implement it. Not downplaying that aspect, but curious what technical challenges this would present.


I don't really know.

(admittedly, I haven't really done any development on the standard JVM).

I did similar before on my own miniature JVM implementation, partly by creating a special "Struct" class, and imparting some "magic" to it (more like that described before).

my own VM's implementation was based on this. underneath, they were largely built on the same core machinery.


or such...



Sent from my phone

On Sep 28, 2012 5:55 PM, "BGB" <cr88...@gmail.com <mailto:cr88...@gmail.com>> wrote:

    On 9/28/2012 4:10 PM, Vitaly Davidovich wrote:

    Since we're in wishful thinking territory now :), the two things
    I'd really like are:

    1) value/struct types (i.e. avoid heap and be able to pack data
    closer together).  I don't how much we can rely on EA.
    2) more auto-vectorization

    I think 2 is being worked on by Vladimir but unclear if there are
    any concrete plans for 1.  I know John Rose has written about it,
    but don't know if anything's actually planned.


    yeah, agreed on 1.
    I remember reading before of mention of using special signatures
    or similar, but I forget the specifics.


    I had before floated the idea of if it could be indicated via a
    special base-class or interface.
    in the latter case, the interface would essentially be "magic",
    and tell the VM: "Hey! This thing here is a struct!".

    this could sort of work, but would exhibit incorrect behavior on
    older JVMs, unless it were done multi-part:
    one part, a JVM extension to support built-in structs (indicated
    via a special class or interface, as before);
    the second part would be providing special
    classes/interfaces/methods, which could be used to "implement" the
    special struct behavior (could just be "native"?);
    the 3rd part would basically be some syntax sugar in Java, mostly
    so that the code isn't filled up with nasty looking method calls.


    say (extensions):
    ValueType interface, provides ability to construct types with
    pass-by-value semantics (mostly would be handled specially by
    "javac" or similar);
    Struct class which implements ValueType, special class, for which
    all derived classes are structs;
    ValueClass class, which is like struct, but creates classes which
    implement pass-by-value semantics.

    so, if we have something like:
    SomeStruct a, b;
    a=new SomeStruct(...);
    b=a;
    the latter could generate code more like if it were:
    b=a.copyValue();
    and when they leave scope:
    a.dropValue();
    b.dropValue();

    and:
    public struct SomeStruct { ... }

    could actually be handled internally more like:
    public final class SomeStruct extends Struct { ... }


    with the VM realizing that Struct and "Struct.copyValue()" and
    similar are magic, with the JIT generating special code to handle
    them more efficiently.

    or, at least, this is my idle thinking at the moment...


    note: unrelated to "java.sql.Struct"...


    Sent from my phone

    On Sep 28, 2012 3:59 PM, "Charles Oliver Nutter"
    <head...@headius.com <mailto:head...@headius.com>> wrote:

        Now what we need is a way to inject new intrinsics into the
        JVM, so I
        can make an asm version of something and tell hotspot "no no, use
        this, not the JVM bytecode" :)

        - Charlie

        On Fri, Sep 28, 2012 at 11:53 AM, Vitaly Davidovich
        <vita...@gmail.com <mailto:vita...@gmail.com>> wrote:
        > Yup, it would have to do extensive pattern matching
        otherwise.  C/C++
        > compilers do the same thing (I.e. have intimate knowledge
        of stdlib calls
        > and may optimize more aggressively or replace code with
        intrinsic
        > altogether).
        >
        > In this case, jit uses the bsf x86 assembly instruction
        whereas hand rolled
        > "copy version" generates asm pretty much matching the java
        code.
        >
        > Sent from my phone
        >
        > On Sep 28, 2012 2:42 PM, "Raffaello Giulietti"
        > <raffaello.giulie...@gmail.com
        <mailto:raffaello.giulie...@gmail.com>> wrote:
        >>
        >> On Fri, Sep 28, 2012 at 8:15 PM, Charles Oliver Nutter
        >> <head...@headius.com <mailto:head...@headius.com>> wrote:
        >> > On Fri, Sep 28, 2012 at 10:21 AM, Raffaello Giulietti
        >> > <raffaello.giulie...@gmail.com
        <mailto:raffaello.giulie...@gmail.com>> wrote:
        >> >> I'm not sure that we are speaking about the same thing.
        >> >>
        >> >> The Java source code of numberOfTrailingZeros() is
        exactly the same in
        >> >> Integer as it is in MyInteger. But, as far as I
        understand, what
        >> >> really runs on the metal upon invocation of the Integer
        method is not
        >> >> JITted code but something else that probably makes use
        of CPU specific
        >> >> instructions. This code is built directly into the JVM
        and need not
        >> >> bear any resemblance with the code that would have been
        produced by
        >> >> JITting the bytecode.
        >> >
        >> > Regardless of whether the method is implemented in Java
        or not, the
        >> > JVM "knows" native/intrinsic/optimized versions of many
        java.lang core
        >> > methods. numberOfTrailingZeros is one such method.
        >> >
        >> > Here, the JVM is using its intrinsified version rather
        than the JITed
        >> > version, presumably because the intrinsified version is
        pre-optimized
        >> > and faster than what the JVM JIT can do for the JVM
        bytecode version.
        >> >
        >> > system ~/projects/jruby-ruby $ java -XX:+PrintCompilation
        >> > -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining Blah
        >> >      65    1 java.lang.String::hashCode (55 bytes)
        >> >      78    2             Blah::doIt (5 bytes)
        >> >      78    3 java.lang.Integer::numberOfTrailingZeros (79
        >> > bytes)
        >> >                             @ 1
>> > java.lang.Integer::numberOfTrailingZeros (79 bytes) (intrinsic)
        >> >      79    1 %           Blah::main @ 2 (29 bytes)
>> > @ 9 Blah::doIt (5 bytes) inline (hot)
        >> >                               @ 1
>> > java.lang.Integer::numberOfTrailingZeros (79 bytes) (intrinsic) >> > @ 15 Blah::doIt (5 bytes) inline (hot)
        >> >                               @ 1
>> > java.lang.Integer::numberOfTrailingZeros (79 bytes) (intrinsic)
        >> >
        >> > system ~/projects/jruby-ruby $ cat Blah.java
        >> > public class Blah {
        >> > public static int value = 0;
        >> > public static void main(String[] args) {
        >> >   for (int i = 0; i < 10_000_000; i++) {
        >> >     value = doIt(i) + doIt(i * 2);
        >> >   }
        >> > }
        >> >
        >> > public static int doIt(int i) {
        >> >   return Integer.numberOfTrailingZeros(i);
        >> > }
        >> > }
        >> > _______________________________________________
        >>
        >>
        >> Yes, this is what Vitaly stated and what happens behind
        the curtains.
        >>
        >> In the end, this means there are no chances for the rest
        of us to
        >> implement better Java code as a replacement for the
        intrinsified
        >> methods.
        >>
        >> For example, the following variant is about 2.5 times
        *faster*,
        >> averaged over all integers, than the JITted original
        method, the one
        >> copied verbatim! (Besides, everybody would agree that it
        is more
        >> readable, I hope.)
        >>
        >> But since the Integer version is intrinsified, it still
        runs about 2
        >> times slower than that (mysterious) code.
        >>
        >>     public static int numberOfTrailingZeros(int i) {
        >>         int n = 0;
        >>         for (; n < 32 && (i & 1 << n) == 0; ++n);
        >>         return n;
        >>     }
        >> _______________________________________________
        >> mlvm-dev mailing list
        >> mlvm-dev@openjdk.java.net <mailto:mlvm-dev@openjdk.java.net>
        >> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
        >
        >
        > _______________________________________________
        > mlvm-dev mailing list
        > mlvm-dev@openjdk.java.net <mailto:mlvm-dev@openjdk.java.net>
        > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
        >
        _______________________________________________
        mlvm-dev mailing list
        mlvm-dev@openjdk.java.net <mailto:mlvm-dev@openjdk.java.net>
        http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev



    _______________________________________________
    mlvm-dev mailing list
    mlvm-dev@openjdk.java.net  <mailto:mlvm-dev@openjdk.java.net>
    http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev


    _______________________________________________
    mlvm-dev mailing list
    mlvm-dev@openjdk.java.net <mailto:mlvm-dev@openjdk.java.net>
    http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev



_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to