/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * (C) Copyright IBM Corporation 2006-2010. */ package x10.core; import java.io.IOException; import java.util.Arrays; import x10.core.fun.VoidFun_0_0; import x10.lang.Place; import x10.rtt.NamedType; import x10.rtt.RuntimeType; import x10.rtt.Type; import x10.rtt.Types; import x10.serialization.SerializationConstants; import x10.serialization.X10JavaDeserializer; import x10.serialization.X10JavaSerializable; import x10.serialization.X10JavaSerializer; public final class IndexedMemoryChunk<T> extends x10.core.Struct implements X10JavaSerializable { private static final long serialVersionUID = 1L; public Type<T> T; public int length; public Object value; // constructor just for allocation public IndexedMemoryChunk(java.lang.System[] $dummy) { // call default constructor instead of "constructor just for allocation" for x10.core.Struct // super($dummy); } public final IndexedMemoryChunk<T> x10$util$IndexedMemoryChunk$$init$S(Type<T> T, int length, Object value) { this.T = T; this.length = length; this.value = value; return this; } public IndexedMemoryChunk(Type<T> T, int length, Object value) { this.T = T; this.length = length; this.value = value; } public final IndexedMemoryChunk<T> x10$util$IndexedMemoryChunk$$init$S(Type<T> T) { this.x10$util$IndexedMemoryChunk$$init$S(T, 0, null); return this; } public IndexedMemoryChunk(Type<T> T) { this(T, 0, null); } // zero value constructor public IndexedMemoryChunk(Type<T> T, java.lang.System $dummy) { this(T); } private IndexedMemoryChunk(Type<T> T, int length, boolean zeroed) { this(T, length, T.makeArray(length)); if (zeroed) { if (!Types.hasNaturalZero(T)) { Object zeroValue = Types.zeroValue(T); java.util.Arrays.fill((Object[]) value, zeroValue); } } } public static <T> IndexedMemoryChunk<T> allocate(Type/*<T>*/ T, long length, boolean zeroed) { if (length > Integer.MAX_VALUE) { // TODO throw new java.lang.OutOfMemoryError("Array length must be shorter than 2^31"); } return new IndexedMemoryChunk<T>(T, (int) length, zeroed); } public static <T> IndexedMemoryChunk<T> allocate(Type/*<T>*/ T, int length, boolean zeroed) { return new IndexedMemoryChunk<T>(T, length, zeroed); } @Override public java.lang.String toString() { StringBuilder sb = new StringBuilder(); sb.append("IndexedMemoryChunk("); int sz = Math.min(length, 10); for (int i = 0; i < sz; i++) { if (i > 0) sb.append(","); sb.append($apply$G(i)); } if (sz < length) sb.append("...(omitted " + (length - sz) + " elements)"); sb.append(")"); return sb.toString(); } public T $apply$G(int i) { return T.getArray(value, i); } public void $set(int i, T v) { T.setArray(value, i, v); } public void set_unsafe(T v, int i) { $set(i, v); } public void clear(int start, int numElems) { if (numElems <= 0) return; if (value instanceof boolean[]) { Arrays.fill(getBooleanArray(), start, start + numElems, false); } else if (value instanceof byte[]) { Arrays.fill(getByteArray(), start, start + numElems, (byte) 0); } else if (value instanceof char[]) { Arrays.fill(getCharArray(), start, start + numElems, (char) 0); } else if (value instanceof short[]) { Arrays.fill(getShortArray(), start, start + numElems, (short) 0); } else if (value instanceof int[]) { Arrays.fill(getIntArray(), start, start + numElems, 0); } else if (value instanceof float[]) { Arrays.fill(getFloatArray(), start, start + numElems, 0.0F); } else if (value instanceof long[]) { Arrays.fill(getLongArray(), start, start + numElems, 0L); } else if (value instanceof double[]) { Arrays.fill(getDoubleArray(), start, start + numElems, 0.0); } else { Object zeroValue = Types.zeroValue(T); Arrays.fill(getObjectArray(), start, start + numElems, zeroValue); } } public void deallocate() { value = null; length = 0; } public static <T> void asyncCopy(IndexedMemoryChunk<T> src, final int srcIndex, final RemoteIndexedMemoryChunk<T> dst, final int dstIndex, final int numElems) { // synchronous version for the same place if (dst.home.id == x10.lang.Runtime.home().id) { System.arraycopy(src.value, srcIndex, dst.$apply$G().value, dstIndex, numElems); return; } // extra copy here simplifies logic and allows us to do this entirely at the Java level. // We'll eventually need to optimize this by writing custom native/JNI code instead of treating // it as just another async to execute remotely. final Object dataToCopy; if (numElems == src.length) { dataToCopy = src.getBackingArray(); } else { dataToCopy = allocate(src.T, numElems, false).getBackingArray(); System.arraycopy(src.value, srcIndex, dataToCopy, 0, numElems); } VoidFun_0_0 copyBody = new $Closure$0(dataToCopy, dst.id, dstIndex, numElems); x10.lang.Runtime.runAsync(dst.home, copyBody, null); } // static nested class version of copyBody public static class $Closure$0 extends x10.core.Ref implements VoidFun_0_0 { private static final long serialVersionUID = 1L; public Object srcData; public int dstId; public int dstIndex; public int numElems; // Just for allocation $Closure$0() { } $Closure$0(Object srcData, int dstId, int dstIndex, int numElems) { this.srcData = srcData; this.dstId = dstId; this.dstIndex = dstIndex; this.numElems = numElems; } public void $apply() { Object dstData = RemoteIndexedMemoryChunk.getValue(dstId); System.arraycopy(srcData, 0, dstData, dstIndex, numElems); } public static final RuntimeType<$Closure$0> $RTT = x10.rtt.StaticVoidFunType.<$Closure$0> make($Closure$0.class, new Type[] { VoidFun_0_0.$RTT }); public RuntimeType<$Closure$0> $getRTT() { return $RTT; } public Type<?> $getParam(int i) { return null; } //TODO Keith This is not compatible with C++ at the moment cause the java backend does not implement send_put public void $_serialize(X10JavaSerializer $serializer) throws IOException { $serializer.write(this.numElems); if (this.numElems > 0) { Class<?> componentType = this.srcData.getClass().getComponentType(); if (componentType.isPrimitive()) { $serializer.write(SerializationConstants.JAVA_OBJECT_STREAM_ID); $serializer.writeUsingObjectOutputStream(this.srcData); } else if (componentType.equals(java.lang.String.class)) { $serializer.write(SerializationConstants.STRING_ID); $serializer.write((java.lang.String[]) this.srcData); } else if (this.srcData instanceof X10JavaSerializable[]) { $serializer.write((X10JavaSerializable[]) this.srcData); } else { $serializer.write((Object[]) this.srcData); } } $serializer.write(this.dstId); $serializer.write(this.dstIndex); } public static X10JavaSerializable $_deserializer(X10JavaDeserializer $deserializer) throws IOException { $Closure$0 $_obj = new $Closure$0(); $deserializer.record_reference($_obj); return $_deserialize_body($_obj, $deserializer); } public static X10JavaSerializable $_deserialize_body($Closure$0 $_obj, X10JavaDeserializer $deserializer) throws IOException { $_obj.numElems = $deserializer.readInt(); if ($_obj.numElems > 0) { short serializationID = $deserializer.readShort(); if (serializationID == SerializationConstants.JAVA_OBJECT_STREAM_ID) { $_obj.srcData = $deserializer.readUsingObjectInputStream(); } else if (serializationID == SerializationConstants.STRING_ID) { $_obj.srcData = $deserializer.readStringArray(); } else { $_obj.srcData = $deserializer.readRef(); } } $_obj.dstId = $deserializer.readInt(); $_obj.dstIndex = $deserializer.readInt(); return $_obj; } } public static <T> void asyncCopy(IndexedMemoryChunk<T> src, int srcIndex, RemoteIndexedMemoryChunk<T> dst, int dstIndex, int numElems, VoidFun_0_0 notifier) { // synchronous version for the same place if (dst.home.id == x10.lang.Runtime.home().id) { System.arraycopy(src.value, srcIndex, dst.$apply$G().value, dstIndex, numElems); notifier.$apply(); return; } throw new java.lang.UnsupportedOperationException("asyncCopy with notifier not implemented for multivm"); // notifier.$apply(); } public static <T> void asyncCopy(final RemoteIndexedMemoryChunk<T> src, final int srcIndex, IndexedMemoryChunk<T> dst, final int dstIndex, final int numElems) { // synchronous version for the same place if (src.home.id == x10.lang.Runtime.home().id) { System.arraycopy(src.$apply$G().value, srcIndex, dst.value, dstIndex, numElems); return; } // A really bad implementation! Leaks dst!! Non-optimized copies! Extra distributed async/finish traffic! final RemoteIndexedMemoryChunk<T> dstWrapper = RemoteIndexedMemoryChunk.wrap(dst); VoidFun_0_0 copyBody1 = new $Closure$1<T>(src, srcIndex, dstWrapper, dstIndex, numElems); x10.lang.Runtime.runAsync(src.home, copyBody1, null); } // static nested class version of copyBody1 public static class $Closure$1<T> extends x10.core.Ref implements VoidFun_0_0 { private static final long serialVersionUID = 1L; public Type<T> srcT; public int srcId; public int srcLength; public int srcIndex; public int dstWrapperId; public Place dstWrapperHome; public int dstIndex; public int numElems; //Just for allocation $Closure$1() { } $Closure$1(RemoteIndexedMemoryChunk<T> src, int srcIndex, RemoteIndexedMemoryChunk<T> dstWrapper, int dstIndex, int numElems) { this.srcT = src.T; this.srcId = src.id; this.srcLength = src.length; this.srcIndex = srcIndex; this.dstWrapperId = dstWrapper.id; this.dstWrapperHome = dstWrapper.home; this.dstIndex = dstIndex; this.numElems = numElems; } public void $apply() { // This body runs at src's home. It accesses the data for src and then does // another async back to dstWrapper's home to transfer the data. Object srcData = RemoteIndexedMemoryChunk.getValue(srcId); // extra copy here simplifies logic and allows us to do this entirely at the Java level. // We'll eventually need to optimize this by writing custom native/JNI code instead of treating // it as just another async to execute remotely. final Object dataToCopy; if (numElems == srcLength) { dataToCopy = srcData; } else { dataToCopy = allocate(srcT, numElems, false).getBackingArray(); System.arraycopy(srcData, srcIndex, dataToCopy, 0, numElems); } // N.B. copyBody2 is same as copyBody VoidFun_0_0 copyBody2 = new $Closure$0(dataToCopy, dstWrapperId, dstIndex, numElems); x10.lang.Runtime.runAsync(dstWrapperHome, copyBody2, null); } public static final RuntimeType<$Closure$1<?>> $RTT = x10.rtt.StaticVoidFunType.<$Closure$1<?>> make($Closure$1.class, new Type[] { VoidFun_0_0.$RTT }); public RuntimeType<$Closure$1<?>> $getRTT() { return $RTT; } public Type<?> $getParam(int i) { return i == 0 ? srcT : null; } //TODO Keith This is not compatible with C++ at the moment cause the java backend does not implement send_put public void $_serialize(X10JavaSerializer $serializer) throws IOException { $serializer.write(this.srcT); $serializer.write(this.srcId); $serializer.write(this.srcLength); $serializer.write(this.srcIndex); $serializer.write(this.dstWrapperId); $serializer.write(this.dstWrapperHome); $serializer.write(this.dstIndex); $serializer.write(this.numElems); } public static X10JavaSerializable $_deserializer(X10JavaDeserializer $deserializer) throws IOException { $Closure$1 $_obj = new $Closure$1(); $deserializer.record_reference($_obj); return $_deserialize_body($_obj, $deserializer); } public static X10JavaSerializable $_deserialize_body($Closure$1 $_obj, X10JavaDeserializer $deserializer) throws IOException { $_obj.srcT = $deserializer.readRef(); $_obj.srcId = $deserializer.readInt(); $_obj.srcLength = $deserializer.readInt(); $_obj.srcIndex = $deserializer.readInt(); $_obj.dstWrapperId = $deserializer.readInt(); $_obj.dstWrapperHome = $deserializer.readRef(); $_obj.dstIndex = $deserializer.readInt(); $_obj.numElems = $deserializer.readInt(); return $_obj; } } public static <T> void asyncCopy(RemoteIndexedMemoryChunk<T> src, int srcIndex, IndexedMemoryChunk<T> dst, int dstIndex, int numElems, VoidFun_0_0 notifier) { // synchronous version for the same place if (src.home.id == x10.lang.Runtime.home().id) { System.arraycopy(src.$apply$G().value, srcIndex, dst.value, dstIndex, numElems); notifier.$apply(); return; } throw new java.lang.UnsupportedOperationException("asyncCopy with notifier not implemented for multivm"); // notifier.$apply(); } public static <T> void copy(IndexedMemoryChunk<T> src, int srcIndex, IndexedMemoryChunk<T> dst, int dstIndex, int numElems) { System.arraycopy(src.value, srcIndex, dst.value, dstIndex, numElems); } public boolean _struct_equals$O(Object o) { return o != null && this.value == ((IndexedMemoryChunk<?>) o).value; } // TODO implement remote operations public RemoteIndexedMemoryChunk<T> getCongruentSibling(x10.lang.Place p) { throw new java.lang.UnsupportedOperationException("Remote operations are not implemented."); } public static final RuntimeType<IndexedMemoryChunk<?>> $RTT = NamedType.<IndexedMemoryChunk<?>> make("x10.util.IndexedMemoryChunk", IndexedMemoryChunk.class, RuntimeType.INVARIANTS(1), new Type[] { Types.STRUCT }); public RuntimeType<IndexedMemoryChunk<?>> $getRTT() { return $RTT; } public Type<?> $getParam(int i) { return i == 0 ? T : null; } // Methods to get the backing array. May be called by generated code. public Object getBackingArray() { return value; } public boolean[] getBooleanArray() { return (boolean[]) value; } public byte[] getByteArray() { return (byte[]) value; } public short[] getShortArray() { return (short[]) value; } public char[] getCharArray() { return (char[]) value; } public int[] getIntArray() { return (int[]) value; } public long[] getLongArray() { return (long[]) value; } public float[] getFloatArray() { return (float[]) value; } public double[] getDoubleArray() { return (double[]) value; } public Object[] getObjectArray() { return (Object[]) value; } public void $_serialize(X10JavaSerializer $serializer) throws IOException { $serializer.write(T); $serializer.write(length); // If the T is a java primitive type, we use default java serialization here // cause its much faster than writing a single element at a time if (Types.isPrimitiveType(T)) { $serializer.writeUsingObjectOutputStream(value); } else if (Types.isStringType(T)) { java.lang.String[] castValue = (java.lang.String[]) value; for (java.lang.String v : castValue) { $serializer.write(v); } } else { Object[] castValue = (Object[]) value; for (Object v : castValue) { if (v instanceof X10JavaSerializable) { $serializer.write((X10JavaSerializable) v); } else { $serializer.write(v); } } } } public static X10JavaSerializable $_deserializer(X10JavaDeserializer $deserializer) throws IOException { IndexedMemoryChunk $_obj = new IndexedMemoryChunk((java.lang.System[]) null); $deserializer.record_reference($_obj); return $_deserialize_body($_obj, $deserializer); } public static X10JavaSerializable $_deserialize_body(IndexedMemoryChunk $_obj, X10JavaDeserializer $deserializer) throws IOException { $_obj.T = $deserializer.readRef(); $_obj.length = $deserializer.readInt(); // If the T is a java primitive type, we use default java serialization here // cause its much faster than reading a single element at a time if (Types.isPrimitiveType($_obj.T)) { $_obj.value = $deserializer.readUsingObjectInputStream(); } else if (Types.isStringType($_obj.T)) { java.lang.String[] values = (java.lang.String[]) $_obj.T.makeArray($_obj.length); for (int i = 0; i < $_obj.length; i++) { values[i] = $deserializer.readString(); } $_obj.value = values; } else { Object[] values = (Object[]) $_obj.T.makeArray($_obj.length); for (int i = 0; i < $_obj.length; i++) { values[i] = $deserializer.readRef(); } $_obj.value = values; } return $_obj; } }