/* * 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.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import x10.lang.Place; import x10.lang.Runtime.Mortal; import x10.rtt.RuntimeType; import x10.rtt.Type; import x10.rtt.Types; import x10.serialization.X10JavaDeserializer; import x10.serialization.X10JavaSerializable; import x10.serialization.X10JavaSerializer; /* * [GlobalGC] Managed X10 (X10 on Java) supports distributed GC, which is mainly implemented here, in GlobalRef.java. * See a paper "Distributed Garbage Collection for Managed X10" in ACM SIGPLAN 2012 X10 Workshop, June 2012. */ public final class GlobalRef<T> extends x10.core.Struct implements Externalizable, X10JavaSerializable { public static final RuntimeType<GlobalRef<?>> $RTT = x10.rtt.NamedType.<GlobalRef<?>> make( "x10.lang.GlobalRef", GlobalRef.class, RuntimeType.INVARIANTS(1), new Type[] { Types.STRUCT } ); public RuntimeType<GlobalRef<?>> $getRTT() { return $RTT; } public Type<?> $getParam(int i) { return i == 0 ? T : null; } /* * GlobalGC debug and support methods */ public static final boolean GLOBALGC_DISABLE = java.lang.Boolean.getBoolean("GLOBALGC_DISABLE"); public static final int GLOBALGC_WEIGHT = java.lang.Integer.getInteger("GLOBALGC_WEIGHT", 100); // initial weight for a remote ref public static final int GLOBALGC_DEBUG = java.lang.Integer.getInteger("GLOBALGC_DEBUG", 0); // 0:nothing, 1:important, 2:info, 3: all private static int inited = 0; { if (inited++ == 0) if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GLOBALGC_DISABLE=" + GLOBALGC_DISABLE + " GLOBALGC_WEIGHT=" + GLOBALGC_WEIGHT + " GLOBALGC_DEBUG=" + GLOBALGC_DEBUG); } private static final Object debugSync = new Object(); private static void GlobalGCDebug(java.lang.String msg) { //if (level > GLOBALGC_DEBUG) return; // XTENLANG-3168: debug level should be checked in caller long time = System.nanoTime(); int placeId = x10.lang.Runtime.home().id; java.lang.String output = "[GlobalGC(time=" + time + ",place=" + placeId + ")] " + msg; synchronized (debugSync) { System.err.println(output); System.err.flush(); } } private static class GlobalizedObjectTracker extends WeakReference<Object> { private static final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); private static AtomicLong lastId = new AtomicLong(0L); private static AtomicLong lastMortalId = new AtomicLong(0L); // used for Mortal objects private /*final*/ long id; // unique id for the corresponding {T,localObj} // id==0 means not assigned, negative ids are assigned to Mortal objects private Object strongRef; // strong reference to the localObj, used to prevent the collection private Type<?> T; // T of corresponding GlobalRef[T](localObj) private int remoteCount; // number of active remote GlobalRefs, should be < #places private final int hashCode; // pre-calculated hashCode // a singleton which represents null value private static final Object $null = new Object() { @Override public java.lang.String toString() { return "<null>"; } }; private static final Object encodeNull(Object obj) { if (obj == null) return $null; return obj; } private static final Object decodeNull(Object obj) { if (obj == $null) return null; return obj; } private GlobalizedObjectTracker(Object obj, Type<?> T) { super(encodeNull(obj), referenceQueue); obj = encodeNull(obj); // if null is allowed for obj, we cannot distinguish the situation that weak reference is removed this.T = T; remoteCount = 0; if (GLOBALGC_DISABLE && !(obj instanceof Mortal)) remoteCount = 1000; // never collect non-Mortal globalized objects strongRef = (remoteCount > 0) ? obj : null; // prevent the collection of the obj hashCode = System.identityHashCode(obj); // should include T? // assign an id boolean isMortal = obj instanceof Mortal; while (true) { if (!isMortal) { id = lastId.incrementAndGet(); if (id > 0) { // try to use the id } else { // wraparound if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GlobalizedObjectTracker.<init>: resetting lastId"); synchronized(lastId) { if (lastId.get() < 0) lastId.set(0L); } continue; // retry } } else { // for Mortal objects, use negative id id = lastMortalId.decrementAndGet(); if (id < 0) { // try to use the id } else { // wraparound if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GlobalizedObjectTracker.<init>: resetting lastMortalId"); synchronized(lastMortalId) { if (lastMortalId.get() > 0) lastMortalId.set(0L); } continue; // retry } } assert(id != 0L); if (id2got.putIfAbsent(id, this) == null) break; // break if successfully put if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GlobalizedObjectTracker.<init>: id=" + id + " still exists, retry"); } if(GLOBALGC_DEBUG>=3)GlobalGCDebug("GlobalizedObjectTracker.<init>(obj=" + obj + ", T=" + T + "), id=" + id); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object other) { if (this == other) return true; if (!(other instanceof GlobalizedObjectTracker)) return false; GlobalizedObjectTracker got = (GlobalizedObjectTracker)other; if (hashCode != got.hashCode) return false; if (!T.equals(got.T)) return false; // if T is different, return false even if obj is the same Object obj = get(); if (obj == null) return false; // weak reference is removed, this GlobalizedObjectTracker is dead and will be removed soon return obj == got.get(); // should use == } private static ConcurrentHashMap<java.lang.Long, GlobalizedObjectTracker> id2got = new ConcurrentHashMap<java.lang.Long, GlobalizedObjectTracker>(); private static ConcurrentHashMap<GlobalizedObjectTracker, java.lang.Long> got2id = new ConcurrentHashMap<GlobalizedObjectTracker, java.lang.Long>(); private static long assignId(Object obj, Type<?> T) { cleanup(); // remove unused GlobalRefs first GlobalizedObjectTracker tmpGot = new GlobalizedObjectTracker(obj, T); // id2got.put was done in the constructor long tmpId = tmpGot.id; java.lang.Long existingId = got2id.putIfAbsent(tmpGot, tmpId); if (existingId != null) { // appropriate GlobalizedObjectTracker already exists id2got.remove(tmpId); // tmpGot will be collected by the next GC if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalizedObjectTracker.assignId: id=" + tmpId + " found for obj=" + obj + ", T=" + T); return existingId; } else { if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalizedObjectTracker.assignId: id=" + tmpId + " assigned for obj=" + obj + ", T=" + T + ", #GOT=" + got2id.size()); return tmpId; } } private static Object getObject(long id) { cleanup(); GlobalizedObjectTracker got = id2got.get(id); if (got == null) { if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GlobalizedObjectTracker.getObject: id=" + id + ", no GlobalizedObjectTracker for the id!"); throw new IllegalStateException("No GlobalizedObjectTracker for id=" + id); } Object obj = got.get(); if (obj == null) { if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GlobalizedObjectTracker.getObject: id=" + id + ", no object for the GlobalizedObjectTracker!"); throw new IllegalStateException("GlobalizedObjectTracker for id=" + id + " has no object"); } return decodeNull(obj); } private static void cleanup() { //TODO: this method is better to be called from GC (or periodically) GlobalizedObjectTracker got = null; while ((got = (GlobalizedObjectTracker)referenceQueue.poll()) != null) { assert(got.strongRef==null && got.id!=0L && got.get()==null); id2got.remove(got.id); // this may return null for tmpGot got2id.remove(got); // this may return null for tmpGot if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalizedObjectTracker.cleanup: id=" + got.id + " removed, #GOT=" + got2id.size()); // got will be collected by the next GC } } private static void changeRemoteCount(long id, int delta) { if (GLOBALGC_DISABLE) return; if (delta == 0) return; assert(id != 0L); cleanup(); GlobalizedObjectTracker got = id2got.get(id); if (got == null) { if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GlobalizedObjectTracker.changeRemoteCount: id=" + id + ", no GlobalizedObjectTracker for the id!"); throw new IllegalStateException("No GlobalizedObjectTracker for id=" + id); } if (id < 0) { // Mortal object if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalizedObjectTracker.changeRemoteCount: id=" + id + " is Mortal, remoteCount=" + got.remoteCount); assert(got.remoteCount == 0); return; } synchronized (got) { if (delta > 0) { if (got.remoteCount == 0) { Object obj = got.get(); if (obj == null) { if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GlobalizedObjectTracker.changeRemoteCount: id=" + id + ", no object for the GlobalizedObjectTracker!"); throw new IllegalStateException("GlobalizedObjectTracker for id=" + id + " has no object"); } got.strongRef = obj; } got.remoteCount += delta; // increment if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalizedObjectTracker.changeRemoteCount: id=" + id + " incremented to remoteCount=" + got.remoteCount); } else if (delta < 0) { assert(got.strongRef != null); got.remoteCount += delta; // decrement if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalizedObjectTracker.changeRemoteCount: id=" + id + " decremented to remoteCount=" + got.remoteCount); assert(got.remoteCount >= 0); if (got.remoteCount == 0) { got.strongRef = null; } } } } } // class GlobalizedObjectTracker private static class RemoteReferenceTracker extends WeakReference<GlobalRef<?>> { private static final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); private final long id; private x10.lang.Place home; private int weightCount; // weight of this remote ref, should be >0 private final int hashCode; // pre-calculated hashCode private RemoteReferenceTracker(GlobalRef<?> gr, int weight) { super(gr, referenceQueue); // gr is stored as weak reference id = gr.id; home = gr.home; weightCount = weight; hashCode = gr.hashCode(); } synchronized private int changeWeightCount(int delta) { weightCount += delta; return weightCount; } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object other) { if (this == other) return true; if (!(other instanceof RemoteReferenceTracker)) return false; RemoteReferenceTracker rrt = (RemoteReferenceTracker)other; if (hashCode != rrt.hashCode) return false; if (id != rrt.id) return false; if (home.id != rrt.home.id) return false; return true; // two rrts contain the same remote GlobalRef (other should be temporary rrt and will be disposed) } private static ConcurrentHashMap<RemoteReferenceTracker, RemoteReferenceTracker> rrtTable = new ConcurrentHashMap<RemoteReferenceTracker, RemoteReferenceTracker>(); private static GlobalRef<?> registerRemoteGlobalRef(GlobalRef<?> gr, int weight) { //if (GLOBALGC_DISABLE) return gr; // it is better to merge remote GlobalRefs even if GlobalGC is disabled, since same FinishState may be passed many times RemoteReferenceTracker rrt = new RemoteReferenceTracker(gr, weight); while (true) { cleanup(); RemoteReferenceTracker existingRrt = rrtTable.putIfAbsent(rrt, rrt); if (existingRrt == null) { // appropriate RemoteReferenceTracker does not exist if(GLOBALGC_DEBUG>=2)GlobalGCDebug("RemoteReferenceTracker.registerRemoteGlobalRef: id=" + rrt.id + " at place=" + rrt.home.id + " registered with weightCount=" + rrt.weightCount + ", #RRT=" + rrtTable.size()); //changeRemoteCount(rrt.home, rrt.id, +weight); // remoteCount was speculatively incremented (or divided) by sender return gr; } else { // appropriate RemoteReferenceTracker already exists GlobalRef<?> existingGr = existingRrt.get(); if (existingGr == null) continue; // racing condition, cleanup and retry //changeRemoteCount(rrt.home, rrt.id, -weight); // decrement speculatively-incremented remoteCount existingRrt.changeWeightCount(+weight); // merge the weight instead of decrement if(GLOBALGC_DEBUG>=2)GlobalGCDebug("RemoteReferenceTracker.registerRemoteGlobalRef: id=" + rrt.id + " at place=" + rrt.home.id + " found with new weightCount=" + existingRrt.weightCount); rrt.weightCount = 0; // this is unnecessary, but for fail-safe return existingGr; } } } private static RemoteReferenceTracker get(GlobalRef<?> gr) { // get corresponding RemoteReferenceTracker for the remote GlobalRef assert(gr.home.id != x10.lang.Runtime.home().id); RemoteReferenceTracker rrt = new RemoteReferenceTracker(gr, 0); RemoteReferenceTracker existingRrt = rrtTable.get(rrt); assert(existingRrt != null); return existingRrt; } private static void cleanup() { //TODO: this method is better to be called from GC (or periodically) RemoteReferenceTracker rrt = null; while ((rrt = (RemoteReferenceTracker)referenceQueue.poll()) != null) { assert(rrt.get() == null); if (rrtTable.remove(rrt) != null) { // if correctly removed, call decrement if(GLOBALGC_DEBUG>=2)GlobalGCDebug("RemoteReferenceTracker.cleanup: id=" + rrt.id + " at place=" + rrt.home.id + " removed with weightCount=" + rrt.weightCount + ", #RRT=" + rrtTable.size()); if (rrt.weightCount > 0) changeRemoteCount(rrt.home, rrt.id, -rrt.weightCount); } rrt.weightCount = 0; // this is unnecessary, but for fail-safe. rrt will be collected by the next GC } } private static void changeRemoteCount(Place place, long id, int delta) { if (GLOBALGC_DISABLE) return; if (delta == 0) return; assert(id != 0L); if (id < 0) { // Mortal object if(GLOBALGC_DEBUG>=2)GlobalGCDebug("RemoteReferenceTracker.changeRemoteCount: id=" + id + " at place=" + place.id + " delta=" + delta + ", Mortal -> do nothing"); return; } if (place.id == x10.lang.Runtime.home().id) { // local GlobalRef if(GLOBALGC_DEBUG>=2)GlobalGCDebug("RemoteReferenceTracker.changeRemoteCount: id=" + id + " at place=" + place.id + " delta=" + delta + ", local -> adjust directly"); GlobalizedObjectTracker.changeRemoteCount(id, delta); } else if (delta > 0) { // remote GlobalRef, increment if(GLOBALGC_DEBUG>=2)GlobalGCDebug("RemoteReferenceTracker.changeRemoteCount: id=" + id + " at place=" + place.id + " delta=" + delta + ", remote -> call runAt and wait"); //x10.lang.Runtime.runAt(placeId, new $Closure$0(id, delta)/*should be KIND_NOT_ASYNC*/); // this does not work inside deserializer //x10.runtime.impl.java.Runtime.runClosureAt(placeId, new $Closure$0(id, delta)); // this does not wait for the execution x10.lang.Runtime.runAtSimple(place, new $Closure$0(id, delta), true/*wait*/); // special simplified version of runAt } else { // remote GlobalRef, decrement can be asynchronous if(GLOBALGC_DEBUG>=2)GlobalGCDebug("RemoteReferenceTracker.changeRemoteCount: id=" + id + " at place=" + place.id + " delta=" + delta + ", remote -> call runAt and not-wait"); x10.lang.Runtime.runAtSimple(place, new $Closure$0(id, delta), false/*not-wait*/); } } // Closure for calling GlobalizedObjectTracker.changeRemoteCount(id, delta) // modified from the compiled code of "async at (place) { changeRemoteCount(id, delta); }" private /*@@public@@*/ static class $Closure$0 extends x10.core.Ref implements x10.core.fun.VoidFun_0_0, x10.serialization.X10JavaSerializable { private static final long serialVersionUID = 1L; public static final x10.rtt.RuntimeType<$Closure$0> $RTT = x10.rtt.StaticVoidFunType.<$Closure$0> make( /* base class */$Closure$0.class, /* parents */new x10.rtt.Type[] { x10.core.fun.VoidFun_0_0.$RTT }); public x10.rtt.RuntimeType<?> $getRTT() {return $RTT;} public Type<?> $getParam(int i) {return null;} private void writeObject(java.io.ObjectOutputStream oos) throws java.io.IOException { if (x10.runtime.impl.java.Runtime.TRACE_SER) { java.lang.System.out.println("Serializer: writeObject(ObjectOutputStream) of " + this + " calling"); } oos.defaultWriteObject(); } public static x10.serialization.X10JavaSerializable $_deserialize_body($Closure$0 $_obj, X10JavaDeserializer $deserializer) throws java.io.IOException { if (x10.runtime.impl.java.Runtime.TRACE_SER) { x10.runtime.impl.java.Runtime.printTraceMessage("X10JavaSerializable: $_deserialize_body() of " + $Closure$0.class + " calling"); } $_obj.id = $deserializer.readLong(); $_obj.delta = $deserializer.readInt(); return $_obj; } public static x10.serialization.X10JavaSerializable $_deserializer(X10JavaDeserializer $deserializer) throws java.io.IOException { $Closure$0 $_obj = new $Closure$0((java.lang.System[]) null); $deserializer.record_reference($_obj); return $_deserialize_body($_obj, $deserializer); } public void $_serialize(X10JavaSerializer $serializer) throws java.io.IOException { $serializer.write(this.id); $serializer.write(this.delta); } // constructor just for allocation public $Closure$0(final java.lang.System[] $dummy) { super($dummy); } public void $apply() { //@@RunAtTest.changeRemoteCount((long) (this.id), (int) (this.delta)); GlobalizedObjectTracker.changeRemoteCount((long) (this.id), (int) (this.delta)); } public long id; public int delta; public $Closure$0(final long id, final int delta) { { this.id = id; this.delta = delta; } } } } // class RemoteReferenceTracker private Type<?> T; public x10.lang.Place home; private long id; // place local id of referenced object private transient Object obj; // constructor just for allocation public GlobalRef(java.lang.System[] $dummy) { // call default constructor instead of "constructor just for allocation" for x10.core.Struct // super($dummy); if(GLOBALGC_DEBUG>=3)GlobalGCDebug("GlobalRef.<init>($dummy) called"); } public GlobalRef() { if(GLOBALGC_DEBUG>=3)GlobalGCDebug("GlobalRef.<init>() called"); T = null; home = null; id = 0L; obj = null; } public final GlobalRef<T> x10$lang$GlobalRef$$init$S() { if(GLOBALGC_DEBUG>=3)GlobalGCDebug("GlobalRef.$init() called"); T = null; home = null; id = 0L; obj = null; return this; } public final GlobalRef<T> x10$lang$GlobalRef$$init$S(final Type<?> T, T obj, __0x10$lang$GlobalRef$$T $dummy) { if(GLOBALGC_DEBUG>=3)GlobalGCDebug("GlobalRef.$init(T=" + T + ", obj=" + obj + ", $dummy) called, isMortal=" + (obj instanceof Mortal)); this.T = T; this.home = x10.lang.Runtime.home(); this.obj = obj; return this; } public GlobalRef(final Type<?> T, T obj, __0x10$lang$GlobalRef$$T $dummy) { if(GLOBALGC_DEBUG>=3)GlobalGCDebug("GlobalRef.<init>(T=" + T + ", obj=" + obj + ", $dummy) called, isMortal=" + (obj instanceof Mortal)); this.T = T; this.home = x10.lang.Runtime.home(); this.obj = obj; } // zero value constructor public GlobalRef(final Type<?> T, java.lang.System $dummy) { this(T, null, (__0x10$lang$GlobalRef$$T) null); } // synthetic type for parameter mangling public abstract static class __0x10$lang$GlobalRef$$T {} private void globalize() { if (isGlobalized()) return; // allready allocated assert (T != null); assert (home != null); id = GlobalizedObjectTracker.assignId(obj, T); if(GLOBALGC_DEBUG>=3)GlobalGCDebug("GlobalRef.globalize: id=" + id + " used for obj=" + obj + ", T=" + T); } private boolean isGlobalized() { return id != 0L; } final public T $apply$G() { return (T)obj; //TODO: should raise Exception if home!=here? } final public x10.lang.Place home() { return this.home; } @Override final public java.lang.String toString() { globalize(); // necessary to decide the id for this object return "GlobalRef(" + this.home + "," + this.id + ")"; } @Override final public int hashCode() { globalize(); // necessary to decide the id for this object return (this.home.hashCode() << 18) + (int) this.id; } @Override final public boolean equals(java.lang.Object other) { if (!(other instanceof GlobalRef<?>)) return false; GlobalRef<?> otherGref = (GlobalRef<?>) other; return this._struct_equals$O(otherGref); } final public boolean equals(x10.core.GlobalRef<T> other) { return this._struct_equals(other); } final public boolean _struct_equals$O(java.lang.Object other) { if (!x10.core.GlobalRef.$RTT.isInstance(other, T)) { return false; } return this._struct_equals((x10.core.GlobalRef<T>) other); } final public boolean _struct_equals(x10.core.GlobalRef<T> other) { //if (T != other.T || home != other.home) return false; if (!T.equals(other.T) || home.id != other.home.id) return false; if (home.id == x10.lang.Runtime.home().id) { // local GlobalRefs return obj == other.obj; } else { // remote GlobalRefs return id == other.id; } } public void writeExternal(ObjectOutput out) throws IOException { if (true) { if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GlobalRef.writeExternal: not supported!"); throw new RuntimeException("GlobalRef.writeExternal is not supported"); } globalize(); out.writeObject(T); out.writeObject(home); out.writeLong(id); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { if (true) { if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GlobalRef.readExternal: not supported!"); throw new RuntimeException("GlobalRef.readExternal is not supported"); } T = (Type<?>) in.readObject(); home = (x10.lang.Place) in.readObject(); id = in.readLong(); if (home.id == x10.lang.Runtime.home().id) { obj = GlobalizedObjectTracker.getObject(id); } else { obj = null; } } public void $_serialize(X10JavaSerializer $serializer) throws IOException { globalize(); int weight = adjustWeight(); assert((id > 0 && weight > 0) || (id < 0 && weight == 0)); // weight should be > 0 for non-Mortal GlobalRef if(GLOBALGC_DEBUG>=3)GlobalGCDebug("GlobalRef.$_serialize: id=" + id + " at place=" + home.id + " serializing, weight=" + weight); //changeRemoteCount(+1); // speculatively increment the remoteCount to avoid racing $serializer.write(T); $serializer.write(home); $serializer.write(id); $serializer.write(weight); // send the weight $serializer.addToGrefMap(this, weight); // to adjust the weight when serialized data is used more than once } public static X10JavaSerializable $_deserializer(X10JavaDeserializer $deserializer) throws java.io.IOException { GlobalRef $_obj = new GlobalRef(); int pos = $deserializer.record_reference($_obj); X10JavaSerializable returned = $_deserialize_body($_obj, $deserializer); // remote GlobalRefs are merged if they have same id if (returned != $_obj) $deserializer.update_reference(pos, returned); return returned; } public static X10JavaSerializable $_deserialize_body(GlobalRef $_obj, X10JavaDeserializer $deserializer) throws IOException { $_obj.T = $deserializer.readRef(); $_obj.home = $deserializer.readRef(); long id = $deserializer.readLong(); $_obj.id = id; int weight = $deserializer.readInt(); // weight got from sender assert((id > 0 && weight > 0) || (id < 0 && weight == 0)); // weight should be > 0 for non-Mortal GlobalRef if ($_obj.home.id == x10.lang.Runtime.home().id) { // local GlobalRef $_obj.obj = GlobalizedObjectTracker.getObject(id); if(GLOBALGC_DEBUG>=3)GlobalGCDebug("GlobalRef.$_deserialize_body: id=" + $_obj.id + " deserialized, weight=" + weight + ", localObj=" + $_obj.obj); GlobalizedObjectTracker.changeRemoteCount($_obj.id, -weight); // decrement speculatively-incremented remoteCount, this must be done after the object is got } else { // remote GlobalRef $_obj.obj = null; if(GLOBALGC_DEBUG>=3)GlobalGCDebug("GlobalRef.$_deserialize_body: id=" + $_obj.id + " at place=" + $_obj.home.id + " deserialized, weight=" + weight); $_obj = RemoteReferenceTracker.registerRemoteGlobalRef($_obj, weight); // remoteCount may be merged } return $_obj; } private void changeRemoteCount(int delta) { globalize(); if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalRef.changeRemoteCount: id=" + id + " at place=" + home.id + " delta=" + delta); RemoteReferenceTracker.changeRemoteCount(home, id, delta); } // Adjust speculative increment of remoteCounts of GlobalRefs (for the case that serialized data is used more than once) public static void adjustRemoteCountsInMap(java.util.Map<GlobalRef<?>,Integer> map, int multiply) { if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalRef.adjustRemoteCountsInMap: multiply=" + multiply); if (multiply == 0) return; for (GlobalRef<?> gr: map.keySet()) { int weight = map.get(gr); gr.changeRemoteCount(weight * multiply); } } private int adjustWeight() { if (id < 0) return 0; // No weight for Mortal GlobalRef if (home.id == x10.lang.Runtime.home().id) { // local GlobalRef int weight = GLOBALGC_WEIGHT; GlobalizedObjectTracker.changeRemoteCount(id, +weight); // add the initial weight if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalRef.adjustWeight(local): id=" + id + " at place=" + home.id + ", weight=" + weight); return weight; } else { // remote GlobalRef RemoteReferenceTracker rrt = RemoteReferenceTracker.get(this); if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalRef.adjustWeight(remote): id=" + id + " at place=" + home.id + ", weightCount=" + rrt.weightCount); assert(rrt.weightCount > 0); int weightCount, weight; while (true) { if (rrt.weightCount == 1) { // add weight to make it dividable RemoteReferenceTracker.changeRemoteCount(home, id, +GLOBALGC_WEIGHT); rrt.changeWeightCount(+GLOBALGC_WEIGHT); } synchronized (rrt) { weightCount = rrt.weightCount; if (weightCount < 2) { // someone stole my weight, retry the addition if(GLOBALGC_DEBUG>=1)GlobalGCDebug("GlobalRef.adjustWeight(remote): retry addition\n"); continue; } weight = weightCount * 2 / 10; // send 20% of weightCount // if we can know the target place, we could assign 1 if it is gref's home if (weight == 0) weight = 1; weightCount = rrt.changeWeightCount(-weight); assert(weightCount > 0); break; } } if(GLOBALGC_DEBUG>=2)GlobalGCDebug("GlobalRef.adjustWeight(remote): id=" + id + " at place=" + home.id + ", weight=" + weight + " remaining=" + weightCount); return weight; } } public static class LocalEval extends x10.core.Ref { private static final long serialVersionUID = 1L; public static final RuntimeType<LocalEval> $RTT = x10.rtt.NamedType.<LocalEval> make("x10.lang.GlobalRef.LocalEval", LocalEval.class); public RuntimeType<?> $getRTT() {return $RTT;} public Type<?> $getParam(int i) {return null;} // constructor just for allocation public LocalEval(final java.lang.System[] $dummy) { super($dummy);} public final LocalEval x10$lang$GlobalRef$LocalEval$$init$S() {return this;} // creation method for java code (1-phase java constructor) public LocalEval() { this((java.lang.System[]) null); x10$lang$GlobalRef$LocalEval$$init$S(); } // not used // // creation method for java code // public static LocalEval $make(){return new LocalEval((java.lang.System[])null).$init();} public static <$T, $U> $U evalAtHome(Type $T, Type $U, x10.core.GlobalRef<$T> ref, x10.core.fun.Fun_0_1<$T,$U> eval) { if (x10.lang.Runtime.home().id == ref.home.id) { return eval.$apply(ref.$apply$G(),$T); } else { return x10.lang.Runtime.<$U>evalAt__1$1x10$lang$Runtime$$T$2$G($U, ref.home, new $Closure$Eval<$T, $U>($T, $U, ref, eval, (x10.core.GlobalRef.LocalEval.$Closure$Eval.__0$1x10$lang$GlobalRef$LocalEval$$Closure$Eval$$T$2__1$1x10$lang$GlobalRef$LocalEval$$Closure$Eval$$T$3x10$lang$GlobalRef$LocalEval$$Closure$Eval$$U$2) null), null); } } public static <$T> $T getLocalOrCopy(Type $T, x10.core.GlobalRef<$T> ref) { if (x10.lang.Runtime.home().id == ref.home.id) { return ref.$apply$G(); } else { return x10.lang.Runtime.<$T>evalAt__1$1x10$lang$Runtime$$T$2$G($T, ref.home, new $Closure$Apply<$T>($T, ref, (x10.core.GlobalRef.LocalEval.$Closure$Apply.__0$1x10$lang$GlobalRef$LocalEval$$Closure$Apply$$T$2) null), null); } } public void $_serialize(X10JavaSerializer $serializer) throws IOException { } public static X10JavaSerializable $_deserializer(X10JavaDeserializer $deserializer) throws java.io.IOException { LocalEval $_obj = new LocalEval((System []) null); $deserializer.record_reference($_obj); return $_deserialize_body($_obj, $deserializer); } public static X10JavaSerializable $_deserialize_body(LocalEval $_obj, X10JavaDeserializer $deserializer) throws IOException { return $_obj; } public static class $Closure$Eval<$T, $U> extends x10.core.Ref implements x10.core.fun.Fun_0_0 { private static final long serialVersionUID = 1L; public static final RuntimeType<$Closure$Eval> $RTT = x10.rtt.StaticFunType.<$Closure$Eval> make($Closure$Eval.class, RuntimeType.INVARIANTS(2), new Type[] {x10.rtt.ParameterizedType.make(x10.core.fun.Fun_0_0.$RTT, x10.rtt.UnresolvedType.PARAM(1))}); public RuntimeType<?> $getRTT() {return $RTT;} public Type<?> $getParam(int i) {if (i ==0)return $T;if (i ==1)return $U;return null;} // constructor just for allocation public $Closure$Eval(final java.lang.System[] $dummy) { super($dummy);} public $Closure$Eval(Type $T, Type $U, x10.core.GlobalRef<$T> ref, x10.core.fun.Fun_0_1<$T,$U> eval, __0$1x10$lang$GlobalRef$LocalEval$$Closure$Eval$$T$2__1$1x10$lang$GlobalRef$LocalEval$$Closure$Eval$$T$3x10$lang$GlobalRef$LocalEval$$Closure$Eval$$U$2 $dummy) { this.$T = $T; this.$U = $U; this.ref = ref; this.eval = eval; } // not used // // creation method for java code // public static <$T, $U> $Closure$Eval $make(Type $T, Type $U, x10.core.GlobalRef<$T> ref, x10.core.fun.Fun_0_1<$T,$U> eval, __0$1x10$lang$GlobalRef$LocalEval$$Closure$Eval$$T$2__1$1x10$lang$GlobalRef$LocalEval$$Closure$Eval$$T$3x10$lang$GlobalRef$LocalEval$$Closure$Eval$$U$2 $dummy){ // return new $Closure$Eval($T, $U, ref, eval, $dummy); // } // synthetic type for parameter mangling public abstract static class __0$1x10$lang$GlobalRef$LocalEval$$Closure$Eval$$T$2__1$1x10$lang$GlobalRef$LocalEval$$Closure$Eval$$T$3x10$lang$GlobalRef$LocalEval$$Closure$Eval$$U$2 {} private Type $T; private Type $U; public x10.core.GlobalRef<$T> ref; public x10.core.fun.Fun_0_1<$T,$U> eval; public $U $apply$G() { return this.eval.$apply(this.ref.$apply$G(),$T); } public void $_serialize(X10JavaSerializer $serializer) throws IOException { $serializer.write($T); $serializer.write($U); $serializer.write(ref); $serializer.write(eval); } public static X10JavaSerializable $_deserializer(X10JavaDeserializer $deserializer) throws java.io.IOException { $Closure$Eval $_obj = new $Closure$Eval((System[]) null); $deserializer.record_reference($_obj); return $_deserialize_body($_obj, $deserializer); } public static X10JavaSerializable $_deserialize_body($Closure$Eval $_obj, X10JavaDeserializer $deserializer) throws IOException { $_obj.$T = $deserializer.readRef(); $_obj.$U = $deserializer.readRef(); $_obj.ref = $deserializer.readRef(); $_obj.eval = $deserializer.readRef(); return $_obj; } } public static class $Closure$Apply<$T> extends x10.core.Ref implements x10.core.fun.Fun_0_0 { private static final long serialVersionUID = 1L; public static final RuntimeType<$Closure$Apply> $RTT = x10.rtt.StaticFunType.<$Closure$Apply> make($Closure$Apply.class, RuntimeType.INVARIANTS(1), new Type[] {x10.rtt.ParameterizedType.make(x10.core.fun.Fun_0_0.$RTT, x10.rtt.UnresolvedType.PARAM(0))}); public RuntimeType<?> $getRTT() {return $RTT;} public Type<?> $getParam(int i) {if (i ==0)return $T;return null;} // constructor just for allocation public $Closure$Apply(final java.lang.System[] $dummy) { super($dummy);} public $Closure$Apply(Type $T, x10.core.GlobalRef<$T> ref, __0$1x10$lang$GlobalRef$LocalEval$$Closure$Apply$$T$2 $dummy) { this.$T = $T; this.ref = ref; } // not used // // creation method for java code // public static <$T> $Closure$Apply $make(Type $T, x10.core.GlobalRef<$T> ref, __0$1x10$lang$GlobalRef$LocalEval$$Closure$Apply$$T$2 $dummy) { // return new $Closure$Apply($T, ref, $dummy); // } // synthetic type for parameter mangling public abstract static class __0$1x10$lang$GlobalRef$LocalEval$$Closure$Apply$$T$2 {} private Type $T; public x10.core.GlobalRef<$T> ref; public $T $apply$G() { return this.ref.$apply$G(); } public void $_serialize(X10JavaSerializer $serializer) throws IOException { $serializer.write($T); $serializer.write(ref); } public static X10JavaSerializable $_deserializer(X10JavaDeserializer $deserializer) throws java.io.IOException { $Closure$Apply $_obj = new $Closure$Apply((System[]) null); $deserializer.record_reference($_obj); return $_deserialize_body($_obj, $deserializer); } public static X10JavaSerializable $_deserialize_body($Closure$Apply $_obj, X10JavaDeserializer $deserializer) throws IOException { $_obj.$T = $deserializer.readRef(); $_obj.ref = $deserializer.readRef(); return $_obj; } } } }