package edu.mit.streamjit.impl.compiler2;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Range;
import edu.mit.streamjit.util.CollectionUtils;
import edu.mit.streamjit.util.Combinators;
import edu.mit.streamjit.util.Pair;
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Represents one core during the compilation.
 * @author Jeffrey Bosboom <jeffreybosboom@gmail.com>
 * @since 10/17/2013
 */
public class Core {
	private final ImmutableMap<Storage, ConcreteStorage> globalStorage, localStorage, allStorage;
	private final List<Pair<ActorGroup, Range<Integer>>> allocations = new ArrayList<>();
	public Core(Set<Storage> storage, ImmutableMap<Storage, ConcreteStorage> globalStorage, StorageFactory localStorageFactory) {
		this.globalStorage = globalStorage;
		//We make ConcreteStorage for every local storage, despite not knowing
		//what we need yet; anything we don't use will get garbage collected
		//when the compiler state is discarded after instantiating the Blob.
		//TODO: this wastes space if we're assigned only part of a fissed
		//schedule; we should wait until we're building code and can compute
		//the space requirement.
		ImmutableMap.Builder<Storage, ConcreteStorage> localStorageBuilder = ImmutableMap.builder();
		for (Storage s : storage)
			if (s.isInternal())
				localStorageBuilder.put(s, localStorageFactory.make(s));
		this.localStorage = localStorageBuilder.build();
		this.allStorage = CollectionUtils.union(globalStorage, localStorage);
	}

	public void allocate(ActorGroup group, Range<Integer> iterations) {
		allocations.add(Pair.make(group, iterations));
	}

	public MethodHandle code() {
		//TODO: here's where to plug in ActorGroup ordering parameters
		List<MethodHandle> code = new ArrayList<>(allocations.size());
		for (Pair<ActorGroup, Range<Integer>> p : allocations)
			code.add(p.first.specialize(p.second, allStorage));
		return Combinators.semicolon(code);
	}

	/**
	 * Returns true iff this Core is empty (has no allocations) and thus doesn't
	 * need to generate or run code.
	 * @return true iff this core is empty
	 */
	public boolean isEmpty() {
		return allocations.isEmpty();
	}

	/**
	 * Returns the ConcreteStorage instances allocated for internal Storage by
	 * this core.
	 * @return local ConcreteStorage instances
	 */
	public ImmutableMap<Storage, ConcreteStorage> localStorage() {
		return allStorage;
	}

	@Override
	public String toString() {
		return allocations.toString();
	}
}

@@ -36,16 +36,64 @@
 iler2;%0A%0A
+import com.google.common.collect.ImmutableList;%0A
 import c
@@ -295,50 +295,181 @@
 til.
-Pair;%0Aimport java.lang.invoke.MethodHandle
+LookupUtils;%0Aimport edu.mit.streamjit.util.Pair;%0Aimport edu.mit.streamjit.util.SemicolonRunnable;%0Aimport java.lang.invoke.MethodHandle;%0Aimport java.lang.invoke.MethodHandles
 ;%0Aim
@@ -1870,24 +1870,164 @@
 ions));%0A%09%7D%0A%0A
+%09private static final MethodHandle RUNNABLE_RUN = LookupUtils.findVirtual(MethodHandles.publicLookup(), Runnable.class, %22run%22, void.class);%0A
 %09public Meth
@@ -2174,16 +2174,81 @@
 ize());%0A
+%09%09List%3CString%3E proxyNames = new ArrayList%3C%3E(allocations.size());%0A
 %09%09for (P
@@ -2295,16 +2295,18 @@
 cations)
+ %7B
 %0A%09%09%09code
@@ -2355,16 +2355,289 @@
 ge));%0A%09%09
+%09proxyNames.add(%22Group%22+p.first.id()+%22Iter%22+p.second.lowerEndpoint()+%22To%22+p.second.upperEndpoint());%0A%09%09%7D%0A%09%09ImmutableList%3CRunnable%3E proxies = Bytecodifier.runnableProxies(code, proxyNames);%0A%09%09Runnable r = new SemicolonRunnable(proxies);%0A%09%09return RUNNABLE_RUN.bindTo(r);%0A%09%09//
 return C

use separate proxies for each allocation