/* JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine Release Version 2.4 A project from the Physics Dept, The University of Oxford Copyright (C) 2007-2010 The University of Oxford This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Details (including contact information) can be found at: jpc.sourceforge.net or the developer website sourceforge.net/projects/jpc/ Conceived and Developed by: Rhys Newman, Ian Preston, Chris Dennis End of licence header */ package org.jpc.emulator.execution.codeblock; import java.util.logging.*; import org.jpc.emulator.execution.Executable; import org.jpc.emulator.execution.decoder.BasicBlock; import org.jpc.emulator.processor.*; /** * * @author Rhys Newman * @author Chris Dennis * @author Ian Preston */ class BackgroundCompiler implements CodeBlockCompiler { private static final Logger LOGGING = Logger.getLogger(BackgroundCompiler.class.getName()); private static final int COMPILER_QUEUE_SIZE = 256; private static final int COMPILE_REQUEST_THRESHOLD = 1024; // private static final int MAX_COMPILER_THREADS = 10; private CodeBlockCompiler immediate, delayed; private CompilerQueue compilerQueue; public BackgroundCompiler(CodeBlockCompiler immediate, CodeBlockCompiler delayed) { this.immediate = immediate; this.delayed = delayed; compilerQueue = new CompilerQueue(COMPILER_QUEUE_SIZE); int compilerCount = 1; // int compilerCount = Runtime.getRuntime().availableProcessors() - 1; // if (compilerCount < 1) // compilerCount = 1; // else if (compilerCount > MAX_COMPILER_THREADS) // compilerCount = MAX_COMPILER_THREADS; // // while (compilerCount-- > 0) { // Thread t = new Thread(new Compiler(), "Background CodeBlock Compiler Thread " + compilerCount); // try { // t.setPriority(Math.max(Thread.MIN_PRIORITY, Thread.currentThread().getPriority() - 3)); // } catch (SecurityException e) { // LOGGING.log(Level.INFO, "security manager prevents setting thread priorities"); // } // t.setDaemon(true); // t.start(); // } } private class Compiler implements Runnable { public void run() { while (true) { ExecuteCountingCodeBlockWrapper target = compilerQueue.getBlock(); if (target == null) { try { Thread.sleep(30); } catch (InterruptedException e) { } continue; } CodeBlock src = target.getTargetBlock(); CodeBlock result = null; // for now exit until we have a compiler if (true) return; if (src instanceof ReplacementBlockTrigger) { continue; } else if (src instanceof RealModeCodeBlock) { result = delayed.getRealModeCodeBlock((BasicBlock) src); } else if (src instanceof ProtectedModeCodeBlock) { result = delayed.getProtectedModeCodeBlock((BasicBlock) src); } if (result == null) { target.setTargetBlock(new ReplacementBlockTrigger(src)); } else { target.setTargetBlock(new ReplacementBlockTrigger(result)); } } } } public RealModeCodeBlock getRealModeCodeBlock(CodeBlock block) { RealModeCodeBlock imm = immediate.getRealModeCodeBlock(block); return new RealModeCodeBlockWrapper(imm); } public ProtectedModeCodeBlock getProtectedModeCodeBlock(CodeBlock block) { ProtectedModeCodeBlock imm = immediate.getProtectedModeCodeBlock(block); return new ProtectedModeCodeBlockWrapper(imm); } public Virtual8086ModeCodeBlock getVirtual8086ModeCodeBlock(CodeBlock block) { Virtual8086ModeCodeBlock imm = immediate.getVirtual8086ModeCodeBlock(block); return new Virtual8086ModeCodeBlockWrapper(imm); } private abstract class ExecuteCountingCodeBlockWrapper extends AbstractCodeBlockWrapper { private volatile int executeCount; private volatile boolean queued = false; public ExecuteCountingCodeBlockWrapper(CodeBlock block) { super(block); } public Executable.Branch execute(Processor cpu) { executeCount++; if ((executeCount % COMPILE_REQUEST_THRESHOLD) == 0) { if (!queued) queued = compilerQueue.addBlock(this); } return super.execute(cpu); } } private class RealModeCodeBlockWrapper extends ExecuteCountingCodeBlockWrapper implements RealModeCodeBlock { RealModeCodeBlockWrapper(RealModeCodeBlock block) { super(block); } } private class ProtectedModeCodeBlockWrapper extends ExecuteCountingCodeBlockWrapper implements ProtectedModeCodeBlock { ProtectedModeCodeBlockWrapper(ProtectedModeCodeBlock block) { super(block); } } private class Virtual8086ModeCodeBlockWrapper extends ExecuteCountingCodeBlockWrapper implements Virtual8086ModeCodeBlock { Virtual8086ModeCodeBlockWrapper(Virtual8086ModeCodeBlock block) { super(block); } } private static class CompilerQueue { private final ExecuteCountingCodeBlockWrapper[] queue; CompilerQueue(int size) { queue = new ExecuteCountingCodeBlockWrapper[size]; } boolean addBlock(ExecuteCountingCodeBlockWrapper block) { for (int i = 0; i < queue.length; i++) { if (queue[i] == null) { queue[i] = block; return true; } } for (int i = 0; i < queue.length; i++) { if (block.executeCount > queue[i].executeCount) { queue[i] = block; return true; } } return false; } ExecuteCountingCodeBlockWrapper getBlock() { int index = 0; int maxCount = 0; for (int i = 0; i < queue.length; i++) { if ((queue[i] != null) && (queue[i].executeCount > maxCount)) { maxCount = queue[i].executeCount; index = i; } } ExecuteCountingCodeBlockWrapper block = queue[index]; queue[index] = null; maxCount /= 2; for (int i = 0; i < queue.length; i++) { if (queue[i] == null) continue; if (queue[i].executeCount < maxCount) queue[i] = null; } return block; } } }