class Point {
int x;
int y;
};
class Line {
Point p1;
Point p2;
};
Line la[2];
public class Point {
int x;
int y;
}
public class Line {
Point p1;
Point p2;
}
Line[] la = new Line[2];
line[1].p1.x
):
Drawbacks - This is not JavaTM anymore!
-XX:+PackedObject
.import com.ibm.jvm.packed.ImportPacked;
import com.ibm.jvm.packed.Packed;
import com.ibm.jvm.packed.PackedObject;
import com.ibm.jvm.packed.reflect.PackedArray;
@Packed
final class Point extends PackedObject { // <- MUST be final and extend PackedObject
public int x;
public int y;
public Point(int x, int y) { this.x = x; this.y = y; }
}
@Packed
@ImportPacked({"Point"}) // <- MUST declare "packed" usage
final class Line extends PackedObject {
public Point p1;
public Point p2;
public Line() {
if (!PackedObject.isPackedSupportEnabled()) {
p1 = new Point();
p2 = new Point();
}
}
public Line(Point p1, Point p2) {
if (!PackedObject.isPackedSupportEnabled()) {
this.p1 = p1;
this.p2 = p2;
}
else {
this.p1.copyFrom(p1); // <- Use PackedObject.copyFrom() for initialization
this.p2.copyFrom(p2);
}
}
}
public class PackedTest {
public static void main(String args[]) {
Point p1 = new Point(1, 1);
Point p2 = new Point(2, 2);
Line l1 = new Line(p1, p2);
System.out.println("\np1 = " + p1 + "\np2 = " + p2 + "\nl1 = " + l1);
p1 = Point(1, 1) p2 = Point(2, 2) l1 = Line(Point(1, 1), Point(2, 2))
l1.p1.x = 47;
l1.p1.y = 11;
System.out.println("\np1 = " + p1 + "\np2 = " + p2 + "\nl1 = " + l1);
> with -XX:-PackedObject p1 = Point(47, 11) <=== p2 = Point(2, 2) l1 = Line(Point(47, 11), Point(2, 2)) > with -XX:+PackedObject p1 = Point(1, 1) <=== p2 = Point(2, 2) l1 = Line(Point(47, 11), Point(2, 2))
p2.x = 8;
p2.y = 15;
System.out.println("\np1 = " + p1 + "\np2 = " + p2 + "\nl1 = " + l1);
> with -XX:-PackedObject p1 = Point(47, 11) p2 = Point(8, 15) l1 = Line(Point(47, 11), Point(8, 15)) <=== > with -XX:+PackedObject p1 = Point(1, 1) p2 = Point(8, 15) l1 = Line(Point(47, 11), Point(2, 2)) <===
l1.p1 = p2;
System.out.println("\np1 = " + p1 + "\np2 = " + p2 + "\nl1 = " + l1);
> with -XX:-PackedObject p1 = Point(47, 11) p2 = Point(8, 15) l1 = Line(Point(8, 15), Point(8, 15)) <=== > with -XX:+PackedObject java.lang.IllegalAccessError: Cannot assign to a nested field of a @Packed type.
@Packed
@ImportPacked({"Point"})
final class Line extends PackedObject {
...
@Packed // MUST be @Packed, static and final
@ImportPacked({"Line"})
public static final class Array extends PackedObject implements Serializable, Cloneable {
private Array() {} // MUST declare private constructor
public static Array allocate(int length) {
return PackedArray.newArray(Line.Array.class, length);
}
public Line at(int index) {
return PackedArray.at(this, index);
}
public int getLength() {
return PackedArray.getLength(this);
}
public Array clone() throws CloneNotSupportedException {
return (Array)super.clone();
}
// Can't declare any other methods or fields!
}
public class PackedTest2 {
Point p1 = new Point(1, 1);
Point p2 = new Point(2, 2);
Line l1 = new Line(p1, p2);
System.out.format("\np1 = " + p1 + "\np2 = " + p2 + "\nl1 = " + l1);
p1 = Point(1, 1) p2 = Point(2, 2) l1 = Line(Point(1, 1), Point(2, 2))
Line.Array la = Line.Array.allocate(3);
la.at(0).copyFrom(l1);
la.at(1).p1.copyFrom(p2);
la.at(2).p1.x = 3;
System.out.println("\nla = " + Line.toString(la));
la = Line.Array(3) ( Line(Point(1, 1), Point(2, 2)), Line(Point(2, 2), Point(0, 0)), Line(Point(3, 0), Point(0, 0)))
public class Point {
protected int x;
protected int y;
public Point() {}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public void set(Point p) {
if (p != null) {
this.x = p.x;
this.y = p.y;
}
}
}
public class Line {
@Intrinsic // @Intrinsic fields have to be private, final
private final Point p1 = IntrinsicObjects.constructWithin("p1", this);
@Intrinsic // @Intrinsic fields have to be private, final
private final Point p2 = IntrinsicObjects.constructWithin("p2", this);
public Line() {}
public Line(Point p1, Point p2) {
this.p1.x = p1.x;
this.p1.y = p1.y;
this.p2.set(p2);
}
public void set(Line l) {
if (l != null) {
this.p1.set(l.p1);
this.p2.set(l.p2);
}
}
}
public class Triangle {
@Intrinsic
private final Line l = IntrinsicObjects.constructWithin("l", this);
@Intrinsic
private final Point p = IntrinsicObjects.constructWithin("p", this);
public Triangle() {}
public Triangle(Line l, Point p) {
this.l.set(l);
this.p.set(p);
}
}
public class IntrinsicFieldTest {
public static void main(String args[]) {
Point p1 = new Point(1, 1);
Point p2 = new Point(2, 2);
Point p3 = new Point(3, 3);
Line l = new Line();
Line l1 = new Line(p1, p2);
Triangle t1 = new Triangle(l1, p3);
p3.set(new Point(5, 5));
System.out.println("\np1 = " + p1 +
"\np2 = " + p2 +
"\np3 = " + p3 +
"\nl1 = " + l1 +
"\nt1 = " + t1);
}
}
p1 = Point(1, 1) p2 = Point(2, 2) p3 = Point(5, 5) l1 = Line(Point(1, 1), Point(2, 2)) t1 = Triangle(Line(Point(1, 1), Point(2, 2)), Point(3, 3))
Line.<init>
|
|||||||
IntrinsicObjects.constructWithin("p1", line)
|
|||||||
IntrinsicObjectModel<Point>.constructWithin(line)
|
|||||||
IntrinsicObjectModel<Point>.instantiate(this, constructor, args...)
|
|||||||
AbstractIntrinsicObjectModel<Point>.constructElementWithin(line, constructor, args...)
|
|||||||
Point p = Constructor<Point>.newInstance(args)
|
|||||||
java.lang.reflect.Constructor.newInstance(args)
|
|||||||
// Reflection magic -> new Point(args)
|
|||||||
AbstractIntrinsicObjectModel<Point>.directlyInitializeTargetField(line, p)
|
|||||||
java.lang.reflect.Field.set(line, p)
|
Line.<init>
|
|||||||
IntrinsicObjects.constructWithin("p1", line)
|
|||||||
IntrinsicObjectModel<Point>.constructWithin(line)
|
|||||||
IntrinsicObjectModel<Point>.instantiate(this, constructor, args...)
|
|||||||
AbstractIntrinsicObjectModel<Point>.constructElementWithin(line, constructor, args...)
|
|||||||
Point p = Constructor<Point>.newInstance(args)
|
|||||||
java.lang.reflect.Constructor.newInstance(args)
|
|||||||
// Reflection magic -> new Point(args)
|
|||||||
AbstractIntrinsicObjectModel<Point>.directlyInitializeTargetField(line, p)
|
|||||||
java.lang.reflect.Field.set(line, p)
|
public class StructuredArrayOfPoint extends StructuredArray {
public static StructuredArrayOfPoint newInstance(final long length) {
return StructuredArray.newInstance(StructuredArrayOfPoint.class, Point.class, length);
}
public Point get(long index) {
return super.get(index);
}
}
public class StructArrayTest {
public static void main(String args[]) {
StructuredArrayOfPoint points = StructuredArrayOfPoint.newInstance(5);
for (int i = 0; i < points.getLength(); i++) {
points.get(i).set(new Point(i, i));
}
System.out.println("points = " + points);
points = StructuredArrayOfPoint(5) ( Point(0, 0), Point(1, 1), Point(2, 2), Point(3, 3), Point(4, 4))
StructuredArray<Line> lines = StructuredArray.newInstance(Line.class, 5);
for (int i = 0; i < lines.getLength(); i++) {
lines.get(i).set(new Line(new Point(i, 2*i), new Point(2*i, 3*i)));
}
System.out.println("lines = " + prettyPrint(lines));
lines = StructuredArray(5) ( Line(Point(0, 0), Point(0, 0)), Line(Point(1, 2), Point(2, 3)), Line(Point(2, 4), Point(4, 6)), Line(Point(3, 6), Point(6, 9)), Line(Point(4, 8), Point(8, 12)))
StructuredArrayOfPoint.newInstance(length)
|
||||||||||||
StructuredArray<Point>.newInstance(length)
|
||||||||||||
StructuredArray<Point>.instantiate(length)
|
||||||||||||
magic_1 = StructuredArray<Point>.getConstructorMagic() <----------------\
|
||||||||||||
magic_1.setConstructionArgs(lengt, ...) |
|
||||||||||||
AbstractStructuredArray<Point>.instantiateStructuredArray() |
|
||||||||||||
magic_2 = AbstractStructuredArray<Point>.getConstructorMagic() <---\ |
|
||||||||||||
magic_2.setConstructionArgs(length, ...) | |
|
||||||||||||
return Constructor<StructuredArrayOfPoint>.newInstance() | |
|
||||||||||||
java.lang.reflect.Constructor.newInstance() | |
|
||||||||||||
// Reflection magic -> new StructuredArrayOfPoint() | |
|
||||||||||||
StructuredArrayOfPoint.<init> | |
|
||||||||||||
StructuredArray<Point>.<init> | |
|
||||||||||||
AbstractStructuredArray<Point>.<init> | |
|
||||||||||||
magic_2 = AbstractStructuredArray<Point>.checkConstructorMagic() <---/ |
|
||||||||||||
AbstractStructuredArray<Point>.allocateInternalStorage(length) |
|
||||||||||||
magic_1 = StructuredArray<Point>.checkConstructorMagic() <----------------/
|
||||||||||||
StructuredArray<Point>.populateLeafElements()
|
||||||||||||
StructuredArray<Point>.populateLeafElement()
|
||||||||||||
AbstractStructuredArray<Point>.constructElementAtIndex()
|
||||||||||||
Point point = Constructor<Point>.newInstance()
|
||||||||||||
// Reflection magic -> new Point()
|
||||||||||||
AbstractStructuredArray<Point>.storeElementInLocalStorageAtIndex(index, point)
|
StructuredArrayOfPoint.newInstance(length)
|
||||||||||||
StructuredArray<Point>.newInstance(length)
|
||||||||||||
StructuredArray<Point>.instantiate(length)
|
||||||||||||
magic_1 = StructuredArray<Point>.getConstructorMagic() <----------------\
|
||||||||||||
magic_1.setConstructionArgs(lengt, ...) |
|
||||||||||||
AbstractStructuredArray<Point>.instantiateStructuredArray() |
|
||||||||||||
magic_2 = AbstractStructuredArray<Point>.getConstructorMagic() <---\ |
|
||||||||||||
magic_2.setConstructionArgs(length, ...) | |
|
||||||||||||
return Constructor<StructuredArrayOfPoint>.newInstance() | |
|
||||||||||||
java.lang.reflect.Constructor.newInstance() | |
|
||||||||||||
// Reflection magic -> new StructuredArrayOfPoint() | |
|
||||||||||||
StructuredArrayOfPoint.<init> | |
|
||||||||||||
StructuredArray<Point>.<init> | |
|
||||||||||||
AbstractStructuredArray<Point>.<init> | |
|
||||||||||||
magic_2 = AbstractStructuredArray<Point>.checkConstructorMagic() <---/ |
|
||||||||||||
AbstractStructuredArray<Point>.allocateInternalStorage(length) |
|
||||||||||||
magic_1 = StructuredArray<Point>.checkConstructorMagic() <----------------/
|
||||||||||||
StructuredArray<Point>.populateLeafElements()
|
||||||||||||
StructuredArray<Point>.populateLeafElement()
|
||||||||||||
AbstractStructuredArray<Point>.constructElementAtIndex()
|
||||||||||||
Point point = Constructor<Point>.newInstance()
|
||||||||||||
// Reflection magic -> new Point()
|
||||||||||||
AbstractStructuredArray<Point>.storeElementInLocalStorageAtIndex(index, point)
|
@Intrinsic
and
IntrinsicObjects.constructWithin()
in the VM.AbstractIntrinsicObjectModel.constructElementWithin()
putfield/getfield
)putfield/getfield
)
$ java -cp ObjectLayout.jar \ -XX:+PrintFieldLayout IntrinsicFieldTest IntrinsicFieldTest$Point: field layout @ 12 --- instance fields start --- @ 12 "x" I @ 16 "y" I @ 20 --- instance fields end --- @ 24 --- instance ends --- ... IntrinsicFieldTest$Line: field layout @ 12 --- instance fields start --- @ 12 "p1" LIntrinsicFieldTest$Point; <=== @ 16 "p2" LIntrinsicFieldTest$Point; <=== @ 20 --- instance fields end --- @ 24 --- instance ends --- ... IntrinsicFieldTest$Triangle: field layout @ 12 --- instance fields start --- @ 12 "l" LIntrinsicFieldTest$Line; <=== @ 16 "p" LIntrinsicFieldTest$Point; <=== @ 20 --- instance fields end --- @ 24 --- instance ends ---
$ java -cp ObjectLayout.jar -XX:+OptimizeObjectLayout \ -XX:+PrintFieldLayout IntrinsicFieldTest IntrinsicFieldTest$Point: field layout @ 12 --- instance fields start --- @ 12 "x" I @ 16 "y" I @ 20 --- instance fields end --- @ 24 --- instance ends --- ... IntrinsicFieldTest$Line: field layout @ 12 --- instance fields start --- @ 12 --- instance fields end --- @ 16 --- intrinsic fields start --- @ 16 "p1" LIntrinsicFieldTest$Point; <=== @ 40 "p2" LIntrinsicFieldTest$Point; <=== @ 64 --- intrinsic fields end --- @ 64 --- instance ends --- ... IntrinsicFieldTest$Triangle: field layout @ 12 --- instance fields start --- @ 12 --- instance fields end --- @ 16 --- intrinsic fields start --- @ 16 "l" LIntrinsicFieldTest$Line; <=== @ 80 "p" LIntrinsicFieldTest$Point; <=== @104 --- intrinsic fields end --- @104 --- instance ends ---
AIOModel.constructElementWithin()
final T constructElementWithin(
final Object containingObject,
final Constructor constructor,
final Object... args)
throws InstantiationException, IllegalAccessException, InvocationTargetException {
T element = constructor.newInstance(args);
field.set(containingObject, set);
return element;
}
AIOM.constructElementWithin()
like a native method in the VMJVM_ObjectLayoutConstructWithin()
)JVM_ENTRY(jobject, JVM_ObjectLayoutConstructWithin(JNIEnv *env, jobject obj,
jobject enclosing, jobject cstr, jobjectArray args0))
JVMWrapper("JVM_ObjectLayoutConstructWithin");
static int foff = ...; // offset of org.objectlayout.AbstractIntrinsicObjectModel.field
oop field = JNIHandles::resolve_non_null(obj)->obj_field(foff);
int slot = java_lang_reflect_Field::slot(field);
int offset = InstanceKlass::cast(k)->field_offset(slot);
oop enclosing_obj = JNIHandles::resolve(enclosing);
oop constructor_mirror = JNIHandles::resolve(cstr);
objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
Reflection::construct_within(enclosing_obj, offset, constructor_mirror, args, CHECK_NULL);
...
JVM_END
oop Reflection::construct_within(oop enclosing_obj, jlong offset, oop constructor_mirror, objArrayHandle args, TRAPS) {
...
char* o = (char*)enclosing_obj + offset; // plain pointer to the embedded receiver
// Install the mark word and the klass pointer into the embedded object
CollectedHeap::post_allocation_setup_common(klass, (HeapWord*)o);
Handle receiver(THREAD, (oop)o);
...
// Ignore result from call and return receiver
invoke(klass, method, receiver, override, ptypes, T_VOID, args, false, CHECK_NULL);
return receiver();
}
putfield
on @Intrinsic
fields as NOPgetfield
on @Intrinsic
fields as simple load
void TemplateTable::fast_accessfield(TosState state) {
// field: Address
// rax : TOS (Top of Stack register)
...
// normal, fast 'getfield'
case Bytecodes::_fast_agetfield:
__ load_heap_oop(rax, field);
__ verify_oop(rax);
break;
// fast 'getfield' for intrinsified fields
case Bytecodes::_fast_agetfield_intr:
__ leaq(rax, field);
__ verify_oop(rax);
putfield
on @Intrinsic
fields as NOPgetfield
on @Intrinsic
fields with new Ideal node CastIntrinsic
LoadP
because @Intrinsic
fields are embeddedvoid Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
...
if (OptimizeObjectLayout && field->is_intrinsic()) {
if (Verbose) {
tty->print("do_field_access() - ");
tty->print("found getfield for intrinsic field %s at bci: %d in ", field->name()->as_quoted_ascii(), bci());
method()->print_name();
tty->cr();
}
const Type *type = TypeOopPtr::make_from_klass_unique(field_klass->as_klass())->cast_to_ptr_type(TypePtr::NotNull);
Node *cast = new CastIntrinsicNode(adr, type);
cast = _gvn.transform(cast);
push(cast);
return;
}
//------------------------------CastIntriniscNode-------------------------------------
// cast pointer of an ecnclosing class to pointer of an intrinsified field (different type)
class CastIntrinsicNode: public CastPPNode {
public:
CastIntrinsicNode (Node *n, const Type *t ): CastPPNode(n, t) { init_class_id(Class_CastIntrinsic); }
...
instruct castIntrinsic(rRegP dst, immL32 src, rFlagsReg cr)
%{
match(Set dst (CastIntrinsic (AddP dst src)));
effect(KILL cr);
format %{ "addq $dst, $src\t# intrinisc getfield" %}
...
public static void shift(Triangle t, int x, int y) {
t.getPoint().x += x;
t.getPoint().setY(t.getPoint().getY() + y);
t.getLine().getP1().x += x;
t.getLine().getP1().y += y;
t.getLine().getP2().x += x;
t.getLine().getP2().y += y;
}
public static void main(String args[]) {
...
Triangle t1 = new Triangle(l1, p3);
for (int i = 0; i < COUNT; i++) {
shift(t1, 1, 1);
}
}
t.getLine().getP1().x += x;
" movl R11, [RSI + #12 (8-bit)] ! Field: IntrinsicFieldDeadReckonTest$Triangle.l
movl R10, [R11 + #12 (8-bit)] ! Field: IntrinsicFieldDeadReckonTest$Line.p1
NullCheck R11
addl [R10 + #12 (8-bit)], RDX ! Field: IntrinsicFieldDeadReckonTest$Point.x
NullCheck R10
t.getLine().getP1().x += x;
" with -XX:+OptimizeObjectLayout
addl [RSI + #44 (8-bit)], RDX
CastIntrinsic
nodes in addnode.cpp
:Node *AddPNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// If the left input is an add of a constant, flatten the expression tree.
const Node *n = in(Address);
const Node *intr = n->isa_CastIntrinsic();
if (n->is_AddP() && n->in(Base) == in(Base) || intr && intr->in(Base)->is_AddP()) {
const AddPNode *addp = intr ? intr->in(Base)->as_AddP() : n->as_AddP(); // Left input is an AddP
lockPermanently()
" operator which marks objects as immutableConstruction (from "Value types for Java"):
final __ByValue class Point {
public final int x;
public final int y;
public Point(int x1, int y1) {
; public static <new>(II)QPoint;
//implicit initialize 'this' to zero
; vnew Point; // stack [ this ]
this.x = x1;
; iload 0 ('x1') // stack [ this x1 ]
; vputfield 'x' // stack [ this ]
this.y = y1;
; iload 1 ('y1') // stack [ this, y1 ]
; vputfield 'y' // stack [ this ]
//implicit: return 'this'
; vreturn
}
}
Point p = __MakeValue(1, 2);
; iconst_1
; iconst_2
; invokestatic Point.<new>(II)QPoint;
; vstore 6 (store 'p')
Classic allocation:
Point p = new Point(1, 2);
; new Point;
; dup
; iconst_1
; iconst_2
; invokespecial Point.<init>(II)V;
; astore 6 (set 'p')
Nested values (from "Value types for Java"):
final __ByValue class Path {
final Point start;
final Point end;
}
class Foo { // regular class
Path path; // value field
}
int startX = path.start.x;
; aload 0 ('this') // stack [ Foo ]
; getfield Foo.path // stack [ path ]
; vgetfield Path.start // stack [ start ]
; vgetfield Point.x // stack [ x ]
; istore 1 // stack [ ]
Array example (from "Value types for Java"):
Point[] points = new Point[100];
; bipush 100
; vnewarray Point
; astore 1 (store 'points')
points[3] = __MakeValue(2, 19);
; aload 1 ('points')
; iconst_3
; iconst_2
; bipush 19
; invokestatic Point.<new>(II)QPoint;
; vastore
"Project Panama: Interconnecting JVM and native code"
But also:
This mail nicely explains the relation between the various subprojects.