package org.dynjs.compiler.bytecode.partial;
import static me.qmx.jitescript.util.CodegenUtils.*;
import java.util.ArrayList;
import java.util.List;
import me.qmx.jitescript.JiteClass;
import org.dynjs.Config;
import org.dynjs.codegen.CodeGeneratingVisitorFactory;
import org.dynjs.compiler.CompilationContext;
import org.dynjs.parser.ast.BlockStatement;
import org.dynjs.runtime.BasicBlock;
import org.dynjs.runtime.Completion;
import org.dynjs.runtime.DynamicClassLoader;
import org.dynjs.runtime.ExecutionContext;
import me.qmx.jitescript.internal.org.objectweb.asm.Opcodes;
public class MultipleClassCompiler extends AbstractPartialCompiler {
private List<PartialCompiler> plans;
public MultipleClassCompiler(Config config, DynamicClassLoader classLoader, CodeGeneratingVisitorFactory factory, List<BlockStatement> chunks, int chunkSize) {
super(config, classLoader, factory);
List<PartialCompiler> plans = new ArrayList<PartialCompiler>();
int classStart = 0;
while (classStart < chunks.size()) {
int classEnd = classStart + chunkSize;
if (classEnd > chunks.size()) {
classEnd = chunks.size();
}
List<BlockStatement> classChunks = chunks.subList(classStart, classEnd);
SingleClassCompiler classPlan = new SingleClassCompiler(this, classChunks);
plans.add(classPlan);
classStart = classEnd;
}
this.plans = treeify(plans, chunkSize);
}
private MultipleClassCompiler(MultipleClassCompiler parent, List<PartialCompiler> plans) {
super(parent);
this.plans = plans;
}
private List<PartialCompiler> treeify(List<PartialCompiler> plans, int chunkSize) {
while (plans.size() > chunkSize) {
List<PartialCompiler> newPlans = new ArrayList<PartialCompiler>();
int treeStart = 0;
while (treeStart < plans.size()) {
int treeEnd = treeStart + chunkSize;
if (treeEnd > plans.size()) {
treeEnd = plans.size();
}
List<PartialCompiler> treePlans = plans.subList(treeStart, treeEnd);
PartialCompiler treePlan = new MultipleClassCompiler(this, treePlans);
newPlans.add(treePlan);
treeStart = treeEnd;
}
plans = newPlans;
}
return plans;
}
@Override
public void define(JiteClass cls, CompilationContext context, boolean strict) {
int numChunks = this.plans.size();
for (int i = 0; i < numChunks; ++i) {
JiteClass chunkClass = new JiteClass(cls.getClassName() + "$" + i, new String[] { p(BasicBlock.class) });
chunkClass.defineDefaultConstructor();
this.plans.get(i).define(chunkClass, context, strict);
defineClass(chunkClass);
cls.defineField("chunk" + i, Opcodes.ACC_PRIVATE, ci(BasicBlock.class), null);
}
cls.defineMethod("call", Opcodes.ACC_PUBLIC, sig(Completion.class, ExecutionContext.class), new MultipleClassCaller(cls.getClassName(), numChunks));
cls.defineMethod("initializeCode", Opcodes.ACC_PRIVATE, sig(void.class), new MultipleClassInitializer(cls.getClassName(), numChunks));
}
}