changeset 14419:443cb527b092

Struct reimplementation - now uses Pointer/Reference instead of Unsafe
author mikael
date Wed, 11 May 2016 10:13:59 -0700
parents f42e35d93d13
children 875ba50f0ddd
files src/java.base/share/classes/java/nicl/HeapScope.java src/java.base/share/classes/java/nicl/NativeLibrary.java src/java.base/share/classes/java/nicl/NativeScope.java src/java.base/share/classes/java/nicl/Scope.java src/java.base/share/classes/java/nicl/types/Pointer.java src/java.base/share/classes/java/nicl/types/Transformer.java src/java.base/share/classes/jdk/internal/nicl/Errno.java src/java.base/share/classes/jdk/internal/nicl/MethodImplGenerator.java src/java.base/share/classes/jdk/internal/nicl/NativeLibraryImpl.java src/java.base/share/classes/jdk/internal/nicl/StructImplGenerator.java src/java.base/share/classes/jdk/internal/nicl/UpcallHandler.java src/java.base/share/classes/jdk/internal/nicl/types/BoundedMemoryRegion.java src/java.base/share/classes/jdk/internal/nicl/types/BoundedPointer.java src/java.base/share/classes/jdk/internal/nicl/types/LayoutTypeImpl.java src/java.base/share/classes/jdk/internal/nicl/types/ReferenceImpl.java src/java.base/share/classes/jdk/internal/nicl/types/UncheckedPointer.java src/jdk.jextract/share/classes/com/sun/tools/jextract/JType.java test/java/nicl/System/UnixSystem.java test/java/nicl/Upcall/CallbackSort.java test/java/nicl/Upcall/StructUpcall.java test/java/nicl/types/StructTest.java
diffstat 21 files changed, 952 insertions(+), 512 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/nicl/HeapScope.java	Wed May 11 10:13:59 2016 -0700
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.nicl;
+
+import java.nicl.types.LayoutType;
+import java.nicl.types.MemoryRegion;
+import java.nicl.types.Pointer;
+import java.nicl.types.Reference;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.nicl.Util;
+import jdk.internal.nicl.types.BoundedMemoryRegion;
+import jdk.internal.nicl.types.BoundedPointer;
+import jdk.internal.nicl.types.LayoutTypeImpl;
+import jdk.internal.nicl.types.ReferenceImpl;
+import jdk.internal.nicl.types.Types;
+
+public class HeapScope implements Scope {
+    private final static Unsafe U = Unsafe.getUnsafe();
+
+    private boolean isAlive = true;
+
+    public HeapScope() {
+    }
+
+    @Override
+    public void checkAlive() {
+        if (!isAlive) {
+            throw new RuntimeException("Scope is not alive");
+        }
+    }
+
+    @Override
+    public void startAllocation() {
+        // FIXME:
+        throw new UnsupportedOperationException("NIY");
+    }
+
+    @Override
+    public void endAllocation() {
+        // FIXME:
+        throw new UnsupportedOperationException("NIY");
+    }
+
+    private BoundedMemoryRegion allocateRegion(long size) {
+        long allocSize = Util.alignUp(size, 8);
+
+        long nElems = allocSize / 8;
+        if (nElems > Integer.MAX_VALUE) {
+            throw new UnsupportedOperationException("allocate size to large");
+        }
+
+        long[] arr = new long[(int)nElems];
+        return new BoundedMemoryRegion(arr, Unsafe.ARRAY_LONG_BASE_OFFSET, allocSize, MemoryRegion.MODE_RW, this);
+    }
+
+    @Override
+    public <T> Pointer<T> allocate(LayoutType<T> type, long count) {
+        // Sanity check for now, can be removed/loosened if needed
+        long size = type.getType().getSize();
+        if (size < 0) {
+            throw new UnsupportedOperationException("Unknown size for type " + type);
+        }
+
+        size *= count;
+        if (size > Integer.MAX_VALUE) {
+            throw new UnsupportedOperationException("allocate size to large");
+        }
+
+        return new BoundedPointer<T>(type, allocateRegion(size));
+    }
+
+    @Override
+    public <T extends Reference<T>> T allocateStruct(LayoutType<T> type) {
+        long size = Util.alignUp(Util.sizeof(type.getCarrierType()), 8);
+        BoundedPointer<T> p = new BoundedPointer<T>(type, allocateRegion(size), 0);
+        return p.deref();
+    }
+
+    @Override
+    public void close() {
+        isAlive = false;
+    }
+}
--- a/src/java.base/share/classes/java/nicl/NativeLibrary.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/java/nicl/NativeLibrary.java	Wed May 11 10:13:59 2016 -0700
@@ -180,7 +180,7 @@
         if ((offset % t.getType().getSize()) != 0) {
             throw new IllegalArgumentException("Invalid offset: " + offset);
         }
-        return struct.ptr().cast(t).offset(offset / t.getType().getSize()).deref().get();
+        return struct.ptr().cast(t).offset(offset / t.getType().getSize()).lvalue().get();
     }
 
     @Deprecated
@@ -189,7 +189,52 @@
         if ((offset % t.getType().getSize()) != 0) {
             throw new IllegalArgumentException("Invalid offset: " + offset);
         }
-        struct.ptr().cast(t).offset(offset / t.getType().getSize()).deref().set(value);
+        struct.ptr().cast(t).offset(offset / t.getType().getSize()).lvalue().set(value);
+    }
+
+    @Deprecated
+    public static <T> Reference<T> buildRef(Pointer<?> p, long offset, LayoutType<T> type) {
+        return buildPtr(p, offset, type).lvalue();
+    }
+
+    @Deprecated
+    public static <T> Pointer<T> buildPtr(Pointer<?> p, long offset, LayoutType<T> type) {
+        return p
+            .cast(NativeLibrary.createLayout(byte.class))
+            .offset(offset)
+            .cast(type);
+    }
+
+    @Deprecated
+    public static void copyFromArray(int[] src, Pointer<?> p, long offset, int nElems) {
+        Pointer<Integer> dst = buildPtr(p, offset, NativeLibrary.createLayout(int.class));
+        for (int i = 0; i < nElems; i++) {
+            dst.offset(i).lvalue().set(src[i]);
+        }
+    }
+
+    @Deprecated
+    public static void copyToArray(Pointer<?> p, long offset, int[] dst, int nElems) {
+        Pointer<Integer> src = buildPtr(p, offset, NativeLibrary.createLayout(int.class));
+        for (int i = 0; i < nElems; i++) {
+            dst[i] = src.offset(i).lvalue().get();
+        }
+    }
+
+    @Deprecated
+    public static <T> void copyFromArray(T[] src, Pointer<?> p, long offset, int nElems, Class<T> elementType) {
+        Pointer<T> dst = buildPtr(p, offset, NativeLibrary.createLayout(elementType));
+        for (int i = 0; i < nElems; i++) {
+            dst.offset(i).lvalue().set(src[i]);
+        }
+    }
+
+    @Deprecated
+    public static <T> void copyToArray(Pointer<?> p, long offset, T[] dst, int nElems, Class<T> elementType) {
+        Pointer<T> src = buildPtr(p, offset, NativeLibrary.createLayout(elementType));
+        for (int i = 0; i < nElems; i++) {
+            dst[i] = src.offset(i).lvalue().get();
+        }
     }
 
     public static int errno() {
--- a/src/java.base/share/classes/java/nicl/NativeScope.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/java/nicl/NativeScope.java	Wed May 11 10:13:59 2016 -0700
@@ -108,7 +108,7 @@
     }
 
     private BoundedMemoryRegion allocateRegion(long size) {
-        return new BoundedMemoryRegion(allocate(size), size);
+        return new BoundedMemoryRegion(allocate(size), size, this);
     }
 
     @Override
@@ -126,29 +126,12 @@
 
         return new BoundedPointer<T>(type, allocateRegion(size));
     }
-/*
+
     @Override
-    public <T> Pointer<T> allocate(LayoutType<T> type) {
-        if (type.getCarrierType().isPrimitive()) {
-            return allocate(type, Util.sizeof(type.getCarrierType()));
-        } else if (Pointer.class.isAssignableFrom(type.getCarrierType())) {
-            return allocate(type, U.addressSize());
-        } else if (Util.isCStruct(type.getCarrierType())) {
-            return allocateStruct(type).ptr();
-        }
-
-        throw new IllegalArgumentException("Unhandled type: " + type.getCarrierType());
-    }
-*/
-    @Override
-    public <T> Reference<T> allocateStruct(LayoutType<T> type) {
-        Class<? extends Reference<T>> implClass = NativeLibrary.getStructImplClass(type.getCarrierType());
-
-        try {
-            return implClass.newInstance();
-        } catch (InstantiationException | IllegalAccessException e) {
-            throw new RuntimeException(e);
-        }
+    public <T extends Reference<T>> T allocateStruct(LayoutType<T> type) {
+        long size = Util.alignUp(Util.sizeof(type.getCarrierType()), 8);
+        BoundedPointer<T> p = new BoundedPointer<T>(type, allocateRegion(size), 0);
+        return p.deref();
     }
 
     @Override
--- a/src/java.base/share/classes/java/nicl/Scope.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/java/nicl/Scope.java	Wed May 11 10:13:59 2016 -0700
@@ -54,7 +54,7 @@
     // FIXME: When .ptr().deref works as expected for structs (returns
     // an actual struct instance instead of a ReferenceImpl instance)
     // this can be removed
-    public <T> Reference<T> allocateStruct(LayoutType<T> type);
+    public <T extends Reference<T>> T allocateStruct(LayoutType<T> type);
 
     @Override
     public void close();
--- a/src/java.base/share/classes/java/nicl/types/Pointer.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/java/nicl/types/Pointer.java	Wed May 11 10:13:59 2016 -0700
@@ -36,5 +36,6 @@
 
     long addr(PointerToken token) throws IllegalAccessException;
 
-    Reference<T> deref();
+    Reference<T> lvalue();
+    T deref();
 }
--- a/src/java.base/share/classes/java/nicl/types/Transformer.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/java/nicl/types/Transformer.java	Wed May 11 10:13:59 2016 -0700
@@ -45,7 +45,7 @@
         ByteArrayOutputStream os = new ByteArrayOutputStream();
 
         byte b;
-        for (int i = 0; (b = cstr.offset(i).deref().get()) != 0; i++) {
+        for (int i = 0; (b = cstr.offset(i).lvalue().get()) != 0; i++) {
             os.write(b);
         }
         return os.toString();
@@ -61,7 +61,7 @@
         }
         // FIXME: Provide a helper copy somewhere which takes pointer arguments
         UNSAFE.copyMemory(ar, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, addr, ar.length);
-        buf.offset(ar.length).deref().set((byte)0);
+        buf.offset(ar.length).lvalue().set((byte)0);
 
         return buf;
     }
@@ -85,7 +85,7 @@
             ar.length);
         for (int i = 0; i < ar.length; i++) {
             Pointer<Byte> s = toCString(ar[i], scope);
-            ptr.offset(i).deref().set(s);
+            ptr.offset(i).lvalue().set(s);
         }
         scope.endAllocation();
         return ptr;
--- a/src/java.base/share/classes/jdk/internal/nicl/Errno.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/nicl/Errno.java	Wed May 11 10:13:59 2016 -0700
@@ -36,7 +36,7 @@
         String osName = System.getProperty("os.name");
         switch (osName) {
         case "Linux": return "__errno_location";
-            //case "Mac OS X": return "dyld_stub___error";
+            //case "Mac OS X": return "__error"; // FIXME: this is cheating
         case "Windows": return null; // no errno here
         default:
             return null;
@@ -64,7 +64,7 @@
     public int errno() {
         try {
             Pointer<Integer> p = NativeLibrary.createPtr((long)errnoMH.invoke(), LayoutTypeImpl.create(int.class));
-            return p.deref().get();
+            return p.lvalue().get();
         } catch (Throwable t) {
             throw new RuntimeException(t);
         }
--- a/src/java.base/share/classes/jdk/internal/nicl/MethodImplGenerator.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/nicl/MethodImplGenerator.java	Wed May 11 10:13:59 2016 -0700
@@ -27,6 +27,7 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.reflect.Method;
+import java.nicl.HeapScope;
 import java.nicl.NativeLibrary;
 import java.nicl.NativeScope;
 import java.nicl.Scope;
@@ -243,7 +244,7 @@
         // If returning a struct, allocate it first
         if (Util.isCStruct(methodType.returnType())) {
             // FIXME: Wrap scope in try-with-resources style handler + call close
-            allocateScope(scopeVarIndex);
+            allocateScope(NativeScope.class, scopeVarIndex);
             allocateStruct(methodType.returnType(), scopeVarIndex, structReturnVarIndex);
         }
 
@@ -266,6 +267,13 @@
         mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MethodHandle.class), "invokeExact", INVOKER_METHOD_TYPE.toMethodDescriptorString(), false);
 
         processReturnValue();
+
+        if (Util.isCStruct(methodType.returnType())) {
+            mv.visitVarInsn(ALOAD, scopeVarIndex);
+            // FIXME (STRUCT-LIFECYCLE):
+            // Leak the allocoated structs for now until the life cycle has been figured out
+            mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Scope.class), "close", Type.getMethodDescriptor(Type.VOID_TYPE), true);
+        }
     }
 
     /**
@@ -293,6 +301,35 @@
         }
     }
 
+    private void copyStructToHeap(int structVarIndex, Class<?> structClass) {
+        /**
+         * FIXME (STRUCT-LIFECYCLE):
+         *
+         * This is disable for now - but there needs to be some amount
+         * of magic here to copy the struct to the heap so that it
+         * survives back up to the caller.
+         */
+        // Nativelibrary.copy(struct.ptr(), new NativeScope().allocateStruct(NativeLibrary.createLayout(structClass)).ptr(), structSize);
+        // FIXME: Hack for now to make struct survive return and not cause problems later when calling c functions
+
+        /*
+        allocateScope(NativeScope.class);
+        allocateStruct(structClass);
+        mv.visitInsn(DUP); // Leave a copy of the struct on top-of-stack
+
+        mv.visitVarInsn(ALOAD, structVarIndex);
+        mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Reference.class), "ptr", Type.getMethodDescriptor(Type.getType(Pointer.class)), true);
+
+        mv.visitInsn(SWAP);
+
+        mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Reference.class), "ptr", Type.getMethodDescriptor(Type.getType(Pointer.class)), true);
+
+        mv.visitLdcInsn(Util.sizeof(structClass));
+        mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "copy", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Pointer.class), Type.getType(Pointer.class), Type.LONG_TYPE), false);
+        */
+        mv.visitVarInsn(ALOAD, structVarIndex);
+    }
+
     /**
      * Extract any return values from the return values array and generate a suitable return instruction
      */
@@ -348,7 +385,7 @@
             mv.visitInsn(ARETURN);
         } else if (Util.isCStruct(methodType.returnType())) {
             if (callingSequence.returnsInMemory()) {
-                // Nothing to do - struct was filled in by callee
+                copyStructToHeap(structReturnVarIndex, methodType.returnType());
             } else {
                 int curValueArrayIndex = 0;
 
@@ -360,9 +397,9 @@
                         curValueArrayIndex += binding.getStorage().getSize() / 8;
                     }
                 }
+                mv.visitVarInsn(ALOAD, structReturnVarIndex);
             }
 
-            mv.visitVarInsn(ALOAD, structReturnVarIndex);
             mv.visitInsn(ARETURN);
         } else if (NativeLibraryImpl.isFunctionalInterface(methodType.returnType())) {
             // FIXME: Need to figure out if the FI is Java or Native
@@ -504,6 +541,8 @@
             default:
                 throw new UnsupportedOperationException("NYI: " + c.getName());
             }
+        } else if (c.isArray()) {
+            throw new IllegalArgumentException("Array types NIY: " + c);
         } else if (Pointer.class.isAssignableFrom(c)) {
             mv.visitIntInsn(ALOAD, localVar);
             mv.visitFieldInsn(GETSTATIC, className, tokenFieldName, Type.getDescriptor(PointerToken.class));
@@ -526,35 +565,67 @@
     }
 
     /**
+     * Allocate a scope, and leave it at top of stack
+     *
+     * @param varIndex the index of the local variable where the scope will be stored
+     */
+    private void allocateScope(Class<? extends Scope> c) {
+        mv.visitTypeInsn(NEW, Type.getInternalName(c));
+        mv.visitInsn(DUP);
+        mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(c), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE), false);
+    }
+
+    /**
      * Allocate a scope, and store it in the local variable
      *
      * @param varIndex the index of the local variable where the scope will be stored
      */
-    private void allocateScope(int scopeVarIndex) {
-        mv.visitTypeInsn(NEW, Type.getInternalName(NativeScope.class));
-        mv.visitInsn(DUP);
-        mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(NativeScope.class), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE), false);
+    private void allocateScope(Class<? extends Scope> c, int scopeVarIndex) {
+        allocateScope(c);
         mv.visitVarInsn(ASTORE, scopeVarIndex);
     }
 
     /**
-     * Allocate a struct, and store it in the local variable
+     * Allocate a struct from the scope at top-of-stack
      *
      * @param c the type of the struct
      * @param varIndex the index of the local variable where the struct will be stored
      */
-    private void allocateStruct(Class<?> c, int scopeVarIndex, int varIndex) {
+    private void allocateStruct(Class<?> c) {
         if (!Util.isCStruct(c)) {
             throw new IllegalArgumentException("Unhandled type: " + c.getName());
         }
 
         // Allocate struct
         mv.visitLdcInsn(Type.getType(c));
-        mv.visitVarInsn(ALOAD, scopeVarIndex);
-        mv.visitLdcInsn(Type.getType(c));
         mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "createLayout", Type.getMethodDescriptor(Type.getType(LayoutType.class), Type.getType(Class.class)), false);
         mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Scope.class), "allocateStruct", Type.getMethodDescriptor(Type.getType(Reference.class), Type.getType(LayoutType.class)), true);
+
+        mv.visitLdcInsn(Type.getType(c));
+        mv.visitInsn(SWAP);
         mv.visitTypeInsn(CHECKCAST, Type.getInternalName(c));
+    }
+
+    /**
+     * Allocate a struct from the scope
+     *
+     * @param c the type of the struct
+     * @param scopeVarIndex the index of the local variable where the scope is stored
+     */
+    private void allocateStruct(Class<?> c, int scopeVarIndex) {
+        mv.visitVarInsn(ALOAD, scopeVarIndex);
+        allocateStruct(c);
+    }
+
+    /**
+     * Allocate a struct from the scope, and store it in a local variable
+     *
+     * @param c the type of the struct
+     * @param scopeVarIndex the index of the local variable where the scope is stored
+     * @param varIndex the index of the local variable where the struct will be stored
+     */
+    private void allocateStruct(Class<?> c, int scopeVarIndex, int varIndex) {
+        allocateStruct(c, scopeVarIndex);
         mv.visitVarInsn(ASTORE, varIndex);
     }
 
--- a/src/java.base/share/classes/jdk/internal/nicl/NativeLibraryImpl.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/nicl/NativeLibraryImpl.java	Wed May 11 10:13:59 2016 -0700
@@ -270,6 +270,12 @@
                 throw new IllegalArgumentException("Failed to look up native type for " + carrierType.getName());
             }
             return type;
+        } else if (carrierType.isArray()) {
+            Class<?> componentType = carrierType.getComponentType();
+            if (!componentType.isPrimitive()) {
+                throw new IllegalArgumentException("Unhandled component type: " + componentType);
+            }
+            return getNativeTypeFor(componentType).getPointerType();
         } else if (Pointer.class.isAssignableFrom(carrierType)) {
             // FIXME: Use correct pointer type here?
             return Types.Cvoid_ptr;
@@ -284,7 +290,7 @@
         }
     }
 
-    static boolean isVectorType(Class<?> c) {
+    public static boolean isVectorType(Class<?> c) {
         return c == Long2.class || c == Long4.class || c == Long8.class;
     }
 
@@ -300,7 +306,7 @@
         throw new IllegalArgumentException("Unhandled vector type: " + c.getName());
     }
 
-    static int getVectorSize(Class<?> c) {
+    public static int getVectorSize(Class<?> c) {
         return (int) getVectorTypeFor(c).getSize();
     }
 
--- a/src/java.base/share/classes/jdk/internal/nicl/StructImplGenerator.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/nicl/StructImplGenerator.java	Wed May 11 10:13:59 2016 -0700
@@ -35,8 +35,10 @@
 import java.nicl.types.LayoutType;
 import java.nicl.types.Pointer;
 import java.nicl.types.PointerToken;
+import java.nicl.types.Reference;
 import java.util.Collections;
 import java.util.stream.Stream;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.nicl.types.PointerTokenImpl;
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.ClassWriter;
@@ -45,18 +47,14 @@
 import jdk.internal.org.objectweb.asm.Type;
 import jdk.internal.org.objectweb.asm.commons.GeneratorAdapter;
 import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
-import jdk.internal.misc.Unsafe;
 
 class StructImplGenerator implements ImplGenerator {
 
     private static final boolean DEBUG = Boolean.getBoolean("jdk.internal.nicl.StructImplGenerator.DEBUG");
 
     private static final Unsafe U = Unsafe.getUnsafe();
-    private static final PointerToken TOKEN = new PointerTokenImpl();
-    private static final Type UNSAFE = Type.getType(Unsafe.class);
 
-    private static final String UNSAFE_FIELD_NAME = "U";
-    private static final String TOKEN_FIELD_NAME = "TOKEN";
+    private static final String POINTER_FIELD_NAME = "ptr";
 
     private final Class<?> hostClass;
     private final Class<?> c;
@@ -94,402 +92,271 @@
         doArraySetter(m, javaType, type, offset, (int) length, elementSize);
     }
 
+    private void allocArray(MethodVisitor mv, Class<?> componentType, int length) {
+        mv.visitLdcInsn(length);
+
+        if (componentType.isPrimitive()) {
+            switch (Type.getDescriptor(componentType)) {
+            case "I":
+                mv.visitIntInsn(NEWARRAY, T_INT);
+                break;
+            // FIXME: Add other primitives here
+            default:
+                throw new IllegalArgumentException("Unhandled type: " + componentType);
+            }
+        } else {
+            mv.visitTypeInsn(ANEWARRAY, Type.getInternalName(componentType));
+        }
+    }
+
     private void doArrayGetter(Method m, Class<?> javaType, java.lang.reflect.Type type, long offset, int length, long elementSize) {
         final Class<?> componentType = javaType.getComponentType();
-        GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC,
-                jdk.internal.org.objectweb.asm.commons.Method.getMethod(m),
-                null, null, cw);
-        mg.visitCode();
 
-        // locals: array, offset
-        int local_ar = mg.newLocal(Type.getType(javaType));
-        int local_i = mg.newLocal(Type.INT_TYPE);
-        int local_offset = mg.newLocal(Type.LONG_TYPE);
-        int local_unsafe = mg.newLocal(UNSAFE);
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, m.getName(), Type.getMethodDescriptor(Type.getType(m.getReturnType())), null, null);
+        mv.visitCode();
 
-        mg.getStatic(Type.getObjectType(implClassName), UNSAFE_FIELD_NAME, UNSAFE);
-        mg.storeLocal(local_unsafe);
+        allocArray(mv, componentType, length);
+        mv.visitVarInsn(ASTORE, 1);
 
-        jdk.internal.org.objectweb.asm.commons.Method unsafe_get;
-        // allocate array
-        mg.push(length);
-        if (componentType.isArray()) {
-            throw new UnsupportedOperationException("Not yet implemented");
-        } else if (componentType == Pointer.class) {
-            mg.newArray(Type.getType(componentType));
-            unsafe_get = new jdk.internal.org.objectweb.asm.commons.Method("getLong", Type.getMethodDescriptor(Type.LONG_TYPE, Type.LONG_TYPE));
-        } else if (componentType.isPrimitive()) {
-            mg.newArray(Type.getType(componentType));
-            String typeName = Character.toUpperCase(componentType.getSimpleName().charAt(0))
-                    + componentType.getSimpleName().substring(1);
-            unsafe_get = new jdk.internal.org.objectweb.asm.commons.Method(
-                    "get" + typeName,
-                    Type.getMethodDescriptor(Type.getType(componentType), Type.LONG_TYPE));
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitFieldInsn(GETFIELD, implClassName, POINTER_FIELD_NAME, Type.getDescriptor(Pointer.class));
+        mv.visitLdcInsn(offset);
+
+        mv.visitVarInsn(ALOAD, 1);
+
+        mv.visitLdcInsn(length);
+
+        if (componentType.isPrimitive()) {
+            switch (Type.getDescriptor(componentType)) {
+            case "I":
+                mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "copyToArray", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Pointer.class), Type.LONG_TYPE, Type.getType(int[].class), Type.INT_TYPE), false);
+                break;
+            // FIXME: Add other primitives here
+            default:
+                throw new UnsupportedOperationException("Unhandled component type: " + componentType);
+            }
         } else {
-            // FIXME: we should support struct type
-            // How do we ensure type to be native struct type?
-            throw new UnsupportedOperationException("Not yet implemented");
+            mv.visitLdcInsn(Type.getType(componentType));
+            mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "copyToArray", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Pointer.class), Type.LONG_TYPE, Type.getType(Object[].class), Type.INT_TYPE, Type.getType(Class.class)), false);
         }
-        mg.storeLocal(local_ar);
 
-        mg.loadThis();
-        mg.getField(Type.getObjectType(implClassName), "payload", Type.LONG_TYPE);
-        if (offset != 0) {
-            mg.push(offset);
-            mg.visitInsn(LADD);
-        }
-        mg.storeLocal(local_offset);
-        mg.push(0);
-        mg.storeLocal(local_i);
+        mv.visitVarInsn(ALOAD, 1);
 
-        // loop to populate array
-        Label loop_exit = new Label();
-        Label loop_start = mg.mark();
-        mg.loadLocal(local_i);
-        mg.push(length);
-        mg.ifICmp(GeneratorAdapter.GE, loop_exit);
-
-        mg.loadLocal(local_ar);
-        mg.loadLocal(local_i);
-        // value
-        mg.loadLocal(local_unsafe);
-        mg.loadLocal(local_offset);
-        if (componentType == Pointer.class) {
-            // FIXME? getAddress for pointer?
-            mg.invokeVirtual(UNSAFE, unsafe_get);
-            mg.visitLdcInsn(Type.getType(Type.getDescriptor(NativeLibraryImpl.getPointerTypeArgument(type))));
-            mg.invokeStatic(Type.getType(NativeLibrary.class),
-                new jdk.internal.org.objectweb.asm.commons.Method("createPtr",
-                    Type.getMethodDescriptor(Type.getType(Pointer.class), Type.LONG_TYPE, Type.getType(Class.class))
-                ));
-        } else if (componentType.isPrimitive()) {
-            mg.invokeVirtual(UNSAFE, unsafe_get);
-        }
-        mg.arrayStore(Type.getType(componentType));
-
-        mg.loadLocal(local_offset);
-        mg.push(elementSize);
-        mg.visitInsn(LADD);
-        mg.storeLocal(local_offset);
-        mg.iinc(local_i, 1);
-        mg.goTo(loop_start);
-
-        // done population
-        mg.mark(loop_exit);
-        mg.loadLocal(local_ar);
-        mg.visitInsn(ARETURN);
-        mg.endMethod();
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
     }
 
     private void doArraySetter(Method m, Class<?> javaType, java.lang.reflect.Type type, long offset, int length, long elementSize) {
         final Class<?> componentType = javaType.getComponentType();
-        GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC,
-                new jdk.internal.org.objectweb.asm.commons.Method(
-                        m.getName().replace("$get", "$set"),
-                        Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(javaType))),
-                null, null, cw);
-        mg.visitCode();
 
-        // locals: array, offset
-        int local_i = mg.newLocal(Type.INT_TYPE);
-        int local_offset = mg.newLocal(Type.LONG_TYPE);
-        int local_unsafe = mg.newLocal(UNSAFE);
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, m.getName().replace("$get", "$set"), Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(m.getReturnType())), null, null);
+        mv.visitCode();
 
-        mg.getStatic(Type.getObjectType(implClassName), UNSAFE_FIELD_NAME, UNSAFE);
-        mg.storeLocal(local_unsafe);
-
-        jdk.internal.org.objectweb.asm.commons.Method unsafe_put;
-        if (componentType.isArray()) {
-            throw new UnsupportedOperationException("Not yet implemented");
-        } else if (componentType == Pointer.class) {
-            unsafe_put = new jdk.internal.org.objectweb.asm.commons.Method("putLong", Type.getMethodDescriptor(Type.VOID_TYPE, Type.LONG_TYPE, Type.LONG_TYPE));
-        } else if (componentType.isPrimitive()) {
-            String typeName = Character.toUpperCase(componentType.getSimpleName().charAt(0))
-                    + componentType.getSimpleName().substring(1);
-            unsafe_put = new jdk.internal.org.objectweb.asm.commons.Method(
-                    "put" + typeName,
-                    Type.getMethodDescriptor(Type.VOID_TYPE, Type.LONG_TYPE, Type.getType(componentType)));
-        } else {
-            // FIXME: we should support struct type
-            // How do we ensure type to be native struct type?
-            throw new UnsupportedOperationException("Not yet implemented");
-        }
-
-        mg.loadThis();
-        mg.getField(Type.getObjectType(implClassName), "payload", Type.LONG_TYPE);
-        if (offset != 0) {
-            mg.push(offset);
-            mg.visitInsn(LADD);
-        }
-
-        mg.storeLocal(local_offset);
-        mg.push(0);
-        mg.storeLocal(local_i);
-
-        // loop to populate array
-        Label loop_exit = new Label();
-        Label loop_start = mg.mark();
-        mg.loadLocal(local_i);
-        mg.push(length);
-        mg.ifICmp(GeneratorAdapter.GE, loop_exit);
-
-        mg.loadLocal(local_unsafe);
-        mg.loadLocal(local_offset);
-
-        mg.loadArg(0);
-        mg.loadLocal(local_i);
-        mg.arrayLoad(Type.getType(componentType));
-
-        if (componentType == Pointer.class) {
-            mg.getStatic(Type.getObjectType(implClassName), TOKEN_FIELD_NAME, Type.getType(PointerToken.class));
-            mg.invokeStatic(Type.getType(NativeLibrary.class),
-                new jdk.internal.org.objectweb.asm.commons.Method("unpack",
-                    Type.getMethodDescriptor(Type.LONG_TYPE, Type.getType(Pointer.class), Type.getType(PointerToken.class))));
-        }
-        mg.invokeVirtual(UNSAFE, unsafe_put);
-
-        mg.loadLocal(local_offset);
-        mg.push(elementSize);
-        mg.visitInsn(LADD);
-        mg.storeLocal(local_offset);
-        mg.iinc(local_i, 1);
-        mg.goTo(loop_start);
-
-        // done population
-        mg.mark(loop_exit);
-        mg.visitInsn(RETURN);
-        mg.endMethod();
-    }
-
-    private void generateVectorGetter(MethodVisitor mv, long off, Class<?> javaType) {
-        int nLongs = NativeLibraryImpl.getVectorSize(javaType) / 8;
-        int unsafeVar = 1;
-        int addrVar = 2;
+        mv.visitVarInsn(ALOAD, 1);
 
         mv.visitVarInsn(ALOAD, 0);
-        mv.visitFieldInsn(GETFIELD, implClassName, "payload", Type.getDescriptor(long.class));
-        if (off != 0) {
-            mv.visitLdcInsn(off);
-            mv.visitInsn(LADD);
-        }
-        mv.visitVarInsn(LSTORE, addrVar);
+        mv.visitFieldInsn(GETFIELD, implClassName, POINTER_FIELD_NAME, Type.getDescriptor(Pointer.class));
+        mv.visitLdcInsn(offset);
 
-        mv.visitFieldInsn(GETSTATIC, implClassName, UNSAFE_FIELD_NAME, Type.getDescriptor(Unsafe.class));
-        mv.visitVarInsn(ASTORE, unsafeVar);
+        mv.visitLdcInsn(length);
 
-        for (int i = 0; i < nLongs; i++) {
-            mv.visitVarInsn(ALOAD, unsafeVar);
-            mv.visitVarInsn(LLOAD, addrVar);
-
-            if (i != 0) {
-                mv.visitLdcInsn((long) 8);
-                mv.visitInsn(LADD);
-
-                if (i < nLongs - 1) {
-                    // prepare for next iteration
-                    mv.visitInsn(DUP2);
-                    mv.visitVarInsn(LSTORE, addrVar);
-                }
+        if (componentType.isPrimitive()) {
+            switch (Type.getDescriptor(componentType)) {
+            case "I":
+                mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "copyFromArray", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(int[].class), Type.getType(Pointer.class), Type.LONG_TYPE, Type.INT_TYPE), false);
+                break;
+            // FIXME: Add other primitives here
+            default:
+                throw new UnsupportedOperationException("Unhandled component type: " + componentType);
             }
-
-            mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "getLong", Type.getMethodDescriptor(Type.LONG_TYPE, Type.LONG_TYPE), false);
-        }
-
-        mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(javaType), "make", Type.getMethodDescriptor(Type.getType(javaType), Collections.nCopies(nLongs, Type.LONG_TYPE).toArray(new Type[0])), false);
-        mv.visitInsn(ARETURN);
-    }
-
-    private void generateVectorSetter(MethodVisitor mv, long off, Class<?> javaType) {
-        int nLongs = NativeLibraryImpl.getVectorSize(javaType) / 8;
-        int unsafeVar = 2;
-        int addrVar = 3;
-
-        /*** FIXME: Remove this when vectors are stable ***/
-        if (DEBUG) {
-            mv.visitVarInsn(ALOAD, 1);
-            mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "printLong", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(javaType)), false);
-        }
-
-        mv.visitVarInsn(ALOAD, 0);
-        mv.visitFieldInsn(GETFIELD, implClassName, "payload", Type.getDescriptor(long.class));
-        if (off != 0) {
-            mv.visitLdcInsn(off);
-            mv.visitInsn(LADD);
-        }
-        mv.visitVarInsn(LSTORE, addrVar);
-
-        mv.visitFieldInsn(GETSTATIC, implClassName, UNSAFE_FIELD_NAME, Type.getDescriptor(Unsafe.class));
-        mv.visitVarInsn(ASTORE, unsafeVar);
-
-        for (int i = 0; i < nLongs; i++) {
-            mv.visitVarInsn(ALOAD, unsafeVar);
-            mv.visitVarInsn(LLOAD, addrVar);
-
-            if (i != 0) {
-                mv.visitLdcInsn((long) 8);
-                mv.visitInsn(LADD);
-
-                if (i < nLongs - 1) {
-                    // prepare for next iteration
-                    mv.visitInsn(DUP2);
-                    mv.visitVarInsn(LSTORE, addrVar);
-                }
-            }
-
-            mv.visitVarInsn(ALOAD, 1);
-            mv.visitLdcInsn(i);
-            mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(javaType), "extract", Type.getMethodDescriptor(Type.LONG_TYPE, Type.INT_TYPE), false);
-
-            mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "putLong", Type.getMethodDescriptor(Type.VOID_TYPE, Type.LONG_TYPE, Type.LONG_TYPE), false);
+        } else {
+            mv.visitLdcInsn(Type.getType(componentType));
+            mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "copyFromArray", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object[].class), Type.getType(Pointer.class), Type.LONG_TYPE, Type.INT_TYPE, Type.getType(Class.class)), false);
         }
 
         mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+    }
+
+    private void pushPrimitiveType(MethodVisitor mv, Class<?> c) {
+        switch (Type.getDescriptor(c)) {
+        case "V":
+            mv.visitFieldInsn(GETSTATIC, Type.getInternalName(Void.class), "TYPE", Type.getDescriptor(Class.class));
+            break;
+        case "Z":
+            mv.visitFieldInsn(GETSTATIC, Type.getInternalName(Boolean.class), "TYPE", Type.getDescriptor(Class.class));
+            break;
+        case "B":
+            mv.visitFieldInsn(GETSTATIC, Type.getInternalName(Byte.class), "TYPE", Type.getDescriptor(Class.class));
+            break;
+        case "C":
+            mv.visitFieldInsn(GETSTATIC, Type.getInternalName(Character.class), "TYPE", Type.getDescriptor(Class.class));
+            break;
+        case "S":
+            mv.visitFieldInsn(GETSTATIC, Type.getInternalName(Short.class), "TYPE", Type.getDescriptor(Class.class));
+            break;
+        case "I":
+            mv.visitFieldInsn(GETSTATIC, Type.getInternalName(Integer.class), "TYPE", Type.getDescriptor(Class.class));
+            break;
+        case "F":
+            mv.visitFieldInsn(GETSTATIC, Type.getInternalName(Float.class), "TYPE", Type.getDescriptor(Class.class));
+            break;
+        case "J":
+            mv.visitFieldInsn(GETSTATIC, Type.getInternalName(Long.class), "TYPE", Type.getDescriptor(Class.class));
+            break;
+        case "D":
+            mv.visitFieldInsn(GETSTATIC, Type.getInternalName(Double.class), "TYPE", Type.getDescriptor(Class.class));
+            break;
+
+        default:
+            throw new UnsupportedOperationException("Unhandled type: " + c.getName());
+        }
+    }
+
+    private void pushType(MethodVisitor mv, Class<?> c) {
+        if (c.isPrimitive()) {
+            pushPrimitiveType(mv, c);
+        } else {
+            mv.visitLdcInsn(Type.getType(c));
+        }
+    }
+
+    private void box(MethodVisitor mv, Class<?> c) {
+        if (c.isPrimitive()) {
+            switch (Type.getDescriptor(c)) {
+            case "V":
+                throw new IllegalArgumentException();
+            case "Z":
+                mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Boolean.class), "valueOf", Type.getMethodDescriptor(Type.getType(Boolean.class), Type.BOOLEAN_TYPE), false);
+                break;
+            case "B":
+                mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Byte.class), "valueOf", Type.getMethodDescriptor(Type.getType(Byte.class), Type.BYTE_TYPE), false);
+                break;
+            case "S":
+                mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Short.class), "valueOf", Type.getMethodDescriptor(Type.getType(Short.class), Type.SHORT_TYPE), false);
+                break;
+            case "C":
+                mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Character.class), "valueOf", Type.getMethodDescriptor(Type.getType(Character.class), Type.CHAR_TYPE), false);
+                break;
+            case "I":
+                mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf", Type.getMethodDescriptor(Type.getType(Integer.class), Type.INT_TYPE), false);
+                break;
+            case "F":
+                mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Float.class), "valueOf", Type.getMethodDescriptor(Type.getType(Float.class), Type.FLOAT_TYPE), false);
+                break;
+            case "J":
+                mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Long.class), "valueOf", Type.getMethodDescriptor(Type.getType(Long.class), Type.LONG_TYPE), false);
+                break;
+            case "D":
+                mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Double.class), "valueOf", Type.getMethodDescriptor(Type.getType(Double.class), Type.DOUBLE_TYPE), false);
+                break;
+            default:
+                throw new UnsupportedOperationException("Unhandled type: " + c);
+            }
+        } else {
+            throw new UnsupportedOperationException("Unhandled type: " + c);
+        }
+    }
+
+
+    private void unbox(MethodVisitor mv, Class<?> c) {
+        if (c.isPrimitive()) {
+            switch (Type.getDescriptor(c)) {
+            case "V":
+                throw new IllegalArgumentException();
+            case "Z":
+                mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Boolean.class));
+                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Boolean.class), "booleanValue", Type.getMethodDescriptor(Type.BOOLEAN_TYPE), false);
+                break;
+            case "B":
+                mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Byte.class));
+                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Byte.class), "byteValue", Type.getMethodDescriptor(Type.BYTE_TYPE), false);
+                break;
+            case "C":
+                mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Character.class));
+                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Character.class), "charValue", Type.getMethodDescriptor(Type.CHAR_TYPE), false);
+                break;
+            case "S":
+                mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Short.class));
+                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Short.class), "shortValue", Type.getMethodDescriptor(Type.SHORT_TYPE), false);
+                break;
+            case "I":
+                mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Integer.class));
+                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Integer.class), "intValue", Type.getMethodDescriptor(Type.INT_TYPE), false);
+                break;
+            case "F":
+                mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Float.class));
+                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Float.class), "floatValue", Type.getMethodDescriptor(Type.FLOAT_TYPE), false);
+                break;
+            case "J":
+                mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Long.class));
+                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Long.class), "longValue", Type.getMethodDescriptor(Type.LONG_TYPE), false);
+                break;
+            case "D":
+                mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Double.class));
+                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Double.class), "doubleValue", Type.getMethodDescriptor(Type.DOUBLE_TYPE), false);
+                break;
+            default:
+                throw new UnsupportedOperationException("Unhandled type: " + c);
+            }
+        }
+    }
+
+    private void pushRef(MethodVisitor mv, long off, Class<?> javaType) {
+        mv.visitVarInsn(ALOAD, 0);
+
+        mv.visitLdcInsn(off);
+        pushType(mv, javaType);
+        mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "createLayout", Type.getMethodDescriptor(Type.getType(LayoutType.class), Type.getType(Class.class)), false);
+
+        mv.visitMethodInsn(INVOKEVIRTUAL, implClassName, "ref", Type.getMethodDescriptor(Type.getType(Reference.class), Type.LONG_TYPE, Type.getType(LayoutType.class)), false);
     }
 
     private void generateGetter(MethodVisitor mv, long off, Class<?> javaType, java.lang.reflect.Type type, Method m) {
-        if (NativeLibraryImpl.isVectorType(javaType)) {
-            generateVectorGetter(mv, off, javaType);
-            return;
+        // return ref(<offset>, NativeLibrary.createLayout(<javaType>)).get();
+
+        pushRef(mv, off, javaType);
+
+        mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Reference.class), "get", Type.getMethodDescriptor(Type.getType(Object.class)), true);
+
+        if (javaType.isPrimitive()) {
+            unbox(mv, javaType);
+        } else {
+            mv.visitTypeInsn(CHECKCAST, Type.getInternalName(javaType));
         }
 
-        mv.visitFieldInsn(GETSTATIC, implClassName, UNSAFE_FIELD_NAME, Type.getDescriptor(Unsafe.class));
-
-        mv.visitVarInsn(ALOAD, 0);
-        mv.visitFieldInsn(GETFIELD, implClassName, "payload", Type.getDescriptor(long.class));
-        if (off != 0) {
-            mv.visitLdcInsn(off);
-            mv.visitInsn(LADD);
-        }
-
-        if (javaType.isPrimitive()) {
-            if (javaType == boolean.class) {
-                Label falseLabel = new Label();
-                Label doneLabel = new Label();
-                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "getByte", Type.getMethodDescriptor(Type.BYTE_TYPE, Type.LONG_TYPE), false);
-                mv.visitJumpInsn(IFEQ, falseLabel);
-                mv.visitInsn(ICONST_1);
-                mv.visitJumpInsn(GOTO, doneLabel);
-                mv.visitLabel(falseLabel);
-                mv.visitInsn(ICONST_0);
-                mv.visitLabel(doneLabel);
-            } else {
-                String typeName = Character.toUpperCase(javaType.getSimpleName().charAt(0)) + javaType.getSimpleName().substring(1);
-                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "get" + typeName, Type.getMethodDescriptor(Type.getType(javaType), Type.LONG_TYPE), false);
-            }
-            mv.visitInsn(NativeLibraryImpl.returnInsn(javaType));
-        } else if (javaType == Pointer.class) {
-            // FIXME? getAddress for pointer?
-            mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "getLong", Type.getMethodDescriptor(Type.LONG_TYPE, Type.LONG_TYPE), false);
-            mv.visitLdcInsn(Type.getType(Type.getDescriptor(NativeLibraryImpl.getPointerTypeArgument(type))));
-            mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "createPtr", Type.getMethodDescriptor(Type.getType(Pointer.class), Type.LONG_TYPE, Type.getType(Class.class)), false);
-            mv.visitInsn(ARETURN);
-        } else if (Util.isCStruct(javaType)) {
-            System.err.println("WARNING: Generating struct getter for struct field (untested!) " + m);
-            mv.visitLdcInsn(Type.getType(javaType));
-            mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "getLong", Type.getMethodDescriptor(Type.LONG_TYPE, Type.LONG_TYPE), false);
-            mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "createStruct", Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Class.class), Type.LONG_TYPE), false);
-            mv.visitTypeInsn(CHECKCAST, Type.getInternalName(javaType));
-            mv.visitInsn(ACONST_NULL);
-            mv.visitInsn(ARETURN);
-        } else if (NativeLibraryImpl.isFunctionalInterface(javaType)) {
-            System.err.println("WARNING: Generating struct getter for functional interface field (untested!): " + m);
-            mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "getLong", Type.getMethodDescriptor(Type.LONG_TYPE, Type.LONG_TYPE), false);
-            mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(UpcallHandler.class), "getHandler", Type.getMethodDescriptor(Type.getType(Object.class), Type.LONG_TYPE), false);
-            mv.visitTypeInsn(CHECKCAST, Type.getInternalName(javaType));
-            mv.visitInsn(ARETURN);
-        } else {
-            throw new UnsupportedOperationException("Unhandled type: " + javaType.getName());
-        }
+        mv.visitInsn(NativeLibraryImpl.returnInsn(javaType));
     }
 
     private void generateSetter(MethodVisitor mv, long off, Class<?> javaType, Method m) {
-        if (NativeLibraryImpl.isVectorType(javaType)) {
-            generateVectorSetter(mv, off, javaType);
-            return;
+        // ref(<offset>, NativeLibrary.createLayout(<javaType>)).set(<value>);
+
+        pushRef(mv, off, javaType);
+
+        mv.visitVarInsn(NativeLibraryImpl.loadInsn(javaType), 1);
+
+        if (javaType.isPrimitive()) {
+            box(mv, javaType);
         }
 
-        mv.visitFieldInsn(GETSTATIC, implClassName, UNSAFE_FIELD_NAME, Type.getDescriptor(Unsafe.class));
-
-        mv.visitVarInsn(ALOAD, 0);
-        mv.visitFieldInsn(GETFIELD, implClassName, "payload", Type.getDescriptor(long.class));
-        if (off != 0) {
-            mv.visitLdcInsn(off);
-            mv.visitInsn(LADD);
-        }
-
-        if (javaType.isPrimitive()) {
-            mv.visitVarInsn(NativeLibraryImpl.loadInsn(javaType), 1);
-
-            if (javaType == boolean.class) {
-                Label falseLabel = new Label();
-                Label doneLabel = new Label();
-                mv.visitJumpInsn(IFEQ, falseLabel);
-                mv.visitInsn(ICONST_1);
-                mv.visitJumpInsn(GOTO, doneLabel);
-                mv.visitLabel(falseLabel);
-                mv.visitInsn(ICONST_0);
-                mv.visitLabel(doneLabel);
-                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "putByte", Type.getMethodDescriptor(Type.VOID_TYPE, Type.LONG_TYPE, Type.BYTE_TYPE), false);
-            } else {
-                String typeName = Character.toUpperCase(javaType.getSimpleName().charAt(0)) + javaType.getSimpleName().substring(1);
-                mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "put" + typeName, Type.getMethodDescriptor(Type.VOID_TYPE, Type.LONG_TYPE, Type.getType(javaType)), false);
-            }
-        } else if (javaType == Pointer.class) {
-            mv.visitVarInsn(ALOAD, 1);
-            mv.visitFieldInsn(GETSTATIC, implClassName, TOKEN_FIELD_NAME, Type.getDescriptor(PointerToken.class));
-            mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "unpack", Type.getMethodDescriptor(Type.LONG_TYPE, Type.getType(Pointer.class), Type.getType(PointerToken.class)), false);
-            // FIXME? Should be putAddress for pointer?
-            mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "putLong", Type.getMethodDescriptor(Type.VOID_TYPE, Type.LONG_TYPE, Type.LONG_TYPE), false);
-        } else if (Util.isCStruct(javaType)) {
-            System.err.println("WARNING: Generating empty implementation for struct setter " + m);
-        } else if (NativeLibraryImpl.isFunctionalInterface(javaType)) {
-            mv.visitInsn(LCONST_0);
-            mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "putLong", Type.getMethodDescriptor(Type.VOID_TYPE, Type.LONG_TYPE, Type.LONG_TYPE), false);
-            System.err.println("WARNING: Generating empty implementation for functional interface setter " + m);
-        } else {
-            throw new UnsupportedOperationException("Unhandled type: " + javaType.getName());
-        }
+        mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Reference.class), "set", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object.class)), true);
 
         mv.visitInsn(RETURN);
     }
 
     private void generateConstructors() {
         {
-            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE), null, null);
+            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Pointer.class)), null, null);
             mv.visitCode();
 
             mv.visitVarInsn(ALOAD, 0);
             mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE), false);
 
             mv.visitVarInsn(ALOAD, 0);
-
-            // FIXME: Don't cheat here
-            /*
-            mv.visitFieldInsn(GETSTATIC, implClassName, UNSAFE_FIELD_NAME, Type.getDescriptor(Unsafe.class));
-            mv.visitLdcInsn(size);
-            mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Unsafe.class), "allocateMemory", Type.getMethodDescriptor(Type.LONG_TYPE, Type.LONG_TYPE), false);
-            */
-            mv.visitLdcInsn(size);
-            mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "allocateMemory", Type.getMethodDescriptor(Type.LONG_TYPE, Type.LONG_TYPE), false);
-
-            mv.visitFieldInsn(PUTFIELD, implClassName, "payload", Type.getDescriptor(long.class));
-
-            mv.visitInsn(RETURN);
-
-            mv.visitMaxs(0, 0);
-            mv.visitEnd();
-        }
-
-        {
-            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, Type.LONG_TYPE), null, null);
-            mv.visitCode();
-
-            mv.visitVarInsn(ALOAD, 0);
-            mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE), false);
-
-            mv.visitVarInsn(ALOAD, 0);
-            mv.visitVarInsn(LLOAD, 1);
-            mv.visitFieldInsn(PUTFIELD, implClassName, "payload", Type.getDescriptor(long.class));
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitFieldInsn(PUTFIELD, implClassName, POINTER_FIELD_NAME, Type.getDescriptor(Pointer.class));
 
             mv.visitInsn(RETURN);
 
@@ -527,6 +394,19 @@
             mv.visitMaxs(0, 0);
             mv.visitEnd();
         }
+
+        { // Reference
+            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, m.getName().replace("$get", "$ref"),
+                                              Type.getMethodDescriptor(Type.getType(Reference.class)), null, null);
+            mv.visitCode();
+
+            pushRef(mv, offset, javaType);
+
+            mv.visitInsn(ARETURN);
+
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+        }
     }
 
     private void generateFieldsAccessors() {
@@ -566,14 +446,15 @@
         }
 
         // Reference<T>.set()
+        // FIXME: Copy here?
         {
             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "set", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(c)), null, null);
             mv.visitCode();
             mv.visitVarInsn(ALOAD, 0);
             mv.visitVarInsn(ALOAD, 1);
             mv.visitTypeInsn(CHECKCAST, implClassName);
-            mv.visitFieldInsn(GETFIELD, implClassName, "payload", Type.getDescriptor(long.class));
-            mv.visitFieldInsn(PUTFIELD, implClassName, "payload", Type.getDescriptor(long.class));
+            mv.visitFieldInsn(GETFIELD, implClassName, POINTER_FIELD_NAME, Type.getDescriptor(Pointer.class));
+            mv.visitFieldInsn(PUTFIELD, implClassName, POINTER_FIELD_NAME, Type.getDescriptor(Pointer.class));
             mv.visitInsn(RETURN);
             mv.visitMaxs(0, 0);
             mv.visitEnd();
@@ -596,14 +477,29 @@
         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "ptr", Type.getMethodDescriptor(Type.getType(Pointer.class)), null, null);
         mv.visitCode();
         mv.visitVarInsn(ALOAD, 0);
-        mv.visitFieldInsn(GETFIELD, implClassName, "payload", Type.getDescriptor(long.class));
-        mv.visitLdcInsn(Type.getType(Type.getDescriptor(c)));
-        mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "createPtr", Type.getMethodDescriptor(Type.getType(Pointer.class), Type.LONG_TYPE, Type.getType(Class.class)), false);
+        mv.visitFieldInsn(GETFIELD, implClassName, POINTER_FIELD_NAME, Type.getDescriptor(Pointer.class));
         mv.visitInsn(ARETURN);
         mv.visitMaxs(0, 0);
         mv.visitEnd();
     }
 
+    private void generateRefHelper() {
+        // private <T> Reference<T> ref(long offset, LayoutType<T> t) {
+        //     return NativeLibrary.createRef(p, offset, t);
+        // }
+        MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "ref", Type.getMethodDescriptor(Type.getType(Reference.class), Type.LONG_TYPE, Type.getType(LayoutType.class)), null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitFieldInsn(GETFIELD, implClassName, POINTER_FIELD_NAME, Type.getDescriptor(Pointer.class));
+        mv.visitVarInsn(LLOAD, 1);
+        mv.visitVarInsn(ALOAD, 3);
+        mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(NativeLibrary.class), "buildRef", Type.getMethodDescriptor(Type.getType(Reference.class), Type.getType(Pointer.class), Type.LONG_TYPE, Type.getType(LayoutType.class)), false);
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+    }
+
+
     @Override
     public Class<?> generate() {
         this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
@@ -612,16 +508,14 @@
 
         cw.visit(52, ACC_PUBLIC | ACC_SUPER, implClassName, null, Type.getInternalName(Object.class), interfaceNames);
 
-        cw.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, UNSAFE_FIELD_NAME, Type.getDescriptor(Unsafe.class), null, null);
-        cw.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, TOKEN_FIELD_NAME, Type.getDescriptor(PointerToken.class), null, null);
-
         if (DEBUG) {
             System.out.println("Generating struct implementation class " + implClassName);
         }
 
-        cw.visitField(ACC_PRIVATE | ACC_FINAL, "payload", Type.getDescriptor(long.class), null, null);
+        cw.visitField(ACC_PRIVATE | ACC_FINAL, POINTER_FIELD_NAME, Type.getDescriptor(Pointer.class), null, null);
 
         generateConstructors();
+        generateRefHelper();
         generateFieldsAccessors();
         generateReferenceImpl();
         generatePointerGetter();
@@ -636,18 +530,6 @@
         Class<?> implCls = U.defineClass(implClassName, classFile, 0, classFile.length, hostClass.getClassLoader(), null);
         U.ensureClassInitialized(implCls);
 
-        try {
-            Field unsafeField = implCls.getDeclaredField(UNSAFE_FIELD_NAME);
-            long unsafeOffset = U.staticFieldOffset(unsafeField);
-            U.putObject(implCls, unsafeOffset, U);
-
-            Field tokenField = implCls.getDeclaredField(TOKEN_FIELD_NAME);
-            long tokenOffset = U.staticFieldOffset(tokenField);
-            U.putObject(implCls, tokenOffset, TOKEN);
-        } catch (NoSuchFieldException e) {
-            e.printStackTrace();
-        }
-
         return implCls;
     }
 }
--- a/src/java.base/share/classes/jdk/internal/nicl/UpcallHandler.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/nicl/UpcallHandler.java	Wed May 11 10:13:59 2016 -0700
@@ -109,8 +109,10 @@
             handler = ID2HANDLER.get(id);
         }
 
-        UpcallContext context = new UpcallContext(integers, vectors, stack, integerReturn, vectorReturn);
-        handler.invoke(context);
+        try (Scope scope = new NativeScope()) {
+            UpcallContext context = new UpcallContext(scope, integers, vectors, stack, integerReturn, vectorReturn);
+            handler.invoke(context);
+        }
     }
 
     private UpcallHandler(MethodHandle mh, int id) throws Throwable {
@@ -130,12 +132,12 @@
         private final Pointer<Long> integerReturns;
         private final Pointer<Long> vectorReturns;
 
-        UpcallContext(long integers, long vectors, long stack, long integerReturn, long vectorReturn) {
-            this.integers = new BoundedPointer<Long>(LONG_LAYOUT_TYPE, new BoundedMemoryRegion(integers, Constants.MAX_INTEGER_ARGUMENT_REGISTERS * Constants.INTEGER_REGISTER_SIZE), 0, MemoryRegion.MODE_R);
-            this.vectors = new BoundedPointer<Long>(LONG_LAYOUT_TYPE, new BoundedMemoryRegion(vectors, Constants.MAX_VECTOR_ARGUMENT_REGISTERS * Constants.VECTOR_REGISTER_SIZE), 0, MemoryRegion.MODE_R);
-            this.stack = new UncheckedPointer<Long>(LONG_LAYOUT_TYPE, stack, MemoryRegion.MODE_R);
-            this.integerReturns = new BoundedPointer<Long>(LONG_LAYOUT_TYPE, new BoundedMemoryRegion(integerReturn, Constants.MAX_INTEGER_RETURN_REGISTERS * Constants.INTEGER_REGISTER_SIZE), 0, MemoryRegion.MODE_W);
-            this.vectorReturns = new BoundedPointer<Long>(LONG_LAYOUT_TYPE, new BoundedMemoryRegion(vectorReturn, Constants.MAX_VECTOR_RETURN_REGISTERS * Constants.VECTOR_REGISTER_SIZE), 0, MemoryRegion.MODE_W);
+        UpcallContext(Scope scope, long integers, long vectors, long stack, long integerReturn, long vectorReturn) {
+            this.integers = new BoundedPointer<Long>(LONG_LAYOUT_TYPE, new BoundedMemoryRegion(integers, Constants.MAX_INTEGER_ARGUMENT_REGISTERS * Constants.INTEGER_REGISTER_SIZE, scope), 0, MemoryRegion.MODE_R);
+            this.vectors = new BoundedPointer<Long>(LONG_LAYOUT_TYPE, new BoundedMemoryRegion(vectors, Constants.MAX_VECTOR_ARGUMENT_REGISTERS * Constants.VECTOR_REGISTER_SIZE, scope), 0, MemoryRegion.MODE_R);
+            this.stack = new BoundedPointer<Long>(LONG_LAYOUT_TYPE, new BoundedMemoryRegion(stack, Long.MAX_VALUE - stack, scope), 0, MemoryRegion.MODE_R);
+            this.integerReturns = new BoundedPointer<Long>(LONG_LAYOUT_TYPE, new BoundedMemoryRegion(integerReturn, Constants.MAX_INTEGER_RETURN_REGISTERS * Constants.INTEGER_REGISTER_SIZE, scope), 0, MemoryRegion.MODE_W);
+            this.vectorReturns = new BoundedPointer<Long>(LONG_LAYOUT_TYPE, new BoundedMemoryRegion(vectorReturn, Constants.MAX_VECTOR_RETURN_REGISTERS * Constants.VECTOR_REGISTER_SIZE, scope), 0, MemoryRegion.MODE_W);
         }
 
         Pointer<Long> getPtr(Storage storage) {
@@ -169,40 +171,35 @@
         if (carrierType.isPrimitive()) {
             switch (Type.getDescriptor(carrierType)) {
                 case "Z":
-                    return src.cast(new LayoutTypeImpl<Boolean>(boolean.class, Types.BOOLEAN)).deref().get();
+                    return src.cast(new LayoutTypeImpl<Boolean>(boolean.class, Types.BOOLEAN)).lvalue().get();
 
                 case "B":
-                    return src.cast(new LayoutTypeImpl<Byte>(byte.class, Types.BYTE)).deref().get();
+                    return src.cast(new LayoutTypeImpl<Byte>(byte.class, Types.BYTE)).lvalue().get();
 
                 case "S":
-                    return src.cast(new LayoutTypeImpl<Short>(short.class, Types.SHORT)).deref().get();
+                    return src.cast(new LayoutTypeImpl<Short>(short.class, Types.SHORT)).lvalue().get();
 
                 case "C":
-                    return src.cast(new LayoutTypeImpl<Character>(char.class, Types.UNSIGNED.SHORT)).deref().get();
+                    return src.cast(new LayoutTypeImpl<Character>(char.class, Types.UNSIGNED.SHORT)).lvalue().get();
 
                 case "I":
-                    return src.cast(new LayoutTypeImpl<Integer>(int.class, Types.INT32)).deref().get();
+                    return src.cast(new LayoutTypeImpl<Integer>(int.class, Types.INT32)).lvalue().get();
 
                 case "J":
-                    return src.cast(new LayoutTypeImpl<Long>(long.class, Types.INT64)).deref().get();
+                    return src.cast(new LayoutTypeImpl<Long>(long.class, Types.INT64)).lvalue().get();
 
                 case "F":
-                    return src.cast(new LayoutTypeImpl<Float>(float.class, Types.FLOAT)).deref().get();
+                    return src.cast(new LayoutTypeImpl<Float>(float.class, Types.FLOAT)).lvalue().get();
 
                 case "D":
-                    return src.cast(new LayoutTypeImpl<Double>(double.class, Types.DOUBLE)).deref().get();
+                    return src.cast(new LayoutTypeImpl<Double>(double.class, Types.DOUBLE)).lvalue().get();
 
                 default:
                     throw new UnsupportedOperationException("Unhandled type: " + carrierType.getName());
             }
         } else if (Pointer.class.isAssignableFrom(carrierType)) {
-            return BoundedPointer.createNativeVoidPointer(src.deref().get());
+            return BoundedPointer.createNativeVoidPointer(src.lvalue().get());
         } else if (NativeLibraryImpl.isVectorType(carrierType)) {
-            long size = NativeLibraryImpl.getVectorSize(carrierType);
-            int nElems = (int)(size / 8);
-
-            long[] bits = new long[nElems];
-
             // FIXME: Work-around for now - the method is called once per stack slot,
             // so we need to return the same vector value all the time
             if ((binding.getOffset() % LONG_LAYOUT_TYPE.getType().getSize()) != 0) {
@@ -210,25 +207,31 @@
             }
             Pointer<Long> baseAddress = src.offset(-(binding.getOffset() / LONG_LAYOUT_TYPE.getType().getSize()));
 
-            Pointer<Long> arrPtr = NativeLibrary.createArrayElementsPointer(bits);
-            NativeLibrary.copy(baseAddress, arrPtr, size);
+            int nElems = NativeLibraryImpl.getVectorSize(carrierType) / 8;
 
             switch (nElems) {
-                case 2:
-                    return Long2.make(bits[0], bits[1]);
-                case 4:
-                    return Long4.make(bits[0], bits[1], bits[2], bits[3]);
-                case 8:
-                    return Long8.make(bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]);
-                default:
-                    throw new UnsupportedOperationException("Unhandled vector size (" + nElems + ") for type " + carrierType.getName());
+            case 2:
+                return baseAddress.cast(NativeLibrary.createLayout(Long2.class)).lvalue().get();
+            case 4:
+                return baseAddress.cast(NativeLibrary.createLayout(Long4.class)).lvalue().get();
+            case 8:
+                return baseAddress.cast(NativeLibrary.createLayout(Long8.class)).lvalue().get();
+            default:
+                throw new UnsupportedOperationException("Unhandled vector size (" + nElems + ") for type " + carrierType.getName());
             }
         } else if (Util.isCStruct(carrierType)) {
             int index = binding.getMember().getArgumentIndex();
             Reference<?> r = structs[index];
             if (r == null) {
+                /**
+                 * FIXME (STRUCT-LIFECYCLE):
+                 *
+                 * Leak memory for now
+                 */
+                scope = new NativeScope();
+
                 @SuppressWarnings({"rawtypes", "unchecked"})
-                Reference<?> rtmp = scope.allocateStruct(new LayoutTypeImpl(carrierType, null));
+                Reference<?> rtmp = scope.allocateStruct(NativeLibrary.createLayout((Class)carrierType));
                 
                 structs[index] = r = rtmp;
             }
@@ -275,8 +278,10 @@
     }
 
     private void copy(long bits, Pointer<Long> dst) {
-        Pointer<Long> src = NativeLibrary.createArrayElementsPointer(new long[] { bits });
-        copy(src, dst, 8);
+        try (Scope scope = new NativeScope()) {
+            Pointer<Long> src = NativeLibrary.createArrayElementsPointer(new long[] { bits }, scope);
+            copy(src, dst, 8);
+        }
     }
 
     private void copy(Pointer<Long> src, Pointer<Long> dst, long bytes) {
@@ -336,36 +341,24 @@
                 throw new RuntimeException(e);
             }
 
-            dst.deref().set(addr);
+            dst.lvalue().set(addr);
         } else if (NativeLibraryImpl.isVectorType(c)) {
-            int nElems = (int) (binding.getStorage().getSize() / 8);
-            long[] bits = new long[nElems];
+            long size = NativeLibraryImpl.getVectorSize(c);
+            int nElems = (int)(size / 8);
 
             switch (nElems) {
-                case 2:
-                    for (int i = 0; i < nElems; i++) {
-                        bits[i] = ((Long2) o).extract(i);
-                    }
-                    break;
-
-                case 4:
-                    for (int i = 0; i < nElems; i++) {
-                        bits[i] = ((Long4) o).extract(i);
-                    }
-                    break;
-
-                case 8:
-                    for (int i = 0; i < nElems; i++) {
-                        bits[i] = ((Long8) o).extract(i);
-                    }
-                    break;
-
-                default:
-                    throw new IllegalArgumentException("Unhandled vector size (" + nElems + ") for type " + c.getName());
+            case 2:
+                dst.cast(NativeLibrary.createLayout(Long2.class)).lvalue().set((Long2)o);
+                break;
+            case 4:
+                dst.cast(NativeLibrary.createLayout(Long4.class)).lvalue().set((Long4)o);
+                break;
+            case 8:
+                dst.cast(NativeLibrary.createLayout(Long8.class)).lvalue().set((Long8)o);
+                break;
+            default:
+                throw new IllegalArgumentException("Unhandled vector size (" + nElems + ") for type " + c.getName());
             }
-
-            Pointer<Long> src = NativeLibrary.createArrayElementsPointer(bits);
-            NativeLibrary.copy(src, dst, bits.length * 8);
         } else if (Util.isCStruct(c)) {
             boolean returnsInMemory = CallingSequence.make(MethodType.methodType(c), 0).returnsInMemory();
 
@@ -375,7 +368,7 @@
 
             if (returnsInMemory) {
                 // the first integer argument register contains a pointer to caller allocated struct
-                long structAddr = context.getPtr(new Storage(StorageClass.INTEGER_ARGUMENT_REGISTER, 0, Constants.INTEGER_REGISTER_SIZE)).deref().get();
+                long structAddr = context.getPtr(new Storage(StorageClass.INTEGER_ARGUMENT_REGISTER, 0, Constants.INTEGER_REGISTER_SIZE)).lvalue().get();
 
                 // FIXME: 32-bit support goes here
                 long size = Util.alignUp(Util.sizeof(c), 8);
@@ -385,7 +378,7 @@
 
                 // the first integer return register needs to be populated with the (caller supplied) struct addr
                 Pointer<Long> retRegPtr = context.getPtr(new Storage(StorageClass.INTEGER_RETURN_REGISTER, 0, Constants.INTEGER_REGISTER_SIZE));
-                retRegPtr.deref().set(structAddr);
+                retRegPtr.lvalue().set(structAddr);
             } else {
                 if ((binding.getOffset() % LONG_LAYOUT_TYPE.getType().getSize()) != 0) {
                     throw new Error("Invalid offset: " + binding.getOffset());
@@ -400,15 +393,15 @@
     }
 
     private void invoke(UpcallContext context) {
-        // FIXME: Handle varargs upcalls here
-        CallingSequence callingSequence = CallingSequence.make(mh.type());
+        try (Scope scope = new NativeScope()) {
+            // FIXME: Handle varargs upcalls here
+            CallingSequence callingSequence = CallingSequence.make(mh.type());
 
-        if (DEBUG) {
-            System.err.println("=== UpcallHandler.invoke ===");
-            System.err.println(callingSequence.asString());
-        }
+            if (DEBUG) {
+                System.err.println("=== UpcallHandler.invoke ===");
+                System.err.println(callingSequence.asString());
+            }
 
-        try (Scope scope = new NativeScope()) {
             Object[] args = boxArguments(scope, context, callingSequence);
 
             Object o = mh.asSpreader(Object[].class, args.length).invoke(args);
--- a/src/java.base/share/classes/jdk/internal/nicl/types/BoundedMemoryRegion.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/nicl/types/BoundedMemoryRegion.java	Wed May 11 10:13:59 2016 -0700
@@ -47,7 +47,7 @@
     }
 
     public BoundedMemoryRegion(long min, long length, Scope scope) {
-        this(null, min, length, MODE_RW, null);
+        this(null, min, length, MODE_RW, scope);
     }
 
     public BoundedMemoryRegion(long min, long length, int mode, Scope scope) {
@@ -121,6 +121,7 @@
     public long getBits(long offset, long size, boolean isSigned) {
         checkAccess(MODE_R);
         checkRange(offset, size);
+        checkAlive();
 
         if (size < 0 || size > Integer.MAX_VALUE) {
             throw new IllegalArgumentException("Invalid size: " + size);
@@ -157,6 +158,7 @@
     public void putBits(long offset, long size, long value) {
         checkAccess(MODE_R);
         checkRange(offset, size);
+        checkAlive();
 
         if (size < 0 || size > Integer.MAX_VALUE) {
             throw new IllegalArgumentException("Invalid size: " + size);
@@ -231,6 +233,7 @@
             throw new UnsupportedOperationException();
         }
         checkRange(offset, U.addressSize());
+        checkAlive();
         return U.getAddress(this.min + offset);
     }
 
@@ -240,6 +243,7 @@
             throw new UnsupportedOperationException();
         }
         checkRange(offset, U.addressSize());
+        checkAlive();
         U.putAddress(this.min + offset, value);
     }
 }
--- a/src/java.base/share/classes/jdk/internal/nicl/types/BoundedPointer.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/nicl/types/BoundedPointer.java	Wed May 11 10:13:59 2016 -0700
@@ -22,6 +22,10 @@
  */
 package jdk.internal.nicl.types;
 
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.nicl.NativeLibrary;
 import java.nicl.types.LayoutType;
 import java.nicl.types.MemoryRegion;
 import java.nicl.types.Pointer;
@@ -58,7 +62,23 @@
     }
 
     @Override
-    public Reference<T> deref() {
+    public T deref() {
+        if (Util.isCStruct(type.getCarrierType())) {
+            Class<? extends Reference<T>> c = NativeLibrary.getStructImplClass(type.getCarrierType());
+
+            try {
+                MethodHandle mh = MethodHandles.lookup().findConstructor(c, MethodType.methodType(void.class, Pointer.class));
+                return (T)mh.invoke(this);
+            } catch (Throwable t) {
+                throw new RuntimeException(t);
+            }
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    @Override
+    public Reference<T> lvalue() {
         // FIXME: check bounds here
         // FIXME: check for and potentially create an instance of the struct here if Util.isCStruct(type.getCarrierType()) ?
         return new ReferenceImpl<T>(type, region, offset, mode);
--- a/src/java.base/share/classes/jdk/internal/nicl/types/LayoutTypeImpl.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/nicl/types/LayoutTypeImpl.java	Wed May 11 10:13:59 2016 -0700
@@ -24,6 +24,7 @@
 
 import java.nicl.types.LayoutType;
 import java.nicl.types.Pointer;
+import jdk.internal.nicl.NativeLibraryImpl;
 import jdk.internal.nicl.Util;
 
 public class LayoutTypeImpl<T> implements LayoutType<T> {
@@ -68,6 +69,8 @@
             return (LayoutTypeImpl<S>) new LayoutTypeImpl<Pointer>(Pointer.class, Types.POINTER);
         } else if (Util.isCStruct(c)) {
             return new LayoutTypeImpl<>(c, null);
+        } else if (NativeLibraryImpl.isVectorType(c)) {
+            return new LayoutTypeImpl<>(c, new Scalar('v', Type.Endianness.NATIVE, NativeLibraryImpl.getVectorSize(c) * 8));
         } else {
             switch (c.getName()) {
             case "java.lang.Object": // FIXME: what does this really mean?
--- a/src/java.base/share/classes/jdk/internal/nicl/types/ReferenceImpl.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/nicl/types/ReferenceImpl.java	Wed May 11 10:13:59 2016 -0700
@@ -28,6 +28,7 @@
 import java.nicl.types.MemoryRegion;
 import java.nicl.types.Pointer;
 import java.nicl.types.Reference;
+import jdk.internal.nicl.NativeLibraryImpl;
 import jdk.internal.nicl.abi.types.AbstractType;
 import jdk.internal.nicl.abi.types.IntegerType;
 import jdk.internal.nicl.abi.types.Types;
@@ -107,8 +108,27 @@
             // FIXME: Can we do better on size and type?
             return (T) NativeLibrary.createPtr(getLongBits(),
                 NativeLibrary.createLayout(Void.class));
-        } else  {
-            // FIXME: Handle vectors, structs here
+        } else if (NativeLibraryImpl.isVectorType(c)) {
+            long size = NativeLibraryImpl.getVectorSize(c);
+            int nElems = (int)(size / 8);
+            long[] bits = new long[nElems];
+
+            Pointer<Long> arrPtr = NativeLibrary.createArrayElementsPointer(bits);
+            // FIXME: Endianness goes here
+            NativeLibrary.copy(ptr(), arrPtr, size);
+
+            switch (nElems) {
+            case 2:
+                return (T) Long2.make(bits[0], bits[1]);
+            case 4:
+                return (T) Long4.make(bits[0], bits[1], bits[2], bits[3]);
+            case 8:
+                return (T) Long8.make(bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]);
+            default:
+                throw new UnsupportedOperationException("Unhandled vector size (" + nElems + ") for type " + c.getName());
+            }
+        } else {
+            // FIXME: Handle structs here
             throw new UnsupportedOperationException("Unhandled type: " + c);
         }
     }
@@ -155,8 +175,39 @@
             } catch (IllegalAccessException iae) {
                 throw new RuntimeException("Access denied", iae);
             }
+        } else if (NativeLibraryImpl.isVectorType(c)) {
+            long size = NativeLibraryImpl.getVectorSize(c);
+            int nElems = (int)(size / 8);
+            long[] bits = new long[nElems];
+
+            Pointer<Long> arrPtr = NativeLibrary.createArrayElementsPointer(bits);
+
+            switch (nElems) {
+                case 2:
+                    for (int i = 0; i < nElems; i++) {
+                        bits[i] = ((Long2) value).extract(i);
+                    }
+                    break;
+
+                case 4:
+                    for (int i = 0; i < nElems; i++) {
+                        bits[i] = ((Long4) value).extract(i);
+                    }
+                    break;
+
+                case 8:
+                    for (int i = 0; i < nElems; i++) {
+                        bits[i] = ((Long8) value).extract(i);
+                    }
+                    break;
+
+                default:
+                    throw new IllegalArgumentException("Unhandled vector size (" + nElems + ") for type " + c.getName());
+            }
+
+            NativeLibrary.copy(arrPtr, ptr(), size);
         } else {
-            // FIXME: Handle vectors, structs here
+            // FIXME: Handle structs here
             throw new UnsupportedOperationException("Unhandled type: " + type.getCarrierType());
         }
     }
--- a/src/java.base/share/classes/jdk/internal/nicl/types/UncheckedPointer.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/java.base/share/classes/jdk/internal/nicl/types/UncheckedPointer.java	Wed May 11 10:13:59 2016 -0700
@@ -40,7 +40,11 @@
     }
 
     public UncheckedPointer(LayoutType<T> type, long offset, int mode) {
-        super(type, BoundedMemoryRegion.EVERYTHING, offset, mode);
+        this(type, BoundedMemoryRegion.EVERYTHING, offset, mode);
+    }
+
+    public UncheckedPointer(LayoutType<T> type, MemoryRegion region, long offset, int mode) {
+        super(type, region, offset, mode);
     }
 
     @Override
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/JType.java	Fri May 06 10:00:31 2016 -0700
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/JType.java	Wed May 11 10:13:59 2016 -0700
@@ -107,8 +107,8 @@
         } else if (t == JType.Short) {
             return "Ljava/lang/Short;";
         } else if (t == JType.Void) {
-			return "Ljava/lang/Void;";
-		} else {
+            return "Ljava/lang/Void;";
+        } else {
             return t.getSignature();
         }
     }
--- a/test/java/nicl/System/UnixSystem.java	Fri May 06 10:00:31 2016 -0700
+++ b/test/java/nicl/System/UnixSystem.java	Wed May 11 10:13:59 2016 -0700
@@ -111,6 +111,8 @@
         system.stat s = (system.stat)scope.allocateStruct(NativeLibrary.createLayout(system.stat.class));
         Pointer<system.stat> p = s.ptr();
 
+        s = p.deref();
+
         try (Scope scope2 = new NativeScope()) {
             int res = i.__xstat(1, Transformer.toCString(path, scope2), p);
             if (res != 0) {
@@ -135,6 +137,8 @@
             try (Scope scope = new NativeScope()) {
                 system.stat s = doStat(i, f.getPath(), scope);
                 assertEquals(s.st_size$get(), 4711);
+                s.st_size$set(4712);
+                assertEquals(s.st_size$get(), 4712);
             } finally {
                 f.delete();
             }
--- a/test/java/nicl/Upcall/CallbackSort.java	Fri May 06 10:00:31 2016 -0700
+++ b/test/java/nicl/Upcall/CallbackSort.java	Wed May 11 10:13:59 2016 -0700
@@ -59,8 +59,8 @@
             Pointer<Integer> p1 = e1.cast(NativeLibrary.createLayout(int.class));
             Pointer<Integer> p2 = e2.cast(NativeLibrary.createLayout(int.class));
 
-            int i1 = p1.deref().get();
-            int i2 = p2.deref().get();
+            int i1 = p1.lvalue().get();
+            int i2 = p2.lvalue().get();
 
             if (DEBUG) {
                 System.out.println("fn(i1=" + i1 + ", i2=" + i2 + ")");
@@ -150,7 +150,7 @@
                 throw new IndexOutOfBoundsException();
             }
 
-            return base.offset(index).deref();
+            return base.offset(index).lvalue();
         }
 
         public int getAt(int index) {
--- a/test/java/nicl/Upcall/StructUpcall.java	Fri May 06 10:00:31 2016 -0700
+++ b/test/java/nicl/Upcall/StructUpcall.java	Wed May 11 10:13:59 2016 -0700
@@ -105,17 +105,17 @@
                 System.err.println("\ts.field1  = " + s.field1$get());
                 System.err.println("\ts.field2 = " + s.field2$get());
                 System.err.println("\ts.field3 = " + s.field3$get());
-                System.err.println("\ts.field4 = " + s.field4$get().deref().get());
-                System.err.println("\ts.field5 = " + s.field5$get().deref().get());
-                System.err.println("\ts.field6 = " + s.field6$get().deref().get());
+                System.err.println("\ts.field4 = " + s.field4$get().lvalue().get());
+                System.err.println("\ts.field5 = " + s.field5$get().lvalue().get());
+                System.err.println("\ts.field6 = " + s.field6$get().lvalue().get());
             }
 
             assertEquals(47, s.field1$get());
             assertEquals(11, s.field2$get());
             assertEquals(93, s.field3$get());
-            assertEquals(123, s.field4$get().cast(NativeLibrary.createLayout(byte.class)).deref().get());
-            assertEquals(124, s.field5$get().cast(NativeLibrary.createLayout(byte.class)).deref().get());
-            assertEquals(125, s.field6$get().cast(NativeLibrary.createLayout(byte.class)).deref().get());
+            assertEquals(123, s.field4$get().cast(NativeLibrary.createLayout(byte.class)).lvalue().get());
+            assertEquals(124, s.field5$get().cast(NativeLibrary.createLayout(byte.class)).lvalue().get());
+            assertEquals(125, s.field6$get().cast(NativeLibrary.createLayout(byte.class)).lvalue().get());
         }
     }
 
@@ -129,9 +129,9 @@
             Pointer<Byte> p2 = scope.allocate(NativeLibrary.createLayout(byte.class));
             Pointer<Byte> p3 = scope.allocate(NativeLibrary.createLayout(byte.class));
 
-            p1.deref().set((byte)123);
-            p2.deref().set((byte)124);
-            p3.deref().set((byte)125);
+            p1.lvalue().set((byte)123);
+            p2.lvalue().set((byte)124);
+            p3.lvalue().set((byte)125);
 
             s.get().field1$set(47);
             s.get().field2$set(11);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nicl/types/StructTest.java	Wed May 11 10:13:59 2016 -0700
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @modules java.base/jdk.internal.misc
+ */
+
+import java.nicl.*;
+import java.nicl.metadata.*;
+import java.nicl.types.*;
+
+public class StructTest {
+    public static final boolean DEBUG = Boolean.getBoolean("StructTest.DEBUG");
+
+    public static final long TOTAL_SIZE = 128;
+    public static final long A_OFFSET  = 0;
+    public static final long A_LENGTH  = 4;
+    public static final long M_OFFSET  = 256;
+    public static final long MA_OFFSET = 512;
+    public static final int MA_LENGTH = 2;
+
+    public static long alignUp(long n, long alignment) {
+        return (n + alignment - 1) & ~(alignment - 1);
+    }
+
+    @C(file="dummy", line=47, column=11, USR="c:@S@MyStruct")
+    @NativeType(layout="[4i=256v2=256v]", ctype="struct MyStruct", size=128l, isRecordType=true)
+    static interface MyStruct extends Reference<MyStruct> {
+        @C(file="dummy", line=47, column=11, USR="c:@SA@MyStruct@field1")
+        @NativeType(layout="4i", ctype="off_t", size=4l)
+        @Array(elementType="int", elementSize=4l, length=4l)
+        @Offset(offset=0l)
+        int[] a$get();
+        void a$set(int[] a);
+
+        @C(file="dummy", line=47, column=11, USR="c:@S@s@FI@m")
+        @NativeType(layout="=256v", ctype="__m256", size=4l)
+        @Array(elementType="int", elementSize=4l, length=4l)
+        @Offset(offset=256l)
+        Long4 m$get();
+        void m$set(Long4 m);
+
+        @C(file="dummy", line=47, column=11, USR="c:@S@s@FI@ma")
+        @Array(elementType="__attribute__((__vector_size__(8 * sizeof(float)))) float", elementSize=32l, length=2l)
+        @NativeType(layout="2=256v", ctype="__m256 [2]", size=64l)
+        @Offset(offset=512l)
+        Long4[] ma$get();
+        void ma$set(Long4[] ma);
+    }
+
+    public int buildInt(long baseValue) {
+        int tmp = 0;
+
+        for (int i = 0; i < 4; i++) {
+            tmp |= baseValue++ << (i * 8);
+        }
+
+        return tmp;
+    }
+
+
+    public long buildLong(long baseValue) {
+        long tmp = 0;
+
+        for (int i = 0; i < 8; i++) {
+            tmp |= baseValue++ << (i * 8);
+        }
+
+        return tmp;
+    }
+
+    public Long4 buildLong4(long baseValue) {
+        long[] tmp = new long[4];
+        for (int i = 0; i < tmp.length; i++, baseValue += 8) {
+            tmp[i] = buildLong(baseValue);
+        }
+        return Long4.make(tmp[0], tmp[1], tmp[2], tmp[3]);
+    }
+
+    public void testIntArray(MyStruct s, Pointer<Byte> p) {
+        {
+            long expected = A_OFFSET / 8;
+
+            int[] ia = s.a$get();
+            assertEquals(A_LENGTH, ia.length);
+
+            for (int i = 0; i < ia.length; i++, expected += 4) {
+                if (DEBUG) {
+                    System.err.println("ia[" + i + "] = 0x" + Integer.toHexString(ia[i]));
+                }
+                try {
+                    assertEquals(buildInt(expected), ia[i]);
+                } catch (Exception e) {
+                    throw new RuntimeException("Failed to verify ia[" + i + "]", e);
+                }
+            }
+        }
+
+        {
+            int counter = 0x80;
+
+            int[] ia = new int[4];
+            for (int i = 0; i < ia.length; i++, counter += 4) {
+                ia[i] = buildInt(counter);
+            }
+            s.a$set(ia);
+        }
+
+        {
+            int expected = 0x80;
+
+            int[] ia = s.a$get();
+            assertEquals(A_LENGTH, ia.length);
+
+            for (int i = 0; i < ia.length; i++, expected += 4) {
+                int val = ia[i];
+                if (DEBUG) {
+                    System.err.println("ia[" + i + "] = 0x" + Integer.toHexString(val));
+                }
+                try {
+                    assertEquals(buildInt(expected), val);
+                } catch (Exception e) {
+                    throw new RuntimeException("Failed to verify ia[" + i + "]", e);
+                }
+            }
+        }
+    }
+
+    public void testVector(MyStruct s, Pointer<Byte> p) {
+        {
+            Long4 l = s.m$get();
+
+            if (DEBUG) {
+                System.err.println("l = " + l);
+            }
+
+            try {
+                assertEquals(buildLong4(M_OFFSET / 8), l);
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to verify l", e);
+            }
+        }
+
+        {
+            s.m$set(buildLong4(0x80));
+        }
+
+        {
+            Long4 l = s.m$get();
+            if (DEBUG) {
+                System.err.println("l = " + l);
+            }
+            try {
+                assertEquals(buildLong4(0x80), l);
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to verify l", e);
+            }
+        }
+    }
+
+    public void testVectorArray(MyStruct s, Pointer<Byte> p) {
+        {
+            Long4[] la = s.ma$get();
+
+            assertEquals(MA_LENGTH, la.length);
+
+            long expected = MA_OFFSET / 8;
+            for (int i = 0; i < la.length; i++, expected += 32) {
+                if (DEBUG) {
+                    System.err.println("la[" + i + "] = " + la[i]);
+                }
+                try {
+                    assertEquals(buildLong4(expected), la[i]);
+                } catch (Exception e) {
+                    throw new RuntimeException("Failed to verify la[" + i + "]", e);
+                }
+            }
+        }
+
+        {
+            Long4[] la = new Long4[MA_LENGTH];
+
+            long counter = 0x80;
+
+            for (int i = 0; i < la.length; i++, counter += 32) {
+                la[i] = buildLong4(counter);
+            }
+            s.ma$set(la);
+        }
+
+        {
+            Long4[] la = s.ma$get();
+
+            assertEquals(MA_LENGTH, la.length);
+
+            long expected = 0x80;
+            for (int i = 0; i < la.length; i++, expected += 32) {
+                if (DEBUG) {
+                    System.err.println("la[" + i + "] = " + la[i]);
+                }
+                try { 
+                   assertEquals(buildLong4(expected), la[i]);
+                } catch (Exception e) {
+                    throw new RuntimeException("Failed to verify la[" + i + "]", e);
+                }
+            }
+        }
+    }
+
+    private static void assertEquals(int expected, int actual) {
+        if (expected != actual) {
+            throw new RuntimeException("actual: 0x" + Long.toHexString(actual) + " does not match expected: 0x" + Long.toHexString(expected));
+        }
+    }
+
+    private static void assertEquals(long expected, long actual) {
+        if (expected != actual) {
+            throw new RuntimeException("actual: 0x" + Long.toHexString(actual) + " does not match expected: 0x" + Long.toHexString(expected));
+        }
+    }
+
+    private static void assertEquals(Long4 expected, Long4 actual) {
+        if (!expected.equals(actual)) {
+            throw new RuntimeException("actual: " + actual + " does not match expected: " + expected);
+        }
+    }
+
+    public void test() {
+        try (Scope scope = new NativeScope()) {
+            MyStruct s = scope.allocateStruct(NativeLibrary.createLayout(MyStruct.class));
+            long size = TOTAL_SIZE;
+            Pointer<Byte> p = scope.allocate(NativeLibrary.createLayout(byte.class), size);
+
+            for (int i = 0; i < size; i++) {
+                p.offset(i).lvalue().set((byte)i);
+            }
+            NativeLibrary.copy(p, s.ptr(), size);
+
+            testIntArray(s, p);
+            testVector(s, p);
+            testVectorArray(s, p);
+        }
+    }
+
+    public static void main(String[] args) {
+        StructTest t = new StructTest();
+        t.test();
+    }
+}