United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4820062 : Provide "struct" syntax in the Java language

Details
Type:
Enhancement
Submit Date:
2003-02-18
Status:
Closed
Updated Date:
2011-10-31
Project Name:
JDK
Resolved Date:
2011-10-31
Component:
specification
OS:
generic,windows_xp
Sub-Component:
language
CPU:
x86,generic
Priority:
P4
Resolution:
Duplicate
Affected Versions:
1.4.1,5.0
Fixed Versions:

Related Reports
Duplicate:
Relates:

Sub Tasks

Description
Name: rmT116609			Date: 02/18/2003


DESCRIPTION OF THE PROBLEM :
The Java language lacks "structs".

The lack of structs gives rise to serious code complexity
when dealing with external systems, and serious performance
implications for code that performs a large amount of I/O
with external systems.

Because of the way Java and Objects are intertwined it would
probably not be entirely practical to insist on the same
struct semantics that are found in C. In particular the lack
of pointers and pass-by-value semantics for a trivial
implementation of structs makes an apples-to-apples theft
from the C language impossible.

However, as the particular problem I am trying to crack is
dealing with high-performance I/O operations (in fact,
OpenGL graphics rendering in this case), I believe there is
an elegant solution based on NIO buffers which should
provide wonderful syntax, high performance, and 100% robust
operation with minimal impact.

The solution I propose is to associate a "struct" with a
Buffer. The buffer's primitive type then becomes the struct,
i.e a position(n) command on the buffer moves the buffer to
access the nth struct in a buffer of these structs.

A struct should syntactically accessed the same as a normal
object, ie. passed by reference, and so on. Struct field
assignments and reads take place directly to and from memory
with no intermediate copy.

A struct should be defined in Java using simple C-like
syntax, and generate a .class file like any other Java class
construct. The difference is that the fields may only be
primitive Java types or themselves structs. Each field is
not stored in an instance of the object itself; instead they
are mapped to offsets in memory from a Buffer. A struct
therefore must have a reference to its parent Buffer to
prevent the buffer from being garbage collected and structs
being allowed to access unmanaged memory.

public struct Vertex {
private float x, y, z, nx, ny, nz;
private byte r, g, b, a;

void normalize() {
//etc
}

};

A struct descends from the class javax.nio.Struct, which has
a package-visible constructor which takes the parent
StructBuffer as a parameter:

public abstract class Struct {

private final Buffer buffer;
private final int position;

Struct(Buffer buffer) {
this.buffer = buffer;
}

}

The usage of the new "struct" keyword, which is
syntactically similar to "class" and "interface", instructs
the runtime not to reserve space for the structs' fields
because they will instead be referenced directly from a
buffer at the specified position.

Then a buffer of this struct should be initialized, perhaps
using the new generics feature to simplify the syntax:

// Allocates a struct buffer with 10 structs in it at the
specified address, which can be a long
StructBuffer<Vertex> buf = new StructBuffer<Vertex>(10,
address);

// or from a ByteBuffer, which will check that the
bytebuffer's capacity is an exact multiple of the struct's size
StructBuffer<Vertex> buf = new StructBuffer(byteBuf);

Then values from the buffer can be referenced directly as
Vertexes:

Vertex v0 = buf.get(0);
v0.normalize();
Vertex v1 = buf.get(1, v1); // Constructs v1 if necessary

The underlying implementation in Java should be identical in
speed to C for the common case (with bounds check
elimination and native byte ordering), yet because a struct
can only be constructed by an existing StructBuffer, it will
have all the safety of bounds-checking and garbage
collection which will prevent illegal writes to memory.

The two problems solved by this RFE would be the sheer
complexity of maintaining multiple buffers to access
different parts of a struct with different primitive types;
and the massive increase in performance afforded by being
able to reference memory directly and bracket accesses to
members of a struct with one bounds check.

You will understand if you do graphics programming; it is a
key requirement of games programmers to have greatly
simplified and efficient access to these operations or the
benefits of C++ simply outweigh the extra complexity and
overhead inherent in Java.

(Review ID: 181371) 
======================================================================

                                    

Comments
EVALUATION

There are some interesting ideas in this proposal,
however, we do not see the need for a new language
feature.  We believe this can be solved as a library
without changes to the language and VM.

As a consequence, we have moved this RFE from
specification to java.util.

We are currently investigating various solutions
and if it should be part of the JDK.  In any event,
it will not be in time for Mustang.

More details will follow.
                                     
2005-09-29
EVALUATION

We are currently considering if this should be addressed in Dolphin.

A combination of library methods and annotation processors should
make it possible to write something like this:

@Struct
interface CK_SLOT_INFO {
  @PaddedString(' ', "utf8", 64)
  String getSlotDescription();
  @PaddedString(' ', "utf8", 32)
  String getManufacturerID();
  @Unsigned(32)
  int getFlags();
  CK_VERSION getHardwareVersion();
  CK_VERSION getFirmwareVersion();
}

(Using an example from PKCS#11)
                                     
2006-02-10
EVALUATION

Response to SDN comment from Cas: you're right about the category.
I have moved this RFE to java.nio.
                                     
2006-02-14
EVALUATION

Responding to SDN comments:

We are considering this RFE as a request to access low-level/native
data structures as can be done with C structs (and C++ classes).

If you're looking for stack allocated objects or value types, you
should vote for RFE 4213096 or RFE 4809540.

Clearly performance will be paramount to the success of any solution
(library based or language syntax) but claiming that it can't be done
with classes is unfounded.  Modern JVMs, such as HotSpot, are very good
at optimizing Java byte code.

The only real difference between a class and a C struct is who generates
the code for accessing members.  Consider a C struct like this:

struct Foo {
    int a;
    int b;
} Foo;

If you have an array of Foo, foos, then a C compiler can compile
an expression like:

foos[6].b

to i386 machine code like:

        movl    foos, %edx
        movl    52(%edx), %eax

where 52 = 6*sizeof(Foo)+sizeof(int) 

You can accomplish something similar in Java:

static int SIZEOF_FOO = 2;
static int SIZEOF_INT = 1;
int getFoo_b(IntBuffer foos, int index) {
    return foos.get(index*SIZEOF_FOO+SIZEOF_INT);
}

The expression similar to foos[6].b would be:

getFoo_b(foos, 6)

HotSpot can inline this:

foos.get(6*SIZEOF_FOO+SIZEOF_INT)

which can be further optimized:

foos.get(13)

This then all boils down to how efficiently HotSpot can handle
IntBuffer.get.  However, as always, C has a performance advantage over Java:
no range checks.  This means that the best we can hope for in Java is
something like this:

        cmpl    $56, size
        jbe     .OUT_OF_BOUNDS_FAILED
        movl    foos, %edx
        movl    52(%edx), %eax

If the Java platform can't handle foos.get(13) efficiently, then you will
get bad performance no matter what solution you dream up.  I don't see how
saying "structs" solves this problem.

The really tedious part of accessing low-level data structures is writing
methods like getFoo_b and constants like SIZEOF_FOO.  This can be automated.
The proposal with @Struct is to have an annotation processor generate such
methods and constants based on a higher abstraction.

So do us a favor and let us know what is wrong with the performance of the
java.nio buffers if it doesn't meet your needs.  That is a realistic way of
solving your problems.  Asking for C structs is not.
                                     
2006-02-17
EVALUATION

Apparently, my previous evaluation could be misunderstood.

I was responding to this SDN comment:

"I'm for structs. Classes are way too expensive to create
 in many situations, and are sometimes semantically invalid
 in various contexts."

So just to be clear:

* We are considering addressing the requirement of accessing
  low-level data structures in Java.

* We are not considering adding C-like structs to Java at this
  time.

* If you're interested in C-like structs, vote for other bugs.
  (But don't get your hopes up).

* If you don't think the @Struct proposal will solve your
  problem, please let us know.  A precondition for the
  @Struct proposal is support from NIO, for example, as Cas
  suggests, "memory mapped objects as a sliding window over
  ByteBuffers".
                                     
2006-02-22
EVALUATION

Proposals for new features in the Java programming language are no longer being accepted or maintained in the bug database at http://bugs.sun.com/. This also applies to proposals for new features in the Java Virtual Machine (that is, in the abstract JVM, as opposed to a JVM implementation like HotSpot).

All proposals for new features should be made through the "JDK Enhancement - Proposal & Roadmap Process" described at http://openjdk.java.net/jeps/1.

Consequently, this specific request to change the Java programming language will not be considered further.

The bug database continues to accept and maintain submissions about technical errors in the design and specification of the Java programming language and the Java Virtual Machine.
                                     
2011-10-31



Hardware and Software, Engineered to Work Together