/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.apache.harmony.luni.platform;


import java.lang.ref.ReferenceQueue;
import java.lang.ref.Reference;
import java.lang.ref.PhantomReference;
import java.util.HashMap;
import java.util.Map;

/**
 * Abstract implementation for the OS memory spies.
 * 
 */
abstract class AbstractMemorySpy implements IMemorySpy {

	// TODO: figure out how to prevent this being a synchronization bottleneck
	protected Map<PlatformAddress,AddressWrapper> memoryInUse = new HashMap<PlatformAddress, AddressWrapper>(); // Shadow to Wrapper

	protected Map<Reference,PlatformAddress> refToShadow = new HashMap<Reference, PlatformAddress>(); // Reference to Shadow

	protected ReferenceQueue<Object> notifyQueue = new ReferenceQueue<Object>();

   	final class AddressWrapper {
		final PlatformAddress shadow;

		final PhantomReference<PlatformAddress> wrAddress;

		volatile boolean autoFree = false;

		AddressWrapper(PlatformAddress address) {
			super();
			this.shadow = address.duplicate();
			this.wrAddress = new PhantomReference<PlatformAddress>(address, notifyQueue);
		}
	}

	public AbstractMemorySpy() {
		super();
	}

	public void alloc(PlatformAddress address) {
		AddressWrapper wrapper = new AddressWrapper(address);
		synchronized (this) {
			memoryInUse.put(wrapper.shadow, wrapper);
			refToShadow.put(wrapper.wrAddress, wrapper.shadow);
		}
	}

	public boolean free(PlatformAddress address) {
		AddressWrapper wrapper;
		synchronized (this) {
			wrapper = memoryInUse.remove(address);
		}
		if (wrapper == null) {
			// Attempt to free memory we didn't alloc
			System.err
					.println("Memory Spy! Fixed attempt to free memory that was not allocated " + address); //$NON-NLS-1$
		}
		return wrapper != null;
	}

	public void rangeCheck(PlatformAddress address, int offset, int length)
			throws IndexOutOfBoundsException {
		// Do nothing
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.harmony.luni.platform.struct.IMemorySpy#autoFree(org.apache.harmony.luni.platform.struct.PlatformAddress)
	 */
	public void autoFree(PlatformAddress address) {
		AddressWrapper wrapper;
		synchronized (this) {
			wrapper = memoryInUse.get(address);
		}
		if (wrapper != null) {
			wrapper.autoFree = true;
		}
	}

	protected void orphanedMemory(Reference ref) {
		AddressWrapper wrapper;
		synchronized (this) {
			PlatformAddress shadow = refToShadow.remove(ref);
			wrapper = memoryInUse.remove(shadow);
		}
        ref.clear();
		if (wrapper != null) {
			// There is a leak if we were not auto-freeing this memory.
			if (!wrapper.autoFree) {
				System.err
						.println("Memory Spy! Fixed memory leak by freeing " + wrapper.shadow); //$NON-NLS-1$
			}
			memoryInUse.put(wrapper.shadow, wrapper);
			wrapper.shadow.free();
		}

	}
}

@@ -3196,22 +3196,19 @@
 ryInUse.
-remove
+get
 (shadow)
@@ -3213,20 +3213,16 @@
 w);%0A
-%09%09%7D%0A
         
 ref.
@@ -3221,23 +3221,12 @@
     
-ref.clear();%0A%09%09
+    
 if (
@@ -3244,19 +3244,32 @@
 null) %7B%0A
-%09%09%09
+                
 // There
@@ -3320,19 +3320,32 @@
 memory.%0A
-%09%09%09
+                
 if (!wra
@@ -3365,29 +3365,67 @@
 ) %7B%0A
-%09%09%09%09System.err%0A%09%09%09%09%09%09
+                    System.err%0A                            
 .pri
@@ -3510,88 +3510,103 @@
 -1$%0A
-%09%09%09%7D%0A%09%09%09memoryInUse.put(wrapper.shadow, wrapper);%0A%09%09%09wrapper.shadow.free();%0A%09%09%7D%0A
+                %7D%0A                wrapper.shadow.free();%0A            %7D%0A%09%09%7D%0A        ref.clear();
 %0A%09%7D%0A

Apply patch HARMONY-1194 ([classlib][nio] unexpected "Memory Spy! Fixed attempt to free memory that was not allocated PlatformAddress[xxx]" messages)